From eb46161b5e70b0cb110e30d786b68d5ce78783e7 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 22 Dec 2023 08:19:17 -0800 Subject: [PATCH] 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; +}