@ -1189,28 +1189,12 @@ impl Document {
use helix_core ::Assoc ;
use helix_core ::Assoc ;
let old_doc = self . text ( ) . clone ( ) ;
let old_doc = self . text ( ) . clone ( ) ;
let changes = transaction . changes ( ) ;
if ! changes . apply ( & mut self . text ) {
return false ;
}
let success = transaction . changes ( ) . apply ( & mut self . text ) ;
if changes . is_empty ( ) {
if success {
if emit_lsp_notification {
helix_event ::dispatch ( DocumentDidChange {
doc : self ,
view : view_id ,
old_text : & old_doc ,
} ) ;
}
for selection in self . selections . values_mut ( ) {
* selection = selection
. clone ( )
// Map through changes
. map ( transaction . changes ( ) )
// Ensure all selections across all views still adhere to invariants.
. ensure_invariants ( self . text . slice ( .. ) ) ;
}
// if specified, the current selection should instead be replaced by transaction.selection
if let Some ( selection ) = transaction . selection ( ) {
if let Some ( selection ) = transaction . selection ( ) {
self . selections . insert (
self . selections . insert (
view_id ,
view_id ,
@ -1221,129 +1205,155 @@ impl Document {
view : view_id ,
view : view_id ,
} ) ;
} ) ;
}
}
return true ;
}
self . modified_since_accessed = true ;
self . modified_since_accessed = true ;
self . version + = 1 ;
for selection in self . selections . values_mut ( ) {
* selection = selection
. clone ( )
// Map through changes
. map ( transaction . changes ( ) )
// Ensure all selections across all views still adhere to invariants.
. ensure_invariants ( self . text . slice ( .. ) ) ;
}
}
if ! transaction . changes ( ) . is_empty ( ) {
// generate revert to savepoint
self . version + = 1 ;
if ! self . savepoints . is_empty ( ) {
// start computing the diff in parallel
let revert = transaction . invert ( & old_doc ) ;
if let Some ( diff_handle ) = & self . diff_handle {
self . savepoints
diff_handle . update_document ( self . text . clone ( ) , false ) ;
. retain_mut ( | save_point | match save_point . upgrade ( ) {
}
Some ( savepoint ) = > {
let mut revert_to_savepoint = savepoint . revert . lock ( ) ;
* revert_to_savepoint =
revert . clone ( ) . compose ( mem ::take ( & mut revert_to_savepoint ) ) ;
true
}
None = > false ,
} )
}
// generate revert to savepoint
// update tree-sitter syntax tree
if ! self . savepoints . is_empty ( ) {
if let Some ( syntax ) = & mut self . syntax {
let revert = transaction . invert ( & old_doc ) ;
// TODO: no unwrap
self . savepoints
let res = syntax . update (
. retain_mut ( | save_point | match save_point . upgrade ( ) {
old_doc . slice ( .. ) ,
Some ( savepoint ) = > {
self . text . slice ( .. ) ,
let mut revert_to_savepoint = savepoint . revert . lock ( ) ;
transaction . changes ( ) ,
* revert_to_savepoint =
) ;
revert . clone ( ) . compose ( mem ::take ( & mut revert_to_savepoint ) ) ;
if res . is_err ( ) {
true
log ::error ! ( "TS parser failed, disabling TS for the current buffer: {res:?}" ) ;
}
self . syntax = None ;
None = > false ,
} )
}
}
}
// update tree-sitter syntax tree
// TODO: all of that should likely just be hooks
if let Some ( syntax ) = & mut self . syntax {
// start computing the diff in parallel
// TODO: no unwrap
if let Some ( diff_handle ) = & self . diff_handle {
let res = syntax . update (
diff_handle . update_document ( self . text . clone ( ) , false ) ;
old_doc . slice ( .. ) ,
}
self . text . slice ( .. ) ,
transaction . changes ( ) ,
) ;
if res . is_err ( ) {
log ::error ! ( "TS parser failed, disabling TS for the current buffer: {res:?}" ) ;
self . syntax = None ;
}
}
let changes = transaction . changes ( ) ;
// map diagnostics over changes too
changes . update_positions ( self . diagnostics . iter_mut ( ) . map ( | diagnostic | {
let assoc = if diagnostic . starts_at_word {
Assoc ::BeforeWord
} else {
Assoc ::After
} ;
( & mut diagnostic . range . start , assoc )
} ) ) ;
changes . update_positions ( self . diagnostics . iter_mut ( ) . filter_map ( | diagnostic | {
if diagnostic . zero_width {
// for zero width diagnostics treat the diagnostic as a point
// rather than a range
return None ;
}
let assoc = if diagnostic . ends_at_word {
Assoc ::AfterWord
} else {
Assoc ::Before
} ;
Some ( ( & mut diagnostic . range . end , assoc ) )
} ) ) ;
self . diagnostics . retain_mut ( | diagnostic | {
if diagnostic . zero_width {
diagnostic . range . end = diagnostic . range . start
} else if diagnostic . range . start > = diagnostic . range . end {
return false ;
}
diagnostic . line = self . text . char_to_line ( diagnostic . range . start ) ;
true
} ) ;
// map diagnostics over changes too
self . diagnostics . sort_unstable_by_key ( | diagnostic | {
changes . update_positions ( self . diagnostics . iter_mut ( ) . map ( | diagnostic | {
( diagnostic . range , diagnostic . severity , diagnostic . provider )
let assoc = if diagnostic . starts_at_word {
} ) ;
Assoc ::BeforeWord
} else {
Assoc ::After
} ;
( & mut diagnostic . range . start , assoc )
} ) ) ;
changes . update_positions ( self . diagnostics . iter_mut ( ) . filter_map ( | diagnostic | {
if diagnostic . zero_width {
// for zero width diagnostics treat the diagnostic as a point
// rather than a range
return None ;
}
let assoc = if diagnostic . ends_at_word {
Assoc ::AfterWord
} else {
Assoc ::Before
} ;
Some ( ( & mut diagnostic . range . end , assoc ) )
} ) ) ;
self . diagnostics . retain_mut ( | diagnostic | {
if diagnostic . zero_width {
diagnostic . range . end = diagnostic . range . start
} else if diagnostic . range . start > = diagnostic . range . end {
return false ;
}
diagnostic . line = self . text . char_to_line ( diagnostic . range . start ) ;
true
} ) ;
self . diagnostics . sort_unstable_by_key ( | diagnostic | {
// Update the inlay hint annotations' positions, helping ensure they are displayed in the proper place
( diagnostic . range , diagnostic . severity , diagnostic . provider )
let apply_inlay_hint_changes = | annotations : & mut Vec < InlineAnnotation > | {
} ) ;
changes . update_positions (
annotations
. iter_mut ( )
. map ( | annotation | ( & mut annotation . char_idx , Assoc ::After ) ) ,
) ;
} ;
// Update the inlay hint annotations' positions, helping ensure they are displayed in the proper place
self . inlay_hints_oudated = true ;
let apply_inlay_hint_changes = | annotations : & mut Vec < InlineAnnotation > | {
for text_annotation in self . inlay_hints . values_mut ( ) {
changes . update_positions (
let DocumentInlayHints {
annotations
id : _ ,
. iter_mut ( )
type_inlay_hints ,
. map ( | annotation | ( & mut annotation . char_idx , Assoc ::After ) ) ,
parameter_inlay_hints ,
) ;
other_inlay_hints ,
} ;
padding_before_inlay_hints ,
padding_after_inlay_hints ,
} = text_annotation ;
apply_inlay_hint_changes ( padding_before_inlay_hints ) ;
apply_inlay_hint_changes ( type_inlay_hints ) ;
apply_inlay_hint_changes ( parameter_inlay_hints ) ;
apply_inlay_hint_changes ( other_inlay_hints ) ;
apply_inlay_hint_changes ( padding_after_inlay_hints ) ;
}
self . inlay_hints_oudated = true ;
helix_event ::dispatch ( DocumentDidChange {
for text_annotation in self . inlay_hints . values_mut ( ) {
doc : self ,
let DocumentInlayHints {
view : view_id ,
id : _ ,
old_text : & old_doc ,
type_inlay_hints ,
changes ,
parameter_inlay_hints ,
ghost_transaction : ! emit_lsp_notification ,
other_inlay_hints ,
} ) ;
padding_before_inlay_hints ,
padding_after_inlay_hints ,
} = text_annotation ;
apply_inlay_hint_changes ( padding_before_inlay_hints ) ;
apply_inlay_hint_changes ( type_inlay_hints ) ;
apply_inlay_hint_changes ( parameter_inlay_hints ) ;
apply_inlay_hint_changes ( other_inlay_hints ) ;
apply_inlay_hint_changes ( padding_after_inlay_hints ) ;
}
if emit_lsp_notification {
if emit_lsp_notification {
// TODO: move to hook
// TODO: move to hook
// emit lsp notification
// emit lsp notification
for language_server in self . language_servers ( ) {
for language_server in self . language_servers ( ) {
let notify = language_server . text_document_did_change (
let notify = language_server . text_document_did_change (
self . versioned_identifier ( ) ,
self . versioned_identifier ( ) ,
& old_doc ,
& old_doc ,
self . text ( ) ,
self . text ( ) ,
changes ,
changes ,
) ;
) ;
if let Some ( notify ) = notify {
if let Some ( notify ) = notify {
tokio ::spawn ( notify ) ;
tokio ::spawn ( notify ) ;
}
}
}
}
}
}
}
success
if let Some ( selection ) = transaction . selection ( ) {
self . selections . insert (
view_id ,
selection . clone ( ) . ensure_invariants ( self . text . slice ( .. ) ) ,
) ;
helix_event ::dispatch ( SelectionDidChange {
doc : self ,
view : view_id ,
} ) ;
}
true
}
}
fn apply_inner (
fn apply_inner (