How to use a custom linter after calling CodeMirror.registerHelper()

I am currently building a code editor with a custom mode.
This is how it is defined:

    let codeMirror = CodeMirror.fromTextArea(textArea,
      {
        mode: "customMode",
        lint: true,
        theme: customtheme,
      }

I then create a custom linter, defined as:

  CodeMirror.registerHelper("lint", "customMode", function (text) {
    // the "myLint()" function returns an array of error objects
    // each object has a "from", "to", "severity", and "message" property
    let errorsArray = myLint(text)
    return errorsArray ;
});

If run the command
console.log(CodeMirror.lint.customMode(code));
An array of error objects is printed to the console, each with a “to”, “from”, “severity” and “message” property. What I’m wondering is, how do I use this function so that these errors can be underlined in red in the code editor?
Thank you

That should just work automatically, if you’ve loaded the lint addon (and make sure to register the helper before creating the editor).

1 Like

Thank you very much! It turns out I wasn’t properly importing the lint addon!

hello! Is there an equivalent functionality in v6 for registerHelper? I’m migrating some old work from v5 to v6 that used registerHelper for combining the hints in autocomplete. I’ve looked into v6 docs but couldn’t find anything on registerHelper. I’m assuming there isn’t one? And if I want to combine the default autocomplete list with our custom list, is that possible to do? Thank you!

The equivalent of registerHelper in 6.x is the language data mechanism. See for example this definition in lang-javascript.

1 Like

thank you! so by doing this from line 85-90

  javascriptLanguage.data.of({
     autocomplete: ifNotIn(dontComplete, completeFromList(snippets.concat(keywords)))
  }),
  javascriptLanguage.data.of({
     autocomplete: localCompletionSource
  }),

it combines both of the lists together in the final result?

Is it correct to say that if I want to add my own custom autocompletes to the default autocompletes, I’ll need to go through the language data mechanism to “create a new language” in order to include the custom list? Say I have different modes I’m supporting and I want to include the same list. I’ll need to determine which langauge to use in order to have it this the following?

    javascriptLanguage.data.of({
      autocomplete: ifNotIn(dontComplete, completeFromList(snippets.concat(keywords)))
    }),
    javascriptLanguage.data.of({
      autocomplete: localCompletionSource
    }),
    config.jsx ? autoCloseTags : [],
  ])

So I’m thinking to have a switch statement that will return the language (either javascriptLanguage from @codemirror/lang-javascript, or htmlLanguage from @codemirror/lang-html based on mode). I don’t see a SQLLanguage from @codemirror/lang-sql. Instead would I be calling one of the dialects instead, using it like StandardSQL.data.of({....})?

Thank you!

You can also add languageData.of(() => globalLanguageData) to your configuration to add language data for all languages (assuming globalLanguageData is an object with an autocomplete property holding a completion source).

1 Like

oh thank you! what might this langaugeData be? is this the languageData from EditorState?

EDIT: oh nevermind that. I found old posts where you showed how to use it

Question: How to augment language completion list with 'completeAnyWord'? - #2 by marijn & Can I use autocomplete without implementing a parser (or language)? - #2 by marijn

However, it’s still not working for me. Here’s a snippet of my code:

viewRef.current.dispatch({
        effects: [
          autocompleteCompartment.reconfigure(
            autocomplete
              ? [
                  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                  // @ts-ignore
                  EditorState.languageData.of(() => ({
                    autocomplete: completeFromList(hintList),
                  })),
                  autocompletion(),
                ]
              : []
          ),
        ],
      });

Without autocompletion(), i’m not getting any errors but still I can’t see the custom list nor the default list. And when I do include autocompletion() it errors out with the following:

Uncaught TypeError: provider is not a function or its return value is not iterable
    at EditorState.languageDataAt (index.js:2826:1)
    at CompletionState.update (index.js:997:1)
    at StateField.update [as updateF] (index.js:1136:1)
    at Object.update (index.js:1798:1)
    at EditorState.eval [as computeSlot] (index.js:2630:1)
    at ensureAddr (index.js:2034:1)
    at new EditorState (index.js:2567:1)
    at EditorState.applyTransaction (index.js:2630:1)
    at get state [as state] (index.js:2281:1)
    at EditorView.update (index.js:6569:1)

:pray:

@marijn thank you for the pointers! I did have to put the object into an array to fix that error

 viewRef.current.dispatch({
        effects: [
          autocompleteCompartment.reconfigure(
            autocomplete
              ? [
                  autocompletion(),
                  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                  // @ts-ignore
                  EditorState.languageData.of(() => [
                    {
                      autocomplete: customCompletion,
                    },
                  ]),
                ]
              : []
          ),
        ],
      });

thank you so much for the help! I greatly appreciate it!! :pray: