From 2240a0895ee1d392247ff42f764ebd87b9b36299 Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 18 Jun 2017 15:20:48 +0300 Subject: [PATCH] editor: autocomplete on typing --- _locales/en/messages.json | 4 ++++ edit.html | 4 ++++ edit.js | 40 +++++++++++++++++++++++++++++++++++++++ prefs.js | 1 + 4 files changed, 49 insertions(+) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index a5b7c4fe..584bb716 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -91,6 +91,10 @@ "message": "Checking...", "description": "Text to display when checking a style for an update" }, + "cm_autocompleteOnTyping": { + "message": "Autocomplete on typing", + "description": "Label for the checkbox in the style editor." + }, "cm_indentWithTabs": { "message": "Use tabs with smart indentation", "description": "Label for the checkbox controlling tabs with smart indentation option for the style editor." diff --git a/edit.html b/edit.html index e3d9ae4c..c8ae2927 100644 --- a/edit.html +++ b/edit.html @@ -704,6 +704,10 @@ +
+ + +
diff --git a/edit.js b/edit.js index 3f939c58..f100b177 100644 --- a/edit.js +++ b/edit.js @@ -161,6 +161,7 @@ function initCodeMirror() { gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"], matchBrackets: true, highlightSelectionMatches: {showToken: /[#.\-\w]/, annotateScrollbar: true}, + hintOptions: {}, lint: {getAnnotations: CodeMirror.lint.css, delay: prefs.get("editor.lintDelay")}, lintReportDelay: prefs.get("editor.lintReportDelay"), styleActiveLine: true, @@ -319,6 +320,13 @@ function acmeEventListener(event) { }, 100); })(); return; + case 'autocompleteOnTyping': + editors.forEach(cm => { + const onOff = el.checked ? 'on' : 'off'; + cm[onOff]('change', autocompleteOnTyping); + cm[onOff]('pick', autocompletePicked); + }); + return; case "matchHighlight": switch (value) { case 'token': @@ -338,6 +346,10 @@ function setupCodeMirror(textarea, index) { var cm = CodeMirror.fromTextArea(textarea, {lint: null}); cm.on("change", indicateCodeChange); + if (prefs.get('editor.autocompleteOnTyping')) { + cm.on('change', autocompleteOnTyping); + cm.on('pick', autocompletePicked); + } cm.on("blur", function(cm) { editors.lastActive = cm; hotkeyRerouter.setState(true); @@ -874,6 +886,34 @@ function toggleStyle() { save(); } +function autocompleteOnTyping(cm, info, debounced) { + if (cm.state.completionActive + || info.origin && !info.origin.includes('input') + || !info.text.last) { + return; + } + if (cm.state.autocompletePicked) { + cm.state.autocompletePicked = false; + return; + } + if (!debounced) { + debounce(autocompleteOnTyping, 100, cm, info, true); + return; + } + if (info.text.last.match(/[-\w!]+$/)) { + cm.state.autocompletePicked = false; + cm.options.hintOptions.completeSingle = false; + cm.execCommand('autocomplete'); + setTimeout(() => { + cm.options.hintOptions.completeSingle = true; + }); + } +} + +function autocompletePicked(cm) { + cm.state.autocompletePicked = true; +} + function refocusMinidialog(cm) { var section = cm.getSection(); if (!section.querySelector(".CodeMirror-dialog")) { diff --git a/prefs.js b/prefs.js index 00b74663..a84cb52d 100644 --- a/prefs.js +++ b/prefs.js @@ -44,6 +44,7 @@ var prefs = new function Prefs() { 'editor.matchHighlight': 'token', // token = token/word under cursor even if nothing is selected // selection = only when something is selected // '' (empty string) = disabled + 'editor.autocompleteOnTyping': false, // show autocomplete dropdown on typing a word token 'editor.contextDelete': contextDeleteMissing(), // "Delete" item in context menu 'badgeDisabled': '#8B0000', // badge background color when disabled