diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..1da747aa --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +indent_size = 2 + +[*.rst] +indent_size = 3 + +[*.{c,h,py}] +indent_size = 4 +max_line_length = 100 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..a2cb7d15 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,45 @@ +name: Docs + +on: + push: + branches: [master] + paths: + - tree_sitter/** + - docs/** + +concurrency: + group: ${{github.workflow}}-${{github.ref}} + cancel-in-progress: true + +permissions: + pages: write + id-token: write + +jobs: + docs: + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{steps.deploy.outputs.page_url}} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: true + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Install + run: pip install -e .[docs] + env: + CFLAGS: "-O0 -g" + - name: Build docs + run: sphinx-build -M html docs docs/_build + - name: Upload docs artifact + uses: actions/deploy-pages@v3 + with: + path: docs/_build/html + - name: Deploy to GitHub Pages + id: deploy + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 788b80af..22451bfd 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ dist *.so __pycache__ wheelhouse +docs/_build diff --git a/README.md b/README.md index 4683c33c..a8e80624 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![CI][ci]](https://github.com/tree-sitter/py-tree-sitter/actions/workflows/ci.yml) [![pypi][pypi]](https://pypi.org/project/tree-sitter/) +[![docs][docs]](https://tree-sitter.github.io/py-tree-sitter/) This module provides Python bindings to the [tree-sitter] parsing library. @@ -35,45 +36,7 @@ Then, you can load it as a `Language` object: import tree_sitter_python as tspython from tree_sitter import Language, Parser -PY_LANGUAGE = Language(tspython.language(), "python") -``` - -#### Build from source - -> [!WARNING] -> This method of loading languages is deprecated and will be removed in `v0.22.0`. -> You should only use it if you need languages that have not updated their bindings. -> Keep in mind that you will need a C compiler in this case. - -First you'll need a Tree-sitter language implementation for each language that you want to parse. - -```sh -git clone https://github.com/tree-sitter/tree-sitter-go -git clone https://github.com/tree-sitter/tree-sitter-javascript -git clone https://github.com/tree-sitter/tree-sitter-python -``` - -Use the `Language.build_library` method to compile these into a library that's -usable from Python. This function will return immediately if the library has -already been compiled since the last time its source code was modified: - -```python -from tree_sitter import Language, Parser - -Language.build_library( - # Store the library in the `build` directory - "build/my-languages.so", - # Include one or more languages - ["vendor/tree-sitter-go", "vendor/tree-sitter-javascript", "vendor/tree-sitter-python"], -) -``` - -Load the languages into your app as `Language` objects: - -```python -GO_LANGUAGE = Language("build/my-languages.so", "go") -JS_LANGUAGE = Language("build/my-languages.so", "javascript") -PY_LANGUAGE = Language("build/my-languages.so", "python") +PY_LANGUAGE = Language(tspython.language()) ``` ### Basic parsing @@ -324,5 +287,6 @@ To try out and explore the code referenced in this README, check out [examples/u [tree query]: https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax [ci]: https://img.shields.io/github/actions/workflow/status/tree-sitter/py-tree-sitter/ci.yml?logo=github&label=CI [pypi]: https://img.shields.io/pypi/v/tree-sitter?logo=pypi&logoColor=ffd242&label=PyPI +[docs]: https://img.shields.io/github/deployments/tree-sitter/py-tree-sitter/github-pages?logo=sphinx&label=Docs [examples/walk_tree.py]: https://github.com/tree-sitter/py-tree-sitter/blob/master/examples/walk_tree.py [examples/usage.py]: https://github.com/tree-sitter/py-tree-sitter/blob/master/examples/usage.py diff --git a/docs/_static/favicon.png b/docs/_static/favicon.png new file mode 100644 index 00000000..945fa841 Binary files /dev/null and b/docs/_static/favicon.png differ diff --git a/docs/_static/logo.png b/docs/_static/logo.png new file mode 100644 index 00000000..73f7f163 Binary files /dev/null and b/docs/_static/logo.png differ diff --git a/docs/classes/tree_sitter.Language.rst b/docs/classes/tree_sitter.Language.rst new file mode 100644 index 00000000..bde57b16 --- /dev/null +++ b/docs/classes/tree_sitter.Language.rst @@ -0,0 +1,53 @@ +Language +======== + +.. autoclass:: tree_sitter.Language + + .. versionchanged:: 0.22.0 + + No longer accepts a ``name`` parameter. + + + Methods + ------- + + .. automethod:: field_id_for_name + .. automethod:: field_name_for_id + .. automethod:: id_for_node_kind + .. automethod:: lookahead_iterator + .. automethod:: next_state + .. automethod:: node_kind_for_id + .. automethod:: node_kind_is_named + .. automethod:: node_kind_is_visible + .. automethod:: query + + Special Methods + --------------- + + .. automethod:: __eq__ + + .. versionadded:: 0.22.0 + .. automethod:: __hash__ + + .. versionadded:: 0.22.0 + .. automethod:: __index__ + + .. versionadded:: 0.22.0 + .. automethod:: __int__ + + .. versionadded:: 0.22.0 + .. automethod:: __ne__ + + .. versionadded:: 0.22.0 + .. automethod:: __repr__ + + .. versionadded:: 0.22.0 + + + Properties + ---------- + + .. autoattribute:: field_count + .. autoattribute:: node_kind_count + .. autoattribute:: parse_state_count + .. autoattribute:: version diff --git a/docs/classes/tree_sitter.LookaheadIterator.rst b/docs/classes/tree_sitter.LookaheadIterator.rst new file mode 100644 index 00000000..23fb6eb3 --- /dev/null +++ b/docs/classes/tree_sitter.LookaheadIterator.rst @@ -0,0 +1,24 @@ +LookaheadIterator +================= + +.. autoclass:: tree_sitter.LookaheadIterator + + Methods + ------- + + .. automethod:: iter_names + .. automethod:: reset + .. automethod:: reset_state + + Special methods + --------------- + + .. automethod:: __iter__ + .. automethod:: __next__ + + Attributes + ---------- + + .. autoattribute:: current_symbol + .. autoattribute:: current_symbol_name + .. autoattribute:: language diff --git a/docs/classes/tree_sitter.Node.rst b/docs/classes/tree_sitter.Node.rst new file mode 100644 index 00000000..137c9212 --- /dev/null +++ b/docs/classes/tree_sitter.Node.rst @@ -0,0 +1,65 @@ +Node +==== + +.. autoclass:: tree_sitter.Node + + Methods + ------- + + .. automethod:: child + .. automethod:: child_by_field_id + .. automethod:: child_by_field_name + .. automethod:: children_by_field_id + .. automethod:: children_by_field_name + .. automethod:: descendant_for_byte_range + .. automethod:: descendant_for_point_range + .. automethod:: edit + .. automethod:: field_name_for_child + .. automethod:: named_child + .. automethod:: named_descendant_for_byte_range + .. automethod:: named_descendant_for_point_range + .. automethod:: sexp + .. automethod:: walk + + Special Methods + --------------- + + .. automethod:: __eq__ + .. automethod:: __hash__ + .. automethod:: __ne__ + .. automethod:: __repr__ + .. automethod:: __str__ + + Attributes + ---------- + + .. autoattribute:: byte_range + .. autoattribute:: child_count + .. autoattribute:: children + .. autoattribute:: descendant_count + .. autoattribute:: end_byte + .. autoattribute:: end_point + .. autoattribute:: grammar_id + .. autoattribute:: grammar_name + .. autoattribute:: has_changes + .. autoattribute:: has_error + .. autoattribute:: id + .. autoattribute:: is_error + .. autoattribute:: is_extra + .. autoattribute:: is_missing + .. autoattribute:: is_named + .. autoattribute:: kind_id + .. autoattribute:: named_child_count + .. autoattribute:: named_children + .. autoattribute:: next_named_sibling + .. autoattribute:: next_parse_state + .. autoattribute:: next_sibling + .. autoattribute:: parent + .. autoattribute:: parse_state + .. autoattribute:: prev_named_sibling + .. autoattribute:: prev_sibling + .. autoattribute:: range + .. autoattribute:: start_byte + .. autoattribute:: start_point + .. autoattribute:: text + .. autoattribute:: type diff --git a/docs/classes/tree_sitter.Parser.rst b/docs/classes/tree_sitter.Parser.rst new file mode 100644 index 00000000..94373272 --- /dev/null +++ b/docs/classes/tree_sitter.Parser.rst @@ -0,0 +1,31 @@ +Parser +====== + +.. autoclass:: tree_sitter.Parser + + .. versionadded:: 0.22.0 + + constructor + + Methods + ------- + + + .. automethod:: parse + .. automethod:: reset + .. automethod:: set_included_ranges + .. automethod:: set_language + .. automethod:: set_timeout_micros + + Attributes + ---------- + + .. autoattribute:: included_ranges + + .. versionadded:: 0.22.0 + .. autoattribute:: language + + .. versionadded:: 0.22.0 + .. autoattribute:: timeout_micros + + .. versionadded:: 0.22.0 diff --git a/docs/classes/tree_sitter.Point.rst b/docs/classes/tree_sitter.Point.rst new file mode 100644 index 00000000..5f07edb6 --- /dev/null +++ b/docs/classes/tree_sitter.Point.rst @@ -0,0 +1,10 @@ +Point +===== + +.. autoclass:: tree_sitter.Point + + Attributes + ---------- + + .. autoattribute:: column + .. autoattribute:: row diff --git a/docs/classes/tree_sitter.Query.rst b/docs/classes/tree_sitter.Query.rst new file mode 100644 index 00000000..dbcfdd0c --- /dev/null +++ b/docs/classes/tree_sitter.Query.rst @@ -0,0 +1,14 @@ +Query +===== + +.. autoclass:: tree_sitter.Query + + .. versionadded:: 0.22.0 + + constructor + + Methods + ------- + + .. automethod:: captures + .. automethod:: matches diff --git a/docs/classes/tree_sitter.Range.rst b/docs/classes/tree_sitter.Range.rst new file mode 100644 index 00000000..817c179f --- /dev/null +++ b/docs/classes/tree_sitter.Range.rst @@ -0,0 +1,22 @@ +Range +===== + +.. autoclass:: tree_sitter.Range + + Special Methods + --------------- + + .. automethod:: __eq__ + .. automethod:: __ne__ + .. automethod:: __repr__ + .. automethod:: __hash__ + + .. versionadded:: 0.22.0 + + Attributes + ---------- + + .. autoattribute:: end_byte + .. autoattribute:: end_point + .. autoattribute:: start_byte + .. autoattribute:: start_point diff --git a/docs/classes/tree_sitter.Tree.rst b/docs/classes/tree_sitter.Tree.rst new file mode 100644 index 00000000..13847a57 --- /dev/null +++ b/docs/classes/tree_sitter.Tree.rst @@ -0,0 +1,19 @@ +Tree +==== + +.. autoclass:: tree_sitter.Tree + + Methods + ------- + + .. automethod:: changed_ranges + .. automethod:: edit + .. automethod:: root_node_with_offset + .. automethod:: walk + + Attributes + ---------- + + .. autoattribute:: included_ranges + .. autoattribute:: root_node + .. autoattribute:: text diff --git a/docs/classes/tree_sitter.TreeCursor.rst b/docs/classes/tree_sitter.TreeCursor.rst new file mode 100644 index 00000000..7e20796e --- /dev/null +++ b/docs/classes/tree_sitter.TreeCursor.rst @@ -0,0 +1,33 @@ +TreeCursor +---------- + +.. autoclass:: tree_sitter.TreeCursor + + Methods + ------- + + .. automethod:: copy + .. automethod:: goto_descendant + .. automethod:: goto_first_child + .. automethod:: goto_first_child_for_byte + .. automethod:: goto_first_child_for_point + .. automethod:: goto_last_child + .. automethod:: goto_next_sibling + .. automethod:: goto_parent + .. automethod:: goto_previous_sibling + .. automethod:: reset + .. automethod:: reset_to + + Special methods + --------------- + + .. automethod:: __copy__ + + Attributes + ---------- + + .. autoattribute:: depth + .. autoattribute:: descendant_index + .. autoattribute:: field_id + .. autoattribute:: field_name + .. autoattribute:: node diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..4331e53b --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,83 @@ +from importlib.metadata import version as v +from pathlib import PurePath +from re import compile as regex +from sys import path + +path.insert(0, str(PurePath(__file__).parents[2] / "tree_sitter")) + +project = "py-tree-sitter" +author = "Max Brunsfeld" +copyright = "2019, MIT license" +release = v("tree_sitter") + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.napoleon", + "sphinx.ext.intersphinx", + "sphinx.ext.githubpages", +] +source_suffix = ".rst" +master_doc = "index" +language = "en" +needs_sphinx = "7.3" +templates_path = ["_templates"] + +intersphinx_mapping = { + "python": ("https://docs.python.org/3.9/", None), +} + +autoclass_content = "class" +autodoc_member_order = "alphabetical" +autosummary_generate = False + +napoleon_numpy_docstring = True +napoleon_google_docstring = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = False +napoleon_use_admonition_for_notes = True + +html_theme = "sphinx_book_theme" +html_theme_options = { + "repository_url": "https://github.com/tree-sitter/py-tree-sitter", + "pygment_light_style": "default", + "pygment_dark_style": "github-dark", + "navigation_with_keys": False, + "use_repository_button": True, + "use_download_button": False, + "use_fullscreen_button": False, + "show_toc_level": 2, +} +html_static_path = ["_static"] +html_logo = "_static/logo.png" +html_favicon = "_static/favicon.png" + + +special_doc = regex('\S*self[^.]+') + + +def process_signature(_app, _what, name, _obj, _options, _signature, return_annotation): + if name == 'tree_sitter.Language': + return '(ptr)', return_annotation + if name == 'tree_sitter.Query': + return '(language, source)', return_annotation + if name == 'tree_sitter.Parser': + return '(language, *, included_ranges=None, timeout_micros=None)', return_annotation + if name == 'tree_sitter.Range': + return '(start_point, end_point, start_byte, end_byte)', return_annotation + + +def process_docstring(_app, what, name, _obj, _options, lines): + if what == 'data': + lines.clear() + elif what == 'method': + if name.endswith('__index__'): + lines[0] = 'Converts ``self`` to an integer for use as an index.' + elif name.endswith('__') and lines and 'self' in lines[0]: + lines[0] = f'Implements ``{special_doc.search(lines[0]).group(0)}``.' + + +def setup(app): + app.connect('autodoc-process-signature', process_signature) + app.connect('autodoc-process-docstring', process_docstring) diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..12bbe52c --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,44 @@ +py-tree-sitter +============== + +Python bindings to the Tree-sitter parsing library. + +Constants +--------- + +.. autodata:: tree_sitter.LANGUAGE_VERSION + + The latest ABI version that is supported by the current version of the library. + + .. note:: + + When a :class:`Language` is generated by the Tree-sitter CLI, it is assigned + an ABI version number that corresponds to the current CLI version. + The Tree-sitter library is generally backwards-compatible with languages + generated using older CLI versions, but is not forwards-compatible. + + .. versionadded:: 0.22.0 + +.. autodata:: tree_sitter.MIN_COMPATIBLE_LANGUAGE_VERSION + + The earliest ABI version that is supported by the current version of the library. + + .. versionadded:: 0.22.0 + + +Classes +------- + +.. autosummary:: + :toctree: classes + :nosignatures: + + tree_sitter.Language + tree_sitter.LookaheadIterator + tree_sitter.Node + tree_sitter.Parser + tree_sitter.Point + tree_sitter.Query + tree_sitter.Range + tree_sitter.Tree + tree_sitter.TreeCursor diff --git a/pyproject.toml b/pyproject.toml index 12a40a41..c6b24b6d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "tree-sitter" version = "0.21.3" -description = "Python bindings for the Tree-Sitter parsing library" +description = "Python bindings to the Tree-sitter parsing library" keywords = ["incremental", "parsing", "tree-sitter"] classifiers = [ "Intended Audience :: Developers", @@ -23,11 +23,15 @@ readme = "README.md" [project.urls] Homepage = "https://tree-sitter.github.io/tree-sitter/" Source = "https://github.com/tree-sitter/py-tree-sitter" +Documentation = "https://tree-sitter.github.io/py-tree-sitter/" [[project.authors]] name = "Max Brunsfeld" email = "maxbrunsfeld@gmail.com" +[project.optional-dependencies] +docs = ["sphinx~=7.3", "sphinx-book-theme"] + [tool.ruff] target-version = "py39" line-length = 100 diff --git a/tree_sitter/__init__.py b/tree_sitter/__init__.py index 603a7d8e..18d8f0f6 100644 --- a/tree_sitter/__init__.py +++ b/tree_sitter/__init__.py @@ -1,4 +1,4 @@ -"""Python bindings for tree-sitter.""" +"""Python bindings to the Tree-sitter parsing library.""" from ._binding import ( Language, @@ -14,6 +14,10 @@ MIN_COMPATIBLE_LANGUAGE_VERSION, ) +Point.__doc__ = 'A position in a multi-line text document, in terms of rows and columns.' +Point.row.__doc__ = 'The zero-based row of the document.' +Point.column.__doc__ = 'The zero-based column of the document.' + __all__ = [ "Language", "LookaheadIterator", diff --git a/tree_sitter/__init__.pyi b/tree_sitter/__init__.pyi index f1025e35..07d24610 100644 --- a/tree_sitter/__init__.pyi +++ b/tree_sitter/__init__.pyi @@ -1,5 +1,6 @@ from collections.abc import ByteString, Callable, Iterator, Sequence from typing import Annotated, Any, Final, NamedTuple, final, overload +from typing_extensions import deprecated _Ptr = Annotated[int, "TSLanguage *"] @@ -210,7 +211,7 @@ class Node: /, ) -> Node | None: ... - # NOTE: deprecated + @deprecated("Use `str()` instead") def sexp(self) -> str: ... def __repr__(self) -> str: ... @@ -225,7 +226,7 @@ class Node: @final -class Tree: +class Tree(): @property def root_node(self) -> Node: ... @@ -233,6 +234,7 @@ class Tree: def included_ranges(self) -> list[Range]: ... @property + @deprecated("Use `root_node.text` instead") def text(self) -> bytes | None: ... def root_node_with_offset( @@ -254,7 +256,7 @@ class Tree: def walk(self) -> TreeCursor: ... - def changed_ranges(self, old_tree: Tree) -> list[Range]: ... + def changed_ranges(self, new_tree: Tree) -> list[Range]: ... @final @@ -297,8 +299,8 @@ class TreeCursor: @overload def goto_first_child_for_point(self, point: Point, /) -> bool: ... - # NOTE: deprecated @overload + @deprecated("Use `goto_first_child_for_point(point)` instead") def goto_first_child_for_point(self, row: int, column: int, /) -> bool: ... def __copy__(self) -> TreeCursor: ... @@ -320,38 +322,56 @@ class Parser: @language.setter def language(self, language: Language) -> None: ... + @language.deleter + def language(self) -> None: ... + @property def included_ranges(self) -> list[Range]: ... @included_ranges.setter def included_ranges(self, ranges: Sequence[Range]) -> None: ... + @included_ranges.deleter + def included_ranges(self) -> None: ... + @property def timeout_micros(self) -> int: ... @timeout_micros.setter def timeout_micros(self, timeout: int) -> None: ... + @timeout_micros.deleter + def timeout_micros(self) -> None: ... + # TODO(0.24): implement logger + @overload + def parse( + self, + source: ByteString | _ParseCB | None, + /, + old_tree: Tree | None = None, + ) -> Tree: ... + + @overload + @deprecated("`keep_text` will be removed") def parse( self, source: ByteString | _ParseCB | None, /, old_tree: Tree | None = None, - # NOTE: deprecated keep_text: bool = True, ) -> Tree: ... def reset(self) -> None: ... - # NOTE: deprecated + @deprecated("Use the `language` setter instead") def set_language(self, language: Language, /) -> None: ... - # NOTE: deprecated + @deprecated("Use the `included_ranges` setter instead") def set_included_ranges(self, ranges: Sequence[Range], /) -> None: ... - # NOTE: deprecated + @deprecated("Use the `timeout_micros` setter instead") def set_timeout_micros(self, timeout: int, /) -> None: ... @@ -394,7 +414,7 @@ class LookaheadIterator(Iterator[int]): @property def current_symbol_name(self) -> str: ... - # NOTE: deprecated + @deprecated("Use `reset_state()` instead") def reset(self, language: _Ptr, state: int, /) -> None: ... # TODO(0.24): rename to reset diff --git a/tree_sitter/binding/docs.h b/tree_sitter/binding/docs.h new file mode 100644 index 00000000..24dd267e --- /dev/null +++ b/tree_sitter/binding/docs.h @@ -0,0 +1,13 @@ +#pragma once + +#define DOC_ATTENTION "\n\nAttention\n---------\n\n" +#define DOC_CAUTION "\n\nCaution\n-------\n\n" +#define DOC_EXAMPLES "\n\nExamples\n--------\n\n" +#define DOC_IMPORTANT "\n\nImportant\n---------\n\n" +#define DOC_NOTE "\n\nNote\n----\n\n" +#define DOC_PARAMETERS "\n\nParameters\n----------\n\n" +#define DOC_RAISES "\n\Raises\n------\n\n" +#define DOC_RETURNS "\n\nReturns\n-------\n\n" +#define DOC_SEE_ALSO "\n\nSee Also\n--------\n\n" +#define DOC_HINT "\n\nHint\n----\n\n" +#define DOC_TIP "\n\nTip\n---\n\n" diff --git a/tree_sitter/binding/language.c b/tree_sitter/binding/language.c index ae61742d..e74af1a7 100644 --- a/tree_sitter/binding/language.c +++ b/tree_sitter/binding/language.c @@ -32,7 +32,7 @@ TSLanguage *language_check_pointer(void *ptr) { (void)ts_language_version(ptr); } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { - PyErr_SetString(PyExc_RuntimeError, "Invalid TSLanguage pointer."); + PyErr_SetString(PyExc_RuntimeError, "Invalid TSLanguage pointer"); } return PyErr_Occurred() ? NULL : (TSLanguage *)ptr; } @@ -220,76 +220,112 @@ PyObject *language_query(Language *self, PyObject *args) { return PyObject_CallFunction((PyObject *)state->query_type, "Os#", self, source, length); } +PyDoc_STRVAR(language_node_kind_for_id_doc, + "node_kind_for_id(self, id, /)\n--\n\n" + "Get the name of the node kind for the given numerical id."); +PyDoc_STRVAR(language_id_for_node_kind_doc, "id_for_node_kind(self, kind, named, /)\n--\n\n" + "Get the numerical id for the given node kind."); +PyDoc_STRVAR(language_node_kind_is_named_doc, "node_kind_is_named(self, id, /)\n--\n\n" + "Check if the node type for the given numerical id " + "is named (as opposed to an anonymous node type)."); +PyDoc_STRVAR(language_node_kind_is_visible_doc, + "node_kind_is_visible(self, id, /)\n--\n\n" + "Check if the node type for the given numerical id " + "is visible (as opposed to an auxiliary node type)."); +PyDoc_STRVAR(language_field_name_for_id_doc, "field_name_for_id(self, field_id, /)\n--\n\n" + "Get the field name for the given numerical id."); +PyDoc_STRVAR(language_field_id_for_name_doc, "field_id_for_name(self, name, /)\n--\n\n" + "Get the numerical id for the given field name."); +PyDoc_STRVAR(language_next_state_doc, + "next_state(self, state, id, /)\n--\n\n" + "Get the next parse state." DOC_TIP "Combine this with ``lookahead_iterator`` to " + "generate completion suggestions or valid symbols in error nodes." DOC_EXAMPLES + ">>> state = language.next_state(node.parse_state, node.grammar_id)"); +PyDoc_STRVAR(language_lookahead_iterator_doc, + "lookahead_iterator(self, state, /)\n--\n\n" + "Create a new :class:`LookaheadIterator` for this language and parse state."); +PyDoc_STRVAR( + language_query_doc, + "query(self, source, /)\n--\n\n" + "Create a new :class:`Query` from a string containing one or more S-expression patterns."); + static PyMethodDef language_methods[] = { - {.ml_name = "node_kind_for_id", - .ml_meth = (PyCFunction)language_node_kind_for_id, - .ml_flags = METH_VARARGS, - .ml_doc = "Get the name of the node kind for the given numerical id."}, - {.ml_name = "id_for_node_kind", - .ml_meth = (PyCFunction)language_id_for_node_kind, - .ml_flags = METH_VARARGS, - .ml_doc = "Get the numerical id for the given node kind."}, - {.ml_name = "node_kind_is_named", - .ml_meth = (PyCFunction)language_node_kind_is_named, - .ml_flags = METH_VARARGS, - .ml_doc = "Check if the node type for the given numerical id is named" - " (as opposed to an anonymous node type)."}, - {.ml_name = "node_kind_is_visible", - .ml_meth = (PyCFunction)language_node_kind_is_visible, - .ml_flags = METH_VARARGS, - .ml_doc = "Check if the node type for the given numerical id is visible" - " (as opposed to an auxiliary node type)."}, - {.ml_name = "field_name_for_id", - .ml_meth = (PyCFunction)language_field_name_for_id, - .ml_flags = METH_VARARGS, - .ml_doc = "Get the name of the field for the given numerical id."}, - {.ml_name = "field_id_for_name", - .ml_meth = (PyCFunction)language_field_id_for_name, - .ml_flags = METH_VARARGS, - .ml_doc = "Return the field id for a field name."}, - {.ml_name = "next_state", - .ml_meth = (PyCFunction)language_next_state, - .ml_flags = METH_VARARGS, - .ml_doc = "Get the next parse state. Combine this with `lookahead_iterator` " - "to generate completion suggestions or valid symbols in error nodes."}, - {.ml_name = "lookahead_iterator", - .ml_meth = (PyCFunction)language_lookahead_iterator, - .ml_flags = METH_VARARGS, - .ml_doc = "Create a new lookahead iterator for this language and parse state. " - "Returns `None` if state is invalid for this language.\n\n" - "Iterating `LookaheadIterator` will yield valid symbols in the " - "given parse state. Newly created lookahead iterators will return " - "the `ERROR` symbol from `LookaheadIterator.current_symbol`.\n\n" - "Lookahead iterators can be useful to generate suggestions and improve syntax " - "error diagnostics. To get symbols valid in an `ERROR` node, use the lookahead " - "iterator on its first leaf node state. For `MISSING` nodes, a lookahead " - "iterator created on the previous non-extra leaf node may be appropriate."}, - {.ml_name = "query", - .ml_meth = (PyCFunction)language_query, - .ml_flags = METH_VARARGS, - .ml_doc = "Create a Query with the given source code."}, + { + .ml_name = "node_kind_for_id", + .ml_meth = (PyCFunction)language_node_kind_for_id, + .ml_flags = METH_VARARGS, + .ml_doc = language_node_kind_for_id_doc, + }, + { + .ml_name = "id_for_node_kind", + .ml_meth = (PyCFunction)language_id_for_node_kind, + .ml_flags = METH_VARARGS, + .ml_doc = language_id_for_node_kind_doc, + }, + { + .ml_name = "node_kind_is_named", + .ml_meth = (PyCFunction)language_node_kind_is_named, + .ml_flags = METH_VARARGS, + .ml_doc = language_node_kind_is_named_doc, + }, + { + .ml_name = "node_kind_is_visible", + .ml_meth = (PyCFunction)language_node_kind_is_visible, + .ml_flags = METH_VARARGS, + .ml_doc = language_node_kind_is_visible_doc, + }, + { + .ml_name = "field_name_for_id", + .ml_meth = (PyCFunction)language_field_name_for_id, + .ml_flags = METH_VARARGS, + .ml_doc = language_field_name_for_id_doc, + }, + { + .ml_name = "field_id_for_name", + .ml_meth = (PyCFunction)language_field_id_for_name, + .ml_flags = METH_VARARGS, + .ml_doc = language_field_id_for_name_doc, + }, + { + .ml_name = "next_state", + .ml_meth = (PyCFunction)language_next_state, + .ml_flags = METH_VARARGS, + .ml_doc = language_next_state_doc, + }, + { + .ml_name = "lookahead_iterator", + .ml_meth = (PyCFunction)language_lookahead_iterator, + .ml_flags = METH_VARARGS, + .ml_doc = language_lookahead_iterator_doc, + }, + { + .ml_name = "query", + .ml_meth = (PyCFunction)language_query, + .ml_flags = METH_VARARGS, + .ml_doc = language_query_doc, + }, {NULL}, }; static PyGetSetDef language_accessors[] = { #if HAS_LANGUAGE_NAMES - {"name", (getter)language_get_name, NULL, "The name of the language.", NULL}, + {"name", (getter)language_get_name, NULL, PyDoc_STR("The name of the language."), NULL}, #endif {"version", (getter)language_get_version, NULL, - "Get the ABI version number that indicates which version of " - "the Tree-sitter CLI was used to generate this Language.", + PyDoc_STR("The ABI version number that indicates which version of " + "the Tree-sitter CLI was used to generate this Language."), NULL}, {"node_kind_count", (getter)language_get_node_kind_count, NULL, - "Get the number of distinct node types in this language.", NULL}, + PyDoc_STR("The number of distinct node types in this language."), NULL}, {"parse_state_count", (getter)language_get_parse_state_count, NULL, - "Get the number of valid states in this language.", NULL}, + PyDoc_STR("The number of valid states in this language."), NULL}, {"field_count", (getter)language_get_field_count, NULL, - "Get the number of fields in this language.", NULL}, + PyDoc_STR("The number of distinct field names in this language."), NULL}, {NULL}, }; static PyType_Slot language_type_slots[] = { - {Py_tp_doc, "A tree-sitter language."}, + {Py_tp_doc, PyDoc_STR("A class that defines how to parse a particular language.")}, {Py_tp_init, language_init}, {Py_tp_repr, language_repr}, {Py_tp_hash, language_hash}, diff --git a/tree_sitter/binding/lookahead_iterator.c b/tree_sitter/binding/lookahead_iterator.c index faeae8f1..84fcc2ac 100644 --- a/tree_sitter/binding/lookahead_iterator.c +++ b/tree_sitter/binding/lookahead_iterator.c @@ -97,7 +97,7 @@ PyObject *lookahead_iterator_next(LookaheadIterator *self) { return PyLong_FromUnsignedLong(symbol); } -PyObject *lookahead_iterator_names_iterator(LookaheadIterator *self) { +PyObject *lookahead_iterator_iter_names(LookaheadIterator *self) { ModuleState *state = GET_MODULE_STATE(self); LookaheadNamesIterator *iter = PyObject_New(LookaheadNamesIterator, state->lookahead_names_iterator_type); @@ -108,47 +108,66 @@ PyObject *lookahead_iterator_names_iterator(LookaheadIterator *self) { return PyObject_Init((PyObject *)iter, state->lookahead_names_iterator_type); } -static PyGetSetDef lookahead_iterator_accessors[] = { - {"language", (getter)lookahead_iterator_get_language, NULL, "Get the language.", NULL}, - {"current_symbol", (getter)lookahead_iterator_get_current_symbol, NULL, - "Get the current symbol.", NULL}, - {"current_symbol_name", (getter)lookahead_iterator_get_current_symbol_name, NULL, - "Get the current symbol name.", NULL}, - {NULL}, -}; +PyDoc_STRVAR(lookahead_iterator_reset_doc, + "reset(self, language, state, /)\n--\n\n" + "Reset the lookahead iterator.\n\n" + ".. deprecated:: 0.22.0\n\n Use :meth:`reset_state` instead." DOC_RETURNS + "``True`` if it was reset successfully or ``False`` if it failed."); +PyDoc_STRVAR(lookahead_iterator_reset_state_doc, + "reset_state(self, state, language=None)\n--\n\n" + "Reset the lookahead iterator." DOC_RETURNS + "``True`` if it was reset successfully or ``False`` if it failed."); +PyDoc_STRVAR(lookahead_iterator_iter_names_doc, "iter_names(self, /)\n--\n\n" + "Iterate symbol names."); static PyMethodDef lookahead_iterator_methods[] = { - {.ml_name = "reset", - .ml_meth = (PyCFunction)lookahead_iterator_reset, - .ml_flags = METH_VARARGS, - .ml_doc = "reset(language, state)\n--\n\n\ - Reset the lookahead iterator to a new language and parse state.\n\ - This returns `True` if the language was set successfully, and `False` otherwise."}, - {.ml_name = "reset_state", - .ml_meth = (PyCFunction)lookahead_iterator_reset_state, - .ml_flags = METH_VARARGS | METH_KEYWORDS, - .ml_doc = "reset_state(state, language=None)\n--\n\n\ - Reset the lookahead iterator to a new parse state and optional language.\n\ - This returns `True` if the state was set successfully, and `False` otherwise."}, + { + .ml_name = "reset", + .ml_meth = (PyCFunction)lookahead_iterator_reset, + .ml_flags = METH_VARARGS, + .ml_doc = lookahead_iterator_reset_doc, + }, + { + .ml_name = "reset_state", + .ml_meth = (PyCFunction)lookahead_iterator_reset_state, + .ml_flags = METH_VARARGS | METH_KEYWORDS, + .ml_doc = lookahead_iterator_reset_state_doc, + }, { .ml_name = "iter_names", - .ml_meth = (PyCFunction)lookahead_iterator_names_iterator, + .ml_meth = (PyCFunction)lookahead_iterator_iter_names, .ml_flags = METH_NOARGS, - .ml_doc = "iter_names()\n--\n\n\ - Get an iterator of the names of possible syntax nodes that could come next.", + .ml_doc = lookahead_iterator_iter_names_doc, }, {NULL}, }; +static PyGetSetDef lookahead_iterator_accessors[] = { + {"language", (getter)lookahead_iterator_get_language, NULL, PyDoc_STR("The current language."), + NULL}, + {"current_symbol", (getter)lookahead_iterator_get_current_symbol, NULL, + PyDoc_STR("The current symbol.\n\nNewly created iterators will return the ``ERROR`` symbol."), + NULL}, + {"current_symbol_name", (getter)lookahead_iterator_get_current_symbol_name, NULL, + PyDoc_STR("The current symbol name."), NULL}, + {NULL}, +}; + static PyType_Slot lookahead_iterator_type_slots[] = { - {Py_tp_doc, "An iterator over the possible syntax nodes that could come next."}, + {Py_tp_doc, + PyDoc_STR( + "A class that is used to look up symbols valid in a specific parse state." DOC_TIP + "Lookahead iterators can be useful to generate suggestions and improve syntax error " + "diagnostics.\n\nTo get symbols valid in an ``ERROR`` node, use the lookahead iterator " + "on its first leaf node state.\nFor ``MISSING`` nodes, a lookahead iterator created " + "on the previous non-extra leaf node may be appropriate.")}, {Py_tp_new, NULL}, {Py_tp_dealloc, lookahead_iterator_dealloc}, {Py_tp_repr, lookahead_iterator_repr}, - {Py_tp_getset, lookahead_iterator_accessors}, - {Py_tp_methods, lookahead_iterator_methods}, {Py_tp_iter, lookahead_iterator_iter}, {Py_tp_iternext, lookahead_iterator_next}, + {Py_tp_methods, lookahead_iterator_methods}, + {Py_tp_getset, lookahead_iterator_accessors}, {0, NULL}, }; diff --git a/tree_sitter/binding/lookahead_iterator.h b/tree_sitter/binding/lookahead_iterator.h index e2670f9f..b7509fb9 100644 --- a/tree_sitter/binding/lookahead_iterator.h +++ b/tree_sitter/binding/lookahead_iterator.h @@ -20,4 +20,4 @@ PyObject *lookahead_iterator_iter(LookaheadIterator *self); PyObject *lookahead_iterator_next(LookaheadIterator *self); -PyObject *lookahead_iterator_names_iterator(LookaheadIterator *self); +PyObject *lookahead_iterator_iter_names(LookaheadIterator *self); diff --git a/tree_sitter/binding/lookahead_names_iterator.c b/tree_sitter/binding/lookahead_names_iterator.c index d83d3683..8d3b95df 100644 --- a/tree_sitter/binding/lookahead_names_iterator.c +++ b/tree_sitter/binding/lookahead_names_iterator.c @@ -23,7 +23,7 @@ PyObject *lookahead_names_iterator_next(LookaheadNamesIterator *self) { } static PyType_Slot lookahead_names_iterator_type_slots[] = { - {Py_tp_doc, "An iterator over the possible syntax nodes that could come next."}, + {Py_tp_doc, PyDoc_STR("An iterator over the names of syntax nodes that could come next.")}, {Py_tp_new, NULL}, {Py_tp_dealloc, lookahead_names_iterator_dealloc}, {Py_tp_repr, lookahead_names_iterator_repr}, diff --git a/tree_sitter/binding/node.c b/tree_sitter/binding/node.c index bc2e1c75..0e5d5328 100644 --- a/tree_sitter/binding/node.c +++ b/tree_sitter/binding/node.c @@ -553,156 +553,237 @@ Py_hash_t node_hash(Node *self) { return id == tree ? id : id ^ tree; } +PyDoc_STRVAR(node_walk_doc, "walk(self, /)\n--\n\n" + "Create a new :class:`TreeCursor` starting from this node."); +PyDoc_STRVAR(node_edit_doc, + "edit(self, /, start_byte, old_end_byte, new_end_byte, start_point, " + "old_end_point, new_end_point)\n--\n\n" + "Edit this node to keep it in-sync with source code that has been edited." DOC_NOTE + "This method is only rarely needed. When you edit a syntax tree via " + ":meth:`Tree.edit`, all of the nodes that you retrieve from the tree afterwards " + "will already reflect the edit. You only need to use this when you have a specific " + ":class:`Node` instance that you want to keep and continue to use after an edit."); +PyDoc_STRVAR(node_sexp_doc, "sexp(self, /)\n--\n\n" + "Get an S-expression representing the node.\n\n" + ".. deprecated:: 0.22.0\n\n Use :obj:`str` instead."); +PyDoc_STRVAR(node_child_doc, + "child(self, index, /)\n--\n\n" + "Get this node's child at the given index, where ``0`` represents the first " + "child." DOC_CAUTION "This method is fairly fast, but its cost is technically " + "``log(i)``, so if you might be iterating over a long list of children, " + "you should use :attr:`children` or :meth:`walk` instead."); +PyDoc_STRVAR(node_named_child_doc, + "named_child(self, index, /)\n--\n\n" + "Get this node's *named* child at the given index, where ``0`` represents the first " + "child." DOC_CAUTION "This method is fairly fast, but its cost is technically " + "``log(i)``, so if you might be iterating over a long list of children, " + "you should use :attr:`children` or :meth:`walk` instead."); +PyDoc_STRVAR(node_child_by_field_id_doc, + "child_by_field_id(self, id, /)\n--\n\n" + "Get the first child with the given numerical field id." DOC_HINT + "You can convert a field name to an id using :meth:`Language.field_id_for_name`." + DOC_SEE_ALSO ":meth:`child_by_field_name`"); +PyDoc_STRVAR(node_children_by_field_id_doc, + "children_by_field_id(self, id, /)\n--\n\n" + "Get a list of children with the given numerical field id." + DOC_SEE_ALSO ":meth:`children_by_field_name`" ); +PyDoc_STRVAR(node_child_by_field_name_doc, "child_by_field_name(self, name, /)\n--\n\n" + "Get the first child with the given field name."); +PyDoc_STRVAR(node_children_by_field_name_doc, "children_by_field_name(self, name, /)\n--\n\n" + "Get a list of children with the given field name."); +PyDoc_STRVAR(node_field_name_for_child_doc, + "field_name_for_child(self, child_index, /)\n--\n\n" + "Get the field name of this node's child at the given index."); +PyDoc_STRVAR(node_descendant_for_byte_range_doc, + "descendant_for_byte_range(self, start_byte, end_byte, /)\n--\n\n" + "Get the smallest node within this node that spans the given byte range."); +PyDoc_STRVAR(node_named_descendant_for_byte_range_doc, + "named_descendant_for_byte_range(self, start_byte, end_byte, /)\n--\n\n" + "Get the smallest *named* node within this node that spans the given byte range."); +PyDoc_STRVAR(node_descendant_for_point_range_doc, + "descendant_for_point_range(self, start_point, end_point, /)\n--\n\n" + "Get the smallest node within this node that spans the given point range."); +PyDoc_STRVAR(node_named_descendant_for_point_range_doc, + "named_descendant_for_point_range(self, start_point, end_point, /)\n--\n\n" + "Get the smallest *named* node within this node that spans the given point range."); + static PyMethodDef node_methods[] = { { .ml_name = "walk", .ml_meth = (PyCFunction)node_walk, .ml_flags = METH_NOARGS, - .ml_doc = "walk()\n--\n\n\ - Get a tree cursor for walking the tree starting at this node.", + .ml_doc = node_walk_doc, }, { .ml_name = "edit", .ml_meth = (PyCFunction)node_edit, .ml_flags = METH_VARARGS | METH_KEYWORDS, - .ml_doc = - "edit(start_byte, old_end_byte, new_end_byte, start_point, old_end_point, new_end_point)\n--\n\n\ - Edit this node to keep it in-sync with source code that has been edited.", + .ml_doc = node_edit_doc, }, { .ml_name = "sexp", .ml_meth = (PyCFunction)node_sexp, .ml_flags = METH_NOARGS, - .ml_doc = "sexp()\n--\n\n\ - Get an S-expression representing the node.", + .ml_doc = node_sexp_doc, }, { .ml_name = "child", .ml_meth = (PyCFunction)node_child, .ml_flags = METH_VARARGS, - .ml_doc = "child(index)\n--\n\n\ - Get child at the given index.", + .ml_doc = node_child_doc, }, { .ml_name = "named_child", .ml_meth = (PyCFunction)node_named_child, .ml_flags = METH_VARARGS, - .ml_doc = "named_child(index)\n--\n\n\ - Get named child by index.", + .ml_doc = node_named_child_doc, }, { .ml_name = "child_by_field_id", .ml_meth = (PyCFunction)node_child_by_field_id, .ml_flags = METH_VARARGS, - .ml_doc = "child_by_field_id(id)\n--\n\n\ - Get child for the given field id.", + .ml_doc = node_child_by_field_id_doc, }, { .ml_name = "child_by_field_name", .ml_meth = (PyCFunction)node_child_by_field_name, .ml_flags = METH_VARARGS, - .ml_doc = "child_by_field_name(name)\n--\n\n\ - Get child for the given field name.", + .ml_doc = node_child_by_field_name_doc, }, { .ml_name = "children_by_field_id", .ml_meth = (PyCFunction)node_children_by_field_id, .ml_flags = METH_VARARGS, - .ml_doc = "children_by_field_id(id)\n--\n\n\ - Get a list of child nodes for the given field id.", + .ml_doc = node_children_by_field_id_doc, }, { .ml_name = "children_by_field_name", .ml_meth = (PyCFunction)node_children_by_field_name, .ml_flags = METH_VARARGS, - .ml_doc = "children_by_field_name(name)\n--\n\n\ - Get a list of child nodes for the given field name.", + .ml_doc = node_children_by_field_name_doc, + }, + { + .ml_name = "field_name_for_child", + .ml_meth = (PyCFunction)node_field_name_for_child, + .ml_flags = METH_VARARGS, + .ml_doc = node_field_name_for_child_doc, }, - {.ml_name = "field_name_for_child", - .ml_meth = (PyCFunction)node_field_name_for_child, - .ml_flags = METH_VARARGS, - .ml_doc = "field_name_for_child(index)\n-\n\n\ - Get the field name of a child node by the index of child."}, { .ml_name = "descendant_for_byte_range", .ml_meth = (PyCFunction)node_descendant_for_byte_range, .ml_flags = METH_VARARGS, - .ml_doc = "descendant_for_byte_range(start_byte, end_byte)\n--\n\n\ - Get the smallest node within this node that spans the given byte range.", + .ml_doc = node_descendant_for_byte_range_doc, }, { .ml_name = "named_descendant_for_byte_range", .ml_meth = (PyCFunction)node_named_descendant_for_byte_range, .ml_flags = METH_VARARGS, - .ml_doc = "named_descendant_for_byte_range(start_byte, end_byte)\n--\n\n\ - Get the smallest named node within this node that spans the given byte range.", + .ml_doc = node_named_descendant_for_byte_range_doc, }, { .ml_name = "descendant_for_point_range", .ml_meth = (PyCFunction)node_descendant_for_point_range, .ml_flags = METH_VARARGS, - .ml_doc = "descendant_for_point_range(start_point, end_point)\n--\n\n\ - Get the smallest node within this node that spans the given point range.", + .ml_doc = node_descendant_for_point_range_doc, }, { .ml_name = "named_descendant_for_point_range", .ml_meth = (PyCFunction)node_named_descendant_for_point_range, .ml_flags = METH_VARARGS, - .ml_doc = "named_descendant_for_point_range(start_point, end_point)\n--\n\n\ - Get the smallest named node within this node that spans the given point range.", + .ml_doc = node_named_descendant_for_point_range_doc, }, {NULL}, }; static PyGetSetDef node_accessors[] = { - {"id", (getter)node_get_id, NULL, "The node's numeric id", NULL}, - {"kind_id", (getter)node_get_kind_id, NULL, "The node's type as a numerical id", NULL}, - {"grammar_id", (getter)node_get_grammar_id, NULL, "The node's grammar type as a numerical id", + {"id", (getter)node_get_id, NULL, + PyDoc_STR("This node's numerical id." DOC_NOTE + "Within a given syntax tree, no two nodes have the same id. However, if a new tree " + "is created based on an older tree, and a node from the old tree is reused in the " + "process, then that node will have the same id in both trees."), + NULL}, + {"kind_id", (getter)node_get_kind_id, NULL, PyDoc_STR("This node's type as a numerical id."), + NULL}, + {"grammar_id", (getter)node_get_grammar_id, NULL, + PyDoc_STR("This node's type as a numerical id as it appears in the grammar ignoring aliases."), + NULL}, + {"grammar_name", (getter)node_get_grammar_name, NULL, + PyDoc_STR("This node's symbol name as it appears in the grammar ignoring aliases."), NULL}, + {"type", (getter)node_get_type, NULL, PyDoc_STR("This node's type as a string."), NULL}, + {"is_named", (getter)node_get_is_named, NULL, + PyDoc_STR("Check if this node is _named_.\n\nNamed nodes correspond to named rules in the " + "grammar, whereas *anonymous* nodes correspond to string literals in the grammar."), NULL}, - {"grammar_name", (getter)node_get_grammar_name, NULL, "The node's grammar name as a string", + {"is_extra", (getter)node_get_is_extra, NULL, + PyDoc_STR("Check if this node is _extra_.\n\nExtra nodes represent things which are not " + "required the grammar but can appear anywhere (e.g. whitespace)."), NULL}, - {"type", (getter)node_get_type, NULL, "The node's type", NULL}, - {"is_named", (getter)node_get_is_named, NULL, "Is this a named node", NULL}, - {"is_extra", (getter)node_get_is_extra, NULL, "Is this an extra node", NULL}, {"has_changes", (getter)node_get_has_changes, NULL, - "Does this node have text changes since it was parsed", NULL}, - {"has_error", (getter)node_get_has_error, NULL, "Does this node contain any errors", NULL}, - {"is_error", (getter)node_get_is_error, NULL, "Is this node an error", NULL}, - {"parse_state", (getter)node_get_parse_state, NULL, "The node's parse state", NULL}, + PyDoc_STR("Check if this node has been edited."), NULL}, + {"has_error", (getter)node_get_has_error, NULL, + PyDoc_STR("Check if this node represents a syntax error or contains any syntax errors " + "anywhere within it."), + NULL}, + {"is_error", (getter)node_get_is_error, NULL, + PyDoc_STR("Check if this node represents a syntax error.\n\nSyntax errors represent parts of " + "the code that could not be incorporated into a valid syntax tree."), + NULL}, + {"parse_state", (getter)node_get_parse_state, NULL, PyDoc_STR("This node's parse state."), + NULL}, {"next_parse_state", (getter)node_get_next_parse_state, NULL, - "The parse state after this node's", NULL}, - {"is_missing", (getter)node_get_is_missing, NULL, "Is this a node inserted by the parser", + PyDoc_STR("The parse state after this node."), NULL}, + {"is_missing", (getter)node_get_is_missing, NULL, + PyDoc_STR("Check if this node is _missing_.\n\nMissing nodes are inserted by the parser in " + "order to recover from certain kinds of syntax errors."), NULL}, - {"start_byte", (getter)node_get_start_byte, NULL, "The node's start byte", NULL}, - {"end_byte", (getter)node_get_end_byte, NULL, "The node's end byte", NULL}, - {"byte_range", (getter)node_get_byte_range, NULL, "The node's byte range", NULL}, - {"range", (getter)node_get_range, NULL, "The node's range", NULL}, - {"start_point", (getter)node_get_start_point, NULL, "The node's start point", NULL}, - {"end_point", (getter)node_get_end_point, NULL, "The node's end point", NULL}, - {"children", (getter)node_get_children, NULL, "The node's children", NULL}, - {"child_count", (getter)node_get_child_count, NULL, "The number of children for a node", NULL}, - {"named_children", (getter)node_get_named_children, NULL, "The node's named children", NULL}, + {"start_byte", (getter)node_get_start_byte, NULL, + PyDoc_STR("The byte offset where this node starts."), NULL}, + {"end_byte", (getter)node_get_end_byte, NULL, + PyDoc_STR("The byte offset where this node ends."), NULL}, + {"byte_range", (getter)node_get_byte_range, NULL, + PyDoc_STR("The byte range of source code that this node represents, in terms of bytes."), + NULL}, + {"range", (getter)node_get_range, NULL, + PyDoc_STR("The range of source code that this node represents."), NULL}, + {"start_point", (getter)node_get_start_point, NULL, PyDoc_STR("This node's start point"), NULL}, + {"end_point", (getter)node_get_end_point, NULL, PyDoc_STR("This node's end point."), NULL}, + {"children", (getter)node_get_children, NULL, + PyDoc_STR("This node's children." DOC_NOTE + "If you're walking the tree recursively, you may want to use :meth:`walk` instead."), + NULL}, + {"child_count", (getter)node_get_child_count, NULL, + PyDoc_STR("This node's number of children."), NULL}, + {"named_children", (getter)node_get_named_children, NULL, + PyDoc_STR("This node's _named_ children."), NULL}, {"named_child_count", (getter)node_get_named_child_count, NULL, - "The number of named children for a node", NULL}, - {"parent", (getter)node_get_parent, NULL, "The node's parent", NULL}, - {"next_sibling", (getter)node_get_next_sibling, NULL, "The node's next sibling", NULL}, - {"prev_sibling", (getter)node_get_prev_sibling, NULL, "The node's previous sibling", NULL}, + PyDoc_STR("This node's number of _named_ children."), NULL}, + {"parent", (getter)node_get_parent, NULL, PyDoc_STR("This node's immediate parent."), NULL}, + {"next_sibling", (getter)node_get_next_sibling, NULL, PyDoc_STR("This node's next sibling."), + NULL}, + {"prev_sibling", (getter)node_get_prev_sibling, NULL, + PyDoc_STR("This node's previous sibling."), NULL}, {"next_named_sibling", (getter)node_get_next_named_sibling, NULL, - "The node's next named sibling", NULL}, + PyDoc_STR("This node's next named sibling."), NULL}, {"prev_named_sibling", (getter)node_get_prev_named_sibling, NULL, - "The node's previous named sibling", NULL}, + PyDoc_STR("This node's previous named sibling."), NULL}, {"descendant_count", (getter)node_get_descendant_count, NULL, - "The number of descendants for a node, including itself", NULL}, - {"text", (getter)node_get_text, NULL, "The node's text, if tree has not been edited", NULL}, + PyDoc_STR("This node's number of descendants, including the node itself."), NULL}, + {"text", (getter)node_get_text, NULL, + PyDoc_STR("The text of the node, if the tree has not been edited"), NULL}, {NULL}, }; static PyType_Slot node_type_slots[] = { - {Py_tp_doc, "A syntax node"}, {Py_tp_new, NULL}, - {Py_tp_dealloc, node_dealloc}, {Py_tp_repr, node_repr}, - {Py_tp_str, node_str}, {Py_tp_richcompare, node_compare}, - {Py_tp_hash, node_hash}, {Py_tp_methods, node_methods}, - {Py_tp_getset, node_accessors}, {0, NULL}, + {Py_tp_doc, PyDoc_STR("A single node within a syntax ``Tree``.")}, + {Py_tp_new, NULL}, + {Py_tp_dealloc, node_dealloc}, + {Py_tp_repr, node_repr}, + {Py_tp_str, node_str}, + {Py_tp_richcompare, node_compare}, + {Py_tp_hash, node_hash}, + {Py_tp_methods, node_methods}, + {Py_tp_getset, node_accessors}, + {0, NULL}, }; PyType_Spec node_type_spec = { diff --git a/tree_sitter/binding/parser.c b/tree_sitter/binding/parser.c index 6966dd86..ce47f280 100644 --- a/tree_sitter/binding/parser.c +++ b/tree_sitter/binding/parser.c @@ -335,58 +335,82 @@ PyObject *parser_set_language_old(Parser *self, PyObject *arg) { Py_RETURN_NONE; } -static PyGetSetDef parser_accessors[] = { - {"language", (getter)parser_get_language, (setter)parser_set_language, - "The parser's current language.", NULL}, - {"included_ranges", (getter)parser_get_included_ranges, (setter)parser_set_included_ranges, - "The ranges of text that the parser should include when parsing.", NULL}, - {"timeout_micros", (getter)parser_get_timeout_micros, (setter)parser_set_timeout_micros, - "The duration in microseconds that parsing is allowed to take.", NULL}, - {NULL}, -}; +PyDoc_STRVAR( + parser_parse_doc, + "parse(self, source, /, old_tree=None, keep_text=True)\n--\n\n" + "Parse a slice of a bytestring or bytes provided in chunks by a callback.\n\n" + "The callback function takes a byte offset and position and returns a bytestring starting " + "at that offset and position. The slices can be of any length. If the given position " + "is at the end of the text, the callback should return an empty slice." DOC_RETURNS + "A :class:`Tree` if parsing succeeded or ``None`` if the parser does not have an " + "assigned language or the timeout expired."); +PyDoc_STRVAR( + parser_reset_doc, + "reset(self, /)\n--\n\n" + "Instruct the parser to start the next parse from the beginning." DOC_NOTE + "If the parser previously failed because of a timeout, then by default, it will resume where " + "it left off on the next call to :meth:`parse`.\nIf you don't want to resume, and instead " + "intend to use this parser to parse some other document, you must call :meth:`reset` first."); +PyDoc_STRVAR(parser_set_language_doc, + "set_language(self, language, /)\n--\n\n" + "Set the language that will be used for parsing.\n\n" + ".. deprecated:: 0.22.0\n\n Use the :attr:`language` setter instead."); +PyDoc_STRVAR(parser_set_included_ranges_doc, + "set_included_ranges(self, ranges, /)\n--\n\n" + "Set the ranges of text that the parser will include when parsing.\n\n" + ".. deprecated:: 0.22.0\n\n Use the :attr:`included_ranges` setter instead."); +PyDoc_STRVAR(parser_set_timeout_micros_doc, + "set_timeout_micros(self, timeout, /)\n--\n\n" + "Set the duration in microseconds that parsing is allowed to take.\n\n" + ".. deprecated:: 0.22.0\n\n Use the :attr:`timeout_micros` setter instead."); static PyMethodDef parser_methods[] = { { .ml_name = "parse", .ml_meth = (PyCFunction)parser_parse, .ml_flags = METH_VARARGS | METH_KEYWORDS, - .ml_doc = "parse(bytes, old_tree=None, keep_text=True)\n--\n\n\ - Parse source code, creating a syntax tree.", + .ml_doc = parser_parse_doc, }, { .ml_name = "reset", .ml_meth = (PyCFunction)parser_reset, .ml_flags = METH_NOARGS, - .ml_doc = "reset()\n--\n\n\ - Instruct the parser to start the next parse from the beginning.", + .ml_doc = parser_reset_doc, }, { .ml_name = "set_timeout_micros", .ml_meth = (PyCFunction)parser_set_timeout_micros_old, .ml_flags = METH_O, - .ml_doc = "set_timeout_micros(timeout_micros)\n--\n\n\ - Set the maximum duration in microseconds that parsing should be allowed to\ - take before halting.", + .ml_doc = parser_set_timeout_micros_doc, }, { .ml_name = "set_included_ranges", .ml_meth = (PyCFunction)parser_set_included_ranges_old, .ml_flags = METH_O, - .ml_doc = "set_included_ranges(ranges)\n--\n\n\ - Set the ranges of text that the parser should include when parsing.", + .ml_doc = parser_set_included_ranges_doc, }, { .ml_name = "set_language", .ml_meth = (PyCFunction)parser_set_language_old, .ml_flags = METH_O, - .ml_doc = "set_language(language)\n--\n\n\ - Set the parser language.", + .ml_doc = parser_set_language_doc, }, {NULL}, }; +static PyGetSetDef parser_accessors[] = { + {"language", (getter)parser_get_language, (setter)parser_set_language, + PyDoc_STR("The language that will be used for parsing."), NULL}, + {"included_ranges", (getter)parser_get_included_ranges, (setter)parser_set_included_ranges, + PyDoc_STR("The ranges of text that the parser will include when parsing."), NULL}, + {"timeout_micros", (getter)parser_get_timeout_micros, (setter)parser_set_timeout_micros, + PyDoc_STR("The duration in microseconds that parsing is allowed to take."), NULL}, + {NULL}, +}; + static PyType_Slot parser_type_slots[] = { - {Py_tp_doc, "A parser"}, + {Py_tp_doc, + PyDoc_STR("A class that is used to produce a :class:`Tree` based on some source code.")}, {Py_tp_new, parser_new}, {Py_tp_init, parser_init}, {Py_tp_dealloc, parser_dealloc}, diff --git a/tree_sitter/binding/query.c b/tree_sitter/binding/query.c index 47b3a80c..89b39aae 100644 --- a/tree_sitter/binding/query.c +++ b/tree_sitter/binding/query.c @@ -622,24 +622,36 @@ PyObject *query_captures(Query *self, PyObject *args, PyObject *kwargs) { return NULL; } +#define QUERY_METHOD_SIGNATURE \ + "(self, node, *, start_point=None, end_point=None, start_byte=None, end_byte=None)\n--\n\n" + +PyDoc_STRVAR(query_matches_doc, + "matches" QUERY_METHOD_SIGNATURE "Get a list of *matches* within the given node.\n\n" + "You can optionally limit the matches to a range of row/column points or of bytes."); +PyDoc_STRVAR( + query_captures_doc, + "captures" QUERY_METHOD_SIGNATURE "Get a list of *captures* within the given node.\n\n" + "You can optionally limit the captures to a range of row/column points or of bytes." DOC_HINT + "This method returns all of the captures while :meth:`matches` only returns the last match."); + static PyMethodDef query_methods[] = { - {.ml_name = "matches", - .ml_meth = (PyCFunction)query_matches, - .ml_flags = METH_KEYWORDS | METH_VARARGS, - .ml_doc = "matches(node)\n--\n\n\ - Get a list of all of the matches within the given node."}, + { + .ml_name = "matches", + .ml_meth = (PyCFunction)query_matches, + .ml_flags = METH_KEYWORDS | METH_VARARGS, + .ml_doc = query_matches_doc, + }, { .ml_name = "captures", .ml_meth = (PyCFunction)query_captures, .ml_flags = METH_KEYWORDS | METH_VARARGS, - .ml_doc = "captures(node)\n--\n\n\ - Get a list of all of the captures within the given node.", + .ml_doc = query_captures_doc, }, {NULL}, }; static PyType_Slot query_type_slots[] = { - {Py_tp_doc, "A set of patterns to search for in a syntax tree."}, + {Py_tp_doc, PyDoc_STR("A set of patterns that match nodes in a syntax tree.")}, {Py_tp_new, query_new}, {Py_tp_dealloc, query_dealloc}, {Py_tp_methods, query_methods}, diff --git a/tree_sitter/binding/range.c b/tree_sitter/binding/range.c index 168afb55..fc52fb2b 100644 --- a/tree_sitter/binding/range.c +++ b/tree_sitter/binding/range.c @@ -81,15 +81,16 @@ PyObject *range_get_end_byte(Range *self, void *Py_UNUSED(payload)) { } static PyGetSetDef range_accessors[] = { - {"start_point", (getter)range_get_start_point, NULL, "The start point of this range", NULL}, - {"start_byte", (getter)range_get_start_byte, NULL, "The start byte of this range", NULL}, - {"end_point", (getter)range_get_end_point, NULL, "The end point of this range", NULL}, - {"end_byte", (getter)range_get_end_byte, NULL, "The end byte of this range", NULL}, + {"start_point", (getter)range_get_start_point, NULL, PyDoc_STR("The start point."), NULL}, + {"start_byte", (getter)range_get_start_byte, NULL, PyDoc_STR("The start byte."), NULL}, + {"end_point", (getter)range_get_end_point, NULL, PyDoc_STR("The end point."), NULL}, + {"end_byte", (getter)range_get_end_byte, NULL, PyDoc_STR("The end byte."), NULL}, {NULL}, }; static PyType_Slot range_type_slots[] = { - {Py_tp_doc, "A range within a document."}, + {Py_tp_doc, PyDoc_STR("A range of positions in a multi-line text document, " + "both in terms of bytes and of rows and columns.")}, {Py_tp_init, range_init}, {Py_tp_dealloc, range_dealloc}, {Py_tp_repr, range_repr}, diff --git a/tree_sitter/binding/tree.c b/tree_sitter/binding/tree.c index d53edd54..97e1943b 100644 --- a/tree_sitter/binding/tree.c +++ b/tree_sitter/binding/tree.c @@ -134,51 +134,74 @@ PyObject *tree_get_included_ranges(Tree *self, PyObject *Py_UNUSED(args)) { return result; } +PyDoc_STRVAR(tree_root_node_with_offset_doc, + "root_node_with_offset(self, offset_bytes, offset_extent, /)\n--\n\n" + "Get the root node of the syntax tree, but with its position shifted " + "forward by the given offset."); +PyDoc_STRVAR(tree_walk_doc, "walk(self, /)\n--\n\n" + "Create a new :class:`TreeCursor` starting from the root of the tree."); +PyDoc_STRVAR(tree_edit_doc, + "edit(self, start_byte, old_end_byte, new_end_byte, start_point, old_end_point, " + "new_end_point)\n--\n\n" + "Edit the syntax tree to keep it in sync with source code that has been edited.\n\n" + "You must describe the edit both in terms of byte offsets and of row/column points."); +PyDoc_STRVAR( + tree_changed_ranges_doc, + "changed_ranges(self, /, new_tree)\n--\n\n" + "Compare this old edited syntax tree to a new syntax tree representing the same document, " + "returning a sequence of ranges whose syntactic structure has changed." DOC_TIP + "For this to work correctly, this syntax tree must have been edited such that its " + "ranges match up to the new tree.\n\nGenerally, you'll want to call this method " + "right after calling the :meth:`Parser.parse` method. Call it on the old tree that " + "was passed to the method, and pass the new tree that was returned from it."); + static PyMethodDef tree_methods[] = { { .ml_name = "root_node_with_offset", .ml_meth = (PyCFunction)tree_root_node_with_offset, .ml_flags = METH_VARARGS, - .ml_doc = "root_node_with_offset(offset_bytes, offset_extent)\n--\n\n\ - Get the root node of the syntax tree, but with its position shifted forward by the given offset.", + .ml_doc = tree_root_node_with_offset_doc, }, { .ml_name = "walk", .ml_meth = (PyCFunction)tree_walk, .ml_flags = METH_NOARGS, - .ml_doc = "walk()\n--\n\n\ - Get a tree cursor for walking this tree.", + .ml_doc = tree_walk_doc, }, { .ml_name = "edit", .ml_meth = (PyCFunction)tree_edit, .ml_flags = METH_KEYWORDS | METH_VARARGS, - .ml_doc = "edit(start_byte, old_end_byte, new_end_byte,\ - start_point, old_end_point, new_end_point)\n--\n\n\ - Edit the syntax tree.", + .ml_doc = tree_edit_doc, }, { .ml_name = "changed_ranges", .ml_meth = (PyCFunction)tree_changed_ranges, .ml_flags = METH_KEYWORDS | METH_VARARGS, - .ml_doc = "changed_ranges(new_tree)\n--\n\n\ - Compare old edited tree to new tree and return changed ranges.", + .ml_doc = tree_changed_ranges_doc, }, {NULL}, }; static PyGetSetDef tree_accessors[] = { - {"root_node", (getter)tree_get_root_node, NULL, "The root node of this tree.", NULL}, - {"text", (getter)tree_get_text, NULL, "The source text for this tree, if unedited.", NULL}, + {"root_node", (getter)tree_get_root_node, NULL, PyDoc_STR("The root node of the syntax tree."), + NULL}, + {"text", (getter)tree_get_text, NULL, + PyDoc_STR("The source text of this tree, if unedited.\n\n" + ".. deprecated:: 0.22.0\n Use ``root_node.text`` instead."), + NULL}, {"included_ranges", (getter)tree_get_included_ranges, NULL, - "Get the included ranges that were used to parse the syntax tree.", NULL}, + PyDoc_STR("The included ranges that were used to parse the syntax tree."), NULL}, {NULL}, }; static PyType_Slot tree_type_slots[] = { - {Py_tp_doc, "A syntax tree"}, {Py_tp_new, NULL}, - {Py_tp_dealloc, tree_dealloc}, {Py_tp_methods, tree_methods}, - {Py_tp_getset, tree_accessors}, {0, NULL}, + {Py_tp_doc, PyDoc_STR("A tree that represents the syntactic structure of a source code file.")}, + {Py_tp_new, NULL}, + {Py_tp_dealloc, tree_dealloc}, + {Py_tp_methods, tree_methods}, + {Py_tp_getset, tree_accessors}, + {0, NULL}, }; PyType_Spec tree_type_spec = { diff --git a/tree_sitter/binding/tree_cursor.c b/tree_sitter/binding/tree_cursor.c index c6e6095c..f2f93883 100644 --- a/tree_sitter/binding/tree_cursor.c +++ b/tree_sitter/binding/tree_cursor.c @@ -22,7 +22,7 @@ PyObject *tree_cursor_get_node(TreeCursor *self, void *Py_UNUSED(payload)) { return self->node; } -PyObject *tree_cursor_get_current_field_id(TreeCursor *self, void *Py_UNUSED(payload)) { +PyObject *tree_cursor_get_field_id(TreeCursor *self, void *Py_UNUSED(payload)) { TSFieldId field_id = ts_tree_cursor_current_field_id(&self->cursor); if (field_id == 0) { Py_RETURN_NONE; @@ -30,7 +30,7 @@ PyObject *tree_cursor_get_current_field_id(TreeCursor *self, void *Py_UNUSED(pay return PyLong_FromUnsignedLong(field_id); } -PyObject *tree_cursor_get_current_field_name(TreeCursor *self, void *Py_UNUSED(payload)) { +PyObject *tree_cursor_get_field_name(TreeCursor *self, void *Py_UNUSED(payload)) { const char *field_name = ts_tree_cursor_current_field_name(&self->cursor); if (field_name == NULL) { Py_RETURN_NONE; @@ -38,12 +38,12 @@ PyObject *tree_cursor_get_current_field_name(TreeCursor *self, void *Py_UNUSED(p return PyUnicode_FromString(field_name); } -PyObject *tree_cursor_get_current_depth(TreeCursor *self, void *Py_UNUSED(args)) { +PyObject *tree_cursor_get_depth(TreeCursor *self, void *Py_UNUSED(args)) { uint32_t depth = ts_tree_cursor_current_depth(&self->cursor); return PyLong_FromUnsignedLong(depth); } -PyObject *tree_cursor_get_current_descendant_index(TreeCursor *self, void *Py_UNUSED(payload)) { +PyObject *tree_cursor_get_descendant_index(TreeCursor *self, void *Py_UNUSED(payload)) { uint32_t index = ts_tree_cursor_current_descendant_index(&self->cursor); return PyLong_FromUnsignedLong(index); } @@ -109,7 +109,7 @@ PyObject *tree_cursor_goto_first_child_for_byte(TreeCursor *self, PyObject *args if (!PyArg_ParseTuple(args, "I:goto_first_child_for_byte", &byte)) { return NULL; } - bool result = ts_tree_cursor_goto_first_child_for_byte(&self->cursor, byte); + int64_t result = ts_tree_cursor_goto_first_child_for_byte(&self->cursor, byte); if (result) { Py_XDECREF(self->node); self->node = NULL; @@ -130,7 +130,8 @@ PyObject *tree_cursor_goto_first_child_for_point(TreeCursor *self, PyObject *arg return NULL; } } - bool result = ts_tree_cursor_goto_first_child_for_point(&self->cursor, (TSPoint){row, column}); + int64_t result = + ts_tree_cursor_goto_first_child_for_point(&self->cursor, (TSPoint){row, column}); if (result) { Py_XDECREF(self->node); self->node = NULL; @@ -179,151 +180,164 @@ PyObject *tree_cursor_copy(PyObject *self, PyObject *Py_UNUSED(args)) { return PyObject_Init((PyObject *)copied, state->tree_cursor_type); } +PyDoc_STRVAR(tree_cursor_goto_first_child_doc, + "goto_first_child(self, /)\n--\n\n" + "Move this cursor to the first child of its current node." DOC_RETURNS "``True`` " + "if the cursor successfully moved, or ``False`` if there were no children."); +PyDoc_STRVAR( + tree_cursor_goto_last_child_doc, + "goto_last_child(self, /)\n--\n\n" + "Move this cursor to the last child of its current node." DOC_RETURNS "``True`` " + "if the cursor successfully moved, or ``False`` if there were no children." DOC_ATTENTION + "This method may be slower than :meth:`goto_first_child` because it needs " + "to iterate through all the children to compute the child's position."); +PyDoc_STRVAR(tree_cursor_goto_parent_doc, + "goto_parent(self, /)\n--\n\n" + "Move this cursor to the parent of its current node." DOC_RETURNS "``True`` " + "if the cursor successfully moved, or ``False`` if there was no parent node " + "(i.e. the cursor was already on the root node)."); +PyDoc_STRVAR(tree_cursor_goto_next_sibling_doc, + "goto_next_sibling(self, /)\n--\n\n" + "Move this cursor to the next sibling of its current node." DOC_RETURNS "``True`` " + "if the cursor successfully moved, or ``False`` if there was no next sibling."); +PyDoc_STRVAR(tree_cursor_goto_previous_sibling_doc, + "goto_previous_sibling(self, /)\n--\n\n" + "Move this cursor to the previous sibling of its current node." DOC_RETURNS + "``True`` if the cursor successfully moved, or ``False`` if there was no previous " + "sibling." DOC_ATTENTION + "This method may be slower than :meth:`goto_next_sibling` due to how node positions " + "are stored.\nIn the worst case, this will need to iterate through all the children " + "up to the previous sibling node to recalculate its position."); +PyDoc_STRVAR( + tree_cursor_goto_descendant_doc, + "goto_descendant(self, index, /)\n--\n\n" + "Move the cursor to the node that is the n-th descendant of the original node that the " + "cursor was constructed with, where ``0`` represents the original node itself."); +PyDoc_STRVAR(tree_cursor_goto_first_child_for_byte_doc, + "goto_first_child_for_byte(self, byte, /)\n--\n\n" + "Move this cursor to the first child of its current node that extends beyond the " + "given byte offset." DOC_RETURNS + "``True`` if the child node was found, ``False`` otherwise."); +PyDoc_STRVAR(tree_cursor_goto_first_child_for_point_doc, + "goto_first_child_for_point(self, *args)\n--\n\n" + "Move this cursor to the first child of its current node that extends beyond the " + "given row/column point.\n\n" + ".. versionchanged:: 0.22.0\n Use ``goto_first_child_for_point(point)`` " + "instead of ``goto_first_child_for_point(row, column)``" DOC_RETURNS + "``True`` if the child node was found, ``False`` otherwise."); +PyDoc_STRVAR(tree_cursor_reset_doc, "reset(self, node, /)\n--\n\n" + "Re-initialize the cursor to start at the original node " + "that it was constructed with."); +PyDoc_STRVAR(tree_cursor_reset_to_doc, + "reset_to(self, cursor, /)\n--\n\n" + "Re-initialize the cursor to the same position as another cursor.\n\n" + "Unlike :meth:`reset`, this will not lose parent information and allows reusing " + "already created cursors."); +PyDoc_STRVAR(tree_cursor_copy_doc, "copy(self, /)\n--\n\n" + "Create an independent copy of the cursor."); +PyDoc_STRVAR(tree_cursor_copy2_doc, "__copy__(self, /)\n--\n\n" + "Use :func:`copy.copy` to create a copy of the cursor."); + static PyMethodDef tree_cursor_methods[] = { { .ml_name = "goto_first_child", .ml_meth = (PyCFunction)tree_cursor_goto_first_child, .ml_flags = METH_NOARGS, - .ml_doc = "goto_first_child()\n--\n\n\ - Go to the first child.\n\n\ - If the current node has children, move to the first child and\n\ - return True. Otherwise, return False.", + .ml_doc = tree_cursor_goto_first_child_doc, }, { .ml_name = "goto_last_child", .ml_meth = (PyCFunction)tree_cursor_goto_last_child, .ml_flags = METH_NOARGS, - .ml_doc = "goto_last_child()\n--\n\n\ - Go to the last child.\n\n\ - If the current node has children, move to the last child and\n\ - return True. Otherwise, return False.", + .ml_doc = tree_cursor_goto_last_child_doc, }, { .ml_name = "goto_parent", .ml_meth = (PyCFunction)tree_cursor_goto_parent, .ml_flags = METH_NOARGS, - .ml_doc = "goto_parent()\n--\n\n\ - Go to the parent.\n\n\ - If the current node is not the root, move to its parent and\n\ - return True. Otherwise, return False.", + .ml_doc = tree_cursor_goto_parent_doc, }, { .ml_name = "goto_next_sibling", .ml_meth = (PyCFunction)tree_cursor_goto_next_sibling, .ml_flags = METH_NOARGS, - .ml_doc = "goto_next_sibling()\n--\n\n\ - Go to the next sibling.\n\n\ - If the current node has a next sibling, move to the next sibling\n\ - and return True. Otherwise, return False.", + .ml_doc = tree_cursor_goto_next_sibling_doc, }, { .ml_name = "goto_previous_sibling", .ml_meth = (PyCFunction)tree_cursor_goto_previous_sibling, .ml_flags = METH_NOARGS, - .ml_doc = "goto_previous_sibling()\n--\n\n\ - Go to the previous sibling.\n\n\ - If the current node has a previous sibling, move to the previous sibling\n\ - and return True. Otherwise, return False.", + .ml_doc = tree_cursor_goto_previous_sibling_doc, }, { .ml_name = "goto_descendant", .ml_meth = (PyCFunction)tree_cursor_goto_descendant, .ml_flags = METH_VARARGS, - .ml_doc = "goto_descendant(index)\n--\n\n\ - Go to the descendant at the given index.\n\n\ - If the current node has a descendant at the given index, move to the\n\ - descendant and return True. Otherwise, return False.", + .ml_doc = tree_cursor_goto_descendant_doc, }, { .ml_name = "goto_first_child_for_byte", .ml_meth = (PyCFunction)tree_cursor_goto_first_child_for_byte, .ml_flags = METH_VARARGS, - .ml_doc = "goto_first_child_for_byte(byte)\n--\n\n\ - Go to the first child that extends beyond the given byte.\n\n\ - If the current node has a child that includes the given byte, move to the\n\ - child and return True. Otherwise, return False.", + .ml_doc = tree_cursor_goto_first_child_for_byte_doc, }, { .ml_name = "goto_first_child_for_point", .ml_meth = (PyCFunction)tree_cursor_goto_first_child_for_point, .ml_flags = METH_VARARGS, - .ml_doc = "goto_first_child_for_point(row, column)\n--\n\n\ - Go to the first child that extends beyond the given point.\n\n\ - If the current node has a child that includes the given point, move to the\n\ - child and return True. Otherwise, return False.", + .ml_doc = tree_cursor_goto_first_child_for_point_doc, }, { .ml_name = "reset", .ml_meth = (PyCFunction)tree_cursor_reset, .ml_flags = METH_VARARGS, - .ml_doc = "reset(node)\n--\n\n\ - Re-initialize a tree cursor to start at a different node.", + .ml_doc = tree_cursor_reset_doc, }, { .ml_name = "reset_to", .ml_meth = (PyCFunction)tree_cursor_reset_to, .ml_flags = METH_VARARGS, - .ml_doc = "reset_to(cursor)\n--\n\n\ - Re-initialize the cursor to the same position as the given cursor.\n\n\ - Unlike `reset`, this will not lose parent information and allows reusing already created cursors\n`", + .ml_doc = tree_cursor_reset_to_doc, }, { .ml_name = "copy", .ml_meth = (PyCFunction)tree_cursor_copy, .ml_flags = METH_NOARGS, - .ml_doc = "copy()\n--\n\n\ - Create an independent copy of the cursor.\n", + .ml_doc = tree_cursor_copy_doc, }, {.ml_name = "__copy__", .ml_meth = (PyCFunction)tree_cursor_copy, .ml_flags = METH_NOARGS, - .ml_doc = NULL}, + .ml_doc = tree_cursor_copy2_doc}, {NULL}, }; static PyGetSetDef tree_cursor_accessors[] = { {"node", (getter)tree_cursor_get_node, NULL, "The current node.", NULL}, - { - "descendant_index", - (getter)tree_cursor_get_current_descendant_index, - NULL, - "current_descendant_index()\n--\n\n\ - Get the index of the cursor's current node out of all of the descendants of the original node.", - NULL, - }, - { - "field_id", - (getter)tree_cursor_get_current_field_id, - NULL, - "current_field_id()\n--\n\n\ - Get the field id of the tree cursor's current node.\n\n\ - If the current node has the field id, return int. Otherwise, return None.", - NULL, - }, - { - "field_name", - (getter)tree_cursor_get_current_field_name, - NULL, - "current_field_name()\n--\n\n\ - Get the field name of the tree cursor's current node.\n\n\ - If the current node has the field name, return str. Otherwise, return None.", - NULL, - }, - { - "depth", - (getter)tree_cursor_get_current_depth, - NULL, - "current_depth()\n--\n\n\ - Get the depth of the cursor's current node relative to the original node.", - NULL, - }, + {"descendant_index", (getter)tree_cursor_get_descendant_index, NULL, + PyDoc_STR("The index of the cursor's current node out of all of the descendants of the " + "original node that the cursor was constructed with.\n\n"), + NULL}, + {"field_id", (getter)tree_cursor_get_field_id, NULL, + PyDoc_STR("The numerical field id of this tree cursor's current node, if available."), NULL}, + {"field_name", (getter)tree_cursor_get_field_name, NULL, + PyDoc_STR("The field name of this tree cursor's current node, if available."), NULL}, + {"depth", (getter)tree_cursor_get_depth, NULL, + PyDoc_STR("The depth of the cursor's current node relative to the original node that it was " + "constructed with."), + NULL}, {NULL}, }; static PyType_Slot tree_cursor_type_slots[] = { - {Py_tp_doc, "A syntax tree cursor"}, {Py_tp_new, NULL}, - {Py_tp_dealloc, tree_cursor_dealloc}, {Py_tp_methods, tree_cursor_methods}, - {Py_tp_getset, tree_cursor_accessors}, {0, NULL}, + {Py_tp_doc, + PyDoc_STR("A class for walking a syntax :class:`Tree` efficiently." DOC_IMPORTANT + "The cursor can only walk into children of the node that it started from.")}, + {Py_tp_new, NULL}, + {Py_tp_dealloc, tree_cursor_dealloc}, + {Py_tp_methods, tree_cursor_methods}, + {Py_tp_getset, tree_cursor_accessors}, + {0, NULL}, }; PyType_Spec tree_cursor_type_spec = { diff --git a/tree_sitter/binding/tree_cursor.h b/tree_sitter/binding/tree_cursor.h index 0e4bdac2..a3696a46 100644 --- a/tree_sitter/binding/tree_cursor.h +++ b/tree_sitter/binding/tree_cursor.h @@ -6,13 +6,13 @@ void tree_cursor_dealloc(TreeCursor *self); PyObject *tree_cursor_get_node(TreeCursor *self, void *payload); -PyObject *tree_cursor_get_current_field_id(TreeCursor *self, void *payload); +PyObject *tree_cursor_get_field_id(TreeCursor *self, void *payload); -PyObject *tree_cursor_get_current_field_name(TreeCursor *self, void *payload); +PyObject *tree_cursor_get_field_name(TreeCursor *self, void *payload); -PyObject *tree_cursor_get_current_depth(TreeCursor *self, void *payload); +PyObject *tree_cursor_get_depth(TreeCursor *self, void *payload); -PyObject *tree_cursor_get_current_descendant_index(TreeCursor *self, void *payload); +PyObject *tree_cursor_get_descendant_index(TreeCursor *self, void *payload); PyObject *tree_cursor_goto_first_child(TreeCursor *self, PyObject *args); diff --git a/tree_sitter/binding/types.h b/tree_sitter/binding/types.h index 0dbcc67f..9c0f15ce 100644 --- a/tree_sitter/binding/types.h +++ b/tree_sitter/binding/types.h @@ -1,5 +1,6 @@ #pragma once +#include "docs.h" #include "tree_sitter/api.h" #include