Skip to content

Commit 60edf2a

Browse files
committed
feat(tui): color SQL, Dockerfiles, config files and scripts in file tools
write, edit and apply_patch color a file by its extension, and many files people edit every day came out plain: no parser was registered for SQL, Dockerfiles, ini/systemd units or HAML, `.sh` files mapped to "shellscript" while the parser is "bash" (likewise Makefiles and Terraform), and extensionless files such as Dockerfile, Gemfile, PKGBUILD or a script with a #! line had no language at all. `detectFiletype` (packages/tui/src/util/filetype.ts) adds file names, dotenv files, ini-style config and systemd/quadlet units, the parser names for shellscript/makefile/terraform, and for a file still unknown the interpreter on its #! line, read from the content or from a diff whose first hunk starts at line 1. write, edit, apply_patch and the permission diff use it; diffs keep their red/green backgrounds with the syntax colors on top. New parsers: erb from the tree-sitter-embedded-template release, with Ruby and HTML injected. SQL, Dockerfile, ini and HAML publish no wasm, so packages/tui/src/parsers bundles builds of them with their highlights queries and licenses, embedded in the binary through file imports; its README names each source commit and the rebuild command. SQL is 2.4 MB, each of the other three under 50 KB. A write that is still running already has its whole content, so it now shows as a colored block titled "Writing" instead of one line. `syntax.files: false` in tui.json goes back to extension-only detection. AI-Model: anthropic/claude-opus-5-5 AI-Variant: high AI-Tool: opencode 1.19.0-vt-227-dfb56f76c7 AI-Platform: linux AI-Harness: Vibeterm e8a9833 AI-Session-ID: ses_ed1e2b932ffe6tTqhsOiGuYXRE
1 parent 65861b2 commit 60edf2a

23 files changed

Lines changed: 1110 additions & 8 deletions

‎packages/tui/src/config/index.tsx‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export const Syntax = Schema.Struct({
4242
description:
4343
"Color a heredoc in a bash command in the language of the command that reads it, such as python or psql (default: true)",
4444
}),
45+
files: Schema.optional(Schema.Boolean).annotate({
46+
description:
47+
"Detect the language of written, edited and patched files beyond their extension: SQL, Dockerfiles, ini-style config and systemd units, dotenv, ERB, HAML, and a #! line on files with none (default: true)",
48+
}),
4549
}).annotate({ description: "Syntax highlighting in tool calls" })
4650
export const Cursor = Schema.Struct({
4751
style: Schema.optional(Schema.Literals(["block", "underline", "line", "default"])).annotate({

‎packages/tui/src/parsers-config.ts‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
import sqlWasm from "./parsers/sql/tree-sitter-sql.wasm" with { type: "file" }
2+
import sqlHighlights from "./parsers/sql/highlights.scm" with { type: "file" }
3+
import dockerfileWasm from "./parsers/dockerfile/tree-sitter-dockerfile.wasm" with { type: "file" }
4+
import dockerfileHighlights from "./parsers/dockerfile/highlights.scm" with { type: "file" }
5+
import iniWasm from "./parsers/ini/tree-sitter-ini.wasm" with { type: "file" }
6+
import iniHighlights from "./parsers/ini/highlights.scm" with { type: "file" }
7+
import hamlWasm from "./parsers/haml/tree-sitter-haml.wasm" with { type: "file" }
8+
import hamlHighlights from "./parsers/haml/highlights.scm" with { type: "file" }
9+
import hamlInjections from "./parsers/haml/injections.scm" with { type: "file" }
10+
11+
const erbInjections: Record<string, string> = { code: "ruby", content: "html" }
12+
const hamlInjectionNodes: Record<string, string> = { ruby_code: "ruby", ruby_attributes: "ruby" }
13+
114
export default {
215
// NOTE: FOR markdown, javascript and typescript, we use the opentui built-in parsers
316
// Warn: when taking queries from the nvim-treesitter repo, make sure to include the query dependencies as well
@@ -382,5 +395,44 @@ export default {
382395
],
383396
},
384397
},
398+
{
399+
filetype: "erb",
400+
wasm: "https://github.com/tree-sitter/tree-sitter-embedded-template/releases/download/v0.25.0/tree-sitter-embedded_template.wasm",
401+
queries: {
402+
highlights: [
403+
"https://raw.githubusercontent.com/tree-sitter/tree-sitter-embedded-template/v0.25.0/queries/highlights.scm",
404+
],
405+
injections: [
406+
"https://raw.githubusercontent.com/tree-sitter/tree-sitter-embedded-template/v0.25.0/queries/injections-erb.scm",
407+
],
408+
},
409+
injectionMapping: {
410+
nodeTypes: erbInjections,
411+
},
412+
},
413+
// No release of these grammars publishes a wasm build, so ./parsers bundles one (see its README).
414+
{
415+
filetype: "sql",
416+
wasm: sqlWasm,
417+
queries: { highlights: [sqlHighlights] },
418+
},
419+
{
420+
filetype: "dockerfile",
421+
wasm: dockerfileWasm,
422+
queries: { highlights: [dockerfileHighlights] },
423+
},
424+
{
425+
filetype: "ini",
426+
wasm: iniWasm,
427+
queries: { highlights: [iniHighlights] },
428+
},
429+
{
430+
filetype: "haml",
431+
wasm: hamlWasm,
432+
queries: { highlights: [hamlHighlights], injections: [hamlInjections] },
433+
injectionMapping: {
434+
nodeTypes: hamlInjectionNodes,
435+
},
436+
},
385437
],
386438
}

‎packages/tui/src/parsers/README.md‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Bundled tree-sitter grammars
2+
3+
These grammars publish no wasm build, so the TUI embeds one. Each directory holds the
4+
grammar's wasm, its own `queries/highlights.scm` from the same commit, and its license.
5+
`haml/injections.scm` is local: the grammar's own injections use capture names opentui does
6+
not read. The `sql` and `ini` queries drop `@spell` from their comment capture:
7+
the TUI theme colors `spell` as plain text, which would override the comment color.
8+
9+
| Language | Source | Commit |
10+
| --- | --- | --- |
11+
| sql | [DerekStride/tree-sitter-sql](https://github.com/DerekStride/tree-sitter-sql) `v0.3.11` | `7b51ecda191d36b92f5a90a8d1bc3faef1c7b8b8` |
12+
| dockerfile | [camdencheek/tree-sitter-dockerfile](https://github.com/camdencheek/tree-sitter-dockerfile) | `971acdd908568b4531b0ba28a445bf0bb720aba5` |
13+
| ini | [justinmk/tree-sitter-ini](https://github.com/justinmk/tree-sitter-ini) | `e4018b5176132b4f3c5d6e61cea383f42288d0f5` |
14+
| haml | [vitallium/tree-sitter-haml](https://github.com/vitallium/tree-sitter-haml) | `b2f317a57cca67c445ae925149911a88e53e6c7b` |
15+
16+
Rebuild one with tree-sitter CLI 0.25.10 and Docker, from a checkout at that commit:
17+
18+
```sh
19+
tree-sitter generate # only when src/parser.c is not committed (sql)
20+
tree-sitter build --wasm --docker -o tree-sitter-<language>.wasm .
21+
```
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
declare module "*.wasm" {
2+
const path: string
3+
export default path
4+
}
5+
6+
declare module "*.scm" {
7+
const path: string
8+
export default path
9+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2021 Camden Cheek
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
[
2+
"FROM"
3+
"AS"
4+
"RUN"
5+
"CMD"
6+
"LABEL"
7+
"EXPOSE"
8+
"ENV"
9+
"ADD"
10+
"COPY"
11+
"ENTRYPOINT"
12+
"VOLUME"
13+
"USER"
14+
"WORKDIR"
15+
"ARG"
16+
"ONBUILD"
17+
"STOPSIGNAL"
18+
"HEALTHCHECK"
19+
"SHELL"
20+
"MAINTAINER"
21+
"CROSS_BUILD"
22+
(heredoc_marker)
23+
(heredoc_end)
24+
] @keyword
25+
26+
[
27+
":"
28+
"@"
29+
] @operator
30+
31+
(comment) @comment
32+
33+
34+
(image_spec
35+
(image_tag
36+
":" @punctuation.special)
37+
(image_digest
38+
"@" @punctuation.special))
39+
40+
[
41+
(double_quoted_string)
42+
(single_quoted_string)
43+
(json_string)
44+
(heredoc_line)
45+
] @string
46+
47+
(expansion
48+
[
49+
"$"
50+
"{"
51+
"}"
52+
] @punctuation.special
53+
) @none
54+
55+
((variable) @constant
56+
(#match? @constant "^[A-Z][A-Z_0-9]*$"))
57+
58+
47.6 KB
Binary file not shown.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
The MIT License (MIT)
3+
4+
Copyright (c) 2024 Vitaly Slobodin <[email protected]>
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[
2+
"="
3+
"-"
4+
] @keyword
5+
6+
(attribute_name) @attribute
7+
(tag_name) @tag
8+
(class) @type
9+
(comment) @comment
10+
11+
[
12+
(quoted_attribute_value)
13+
] @string
14+
15+
(verbatim_string) @string
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(ruby_code) @injection.content
2+
3+
(ruby_attributes) @injection.content

0 commit comments

Comments
 (0)