diff --git a/build.zig b/build.zig index fb74de340..2cce41a31 100644 --- a/build.zig +++ b/build.zig @@ -10,6 +10,7 @@ const font = @import("src/font/main.zig"); const renderer = @import("src/renderer.zig"); const terminfo = @import("src/terminfo/main.zig"); const config_vim = @import("src/config/vim.zig"); +const config_sublime_syntax = @import("src/config/sublime_syntax.zig"); const fish_completions = @import("src/build/fish_completions.zig"); const build_config = @import("src/build_config.zig"); const BuildConfig = build_config.BuildConfig; @@ -515,6 +516,22 @@ pub fn build(b: *std.Build) !void { }); } + // Sublime syntax highlighting for bat cli tool + // NOTE: The current implementation requires symlinking the generated + // 'ghostty.sublime-syntax' file from zig-out to the '~.config/bat/syntaxes' + // directory. The syntax then needs to be mapped to the correct language in + // the config file within the '~.config/bat' directory + // (ex: --map-syntax "/Users/user/.config/ghostty/config:Ghostty Config"). + { + const wf = b.addWriteFiles(); + _ = wf.add("ghostty.sublime-syntax", config_sublime_syntax.syntax); + b.installDirectory(.{ + .source_dir = wf.getDirectory(), + .install_dir = .prefix, + .install_subdir = "share/bat/syntaxes", + }); + } + // Documentation if (emit_docs) { try buildDocumentation(b, config); diff --git a/src/config/sublime_syntax.zig b/src/config/sublime_syntax.zig new file mode 100644 index 000000000..1b7c4900a --- /dev/null +++ b/src/config/sublime_syntax.zig @@ -0,0 +1,51 @@ +const std = @import("std"); +const Config = @import("Config.zig"); + +const Template = struct { + const header = + \\%YAML 1.2 + \\--- + \\# See http://www.sublimetext.com/docs/syntax.html + \\name: Ghostty Config + \\file_extensions: + \\ - ghostty + \\scope: source.ghostty + \\ + \\contexts: + \\ main: + \\ # Comments + \\ - match: '#.*$' + \\ scope: comment.line.number-sign.ghostty + \\ + \\ # Keywords + \\ - match: '\b( + ; + const footer = + \\)\b' + \\ scope: keyword.other.ghostty + \\ + ; +}; + +/// Check if a field is internal (starts with underscore) +fn isInternal(name: []const u8) bool { + return name.len > 0 and name[0] == '_'; +} + +/// Generate keywords from Config fields +fn generateKeywords() []const u8 { + @setEvalBranchQuota(5000); + var keywords: []const u8 = ""; + const config_fields = @typeInfo(Config).Struct.fields; + + for (config_fields) |field| { + if (isInternal(field.name)) continue; + if (keywords.len > 0) keywords = keywords ++ "|"; + keywords = keywords ++ field.name; + } + + return keywords; +} + +/// Complete Sublime syntax file content +pub const syntax = Template.header ++ generateKeywords() ++ Template.footer;