monaco-editor icon indicating copy to clipboard operation
monaco-editor copied to clipboard

[Feature Request] Is it possible to update auto completion suggestions when re-render editor component?

Open ranlix opened this issue 3 years ago • 2 comments

Context

  • [X] This issue is not a bug report. (please use a different template for reporting a bug)
  • [X] This issue is not a duplicate of an existing issue. (please use the search to find existing issues)

Description

I just write a SQL editor, which has default sql keywords as auto completion suggestions, and I pass some database tables' name as suggestions via registerCompletionItemProvider, that works.

But when I change my database, the tables change as well. The new suggestions contain duplicated items after that.

interface Range {
  startLineNumber: number;
  endLineNumber: number;
  startColumn: number;
  endColumn: number;
}

const getEditorAutoCompleteSuggestion = (
  range: Range,
  tables: string[]
): monaco.languages.ProviderResult<monaco.languages.CompletionList> => {
  const suggestionsFromDefaultKeywords = DEFAULT_SQL_KEYWORDS.split("|").map(
    (kw) => ({
      label: `${kw.toUpperCase()}`,
      kind: monaco.languages.CompletionItemKind.Keyword,
      detail: "Keyword",
      insertText: `${kw.toUpperCase()} `,
      range: range,
    })
  );
  const tableNameKeywords = tables?.map((tableName: string) => ({
    label: tableName,
    kind: monaco.languages.CompletionItemKind.Folder,
    detail: "Table",
    insertText: tableName,
    range: range,
  }));
  const suggestions = {
    suggestions: [...suggestionsFromDefaultKeywords, ...tableNameKeywords],
  };
  return suggestions;
};

const QueryInstance: React.FC = () => {
  const monaco = useMonaco();
  const { tables } = useRecoilValue(dbTablesState);
  const ref = useRef<unknown>();
  
  useEffect(() => {
    // or make sure that it exists by other ways
    if (monaco) {

      ref.current = monaco?.languages.registerCompletionItemProvider("sql", {
        provideCompletionItems: (
          model: monaco.editor.ITextModel,
          position: monaco.Position
        ) => {
          const word = model.getWordUntilPosition(position);
          const range = {
            startLineNumber: position.lineNumber,
            endLineNumber: position.lineNumber,
            startColumn: word.startColumn,
            endColumn: word.endColumn,
          };
          return getEditorAutoCompleteSuggestion(range, tables);
        },
      });
    }
    return () => {
      monaco?.languages.registerCompletionItemProvider("sql", {
        provideCompletionItems: () => {
          return {
            suggestions: [],
          };
        },
      });
    };
  }, [monaco, tables]);
image

Is there any way to remove the duplicated suggestions?

ranlix avatar Jun 14 '22 06:06 ranlix

I found that when component props(monaco or tables) update, there will be duplicated suggestions here.

ranlix avatar Jun 14 '22 07:06 ranlix

You need to use the dispose returned when you register the completion item otherwise you are just adding an additional provider that is returning an empty set of suggestions.

Something like this:

  useEffect(() => {
    let disposable = null;
    // or make sure that it exists by other ways
    if (monaco) {

      disposable = monaco?.languages.registerCompletionItemProvider("sql", {
        provideCompletionItems: (
          model: monaco.editor.ITextModel,
          position: monaco.Position
        ) => {
          const word = model.getWordUntilPosition(position);
          const range = {
            startLineNumber: position.lineNumber,
            endLineNumber: position.lineNumber,
            startColumn: word.startColumn,
            endColumn: word.endColumn,
          };
          return getEditorAutoCompleteSuggestion(range, tables);
        },
      });
    }
    return () => {
      disposable?.dispose();
    };
  }, [monaco, tables]);

mpcaddy avatar Jun 25 '22 23:06 mpcaddy