Search code examples
javascriptautocompletecodemirror

In CodeMirror, bind `%%` to autocomplete and add `%%` after the chosen option


I have a project that want to have CodeMirror implemented. Basically, one of the requirements is that you can type double % (for example: %% keyword %%) to display a list (a hint). I have seen the official example with Ctrl+Space, but I'm wondering how I can make typing the second percent character of the start double percent be a trigger to show the hint list, and how I can display the keyword with the end double percent after choosing an option from the list. I need help or any demo or sample code.


Solution

  • I was having similar problems with CodeMirror, I'll share what I have learned.

    type double % (for example: %% keyword %%) to display a list (a hint).

    To achieve this, first you need to handle the 'change' event:

    var cm = CodeMirror.fromTextArea(document.getElementById('textArea'),
    {
      mode:        'your_custom_language',
      lineNumbers: true,
      extraKeys:   {'Ctrl-Space': 'autocomplete'}
    });
    
    var onChange = function(instance, object)
    {
        // do stuff...
    }
    
    CodeMirror.on(cm, 'change', onChange);
    

    Then, on the onChange function you must do the following:

    1. Check if the last inserted character is %.
    2. Check if the previous character is %.
    3. Summon the hint list.

    I did it this way:

    var onChange = function(instance, object)
    {
        // Check if the last inserted character is `%`.
        if (object.text[0] === '%' &&
            // Check if the previous character is `%`.
            instance.getRange({ch: object.to.ch - 1, line: object.to.line}, object.to) === '%')
        {
            // Summon the hint list.
            CodeMirror.showHint(cm, CodeMirror.hint.your_custom_language);
        }
    }
    

    Note that I use the cm object previously declared, you must change this to meet your requirements. And also, the deduced context for your keyword will not match what you're expecting; in order to fix this you need to modify your own codemirror/addon/hint/your_custom_language-hint.js; in my case, I based my custom language on JavaScript (refactoring the javascript-hint.js) modifying the function called maybeAdd from:

    function maybeAdd(str) {
      if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
    }
    

    to:

    function maybeAdd(str)
    {
      if (isValidHint(str))
      {
        found.push({text: '%%' + str + '%%', displayText: str});
      }
    }
    

    Note that the array found of getCompletions is no longer storing strings, it is storing objects with this format:

    {
        // this will be written when the hint is selected.
        "text": "%%text%%",
        // this will be shown on the hint list.
        "displayText": "text",
        // You can custom each hint match with a CSS class.
        "className": "CSSClass"
    }
    

    Please, note that all the things I've writed above are refactoring of my CodeMirror custom language, it is untested on your own custom language but I hope it helps.

    BTW; I think that CodeMirror documentation doesn't look clear and lacks on examples of many demanded features.