prompt has fuzzy filtering which is more discoverable than the menu
mode's regex filtering (because that one needs / to trigger it).
There are no important differences left, so replace the menu builtin
with a prompt-based command.
prompt does not support markup in the completion menu, so drop that
feature for now.
Read output from the script as it comes and update the candidate
list progressively.
Disable updating of the list when a completion has been explicitely
selected.
Usually, the prompt resets "m_line_changed" after invoking the
change handler:
if (m_line_changed)
{
m_callback(m_line_editor.line(), PromptEvent::Change, context());
m_line_changed = false;
}
but with
prompt '' '' -on-change %{ execute-keys <a-semicolon>vl } -shell-script-candidates %{ seq 100 }
the change handler pushes a normal mode with "<a-semicolon>" and then
hands back control to the event loop. Later when the normal mode is
popped we run "Prompt::on_enabled()" but don't actually redraw the
completion pager.
Since the <a-semicolon> excursion by definition did not change our
prompt state, we don't need to recompute completions, only render them.
Do that.
This helps commands that use preview the selected completion via a
"prompt -on-change" handler.
This removes the timing dependent behaviour where `Tab` would only
display the completion menu if pressed before the prompt idle timeout
This means `exec :dc<tab>` now expands 'dc' to 'define-command'
instead of just showing the completion menu a few millis early.
ensure cursor is visible after user input except if the command
implementation opted-out. Hooks and timers should not enforce
visible cursor.
PageUp/PageDown and `<c-f>` / `<c-b>` commands still move the cursor
as this seemed a desired behaviour.
This is currently broken on various corner cases and breaks the
"master branch should be good for day to day work" implicit rule,
ongoing work to stabilize this feature will take place on the
no-cursor-move-on-scroll branch until its deemed ready.
This reverts commit 1e38045d70.
Closes#4963
Kakoune now does not touch cursors when scrolling. It checks
if either the buffer or selections has been modified since
last redraw.
Fixes#4124Fixes#2844
My terminal allows to map <c-[> and <esc> independently. I like
to use <c-[> as escape key so I have this mapping:
map global prompt <c-[> <esc>
Unfortunately, this is not equivalent to <esc>. Since mappings are
run with history disabled, <c-[> will not add the command to the
prompt history.
So disabling command history inside mappings is wrong in case the
command prompt was created before mapping execution. The behavior
should be: "a prompt that is both created and closed inside a
noninteractive context does not add to prompt history", where
"noninteractive" means inside a mapping, hook, command, execute-keys
or evaluate-commands.
Implement this behavior, it should better meet user expectations.
Scripts can always use "set-register" to add to history.
Here are my test cases:
1. Basic regression test (needs above mapping):
:nop should be added to history<c-[>
---
2. Create the prompt in a noninteractive context:
:exec %{:}
now we're back in the interactive context, so we can type:
nop should be added to history<ret>
---
3. To check if it works for nested prompts, first set up this mapping.
map global prompt <c-j> '<a-semicolon>:nop should NOT be added to history<ret>'
map global prompt <c-h> '<a-semicolon>:nop should be added to history first'
Then type
:nop should be added to history second<c-j><c-h><ret><ret>
the inner command run by <c-j> should not be added to history because
it only existed in a noninteractive context.
---
See also the discussion https://github.com/mawww/kakoune/pull/4692
We could automate the tests if we had a test setup that allowed
feeding interactive key input into Kakoune instead of using
"execute-commands". Some projects use tmux, or maybe we can mock
the terminal.
The commit after next will fix a bug where we wrongly disable prompt
history in some scenarios. The root cause is that life span of
"disable_history" does not model when we actually want to disable
history.
Let's rename the state variable to "noninteractive". It's set whenever
we are executing a hook, mapping or command.
Note that it's also active inside ":prompt"'s callback, which doesn't
play well with the new name :(
When unmapping a key sequence that is currently executing, we continue
executing freed memory which can have weird effects. Let's instead
throw an error if that happens. In future we can support unmap in
this scenario.
Closes#4896
input_handler.cc:1476:16: error: alias template 'ConstArrayView' requires template arguments; argument deduction only allowed for class templates
insert(ConstArrayView{content});
^
input_handler.cc:1522:16: error: alias template 'ConstArrayView' requires template arguments; argument deduction only allowed for class templates
insert(ConstArrayView{str});
^
Handle begin/end paste directly in paste csi, manage paste buffer
out of get_char, filter Key::Invalid earlier.
get_next_key returning Key::Invalid means there was some input but
it could not be represented as a Key. An empty optional means there
was no input at all.
Text pasted into Kakoune's normal mode is interpreted as command
sequence, which is probably never what the user wants. Text
pasted during insert mode will be inserted fine but may trigger
auto-indentation hooks which is likely not what users want.
Bracketed paste is pair of escape codes sent by terminals that allow
applications to distinguish between pasted text and typed text.
Let's use this feature to always insert pasted text verbatim, skipping
keymap lookup and the InsertChar hook. In future, we could add a
dedicated Paste hook.
We need to make a decision on whether to paste before or after the
selection. I chose "before" because that's what I'm used to.
TerminalUI::set_on_key has
EventManager::instance().force_signal(0);
I'm not sure if we want the same for TerminalUI::set_on_paste?
I assume it doesn't matter because they are always called in tandem.
Closes#2465
Recent changes for selection-undo added an assertion that triggers
when a mouse-drag overlaps with an insert mode, because both events
record selection history. However this is actually fine. The one
that finishes last concludes the selection edition, while the other
one will be a nop.
The test could be simpler (i.e. not require sleeps) but I figured it
doesn't hurt add this since we don't have any comparable tests.
With overlapping selections, pasting after breaks assumption of
SelectionList::for_each as our changes are no longer happening in
increasing locations.
We hence cannot rely on the ForwardChangeTracker in that case and
have to rely on the more general (and more costly) ranges update logic.
This interacts poorly with paste linewise pastes and we try to preserve
the current behaviour by tracking the last paste position.
Overall, this change really begs for overlapping selections to be
removed, but we will fix them like that for now.
Fixes#4779
From the issue:
> It often happens to me that I carefully craft a selection with multiple
> cursors, ready to make changes elegantly, only to completely mess it
> up by pressing a wrong key (by merging the cursors for example). Being
> able to undo the last selection change (even if only until the previous
> buffer change) would make this much less painful.
Fix this by recording selection changes and allowing simple linear
undo/redo of selection changes.
The preliminary key bindings are <c-h> and <c-k>.
Here are some other vacant normal mode keys I considered
X Y
<backspace> <minus>
# ^ =
<plus> '
unfortunately none of them is super convenient to type. Maybe we
can kick out some other normal mode command?
---
This feature has some overlap with the jump list (<c-o>/<c-i>) and
with undo (u) but each of the three features have their moment.
Currently there's no special integration with either peer feature;
the three histories are completely independent. In future we might
want to synchronize them so we can implement Sublime Text's "Soft
undo" feature.
Note that it is possible to restore selections that predate a buffer
modification. Depending on the buffer modification, the selections
might look different of course. (When trying to apply an old buffer's
selection to the new buffer, Kakoune computes a diff of the buffers
and updates the selection accordingly. This works quite well for
many practical examples.)
This makes us record the full history of all selections for each
client. This seems wasteful, we could set a limit. I don't expect
excessive memory usage in practice (we also keep the full history of
buffer changes) but I could be wrong.
Closes#898
To be able to undo selection changes, we want to record selections
from all commands that modify selections. Each such command will get
its own private copy of the selections object.
This copy will live until the command is finished executing.
All child commands that are run while the command is executing,
will also use the same copy, because to the user it's all just one
selection change anyway.
Add an RAII object in all places where we might modify selections.
The next commit will use this to create the private selections copy
in the constructor (if there is none) and remove redundant history
items in the destructor.
We could avoid the RAII object in some places but that seems worse.
For lifetimes that don't correspond to a lexical scope, we use a
std::unique_ptr. For lambdas that require conversion to std::function,
we use std::shared_ptr because we need something that's copyable.
This makes the function easier to find for newcomers because
to_string() is the obvious name. It enables format() to do the
conversion automatically which seems like good idea (since there is
no other obvious representation).
Of course this change makes it a bit harder to grep but that's not
a problem with clang tooling.
We need to cast the function in one place when calling transform()
but that's acceptable.
Terminals that support CSI u escape codes (like iTerm2, Kitty and foot)
allow us to map <s-backspace> independently of <backspace>.
Users expect that <s-backspace> does the same as <backspace>,
especially when typing ALL_CAPS. Make it so.
The first version of 0cf719103 (Make Shift+Space insert a space in
insert mode, 2022-02-09) did that already but I later dropped it
because I wasn't sure if it's right.
Insert mode completions are accepted by typing any key. For example,
if there is a completion "somefunction()", then typing
some<c-n>;
will insert
somefunction();
and then the InsertCompletionHide hook will fire. The hook parameter
is a range that contains the entire thing: the actual completion plus
the trailing semicolon that closed the completion menu.
The [original motivation] for the hook parameter was to support
removing text inserted by completion, so we can apply text edits
or expand snippets instead. One problem is that we don't want to
remove the semicolon. Another problem came up in a discussion
about [snippets]: let's say we have a snippet "add" that expands to
add(?, ?)
where ? are placeholders. After snippet expansion the cursor replaces
the first placeholder. If I type "ad<c-n>1" I expect to get "add(1, ?)".
If the InsertCompletionHide hook only runs after processing the "1"
keystroke, this is not possible without evil hacks.
Fix these problems by running InsertCompletionHide when a completion is
accepted _before_ inserting anything else into the buffer. This should
make it much easier to fully implement [LSP text edits]. I doubt
that anyone besides kak-lsp is using the hook parameter today so this
should be a low-risk fix.
[original motivation]: https://github.com/mawww/kakoune/issues/2898
[snippets]: https://github.com/kak-lsp/kak-lsp/pull/616#discussion_r883208858
[LSP text edits]: https://github.com/kak-lsp/kak-lsp/issues/40
Deleting a buffer resets normal mode on all clients that were
displaing that buffer, but ScopedForceNormalMode that are used
from user mode do not take this possiblity into account on
destruction, which leads to deleting the last normal mode from
the context, ending up with an empty mode stack.
Fixes#3909
In normal mode, the mode line contains "1 sel" or "n sels (k)" when n > 1,
whereas in insert mode, it contains "n sels (k)" even for n == 1. Change
the contents in insert mode to match normal mode.
They are quite different use cases, and this allow moving InsertMode
to input_handler.hh which is what uses it.
This also cleans up the code as we can get rid of get_insert_pos and
rely more on SelectionList::for_each.