fix: handle more cases of editing subtrees that depend on column values
(cherry picked from commit a83b893016)
This commit is contained in:
parent
77794c558f
commit
d10308528d
5 changed files with 137 additions and 3 deletions
|
|
@ -501,6 +501,67 @@ h + i
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parsing_after_editing_tree_that_depends_on_column_position() {
|
||||
let dir = fixtures_dir()
|
||||
.join("test_grammars")
|
||||
.join("depends_on_column");
|
||||
|
||||
let grammar_json = load_grammar_file(&dir.join("grammar.js"), None).unwrap();
|
||||
let (grammar_name, parser_code) = generate_parser_for_grammar(grammar_json.as_str()).unwrap();
|
||||
|
||||
let mut parser = Parser::new();
|
||||
parser
|
||||
.set_language(&get_test_language(&grammar_name, &parser_code, Some(&dir)))
|
||||
.unwrap();
|
||||
|
||||
let mut code = b"\n x".to_vec();
|
||||
let mut tree = parser.parse(&code, None).unwrap();
|
||||
assert_eq!(tree.root_node().to_sexp(), "(x_is_at (odd_column))");
|
||||
|
||||
perform_edit(
|
||||
&mut tree,
|
||||
&mut code,
|
||||
&Edit {
|
||||
position: 1,
|
||||
deleted_length: 0,
|
||||
inserted_text: b" ".to_vec(),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(code, b"\n x");
|
||||
|
||||
let mut recorder = ReadRecorder::new(&code);
|
||||
let mut tree = parser
|
||||
.parse_with(&mut |i, _| recorder.read(i), Some(&tree))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(tree.root_node().to_sexp(), "(x_is_at (even_column))",);
|
||||
assert_eq!(recorder.strings_read(), vec!["\n x"]);
|
||||
|
||||
perform_edit(
|
||||
&mut tree,
|
||||
&mut code,
|
||||
&Edit {
|
||||
position: 1,
|
||||
deleted_length: 0,
|
||||
inserted_text: b"\n".to_vec(),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(code, b"\n\n x");
|
||||
|
||||
let mut recorder = ReadRecorder::new(&code);
|
||||
let tree = parser
|
||||
.parse_with(&mut |i, _| recorder.read(i), Some(&tree))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(tree.root_node().to_sexp(), "(x_is_at (even_column))",);
|
||||
assert_eq!(recorder.strings_read(), vec!["\n\n x"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parsing_after_detecting_error_in_the_middle_of_a_string_token() {
|
||||
let mut parser = Parser::new();
|
||||
|
|
|
|||
|
|
@ -677,7 +677,8 @@ Subtree ts_subtree_edit(Subtree self, const TSInputEdit *input_edit, SubtreePool
|
|||
Edit edit = entry.edit;
|
||||
bool is_noop = edit.old_end.bytes == edit.start.bytes && edit.new_end.bytes == edit.start.bytes;
|
||||
bool is_pure_insertion = edit.old_end.bytes == edit.start.bytes;
|
||||
bool invalidate_first_row = ts_subtree_depends_on_column(*entry.tree);
|
||||
bool parent_depends_on_column = ts_subtree_depends_on_column(*entry.tree);
|
||||
bool column_shifted = edit.new_end.extent.column != edit.old_end.extent.column;
|
||||
|
||||
Length size = ts_subtree_size(*entry.tree);
|
||||
Length padding = ts_subtree_padding(*entry.tree);
|
||||
|
|
@ -771,8 +772,12 @@ Subtree ts_subtree_edit(Subtree self, const TSInputEdit *input_edit, SubtreePool
|
|||
(child_left.bytes > edit.old_end.bytes) ||
|
||||
(child_left.bytes == edit.old_end.bytes && child_size.bytes > 0 && i > 0)
|
||||
) && (
|
||||
!invalidate_first_row ||
|
||||
child_left.extent.row > entry.tree->ptr->padding.extent.row
|
||||
!parent_depends_on_column ||
|
||||
child_left.extent.row > padding.extent.row
|
||||
) && (
|
||||
!ts_subtree_depends_on_column(*child) ||
|
||||
!column_shifted ||
|
||||
child_left.extent.row > edit.old_end.extent.row
|
||||
)) {
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
21
test/fixtures/test_grammars/depends_on_column/corpus.txt
vendored
Normal file
21
test/fixtures/test_grammars/depends_on_column/corpus.txt
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
==================
|
||||
X is at odd column
|
||||
==================
|
||||
|
||||
x
|
||||
|
||||
---
|
||||
|
||||
(x_is_at
|
||||
(odd_column))
|
||||
|
||||
===================
|
||||
X is at even column
|
||||
===================
|
||||
|
||||
x
|
||||
|
||||
---
|
||||
|
||||
(x_is_at
|
||||
(even_column))
|
||||
7
test/fixtures/test_grammars/depends_on_column/grammar.js
vendored
Normal file
7
test/fixtures/test_grammars/depends_on_column/grammar.js
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
module.exports = grammar({
|
||||
name: "depends_on_column",
|
||||
rules: {
|
||||
x_is_at: ($) => seq(/[ \r\n]*/, choice($.odd_column, $.even_column), "x"),
|
||||
},
|
||||
externals: ($) => [$.odd_column, $.even_column],
|
||||
});
|
||||
40
test/fixtures/test_grammars/depends_on_column/scanner.c
vendored
Normal file
40
test/fixtures/test_grammars/depends_on_column/scanner.c
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#include "tree_sitter/parser.h"
|
||||
|
||||
enum TokenType { ODD_COLUMN, EVEN_COLUMN };
|
||||
|
||||
// The scanner is stateless
|
||||
|
||||
void *tree_sitter_depends_on_column_external_scanner_create() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tree_sitter_depends_on_column_external_scanner_destroy(
|
||||
void *payload
|
||||
) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
unsigned tree_sitter_depends_on_column_external_scanner_serialize(
|
||||
void *payload,
|
||||
char *buffer
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tree_sitter_depends_on_column_external_scanner_deserialize(
|
||||
void *payload,
|
||||
const char *buffer,
|
||||
unsigned length
|
||||
) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
bool tree_sitter_depends_on_column_external_scanner_scan(
|
||||
void *payload,
|
||||
TSLexer *lexer,
|
||||
const bool *valid_symbols
|
||||
) {
|
||||
lexer->result_symbol =
|
||||
lexer->get_column(lexer) % 2 ? ODD_COLUMN : EVEN_COLUMN;
|
||||
return true;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue