Skip to content

TextArea with textual[syntax] causes crash as of tree-sitter 0.25.0 #5976

@davep

Description

@davep

If I create a fresh build environment (in this case using rye):

rye init .
rye add "textual[syntax]"

and run this code:

from textual.app import App, ComposeResult
from textual.widgets import TextArea

class EditApp(App[None]):

    def compose(self) -> ComposeResult:
        yield TextArea.code_editor(language="python")

if __name__ == "__main__":
    EditApp().run()

I get this crash:

╭───────────────────────────────────────────────────────── Traceback (most recent call last) ──────────────────────────────────────────────────────────╮
│ /Users/davep/temp/x/edit.py:7 in compose                                                                                                             │
│                                                                                                                                                      │
│    4 class EditApp(App[None]):                                                                                                                       │
│    5 │                                                                                                                                               │
│    6 │   def compose(self) -> ComposeResult:                                                                                                         │
│ ❱  7 │   │   yield TextArea.code_editor(language="python")                                                                                           │
│    8                                                                                                                                                 │
│    9 if __name__ == "__main__":                                                                                                                      │
│   10 │   EditApp().run()                                                                                                                             │
│                                                                                                                                                      │
│ ╭───────────────────────────────────────── locals ──────────────────────────────────────────╮                                                        │
│ │ self = EditApp(title='EditApp', classes={'-dark-mode'}, pseudo_classes={'focus', 'dark'}) │                                                        │
│ ╰───────────────────────────────────────────────────────────────────────────────────────────╯                                                        │
│                                                                                                                                                      │
│ /Users/davep/temp/x/.venv/lib/python3.13/site-packages/textual/widgets/_text_area.py:592 in code_editor                                              │
│                                                                                                                                                      │
│    589 │   │   │   compact: Enable compact style (without borders).                             ╭───────────── locals ──────────────╮                │
│    590 │   │   │   highlight_cursor_line: Highlight the line under the cursor.                  │               classes = None      │                │
│    591 │   │   """                                                                              │               compact = False     │                │
│ ❱  592 │   │   return cls(                                                                      │              disabled = False     │                │
│    593 │   │   │   text,                                                                        │ highlight_cursor_line = True      │                │
│    594 │   │   │   language=language,                                                           │                    id = None      │                │
│    595 │   │   │   theme=theme,                                                                 │              language = 'python'  │                │
│                                                                                                 │     line_number_start = 1         │                │
│                                                                                                 │       max_checkpoints = 50        │                │
│                                                                                                 │                  name = None      │                │
│                                                                                                 │             read_only = False     │                │
│                                                                                                 │           show_cursor = True      │                │
│                                                                                                 │     show_line_numbers = True      │                │
│                                                                                                 │             soft_wrap = False     │                │
│                                                                                                 │          tab_behavior = 'indent'  │                │
│                                                                                                 │                  text = ''        │                │
│                                                                                                 │                 theme = 'monokai' │                │
│                                                                                                 │               tooltip = None      │                │
│                                                                                                 ╰───────────────────────────────────╯                │
│                                                                                                                                                      │
│ /Users/davep/temp/x/.venv/lib/python3.13/site-packages/textual/widgets/_text_area.py:530 in __init__                                                 │
│                                                                                                                                                      │
│    527 │   │                                                                                    ╭────────────── locals ──────────────╮               │
│    528 │   │   self._line_cache: LRUCache[tuple, Strip] = LRUCache(1024)                        │               classes = None       │               │
│    529 │   │                                                                                    │               compact = False      │               │
│ ❱  530 │   │   self._set_document(text, language)                                               │              disabled = False      │               │
│    531 │   │                                                                                    │ highlight_cursor_line = True       │               │
│    532 │   │   self.language = language                                                         │                    id = None       │               │
│    533 │   │   self.theme = theme                                                               │              language = 'python'   │               │
│                                                                                                 │     line_number_start = 1          │               │
│                                                                                                 │       max_checkpoints = 50         │               │
│                                                                                                 │                  name = None       │               │
│                                                                                                 │             read_only = False      │               │
│                                                                                                 │                  self = TextArea() │               │
│                                                                                                 │           show_cursor = True       │               │
│                                                                                                 │     show_line_numbers = True       │               │
│                                                                                                 │             soft_wrap = False      │               │
│                                                                                                 │          tab_behavior = 'indent'   │               │
│                                                                                                 │                  text = ''         │               │
│                                                                                                 │                 theme = 'monokai'  │               │
│                                                                                                 │               tooltip = None       │               │
│                                                                                                 ╰────────────────────────────────────╯               │
│                                                                                                                                                      │
│ /Users/davep/temp/x/.venv/lib/python3.13/site-packages/textual/widgets/_text_area.py:1009 in _set_document                                           │
│                                                                                                                                                      │
│   1006 │   │   self.document = document                                                                                                              │
│   1007 │   │   self.wrapped_document = WrappedDocument(document, tab_width=self.indent_width)                                                        │
│   1008 │   │   self.navigator = DocumentNavigator(self.wrapped_document)                                                                             │
│ ❱ 1009 │   │   self._build_highlight_map()                                                                                                           │
│   1010 │   │   self.move_cursor((0, 0))                                                                                                              │
│   1011 │   │   self._rewrap_and_refresh_virtual_size()                                                                                               │
│   1012                                                                                                                                               │
│                                                                                                                                                      │
│ ╭─────────────────────────────────────────────────── locals ───────────────────────────────────────────────────╮                                     │
│ │          document = <textual.document._syntax_aware_document.SyntaxAwareDocument object at 0x1056bb770>      │                                     │
│ │ document_language = <Language id=4387700744, version=14, name=None>                                          │                                     │
│ │   highlight_query = ';; From tree-sitter-python licensed under MIT License\n; Copyright (c) 2016 Max B'+7281 │                                     │
│ │          language = 'python'                                                                                 │                                     │
│ │              self = TextArea()                                                                               │                                     │
│ │              text = ''                                                                                       │                                     │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯                                     │
│                                                                                                                                                      │
│ /Users/davep/temp/x/.venv/lib/python3.13/site-packages/textual/widgets/_text_area.py:665 in _build_highlight_map                                     │
│                                                                                                                                                      │
│    662 │   │   if not self._highlight_query:                                                    ╭─────────────────── locals ───────────────────╮     │
│    663 │   │   │   return                                                                       │ highlights = defaultdict(<class 'list'>, {}) │     │
│    664 │   │                                                                                    │       self = TextArea()                      │     │
│ ❱  665 │   │   captures = self.document.query_syntax_tree(self._highlight_query)                ╰──────────────────────────────────────────────╯     │
│    666 │   │   for highlight_name, nodes in captures.items():                                                                                        │
│    667 │   │   │   for node in nodes:                                                                                                                │
│    668 │   │   │   │   node_start_row, node_start_column = node.start_point                                                                          │
│                                                                                                                                                      │
│ /Users/davep/temp/x/.venv/lib/python3.13/site-packages/textual/document/_syntax_aware_document.py:91 in query_syntax_tree                            │
│                                                                                                                                                      │
│    88 │   │   if end_point is not None:                                                                                                              │
│    89 │   │   │   captures_kwargs["end_point"] = end_point                                                                                           │
│    90 │   │                                                                                                                                          │
│ ❱  91 │   │   captures = query.captures(self._syntax_tree.root_node, **captures_kwargs)                                                              │
│    92 │   │   return captures                                                                                                                        │
│    93 │                                                                                                                                              │
│    94 │   def replace_range(self, start: Location, end: Location, text: str) -> EditResult:                                                          │
│                                                                                                                                                      │
│ ╭─────────────────────────────────────────────── locals ────────────────────────────────────────────────╮                                            │
│ │ captures_kwargs = {}                                                                                  │                                            │
│ │       end_point = None                                                                                │                                            │
│ │           query = <tree_sitter.Query object at 0x10572e910>                                           │                                            │
│ │            self = <textual.document._syntax_aware_document.SyntaxAwareDocument object at 0x1056bb770> │                                            │
│ │     start_point = None                                                                                │                                            │
│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────╯                                            │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
AttributeError: 'tree_sitter.Query' object has no attribute 'captures'

If I then pin tree-sitter to anything less than 0.25.0:

rye add "tree-sitter<0.25.0"

the code works again.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions