Monaco-editor: Auto complete for HTML -- add the close tag

Created on 5 Oct 2016  路  17Comments  路  Source: microsoft/monaco-editor

Hi
There is a way to configure HTML autocomplete
I would like that it will add the close tag as done in other editors
Thanks
Orly

monaco-editor npm version: 0.5.3
Browser: N/A
OS: N/A

feature-request monaco-html

Most helpful comment

My solution.

import monaco from 'monaco-editor/esm/vs/editor/editor.api';

monaco.languages.registerCompletionItemProvider('html', {
  triggerCharacters: ['>'],
  provideCompletionItems: (model, position) => {
    const codePre: string = model.getValueInRange({
      startLineNumber: position.lineNumber,
      startColumn: 1,
      endLineNumber: position.lineNumber,
      endColumn: position.column,
    });

    const tag = codePre.match(/.*<(\w+)>$/)?.[1];

    if (!tag) {
      return {};
    }

    const word = model.getWordUntilPosition(position);

    return {
      suggestions: [
        {
          label: `</${tag}>`,
          kind: monaco.languages.CompletionItemKind.EnumMember,
          insertText: `</${tag}>`,
          range:  {
             startLineNumber: position.lineNumber,
             endLineNumber: position.lineNumber,
             startColumn: word.startColumn,
             endColumn: word.endColumn,
          },
        },
      ],
    };
  },
});

All 17 comments

Status?

Status?

Only every other editor supports this, I guess it's not important. </sarcasm>

In VSCode we wait with adding the closing tag until you type the > .
That's something to port to the Monaco editor. PRs welcome...

I guess tagClosing.ts needs to be ported to monaco-html

@mofux Yes, exactly.

Status?

Could be something like this:

```
editor.onKeyDown(function(e) {
if(e.keyCode == 84 && editor.getModel()._languageIdentifier.language == "xml"){
var position = editor.getPosition();
var text = editor.getValue(position);
var splitedText= text.split("n");
var line = splitedText[position.lineNumber-1];
var regex = /<(w+)[^/>]*$/;
if (line.match(regex)) {
var content = "";
editor.trigger('bla', 'type', { text: content});
editor.setPosition(position);
}
}
}, 'editorTextFocus && !suggestWidgetVisible && !renameInputVisible && !inSnippetMode && !quickFixWidgetVisible')

@TortoiseMaster regex for parsing XML...

wow 2020 and still this issue not solved??

wow 2020 and still this issue not solved??

Yes, most of the people working on this project are interested in more important issues

if they ever complete it (which i highly doubt now :P), they better make the tab push in it so i can get a general syntax autocomplete after tab.

Seems none of the maintainers really care about bringing Monaco up to date with other editors...

@TortoiseMaster any progress with your code? i noticed that even style & script syntax are missing when using html language mode.. now i have to think whether to add them manually going through docs or switch to any better alternative sigh.

@aloksharma1 Now it looks like this:

function onXMLKeyDownListener(editor)
{
    function isBracketClose(event) {
        return (event.browserEvent && event.browserEvent.key == ">") || (event.keyCode == 84 && e.shiftKey);
    }
    return function(e)
    {
        // console.log("EVENT ", e, isQuote(e), isBracketClose(e))

        if (isBracketClose(e) /*  > */){
            const position = editor.getPosition();
            const text = editor.getValue(position);
            const splitedText= text.split("\n");
            const line = splitedText[position.lineNumber-1];


            let preLine = line.substring(0, position.column-1);
            let postLine = line.substring(position.column-1);

            let i = 1;
            while (preLine.indexOf("<") == -1 && position.lineNumber - i >= 0) {
                preLine = splitedText[position.lineNumber - 1 - i] + preLine;
                i++;
            }

            const regex = /<(\w+)[^\/>]*$/;
            if (preLine.match(regex) && !(postLine.indexOf(">") < postLine.indexOf("<"))) {
                let content = "</"+preLine.match(regex)[1]+">";
                editor.trigger('bla', 'type', {text: content});
                editor.setPosition(position);
            }
        }
    }

}

My solution.

import monaco from 'monaco-editor/esm/vs/editor/editor.api';

monaco.languages.registerCompletionItemProvider('html', {
  triggerCharacters: ['>'],
  provideCompletionItems: (model, position) => {
    const codePre: string = model.getValueInRange({
      startLineNumber: position.lineNumber,
      startColumn: 1,
      endLineNumber: position.lineNumber,
      endColumn: position.column,
    });

    const tag = codePre.match(/.*<(\w+)>$/)?.[1];

    if (!tag) {
      return {};
    }

    const word = model.getWordUntilPosition(position);

    return {
      suggestions: [
        {
          label: `</${tag}>`,
          kind: monaco.languages.CompletionItemKind.EnumMember,
          insertText: `</${tag}>`,
          range:  {
             startLineNumber: position.lineNumber,
             endLineNumber: position.lineNumber,
             startColumn: word.startColumn,
             endColumn: word.endColumn,
          },
        },
      ],
    };
  },
});

My solution.

import monaco from 'monaco-editor/esm/vs/editor/editor.api';

monaco.languages.registerCompletionItemProvider('html', {
  triggerCharacters: ['>'],
  provideCompletionItems: (model, position) => {
    const codePre: string = model.getValueInRange({
      startLineNumber: position.lineNumber,
      startColumn: 1,
      endLineNumber: position.lineNumber,
      endColumn: position.column,
    });

    const tag = codePre.match(/.*<(\w+)>$/)?.[1];

    if (!tag) {
      return {};
    }

    const word = model.getWordUntilPosition(position);

    return {
      suggestions: [
        {
          label: `</${tag}>`,
          kind: monaco.languages.CompletionItemKind.EnumMember,
          insertText: `</${tag}>`,
          range:  {
             startLineNumber: position.lineNumber,
             endLineNumber: position.lineNumber,
             startColumn: word.startColumn,
             endColumn: word.endColumn,
          },
        },
      ],
    };
  },
});

Thanks, @EmiyaYang. I was getting some errors on my console, when I'm just typing on the editor without starting with <

errors.ts:22 Uncaught Error: i.suggestions is not iterable

TypeError: i.suggestions is not iterable
    at b (suggest.ts:190)
    at Object.<anonymous> (suggest.ts:238)
    at Generator.next (<anonymous>)
    at r (compressedObjectTreeModel.ts:457)
    at errors.ts:22

So, I replace return {} with just return in the if word doesn't match tag regexp.

...
    const tag = codePre.match(/.*<(\w+)>$/)?.[1];

    if (!tag) {
-       return {};
+       return
    }

    const word = model.getWordUntilPosition(position);
...
Was this page helpful?
0 / 5 - 0 ratings

Related issues

akosyakov picture akosyakov  路  16Comments

meyer picture meyer  路  33Comments

Raathigesh picture Raathigesh  路  41Comments

tylerlong picture tylerlong  路  17Comments

valarGuru picture valarGuru  路  21Comments