From e9632a0f9148dbab4aae4d1de50ce73cff86583f Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Thu, 21 Dec 2023 10:52:41 -0600 Subject: [PATCH 1/4] build: build Vim plugin files for Ghostty config file Generate Vim syntax and ftplugin files for the Ghostty config file that highlight Ghostty config keywords and offer completion for valid config keys. The list of configuration keys is generated at compile time. The plugin files are installed to ${prefix}/share/vim/vimfiles, which is a standard location for installing 3rd party Vim plugin files. --- build.zig | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/build.zig b/build.zig index 4318997cb..bc773c7fe 100644 --- a/build.zig +++ b/build.zig @@ -13,6 +13,7 @@ const LibtoolStep = @import("src/build/LibtoolStep.zig"); const LipoStep = @import("src/build/LipoStep.zig"); const XCFrameworkStep = @import("src/build/XCFrameworkStep.zig"); const Version = @import("src/build/Version.zig"); +const Config = @import("src/config/Config.zig"); // Do a comptime Zig version requirement. The required Zig version is // somewhat arbitrary: it is meant to be a version that we feel works well, @@ -402,6 +403,113 @@ pub fn build(b: *std.Build) !void { } } + // Vim plugin + { + const wf = b.addWriteFiles(); + + // syntax/ghostty.vim + { + var buf = std.ArrayList(u8).init(b.allocator); + defer buf.deinit(); + + const writer = buf.writer(); + try writer.print( + \\" Vim syntax file + \\" Language: Ghostty config file + \\" Maintainer: Ghostty + \\" + \\" THIS FILE IS AUTO-GENERATED + \\ + \\if exists('b:current_syntax') + \\ finish + \\endif + \\ + \\let b:current_syntax = 'ghostty' + \\ + \\let s:cpo_save = &cpo + \\set cpo&vim + \\ + \\ + , .{}); + + const config_fields = @typeInfo(Config).Struct.fields; + var keywords = try std.ArrayList([]const u8).initCapacity(b.allocator, config_fields.len); + defer keywords.deinit(); + + inline for (config_fields) |field| { + // Ignore fields which begin with _ + if (field.name[0] != '_') { + keywords.appendAssumeCapacity(field.name); + } + } + + try writer.print( + \\syn keyword ghosttyConfigKeyword + \\ \ {s} + \\ + \\syn match ghosttyConfigComment /#.*/ contains=@Spell + \\ + \\hi def link ghosttyConfigComment Comment + \\hi def link ghosttyConfigKeyword Keyword + \\ + \\let &cpo = s:cpo_save + \\unlet s:cpo_save + \\ + , .{ + try std.mem.join(b.allocator, "\n\t\\ ", keywords.items), + }); + + _ = wf.add("syntax/ghostty.vim", buf.items); + } + + // ftdetect/ghostty.vim + { + _ = wf.add( + "ftdetect/ghostty.vim", + "au BufRead,BufNewFile */.config/ghostty/config set ft=ghostty\n", + ); + } + + // ftplugin/ghostty.vim + { + var buf = std.ArrayList(u8).init(b.allocator); + defer buf.deinit(); + + const writer = buf.writer(); + try writer.writeAll( + \\" Vim filetype plugin file + \\" Language: Ghostty config file + \\" Maintainer: Ghostty + \\" + \\" THIS FILE IS AUTO-GENERATED + \\ + \\if exists('b:did_ftplugin') + \\ finish + \\endif + \\let b:did_ftplugin = 1 + \\ + \\setlocal commentstring=#%s + \\setlocal iskeyword+=- + \\ + \\" Use syntax keywords for completion + \\setlocal omnifunc=syntaxcomplete#Complete + \\ + \\let b:undo_ftplugin = 'setl cms< isk< ofu<' + \\ + ); + + _ = wf.add("ftplugin/ghostty.vim", buf.items); + } + + const install_vim_plugin = b.addInstallDirectory(.{ + .source_dir = wf.getDirectory(), + .install_dir = .prefix, + .install_subdir = "share/vim/vimfiles", + }); + install_vim_plugin.step.dependOn(&wf.step); + b.getInstallStep().dependOn(&install_vim_plugin.step); + } + // App (Linux) if (target.isLinux()) { // https://developer.gnome.org/documentation/guidelines/maintainer/integrating.html From f7033524ec56ce0e4a2c330092af4635b0dd433e Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Thu, 21 Dec 2023 11:15:47 -0600 Subject: [PATCH 2/4] macos: add generated Vim plugin files to app bundle --- macos/Ghostty.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/macos/Ghostty.xcodeproj/project.pbxproj b/macos/Ghostty.xcodeproj/project.pbxproj index 8ea8bfca5..641133f89 100644 --- a/macos/Ghostty.xcodeproj/project.pbxproj +++ b/macos/Ghostty.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 55154BE02B33911F001622DC /* ghostty in Resources */ = {isa = PBXBuildFile; fileRef = 55154BDF2B33911F001622DC /* ghostty */; }; + 552964E62B34A9B400030505 /* vim in Resources */ = {isa = PBXBuildFile; fileRef = 552964E52B34A9B400030505 /* vim */; }; 8503D7C72A549C66006CFF3D /* FullScreenHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8503D7C62A549C66006CFF3D /* FullScreenHandler.swift */; }; 857F63812A5E64F200CA4815 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 857F63802A5E64F200CA4815 /* MainMenu.xib */; }; A51B78472AF4B58B00F3EDB9 /* TerminalWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51B78462AF4B58B00F3EDB9 /* TerminalWindow.swift */; }; @@ -54,6 +55,7 @@ /* Begin PBXFileReference section */ 3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = GhosttyReleaseLocal.entitlements; sourceTree = ""; }; 55154BDF2B33911F001622DC /* ghostty */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ghostty; path = "../zig-out/share/ghostty"; sourceTree = ""; }; + 552964E52B34A9B400030505 /* vim */ = {isa = PBXFileReference; lastKnownFileType = folder; name = vim; path = "../zig-out/share/vim"; sourceTree = ""; }; 8503D7C62A549C66006CFF3D /* FullScreenHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenHandler.swift; sourceTree = ""; }; 857F63802A5E64F200CA4815 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = ""; }; A51B78462AF4B58B00F3EDB9 /* TerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalWindow.swift; sourceTree = ""; }; @@ -222,6 +224,7 @@ isa = PBXGroup; children = ( 55154BDF2B33911F001622DC /* ghostty */, + 552964E52B34A9B400030505 /* vim */, A5A1F8842A489D6800D1E8BC /* terminfo */, ); name = Resources; @@ -350,6 +353,7 @@ A596309A2AEE1C6400D64628 /* Terminal.xib in Resources */, 55154BE02B33911F001622DC /* ghostty in Resources */, A5A1F8852A489D6800D1E8BC /* terminfo in Resources */, + 552964E62B34A9B400030505 /* vim in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 4f01aafdbaf6a944a614dbb8a182220bf9239c3e Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Thu, 21 Dec 2023 20:50:58 -0600 Subject: [PATCH 3/4] build: move Vim plugin file generation into a separate Step --- build.zig | 113 +++------------------------------ src/build/VimStep.zig | 143 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 106 deletions(-) create mode 100644 src/build/VimStep.zig diff --git a/build.zig b/build.zig index bc773c7fe..ce653675e 100644 --- a/build.zig +++ b/build.zig @@ -13,7 +13,7 @@ const LibtoolStep = @import("src/build/LibtoolStep.zig"); const LipoStep = @import("src/build/LipoStep.zig"); const XCFrameworkStep = @import("src/build/XCFrameworkStep.zig"); const Version = @import("src/build/Version.zig"); -const Config = @import("src/config/Config.zig"); +const VimStep = @import("src/build/VimStep.zig"); // Do a comptime Zig version requirement. The required Zig version is // somewhat arbitrary: it is meant to be a version that we feel works well, @@ -404,111 +404,12 @@ pub fn build(b: *std.Build) !void { } // Vim plugin - { - const wf = b.addWriteFiles(); - - // syntax/ghostty.vim - { - var buf = std.ArrayList(u8).init(b.allocator); - defer buf.deinit(); - - const writer = buf.writer(); - try writer.print( - \\" Vim syntax file - \\" Language: Ghostty config file - \\" Maintainer: Ghostty - \\" - \\" THIS FILE IS AUTO-GENERATED - \\ - \\if exists('b:current_syntax') - \\ finish - \\endif - \\ - \\let b:current_syntax = 'ghostty' - \\ - \\let s:cpo_save = &cpo - \\set cpo&vim - \\ - \\ - , .{}); - - const config_fields = @typeInfo(Config).Struct.fields; - var keywords = try std.ArrayList([]const u8).initCapacity(b.allocator, config_fields.len); - defer keywords.deinit(); - - inline for (config_fields) |field| { - // Ignore fields which begin with _ - if (field.name[0] != '_') { - keywords.appendAssumeCapacity(field.name); - } - } - - try writer.print( - \\syn keyword ghosttyConfigKeyword - \\ \ {s} - \\ - \\syn match ghosttyConfigComment /#.*/ contains=@Spell - \\ - \\hi def link ghosttyConfigComment Comment - \\hi def link ghosttyConfigKeyword Keyword - \\ - \\let &cpo = s:cpo_save - \\unlet s:cpo_save - \\ - , .{ - try std.mem.join(b.allocator, "\n\t\\ ", keywords.items), - }); - - _ = wf.add("syntax/ghostty.vim", buf.items); - } - - // ftdetect/ghostty.vim - { - _ = wf.add( - "ftdetect/ghostty.vim", - "au BufRead,BufNewFile */.config/ghostty/config set ft=ghostty\n", - ); - } - - // ftplugin/ghostty.vim - { - var buf = std.ArrayList(u8).init(b.allocator); - defer buf.deinit(); - - const writer = buf.writer(); - try writer.writeAll( - \\" Vim filetype plugin file - \\" Language: Ghostty config file - \\" Maintainer: Ghostty - \\" - \\" THIS FILE IS AUTO-GENERATED - \\ - \\if exists('b:did_ftplugin') - \\ finish - \\endif - \\let b:did_ftplugin = 1 - \\ - \\setlocal commentstring=#%s - \\setlocal iskeyword+=- - \\ - \\" Use syntax keywords for completion - \\setlocal omnifunc=syntaxcomplete#Complete - \\ - \\let b:undo_ftplugin = 'setl cms< isk< ofu<' - \\ - ); - - _ = wf.add("ftplugin/ghostty.vim", buf.items); - } - - const install_vim_plugin = b.addInstallDirectory(.{ - .source_dir = wf.getDirectory(), - .install_dir = .prefix, - .install_subdir = "share/vim/vimfiles", - }); - install_vim_plugin.step.dependOn(&wf.step); - b.getInstallStep().dependOn(&install_vim_plugin.step); - } + const vim_step = VimStep.create(b); + b.installDirectory(.{ + .source_dir = vim_step.getDirectory(), + .install_dir = .prefix, + .install_subdir = "share/vim/vimfiles", + }); // App (Linux) if (target.isLinux()) { diff --git a/src/build/VimStep.zig b/src/build/VimStep.zig new file mode 100644 index 000000000..7b5ef9154 --- /dev/null +++ b/src/build/VimStep.zig @@ -0,0 +1,143 @@ +//! A Zig build step that generates Vim plugin files for Ghostty's configuration +//! file. + +const VimStep = @This(); + +const std = @import("std"); +const Step = std.Build.Step; + +const Config = @import("../config/Config.zig"); + +step: *Step, + +// The build step that generates the file contents +generate_step: Step, + +pub fn create(b: *std.Build) *VimStep { + const self = b.allocator.create(VimStep) catch @panic("OOM"); + + const write_file = Step.WriteFile.create(b); + + self.* = .{ + .step = &write_file.step, + .generate_step = Step.init(.{ + .id = .custom, + .name = "generate Vim plugin files", + .owner = b, + .makeFn = make, + }), + }; + + write_file.step.dependOn(&self.generate_step); + + return self; +} + +pub fn getDirectory(self: *VimStep) std.Build.LazyPath { + const wf = @fieldParentPtr(Step.WriteFile, "step", self.step); + return wf.getDirectory(); +} + +fn make(step: *Step, prog_node: *std.Progress.Node) !void { + _ = prog_node; + const self = @fieldParentPtr(VimStep, "generate_step", step); + const wf = @fieldParentPtr(Step.WriteFile, "step", self.step); + const b = step.owner; + + // syntax/ghostty.vim + { + var buf = std.ArrayList(u8).init(b.allocator); + defer buf.deinit(); + + const writer = buf.writer(); + try writer.print( + \\" Vim syntax file + \\" Language: Ghostty config file + \\" Maintainer: Ghostty + \\" + \\" THIS FILE IS AUTO-GENERATED + \\ + \\if exists('b:current_syntax') + \\ finish + \\endif + \\ + \\let b:current_syntax = 'ghostty' + \\ + \\let s:cpo_save = &cpo + \\set cpo&vim + \\ + \\ + , .{}); + + const config_fields = @typeInfo(Config).Struct.fields; + var keywords = try std.ArrayList([]const u8).initCapacity( + b.allocator, + config_fields.len, + ); + defer keywords.deinit(); + + inline for (config_fields) |field| { + // Ignore fields which begin with _ + if (field.name[0] != '_') { + keywords.appendAssumeCapacity(field.name); + } + } + + try writer.print( + \\syn keyword ghosttyConfigKeyword + \\ \ {s} + \\ + \\syn match ghosttyConfigComment /#.*/ contains=@Spell + \\ + \\hi def link ghosttyConfigComment Comment + \\hi def link ghosttyConfigKeyword Keyword + \\ + \\let &cpo = s:cpo_save + \\unlet s:cpo_save + \\ + , .{ + try std.mem.join(b.allocator, "\n\t\\ ", keywords.items), + }); + + _ = wf.add("syntax/ghostty.vim", buf.items); + } + + // ftdetect/ghostty.vim + { + _ = wf.add( + "ftdetect/ghostty.vim", + "au BufRead,BufNewFile */.config/ghostty/config set ft=ghostty\n", + ); + } + + // ftplugin/ghostty.vim + { + var buf = std.ArrayList(u8).init(b.allocator); + defer buf.deinit(); + + const writer = buf.writer(); + try writer.writeAll( + \\" Vim filetype plugin file + \\" Language: Ghostty config file + \\" Maintainer: Ghostty + \\" + \\" THIS FILE IS AUTO-GENERATED + \\ + \\if exists('b:did_ftplugin') + \\ finish + \\endif + \\let b:did_ftplugin = 1 + \\ + \\setlocal commentstring=#%s + \\setlocal iskeyword+=- + \\ + \\" Use syntax keywords for completion + \\setlocal omnifunc=syntaxcomplete#Complete + \\ + \\let b:undo_ftplugin = 'setl cms< isk< ofu<' + \\ + ); + + _ = wf.add("ftplugin/ghostty.vim", buf.items); + } +} From eb46161b5e70b0cb110e30d786b68d5ce78783e7 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 22 Dec 2023 08:19:17 -0800 Subject: [PATCH 4/4] config: generate vim configs at comptime --- build.zig | 19 +++--- src/build/VimStep.zig | 143 ------------------------------------------ src/config.zig | 3 + src/config/vim.zig | 85 +++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 150 deletions(-) delete mode 100644 src/build/VimStep.zig create mode 100644 src/config/vim.zig diff --git a/build.zig b/build.zig index ce653675e..8856eb766 100644 --- a/build.zig +++ b/build.zig @@ -8,12 +8,12 @@ const apprt = @import("src/apprt.zig"); 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 WasmTarget = @import("src/os/wasm/target.zig").Target; const LibtoolStep = @import("src/build/LibtoolStep.zig"); const LipoStep = @import("src/build/LipoStep.zig"); const XCFrameworkStep = @import("src/build/XCFrameworkStep.zig"); const Version = @import("src/build/Version.zig"); -const VimStep = @import("src/build/VimStep.zig"); // Do a comptime Zig version requirement. The required Zig version is // somewhat arbitrary: it is meant to be a version that we feel works well, @@ -404,12 +404,17 @@ pub fn build(b: *std.Build) !void { } // Vim plugin - const vim_step = VimStep.create(b); - b.installDirectory(.{ - .source_dir = vim_step.getDirectory(), - .install_dir = .prefix, - .install_subdir = "share/vim/vimfiles", - }); + { + const wf = b.addWriteFiles(); + _ = wf.add("syntax/ghostty.vim", config_vim.syntax); + _ = wf.add("ftdetect/ghostty.vim", config_vim.ftdetect); + _ = wf.add("ftplugin/ghostty.vim", config_vim.ftplugin); + b.installDirectory(.{ + .source_dir = wf.getDirectory(), + .install_dir = .prefix, + .install_subdir = "share/vim/vimfiles", + }); + } // App (Linux) if (target.isLinux()) { diff --git a/src/build/VimStep.zig b/src/build/VimStep.zig deleted file mode 100644 index 7b5ef9154..000000000 --- a/src/build/VimStep.zig +++ /dev/null @@ -1,143 +0,0 @@ -//! A Zig build step that generates Vim plugin files for Ghostty's configuration -//! file. - -const VimStep = @This(); - -const std = @import("std"); -const Step = std.Build.Step; - -const Config = @import("../config/Config.zig"); - -step: *Step, - -// The build step that generates the file contents -generate_step: Step, - -pub fn create(b: *std.Build) *VimStep { - const self = b.allocator.create(VimStep) catch @panic("OOM"); - - const write_file = Step.WriteFile.create(b); - - self.* = .{ - .step = &write_file.step, - .generate_step = Step.init(.{ - .id = .custom, - .name = "generate Vim plugin files", - .owner = b, - .makeFn = make, - }), - }; - - write_file.step.dependOn(&self.generate_step); - - return self; -} - -pub fn getDirectory(self: *VimStep) std.Build.LazyPath { - const wf = @fieldParentPtr(Step.WriteFile, "step", self.step); - return wf.getDirectory(); -} - -fn make(step: *Step, prog_node: *std.Progress.Node) !void { - _ = prog_node; - const self = @fieldParentPtr(VimStep, "generate_step", step); - const wf = @fieldParentPtr(Step.WriteFile, "step", self.step); - const b = step.owner; - - // syntax/ghostty.vim - { - var buf = std.ArrayList(u8).init(b.allocator); - defer buf.deinit(); - - const writer = buf.writer(); - try writer.print( - \\" Vim syntax file - \\" Language: Ghostty config file - \\" Maintainer: Ghostty - \\" - \\" THIS FILE IS AUTO-GENERATED - \\ - \\if exists('b:current_syntax') - \\ finish - \\endif - \\ - \\let b:current_syntax = 'ghostty' - \\ - \\let s:cpo_save = &cpo - \\set cpo&vim - \\ - \\ - , .{}); - - const config_fields = @typeInfo(Config).Struct.fields; - var keywords = try std.ArrayList([]const u8).initCapacity( - b.allocator, - config_fields.len, - ); - defer keywords.deinit(); - - inline for (config_fields) |field| { - // Ignore fields which begin with _ - if (field.name[0] != '_') { - keywords.appendAssumeCapacity(field.name); - } - } - - try writer.print( - \\syn keyword ghosttyConfigKeyword - \\ \ {s} - \\ - \\syn match ghosttyConfigComment /#.*/ contains=@Spell - \\ - \\hi def link ghosttyConfigComment Comment - \\hi def link ghosttyConfigKeyword Keyword - \\ - \\let &cpo = s:cpo_save - \\unlet s:cpo_save - \\ - , .{ - try std.mem.join(b.allocator, "\n\t\\ ", keywords.items), - }); - - _ = wf.add("syntax/ghostty.vim", buf.items); - } - - // ftdetect/ghostty.vim - { - _ = wf.add( - "ftdetect/ghostty.vim", - "au BufRead,BufNewFile */.config/ghostty/config set ft=ghostty\n", - ); - } - - // ftplugin/ghostty.vim - { - var buf = std.ArrayList(u8).init(b.allocator); - defer buf.deinit(); - - const writer = buf.writer(); - try writer.writeAll( - \\" Vim filetype plugin file - \\" Language: Ghostty config file - \\" Maintainer: Ghostty - \\" - \\" THIS FILE IS AUTO-GENERATED - \\ - \\if exists('b:did_ftplugin') - \\ finish - \\endif - \\let b:did_ftplugin = 1 - \\ - \\setlocal commentstring=#%s - \\setlocal iskeyword+=- - \\ - \\" Use syntax keywords for completion - \\setlocal omnifunc=syntaxcomplete#Complete - \\ - \\let b:undo_ftplugin = 'setl cms< isk< ofu<' - \\ - ); - - _ = wf.add("ftplugin/ghostty.vim", buf.items); - } -} diff --git a/src/config.zig b/src/config.zig index 57c4bcd88..398f5fa92 100644 --- a/src/config.zig +++ b/src/config.zig @@ -21,4 +21,7 @@ pub const Wasm = if (!builtin.target.isWasm()) struct {} else @import("config/Wa test { @import("std").testing.refAllDecls(@This()); + + // Vim syntax file, not used at runtime but we want to keep it tested. + _ = @import("config/vim.zig"); } diff --git a/src/config/vim.zig b/src/config/vim.zig new file mode 100644 index 000000000..a57a59b72 --- /dev/null +++ b/src/config/vim.zig @@ -0,0 +1,85 @@ +const std = @import("std"); +const Config = @import("Config.zig"); + +/// This is the associated Vim file as named by the variable. +pub const syntax = comptimeGenSyntax(); +pub const ftdetect = "au BufRead,BufNewFile */.config/ghostty/config set ft=ghostty\n"; +pub const ftplugin = + \\" Vim filetype plugin file + \\" Language: Ghostty config file + \\" Maintainer: Ghostty + \\" + \\" THIS FILE IS AUTO-GENERATED + \\ + \\if exists('b:did_ftplugin') + \\ finish + \\endif + \\let b:did_ftplugin = 1 + \\ + \\setlocal commentstring=#%s + \\setlocal iskeyword+=- + \\ + \\" Use syntax keywords for completion + \\setlocal omnifunc=syntaxcomplete#Complete + \\ + \\let b:undo_ftplugin = 'setl cms< isk< ofu<' + \\ +; + +/// Generates the syntax file at comptime. +fn comptimeGenSyntax() []const u8 { + comptime { + var counting_writer = std.io.countingWriter(std.io.null_writer); + try writeSyntax(&counting_writer.writer()); + + var buf: [counting_writer.bytes_written]u8 = undefined; + var stream = std.io.fixedBufferStream(&buf); + try writeSyntax(stream.writer()); + return stream.getWritten(); + } +} + +/// Writes the syntax file to the given writer. +fn writeSyntax(writer: anytype) !void { + try writer.writeAll( + \\" Vim syntax file + \\" Language: Ghostty config file + \\" Maintainer: Ghostty + \\" + \\" THIS FILE IS AUTO-GENERATED + \\ + \\if exists('b:current_syntax') + \\ finish + \\endif + \\ + \\let b:current_syntax = 'ghostty' + \\ + \\let s:cpo_save = &cpo + \\set cpo&vim + \\ + \\syn keyword ghosttyConfigKeyword + ); + + const config_fields = @typeInfo(Config).Struct.fields; + inline for (config_fields) |field| { + if (field.name[0] == '_') continue; + try writer.print("\n\t\\ {s}", .{field.name}); + } + + try writer.writeAll( + \\ + \\ + \\syn match ghosttyConfigComment /#.*/ contains=@Spell + \\ + \\hi def link ghosttyConfigComment Comment + \\hi def link ghosttyConfigKeyword Keyword + \\ + \\let &cpo = s:cpo_save + \\unlet s:cpo_save + \\ + ); +} + +test { + _ = syntax; +}