summaryrefslogtreecommitdiff
path: root/src/buffer.hh
AgeCommit message (Collapse)Author
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-03Prevent deletion of buffers while creating new windowsMaxime Coste
`kak -n -E 'hook global WinCreate .* %{ delete-buffer }'` was crashing because we would delete the buffer during window construction, which would not be able to delete the window as it was not fully constructed and registered yet. This led to a window referencing a deleted buffer. Fixing this by deleting the window later on failed because we can enter an infinite loop where we constantly create a new *scratch* buffer, then a window to display it, which deletes that buffer. Make it an error to try to delete a buffer while a new window is being setup by adding a Locked flag to buffers and checking that in BufferManager::delete_buffer Fixes #5311
2025-05-23Disable BufSetOption hook during buffer registrationMaxime Coste
The hook is manually triggred at the end of registration, by disabling it we avoid the hook being potentially called multiple times due to interaction with other hooks. Fixes #5324
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.
2025-02-04Revert "WIP linked list shared strings"Maxime Coste
This got pushed by accident This reverts commit 2856b99e0914cc7a659977f2b33308cb5b4c9bb7.
2025-01-22WIP linked list shared stringsMaxime Coste
2024-12-03Compact BufferIterator to avoid paddingMaxime Coste
2024-12-03Do not store buffer pointer in BufferIteratorMaxime Coste
This makes BufferIterator smaller and trivially move/copyable
2024-11-30Cache buffer lines ArrayView in BufferIteratorMaxime Coste
The extra indirection of going through the buffer can be costly as the compiler does not know the buffer is not supposed to be mutated during iteration, so it has to actually reload the values which adds memory accesses in the Buffer instance which can be costly in say regex searches where memory access tends to dominate performance. Storing this in the BufferIterator lets the compiler put this info in registers and not reload it.
2024-08-15Remove unused ConstexprVector and rename constexpr_utils.hh to array.hhMaxime Coste
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-01-21Replace std::strong_ordering with auto return type to not require <compare>Maxime Coste
2022-11-20Change BufferIterator comparison to assert same bufferMaxime Coste
Comparing iterators between buffers should never happen, and the only place we did was with default constructed BufferIterator which we replace by casting the iterator to bool. This should improve performance on iterator heavy code.
2022-07-05Distinguish between non-eol max column target and plain max columnMaxime Coste
2021-11-21Convert comparisons to spaceship operatorMaxime 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
2020-01-01Add 'history' and 'uncommitted_modifications' expansionsJason Felice
2019-12-19Update fs status post buffer writeMaxime Coste
2019-12-18Cleanup replaced range selection logicMaxime Coste
Do not access Buffer::m_changes to find the inserted range, return it directly from Buffer::insert and Buffer::replace. This fixes a wrong behaviour where replacing at eof would lose the selected end of line (as the implementation does not actually replace that end of line)
2019-12-04Merge remote-tracking branch 'lenormf/reload-buffer-hash'Maxime Coste
2019-12-03src: Reload buffers when their contents' hash changesFrank LENORMAND
Instead of triggering a reload event when the timestamp of a buffer's underlying file changes, do so when its contents are actually modified.
2019-11-29buffer.hh: Fix building on musl+libc++Kylie McClain
Fixes #3233.
2019-11-09Add static or const where usefulJason Felice
2019-10-17Remove explicit sizes from make_array callsMaxime Coste
2019-01-20Fix warning on gcc 8Maxime Coste
2018-11-01Use BufferCoord sentinel type for regex matching on BufferIteratorsMaxime Coste
BufferIterators are large-ish, and need to check the buffer pointer on comparison. Checking against a coord is just a 64 bit comparison.
2018-10-30Buffer: Remove m_line_count field from BufferIteratorMaxime Coste
It seems unlikely this would give performance gain, as buffer lines are always accessed when we read that field, leading to all the necessary data already being in memory. Removing it reduces the size of a BufferIterator, which are already pretty hefty objects.
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-05-09Mark Client, Window, Buffer and OptionManager as finalMaxime Coste
Avoids warning about non virtual destructor calls on them, as they have a vtable due to OptionManagerWatcher.
2018-05-02Refactor buffer undo treeMaxime Coste
Store the undo tree as an array of undo nodes, instead of as a pointer based tree.
2018-03-13Do not jump to buffer start on `g.` with no previous modificationsMaxime Coste
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.
2017-11-12Move Array and ConstexprVector to a constexpr_utils.hh headerMaxime Coste
2017-09-20Add max_history_id in status printed with <a-u> and <a-U>Delapouite
2017-08-18Respecify EnumDescs array sizes manually to workaround clang-3.6 bugMaxime Coste
2017-08-12Remove size redundancy in enum_desc function declarationMaxime Coste
The need to have the array size in the return type was redundant with the actual list of elements.
2017-08-04Purge history on buffer reload when NoUndo flag is onMaxime Coste
We were preserving the history in that case, so on fifo buffers (that set the NoUndo flag until the fifo is closed), we still had the history from the "previous life" of the buffer, leading crashes when trying to apply it. Fixes #1518
2017-07-07Formatting fixesMaxime Coste
2017-06-11Fix the Buffer::end() madnessMaxime Coste
Until now, buffer had multiple recognized end coordinates, either { line_count, 0 } or { line_count - 1, line[line_count - 1].length }. Now the only correct end coord is { line_count, 0 }, removing the need for various special cases.
2017-06-07noexept-ify BufferIterator methodsMaxime Coste
2017-06-07Use String default ctor instead of empty stringMaxime Coste
2017-05-22Do not avoid eol in insert mode vertical movementMaxime Coste
2017-05-22Remove virtual destructor from OptionManagerWatcherMaxime Coste
We should never destruct anything through an OptionManagerWatcher pointer, so having all those destructor virtual makes no sense.
2017-05-07Respect tabstop in Buffer::offset_coordMaxime Coste
2017-03-16Try to clean up option include a bitMaxime Coste
2017-03-15Small code tweaks regarding flags handlingMaxime Coste
2017-03-15Migrate WithBitOps template specialization to with_bit_ops functionMaxime Coste
This way we dont depend on knowing the base template to enable bit ops on an enum type.
2017-03-15Migrate to a more value based meta programming modelMaxime Coste
Introduce Meta::Type<T> to store a type as value, and pass it around, migrate enum_desc and option_type_name to this.
2017-02-20Fix performance of word completion with many different selectionsMaxime Coste
Fixes #1228