Fix -
being a word character for selections (#17171)
Co-Authored-By: Mikayla <mikayla@zed.dev> Co-Authored-By: Nate <nate@zed.dev> Closes #15606 Closes #13515 Release Notes: - Fixes `-` being considered a word character for selections in some languages Co-authored-by: Mikayla <mikayla@zed.dev> Co-authored-by: Nate <nate@zed.dev>
This commit is contained in:
parent
c0731bfa28
commit
ee6ec50b15
12 changed files with 239 additions and 143 deletions
|
@ -89,13 +89,12 @@ pub use inline_completion_provider::*;
|
|||
pub use items::MAX_TAB_TITLE_LEN;
|
||||
use itertools::Itertools;
|
||||
use language::{
|
||||
char_kind,
|
||||
language_settings::{self, all_language_settings, InlayHintSettings},
|
||||
markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CharKind, CodeLabel,
|
||||
CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt,
|
||||
Point, Selection, SelectionGoal, TransactionId,
|
||||
};
|
||||
use language::{point_to_lsp, BufferRow, Runnable, RunnableRange};
|
||||
use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange};
|
||||
use linked_editing_ranges::refresh_linked_ranges;
|
||||
use task::{ResolvedTask, TaskTemplate, TaskVariables};
|
||||
|
||||
|
@ -2443,7 +2442,8 @@ impl Editor {
|
|||
|
||||
if let Some(completion_menu) = completion_menu {
|
||||
let cursor_position = new_cursor_position.to_offset(buffer);
|
||||
let (word_range, kind) = buffer.surrounding_word(completion_menu.initial_position);
|
||||
let (word_range, kind) =
|
||||
buffer.surrounding_word(completion_menu.initial_position, true);
|
||||
if kind == Some(CharKind::Word)
|
||||
&& word_range.to_inclusive().contains(&cursor_position)
|
||||
{
|
||||
|
@ -3289,10 +3289,8 @@ impl Editor {
|
|||
let start_anchor = snapshot.anchor_before(selection.start);
|
||||
|
||||
let is_word_char = text.chars().next().map_or(true, |char| {
|
||||
let scope = snapshot.language_scope_at(start_anchor.to_offset(&snapshot));
|
||||
let kind = char_kind(&scope, char);
|
||||
|
||||
kind == CharKind::Word
|
||||
let classifier = snapshot.char_classifier_at(start_anchor.to_offset(&snapshot));
|
||||
classifier.is_word(char)
|
||||
});
|
||||
|
||||
if is_word_char {
|
||||
|
@ -3923,7 +3921,7 @@ impl Editor {
|
|||
|
||||
fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
|
||||
let offset = position.to_offset(buffer);
|
||||
let (word_range, kind) = buffer.surrounding_word(offset);
|
||||
let (word_range, kind) = buffer.surrounding_word(offset, true);
|
||||
if offset > word_range.start && kind == Some(CharKind::Word) {
|
||||
Some(
|
||||
buffer
|
||||
|
@ -12302,10 +12300,11 @@ fn snippet_completions(
|
|||
};
|
||||
|
||||
let scope = language.map(|language| language.default_scope());
|
||||
let classifier = CharClassifier::new(scope).for_completion(true);
|
||||
let mut last_word = line_at
|
||||
.chars()
|
||||
.rev()
|
||||
.take_while(|c| char_kind(&scope, *c) == CharKind::Word)
|
||||
.take_while(|c| classifier.is_word(*c))
|
||||
.collect::<String>();
|
||||
last_word = last_word.chars().rev().collect();
|
||||
let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
|
||||
|
@ -12436,8 +12435,11 @@ impl CompletionProvider for Model<Project> {
|
|||
}
|
||||
|
||||
let buffer = buffer.read(cx);
|
||||
let scope = buffer.snapshot().language_scope_at(position);
|
||||
if trigger_in_words && char_kind(&scope, char) == CharKind::Word {
|
||||
let classifier = buffer
|
||||
.snapshot()
|
||||
.char_classifier_at(position)
|
||||
.for_completion(true);
|
||||
if trigger_in_words && classifier.is_word(char) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -613,7 +613,7 @@ pub fn show_link_definition(
|
|||
TriggerPoint::Text(trigger_anchor) => {
|
||||
// If no symbol range returned from language server, use the surrounding word.
|
||||
let (offset_range, _) =
|
||||
snapshot.surrounding_word(*trigger_anchor);
|
||||
snapshot.surrounding_word(*trigger_anchor, false);
|
||||
RangeInEditor::Text(
|
||||
snapshot.anchor_before(offset_range.start)
|
||||
..snapshot.anchor_after(offset_range.end),
|
||||
|
|
|
@ -1225,7 +1225,7 @@ impl SearchableItem for Editor {
|
|||
}
|
||||
SeedQuerySetting::Selection => String::new(),
|
||||
SeedQuerySetting::Always => {
|
||||
let (range, kind) = snapshot.surrounding_word(selection.start);
|
||||
let (range, kind) = snapshot.surrounding_word(selection.start, true);
|
||||
if kind == Some(CharKind::Word) {
|
||||
let text: String = snapshot.text_for_range(range).collect();
|
||||
if !text.trim().is_empty() {
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
//! in editor given a given motion (e.g. it handles converting a "move left" command into coordinates in editor). It is exposed mostly for use by vim crate.
|
||||
|
||||
use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint};
|
||||
use crate::{
|
||||
char_kind, scroll::ScrollAnchor, CharKind, DisplayRow, EditorStyle, RowExt, ToOffset, ToPoint,
|
||||
};
|
||||
use crate::{scroll::ScrollAnchor, CharKind, DisplayRow, EditorStyle, RowExt, ToOffset, ToPoint};
|
||||
use gpui::{px, Pixels, WindowTextSystem};
|
||||
use language::Point;
|
||||
use multi_buffer::{MultiBufferRow, MultiBufferSnapshot};
|
||||
|
@ -264,10 +262,10 @@ pub fn line_end(
|
|||
/// uppercase letter, lowercase letter, '_' character or language-specific word character (like '-' in CSS).
|
||||
pub fn previous_word_start(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
|
||||
let raw_point = point.to_point(map);
|
||||
let scope = map.buffer_snapshot.language_scope_at(raw_point);
|
||||
let classifier = map.buffer_snapshot.char_classifier_at(raw_point);
|
||||
|
||||
find_preceding_boundary_display_point(map, point, FindRange::MultiLine, |left, right| {
|
||||
(char_kind(&scope, left) != char_kind(&scope, right) && !right.is_whitespace())
|
||||
(classifier.kind(left) != classifier.kind(right) && !classifier.is_whitespace(right))
|
||||
|| left == '\n'
|
||||
})
|
||||
}
|
||||
|
@ -277,13 +275,14 @@ pub fn previous_word_start(map: &DisplaySnapshot, point: DisplayPoint) -> Displa
|
|||
/// lowerspace characters and uppercase characters.
|
||||
pub fn previous_subword_start(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
|
||||
let raw_point = point.to_point(map);
|
||||
let scope = map.buffer_snapshot.language_scope_at(raw_point);
|
||||
let classifier = map.buffer_snapshot.char_classifier_at(raw_point);
|
||||
|
||||
find_preceding_boundary_display_point(map, point, FindRange::MultiLine, |left, right| {
|
||||
let is_word_start =
|
||||
char_kind(&scope, left) != char_kind(&scope, right) && !right.is_whitespace();
|
||||
let is_subword_start =
|
||||
left == '_' && right != '_' || left.is_lowercase() && right.is_uppercase();
|
||||
classifier.kind(left) != classifier.kind(right) && !right.is_whitespace();
|
||||
let is_subword_start = classifier.is_word('-') && left == '-' && right != '-'
|
||||
|| left == '_' && right != '_'
|
||||
|| left.is_lowercase() && right.is_uppercase();
|
||||
is_word_start || is_subword_start || left == '\n'
|
||||
})
|
||||
}
|
||||
|
@ -292,10 +291,10 @@ pub fn previous_subword_start(map: &DisplaySnapshot, point: DisplayPoint) -> Dis
|
|||
/// uppercase letter, lowercase letter, '_' character or language-specific word character (like '-' in CSS).
|
||||
pub fn next_word_end(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
|
||||
let raw_point = point.to_point(map);
|
||||
let scope = map.buffer_snapshot.language_scope_at(raw_point);
|
||||
let classifier = map.buffer_snapshot.char_classifier_at(raw_point);
|
||||
|
||||
find_boundary(map, point, FindRange::MultiLine, |left, right| {
|
||||
(char_kind(&scope, left) != char_kind(&scope, right) && !left.is_whitespace())
|
||||
(classifier.kind(left) != classifier.kind(right) && !classifier.is_whitespace(left))
|
||||
|| right == '\n'
|
||||
})
|
||||
}
|
||||
|
@ -305,13 +304,14 @@ pub fn next_word_end(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint
|
|||
/// lowerspace characters and uppercase characters.
|
||||
pub fn next_subword_end(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint {
|
||||
let raw_point = point.to_point(map);
|
||||
let scope = map.buffer_snapshot.language_scope_at(raw_point);
|
||||
let classifier = map.buffer_snapshot.char_classifier_at(raw_point);
|
||||
|
||||
find_boundary(map, point, FindRange::MultiLine, |left, right| {
|
||||
let is_word_end =
|
||||
(char_kind(&scope, left) != char_kind(&scope, right)) && !left.is_whitespace();
|
||||
let is_subword_end =
|
||||
left != '_' && right == '_' || left.is_lowercase() && right.is_uppercase();
|
||||
(classifier.kind(left) != classifier.kind(right)) && !classifier.is_whitespace(left);
|
||||
let is_subword_end = classifier.is_word('-') && left != '-' && right == '-'
|
||||
|| left != '_' && right == '_'
|
||||
|| left.is_lowercase() && right.is_uppercase();
|
||||
is_word_end || is_subword_end || right == '\n'
|
||||
})
|
||||
}
|
||||
|
@ -509,14 +509,14 @@ pub fn chars_before(
|
|||
|
||||
pub(crate) fn is_inside_word(map: &DisplaySnapshot, point: DisplayPoint) -> bool {
|
||||
let raw_point = point.to_point(map);
|
||||
let scope = map.buffer_snapshot.language_scope_at(raw_point);
|
||||
let classifier = map.buffer_snapshot.char_classifier_at(raw_point);
|
||||
let ix = map.clip_point(point, Bias::Left).to_offset(map, Bias::Left);
|
||||
let text = &map.buffer_snapshot;
|
||||
let next_char_kind = text.chars_at(ix).next().map(|c| char_kind(&scope, c));
|
||||
let next_char_kind = text.chars_at(ix).next().map(|c| classifier.kind(c));
|
||||
let prev_char_kind = text
|
||||
.reversed_chars_at(ix)
|
||||
.next()
|
||||
.map(|c| char_kind(&scope, c));
|
||||
.map(|c| classifier.kind(c));
|
||||
prev_char_kind.zip(next_char_kind) == Some((CharKind::Word, CharKind::Word))
|
||||
}
|
||||
|
||||
|
@ -527,7 +527,7 @@ pub(crate) fn surrounding_word(
|
|||
let position = map
|
||||
.clip_point(position, Bias::Left)
|
||||
.to_offset(map, Bias::Left);
|
||||
let (range, _) = map.buffer_snapshot.surrounding_word(position);
|
||||
let (range, _) = map.buffer_snapshot.surrounding_word(position, false);
|
||||
let start = range
|
||||
.start
|
||||
.to_point(&map.buffer_snapshot)
|
||||
|
|
|
@ -226,6 +226,7 @@ impl EditorLspTestContext {
|
|||
..Default::default()
|
||||
},
|
||||
block_comment: Some(("<!-- ".into(), " -->".into())),
|
||||
word_characters: ['-'].into_iter().collect(),
|
||||
..Default::default()
|
||||
},
|
||||
Some(tree_sitter_html::language()),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue