Search code examples
codemirrorcodemirror-modesreact-codemirror

codemirror inner mode auto indentation problems


I'm having some trouble getting codemirror to apply the correct autoindentation to inner modes in a mixed mode.

You can see a live version of the mode (and how it's not working) here: https://extremely-alpha.iodide.io/notebooks/216/ but in short the idea is to be able to use matlab style block delimiters to switch between languages like this:

%% js
[1,2,3].forEach(i => {
  console.log(i)
})

%% py
for i in range(5):
    for j in range(10):
        print i+j

%% css
div#foo {
    border: 1px solid pink
}

As you can see from my example link, the syntax highlighting works ok, but you'll also notice that the indentation is not working as desired.

The code for this codemirror mode is here on github. It is very much based on codemirror's html mixed mode.

I tried adding copyState to my code, again following the html mixed mode --

copyState: state => {
    let local;
    if (state.localState) {
      console.log("state.localState copied");
      local = CodeMirror.copyState(state.localMode, state.localState);
    }
    return {
      token: state.token,
      localMode: state.localMode,
      localState: local
    };
  },

-- but this results in a different kind of weird indentation behavior, and doesn't end up working.

I've been banging my head against this for quite some time, and I haven't been able to piece it together via google, api docs and forums, so any help would be greatly appreciated! Thank you!


Solution

  • in case anyone comes across this problem in the future: it turns out codemirror modes do not typically come with sensible defaults built in, or at least they are not loaded by default when you use CodeMirror.getMode(...). In my case, I had to change from

    const innerModes = {
      js: CodeMirror.getMode({}, { name: "javascript" }),
      py: CodeMirror.getMode({}, { name: "python" }),
      md: CodeMirror.getMode({}, { name: "markdown" }),
      css: CodeMirror.getMode({}, { name: "css" }),
      raw: CodeMirror.getMode({}, { name: "text/plain" }),
      fetch: CodeMirror.getMode({}, { name: "fetch" })
    };
    

    to:

    const innerModes = {
      js: CodeMirror.getMode(
        { indentUnit: 2, statementIndent: 2 },
        { name: "javascript" }
      ),
      py: CodeMirror.getMode(
        { indentUnit: 4, hangingIndent: 4 },
        { name: "python" }
      ),
      md: CodeMirror.getMode({}, { name: "markdown" }),
      css: CodeMirror.getMode({ indentUnit: 2 }, { name: "css" }),
      raw: CodeMirror.getMode({}, { name: "text/plain" }),
      fetch: CodeMirror.getMode({}, { name: "fetch" })
    };
    

    This prevented NaNs from getting passed out of the indent function of the sub-modes.