【问题标题】:How to enable code hinting using codemirror?如何使用 codemirror 启用代码提示?
【发布时间】:2015-11-16 21:44:08
【问题描述】:

我正在使用 codemirror 来允许用户输入任何代码,例如 css/html/js。

如果用户在 css 模式下输入类似内容,我需要启用

div {
 padding-
}

它应该提示用户从列表中选择可用的选项,例如

div {
padding-top
padding-left
padding-right
padding-bottom
}

类似于使用 codemirror 的 sublime 编辑器。 sublime 自动提示的演示请参见附图

这是我的代码:

 <script src="codemirror-5.4/mode/javascript/javascript.js"></script>
  <script src="codemirror-5.4/mode/css/css.js"></script>
  <script src="codemirror-5.4/mode/htmlmixed/htmlmixed.js"></script>
  <script src="codemirror-5.4/addon/display/fullscreen.js"></script>
  <script src="codemirror-5.4/keymap/sublime.js"></script>
  <script src="codemirror-5.4/addon/hint/show-hint.js"></script>
  <script src="codemirror-5.4/addon/hint/css-hint.js"></script>
  <script src="codemirror-5.4/addon/hint/javascript.js"></script>

<h3>Editor</h3>
  <div class="control-group">
    <label class="control-label" for="textarea2">HTML</label>
    <div class="controls">
        <textarea class="code" name="code" id="codert" cols="40" rows="5" placeholder="Enter code here ..." style="width: 810px; height: 200px">
       </textarea>
        </div>
    </div>

    <div class="control-group">
        <label class="control-label" for="textarea3">CSS</label>
        <div class="controls">
          <textarea id="code" class="code" name="codeCSS"  cols="40" rows="5" placeholder="Enter code here ..." style="width: 810px; height: 200px">
        </textarea>
        </div>
    </div>
    <div class="control-group">
        <label class="control-label" for="textarea3">javascript</label>
        <div class="controls">
            <textarea id="codeJS" class="code" name="codeJS"  cols="40" rows="5" placeholder="Enter code here ..." style="width: 0px; height: 0px">
           </textarea>
        </div>
    </div>

codemirror 的 JavaScript 代码

<script>

   function loadCSS() {
    var $head = $("#preview").contents().find("head");                
    $head.html("<style>" + editor.getValue() + "</style>");
}; 

function loadJS() {
    var scriptTag = "<script>"+editorJS.getValue()+"<";
    scriptTag +=  "/script>";

    var previewFrame2 = document.getElementById('preview');
    var preview2 =  previewFrame2.contentDocument ||  previewFrame2.contentWindow.document;
    preview2.open();
    preview2.write(editor2.getValue()+scriptTag);
    preview2.close();

    loadCSS();
};

var delay;
// Initialize CodeMirror editor with a nice html5 canvas demo.

// css editor
var editor = CodeMirror.fromTextArea(document.getElementById('code'), {
    lineNumbers: true,
    styleActiveLine: true,
    matchBrackets: true,
    mode: "text/x-scss",
    keyMap: "sublime",
    theme: 'monokai',
    autoCloseTags: true,
    lineWrapping: true,
    extraKeys: {"Ctrl-Space": "autocomplete"}
});
editor.on("change", function() {
    clearTimeout(delay);

    delay = setTimeout(updatePreview, 0);
});

function updatePreview() {
    loadCSS();
}
setTimeout(updatePreview, 0);


var delay2;
// Initialize CodeMirror editor with a nice html5 canvas demo.
var editor2 = CodeMirror.fromTextArea(document.getElementById('codert'), {
    lineNumbers: true,
    styleActiveLine: true,
    matchBrackets: true,
    mode: "text/html",
    keyMap: "sublime",
    theme: 'monokai',
    autoCloseTags: true,
    lineWrapping: true,
    extraKeys: {"Ctrl-Space": "autocomplete"}
});
editor2.on("change", function() {
    clearTimeout(delay2);

    delay2 = setTimeout(updatePreview2, 0);
});

function updatePreview2() {
    var scriptTag = "<script>"+editorJS.getValue()+"<";
    scriptTag +=  "/script>";

    var previewFrame2 = document.getElementById('preview');
    var preview2 =  previewFrame2.contentDocument ||  previewFrame2.contentWindow.document;
    preview2.open();
    preview2.write(editor2.getValue()+scriptTag);
    preview2.close();

    loadCSS();
}
setTimeout(updatePreview2, 0);


var delayJS;
// Initialize CodeMirror editor with a nice html5 canvas demo.
var editorJS = CodeMirror.fromTextArea(document.getElementById('codeJS'), {
    lineNumbers: true,
    styleActiveLine: true,
    matchBrackets: true,
    mode: 'javascript',
    keyMap: "sublime",
    theme: 'monokai',
    autoCloseTags: true,
    lineWrapping: true,
    extraKeys: {"Ctrl-Space": "autocomplete"}
});
editorJS.on("change", function() {
    clearTimeout(delayJS);

    delayJS = setTimeout(updatePreviewJS, 0);
});

function updatePreviewJS() {
    loadJS();
}
setTimeout(updatePreviewJS, 0);
</script>

【问题讨论】:

    标签: javascript html css autocomplete codemirror


    【解决方案1】:

    来自code mirror website

    function getCompletions(token, context) {
      var found = [], start = token.string;
      function maybeAdd(str) {
        if (str.indexOf(start) == 0) found.push(str);
      }
      function gatherCompletions(obj) {
        if (typeof obj == "string") forEach(stringProps, maybeAdd);
        else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
        else if (obj instanceof Function) forEach(funcProps, maybeAdd);
        for (var name in obj) maybeAdd(name);
      }
    
      if (context) {
        // If this is a property, see if it belongs to some object we can
        // find in the current environment.
        var obj = context.pop(), base;
        if (obj.className == "js-variable")
          base = window[obj.string];
        else if (obj.className == "js-string")
          base = "";
        else if (obj.className == "js-atom")
          base = 1;
        while (base != null && context.length)
          base = base[context.pop().string];
        if (base != null) gatherCompletions(base);
      }
      else {
        // If not, just look in the window object and any local scope
        // (reading into JS mode internals to get at the local variables)
        for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
        gatherCompletions(window);
        forEach(keywords, maybeAdd);
      }
      return found;
    }
    

    您按 ctrl+空格来启用代码提示。

    【讨论】:

    • 那是 javascript。 html函数可以在这里找到codemirror.net/demo/html5complete.html
    • 你写的代码是codemirror提供的demo示例代码。但该功能不仅仅适用于该代码。顺便说一句,css自动提示怎么样?任何想法?谢谢!
    • @Packer 我在回答中说它来自网站。对css一无所知。谷歌群组上有一个关于它的大讨论!
    • 我认为这可能行得通stackoverflow.com/a/19544473/1675954,有没有投票的机会?
    【解决方案2】:

    您没有发布所有代码,所以我可能是错的,但请确保将 show-hint.css 样式表添加到页眉。

    <link rel="stylesheet" href="../addon/hint/show-hint.css">
    

    否则,提示不会出现,我认为自动完成功能不起作用。

    【讨论】:

      【解决方案3】:

      编织:http://kodeweave.sourceforge.net/editor/#bc08cb08dee7609bbe7df11e8a55f27a

      有很多不同的方法可以实现代码提示/自动完成。

      var arrows = [37, 38, 39, 40]
      
      editor.on("keyup", function(cm, e) {
        if (arrows.indexOf(e.keyCode) < 0) {
          editor.execCommand("autocomplete")
        }
      })
      

      当然 Codemirror 有 official documentation 用于代码提示/自动完成。
      XML completion
      HTML completion
      JavaScript completion

      您也可以view the source 获取 javascript 示例来学习如何制作自己的提示。

      【讨论】:

        【解决方案4】:

        这就是我使用 CodeMirror 5 在我的应用程序 UI 中启用自定义代码提示的方式

        (它基本上是由我在网上找到的几种解决方案和https://codemirror.net/demo/complete.html的源代码组成的大杂烩)

        首先我添加了 CodeMirror 和代码提示插件

        <script src="libs/codemirror-5/codemirror.min.js"></script>
        <script src="libs/codemirror-5/plugins/show-hint.js"></script>
        

        我重载了(正确的术语吗?)showHint 命令,将它放在一个函数中(注意,因为 CM 调用了这个函数,它会将实例上下文作为可用参数注入)。

        function getSnippets(codemirror) {
        
            let snippets = [
                {text: 'SELECT', displayName: 'select'},
                {text: 'UPDATE', displayName: 'update'},
                {text: 'CREATE', displayName: 'create'},
                // other snippets for hinting
            ]
        
            CodeMirror.showHint(codemirror, function () {
        
                let cursor = codemirror.getCursor();
                let line = codemirror.getLine(cursor.line);
                let start = cursor.ch, end = cursor.ch;
                // corrects ignoring trailing whitespaces removal
                while (start && /\w/.test(line.charAt(start - 1)))
                            --start;
                while (end < line.length && /\w/.test(line.charAt(end)))
                            ++end;
                const token = codemirror.getTokenAt(cursor);
                const currentWord = token.string;
        
                // reduce hint options if user has already entered something
                const list = snippets.filter(function (item) {
                    return item.displayText.indexOf(currentWord) >= 0;
                });
        
                return {
                    list: list.length ? list : snippets,
                    from: CodeMirror.Pos(cursor.line, start),
                    to: CodeMirror.Pos(cursor.line, end)
                };
            }, {completeSingle: true});
        }
        

        然后,在 codemirror 实例选项中,我通过按 Ctrl+Space 定义了提示调用,这将调用我之前定义的 getSnippets 函数

        let codemirrorOptions = {
            mode: 'sql',
            extraKeys: {
                "Ctrl-Space": getSnippets
            },
            lineNumbers: false,
            lineWrapping: true
        }; 
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-24
          • 2013-04-14
          • 2023-04-10
          • 1970-01-01
          • 2014-04-15
          • 2015-10-14
          相关资源
          最近更新 更多