summaryrefslogtreecommitdiff
path: root/src/normal.cc
AgeCommit message (Collapse)Author
2025-07-10More CI compilation fixesMaxime Coste
2025-07-08Replace on_scope_end with CTAD with OnScopeEnd directlyMaxime Coste
2025-06-30Stop apply_diff() from creating non-monotonic changesJohannes Altmanninger
Commit ba41928aa (Remove spurious newline when | replaces at buffer end, 2024-11-28) also tried to fix a "DiffOp::Add" code path. Unless I'm misremembering, I had run into a crash and extracted this unit test. When apply_diff() decides to erase the last line, and then insert something at the end, buffer changes might look like: {.type=Erase, .begin={2, 0}, .end={3, 0}} {.type=Insert, .begin={1, 5}, .end={5, 0}} The "{1, 5}" is caused by "pos = buffer.prev(pos);" added by the aforementioned commit. It's problematic because it breaks the caller's "ForwardChangesTracker" invariant: the previous Erase leaves the cursor at {2, 0}, so the insert cannot start before that. Additionally, the inserted range returned by apply_diff() would be "{ {2, 0}, {4, 0} }" whose end position is weirdly different from the Insert's end position. It questionable that we are passing on this weird state. The "pos = buffer.prev(pos);" statement was added so we actually delete the current final newline. We still leave "tried_to_erase_final_newline" set, meaning we'll also delete the the final newline after we're done. But deleting the "current final newline" the way we do it is confusing, because we do it at every step DiffOp::Add step. This would blow up if there are multiple successive contiguous DiffOp::Add events. I doubt this ever happens but it's still confusing. Remove this logic, and restore historical behavior in case we append at the buffer end. This does not break the system test added by ba41928aa because in that case, we 1. first delete the entire buffer, setting pos={0, 0}, but also restoring the EOL invariant, so the end position would be {0, 1}. 2. then we insert at pos={0, 0}, and since "buffer.is_end(pos)" is false we don't run into this bad code path. While at it add an assertion to clarify that we already assume that the diff algorithm never gives us empty DiffOp::Keep, and always monotonically increasing positions, except for the very special case where we deleted until buffer end, which should already be handled. The unit test is not perfect because it depends on the current behavior of the diff algorithm.
2025-06-26Remove spurious newline when | replaces at buffer endJohannes Altmanninger
My kak -e "exec %{%ca<ret>b<esc>%|printf '\n\n'<ret>}" adds a spurious third line. When we replace up to the end everything, we keep around a single newline to uphold the buffer invariant, but that newline Commit de1433d30 (Avoid the spurious newline insertion when replacing at end of buffer, 2016-03-16) fixed an issue for most commands that replace until the buffer end. A similar issue exists for the "|" command. It triggers in fewer cases because the replacement is implemented by applying edits computed by the diff algorithm. It does trigger when "|" replaces the entire buffer. Fix that by erasing the spurious newline. Alternatively, we could allow the diff steps of kind "remove" to delete the entire buffer, and only restore the invariant after the whole diff is applied. This should work because the one-past-end position is valid for Buffer::insert() even if the buffer is empty. It is not valid for Buffer::erase() or Buffer::advance() where count>0 but if we do that when we're already at the buffer end, that is probably a bug in the diff. I tried this but ran into a assertion in ForwardChangesTracker (kak_assert(change.begin >= cur_pos)). Alternatively, we could change the diff algorithm to always insert before deleting. I encountered this issue when using ansi-enable on a fifo buffer. Specifically, the first BufReadFifo hook would replace the entire inserted text but leave around a spurious newline.
2025-06-19Merge remote-tracking branch 'SeerLite/macro-disable-keymaps'Maxime Coste
2025-05-29Merge overlapping selections before replacing charactersMaxime Coste
Without doing this, replace with multiple selection at buffer end breaks as the first selection will replace the end-of-line with a non-eol character, then a new eol will automatically be added which will put remaining selections past the end of the buffer. Fixes #5316
2025-05-11Use linewise paste only if register is missing no trailing newlineJohannes Altmanninger
We use linewise paste if any of the pasted register elements has a trailing newline. As shown in the previous patch, this leads to awkward situations where insertion positions from <a-P> are not monotonically increasing. This complicated behavior is questionable. The root cause is that linewise paste may insert some strings that don't have a trailing newline. This leads to weird cases of GIGO, especially when using <a-P> when the last element is missing a trailing newline. Simplify the implementation by not activating linewise paste in that case. Instead of special-casing the last element, try to simplify the behavior further by using line-wise paste only if *all* elements are properly terminated. I can't think of a real-world case where the existing behavior would be desired. A regression test shows a change in behavior. Might be less weird now. The added test case is a copy except it uses "P" instead of "p" (the extra newline is because "d" deletes the last newline in the buffer which gets added back implicitly). (I think the list of register elements is never empty, so this should never cause a trivial linewise paste. Even if so, that would be fine because inserting nothing is a nop either way.) Fixes #5312
2025-05-11Fix <a-?> crash when first selection wrapsJohannes Altmanninger
The <?> and <a-?> commands drop selections where the search wrapped. If a selection is dropped this way, we adjust the new main index. If the very first selection is dropped this way, *and* it happens to be the main index, "--main_index" overflows and chaos ensues. Fix this by saturating main index at zero. This seems more intuitive than wrapping around ("% new_sels.size()"). This issue only happens to <a-?>, not <?>. When <?> wraps when starting from the first selection, it necessarily also wraps after all other selections. (Based on this insight, I started drafting an optimization to skip searches whose results would be discarded anyway because they will definitely wrap. Not sure if it's worth it, since it applies only to the rare edge case of <?>/<a-?> with multiple selections.) Fixes #5314
2025-04-15Disable keymaps when playing macroSeerLite
Macros are already recorded with keymaps resolved, so there's no need to resolve them again.
2025-03-24Fix prompt history recording when using mapped keysJohannes Altmanninger
Commit e3122ab2c (Refactor prompt history handling, 2023-07-05) was a nice simplification but it breaks a rare edge case. It suppresses history recording if all keys the prompt receives were synthesized. That's not quite the right criteria: it means that if prompt is created, edited and and executed, all via mapped keys, we fail to add to history. The criteria should rather be something like "if all keys the prompt receives came from synthesized events". Make it so. This allows us to get rid of the "noninteractive" nested bool that was only used for disabling history.
2025-03-24Default InputHandler::handle_key() synthesized argumentJohannes Altmanninger
We have only one place where we handle actual keys typed by the user.
2024-10-22Remove now unused CompletionFlagsMaxime Coste
Since shell-script-completions now runs the script asynchronously and unconditionally, there is no use for the CompletionFlags::Fast anymore which means we can remove that type altogether.
2024-08-26Do not gather full input data in a single string when pipingMaxime Coste
Refactor ShellManager and pipe to feed lines from the buffer directly, this should reduce memory use when piping big chunks of buffers. The pipe output is still provided as a single big buffer.
2024-08-16include headers cleanupAdriĆ  Arrufat
2024-08-12Reduce headers dependency graphMaxime Coste
Move more code into the implementation files to reduce the amount of code pulled by headers.
2024-07-27Reduce templatization further to reduce binary sizeMaxime Coste
2024-07-24De-templatize regex selection codeMaxime Coste
This led to lots of duplicated code gen, longer compile time, and most likely unnoticeable performance difference
2024-07-24Merge remote-tracking branch 'JustTaken/view-offset'Maxime Coste
2024-07-22Fix logic to get minimun custom offsetJustTaken
Now the scrolloff can be specified in the configuration file and if either one of the column or line offset given is too large to fit in the buffer, half of the window dimension is taken in it's place. `v<` and `v>` account custom scroll offset as well.
2024-07-22Handle word completion when recording macrosMaxime Coste
Make last insert and macro recording closer together, paving the way towards moving last insert to a register. Use a FunctionRef for insert completer key insertion support.
2024-07-20Take in account scrolloff when moving viewportJustTaken
`vt` and `vb` respect custom scroll offset
2024-07-21De-templatize select_objectMaxime Coste
This removes lots of duplicated codegen at the expense of slightly worse constant folding optimizations
2024-06-24Remove some selection copies in pipe and throw early if read onlyMaxime Coste
Throwing early avoids losing selections in this case.
2024-05-31Add v< and v> to scroll cursor to the leftmost/rightmost columnMaxime Coste
2024-04-12Rotate through strings when pasting instead of repeating the lastMaxime Coste
This seems like a better overall behaviour. Closes #5135
2024-03-23Add some missing ScopedEdition and fix redoMaxime Coste
tabs <-> space conversion functions did not create a ScopedEdition leading to uncommited modifications. Fixing this did fix the interactive error, but that error still existed in non interactive context so redo now considers there there is no redo child if there are uncommited modifiations (which is correct as this means we are currently creating a new leaf in the undo tree) Fixes #5124
2024-01-15Don't modify prompt history when validating empty inputJohannes Altmanninger
Fixes #5076
2023-12-06Hide empty and undocumented mappings from autoinfoChris Webb
Users who rebind default keys and unmap the originals by binding them to empty strings with empty docstrings end up with empty lines in the autoinfo. For example, https://github.com/mawww/kakoune/issues/4918. Hide completely null bindings which have both an empty mapping and an empty docstring in the autoinfo, as an easy mechanism for these users to eliminate the UI noise. Fixes https://github.com/mawww/kakoune/issues/4918
2023-11-14Use a separate copy of the command completer for each completionMaxime Coste
This make the completer lifetime tied to the Prompt mode and removes the need for the Start flag. It also makes it possible to cleanup on completer destruction.
2023-11-11Fix spurious incremental search when incsearch=falseJohannes Altmanninger
Regressed in a2c41593a (Fix partial regex text being pushed in history, 2023-11-02).
2023-11-03Use explicit target types for gather calls to bypass clang regressionMaxime Coste
Since clang-16 there has been a regression in the P0522R0 support. (Bug report at https://github.com/llvm/llvm-project/issue/63281) Closes #4892
2023-11-02Fix partial regex text being pushed in historyMaxime Coste
2023-10-04Refactor regex_prompt logic and fix function being called on abortMaxime Coste
Fixes #4993
2023-09-08Revert "Do not make cursor visible on force redraw"Maxime Coste
This unfortunately breaks the testing framework, more work necessary before we can do that. This reverts commit 9b1f4f5f204072ceec6481c2b57a7c4c66d8feab.
2023-09-08Do not make cursor visible on force redrawMaxime Coste
2023-09-02Do not make cursor visible after mouse scrolling and view commandsMaxime Coste
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.
2023-08-27Remove Window::force_redraw()Maxime Coste
This was mostly redundant with Client::force_redraw.
2023-08-23Revert "Only make cursor visible after buffer or selection change"Maxime Coste
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 1e38045d702ec6eb2425016d9b02636270ab1b1e. Closes #4963
2023-08-16Only make cursor visible after buffer or selection changeMaxime Coste
Kakoune now does not touch cursors when scrolling. It checks if either the buffer or selections has been modified since last redraw. Fixes #4124 Fixes #2844
2023-08-14Change `+` command not to duplicate identical selections more than onceMaxime Coste
The current exponential behaviour does not seem that useful, it seems more predictible that pressing `+` twice would end up with 3 copies of the original selections instead of 4. Fixes #4533
2023-08-13Minor formatting tweaksMaxime Coste
2023-08-05Removed unused capturesMaxime Coste
2023-07-05Refactor prompt history handlingMaxime Coste
Share incremental regex logic, pass the synthetized nature of keys through to input handlers.
2023-07-05Merge remote-tracking branch 'krobelus/allow-history-in-mappings'Maxime Coste
2023-07-03Merge common docstring in key mapping assistantMaxime Coste
Fixes #4942
2023-06-17Disable history only for prompts that are never shown in the UIJohannes Altmanninger
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.
2023-06-17Rename "disable_history" stack state to "noninteractive"Johannes Altmanninger
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 :(
2023-06-17Revert "Switch undo storage from a tree to a plain list"Maxime Coste
Moving across history moved to <c-j>/<c-k> to keep <a-u>/<a-U> for selection undo/redo This reverts commit e0d33f51b36c9f0be7ae2467dab455d211bbf561.
2023-05-29Refactor KeymapManager to enfore setting is_executing on key iterationMaxime Coste
Add an iterator based remove to HashMap as that was missing. Make KeymapManager responsible for throwing on unmap an executing mapping.
2023-05-25unmap: fail if the mapping is currently executingJohannes Altmanninger
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