How does the autocomplete module prevent default key effects?

I am trying to add an effect during autocompletion in my CM-based editor.

My approach at the moment is this:

const showAssistContextKeymap = keymap.of(
  completionKeymap
    .filter((binding) => binding.key != 'Ctrl-Space')
    .filter((binding) => binding.key != 'Enter')
    .concat(
      [{
        key: 'Ctrl-Space',
        run: (view) => { showAssistContext(view); startCompletion(view); }
      }, {
        key: 'Enter',
        preventDefault: true,
        run: (view) => { hideAssistContext(view); acceptCompletion(view); }
      }]
    )
)

This almost works. The problem is that preventDefault does not do, what I thought it does. When I press Enter, a new-line is also inserted, after the completion is accepted.

I took a look at the source code of the autocompletion module, but I cannot figure out how does it disable the new-line insertion (or movement of the cursor, in the case of the arrows).

So how does the autocomplete module prevent default key effects?

Ooooh, I figured it out. The return value matters. As described in the docs:

run⁠?: Command

The command to execute when this binding is triggered. When the command function returns false, further bindings will be tried for the key.

So the correct code is this:

const showAssistContextKeymap = keymap.of(
  completionKeymap
    .filter((binding) => binding.key != 'Ctrl-Space')
    .filter((binding) => binding.key != 'Enter')
    .concat(
      [{
        key: 'Ctrl-Space',
        run: (view) => showAssistContext(view) && startCompletion(view)
      }, {
        key: 'Enter',
        run: (view) => hideAssistContext(view) && acceptCompletion(view)
      }]
    )
)

Subtle, but important difference.

That still begs the question: what should preventDefault do in the case run returns false?

I understand the docs as “it should prevent a new-line to be added in this case”. But it does not.

preventDefault⁠?: boolean

When set to true (the default is false), this will always prevent the further handling for the bound key, even if the command(s) return false. This can be useful for cases where the native behavior of the key is annoying or irrelevant but the command doesn’t always apply (such as, Mod-u for undo selection, which would cause the browser to view source instead when no selection can be undone).

Have you considered reading the docs?

1 Like

Haha, sounds like you’re joking, because I linked to the same part of the docs and quoted it.

So we agree that the behavior I observed does not match what’s described in the docs?

It prevents the browser’s default behavior, not any other handlers from running.

This makes sense. Thanks! I was a little tired when I was reading it yesterday, so I understood it otherwise.

The documentation is great. CM for the win :fist: