summaryrefslogtreecommitdiff
path: root/src/buffer_utils.cc
AgeCommit message (Collapse)Author
2025-07-08Replace on_scope_end with CTAD with OnScopeEnd directlyMaxime Coste
2025-07-08Merge remote-tracking branch 'pjungkamp/history'Maxime Coste
2025-07-05Introduce `history_since_<id>` value expansionPhilipp Jungkamp
The `history_since_<id>` value expansion allows incremental parsing of a buffer's history. declare-option int my_last_history_id define-command my-process-history ... # process the initial buffer history my-process-history %val{bufname} 0 %val{history} set-option buffer my_last_history_id 0 # only process new history changes on idle hook buffer NormalIdle %{ evaluate-commands %exp{ my-process-history \ %%val{bufname} \ %%opt{my_last_history_id} \ %%val{history_since_%opt{my_last_history_id}} } set-option buffer my_last_history_id %val{history_id} }
2025-06-26Fix flaky blame-in-diff test and "edit -fifo" in BufCloseFifoJohannes Altmanninger
This test uses ui_out and ui_in to coordinate events. This is brittle[1] because ui_out behavior depends on timing. Since this test doesn't really care about intermediate UI state, express the sequence using BufCloseFifo instead. This hits another issue: inside git blame-jump's BufCloseFifo, we run git blame, which runs another "edit -fifo .. *git*". A special aspect of fifo buffers is that any existing *git* buffer will be reused instead of being recreated[2]. After BufCloseFifo, the fifo watcher destructor will reset the fifo flag, even if BufCloseFifo has recreated the fifo buffer. This breaks invariants and causes the next fifo watcher destructor do fail its assertion. Let's not reset fifo flags in this case. This should be safe because it's the very last thing the fifo watcher does, so it's okay if another one is active now. Alternatively we could reject this kind of recursion, or implement it in a different way (using ScopedSetBool for the flags). Reported-by: Nico Sonack <nsonack@herrhotzenplotz.de> [1]: https://lists.sr.ht/~mawww/kakoune/%3C20241210100417.1150697-1-aclopte@gmail.com%3E [2]: This removes the need to use delete-buffer which also ensures that the buffer remains visible in any client it's already shown.
2025-02-19Cleanup file.cc/hh dependenciesMaxime Coste
file.cc/hh should not know about Context, Buffer, etc... It should be a pretty low level set of helper functions. Move buffer related functions to buffer_utils and extract busy indicators to callers.
2024-12-01Fix extra newline inserted into stdin buffersJohannes Altmanninger
Commit c3b01a3c9 (Add back option to scroll in stdin buffers, 2024-11-27) missed the case where the initial read from stdin had no trailing newline: for i in $(seq 50); do printf .; sleep .1; done | kak After the first read, we transplant the initial newline to end. This creates an extra newline because we already added a fake newline to uphold buffer invariants. Fix that.
2024-12-01Scrolling BufReadFifo to not not report final empty lineJohannes Altmanninger
Whereas nonscrolling fifos generally[^1] append to the very end of the buffer, scrolling fifos generally insert *before* the final empty line. This means that every single BufReadFifo hook in a scrolling fifo will report an additional newline. This is clearly wrong. Even reporting it only once would be wrong, because the newline is not added by a fifo read. This behavior has always existed for "edit -scroll -fifo" buffers. For stdin buffers, it was re-introduced in c3b01a3c9 (Add back option to scroll in stdin buffers, 2024-11-27). Fix this by ending the reported range before the final empty line. Handle one edge case: if the inserted range did not end with a newline, the final empty line collapses into the previous line. In this case we already don't report the newline because it's declared "artificially-added" by 658915086 (Fix BufReadFifo overlapping range on partial line, 2024-11-23). This fixes the problem described at https://github.com/mawww/kakoune/issues/5255#issuecomment-2505650511 Tests are copied verbatim from the no-scroll cases (not yet sure how to share logic / parameterize a test in a nice way): $ diff -ur test/commands/fifo-read-ranges{,-scroll} -edit -fifo fifo *fifo* +edit -fifo fifo -scroll *fifo* $ diff -ur test/commands/fifo-read-ranges-noeol{,-scroll} -edit -fifo fifo *fifo* +edit -fifo fifo -scroll *fifo* [^1]: unless the very last character is a fake newline (except for the first read, to not scroll) which we already don't report.
2024-11-28Add back option to scroll in stdin buffersJohannes Altmanninger
Commit 582c3c56b (Do not add trailing newline to non-scrolling fifo buffers, 2024-01-28) completely forgot about stdin buffers, breaking the ability to make them scrolling via "ge". For example while sleep 1; do seq $LINES date done | kak Let's fix that by adding the trailing newline back for stdin buffers. Unlike "edit -scroll", don't scroll until the user explicitly moves the cursor.
2024-11-28Fix BufReadFifo overlapping range on partial lineJohannes Altmanninger
As reported in [1], when reading from a fifo a buffer that is not newline-terminated, we add a newline automatically, and include that in the range reported to BufReadFifo. I'm not 100% sure if this is really wrong but since the typical consumer of BufReadFifo does something like select %val{hook_param} exec |grep foo<ret> it seems safe to remove this newline; doing so means that 1. "grep foo" will no longer see a newline in stdin, which seems good. 2. Kakoune will strip a trailing newline from the command output, since the input didn't have one. So the input is the same. Let's remove any artificially-added newline from the hook parameter. [1]: https://lists.sr.ht/~mawww/kakoune/%3CZzXjfXnETd2gbeXa@thristian.org%3E
2024-11-28Fix overlapping range passed to BufReadFifo in non-scrolling fifosJohannes Altmanninger
On the first read from a nonscrolling fifo, we insert after the buffer contents (which is just "\n"), and later delete the redundant newline (582c3c56b (Do not add trailing newline to non-scrolling fifo buffers, 2024-01-28)). This deletion invalidates inserted ranges passed to BufReadFifo. Fix that. The test uses another fifo to pass ranges. I guess it could use "ui_out -until" as well but this seems simpler. The test script needs a fd but 3 and 4 are already taken so use 5. I didn't find a portable way to check if it's already taken. Fixes #5255
2024-08-12Move debug utils to debug.hh/debug.ccMaxime Coste
Lots of code includes buffer_utils.hh just for write_to_debug_buffer which pulls many unnecessary dependencies. Reorganise to reduce compile times.
2024-04-27Ensure re-used fifo buffers makes that buffer the latest openedMaxime Coste
2024-02-28Use std::find when detecting end of line formatMaxime Coste
2024-02-28Templatize StringData::createMaxime Coste
This improves performance by letting the compiler optimize most use cases where string count and length are known are compile time.
2024-02-18Try to fix crash due to fifo read regressionJohannes Altmanninger
I saw a crash when running git log --oneline %arg{@} hook -once buffer NormalIdle .* %{ execute-keys -draft \ %{gk!} \ %{git diff --quiet || echo "Unstaged changes";} \ %{git diff --quiet --cached || echo "Staged changes";} \ <ret> } Backtrace (I still have GDB attached): #4 0x00006502c740b13f in Kakoune::operator- (rhs=..., lhs=...) at /home/johannes/git/kakoune/src/units.hh:33 33 { return RealType(lhs.m_value - rhs.m_value); } (gdb) up #5 Kakoune::Buffer::next (coord=..., this=0x6502c90d7ff0) at /home/johannes/git/kakoune/src/buffer.inl.hh:18 18 if (coord.column < m_lines[coord.line].length() - 1) (gdb) up #6 FifoWatcher::read_fifo (this=0x6502c90d9e48) at buffer_utils.cc:252 252 m_buffer.erase(pos, m_buffer.next(pos)); This was introduced in 582c3c56b (Do not add trailing newline to non-scrolling fifo buffers, 2024-01-28). The problem seems to be that we call "m_buffer.next()" on a position that is past-end the buffer, so m_lines[coord.line] is out-of-bounds. Fix it. For some reason I have not managed to reproduce the crash, not even with sanitize=address. There might be another problem: m_had_trailing_newline is intentionally uninitialized because it is supposed to be read only on the second read() with a positive return value. Unfortunately I think it's possible that e.g. a NormalIdle hook inserts some text before the first positive read(). Then, this line const bool is_first = pos == BufferCoord{0,0}; if (not m_scroll and (is_first or m_had_trailing_newline)) pos = m_buffer.next(pos); will read uninitialized "m_had_trailing_newline". Fix that too, to be on the safe side. Sadly I don't have a test for this one either so I'm not sure.
2024-02-06Use different hash algorithms for strings and file hashingMaxime Coste
For hash map, using fnv1a is faster as it is a much simpler algorithm we can afford to inline. For files murmur3 should win as it processes bytes 4 by 4.
2024-01-30Do not add trailing newline to non-scrolling fifo buffersJohannes Altmanninger
Internally, all lines have a trailing "\n". Buffers created empty (like fifo buffers) start with a single line. When reading data into fifo buffers, we insert *before* the last line's trailing newline ("last newline"). This enables autoscrolling (enabled with "edit -scroll") as long as the cursor is on the last newline. When autoscrolling is disabled, we have a special case to insert *after* the last newline. This means that a cursor on that newline won't be moved. Then we transplant the newline character from the beginning to the end of the buffer. This special case happens only on the very first fifo read; on subsequent reads, the cursor at position 1.1 will not be moved anway because insertions happen below 1.1. Since we always insert (effectively) before the last newline, fifo buffers have a trailing empty line. For autoscrolling buffers this seems correct; it gives users an obvious way to toggle autoscrolling. For non-scrolling buffers the newline is redundant. Remove it. This requires keeping track of whether the last newline comes from the fifo, or was added by us. The shortest fix I could find is to always append to the buffer if not scrolling, and then delete the added newline character if applicable. m_buffer.insert(m_scroll ? pos : m_buffer.next(pos), StringView(data, data+count)); if (not m_scroll and not m_had_trailing_newline) m_buffer.erase(pos, m_buffer.next(pos)); maybe that's the best fix overall; but erasing at the end seems better than erasing in the middle, so do that whenever possible. Reported in https://lists.sr.ht/~mawww/kakoune/%3CZbTK7qit9nzvrMkx@gmail.com%3E
2023-10-25Clear buffer values on fifo buffer recreationMaxime Coste
The cached WordDB/Highlighters/FifoReader are not relevant and are better fully rebuilt than updated. This speeds up rebuilding the WordDB of big fifo buffers such as a `git log`.
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-04-17Switch undo storage from a tree to a plain listOlivier Perret
Whenever a new history node is committed after some undo steps, instead of creating a new branch in the undo graph, we first append the inverse modifications starting from the end of the undo list up to the current position before adding the new node. For example let's assume that the undo history is A-B-C, that a single undo has been done (bringing us to state B) and that a new change D is committed. Instead of creating a new branch starting at B, we add the inverse of C (noted ^C) at the end, and D afterwards. This results in the undo history A-B-C-^C-D. Since C-^C collapses to a null change, this is equivalent to A-B-D but without having lost the C branch of the history. If a new change is committed while no undo has been done, the new history node is simply appended to the list, as was the case previously. This results in a simplification of the user interaction, as two bindings are now sufficient to walk the entire undo history, as opposed to needing extra bindings to switch branches whenever they occur. The <a-u> and <a-U> bindings are now free. It also simplifies the implementation, as the graph traversal and branching code are not needed anymore. The parent and child of a node are now respectively the previous and the next elements in the list, so there is no need to store their ID as part of the node. Only the committing of an undo group is slightly more complex, as inverse history nodes need to be added depending on the current position in the undo list. The following article was the initial motivation for this change: https://github.com/zaboople/klonk/blob/master/TheGURQ.md
2023-02-10Avoid extra indirection for storing FifoWatcherMaxime Coste
By improving the Value interface we can avoid storing a unique_ptr to a FifoWatcher and directly store the FifoWatcher.
2021-05-28Fix File Buffer flag not being correctly appliedMaxime Coste
2021-05-28Support opening files bigger than 2 GiBMaxime Coste
The real technical limit is with lines bigger than 2 GiB and buffers with more than 2 Gi lines, refactor buffer loading to make it possible to load those files. Fix an overflow with the hash_data function at the same time
2021-03-31Parse more data at each fifo buffer readMaxime Coste
2021-03-11Do not select on non-urgent fd when handling only urgent eventsMaxime Coste
This avoids 100% CPU usage when we have pending fifo input while running a shell process, as we will not end-up busy looping in pselect but not reading the available data due to being only processing urgent events.
2020-06-27Refactor how InsetCompletionHide hook parameter is computedMaxime Coste
Keep track of inserted ranges instead of trying to re-derive them. Fixes #3556
2020-05-10Support piping data to client stdinMaxime Coste
Pass the client stdin fd to the server and open a fifo buffer from it. Fixes #3394
2020-03-14Allow reading from fifo in readonly buffersMaxime Coste
readonly is supposed to prevent the user from modifying the buffer and it can be useful to generate a readonly fifo buffer. Fixes #3398
2020-03-02Expand env vars as list of stringsMaxime Coste
This makes it possible to do :select `%val{selections_decs}` and to correctly combine $kak_quoted with those.
2020-01-09Fix compilation on 32bit platformsMaxime Coste
Fixes #3284
2020-01-02Few style changes on history exposition codeMaxime Coste
2020-01-02Merge remote-tracking branch 'eraserhd/history-api'Maxime Coste
2020-01-01Add 'history' and 'uncommitted_modifications' expansionsJason Felice
2019-12-28Refactor fifo buffer reader codeMaxime Coste
2019-11-12Fix display column computationsJason Felice
Closes #3201
2019-11-12Add support for selecting and exporting selections in display columnsMaxime Coste
Fixes #2724
2019-06-11Fix emission of BufReadFifo eventsJason Felice
The hook parameter should not be adjusted for the prevention of scrolling. Also, ensure that the last BufReadFifo is triggered if we encounter an error or EOF after appending some data to the buffer. Closes #2946
2018-11-14Change BufReadFifo hook param to contain the inserted rangeMaxime Coste
the buffer name was not a very interesting information, whereas the buffer range allows a hook to run only on the appended text instead of all the buffer.
2018-10-23Refactor Hook management to have a well defined list of hooksMaxime Coste
Hooks are now an enum class instead of passing strings around.
2018-02-11Refuse modification of ReadOnly buffers and make Debug buffer readonlyMaxime Coste
The debug buffer is a bit special as lots of events might mutate it, permitting it to be modified leads to some buggy behaviour: For example, `pipe` uses a ForwardChangeTracker to track buffer changes, but when applied on a debug buffer with the profile flag on, each shell execution will trigger an additional modification of the buffer while applying the changes, leading to an assertion failing as changes might not be happening in a forward way anymore. Trying to modify a debug buffer will now raise an error immediatly.
2018-02-05Remove the `New` flag from a buffer after reloading itMaxime Coste
If we reload a buffer, it means its underlying file exists, hence the New flag does not make sense anymore. It could be that the file appeared on the filesystem in the meantime.
2017-08-29Do less implicit parse_filename callsMaxime Coste
2017-03-08Add a -debug flag to :edit to set the buffer as debug dataMaxime Coste
As for the *debug* buffer, buffers with the debug flag wont get used for cycling through buffer, or word completion.
2017-01-25Fix fifo reading not handling potential errors from the read callMaxime Coste
Fixes #1153
2016-12-03Change ValueId to just be an enum class, it does not need any operatorsMaxime Coste
2016-12-01Make FDWatcher support Read, Write and Except events, instead of just ReadMaxime Coste
2016-11-28Cleanup include dependencies a bitMaxime Coste
2016-11-14Propagate the hooks disabled state through prompt, menu, and command executionMaxime Coste
Maintain it as well during buffer creation even if the hooks are not executed in client context. Fixes #818
2016-10-23Re-enable undo support on fifo buffers when the fifo closesMaxime Coste
Fixes #881
2016-10-01Rename get_width to codepoint_widthMaxime Coste