Dynamic autocompletion

Hey everyone,
I’ve created a code-editor using codemirror in react js. i want to provide dynamic autocompletion in the editor using tern js.
here is the code would look in vanilla js.

import { EditorView, basicSetup } from "codemirror";
import { EditorState } from "@codemirror/state";
import { javascript } from "@codemirror/lang-javascript";
import { autocompletion } from "@codemirror/autocomplete";

const state = EditorState.create({
  doc: "function main(){\n  return true;\n}\n",
  extensions: [basicSetup, javascript(), autocompletion()],
});
const editorView = new EditorView({
  state,
  parent: document.querySelector("#editor"),
});

here is the code of how I’ve created the tern server. you can try it to find how it is providing completions.

import * as tern from "tern";
import "tern/plugin/doc_comment";
import "tern/plugin/complete_strings";
import ecma from "tern/defs/ecmascript.json";

export default function getAutocompletion(code) {
  const query = {
    type: "completions",
    file: "temp.js",
    end: code.length,
    lineCharPositions: true,
    types: true,
  };

  const defs = [ecma];

  const ternServer = new tern.Server({
    getFile(filename, callback) {
      callback(null, code);
    },
    async: false,
    defs,
  });

  let ast = code;
  const completionList = [];

  ternServer.request(
    {
      query,
      files: [
        {
          type: "full",
          name: "temp.js",
          text: code,
          scope: "document",
        },
      ],
      doc: ast,
    },
    (error, res) => {
      if (error) {
        console.error("Tern.js error:", error);
        return;
      }

      if (res?.completions) {
        completionList.push(
          ...res?.completions.map((item) => ({
            label: item.name,
            detail: item.type,
            apply: () => item.name,
          }))
        );
      }
    }
  );

  return completionList;
}

console.log(getAutocompletion("let obj = {\n  foo: true\n}\nobj."));

can somebody help me use this getAutocompletion function to get completions in the editor ? I’ve tried various ways like override in autocompletion extension, completionList, using EditorView.updateListener.of() and few more… but none of them showed me completions in the editor.

Does the autocompletion example not give you enough information to do this?

I’ve tried it but it isn’t working as expected. I want to update the list of autocompletion every time there is a change the EditorState.doc. the getAutocompletions function returns completions dynamically using the tern server, the completions are not stored statically in a array. Isn’t there any proper way to solve this issue ? Or would it be a better approach to use codemirror v5 coz it has addon of tern server ?

That’s how autocompletion works in general, in CodeMirror. Completion can happen from a static list, but usually a completion source function returns a specific list for a completion at a given point in the current document.

1 Like

Hey, Thank you for your help. After spending hours going through the documentation and my code, I was finally able to solve the problem - actually, I solved it two days ago.

I used a function in the documentation that looked like this:

function myCompletions(context) {
  let before = context.matchBefore(/\w+/);
  // getting my completions amd storing it in completions variable
  let completions = getAutocompletion(context.state.doc.toString());

  // If completion wasn't explicitly started and there is no word before the cursor, don't open completions.
  if (!context.explicit && !before) {
    return null;
  }

  return {
    from: before ? before.from : context.pos,
    options: completions,
    validFor: /^\w*$/,
  };
}

I then used this function to override the completions in the autocompletion extension like so:

autocompletion({ override: [customProvider] })

Once again, thank you for your support.