Commands added:
* `move_anchored_line_up`
* `move_anchored_line_down`
* `move_anchored_visual_line_up`
* `move_anchored_visual_line_down`
* `extend_anchored_line_up`
* `extend_anchored_line_down`
* `extend_anchored_visual_line_up`
* `extend_anchored_visual_line_down`
These new commands move cursors vertically. A cursor will move depending
on its position:
* If it is on a newline character of a non-empty line, the cursor will
stay on newlines (i.e. on a line's last character).
* If it is on a non-newline character of a non-empty line, the cursor
will try to avoid newline characters. It will move normally, but if
it would end up on a newline, instead it will be moved one position
left of it (i.e. the line's second to last character).
* If it is on the newline character of an empty line (that contains
nothing except the newline character), the cursor will continue to
move like before: If it stayed on newline before, it will continue to
do so. Otherwise it will try to avoid them (except on empty lines).
Commands added:
* `move_same_line_char_left`
* `move_same_line_char_right`
* `extend_same_line_char_left`
* `extend_same_line_char_right`
* `append_mode_same_line`
These new commands move cursors, while making them stay in the same
line. So if a cursor would wrap around into another line, instead it
won't move and stay at its current position.
We clone this type very often in LSP pickers, for example diagnostics
and symbols. We can use a single Arc in many cases to avoid the
unnecessary clones.
The lsp location type has the lsp's URI type and a range. We can replace
that with a custom type private to the lsp commands module that uses the
core URI type instead.
We can't entirely replace the type with a new Location type in core.
That type might look like:
pub struct Location {
uri: crate::Uri,
range: crate::Range,
}
But we can't convert every `lsp::Location` to this type because for
definitions, references and diagnostics language servers send documents
which we haven't opened yet, so we don't have the information to convert
an `lsp::Range` (line+col) to a `helix_core::Range` (char indexing).
This cleans up the picker definitions in this file so that they can all
use helpers like `jump_to_location` and `location_to_file_location` for
the picker preview. It also removes the only use of the deprecated
`PathOrId::from_path_buf` function, allowing us to drop the owned
variant of that type in the child commit.
Whenever a document is changed helix maps various positions like the
cursor or diagnostics through the `ChangeSet` applied to the document.
Currently, this mapping handles replacements as follows:
* Move position to the left for `Assoc::Before` (start of selection)
* Move position to the right for `Assoc::After` (end of selection)
However, when text is exactly replaced this can produce weird results
where the cursor is moved when it shouldn't. For example if `foo` is
selected and a separate cursor is placed on each character (`s.<ret>`)
and the text is replaced (for example `rx`) then the cursors are moved
to the side instead of remaining in place.
This change adds a special case to the mapping code of replacements:
If the deleted and inserted text have the same (char) length then
the position is returned as if the replacement doesn't exist.
only keep selections invariant under replacement
Keeping selections unchanged if they are inside an exact replacement
is intuitive. However, for diagnostics this is not desirable as
helix would otherwise fail to remove diagnostics if replacing parts
of the document.
The `take_while` should limit the layers to those that can match the
input range so we don't always scan the entire `injection_layers`. We
can limit `depth == 1` layers to those that start before the search
`end`. Deeper layers overlap with shallower layers though so we need
to allow those layers as well in the `take_while`.
For example
```vue
<script setup lang="ts">
const foo = 'bar'.match(/foo/);
const bar = foo;
</script>
```
L2 and L3 are a typescript layer and the `/foo/` part is a small regex
layer. If you used `A-o` before the regex layer you would select the
entire typescript layer. The search in `layer_id_containing_byte_range`
would not consider the typescript layer since the regex layer comes
earlier in `injection_ranges` and that layer's start is after `end`.
The regex layer has a depth of `2` though so the change in this commit
allows scanning through that layer.
Co-authored-by: Pascal Kuthe <pascalkuthe@pm.me>
* feat(languages): update `just` grammar and queries
Bump the
* refactor(syntax): inject shebang by id not name
---------
Co-authored-by: Trevor Gross <tmgross@umich.edu>
The line annotation as implemented in #5420 had two shortcomings:
* It required the height of virtual text lines to be known ahead time
* It checked for line anchors at every grapheme
The first problem made the API impractical to use in practice because
almost all virtual text needs to be softwrapped. For example inline
diagnostics should be softwrapped to avoid cutting off the diagnostic
message (as no scrolling is possible). While more complex virtual text
like side by side diffs must dynamically calculate the number of empty
lines two align two documents (which requires taking account both
softwrap and virtual text). To address this, the API has been
refactored to use a trait.
The second issue caused some performance overhead and unnecessarily
complicated the `DocumentFormatter`. It was addressed by only calling
the trait mentioned above at line breaks (instead of always). This
allows offers additional flexibility to annotations as it offers
the flexibility to align lines (needed for side by side diffs).
This introduces a custom URI type in core meant to be extended later
if we want to support other schemes. For now it's just a wrapper over a
PathBuf. We use this new URI type to firewall `lsp::Url`. This was
previously done in 8141a4a but using a custom URI type is more flexible
and will improve the way Pickers handle paths for previews in the child
commit(s).
Co-authored-by: soqb <cb.setho@gmail.com>
We will use this in the child commit to improve the picker's running
indicator. Nucleo 0.4.0 includes an `active_injectors` member that we
can use to detect if anything can push to the picker. When that count
drops to zero we can remove the running indicator.
Nucleo 0.4.1 contains a fix for crashes with interactive global search
on a large directory.
When parsing injections, we skip adding a new layer if there is an
existing layer covering the same range. When doing so we did not update
the parent layer ID, so some layers could have `parent` layer IDs that
pointed to a layer that no longer existed in the `layers` HopSlotMap
which could cause a panic when using `A-o`.
To fix this we update the `parent` pointer for both newly created
injection layers and reused ones.
This is useful for resetting multiple changes at once. For example you
might use 'maf' or even '%' to select a larger region and reset all
changes within.
The original behavior of resetting the change on the current line is
retained when the primary selection is 1-width since we look for chunks
in the line range of each selection.
It can be convenient to define project specific debugger templates, some of
which might not necessitate prompting the user to define completion.
This commit makes completion optional for debugger templates and starts the
dap immediately if undefined or empty.
This uses the new TreeCursor type from the parent commit to reimplement
the tree-sitter motions (`A-p/o/i/n`). Other tree-sitter related
features like textobjects are not touched with this change and will
need a different, unrelated approach to solve.
This uses the layer parentage information from the parent commit to
traverse the layers. It's a similar API to `tree_sitter:TreeCursor`
but internally it does not use a `tree_sitter::TreeCursor` currently
because that interface is behaving very unexpectedly. Using the
`next_sibling`/`prev_sibling`/`parent` API on `tree_sitter::Node`
reflects the previous code's behavior so this should result in no
surprising changes.
This commit adds a `parent` field to the `LanguageLayer`. This
information is conveniently already available when we parse injections.
This will be used in the child commit to create a type that can
traverse injection layers using this information.