diff --git a/build.zig b/build.zig index 4318997cb..8856eb766 100644 --- a/build.zig +++ b/build.zig @@ -8,6 +8,7 @@ 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"); @@ -402,6 +403,19 @@ pub fn build(b: *std.Build) !void { } } + // Vim plugin + { + 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()) { // https://developer.gnome.org/documentation/guidelines/maintainer/integrating.html 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; }; 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; +}