Squashed 'src/syntax/' content from commit 3619572

git-subtree-dir: src/syntax
git-subtree-split: 3619572ed88841cd2106c141c0baacfcb8496023
This commit is contained in:
CJ van den Berg 2024-07-31 08:50:30 +02:00
commit f94c567994
8 changed files with 768 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/.zig-cache/

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 CJ van den Berg
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

2
README.md Normal file
View file

@ -0,0 +1,2 @@
# flow-syntax
Syntax highlighting module used by [flow](https://github.com/neurocyte/flow), [zat](https://github.com/neurocyte/zat) and [zine](https://github.com/kristoff-it/zine)

94
build.zig Normal file
View file

@ -0,0 +1,94 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const tree_sitter_dep = b.dependency("tree-sitter", .{
.target = target,
.optimize = optimize,
});
_ = b.addModule("syntax", .{
.root_source_file = b.path("src/syntax.zig"),
.imports = &.{
.{ .name = "treez", .module = tree_sitter_dep.module("treez") },
ts_queryfile(b, tree_sitter_dep, "tree-sitter-agda/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-bash/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-c-sharp/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-c/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-cpp/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-css/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-diff/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-dockerfile/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-git-rebase/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-gitcommit/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-go/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-fish/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-haskell/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-html/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-java/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-javascript/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-jsdoc/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-json/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-kdl/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-lua/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-make/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-markdown/tree-sitter-markdown/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-markdown/tree-sitter-markdown-inline/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-nasm/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-nim/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-ninja/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-nix/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-ocaml/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-openscad/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-org/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-php/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-python/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-purescript/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-regex/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-ruby/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-rust/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-ssh-config/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-scala/queries/scala/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-scheme/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-superhtml/tree-sitter-superhtml/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-toml/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-typescript/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-xml/queries/dtd/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-xml/queries/xml/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-yaml/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-zig/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-ziggy/tree-sitter-ziggy/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-ziggy/tree-sitter-ziggy-schema/queries/highlights.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-cpp/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-gitcommit/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-html/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-javascript/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-kdl/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-lua/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-markdown/tree-sitter-markdown-inline/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-markdown/tree-sitter-markdown/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-nasm/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-nix/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-openscad/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-php/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-purescript/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-purescript/vim_queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-rust/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-superhtml/tree-sitter-superhtml/queries/injections.scm"),
ts_queryfile(b, tree_sitter_dep, "tree-sitter-zig/queries/injections.scm"),
},
});
}
fn ts_queryfile(b: *std.Build, dep: *std.Build.Dependency, comptime sub_path: []const u8) std.Build.Module.Import {
return .{
.name = sub_path,
.module = b.createModule(.{
.root_source_file = dep.path(sub_path),
}),
};
}

16
build.zig.zon Normal file
View file

@ -0,0 +1,16 @@
.{
.name = "flow-syntax",
.version = "0.0.1",
.dependencies = .{
.@"tree-sitter" = .{
.url = "https://github.com/neurocyte/tree-sitter/releases/download/master-eda7be4e1fa1ef5046153e1ad6a3e5097d7746f3/source.tar.gz",
.hash = "1220d69c4591a68ab00731fa9becda325da182851afeef30b41011a86f1fba6c19e6",
},
},
.paths = .{
"src",
"build.zig",
"build.zig.zon",
},
}

128
src/file_type.zig Normal file
View file

@ -0,0 +1,128 @@
const std = @import("std");
const treez = @import("treez");
pub const FileType = @This();
color: u24,
icon: []const u8,
name: []const u8,
lang_fn: LangFn,
extensions: []const []const u8,
highlights: [:0]const u8,
injections: ?[:0]const u8,
first_line_matches: ?FirstLineMatch = null,
comment: []const u8,
formatter: ?[]const []const u8,
language_server: ?[]const []const u8,
pub fn get_by_name(name: []const u8) ?*const FileType {
for (file_types) |*file_type|
if (std.mem.eql(u8, file_type.name, name))
return file_type;
return null;
}
pub fn guess(file_path: ?[]const u8, content: []const u8) ?*const FileType {
if (guess_first_line(content)) |ft| return ft;
for (file_types) |*file_type|
if (file_path) |fp| if (match_file_type(file_type, fp))
return file_type;
return null;
}
fn guess_first_line(content: []const u8) ?*const FileType {
const first_line = if (std.mem.indexOf(u8, content, "\n")) |pos| content[0..pos] else content;
for (file_types) |*file_type|
if (file_type.first_line_matches) |match|
if (match_first_line(match, first_line))
return file_type;
return null;
}
fn match_first_line(match: FirstLineMatch, first_line: []const u8) bool {
if (match.prefix) |prefix|
if (prefix.len > first_line.len or !std.mem.eql(u8, first_line[0..prefix.len], prefix))
return false;
if (match.content) |content|
if (std.mem.indexOf(u8, first_line, content)) |_| {} else return false;
return true;
}
fn match_file_type(file_type: *const FileType, file_path: []const u8) bool {
const basename = std.fs.path.basename(file_path);
const extension = std.fs.path.extension(file_path);
return for (file_type.extensions) |ext| {
if (ext.len == basename.len and std.mem.eql(u8, ext, basename))
return true;
if (extension.len > 0 and ext.len == extension.len - 1 and std.mem.eql(u8, ext, extension[1..]))
return true;
} else false;
}
pub fn Parser(comptime lang: []const u8) LangFn {
return get_parser(lang);
}
fn get_parser(comptime lang: []const u8) LangFn {
const language_name = ft_func_name(lang);
return @extern(?LangFn, .{ .name = "tree_sitter_" ++ language_name }) orelse @compileError(std.fmt.comptimePrint("Cannot find extern tree_sitter_{s}", .{language_name}));
}
fn ft_func_name(comptime lang: []const u8) []const u8 {
var transform: [lang.len]u8 = undefined;
for (lang, 0..) |c, i|
transform[i] = if (c == '-') '_' else c;
const func_name = transform;
return &func_name;
}
const LangFn = *const fn () callconv(.C) ?*const treez.Language;
const FirstLineMatch = struct {
prefix: ?[]const u8 = null,
content: ?[]const u8 = null,
};
pub const file_types = load_file_types(@import("file_types.zig"));
fn vec(comptime args: anytype) []const []const u8 {
var cmd: []const []const u8 = &[_][]const u8{};
inline for (args) |arg| {
cmd = cmd ++ [_][]const u8{arg};
}
return cmd;
}
fn load_file_types(comptime Namespace: type) []const FileType {
comptime switch (@typeInfo(Namespace)) {
.Struct => |info| {
var count = 0;
for (info.decls) |_| {
// @compileLog(decl.name, @TypeOf(@field(Namespace, decl.name)));
count += 1;
}
var construct_types: [count]FileType = undefined;
var i = 0;
for (info.decls) |decl| {
const lang = decl.name;
const args = @field(Namespace, lang);
construct_types[i] = .{
.color = if (@hasField(@TypeOf(args), "color")) args.color else 0xffffff,
.icon = if (@hasField(@TypeOf(args), "icon")) args.icon else "󱀫",
.name = lang,
.lang_fn = if (@hasField(@TypeOf(args), "parser")) args.parser else get_parser(lang),
.extensions = vec(args.extensions),
.comment = args.comment,
.highlights = if (@hasField(@TypeOf(args), "highlights")) @embedFile(args.highlights) else @embedFile("tree-sitter-" ++ lang ++ "/queries/highlights.scm"),
.injections = if (@hasField(@TypeOf(args), "injections")) @embedFile(args.injections) else null,
.first_line_matches = if (@hasField(@TypeOf(args), "first_line_matches")) args.first_line_matches else null,
.formatter = if (@hasField(@TypeOf(args), "formatter")) vec(args.formatter) else null,
.language_server = if (@hasField(@TypeOf(args), "language_server")) vec(args.language_server) else null,
};
i += 1;
}
const types = construct_types;
return &types;
},
else => @compileError("expected tuple or struct type"),
};
}

366
src/file_types.zig Normal file
View file

@ -0,0 +1,366 @@
pub const agda = .{
.extensions = .{"agda"},
.comment = "--",
};
pub const bash = .{
.color = 0x3e474a,
.icon = "󱆃",
.extensions = .{ "sh", "bash", ".profile" },
.comment = "#",
.first_line_matches = .{ .prefix = "#!", .content = "sh" },
.formatter = .{ "shfmt", "--indent", "4" },
.language_server = .{ "bash-language-server", "start" },
};
pub const c = .{
.icon = "",
.extensions = .{ "c", "h" },
.comment = "//",
.formatter = .{"clang-format"},
.language_server = .{"clangd"},
};
pub const @"c-sharp" = .{
.color = 0x68217a,
.icon = "󰌛",
.extensions = .{"cs"},
.comment = "//",
.language_server = .{ "omnisharp", "-lsp" },
};
pub const conf = .{
.color = 0x000000,
.icon = "",
.extensions = .{ "conf", "config", ".gitconfig" },
.highlights = fish.highlights,
.comment = "#",
.parser = fish.parser,
};
pub const cpp = .{
.color = 0x9c033a,
.icon = "",
.extensions = .{ "cc", "cpp", "cxx", "hpp", "hxx", "h", "ipp", "ixx" },
.comment = "//",
.injections = "tree-sitter-cpp/queries/injections.scm",
.formatter = .{"clang-format"},
.language_server = .{"clangd"},
};
pub const css = .{
.color = 0x3d8fc6,
.icon = "󰌜",
.extensions = .{"css"},
.comment = "//",
};
pub const diff = .{
.extensions = .{ "diff", "patch" },
.comment = "#",
};
pub const dockerfile = .{
.color = 0x019bc6,
.icon = "",
.extensions = .{ "Dockerfile", "dockerfile", "docker", "Containerfile", "container" },
.comment = "#",
};
pub const dtd = .{
.icon = "󰗀",
.extensions = .{"dtd"},
.comment = "<!--",
.highlights = "tree-sitter-xml/queries/dtd/highlights.scm",
};
pub const fish = .{
.extensions = .{"fish"},
.comment = "#",
.parser = @import("file_type.zig").Parser("fish"),
.highlights = "tree-sitter-fish/queries/highlights.scm",
};
pub const @"git-rebase" = .{
.color = 0xf34f29,
.icon = "",
.extensions = .{"git-rebase-todo"},
.comment = "#",
};
pub const gitcommit = .{
.color = 0xf34f29,
.icon = "",
.extensions = .{"COMMIT_EDITMSG"},
.comment = "#",
.injections = "tree-sitter-gitcommit/queries/injections.scm",
};
pub const go = .{
.color = 0x00acd7,
.icon = "󰟓",
.extensions = .{"go"},
.comment = "//",
.language_server = .{"gopls"},
};
pub const haskell = .{
.color = 0x5E5185,
.icon = "󰲒",
.extensions = .{"hs"},
.comment = "--",
.language_server = .{"haskell-language-server-wrapper", "lsp"},
};
pub const html = .{
.color = 0xe54d26,
.icon = "󰌝",
.extensions = .{"html"},
.comment = "<!--",
.injections = "tree-sitter-html/queries/injections.scm",
.language_server = .{ "superhtml", "lsp" }, // https://github.com/kristoff-it/super-html.git
.formatter = .{ "superhtml", "fmt", "--stdin" },
};
pub const superhtml = .{
.color = 0xe54d26,
.icon = "󰌝",
.extensions = .{"shtml"},
.comment = "<!--",
.highlights = "tree-sitter-superhtml/tree-sitter-superhtml/queries/highlights.scm",
.injections = "tree-sitter-superhtml/tree-sitter-superhtml/queries/injections.scm",
.language_server = .{ "superhtml", "lsp" },
.formatter = .{ "superhtml", "fmt", "--stdin-super" },
};
pub const java = .{
.color = 0xEA2D2E,
.icon = "",
.extensions = .{"java"},
.comment = "//",
};
pub const javascript = .{
.color = 0xf0db4f,
.icon = "󰌞",
.extensions = .{"js"},
.comment = "//",
.injections = "tree-sitter-javascript/queries/injections.scm",
.language_server = .{ "deno", "lsp" },
};
pub const json = .{
.extensions = .{"json"},
.comment = "//",
.language_server = .{ "deno", "lsp" },
};
pub const kdl = .{
.color = 0x000000,
.icon = "",
.extensions = .{"kdl"},
.comment = "//",
};
pub const lua = .{
.color = 0x02027d,
.icon = "󰢱",
.extensions = .{"lua"},
.comment = "--",
.injections = "tree-sitter-lua/queries/injections.scm",
.first_line_matches = .{ .prefix = "--", .content = "lua" },
.language_server = .{"lua-lsp"},
};
pub const make = .{
.extensions = .{ "makefile", "Makefile", "MAKEFILE", "GNUmakefile", "mk", "mak", "dsp" },
.comment = "#",
};
pub const markdown = .{
.color = 0x000000,
.icon = "󰍔",
.extensions = .{"md"},
.comment = "<!--",
.highlights = "tree-sitter-markdown/tree-sitter-markdown/queries/highlights.scm",
.injections = "tree-sitter-markdown/tree-sitter-markdown/queries/injections.scm",
.language_server = .{ "deno", "lsp" },
};
pub const @"markdown-inline" = .{
.color = 0x000000,
.icon = "󰍔",
.extensions = .{},
.comment = "<!--",
.highlights = "tree-sitter-markdown/tree-sitter-markdown-inline/queries/highlights.scm",
.injections = "tree-sitter-markdown/tree-sitter-markdown-inline/queries/injections.scm",
};
pub const nasm = .{
.extensions = .{ "asm", "nasm" },
.comment = "#",
.injections = "tree-sitter-nasm/queries/injections.scm",
};
pub const nim = .{
.color = 0xffe953,
.icon = "",
.extensions = .{"nim"},
.comment = "#",
.language_server = .{"nimlangserver"},
};
pub const nimble = .{
.color = 0xffe953,
.icon = "",
.extensions = .{"nimble"},
.highlights = toml.highlights,
.comment = "#",
.parser = toml.parser,
};
pub const ninja = .{
.extensions = .{"ninja"},
.comment = "#",
};
pub const nix = .{
.color = 0x5277C3,
.icon = "󱄅",
.extensions = .{"nix"},
.comment = "#",
.injections = "tree-sitter-nix/queries/injections.scm",
};
pub const ocaml = .{
.color = 0xF18803,
.icon = "",
.extensions = .{ "ml", "mli" },
.comment = "(*",
};
pub const openscad = .{
.color = 0x000000,
.icon = "󰻫",
.extensions = .{"scad"},
.comment = "//",
.injections = "tree-sitter-openscad/queries/injections.scm",
};
pub const org = .{
.icon = "",
.extensions = .{"org"},
.comment = "#",
};
pub const php = .{
.color = 0x6181b6,
.icon = "󰌟",
.extensions = .{"php"},
.comment = "//",
.injections = "tree-sitter-php/queries/injections.scm",
};
pub const purescript = .{
.color = 0x14161a,
.icon = "",
.extensions = .{"purs"},
.comment = "--",
.injections = "tree-sitter-purescript/queries/injections.scm",
};
pub const python = .{
.color = 0xffd845,
.icon = "󰌠",
.extensions = .{"py"},
.comment = "#",
.first_line_matches = .{ .prefix = "#!", .content = "/bin/bash" },
.language_server = .{"pylsp"},
};
pub const regex = .{
.extensions = .{},
.comment = "#",
};
pub const ruby = .{
.color = 0xd91404,
.icon = "󰴭",
.extensions = .{"rb"},
.comment = "#",
};
pub const rust = .{
.color = 0x000000,
.icon = "󱘗",
.extensions = .{"rs"},
.comment = "//",
.injections = "tree-sitter-rust/queries/injections.scm",
.language_server = .{"rust-analyzer"},
};
pub const scheme = .{
.extensions = .{ "scm", "ss", "el" },
.comment = ";",
};
pub const @"ssh-config" = .{
.extensions = .{".ssh/config"},
.comment = "#",
};
pub const toml = .{
.extensions = .{"toml"},
.comment = "#",
.highlights = "tree-sitter-toml/queries/highlights.scm",
.parser = @import("file_type.zig").Parser("toml"),
};
pub const typescript = .{
.color = 0x007acc,
.icon = "󰛦",
.extensions = .{ "ts", "tsx" },
.comment = "//",
.language_server = .{ "deno", "lsp" },
};
pub const xml = .{
.icon = "󰗀",
.extensions = .{"xml"},
.comment = "<!--",
.highlights = "tree-sitter-xml/queries/xml/highlights.scm",
.first_line_matches = .{ .prefix = "<?xml " },
};
pub const yaml = .{
.color = 0x000000,
.icon = "",
.extensions = .{"yaml", "yml"},
.comment = "#",
};
pub const zig = .{
.color = 0xf7a41d,
.icon = "",
.extensions = .{ "zig", "zon" },
.comment = "//",
.formatter = .{ "zig", "fmt", "--stdin" },
.language_server = .{"zls"},
.injections = "tree-sitter-zig/queries/injections.scm",
};
pub const ziggy = .{
.color = 0xf7a41d,
.icon = "",
.extensions = .{ "ziggy", "zgy" },
.comment = "//",
.highlights = "tree-sitter-ziggy/tree-sitter-ziggy/queries/highlights.scm",
};
pub const @"ziggy-schema" = .{
.color = 0xf7a41d,
.icon = "",
.extensions = .{ "ziggy-schema", "zyg-schema" },
.comment = "//",
.highlights = "tree-sitter-ziggy/tree-sitter-ziggy-schema/queries/highlights.scm",
};

140
src/syntax.zig Normal file
View file

@ -0,0 +1,140 @@
const std = @import("std");
const treez = @import("treez");
const Self = @This();
pub const Edit = treez.InputEdit;
pub const FileType = @import("file_type.zig");
pub const Range = treez.Range;
pub const Point = treez.Point;
const Language = treez.Language;
const Parser = treez.Parser;
const Query = treez.Query;
const Tree = treez.Tree;
pub const Node = treez.Node;
a: std.mem.Allocator,
lang: *const Language,
file_type: *const FileType,
parser: *Parser,
query: *Query,
injections: *Query,
tree: ?*Tree = null,
pub fn create(file_type: *const FileType, a: std.mem.Allocator, content: []const u8) !*Self {
const self = try a.create(Self);
self.* = .{
.a = a,
.lang = file_type.lang_fn() orelse std.debug.panic("tree-sitter parser function failed for language: {d}", .{file_type.name}),
.file_type = file_type,
.parser = try Parser.create(),
.query = try Query.create(self.lang, file_type.highlights),
.injections = try Query.create(self.lang, file_type.highlights),
};
errdefer self.destroy();
try self.parser.setLanguage(self.lang);
try self.refresh_full(content);
return self;
}
pub fn create_file_type(a: std.mem.Allocator, content: []const u8, lang_name: []const u8) !*Self {
const file_type = FileType.get_by_name(lang_name) orelse return error.NotFound;
return create(file_type, a, content);
}
pub fn create_guess_file_type(a: std.mem.Allocator, content: []const u8, file_path: ?[]const u8) !*Self {
const file_type = FileType.guess(file_path, content) orelse return error.NotFound;
return create(file_type, a, content);
}
pub fn destroy(self: *Self) void {
if (self.tree) |tree| tree.destroy();
self.query.destroy();
self.parser.destroy();
self.a.destroy(self);
}
pub fn refresh_full(self: *Self, content: []const u8) !void {
if (self.tree) |tree| tree.destroy();
self.tree = try self.parser.parseString(null, content);
}
pub fn edit(self: *Self, ed: Edit) void {
if (self.tree) |tree| tree.edit(&ed);
}
pub fn refresh(self: *Self, content: []const u8) !void {
const old_tree = self.tree;
defer if (old_tree) |tree| tree.destroy();
self.tree = try self.parser.parseString(old_tree, content);
}
pub fn refresh_from_buffer(self: *Self, buffer: anytype, metrics: anytype) !void {
const old_tree = self.tree;
defer if (old_tree) |tree| tree.destroy();
const State = struct {
buffer: @TypeOf(buffer),
metrics: @TypeOf(metrics),
syntax: *Self,
result_buf: [1024]u8 = undefined,
};
var state: State = .{
.buffer = buffer,
.metrics = metrics,
.syntax = self,
};
const input: treez.Input = .{
.payload = &state,
.read = struct {
fn read(payload: ?*anyopaque, _: u32, position: treez.Point, bytes_read: *u32) callconv(.C) [*:0]const u8 {
const ctx: *State = @ptrCast(@alignCast(payload orelse return ""));
const result = ctx.buffer.get_from_pos(.{ .row = position.row, .col = position.column }, &ctx.result_buf, ctx.metrics);
bytes_read.* = @intCast(result.len);
return @ptrCast(result.ptr);
}
}.read,
.encoding = .utf_8,
};
self.tree = try self.parser.parse(old_tree, input);
}
fn CallBack(comptime T: type) type {
return fn (ctx: T, sel: Range, scope: []const u8, id: u32, capture_idx: usize, node: *const Node) error{Stop}!void;
}
pub fn render(self: *const Self, ctx: anytype, comptime cb: CallBack(@TypeOf(ctx)), range: ?Range) !void {
const cursor = try Query.Cursor.create();
defer cursor.destroy();
const tree = if (self.tree) |p| p else return;
cursor.execute(self.query, tree.getRootNode());
if (range) |r| cursor.setPointRange(r.start_point, r.end_point);
while (cursor.nextMatch()) |match| {
var idx: usize = 0;
for (match.captures()) |capture| {
try cb(ctx, capture.node.getRange(), self.query.getCaptureNameForId(capture.id), capture.id, idx, &capture.node);
idx += 1;
}
}
}
pub fn highlights_at_point(self: *const Self, ctx: anytype, comptime cb: CallBack(@TypeOf(ctx)), point: Point) void {
const cursor = Query.Cursor.create() catch return;
defer cursor.destroy();
const tree = if (self.tree) |p| p else return;
cursor.execute(self.query, tree.getRootNode());
cursor.setPointRange(.{ .row = point.row, .column = 0 }, .{ .row = point.row + 1, .column = 0 });
while (cursor.nextMatch()) |match| {
for (match.captures()) |capture| {
const range = capture.node.getRange();
const start = range.start_point;
const end = range.end_point;
const scope = self.query.getCaptureNameForId(capture.id);
if (start.row == point.row and start.column <= point.column and point.column < end.column)
cb(ctx, range, scope, capture.id, 0, &capture.node) catch return;
break;
}
}
return;
}