【问题标题】:codemirror autocomplete after any keyup?任何键位后codemirror自动完成?
【发布时间】:2012-11-24 12:21:45
【问题描述】:

我正在尝试添加一个自定义自动完成功能,我想在用户输入时触发它(当然是可配置的)。我发现了几个 codemirror 的自动完成示例:

http://codemirror.net/demo/complete.htmlhttp://codemirror.net/demo/xmlcomplete.html

但这两个都在特定键上触发(一个是 Control-Space,另一个是 'extraKeys 功能来处理事件,但我想从任何键触发。我尝试了以下方法:

        var editor = CodeMirror.fromTextArea(document.getElementById("code"),
        {
             lineNumbers: true,
             mode: "text/x-mysql",
             fixedGutter: true,
             gutter: true,
//           extraKeys: {"'.'": "autocomplete"}
             keyup: function(e)
             {
                console.log('testing');
             },
             onkeyup: function(e)
             {
                console.log('testing2');
             }
        });

但是没有运气。关于如何从任何 keyup 事件触发的任何建议?

【问题讨论】:

    标签: javascript codemirror key-events


    【解决方案1】:

    对于 5.7 版,以前提出的解决方案都不适用于我(我认为即使是早期版本也存在错误)。我的解决方案

        myCodeMirror.on("keyup", function (cm, event) {
            if (!cm.state.completionActive && /*Enables keyboard navigation in autocomplete list*/
                event.keyCode != 13) {        /*Enter - do not open autocomplete list just after item has been selected in it*/ 
                CodeMirror.commands.autocomplete(cm, null, {completeSingle: false});
            }
        });
    

    工作原理:

    仅当它尚未打开时才会打开自动完成弹出窗口(否则键盘导航会导致重新打开弹出窗口并再次选择第一个项目)。

    当您单击 Enter 时,您希望关闭弹出窗口,因此这是不应触发自动补全的字符的特殊情况(但您可能会考虑一种情况,即您希望为空行显示反补全) .

    然后最后一个修复是设置completeSingle: false,它可以防止在您输入某个单词时大小写,并且在中间自动完成并且您继续通过反射输入。所以用户总是需要从弹出窗口中选择想要的字符串(即使它是单个选项)。

    【讨论】:

    • 除了注释末尾的括号会破坏代码外,此方法有效:/*Enter - 不要在项目被选中后立即打开自动完成列表*/)
    • 'null' ¿ 是什么意思?
    • @AlbertoAcuña 而不是CodeMirror.commands.autocomplete(cm, null, {completeSingle: false});(根据代码中的注释,它现在是为向后兼容而保留的旧接口),您可以使用cm.showHint({completeSingle: false});
    【解决方案2】:

    可以通过以下方式实现最类似于 IntelliSense 的行为:

    var ExcludedIntelliSenseTriggerKeys =
    {
        "8": "backspace",
        "9": "tab",
        "13": "enter",
        "16": "shift",
        "17": "ctrl",
        "18": "alt",
        "19": "pause",
        "20": "capslock",
        "27": "escape",
        "33": "pageup",
        "34": "pagedown",
        "35": "end",
        "36": "home",
        "37": "left",
        "38": "up",
        "39": "right",
        "40": "down",
        "45": "insert",
        "46": "delete",
        "91": "left window key",
        "92": "right window key",
        "93": "select",
        "107": "add",
        "109": "subtract",
        "110": "decimal point",
        "111": "divide",
        "112": "f1",
        "113": "f2",
        "114": "f3",
        "115": "f4",
        "116": "f5",
        "117": "f6",
        "118": "f7",
        "119": "f8",
        "120": "f9",
        "121": "f10",
        "122": "f11",
        "123": "f12",
        "144": "numlock",
        "145": "scrolllock",
        "186": "semicolon",
        "187": "equalsign",
        "188": "comma",
        "189": "dash",
        "190": "period",
        "191": "slash",
        "192": "graveaccent",
        "220": "backslash",
        "222": "quote"
    }
    
    EditorInstance.on("keyup", function(editor, event)
    {
        var __Cursor = editor.getDoc().getCursor();
        var __Token = editor.getTokenAt(__Cursor);
    
        if (!editor.state.completionActive &&
            !ExcludedIntelliSenseTriggerKeys[(event.keyCode || event.which).toString()] &&
            (__Token.type == "tag" || __Token.string == " " || __Token.string == "<" || __Token.string == "/"))
        {
            CodeMirror.commands.autocomplete(editor, null, { completeSingle: false });
        }
    });
    

    【讨论】:

    • 你能再解释一下吗?特别是 __Token 条件,它似乎适用于 xml(?)
    • 此数组包含不应触发 IntelliSense 下拉菜单的键代码,即。功能键,换档或控制。如果引发来自 CodeMirror 的事件,则将针对此数组检查按下的键,并且仅当它不存在时处理程序才会继续。这只是为了避免不必要的弹出菜单(我觉得这很烦人)。
    • 我添加了 "32": "space" 并删除了 "190": "period" 以便更像 Visual Studio IntelliSense。
    • exclude keys 运行良好!但我不明白令牌条件。这只是将自动完成再次限制为一个非常小的子集。我已经从条件中删除了该部分,现在它工作得很好。你的意思是否定它吗?
    【解决方案3】:

    要同时显示自动完成小部件:

    onKeyEvent: function (e, s) {
        if (s.type == "keyup") {
            CodeMirror.showHint(e);
        }
    }
    

    【讨论】:

      【解决方案4】:
      editor.on("inputRead",function(cm,changeObj){
         // hinting logic
      })
      

      就我所见,“inputRead”是在“codemirror”中显示“自动完成”的最佳事件。 唯一的缺点是您不能在退格或删除时显示提示。

      【讨论】:

      • 您能否详细说明为什么它是最佳选择?此外,如果您可以展示一些您成功实现的示例提示逻辑,那将对其他人有所帮助。
      • "keyup"/"keydown" 事件捕获上/下/右/左键。所以“inputRead”是捕捉提示逻辑的最佳方式。就提示逻辑而言,它取决于您要实现它的语言。对于 javascript,您可以查看“tern.js”。为了构建提示逻辑,您需要在继续之前查看目标语言的标记器、解析器和语义。
      • 谢谢,我什至不知道这个事件。对于提示逻辑,我只是​​使用了cm.showHint({completeSingle: false})
      【解决方案5】:

      使用此功能无需 CTRL + Space 即可自动完成 codeMirror。

      在 show-hint.js 中将 completeSingle 设置为 false

      editor.on("inputRead", function(instance) {
          if (instance.state.completionActive) {
                  return;
          }
          var cur = instance.getCursor();
          var token = instance.getTokenAt(cur);
          if (token.type && token.type != "comment") {
                  CodeMirror.commands.autocomplete(instance);
          }
      });
      

      【讨论】:

        【解决方案6】:

        让我分享一个完整的例子,在任何 keyup 之后包含自动完成(用于 hive sql):

        包括脚本和样式:

        <link rel="stylesheet" href="/static/codemirror/lib/codemirror.css">
        <link rel="stylesheet" href="/static/codemirror/theme/material.css">
        <link rel="stylesheet" href="/static/codemirror/addon/hint/show-hint.css" />
        
        <script type="text/javascript" src="/static/codemirror/lib/CodeMirror.js"></script>
        <script type="text/javascript" src="/static/codemirror/mode/sql/sql.js"></script>
        <script type="text/javascript" src="/static/codemirror/addon/hint/show-hint.js"></script>
        <script type="text/javascript" src="/static/codemirror/addon/hint/sql-hint.js"></script>
        

        HTML:

        <textarea id="code" name="code" rows="4" placeholder="" value=""></textarea>
        

        脚本:

        <script>
        
            $(function () {
                initSqlEditor();
                initAutoComplete();
            });
        
            // init sql editor
            function initSqlEditor() {
        
                var editor = CodeMirror.fromTextArea(document.getElementById('code'), {
                    autofocus: true,
                    extraKeys: {
                        "Tab": "autocomplete"
                    },
                    hint: CodeMirror.hint.sql,
                    lineNumbers: true,
                    mode: 'text/x-hive',
                    lineWrapping: true,
                    theme: 'material',
                });
        
                editor.on('keyup', function(editor, event){
                    // type code and show autocomplete hint in the meanwhile
                    CodeMirror.commands.autocomplete(editor);
                });
            }
        
            /**
             * Init autocomplete for table name and column names in table.
             */
            function initAutoComplete() {
        
                CodeMirror.commands.autocomplete = function (cmeditor) {
        
                    CodeMirror.showHint(cmeditor, CodeMirror.hint.sql, {
        
                        // "completeSingle: false" prevents case when you are typing some word
                        // and in the middle it is automatically completed and you continue typing by reflex.
                        // So user will always need to select the intended string
                        // from popup (even if it's single option). (copy from @Oleksandr Pshenychnyy)
                        completeSingle: false,
        
                        // there are 2 ways to autocomplete field name:
                        // (1) table_name.field_name (2) field_name
                        // Put field name in table names to autocomplete directly
                        // no need to type table name first.
                        tables: {
                            "table1": ["col_A", "col_B", "col_C"],
                            "table2": ["other_columns1", "other_columns2"],
                            "col_A": [],
                            "col_B": [],
                            "col_C": [],
                            "other_columns1": [],
                            "other_columns2": [],
                        }
                    });
                }
            }
        
        </script>
        

        【讨论】:

          【解决方案7】:

          我认为每个人都有自己的用例。我还必须从不同的答案中挑选部分来制作最适合我的情况的东西。

          据我说,我只想显示关于字母、数字和 (.) 的建议,但按下 ctrl 键除外。因为有时我复制或粘贴一些东西,所以不应该打开建议。 46 ascii 用于 (.) 我已经包含在数字中。

          activeEditor.on("keydown", function (cm, event) {
            if (
              !(event.ctrlKey) &&
              (event.keyCode >= 65 && event.keyCode <= 90) || 
              (event.keyCode >= 97 && event.keyCode <= 122) || 
              (event.keyCode >= 46 && event.keyCode <= 57)
            ) {
              CodeMirror.commands.autocomplete(cm, null, {completeSingle: false});
            }
          });
          

          请记住包括 3 件事 -

          1. 显示提示的js和css - <link rel="stylesheet" href="codemirror/addon/hint/show-hint.css"> <script src="codemirror/addon/hint/show-hint.js"></script>

          2. 您想要提示的语言脚本 - 例如 - javascript <script src="codemirror/addon/hint/javascript-hint.js"></script>

          3. 在初始化代码编辑器时包含此行。我使用了 javascript 提示。 hint: CodeMirror.hint.javascript

          【讨论】:

            【解决方案8】:
            editor.on('keyup', function(){
                CodeMirror.commands.autocomplete(editor);
            });
            

            它可能有效

            【讨论】:

            • 这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方发表评论 - 您可以随时评论自己的帖子,一旦您有足够的reputation,您就可以comment on any post
            • 这是这个问题的答案!在您的代码下方添加此代码,每次您按下键时,它都会触发自动完成事件。
            • 如果您按箭头键向下移动提示选项,它将重置并卡在顶部选项,使用此代码。
            【解决方案9】:

            稍微更改了 Oleksandr Pshenychnyy 的答案(请参阅 here),因为我还不能添加 cmets 而回答

            下面的代码只允许在按下字母键时自动完成(可能是你想要的,而不是任何键)

            editor.on("keyup", function (cm, event) {
            if (!cm.state.completionActive &&   /*Enables keyboard navigation in autocomplete list*/
                 event.keyCode > 64 && event.keyCode < 91){// only when a letter key is pressed
                     CodeMirror.commands.autocomplete(cm, null, {completeSingle: false});
                }
            });
            

            (这在逻辑上应该可行,但如果可行,请发表评论!)

            【讨论】:

              【解决方案10】:

              注意:此答案does not 适用于最新版本的 CodeMirror。

              onKeyEvent: function(e , s){
                              if (s.type == "keyup")
                              {
                                  console.log("test");   
                              }
                          }
              

              【讨论】:

                【解决方案11】:

                对于这种情况,更改事件是更好的选择

                editor.on('change', (cm, event) => {
                         editor.execCommand('autocomplete');
                        });
                

                【讨论】:

                • 确实,“execCommand('autocomplete')” 是我需要与 Angular 和 ngx-codemirror 一起使用的,感谢您的提示!
                猜你喜欢
                • 1970-01-01
                • 2013-10-15
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-04-04
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多