codemirror autocomplete after any keyup?

2020-02-23 07:19发布

I'm working on trying to add a custom autocomplete, that I want to trigger whenever the user is typing (configurable of course). I've found a couple examples of autocomplete for codemirror:

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

But both of these trigger on specific keys (Control-Space for one and '<' for the other) and both use the extraKeys functionality to process the events, but I want to trigger from any key. I have tried the following:

        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');
             }
        });

But have had no luck. Any suggestions on how I could trigger from any keyup events?

10条回答
我命由我不由天
2楼-- · 2020-02-23 07:52

For version 5.7 neither of the previously proposed solutions work fine for me (and I think they have bugs even for earlier versions). My solution:

    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});
        }
    });

How it works:

This opens autocomplete popup only if it is not opened yet (otherwise keyboard-navigation would have caused reopening the popup with 1st item selected again).

When you click Enter you want popup to close so this is special case of a character which shouldn't trigger autocompletion (you may consider a case when you want to show antocompletion for empty line though).

Then last fix is setting completeSingle: false which 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).

查看更多
别忘想泡老子
3楼-- · 2020-02-23 07:59

The most IntelliSense-like behavior can be achieved by this:

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 });
    }
});
查看更多
走好不送
4楼-- · 2020-02-23 08:04

Let me share a full example that contains autocomplete(for hive sql) after any keyup:

Include scripts and styles:

<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 :

<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>
查看更多
Deceive 欺骗
5楼-- · 2020-02-23 08:04

changed Oleksandr Pshenychnyy's answer a little bit(see here), Answering as I can't add comments yet

The code below only allows autocomplete to come up when a letter key is pressed (probably what you want instead on any key)

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});
    }
});

(this should work logically, but could some please comment if this works or not !)

查看更多
登录 后发表回答