在vue中實現Monaco Editor自定義提示功能

此次接到一個需求,要在瀏覽器的IDE中支持自定義提示功能,以下所示:php

clipboard.png

能夠看到,它能夠根據用戶輸入的內容來一項一項排除,只顯示徹底匹配的那一項。
項目的框架是Vue,編輯器用的是Monaco Editorjava

什麼是Monaco Editor

vscode是咱們常常在用的編輯器,它的前身是微軟的一個叫Monaco Workbench的項目,而Monaco Editor就是從這個項目中成長出來的一個web編輯器,他們很大一部分的代碼都是共用的,因此Monaco EditorVSCode在編輯代碼,交互及UI上幾乎是一摸同樣的。不一樣的是,二者的平臺不同,Monaco Editor基於瀏覽器,而VSCode基於electron,因此功能上VSCode更加健全,性能比較強大。react

用法

  1. 安裝web

    npm install monaco-editor --save
  2. 使用sql

    <div id="monaco" class="monaco-editor"></div>
    import * as monaco from 'monaco-editor';
    this.fileEditor = this.monaco.editor.create(document.getElementById('monaco'), {
      value: null,
      language: 'sql'  // 這裏以sql爲例
    })
    
    this.fileEditor.dispose(); // 使用完後銷燬

    這裏引入monaco要注意,在react中如下面方式引入:npm

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

實現自定義提示功能

查看了資料後,發如今monaco中有提供一個提示功能的方法registerCompletionItemProvider,具體實現以下:json

this.monaco.languages.registerCompletionItemProvider('sql', { // 這裏以sql語言爲例
  provideCompletionItems () {
    return [{
      label: '${_DB',  // 顯示的提示內容
      kind: this.monaco.languages.CompletionItemKind['Function'], // 用來顯示提示內容後的不一樣的圖標
      insertText: '{_DB', // 選擇後粘貼到編輯器中的文字
      detail: '' // 提示內容後的說明
    }];
  },
  triggerCharacters: ['$'] // 觸發提示的字符,能夠寫多個
});

以上的用法,我試了一下以後發現,雖然triggerCharacters的值是數組,能夠有多個,可是裏面的字符串只能識別一個字符。一開始的需求是輸入${_以後提示${_DB,可是因爲不能識別多個字符,只能作到出現$就提示。api

還有一個問題就是registerCompletionItemProvider的第一個參數只能是字符串,若是有多種語言只能疊加劇複寫,恰巧個人需求是有多種語言,因此只能以下解決,也就是每種語言都寫了一遍:數組

['json', 'yaml', 'php', 'go', 'sql', 'java', 'markdown', 'plaintext'].map(item => {
  this.monaco.languages.registerCompletionItemProvider(item, {
    provideCompletionItems () {
      return [{
        label: '${_DB',
        kind: this.monaco.languages.CompletionItemKind['Function'],
        insertText: '{_DB',
        detail: ''
      }];
    },
    triggerCharacters: ['$']
  });
});

需求是${_DB:key:value,也就是說在輸入${_DB後,再輸入一個:提示出key,在key以後輸入:提示value瀏覽器

這裏又碰到一個問題,須要知道當前輸入的內容來判斷是$仍是:,並且後面兩個觸發提示的符號同是:,沒法區分,只能經過識別:的位置來判斷是提示key仍是value,因此還要知道當前輸入的:以前的內容。

那麼只有在provideCompletionItems這一步判斷,可是查遍了資料沒有發現這樣的參數,provideCompletionItems只有modelpositiontoken這幾個參數,後來發現model中的getLineContent方法能夠獲取指定行的全部內容,而position能夠獲取當前輸入行的行數和列數,因而就有了如下解決方法:

this.monaco.languages.registerCompletionItemProvider(item, {
  provideCompletionItems (model, position) {
    // 獲取當前行數
    const line = position.lineNumber
    
    // 獲取當前列數
    const column = position.column
    
    // 獲取當前輸入行的全部內容
    const content = model.getLineContent(line)
    
    // 經過下標來獲取當前光標後一個內容,即爲剛輸入的內容
    const sym = content[column - 2]
    
    if (sym === '$') {
      return [{
        label: '${_DB',
        kind: this.monaco.languages.CompletionItemKind['Function'],
        insertText: '{_DB',
        detail: ''
      }];
    }
    
    return [{
      label: ':abb',
      kind: this.monaco.languages.CompletionItemKind['Function'],
      insertText: 'abb',
      detail: ''
    },
    {
      label: ':bc',
      kind: this.monaco.languages.CompletionItemKind['Function'],
      insertText: 'bc',
      detail: ''
    }];
  },
  triggerCharacters: ['$', ':']
});

能獲取光標後的第一個內容,後面的內容就都能獲取啦,若是識別到前面的內容是${_DB就提示key,不然提示value

最後總結下來就是必定要多看文檔,勤於測試就能解決問題啦~

啦啦啦~ 交差去啦~

相關文章
相關標籤/搜索