"no ... in context": eval [-draft] / edit -scratch / require-module

This requires several steps to explain, but ultimately, the problem is that I can’t seem to be able to use edit -scratch from within top-level code run by require-module

  1. One can use an edit -scratch; ...; delete-buffer block to make text substitutions in the source code before loading it. In sel-editor / sel-editor.kak , I use this trick to avoid typing the “namespace” prefix all over the place: I wrapped the entire module code in a loader function that does the substitutions (%s-replace @E@ with sel-editor, essentially), then eval's the modified code
  2. For code that runs from kakrc, this requires an eval -draft ... wrapper, otherwise I get a no input handler in context error
  3. If I try to also use this trick from within provide-module %{ }, it fails at require-module time (whether require- is called at kakrc time, or later, even manually)
    • with a eval -draft wrapper, it fails with no selections in context
    • with a eval wrapper, it fails with no input handler in context

What is so special about code inside provide-module? I tested the same thing in a NormalIdle hook and it works with a simple eval -draft.

Note: I’m talking about top-level code inside provide-module, not code inside def's created by provide-module

When you require-module, Kakoune explicitly executes the code in an empty context:

Context empty_context{Context::EmptyContextFlag{}};
execute(module->value.commands, empty_context);

Normally, when a new context is created, it starts as a copy of the current execution context. However, using the EmptyContextFlag constructor means the context doesn’t have any of the things passed to the regular context constructor, such as an input handler or a list of selections.

I would have expected eval -draft to work around this; it usually creates a “headless” window context you can use for tricks like this; as you point out, it even works in kakrc. Looking at the code for eval -draft, I see it makes an input handler from (among other things) the source context’s selections:

Optional<InputHandler> input_handler;
Context* effective_context = base_context;

const bool draft = (bool)parser.get_switch("draft");
if (draft)
{
    input_handler.emplace(base_context->selections(), // <-- see, here!
                          Context::Flags::Draft,
                          base_context->name());
    effective_context = &input_handler->context();
...

I wonder if the EmptyContextFlag constructor should be updated to initialise the context with an empty list of selections, or if the Context class should be updated to create and return an empty list if it doesn’t have a selection list, so that eval -draft can work. On one hand, a list of selections is supposed to be exclusive to a window context, so giving every context a selection list might break things. On the other hand, what kind of selection list does kakrc have? Surely modules should be no more restrictive than kakrc execution.

1 Like