.github
workflows build.yml
content help.txt ollama.txt
queries bash.scm c.scm cpp.scm css.scm dockerfile.scm go.scm html.scm javascript.scm lua.scm markdown.scm php.scm python.scm sql.scm tsx.scm typescript.scm
samples format.txt lsp.c ollama.py test.c test.cpp test.css test.dockerfile test.html test.js test.lua test.md test.php test.py test.rb test.sh test.sql test.ts test.tsx
vendor
github.com
mattn
go-runewidth .travis.yml LICENSE README.md go.test.sh runewidth.go runewidth_appengine.go runewidth_js.go runewidth_posix.go runewidth_table.go runewidth_windows.go
mitjafelicijan
go-tree-sitter
bash binding.go parser.c parser.h scanner.c
c binding.go parser.c parser.h
cpp binding.go parser.c parser.h scanner.c
css binding.go parser.c parser.h scanner.c
dockerfile binding.go parser.c parser.h scanner.c
golang binding.go parser.c parser.h
html binding.go parser.c parser.h scanner.c tag.h
javascript binding.go parser.c parser.h scanner.c
lua binding.go parser.c parser.h scanner.c
markdown
tree-sitter-markdown binding.go parser.c parser.h scanner.c
php
tree_sitter .keep alloc.h array.h parser.h
binding.go parser.c parser.h scanner.c scanner.h
python binding.go parser.c parser.h scanner.c
sql
tree_sitter .keep alloc.h array.h parser.h
binding.go parser.c scanner.c
typescript
tsx binding.go parser.c parser.h scanner.c scanner.h
typescript binding.go parser.c parser.h scanner.c scanner.h
.gitignore LICENSE Makefile README.md alloc.c alloc.h api.h array.h atomic.h bindings.c bindings.go bindings.h bits.h clock.h error_costs.h get_changed_ranges.c get_changed_ranges.h host.h iter.go language.c language.h length.h lexer.c lexer.h node.c parser.c parser.h point.h ptypes.h query.c reduce_action.h reusable_node.h stack.c stack.h subtree.c subtree.h test_grammar.go test_grammar.js test_grammar_generate.sh tree.c tree.h tree_cursor.c tree_cursor.h umachine.h unicode.h urename.h utf.h utf16.h utf8.h wasm_store.c wasm_store.h
nsf
termbox-go AUTHORS LICENSE README.md api.go api_common.go api_windows.go collect_terminfo.py escwait.go escwait_darwin.go syscalls_darwin.go syscalls_darwin_amd64.go syscalls_dragonfly.go syscalls_freebsd.go syscalls_linux.go syscalls_netbsd.go syscalls_openbsd.go syscalls_windows.go termbox.go termbox_common.go termbox_windows.go terminfo.go terminfo_builtin.go
modules.txt
.gitignore LICENSE Makefile README.md buffer.go colors.go command.go config.go editor.go embed.go ftypes.go go.mod go.sum info.go intro.go kevent.go lsp.go main.go ollama.go replace.go syntax.go theme.go treesitter.txt
vendor/github.com/mitjafelicijan/go-tree-sitter/get_changed_ranges.c raw
  1#include "./get_changed_ranges.h"
  2#include "./subtree.h"
  3#include "./language.h"
  4#include "./error_costs.h"
  5#include "./tree_cursor.h"
  6#include <assert.h>
  7
  8// #define DEBUG_GET_CHANGED_RANGES
  9
 10static void ts_range_array_add(
 11  TSRangeArray *self,
 12  Length start,
 13  Length end
 14) {
 15  if (self->size > 0) {
 16    TSRange *last_range = array_back(self);
 17    if (start.bytes <= last_range->end_byte) {
 18      last_range->end_byte = end.bytes;
 19      last_range->end_point = end.extent;
 20      return;
 21    }
 22  }
 23
 24  if (start.bytes < end.bytes) {
 25    TSRange range = { start.extent, end.extent, start.bytes, end.bytes };
 26    array_push(self, range);
 27  }
 28}
 29
 30bool ts_range_array_intersects(
 31  const TSRangeArray *self,
 32  unsigned start_index,
 33  uint32_t start_byte,
 34  uint32_t end_byte
 35) {
 36  for (unsigned i = start_index; i < self->size; i++) {
 37    TSRange *range = &self->contents[i];
 38    if (range->end_byte > start_byte) {
 39      if (range->start_byte >= end_byte) break;
 40      return true;
 41    }
 42  }
 43  return false;
 44}
 45
 46void ts_range_array_get_changed_ranges(
 47  const TSRange *old_ranges, unsigned old_range_count,
 48  const TSRange *new_ranges, unsigned new_range_count,
 49  TSRangeArray *differences
 50) {
 51  unsigned new_index = 0;
 52  unsigned old_index = 0;
 53  Length current_position = length_zero();
 54  bool in_old_range = false;
 55  bool in_new_range = false;
 56
 57  while (old_index < old_range_count || new_index < new_range_count) {
 58    const TSRange *old_range = &old_ranges[old_index];
 59    const TSRange *new_range = &new_ranges[new_index];
 60
 61    Length next_old_position;
 62    if (in_old_range) {
 63      next_old_position = (Length) {old_range->end_byte, old_range->end_point};
 64    } else if (old_index < old_range_count) {
 65      next_old_position = (Length) {old_range->start_byte, old_range->start_point};
 66    } else {
 67      next_old_position = LENGTH_MAX;
 68    }
 69
 70    Length next_new_position;
 71    if (in_new_range) {
 72      next_new_position = (Length) {new_range->end_byte, new_range->end_point};
 73    } else if (new_index < new_range_count) {
 74      next_new_position = (Length) {new_range->start_byte, new_range->start_point};
 75    } else {
 76      next_new_position = LENGTH_MAX;
 77    }
 78
 79    if (next_old_position.bytes < next_new_position.bytes) {
 80      if (in_old_range != in_new_range) {
 81        ts_range_array_add(differences, current_position, next_old_position);
 82      }
 83      if (in_old_range) old_index++;
 84      current_position = next_old_position;
 85      in_old_range = !in_old_range;
 86    } else if (next_new_position.bytes < next_old_position.bytes) {
 87      if (in_old_range != in_new_range) {
 88        ts_range_array_add(differences, current_position, next_new_position);
 89      }
 90      if (in_new_range) new_index++;
 91      current_position = next_new_position;
 92      in_new_range = !in_new_range;
 93    } else {
 94      if (in_old_range != in_new_range) {
 95        ts_range_array_add(differences, current_position, next_new_position);
 96      }
 97      if (in_old_range) old_index++;
 98      if (in_new_range) new_index++;
 99      in_old_range = !in_old_range;
100      in_new_range = !in_new_range;
101      current_position = next_new_position;
102    }
103  }
104}
105
106typedef struct {
107  TreeCursor cursor;
108  const TSLanguage *language;
109  unsigned visible_depth;
110  bool in_padding;
111} Iterator;
112
113static Iterator iterator_new(
114  TreeCursor *cursor,
115  const Subtree *tree,
116  const TSLanguage *language
117) {
118  array_clear(&cursor->stack);
119  array_push(&cursor->stack, ((TreeCursorEntry) {
120    .subtree = tree,
121    .position = length_zero(),
122    .child_index = 0,
123    .structural_child_index = 0,
124  }));
125  return (Iterator) {
126    .cursor = *cursor,
127    .language = language,
128    .visible_depth = 1,
129    .in_padding = false,
130  };
131}
132
133static bool iterator_done(Iterator *self) {
134  return self->cursor.stack.size == 0;
135}
136
137static Length iterator_start_position(Iterator *self) {
138  TreeCursorEntry entry = *array_back(&self->cursor.stack);
139  if (self->in_padding) {
140    return entry.position;
141  } else {
142    return length_add(entry.position, ts_subtree_padding(*entry.subtree));
143  }
144}
145
146static Length iterator_end_position(Iterator *self) {
147  TreeCursorEntry entry = *array_back(&self->cursor.stack);
148  Length result = length_add(entry.position, ts_subtree_padding(*entry.subtree));
149  if (self->in_padding) {
150    return result;
151  } else {
152    return length_add(result, ts_subtree_size(*entry.subtree));
153  }
154}
155
156static bool iterator_tree_is_visible(const Iterator *self) {
157  TreeCursorEntry entry = *array_back(&self->cursor.stack);
158  if (ts_subtree_visible(*entry.subtree)) return true;
159  if (self->cursor.stack.size > 1) {
160    Subtree parent = *self->cursor.stack.contents[self->cursor.stack.size - 2].subtree;
161    return ts_language_alias_at(
162      self->language,
163      parent.ptr->production_id,
164      entry.structural_child_index
165    ) != 0;
166  }
167  return false;
168}
169
170static void iterator_get_visible_state(
171  const Iterator *self,
172  Subtree *tree,
173  TSSymbol *alias_symbol,
174  uint32_t *start_byte
175) {
176  uint32_t i = self->cursor.stack.size - 1;
177
178  if (self->in_padding) {
179    if (i == 0) return;
180    i--;
181  }
182
183  for (; i + 1 > 0; i--) {
184    TreeCursorEntry entry = self->cursor.stack.contents[i];
185
186    if (i > 0) {
187      const Subtree *parent = self->cursor.stack.contents[i - 1].subtree;
188      *alias_symbol = ts_language_alias_at(
189        self->language,
190        parent->ptr->production_id,
191        entry.structural_child_index
192      );
193    }
194
195    if (ts_subtree_visible(*entry.subtree) || *alias_symbol) {
196      *tree = *entry.subtree;
197      *start_byte = entry.position.bytes;
198      break;
199    }
200  }
201}
202
203static void iterator_ascend(Iterator *self) {
204  if (iterator_done(self)) return;
205  if (iterator_tree_is_visible(self) && !self->in_padding) self->visible_depth--;
206  if (array_back(&self->cursor.stack)->child_index > 0) self->in_padding = false;
207  self->cursor.stack.size--;
208}
209
210static bool iterator_descend(Iterator *self, uint32_t goal_position) {
211  if (self->in_padding) return false;
212
213  bool did_descend = false;
214  do {
215    did_descend = false;
216    TreeCursorEntry entry = *array_back(&self->cursor.stack);
217    Length position = entry.position;
218    uint32_t structural_child_index = 0;
219    for (uint32_t i = 0, n = ts_subtree_child_count(*entry.subtree); i < n; i++) {
220      const Subtree *child = &ts_subtree_children(*entry.subtree)[i];
221      Length child_left = length_add(position, ts_subtree_padding(*child));
222      Length child_right = length_add(child_left, ts_subtree_size(*child));
223
224      if (child_right.bytes > goal_position) {
225        array_push(&self->cursor.stack, ((TreeCursorEntry) {
226          .subtree = child,
227          .position = position,
228          .child_index = i,
229          .structural_child_index = structural_child_index,
230        }));
231
232        if (iterator_tree_is_visible(self)) {
233          if (child_left.bytes > goal_position) {
234            self->in_padding = true;
235          } else {
236            self->visible_depth++;
237          }
238          return true;
239        }
240
241        did_descend = true;
242        break;
243      }
244
245      position = child_right;
246      if (!ts_subtree_extra(*child)) structural_child_index++;
247    }
248  } while (did_descend);
249
250  return false;
251}
252
253static void iterator_advance(Iterator *self) {
254  if (self->in_padding) {
255    self->in_padding = false;
256    if (iterator_tree_is_visible(self)) {
257      self->visible_depth++;
258    } else {
259      iterator_descend(self, 0);
260    }
261    return;
262  }
263
264  for (;;) {
265    if (iterator_tree_is_visible(self)) self->visible_depth--;
266    TreeCursorEntry entry = array_pop(&self->cursor.stack);
267    if (iterator_done(self)) return;
268
269    const Subtree *parent = array_back(&self->cursor.stack)->subtree;
270    uint32_t child_index = entry.child_index + 1;
271    if (ts_subtree_child_count(*parent) > child_index) {
272      Length position = length_add(entry.position, ts_subtree_total_size(*entry.subtree));
273      uint32_t structural_child_index = entry.structural_child_index;
274      if (!ts_subtree_extra(*entry.subtree)) structural_child_index++;
275      const Subtree *next_child = &ts_subtree_children(*parent)[child_index];
276
277      array_push(&self->cursor.stack, ((TreeCursorEntry) {
278        .subtree = next_child,
279        .position = position,
280        .child_index = child_index,
281        .structural_child_index = structural_child_index,
282      }));
283
284      if (iterator_tree_is_visible(self)) {
285        if (ts_subtree_padding(*next_child).bytes > 0) {
286          self->in_padding = true;
287        } else {
288          self->visible_depth++;
289        }
290      } else {
291        iterator_descend(self, 0);
292      }
293      break;
294    }
295  }
296}
297
298typedef enum {
299  IteratorDiffers,
300  IteratorMayDiffer,
301  IteratorMatches,
302} IteratorComparison;
303
304static IteratorComparison iterator_compare(
305  const Iterator *old_iter,
306  const Iterator *new_iter
307) {
308  Subtree old_tree = NULL_SUBTREE;
309  Subtree new_tree = NULL_SUBTREE;
310  uint32_t old_start = 0;
311  uint32_t new_start = 0;
312  TSSymbol old_alias_symbol = 0;
313  TSSymbol new_alias_symbol = 0;
314  iterator_get_visible_state(old_iter, &old_tree, &old_alias_symbol, &old_start);
315  iterator_get_visible_state(new_iter, &new_tree, &new_alias_symbol, &new_start);
316
317  if (!old_tree.ptr && !new_tree.ptr) return IteratorMatches;
318  if (!old_tree.ptr || !new_tree.ptr) return IteratorDiffers;
319
320  if (
321    old_alias_symbol == new_alias_symbol &&
322    ts_subtree_symbol(old_tree) == ts_subtree_symbol(new_tree)
323  ) {
324    if (old_start == new_start &&
325        !ts_subtree_has_changes(old_tree) &&
326        ts_subtree_symbol(old_tree) != ts_builtin_sym_error &&
327        ts_subtree_size(old_tree).bytes == ts_subtree_size(new_tree).bytes &&
328        ts_subtree_parse_state(old_tree) != TS_TREE_STATE_NONE &&
329        ts_subtree_parse_state(new_tree) != TS_TREE_STATE_NONE &&
330        (ts_subtree_parse_state(old_tree) == ERROR_STATE) ==
331        (ts_subtree_parse_state(new_tree) == ERROR_STATE)) {
332      return IteratorMatches;
333    } else {
334      return IteratorMayDiffer;
335    }
336  }
337
338  return IteratorDiffers;
339}
340
341#ifdef DEBUG_GET_CHANGED_RANGES
342static inline void iterator_print_state(Iterator *self) {
343  TreeCursorEntry entry = *array_back(&self->cursor.stack);
344  TSPoint start = iterator_start_position(self).extent;
345  TSPoint end = iterator_end_position(self).extent;
346  const char *name = ts_language_symbol_name(self->language, ts_subtree_symbol(*entry.subtree));
347  printf(
348    "(%-25s %s\t depth:%u [%u, %u] - [%u, %u])",
349    name, self->in_padding ? "(p)" : "   ",
350    self->visible_depth,
351    start.row + 1, start.column,
352    end.row + 1, end.column
353  );
354}
355#endif
356
357unsigned ts_subtree_get_changed_ranges(
358  const Subtree *old_tree, const Subtree *new_tree,
359  TreeCursor *cursor1, TreeCursor *cursor2,
360  const TSLanguage *language,
361  const TSRangeArray *included_range_differences,
362  TSRange **ranges
363) {
364  TSRangeArray results = array_new();
365
366  Iterator old_iter = iterator_new(cursor1, old_tree, language);
367  Iterator new_iter = iterator_new(cursor2, new_tree, language);
368
369  unsigned included_range_difference_index = 0;
370
371  Length position = iterator_start_position(&old_iter);
372  Length next_position = iterator_start_position(&new_iter);
373  if (position.bytes < next_position.bytes) {
374    ts_range_array_add(&results, position, next_position);
375    position = next_position;
376  } else if (position.bytes > next_position.bytes) {
377    ts_range_array_add(&results, next_position, position);
378    next_position = position;
379  }
380
381  do {
382    #ifdef DEBUG_GET_CHANGED_RANGES
383    printf("At [%-2u, %-2u] Compare ", position.extent.row + 1, position.extent.column);
384    iterator_print_state(&old_iter);
385    printf("\tvs\t");
386    iterator_print_state(&new_iter);
387    puts("");
388    #endif
389
390    // Compare the old and new subtrees.
391    IteratorComparison comparison = iterator_compare(&old_iter, &new_iter);
392
393    // Even if the two subtrees appear to be identical, they could differ
394    // internally if they contain a range of text that was previously
395    // excluded from the parse, and is now included, or vice-versa.
396    if (comparison == IteratorMatches && ts_range_array_intersects(
397      included_range_differences,
398      included_range_difference_index,
399      position.bytes,
400      iterator_end_position(&old_iter).bytes
401    )) {
402      comparison = IteratorMayDiffer;
403    }
404
405    bool is_changed = false;
406    switch (comparison) {
407      // If the subtrees are definitely identical, move to the end
408      // of both subtrees.
409      case IteratorMatches:
410        next_position = iterator_end_position(&old_iter);
411        break;
412
413      // If the subtrees might differ internally, descend into both
414      // subtrees, finding the first child that spans the current position.
415      case IteratorMayDiffer:
416        if (iterator_descend(&old_iter, position.bytes)) {
417          if (!iterator_descend(&new_iter, position.bytes)) {
418            is_changed = true;
419            next_position = iterator_end_position(&old_iter);
420          }
421        } else if (iterator_descend(&new_iter, position.bytes)) {
422          is_changed = true;
423          next_position = iterator_end_position(&new_iter);
424        } else {
425          next_position = length_min(
426            iterator_end_position(&old_iter),
427            iterator_end_position(&new_iter)
428          );
429        }
430        break;
431
432      // If the subtrees are different, record a change and then move
433      // to the end of both subtrees.
434      case IteratorDiffers:
435        is_changed = true;
436        next_position = length_min(
437          iterator_end_position(&old_iter),
438          iterator_end_position(&new_iter)
439        );
440        break;
441    }
442
443    // Ensure that both iterators are caught up to the current position.
444    while (
445      !iterator_done(&old_iter) &&
446      iterator_end_position(&old_iter).bytes <= next_position.bytes
447    ) iterator_advance(&old_iter);
448    while (
449      !iterator_done(&new_iter) &&
450      iterator_end_position(&new_iter).bytes <= next_position.bytes
451    ) iterator_advance(&new_iter);
452
453    // Ensure that both iterators are at the same depth in the tree.
454    while (old_iter.visible_depth > new_iter.visible_depth) {
455      iterator_ascend(&old_iter);
456    }
457    while (new_iter.visible_depth > old_iter.visible_depth) {
458      iterator_ascend(&new_iter);
459    }
460
461    if (is_changed) {
462      #ifdef DEBUG_GET_CHANGED_RANGES
463      printf(
464        "  change: [[%u, %u] - [%u, %u]]\n",
465        position.extent.row + 1, position.extent.column,
466        next_position.extent.row + 1, next_position.extent.column
467      );
468      #endif
469
470      ts_range_array_add(&results, position, next_position);
471    }
472
473    position = next_position;
474
475    // Keep track of the current position in the included range differences
476    // array in order to avoid scanning the entire array on each iteration.
477    while (included_range_difference_index < included_range_differences->size) {
478      const TSRange *range = &included_range_differences->contents[
479        included_range_difference_index
480      ];
481      if (range->end_byte <= position.bytes) {
482        included_range_difference_index++;
483      } else {
484        break;
485      }
486    }
487  } while (!iterator_done(&old_iter) && !iterator_done(&new_iter));
488
489  Length old_size = ts_subtree_total_size(*old_tree);
490  Length new_size = ts_subtree_total_size(*new_tree);
491  if (old_size.bytes < new_size.bytes) {
492    ts_range_array_add(&results, old_size, new_size);
493  } else if (new_size.bytes < old_size.bytes) {
494    ts_range_array_add(&results, new_size, old_size);
495  }
496
497  *cursor1 = old_iter.cursor;
498  *cursor2 = new_iter.cursor;
499  *ranges = results.contents;
500  return results.size;
501}