Skip to content

Commit

Permalink
only extend diagnostic end for words
Browse files Browse the repository at this point in the history
Diagnostics are currently extended if text is inserted at their end. This is
desirable when inserting text after an identifier. For example consider:

let foo = 2;
    --- unused variable

Renaming the identifier should extend the diagnostic:

let foobar = 2;
    ------ unused variable

This is currently implemented in helix bug as a consequence adding whitespaces
or a type hint also extends the diagnostic:

let foo      = 2;
    -------- unused variable
let foo: Bar = 2;
    -------- unused variable

In these cases the diagnostic should remain unchanged:

let foo      = 2;
    --- unused variable
let foo: Bar = 2;
    --- unused variable

As a heuristic helix will now only extend diagnostics that end on a word char
if new chars are appended to the word (so not for punctuation/ whitespace).
The idea for this mapping was inspired for the word level tracking vscode uses
for many positions. While VSCode doesn't currently update diagnostics after
receiving publishDiagnostic it does use this system for inlay hints for example.
Similarly, the new association mechanism implemented here can be used for word
level tracking of inlay hints.
  • Loading branch information
pascalkuthe committed May 20, 2023
1 parent 10d5239 commit e147f3e
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 18 deletions.
2 changes: 2 additions & 0 deletions helix-core/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ pub enum DiagnosticTag {
#[derive(Debug, Clone)]
pub struct Diagnostic {
pub range: Range,
// whether this diagnostic ends at the end of(or inside) a word
pub ends_at_word: bool,
pub line: usize,
pub message: String,
pub severity: Option<Severity>,
Expand Down
37 changes: 21 additions & 16 deletions helix-core/src/transaction.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use smallvec::SmallVec;

use crate::{Range, Rope, Selection, Tendril};
use crate::{chars::char_is_word, Range, Rope, Selection, Tendril};
use std::borrow::Cow;

/// (from, to, replacement)
Expand All @@ -22,6 +22,20 @@ pub enum Operation {
pub enum Assoc {
Before,
After,
/// Acts like `After` if a word character is inserted
/// after the position, otherwise acts like `Before`
AfterWord,
}

impl Assoc {
fn insert_offset(self, s: &str) -> usize {
match self {
Assoc::After => s.chars().count(),
Assoc::AfterWord => s.chars().take_while(|&c| char_is_word(c)).count(),
// return position before inserted text
Assoc::Before => 0,
}
}
}

#[derive(Debug, Default, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -360,37 +374,28 @@ impl ChangeSet {
}
}
Insert(s) => {
let ins = s.chars().count();

// a subsequent delete means a replace, consume it
if let Some(Delete(len)) = iter.peek() {
iter.next();

old_end = old_pos + len;
// in range of replaced text
if old_end > pos {
// at point or tracking before
if pos == old_pos || assoc == Assoc::Before {
// replacement starting at the point doesn't
// move the point forward
if pos == old_pos {
return new_pos;
} else {
// place to end of insert
return new_pos + ins;
}
return new_pos + assoc.insert_offset(s);
}
} else {
// at insert point
if old_pos == pos {
// return position before inserted text
if assoc == Assoc::Before {
return new_pos;
} else {
// after text
return new_pos + ins;
}
return new_pos + assoc.insert_offset(s);
}
}

new_pos += ins;
new_pos += s.chars().count();
}
}
old_pos = old_end;
Expand Down
7 changes: 6 additions & 1 deletion helix-term/src/application.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use arc_swap::{access::Map, ArcSwap};
use futures_util::Stream;
use helix_core::{
chars::char_is_word,
diagnostic::{DiagnosticTag, NumberOrString},
path::get_relative_path,
pos_at_coords, syntax, Selection,
Expand Down Expand Up @@ -777,7 +778,6 @@ impl Application {
}
}
}

}

let unchaged_diag_sources = &unchaged_diag_sources_;
Expand Down Expand Up @@ -858,8 +858,13 @@ impl Application {
Vec::new()
};

let ends_at_word = start != end
&& end != 0
&& text.get_char(end - 1).map_or(false, char_is_word);

Some(Diagnostic {
range: Range { start, end },
ends_at_word,
line: diagnostic.range.start.line as usize,
message: diagnostic.message.clone(),
severity,
Expand Down
7 changes: 6 additions & 1 deletion helix-view/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1119,7 +1119,12 @@ impl Document {
// map state.diagnostics over changes::map_pos too
for diagnostic in &mut self.diagnostics {
diagnostic.range.start = changes.map_pos(diagnostic.range.start, Assoc::After);
diagnostic.range.end = changes.map_pos(diagnostic.range.end, Assoc::After);
let assoc = if diagnostic.ends_at_word {
Assoc::AfterWord
} else {
Assoc::Before
};
diagnostic.range.end = changes.map_pos(diagnostic.range.end, assoc);
diagnostic.line = self.text.char_to_line(diagnostic.range.start);
}
self.diagnostics
Expand Down

0 comments on commit e147f3e

Please sign in to comment.