From 0105fe4dad2c6048af4c9c2f2b178c31b29fa2f9 Mon Sep 17 00:00:00 2001 From: Alejandro Giacometti Date: Wed, 8 Jul 2026 23:51:10 +0100 Subject: [PATCH] Move each language plugin into its own package with .scm queries Each plugin now lives in languages// (plugin.py plus its .scm file(s)), loaded at import via a small load_query helper instead of inline Python string literals. SQL's DDL becomes a static sql.scm, js/ts compose shared .scm fragments, and html's semantic-tag query resolves to a static file. Extraction output is unchanged: no snapshot diff, no language_plugin_version bumps. Docs (rbtr-languages skill, README, ARCHITECTURE) gain a "Where queries live" note. --- .agents/skills/rbtr-languages/SKILL.md | 24 ++- packages/rbtr/ARCHITECTURE.md | 10 +- packages/rbtr/README.md | 35 +++-- packages/rbtr/src/rbtr/languages/__init__.py | 42 +++--- packages/rbtr/src/rbtr/languages/_queries.py | 25 ++++ .../rbtr/src/rbtr/languages/bash/__init__.py | 1 + .../rbtr/src/rbtr/languages/bash/bash.scm | 31 ++++ .../languages/{bash.py => bash/plugin.py} | 35 +---- .../rbtr/src/rbtr/languages/c/__init__.py | 1 + packages/rbtr/src/rbtr/languages/c/c.scm | 61 ++++++++ .../src/rbtr/languages/{c.py => c/plugin.py} | 64 +------- .../rbtr/src/rbtr/languages/cpp/__init__.py | 1 + .../rbtr/languages/{cpp.py => cpp/cpp.scm} | 54 ------- .../rbtr/src/rbtr/languages/cpp/plugin.py | 55 +++++++ .../rbtr/src/rbtr/languages/css/__init__.py | 1 + packages/rbtr/src/rbtr/languages/css/css.scm | 21 +++ .../rbtr/languages/{css.py => css/plugin.py} | 25 +--- .../rbtr/src/rbtr/languages/go/__init__.py | 1 + packages/rbtr/src/rbtr/languages/go/go.scm | 49 ++++++ .../rbtr/languages/{go.py => go/plugin.py} | 53 +------ .../rbtr/src/rbtr/languages/hcl/__init__.py | 1 + packages/rbtr/src/rbtr/languages/hcl/hcl.scm | 3 + .../rbtr/languages/{hcl.py => hcl/plugin.py} | 7 +- .../rbtr/src/rbtr/languages/html/__init__.py | 1 + .../rbtr/src/rbtr/languages/html/html.scm | 18 +++ .../src/rbtr/languages/html/injections.scm | 8 + .../languages/{html.py => html/plugin.py} | 33 +--- .../rbtr/src/rbtr/languages/java/__init__.py | 1 + .../rbtr/src/rbtr/languages/java/java.scm | 42 ++++++ .../languages/{java.py => java/plugin.py} | 46 +----- .../src/rbtr/languages/javascript/__init__.py | 1 + .../rbtr/languages/javascript/javascript.scm | 4 + .../{javascript.py => javascript/plugin.py} | 135 +---------------- .../src/rbtr/languages/javascript/shared.scm | 20 +++ .../rbtr/languages/javascript/typescript.scm | 36 +++++ .../rbtr/languages/javascript/variables.scm | 54 +++++++ .../rbtr/src/rbtr/languages/json/__init__.py | 1 + .../rbtr/src/rbtr/languages/json/json.scm | 2 + .../languages/{json.py => json/plugin.py} | 6 +- .../rbtr/src/rbtr/languages/less/__init__.py | 1 + .../rbtr/src/rbtr/languages/less/less.scm | 20 +++ .../languages/{less.py => less/plugin.py} | 25 +--- .../src/rbtr/languages/markdown/__init__.py | 1 + .../rbtr/languages/markdown/injections.scm | 4 + .../src/rbtr/languages/markdown/links.scm | 1 + .../{markdown.py => markdown/plugin.py} | 15 +- .../src/rbtr/languages/markdown/sections.scm | 3 + .../src/rbtr/languages/python/__init__.py | 1 + .../languages/{python.py => python/plugin.py} | 56 +------ .../rbtr/src/rbtr/languages/python/python.scm | 52 +++++++ .../rbtr/src/rbtr/languages/rst/__init__.py | 1 + .../rbtr/languages/{rst.py => rst/plugin.py} | 9 +- .../src/rbtr/languages/rst/references.scm | 5 + .../rbtr/src/rbtr/languages/ruby/__init__.py | 1 + .../languages/{ruby.py => ruby/plugin.py} | 51 +------ .../rbtr/src/rbtr/languages/ruby/ruby.scm | 48 ++++++ .../rbtr/src/rbtr/languages/rust/__init__.py | 1 + .../languages/{rust.py => rust/plugin.py} | 48 +----- .../rbtr/src/rbtr/languages/rust/rust.scm | 44 ++++++ .../rbtr/src/rbtr/languages/scss/__init__.py | 1 + .../languages/{scss.py => scss/plugin.py} | 34 +---- .../rbtr/src/rbtr/languages/scss/scss.scm | 29 ++++ .../rbtr/src/rbtr/languages/sfc/__init__.py | 1 + .../src/rbtr/languages/sfc/injections.scm | 41 +++++ .../rbtr/languages/{sfc.py => sfc/plugin.py} | 23 +-- packages/rbtr/src/rbtr/languages/sql.py | 141 ------------------ .../rbtr/src/rbtr/languages/sql/__init__.py | 1 + .../rbtr/src/rbtr/languages/sql/plugin.py | 65 ++++++++ packages/rbtr/src/rbtr/languages/sql/sql.scm | 67 +++++++++ .../rbtr/src/rbtr/languages/toml/__init__.py | 1 + .../languages/{toml.py => toml/plugin.py} | 21 +-- .../rbtr/src/rbtr/languages/toml/toml.scm | 17 +++ .../rbtr/src/rbtr/languages/yaml/__init__.py | 1 + .../languages/{yaml.py => yaml/plugin.py} | 9 +- .../rbtr/src/rbtr/languages/yaml/yaml.scm | 5 + 75 files changed, 966 insertions(+), 886 deletions(-) create mode 100644 packages/rbtr/src/rbtr/languages/_queries.py create mode 100644 packages/rbtr/src/rbtr/languages/bash/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/bash/bash.scm rename packages/rbtr/src/rbtr/languages/{bash.py => bash/plugin.py} (79%) create mode 100644 packages/rbtr/src/rbtr/languages/c/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/c/c.scm rename packages/rbtr/src/rbtr/languages/{c.py => c/plugin.py} (56%) create mode 100644 packages/rbtr/src/rbtr/languages/cpp/__init__.py rename packages/rbtr/src/rbtr/languages/{cpp.py => cpp/cpp.scm} (55%) create mode 100644 packages/rbtr/src/rbtr/languages/cpp/plugin.py create mode 100644 packages/rbtr/src/rbtr/languages/css/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/css/css.scm rename packages/rbtr/src/rbtr/languages/{css.py => css/plugin.py} (81%) create mode 100644 packages/rbtr/src/rbtr/languages/go/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/go/go.scm rename packages/rbtr/src/rbtr/languages/{go.py => go/plugin.py} (64%) create mode 100644 packages/rbtr/src/rbtr/languages/hcl/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/hcl/hcl.scm rename packages/rbtr/src/rbtr/languages/{hcl.py => hcl/plugin.py} (95%) create mode 100644 packages/rbtr/src/rbtr/languages/html/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/html/html.scm create mode 100644 packages/rbtr/src/rbtr/languages/html/injections.scm rename packages/rbtr/src/rbtr/languages/{html.py => html/plugin.py} (81%) create mode 100644 packages/rbtr/src/rbtr/languages/java/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/java/java.scm rename packages/rbtr/src/rbtr/languages/{java.py => java/plugin.py} (70%) create mode 100644 packages/rbtr/src/rbtr/languages/javascript/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/javascript/javascript.scm rename packages/rbtr/src/rbtr/languages/{javascript.py => javascript/plugin.py} (67%) create mode 100644 packages/rbtr/src/rbtr/languages/javascript/shared.scm create mode 100644 packages/rbtr/src/rbtr/languages/javascript/typescript.scm create mode 100644 packages/rbtr/src/rbtr/languages/javascript/variables.scm create mode 100644 packages/rbtr/src/rbtr/languages/json/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/json/json.scm rename packages/rbtr/src/rbtr/languages/{json.py => json/plugin.py} (91%) create mode 100644 packages/rbtr/src/rbtr/languages/less/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/less/less.scm rename packages/rbtr/src/rbtr/languages/{less.py => less/plugin.py} (76%) create mode 100644 packages/rbtr/src/rbtr/languages/markdown/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/markdown/injections.scm create mode 100644 packages/rbtr/src/rbtr/languages/markdown/links.scm rename packages/rbtr/src/rbtr/languages/{markdown.py => markdown/plugin.py} (97%) create mode 100644 packages/rbtr/src/rbtr/languages/markdown/sections.scm create mode 100644 packages/rbtr/src/rbtr/languages/python/__init__.py rename packages/rbtr/src/rbtr/languages/{python.py => python/plugin.py} (77%) create mode 100644 packages/rbtr/src/rbtr/languages/python/python.scm create mode 100644 packages/rbtr/src/rbtr/languages/rst/__init__.py rename packages/rbtr/src/rbtr/languages/{rst.py => rst/plugin.py} (98%) create mode 100644 packages/rbtr/src/rbtr/languages/rst/references.scm create mode 100644 packages/rbtr/src/rbtr/languages/ruby/__init__.py rename packages/rbtr/src/rbtr/languages/{ruby.py => ruby/plugin.py} (74%) create mode 100644 packages/rbtr/src/rbtr/languages/ruby/ruby.scm create mode 100644 packages/rbtr/src/rbtr/languages/rust/__init__.py rename packages/rbtr/src/rbtr/languages/{rust.py => rust/plugin.py} (86%) create mode 100644 packages/rbtr/src/rbtr/languages/rust/rust.scm create mode 100644 packages/rbtr/src/rbtr/languages/scss/__init__.py rename packages/rbtr/src/rbtr/languages/{scss.py => scss/plugin.py} (71%) create mode 100644 packages/rbtr/src/rbtr/languages/scss/scss.scm create mode 100644 packages/rbtr/src/rbtr/languages/sfc/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/sfc/injections.scm rename packages/rbtr/src/rbtr/languages/{sfc.py => sfc/plugin.py} (82%) delete mode 100644 packages/rbtr/src/rbtr/languages/sql.py create mode 100644 packages/rbtr/src/rbtr/languages/sql/__init__.py create mode 100644 packages/rbtr/src/rbtr/languages/sql/plugin.py create mode 100644 packages/rbtr/src/rbtr/languages/sql/sql.scm create mode 100644 packages/rbtr/src/rbtr/languages/toml/__init__.py rename packages/rbtr/src/rbtr/languages/{toml.py => toml/plugin.py} (89%) create mode 100644 packages/rbtr/src/rbtr/languages/toml/toml.scm create mode 100644 packages/rbtr/src/rbtr/languages/yaml/__init__.py rename packages/rbtr/src/rbtr/languages/{yaml.py => yaml/plugin.py} (89%) create mode 100644 packages/rbtr/src/rbtr/languages/yaml/yaml.scm diff --git a/.agents/skills/rbtr-languages/SKILL.md b/.agents/skills/rbtr-languages/SKILL.md index 0cba42ac..04324ed4 100644 --- a/.agents/skills/rbtr-languages/SKILL.md +++ b/.agents/skills/rbtr-languages/SKILL.md @@ -115,6 +115,22 @@ at absolute line numbers. Every file also gets a host-language chunk (a content-less presence chunk if it would produce none), so dedup works. See ARCHITECTURE “Dispatch chain” for the mechanism and rationale. +### Where queries live + +Every query — `reg.query`, `reg.injection_query`, and any query a chunker +compiles — is a `.scm` file in the plugin's own package +(`languages//.scm`), loaded at import via +`load_query(__package__, "")`. Never inline a query as a Python string +literal (the house rule against embedding a foreign language). The `uv` +build backend ships `.scm` as package data with no extra config. + +Compose in Python when a query is built from parts — the query language has +no `#include`: js/ts concatenate shared fragment files with `+` +(`load_query(pkg, "javascript") + load_query(pkg, "shared") + …`); SQL groups +its DDL verbs into `[...]` alternations within one `sql.scm`. Prefer these to +generating query text from Python data. Editing a `.scm` is an extraction +change — the `language_plugin_version` bump rule (below) applies. + ## Capture conventions The query's capture names drive the chunk kind (see `_CAPTURE_KIND` in @@ -188,7 +204,9 @@ captured node, so they work for any language: 1. Read the grammar: its `queries/tags.scm` (the authors' definition list — see the tags reference) **and** the real node structure (parse a snippet, print the tree). Never guess node types. -2. Extend the `_QUERY` (or chunker). Verify against a parsed snippet. +2. Edit the language's `.scm` query file (or chunker) — queries live in + `languages//*.scm`, loaded via `load_query`, never inline (see + *Where queries live*). Verify against a parsed snippet. 3. Add the construct to that language's sample in `tests/languages/samples/` and regenerate the snapshot with `just snapshots`; review the diff. 4. Bump `language_plugin_version` — any extraction change triggers @@ -232,6 +250,10 @@ itself a tree-sitter query, so it is **inspiration for ours, not a drop-in**: (ts ← js), and only the 9 code grammars ship one. - Running it live would couple extraction to upstream drift. We don't. +Distinct from **rbtr's own** `.scm` files (see *Where queries live*): we load +those at runtime (`reg.query` / `injection_query`) as the source of truth, +whereas `tags.scm` we only mine for ideas. + Curated per-language verdicts (take / modify / ignore) and the `@definition.* → ChunkKind` mapping live in `references/tags-scm-reference.md`. diff --git a/packages/rbtr/ARCHITECTURE.md b/packages/rbtr/ARCHITECTURE.md index cefb6c8e..55a2fe4d 100644 --- a/packages/rbtr/ARCHITECTURE.md +++ b/packages/rbtr/ARCHITECTURE.md @@ -1070,10 +1070,12 @@ chunks. ## Language plugins -[pluggy]-based. Each plugin is a Python file under -`rbtr/languages/` that returns `LanguageRegistration` -instances. A plugin provides whatever combination of fields -its language needs - there are no tiers or categories. +[pluggy]-based. Each plugin is a package under +`rbtr/languages//` (a `plugin.py` plus its tree-sitter +queries as sibling `.scm` files, loaded via `load_query`) +that returns `LanguageRegistration` instances. A plugin +provides whatever combination of fields its language needs - +there are no tiers or categories. [pluggy]: https://pluggy.readthedocs.io/ diff --git a/packages/rbtr/README.md b/packages/rbtr/README.md index 70b982b1..91c6760a 100644 --- a/packages/rbtr/README.md +++ b/packages/rbtr/README.md @@ -375,30 +375,34 @@ for how the plugin system works. ## Writing a language plugin -Every plugin is a Python file under `rbtr/languages/` -with a pluggy hook that returns `LanguageRegistration` -instances. A plugin provides whatever fields its language -needs. +Every plugin is a package under `rbtr/languages//` — a +`plugin.py` with a pluggy hook that returns +`LanguageRegistration` instances, plus its tree-sitter query +in a sibling `.scm` file. A plugin provides whatever fields +its language needs. ### Query-based plugin (preferred) Most languages need only a tree-sitter query. The generic `extract_symbols` pipeline handles parsing, capture -matching, scope detection, and chunk construction. +matching, scope detection, and chunk construction. The query +lives in its own `.scm` file, loaded with `load_query`: -```python -# rbtr/languages/swift.py -from __future__ import annotations -from rbtr.languages.hookspec import LanguageRegistration, hookimpl - -_QUERY = """\ +```scm +; rbtr/languages/swift/swift.scm (function_declaration name: (identifier) @_fn_name) @function (class_declaration name: (type_identifier) @_cls_name) @class (import_declaration (identifier) @_import_module) @import -""" +``` + +```python +# rbtr/languages/swift/plugin.py +from __future__ import annotations +from rbtr.languages._queries import load_query +from rbtr.languages.hookspec import LanguageRegistration, hookimpl class SwiftPlugin: @hookimpl @@ -408,7 +412,7 @@ class SwiftPlugin: id="swift", extensions=frozenset({".swift"}), grammar_module="tree_sitter_swift", - query=_QUERY, + query=load_query(__package__, "swift"), scope_types=frozenset({"class_declaration"}), doc_comment_node_types=frozenset({"comment"}), ), @@ -456,7 +460,7 @@ content-minus-children), write a custom chunker. The chunker receives the grammar from the manager: ```python -# rbtr/languages/example.py +# rbtr/languages/example/plugin.py from __future__ import annotations from collections.abc import Iterator from typing import TYPE_CHECKING @@ -496,7 +500,8 @@ class ExamplePlugin: ### Registration -Built-in plugins: import the class at the top of +Built-in plugins: add the `/` package (a `plugin.py` +and any `.scm` files), then import the class at the top of `rbtr/languages/__init__.py` and list it in `_register_builtins`. External plugins: register via setuptools entry points: diff --git a/packages/rbtr/src/rbtr/languages/__init__.py b/packages/rbtr/src/rbtr/languages/__init__.py index b9d17f14..617f287c 100644 --- a/packages/rbtr/src/rbtr/languages/__init__.py +++ b/packages/rbtr/src/rbtr/languages/__init__.py @@ -41,28 +41,28 @@ import pluggy from tree_sitter import Language -from rbtr.languages.bash import BashPlugin -from rbtr.languages.c import CPlugin -from rbtr.languages.cpp import CppPlugin -from rbtr.languages.css import CssPlugin -from rbtr.languages.go import GoPlugin -from rbtr.languages.hcl import HclPlugin +from rbtr.languages.bash.plugin import BashPlugin +from rbtr.languages.c.plugin import CPlugin +from rbtr.languages.cpp.plugin import CppPlugin +from rbtr.languages.css.plugin import CssPlugin +from rbtr.languages.go.plugin import GoPlugin +from rbtr.languages.hcl.plugin import HclPlugin from rbtr.languages.hookspec import PROJECT_NAME, LanguageHookspec, LanguageRegistration -from rbtr.languages.html import HtmlPlugin -from rbtr.languages.java import JavaPlugin -from rbtr.languages.javascript import JavaScriptPlugin -from rbtr.languages.json import JsonPlugin -from rbtr.languages.less import LessPlugin -from rbtr.languages.markdown import MarkdownPlugin -from rbtr.languages.python import PythonPlugin -from rbtr.languages.rst import RstPlugin -from rbtr.languages.ruby import RubyPlugin -from rbtr.languages.rust import RustPlugin -from rbtr.languages.scss import ScssPlugin -from rbtr.languages.sfc import SveltePlugin, VuePlugin -from rbtr.languages.sql import SqlPlugin -from rbtr.languages.toml import TomlPlugin -from rbtr.languages.yaml import YamlPlugin +from rbtr.languages.html.plugin import HtmlPlugin +from rbtr.languages.java.plugin import JavaPlugin +from rbtr.languages.javascript.plugin import JavaScriptPlugin +from rbtr.languages.json.plugin import JsonPlugin +from rbtr.languages.less.plugin import LessPlugin +from rbtr.languages.markdown.plugin import MarkdownPlugin +from rbtr.languages.python.plugin import PythonPlugin +from rbtr.languages.rst.plugin import RstPlugin +from rbtr.languages.ruby.plugin import RubyPlugin +from rbtr.languages.rust.plugin import RustPlugin +from rbtr.languages.scss.plugin import ScssPlugin +from rbtr.languages.sfc.plugin import SveltePlugin, VuePlugin +from rbtr.languages.sql.plugin import SqlPlugin +from rbtr.languages.toml.plugin import TomlPlugin +from rbtr.languages.yaml.plugin import YamlPlugin class LanguageManager: diff --git a/packages/rbtr/src/rbtr/languages/_queries.py b/packages/rbtr/src/rbtr/languages/_queries.py new file mode 100644 index 00000000..a25f14f8 --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/_queries.py @@ -0,0 +1,25 @@ +"""Load tree-sitter queries from `.scm` files beside each plugin. + +Query text lives in `.scm` inside the plugin's own package, +loaded at import time via `load_query` — not embedded inline in Python. +See ARCHITECTURE "Where queries live" for the rationale. +""" + +from __future__ import annotations + +from importlib.resources import files + + +def load_query(package: str, name: str) -> str: + """Return the text of a `.scm` query file in *package*. + + Args: + package: The plugin package to resolve against, normally the + caller's own `__package__` (e.g. `"rbtr.languages.python"`). + name: Query filename without the `.scm` extension (e.g. + `"python"`, `"injections"`). + + Returns: + The file's contents verbatim. + """ + return (files(package) / f"{name}.scm").read_text(encoding="utf-8") diff --git a/packages/rbtr/src/rbtr/languages/bash/__init__.py b/packages/rbtr/src/rbtr/languages/bash/__init__.py new file mode 100644 index 00000000..db66ecff --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/bash/__init__.py @@ -0,0 +1 @@ +"""Bash language plugin package.""" diff --git a/packages/rbtr/src/rbtr/languages/bash/bash.scm b/packages/rbtr/src/rbtr/languages/bash/bash.scm new file mode 100644 index 00000000..037ec36b --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/bash/bash.scm @@ -0,0 +1,31 @@ +(function_definition + name: (word) @_fn_name) @function + +(command + name: (command_name + (word) @_cmd) + . + (word) @_import_module + (#eq? @_cmd "source")) @import + +(command + name: (command_name + (word) @_cmd) + . + (word) @_import_module + (#eq? @_cmd ".")) @import + +(program + (variable_assignment + name: (variable_name) @_var_name) @variable) + +(program + (declaration_command + (variable_assignment + name: (variable_name) @_var_name)) @variable) + +(command + name: (command_name (word) @_cmd) + argument: (concatenation (word) @_var_name) + (#eq? @_cmd "alias") + (#match? @_var_name "=")) @variable diff --git a/packages/rbtr/src/rbtr/languages/bash.py b/packages/rbtr/src/rbtr/languages/bash/plugin.py similarity index 79% rename from packages/rbtr/src/rbtr/languages/bash.py rename to packages/rbtr/src/rbtr/languages/bash/plugin.py index 186318f0..562652a7 100644 --- a/packages/rbtr/src/rbtr/languages/bash.py +++ b/packages/rbtr/src/rbtr/languages/bash/plugin.py @@ -20,6 +20,7 @@ class system, or module structure. from typing import TYPE_CHECKING +from rbtr.languages._queries import load_query from rbtr.languages.hookspec import LanguageRegistration, hookimpl, resolve_name if TYPE_CHECKING: @@ -33,39 +34,7 @@ def _strip_alias_eq(capture_name: str, node: Node, captures: dict[str, list[Node # ── Query ──────────────────────────────────────────────────────────── -_QUERY = """\ -(function_definition - name: (word) @_fn_name) @function - -(command - name: (command_name - (word) @_cmd) - . - (word) @_import_module - (#eq? @_cmd "source")) @import - -(command - name: (command_name - (word) @_cmd) - . - (word) @_import_module - (#eq? @_cmd ".")) @import - -(program - (variable_assignment - name: (variable_name) @_var_name) @variable) - -(program - (declaration_command - (variable_assignment - name: (variable_name) @_var_name)) @variable) - -(command - name: (command_name (word) @_cmd) - argument: (concatenation (word) @_var_name) - (#eq? @_cmd "alias") - (#match? @_var_name "=")) @variable -""" +_QUERY = load_query(__package__, "bash") # ── Plugin ─────────────────────────────────────────────────────────── diff --git a/packages/rbtr/src/rbtr/languages/c/__init__.py b/packages/rbtr/src/rbtr/languages/c/__init__.py new file mode 100644 index 00000000..e7a6a312 --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/c/__init__.py @@ -0,0 +1 @@ +"""C language plugin package.""" diff --git a/packages/rbtr/src/rbtr/languages/c/c.scm b/packages/rbtr/src/rbtr/languages/c/c.scm new file mode 100644 index 00000000..918c4adc --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/c/c.scm @@ -0,0 +1,61 @@ + +(function_definition + declarator: (function_declarator + declarator: (identifier) @_fn_name)) @function + +(preproc_include + path: (system_lib_string) @_import_module) @import + +(preproc_include + path: (string_literal) @_import_module) @import + +(struct_specifier + name: (type_identifier) @_cls_name + body: (field_declaration_list)) @class + +(union_specifier + name: (type_identifier) @_cls_name + body: (field_declaration_list)) @class + +(enum_specifier + name: (type_identifier) @_cls_name + body: (enumerator_list)) @class + +(enumerator + name: (identifier) @_var_name) @variable + +(type_definition + declarator: (type_identifier) @_cls_name) @class + +(type_definition + declarator: (function_declarator + declarator: (parenthesized_declarator + (pointer_declarator + declarator: (type_identifier) @_cls_name)))) @class + +(preproc_function_def + name: (identifier) @_fn_name) @function + +(preproc_def + name: (identifier) @_var_name) @variable + +(translation_unit + (declaration + declarator: (function_declarator + declarator: (identifier) @_fn_name)) @function) + +(translation_unit + (declaration + declarator: (init_declarator + declarator: (identifier) @_var_name)) @variable) + +(translation_unit + (declaration + declarator: (pointer_declarator + declarator: (identifier) @_var_name)) @variable) + +(translation_unit + (declaration + declarator: (init_declarator + declarator: (pointer_declarator + declarator: (identifier) @_var_name))) @variable) diff --git a/packages/rbtr/src/rbtr/languages/c.py b/packages/rbtr/src/rbtr/languages/c/plugin.py similarity index 56% rename from packages/rbtr/src/rbtr/languages/c.py rename to packages/rbtr/src/rbtr/languages/c/plugin.py index 69d6c41f..37bbcb35 100644 --- a/packages/rbtr/src/rbtr/languages/c.py +++ b/packages/rbtr/src/rbtr/languages/c/plugin.py @@ -21,72 +21,12 @@ from __future__ import annotations +from rbtr.languages._queries import load_query from rbtr.languages.hookspec import LanguageRegistration, hookimpl # ── Query ──────────────────────────────────────────────────────────── -_QUERY = """ -(function_definition - declarator: (function_declarator - declarator: (identifier) @_fn_name)) @function - -(preproc_include - path: (system_lib_string) @_import_module) @import - -(preproc_include - path: (string_literal) @_import_module) @import - -(struct_specifier - name: (type_identifier) @_cls_name - body: (field_declaration_list)) @class - -(union_specifier - name: (type_identifier) @_cls_name - body: (field_declaration_list)) @class - -(enum_specifier - name: (type_identifier) @_cls_name - body: (enumerator_list)) @class - -(enumerator - name: (identifier) @_var_name) @variable - -(type_definition - declarator: (type_identifier) @_cls_name) @class - -(type_definition - declarator: (function_declarator - declarator: (parenthesized_declarator - (pointer_declarator - declarator: (type_identifier) @_cls_name)))) @class - -(preproc_function_def - name: (identifier) @_fn_name) @function - -(preproc_def - name: (identifier) @_var_name) @variable - -(translation_unit - (declaration - declarator: (function_declarator - declarator: (identifier) @_fn_name)) @function) - -(translation_unit - (declaration - declarator: (init_declarator - declarator: (identifier) @_var_name)) @variable) - -(translation_unit - (declaration - declarator: (pointer_declarator - declarator: (identifier) @_var_name)) @variable) - -(translation_unit - (declaration - declarator: (init_declarator - declarator: (pointer_declarator - declarator: (identifier) @_var_name))) @variable) -""" +_QUERY = load_query(__package__, "c") # ── Plugin ─────────────────────────────────────────────────────────── diff --git a/packages/rbtr/src/rbtr/languages/cpp/__init__.py b/packages/rbtr/src/rbtr/languages/cpp/__init__.py new file mode 100644 index 00000000..609d7979 --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/cpp/__init__.py @@ -0,0 +1 @@ +"""C++ language plugin package.""" diff --git a/packages/rbtr/src/rbtr/languages/cpp.py b/packages/rbtr/src/rbtr/languages/cpp/cpp.scm similarity index 55% rename from packages/rbtr/src/rbtr/languages/cpp.py rename to packages/rbtr/src/rbtr/languages/cpp/cpp.scm index 3598aab4..7a89a1ad 100644 --- a/packages/rbtr/src/rbtr/languages/cpp.py +++ b/packages/rbtr/src/rbtr/languages/cpp/cpp.scm @@ -1,31 +1,4 @@ -"""C++ language plugin. -Provides symbol extraction (functions, prototypes, classes, structs, -unions, enums, type aliases, namespaces, methods including operator -overloads, namespace/global variables, and function/object-like -macros) and include directive capture. Namespaces are both a symbol -(class) and a naming scope. - -Extracted chunks:: - - void greet() {} → function "greet", scope "" - class Shape {}; → class "Shape", scope "" - struct Point { ... }; → class "Point", scope "" - class Foo { - void bar() {} → method "bar", scope "Foo" - }; - - #include - → import, metadata {module: "iostream"} -""" - -from __future__ import annotations - -from rbtr.languages.hookspec import LanguageRegistration, hookimpl - -# ── Query ──────────────────────────────────────────────────────────── - -_QUERY = """ (function_definition declarator: (function_declarator declarator: (identifier) @_fn_name)) @function @@ -129,30 +102,3 @@ class Foo { declarator: (init_declarator declarator: (pointer_declarator declarator: (identifier) @_var_name))) @variable)) -""" - -# ── Plugin ─────────────────────────────────────────────────────────── - - -class CppPlugin: - """C++ language support — functions, classes, methods, includes.""" - - @hookimpl - def rbtr_register_languages(self) -> list[LanguageRegistration]: - return [ - LanguageRegistration( - id="cpp", - extensions=frozenset({".cpp", ".cc", ".cxx", ".hpp", ".hxx"}), - grammar_module="tree_sitter_cpp", - query=_QUERY, - scope_types=frozenset( - {"class_specifier", "struct_specifier", "namespace_definition"} - ), - class_scope_types=frozenset({"class_specifier", "struct_specifier"}), - # Same grammar as C — single `comment` node. - doc_comment_node_types=frozenset({"comment"}), - source_roots=("", "include", "src"), - test_prefix="test_", - language_plugin_version=5, - ), - ] diff --git a/packages/rbtr/src/rbtr/languages/cpp/plugin.py b/packages/rbtr/src/rbtr/languages/cpp/plugin.py new file mode 100644 index 00000000..0f98c914 --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/cpp/plugin.py @@ -0,0 +1,55 @@ +"""C++ language plugin. + +Provides symbol extraction (functions, prototypes, classes, structs, +unions, enums, type aliases, namespaces, methods including operator +overloads, namespace/global variables, and function/object-like +macros) and include directive capture. Namespaces are both a symbol +(class) and a naming scope. + +Extracted chunks:: + + void greet() {} → function "greet", scope "" + class Shape {}; → class "Shape", scope "" + struct Point { ... }; → class "Point", scope "" + class Foo { + void bar() {} → method "bar", scope "Foo" + }; + + #include + → import, metadata {module: "iostream"} +""" + +from __future__ import annotations + +from rbtr.languages._queries import load_query +from rbtr.languages.hookspec import LanguageRegistration, hookimpl + +# ── Query ──────────────────────────────────────────────────────────── + +_QUERY = load_query(__package__, "cpp") + +# ── Plugin ─────────────────────────────────────────────────────────── + + +class CppPlugin: + """C++ language support — functions, classes, methods, includes.""" + + @hookimpl + def rbtr_register_languages(self) -> list[LanguageRegistration]: + return [ + LanguageRegistration( + id="cpp", + extensions=frozenset({".cpp", ".cc", ".cxx", ".hpp", ".hxx"}), + grammar_module="tree_sitter_cpp", + query=_QUERY, + scope_types=frozenset( + {"class_specifier", "struct_specifier", "namespace_definition"} + ), + class_scope_types=frozenset({"class_specifier", "struct_specifier"}), + # Same grammar as C — single `comment` node. + doc_comment_node_types=frozenset({"comment"}), + source_roots=("", "include", "src"), + test_prefix="test_", + language_plugin_version=5, + ), + ] diff --git a/packages/rbtr/src/rbtr/languages/css/__init__.py b/packages/rbtr/src/rbtr/languages/css/__init__.py new file mode 100644 index 00000000..f1849f82 --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/css/__init__.py @@ -0,0 +1 @@ +"""CSS language plugin package.""" diff --git a/packages/rbtr/src/rbtr/languages/css/css.scm b/packages/rbtr/src/rbtr/languages/css/css.scm new file mode 100644 index 00000000..dc091e41 --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/css/css.scm @@ -0,0 +1,21 @@ +(rule_set + (selectors) @_section_name) @doc_section + +(media_statement) @doc_section + +(charset_statement) @doc_section + +(keyframes_statement + (keyframes_name) @_section_name) @doc_section + +(import_statement + (call_expression + (arguments + (string_value (string_content) @_import_module)))) @import + +(import_statement + (string_value (string_content) @_import_module)) @import + +(declaration + (property_name) @_var_name + (#match? @_var_name "^--")) @variable diff --git a/packages/rbtr/src/rbtr/languages/css.py b/packages/rbtr/src/rbtr/languages/css/plugin.py similarity index 81% rename from packages/rbtr/src/rbtr/languages/css.py rename to packages/rbtr/src/rbtr/languages/css/plugin.py index 55663259..36d43129 100644 --- a/packages/rbtr/src/rbtr/languages/css.py +++ b/packages/rbtr/src/rbtr/languages/css/plugin.py @@ -18,34 +18,13 @@ from typing import TYPE_CHECKING +from rbtr.languages._queries import load_query from rbtr.languages.hookspec import LanguageRegistration, enclosing_nodes_of_type, hookimpl if TYPE_CHECKING: from tree_sitter import Node -_QUERY = """\ -(rule_set - (selectors) @_section_name) @doc_section - -(media_statement) @doc_section - -(charset_statement) @doc_section - -(keyframes_statement - (keyframes_name) @_section_name) @doc_section - -(import_statement - (call_expression - (arguments - (string_value (string_content) @_import_module)))) @import - -(import_statement - (string_value (string_content) @_import_module)) @import - -(declaration - (property_name) @_var_name - (#match? @_var_name "^--")) @variable -""" +_QUERY = load_query(__package__, "css") def css_nesting_scope(capture_name: str, node: Node, captures: dict[str, list[Node]]) -> list[str]: diff --git a/packages/rbtr/src/rbtr/languages/go/__init__.py b/packages/rbtr/src/rbtr/languages/go/__init__.py new file mode 100644 index 00000000..1c49c64b --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/go/__init__.py @@ -0,0 +1 @@ +"""Go language plugin package.""" diff --git a/packages/rbtr/src/rbtr/languages/go/go.scm b/packages/rbtr/src/rbtr/languages/go/go.scm new file mode 100644 index 00000000..e14e6fa1 --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/go/go.scm @@ -0,0 +1,49 @@ +(function_declaration + name: (identifier) @_fn_name) @function + +(method_declaration + receiver: (parameter_list + (parameter_declaration + type: [ + (type_identifier) @_scope + (pointer_type (type_identifier) @_scope) + ])) + name: (field_identifier) @_method_name) @method + +(type_declaration + (type_spec + name: (type_identifier) @_cls_name)) @class + +(type_spec + (interface_type + (method_elem + name: (field_identifier) @_method_name) @method)) + +(type_declaration + (type_alias + name: (type_identifier) @_cls_name)) @class + +(import_declaration + (import_spec + path: (interpreted_string_literal) @_import_module) @import) + +(import_declaration + (import_spec_list + (import_spec + path: (interpreted_string_literal) @_import_module) @import)) + +(source_file + (var_declaration + (var_spec + name: (identifier) @_var_name) @variable)) + +(source_file + (const_declaration + (const_spec + name: (identifier) @_var_name) @variable)) + +(source_file + (var_declaration + (var_spec_list + (var_spec + name: (identifier) @_var_name) @variable))) diff --git a/packages/rbtr/src/rbtr/languages/go.py b/packages/rbtr/src/rbtr/languages/go/plugin.py similarity index 64% rename from packages/rbtr/src/rbtr/languages/go.py rename to packages/rbtr/src/rbtr/languages/go/plugin.py index b8388737..49301b93 100644 --- a/packages/rbtr/src/rbtr/languages/go.py +++ b/packages/rbtr/src/rbtr/languages/go/plugin.py @@ -18,61 +18,12 @@ from __future__ import annotations +from rbtr.languages._queries import load_query from rbtr.languages.hookspec import LanguageRegistration, hookimpl # ── Query ──────────────────────────────────────────────────────────── -_QUERY = """\ -(function_declaration - name: (identifier) @_fn_name) @function - -(method_declaration - receiver: (parameter_list - (parameter_declaration - type: [ - (type_identifier) @_scope - (pointer_type (type_identifier) @_scope) - ])) - name: (field_identifier) @_method_name) @method - -(type_declaration - (type_spec - name: (type_identifier) @_cls_name)) @class - -(type_spec - (interface_type - (method_elem - name: (field_identifier) @_method_name) @method)) - -(type_declaration - (type_alias - name: (type_identifier) @_cls_name)) @class - -(import_declaration - (import_spec - path: (interpreted_string_literal) @_import_module) @import) - -(import_declaration - (import_spec_list - (import_spec - path: (interpreted_string_literal) @_import_module) @import)) - -(source_file - (var_declaration - (var_spec - name: (identifier) @_var_name) @variable)) - -(source_file - (const_declaration - (const_spec - name: (identifier) @_var_name) @variable)) - -(source_file - (var_declaration - (var_spec_list - (var_spec - name: (identifier) @_var_name) @variable))) -""" +_QUERY = load_query(__package__, "go") # ── Plugin ─────────────────────────────────────────────────────────── diff --git a/packages/rbtr/src/rbtr/languages/hcl/__init__.py b/packages/rbtr/src/rbtr/languages/hcl/__init__.py new file mode 100644 index 00000000..763eee1f --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/hcl/__init__.py @@ -0,0 +1 @@ +"""HCL language plugin package.""" diff --git a/packages/rbtr/src/rbtr/languages/hcl/hcl.scm b/packages/rbtr/src/rbtr/languages/hcl/hcl.scm new file mode 100644 index 00000000..ed31d0d4 --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/hcl/hcl.scm @@ -0,0 +1,3 @@ +(config_file + (body + (block) @doc_section)) diff --git a/packages/rbtr/src/rbtr/languages/hcl.py b/packages/rbtr/src/rbtr/languages/hcl/plugin.py similarity index 95% rename from packages/rbtr/src/rbtr/languages/hcl.py rename to packages/rbtr/src/rbtr/languages/hcl/plugin.py index c336142f..6f030621 100644 --- a/packages/rbtr/src/rbtr/languages/hcl.py +++ b/packages/rbtr/src/rbtr/languages/hcl/plugin.py @@ -14,6 +14,7 @@ from typing import TYPE_CHECKING +from rbtr.languages._queries import load_query from rbtr.languages.hookspec import LanguageRegistration, hookimpl, resolve_name if TYPE_CHECKING: @@ -21,11 +22,7 @@ # Top-level blocks only: a `block` whose body is the file's own body, # not one nested inside another block. -_QUERY = """\ -(config_file - (body - (block) @doc_section)) -""" +_QUERY = load_query(__package__, "hcl") def hcl_block_name(capture_name: str, node: Node, captures: dict[str, list[Node]]) -> str: diff --git a/packages/rbtr/src/rbtr/languages/html/__init__.py b/packages/rbtr/src/rbtr/languages/html/__init__.py new file mode 100644 index 00000000..76f07495 --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/html/__init__.py @@ -0,0 +1 @@ +"""HTML language plugin package.""" diff --git a/packages/rbtr/src/rbtr/languages/html/html.scm b/packages/rbtr/src/rbtr/languages/html/html.scm new file mode 100644 index 00000000..21b555eb --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/html/html.scm @@ -0,0 +1,18 @@ +(element (start_tag (tag_name) @_tag) + (#any-of? @_tag "head" "body" "article" "aside" "nav" "section" "header" "main" "footer" "figure" "form" "dialog" "details" "table")) @doc_section + +(script_element + (start_tag + (attribute (attribute_name) @_a + (quoted_attribute_value (attribute_value) @_import_module)) + (#eq? @_a "src"))) @import + +(element + [(start_tag (tag_name) @_lt + (attribute (attribute_name) @_h + (quoted_attribute_value (attribute_value) @_import_module))) + (self_closing_tag (tag_name) @_lt + (attribute (attribute_name) @_h + (quoted_attribute_value (attribute_value) @_import_module)))] + (#eq? @_lt "link") + (#eq? @_h "href")) @import diff --git a/packages/rbtr/src/rbtr/languages/html/injections.scm b/packages/rbtr/src/rbtr/languages/html/injections.scm new file mode 100644 index 00000000..ee86b625 --- /dev/null +++ b/packages/rbtr/src/rbtr/languages/html/injections.scm @@ -0,0 +1,8 @@ +; Inline