diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-04-04 19:22:04 +0300 |
|---|---|---|
| committer | Can Celik <ogulcancelik@gmail.com> | 2026-04-05 01:23:06 +0300 |
| commit | 41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch) | |
| tree | 3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/extra | |
| parent | 55c138263e190a1e79d4b997bfb9397306c0ec1f (diff) | |
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/extra')
| -rw-r--r-- | vendor/libghostty-vt/src/extra/bash.zig | 337 | ||||
| -rw-r--r-- | vendor/libghostty-vt/src/extra/fish.zig | 202 | ||||
| -rw-r--r-- | vendor/libghostty-vt/src/extra/sublime.zig | 50 | ||||
| -rw-r--r-- | vendor/libghostty-vt/src/extra/vim.zig | 121 | ||||
| -rw-r--r-- | vendor/libghostty-vt/src/extra/zsh.zig | 231 |
5 files changed, 941 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/extra/bash.zig b/vendor/libghostty-vt/src/extra/bash.zig new file mode 100644 index 00000000..279e038c --- /dev/null +++ b/vendor/libghostty-vt/src/extra/bash.zig @@ -0,0 +1,337 @@ +const std = @import("std"); + +const Config = @import("../config/Config.zig"); +const Action = @import("../cli.zig").ghostty.Action; + +/// A bash completions configuration that contains all the available commands +/// and options. +/// +/// Notes: bash completion support for --<key>=<value> depends on setting the completion +/// system to _not_ print a space following each successful completion (see -o nospace). +/// This results leading or tailing spaces being necessary to move onto the next match. +/// +/// bash completion will read = as it's own completiong word regardless of whether or not +/// it's part of an on going completion like --<key>=. Working around this requires looking +/// backward in the command line args to pretend the = is an empty string +/// see: https://www.gnu.org/software/gnuastro/manual/html_node/Bash-TAB-completion-tutorial.html +pub const completions = comptimeGenerateBashCompletions(); + +fn comptimeGenerateBashCompletions() []const u8 { + comptime { + @setEvalBranchQuota(50000); + var counter: std.Io.Writer.Discarding = .init(&.{}); + try writeBashCompletions(&counter.writer); + + var buf: [counter.count]u8 = undefined; + var writer: std.Io.Writer = .fixed(&buf); + try writeBashCompletions(&writer); + const final = buf; + return final[0..writer.end]; + } +} + +fn writeBashCompletions(writer: *std.Io.Writer) !void { + const pad1 = " "; + const pad2 = pad1 ++ pad1; + const pad3 = pad2 ++ pad1; + const pad4 = pad3 ++ pad1; + const pad5 = pad4 ++ pad1; + + try writer.writeAll( + \\_ghostty() { + \\ + \\ # compat: mapfile -t COMPREPLY < <( "$@" ) + \\ _compreply() { + \\ COMPREPLY=() + \\ while IFS='' read -r line; do COMPREPLY+=("$line"); done < <( "$@" ) + \\ } + \\ + \\ # -o nospace requires we add back a space when a completion is finished + \\ # and not part of a --key= completion + \\ _add_spaces() { + \\ for idx in "${!COMPREPLY[@]}"; do + \\ [ -n "${COMPREPLY[idx]}" ] && COMPREPLY[idx]="${COMPREPLY[idx]} "; + \\ done + \\ } + \\ + \\ _fonts() { + \\ local IFS=$'\n' + \\ COMPREPLY=() + \\ while read -r line; do COMPREPLY+=("$line"); done < <( compgen -P '"' -S '"' -W "$($ghostty +list-fonts | grep '^[A-Z]' )" -- "$cur") + \\ } + \\ + \\ _themes() { + \\ local IFS=$'\n' + \\ COMPREPLY=() + \\ while read -r line; do COMPREPLY+=("$line"); done < <( compgen -P '"' -S '"' -W "$($ghostty +list-themes | sed -E 's/^(.*) \(.*$/\1/')" -- "$cur") + \\ } + \\ + \\ _files() { + \\ _compreply compgen -o filenames -f -- "$cur" + \\ for i in "${!COMPREPLY[@]}"; do + \\ if [[ -d "${COMPREPLY[i]}" ]]; then + \\ COMPREPLY[i]="${COMPREPLY[i]}/"; + \\ fi + \\ if [[ -f "${COMPREPLY[i]}" ]]; then + \\ COMPREPLY[i]="${COMPREPLY[i]} "; + \\ fi + \\ done + \\ } + \\ + \\ _dirs() { + \\ _compreply compgen -o dirnames -d -- "$cur" + \\ for i in "${!COMPREPLY[@]}"; do + \\ if [[ -d "${COMPREPLY[i]}" ]]; then + \\ COMPREPLY[i]="${COMPREPLY[i]}/"; + \\ fi + \\ done + \\ if [[ "${#COMPREPLY[@]}" == 0 && -d "$cur" ]]; then + \\ COMPREPLY=( "$cur " ) + \\ fi + \\ } + \\ + \\ _handle_config() { + \\ local config="--help" + \\ config+=" --version" + \\ + ); + + for (@typeInfo(Config).@"struct".fields) |field| { + if (field.name[0] == '_') continue; + switch (field.type) { + bool, ?bool => try writer.writeAll(pad2 ++ "config+=\" '--" ++ field.name ++ " '\"\n"), + else => try writer.writeAll(pad2 ++ "config+=\" --" ++ field.name ++ "=\"\n"), + } + } + + try writer.writeAll( + \\ + \\ case "$prev" in + \\ + ); + + for (@typeInfo(Config).@"struct".fields) |field| { + if (field.name[0] == '_') continue; + try writer.writeAll(pad3 ++ "--" ++ field.name ++ ") "); + + if (std.mem.startsWith(u8, field.name, "font-family")) + try writer.writeAll("_fonts ;;") + else if (std.mem.eql(u8, "theme", field.name)) + try writer.writeAll("_themes ;;") + else if (std.mem.eql(u8, "working-directory", field.name)) + try writer.writeAll("_dirs ;;") + else if (field.type == Config.RepeatablePath) + try writer.writeAll("_files ;;") + else { + const compgenPrefix = "_compreply compgen -W \""; + const compgenSuffix = "\" -- \"$cur\"; _add_spaces ;;"; + switch (@typeInfo(field.type)) { + .bool => try writer.writeAll("return ;;"), + .@"enum" => |info| { + try writer.writeAll(compgenPrefix); + for (info.fields, 0..) |f, i| { + if (i > 0) try writer.writeAll(" "); + try writer.writeAll(f.name); + } + try writer.writeAll(compgenSuffix); + }, + .@"struct" => |info| { + if (!@hasDecl(field.type, "parseCLI") and info.layout == .@"packed") { + try writer.writeAll(compgenPrefix); + for (info.fields, 0..) |f, i| { + if (i > 0) try writer.writeAll(" "); + try writer.writeAll(f.name ++ " no-" ++ f.name); + } + try writer.writeAll(compgenSuffix); + } else { + try writer.writeAll("return ;;"); + } + }, + else => try writer.writeAll("return ;;"), + } + } + + try writer.writeAll("\n"); + } + + try writer.writeAll( + \\ *) _compreply compgen -W "$config" -- "$cur" ;; + \\ esac + \\ + \\ return 0 + \\ } + \\ + \\ _handle_actions() { + \\ + ); + + for (@typeInfo(Action).@"enum".fields) |field| { + const options = @field(Action, field.name).options(); + // assumes options will never be created with only <_name> members + if (@typeInfo(options).@"struct".fields.len == 0) continue; + + var buffer: [field.name.len]u8 = undefined; + const bashName: []u8 = buffer[0..field.name.len]; + @memcpy(bashName, field.name); + + std.mem.replaceScalar(u8, bashName, '-', '_'); + try writer.writeAll(pad2 ++ "local " ++ bashName ++ "=\""); + + { + var count = 0; + for (@typeInfo(options).@"struct".fields) |opt| { + if (opt.name[0] == '_') continue; + if (count > 0) try writer.writeAll(" "); + switch (opt.type) { + bool, ?bool => try writer.writeAll("'--" ++ opt.name ++ " '"), + else => try writer.writeAll("--" ++ opt.name ++ "="), + } + count += 1; + } + } + try writer.writeAll(" --help\"\n"); + } + + try writer.writeAll( + \\ + \\ case "${COMP_WORDS[1]}" in + \\ + ); + + for (@typeInfo(Action).@"enum".fields) |field| { + const options = @field(Action, field.name).options(); + if (@typeInfo(options).@"struct".fields.len == 0) continue; + + // bash doesn't allow variable names containing '-' so replace them + var buffer: [field.name.len]u8 = undefined; + const bashName: []u8 = buffer[0..field.name.len]; + _ = std.mem.replace(u8, field.name, "-", "_", bashName); + + try writer.writeAll(pad3 ++ "+" ++ field.name ++ ")\n"); + try writer.writeAll(pad4 ++ "case $prev in\n"); + for (@typeInfo(options).@"struct".fields) |opt| { + if (opt.name[0] == '_') continue; + + try writer.writeAll(pad5 ++ "--" ++ opt.name ++ ") "); + + const compgenPrefix = "_compreply compgen -W \""; + const compgenSuffix = "\" -- \"$cur\"; _add_spaces ;;"; + switch (@typeInfo(opt.type)) { + .bool => try writer.writeAll("return ;;"), + .@"enum" => |info| { + try writer.writeAll(compgenPrefix); + for (info.fields, 0..) |f, i| { + if (i > 0) try writer.writeAll(" "); + try writer.writeAll(f.name); + } + try writer.writeAll(compgenSuffix); + }, + .optional => |optional| { + switch (@typeInfo(optional.child)) { + .@"enum" => |info| { + try writer.writeAll(compgenPrefix); + for (info.fields, 0..) |f, i| { + if (i > 0) try writer.writeAll(" "); + try writer.writeAll(f.name); + } + try writer.writeAll(compgenSuffix); + }, + else => { + if (std.mem.eql(u8, "config-file", opt.name)) { + try writer.writeAll("return ;;"); + } else try writer.writeAll("return;;"); + }, + } + }, + else => { + if (std.mem.eql(u8, "config-file", opt.name)) { + try writer.writeAll("_files ;;"); + } else try writer.writeAll("return;;"); + }, + } + try writer.writeAll("\n"); + } + try writer.writeAll(pad5 ++ "*) _compreply compgen -W \"$" ++ bashName ++ "\" -- \"$cur\" ;;\n"); + try writer.writeAll( + \\ esac + \\ ;; + \\ + ); + } + + try writer.writeAll( + \\ *) _compreply compgen -W "--help" -- "$cur" ;; + \\ esac + \\ + \\ return 0 + \\ } + \\ + \\ # begin main logic + \\ local topLevel="-e" + \\ topLevel+=" --help" + \\ topLevel+=" --version" + \\ + ); + + for (@typeInfo(Action).@"enum".fields) |field| { + try writer.writeAll(pad1 ++ "topLevel+=\" +" ++ field.name ++ "\"\n"); + } + + try writer.writeAll( + \\ + \\ local cur=""; local prev=""; local prevWasEq=false; COMPREPLY=() + \\ local ghostty="$1" + \\ + \\ # script assumes default COMP_WORDBREAKS of roughly $' \t\n"\'><=;|&(:' + \\ # if = is missing this script will degrade to matching on keys only. + \\ # eg: --key= + \\ # this can be improved if needed see: https://github.com/ghostty-org/ghostty/discussions/2994 + \\ + \\ if [ "$2" = "=" ]; then cur="" + \\ else cur="$2" + \\ fi + \\ + \\ if [ "$3" = "=" ]; then prev="${COMP_WORDS[COMP_CWORD-2]}"; prevWasEq=true; + \\ else prev="${COMP_WORDS[COMP_CWORD-1]}" + \\ fi + \\ + \\ # current completion is double quoted add a space so the cursor progresses + \\ if [[ "$2" == \"*\" ]]; then + \\ COMPREPLY=( "$cur " ); + \\ return; + \\ fi + \\ + \\ case "$COMP_CWORD" in + \\ 1) + \\ case "${COMP_WORDS[1]}" in + \\ -e | --help | --version) return 0 ;; + \\ --*) _handle_config ;; + \\ *) _compreply compgen -W "${topLevel}" -- "$cur"; _add_spaces ;; + \\ esac + \\ ;; + \\ *) + \\ case "$prev" in + \\ -e | --help | --version) return 0 ;; + \\ *) + \\ if [[ "=" != "${COMP_WORDS[COMP_CWORD]}" && $prevWasEq != true ]]; then + \\ # must be completing with a space after the key eg: '--<key> ' + \\ # clear out prev so we don't run any of the key specific completions + \\ prev="" + \\ fi + \\ + \\ case "${COMP_WORDS[1]}" in + \\ --*) _handle_config ;; + \\ +*) _handle_actions ;; + \\ esac + \\ ;; + \\ esac + \\ ;; + \\ esac + \\ + \\ return 0 + \\} + \\ + \\complete -o nospace -o bashdefault -F _ghostty ghostty + \\ + ); +} diff --git a/vendor/libghostty-vt/src/extra/fish.zig b/vendor/libghostty-vt/src/extra/fish.zig new file mode 100644 index 00000000..73fa9a70 --- /dev/null +++ b/vendor/libghostty-vt/src/extra/fish.zig @@ -0,0 +1,202 @@ +//! Fish completions. +const std = @import("std"); + +const Config = @import("../config/Config.zig"); +const Action = @import("../cli.zig").ghostty.Action; +const help_strings = @import("help_strings"); + +/// A fish completions configuration that contains all the available commands +/// and options. +pub const completions = comptimeGenerateCompletions(); + +fn comptimeGenerateCompletions() []const u8 { + comptime { + @setEvalBranchQuota(50000); + var counter: std.Io.Writer.Discarding = .init(&.{}); + try writeCompletions(&counter.writer); + + var buf: [counter.count]u8 = undefined; + var writer: std.Io.Writer = .fixed(&buf); + try writeCompletions(&writer); + const final = buf; + return final[0..writer.end]; + } +} + +fn writeCompletions(writer: *std.Io.Writer) !void { + { + try writer.writeAll("set -l commands \""); + var count: usize = 0; + for (@typeInfo(Action).@"enum".fields) |field| { + if (count > 0) try writer.writeAll(" "); + try writer.writeAll("+"); + try writer.writeAll(field.name); + count += 1; + } + try writer.writeAll("\"\n"); + } + + try writer.writeAll("complete -c ghostty -f\n"); + + try writer.writeAll("complete -c ghostty -s e -l help -f\n"); + try writer.writeAll("complete -c ghostty -n \"not __fish_seen_subcommand_from $commands\" -l version -f\n"); + + for (@typeInfo(Config).@"struct".fields) |field| { + if (field.name[0] == '_') continue; + + try writer.writeAll("complete -c ghostty -n \"not __fish_seen_subcommand_from $commands\" -l "); + try writer.writeAll(field.name); + try writer.writeAll(if (field.type != bool) " -r" else " "); + if (std.mem.startsWith(u8, field.name, "font-family")) + try writer.writeAll(" -f -a \"(ghostty +list-fonts | grep '^[A-Z]')\"") + else if (std.mem.eql(u8, "theme", field.name)) + try writer.writeAll(" -f -a \"(ghostty +list-themes | sed -E 's/^(.*) \\(.*\\$/\\1/')\"") + else if (std.mem.eql(u8, "working-directory", field.name)) + try writer.writeAll(" -f -k -a \"(__fish_complete_directories)\"") + else { + try writer.writeAll(if (field.type != Config.RepeatablePath) " -f" else " -F"); + switch (@typeInfo(field.type)) { + .bool => {}, + .@"enum" => |info| { + try writer.writeAll(" -a \""); + for (info.fields, 0..) |f, i| { + if (i > 0) try writer.writeAll(" "); + try writer.writeAll(f.name); + } + try writer.writeAll("\""); + }, + .@"struct" => |info| { + if (!@hasDecl(field.type, "parseCLI") and info.layout == .@"packed") { + try writer.writeAll(" -a \""); + for (info.fields, 0..) |f, i| { + if (i > 0) try writer.writeAll(" "); + try writer.writeAll(f.name); + try writer.writeAll(" no-"); + try writer.writeAll(f.name); + } + try writer.writeAll("\""); + } + }, + else => {}, + } + } + + if (@hasDecl(help_strings.Config, field.name)) { + const help = @field(help_strings.Config, field.name); + const desc = getDescription(help); + try writer.writeAll(" -d \""); + try writer.writeAll(desc); + try writer.writeAll("\""); + } + + try writer.writeAll("\n"); + } + + { + try writer.writeAll("complete -c ghostty -n \"string match -q -- '+*' (commandline -pt)\" -f -a \""); + var count: usize = 0; + for (@typeInfo(Action).@"enum".fields) |field| { + if (count > 0) try writer.writeAll(" "); + try writer.writeAll("+"); + try writer.writeAll(field.name); + count += 1; + } + try writer.writeAll("\"\n"); + } + + for (@typeInfo(Action).@"enum".fields) |field| { + if (std.mem.eql(u8, "help", field.name)) continue; + if (std.mem.eql(u8, "version", field.name)) continue; + + const options = @field(Action, field.name).options(); + for (@typeInfo(options).@"struct".fields) |opt| { + if (opt.name[0] == '_') continue; + try writer.writeAll("complete -c ghostty -n \"__fish_seen_subcommand_from +" ++ field.name ++ "\" -l "); + try writer.writeAll(opt.name); + try writer.writeAll(if (opt.type != bool) " -r" else ""); + + // special case +validate_config --config-file + if (std.mem.eql(u8, "config-file", opt.name)) { + try writer.writeAll(" -F"); + } else try writer.writeAll(" -f"); + + switch (@typeInfo(opt.type)) { + .bool => {}, + .@"enum" => |info| { + try writer.writeAll(" -a \""); + for (info.fields, 0..) |f, i| { + if (i > 0) try writer.writeAll(" "); + try writer.writeAll(f.name); + } + try writer.writeAll("\""); + }, + .optional => |optional| { + switch (@typeInfo(optional.child)) { + .@"enum" => |info| { + try writer.writeAll(" -a \""); + for (info.fields, 0..) |f, i| { + if (i > 0) try writer.writeAll(" "); + try writer.writeAll(f.name); + } + try writer.writeAll("\""); + }, + else => {}, + } + }, + else => {}, + } + try writer.writeAll("\n"); + } + } +} + +fn getDescription(comptime help: []const u8) []const u8 { + var out: [help.len * 2]u8 = undefined; + var len: usize = 0; + var prev_was_space = false; + + for (help, 0..) |c, i| { + switch (c) { + '.' => { + out[len] = '.'; + len += 1; + + if (i + 1 >= help.len) break; + const next = help[i + 1]; + if (next == ' ' or next == '\n') break; + }, + '\n' => { + if (!prev_was_space and len > 0) { + out[len] = ' '; + len += 1; + prev_was_space = true; + } + }, + '"' => { + out[len] = '\\'; + out[len + 1] = '"'; + len += 2; + prev_was_space = false; + }, + else => { + out[len] = c; + len += 1; + prev_was_space = (c == ' '); + }, + } + } + + return out[0..len]; +} + +test "getDescription" { + const testing = std.testing; + + const input = "First sentence with \"quotes\"\nand newlines. Second sentence."; + const expected = "First sentence with \\\"quotes\\\" and newlines."; + + comptime { + const result = getDescription(input); + try testing.expectEqualStrings(expected, result); + } +} diff --git a/vendor/libghostty-vt/src/extra/sublime.zig b/vendor/libghostty-vt/src/extra/sublime.zig new file mode 100644 index 00000000..e0deb2fa --- /dev/null +++ b/vendor/libghostty-vt/src/extra/sublime.zig @@ -0,0 +1,50 @@ +const Config = @import("../config/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: '^\s*#.*$' + \\ 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; diff --git a/vendor/libghostty-vt/src/extra/vim.zig b/vendor/libghostty-vt/src/extra/vim.zig new file mode 100644 index 00000000..dbd72713 --- /dev/null +++ b/vendor/libghostty-vt/src/extra/vim.zig @@ -0,0 +1,121 @@ +const std = @import("std"); +const Config = @import("../config/Config.zig"); + +/// This is the associated Vim file as named by the variable. +pub const syntax = comptimeGenSyntax(); +pub const ftdetect = + \\" Vim filetype detect file + \\" Language: Ghostty config file + \\" Maintainer: Ghostty <https://github.com/ghostty-org/ghostty> + \\" + \\" THIS FILE IS AUTO-GENERATED + \\ + \\au BufRead,BufNewFile */ghostty/config,*/*.ghostty/config,*/ghostty/themes/*,*.ghostty setf ghostty + \\ +; +pub const ftplugin = + \\" Vim filetype plugin file + \\" Language: Ghostty config file + \\" Maintainer: Ghostty <https://github.com/ghostty-org/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 + \\ + \\" Ask ghostty to explain config keywords + \\setlocal keywordprg=ghostty\ +explain-config + \\ + \\let b:undo_ftplugin = 'setl cms< isk< ofu< kp<' + \\ + \\if !exists('current_compiler') + \\ compiler ghostty + \\ let b:undo_ftplugin .= " makeprg< errorformat<" + \\endif + \\ +; +pub const compiler = + \\" Vim compiler file + \\" Language: Ghostty config file + \\" Maintainer: Ghostty <https://github.com/ghostty-org/ghostty> + \\" + \\" THIS FILE IS AUTO-GENERATED + \\ + \\if exists("current_compiler") + \\ finish + \\endif + \\let current_compiler = "ghostty" + \\ + \\CompilerSet makeprg=ghostty\ +validate-config\ --config-file=%:S + \\CompilerSet errorformat=%f:%l:%m,%m + \\ +; + +/// Generates the syntax file at comptime. +fn comptimeGenSyntax() []const u8 { + comptime { + @setEvalBranchQuota(50000); + var counter: std.Io.Writer.Discarding = .init(&.{}); + try writeSyntax(&counter.writer); + + var buf: [counter.count]u8 = undefined; + var writer: std.Io.Writer = .fixed(&buf); + try writeSyntax(&writer); + const final = buf; + return final[0..writer.end]; + } +} + +/// Writes the syntax file to the given writer. +fn writeSyntax(writer: *std.Io.Writer) !void { + try writer.writeAll( + \\" Vim syntax file + \\" Language: Ghostty config file + \\" Maintainer: Ghostty <https://github.com/ghostty-org/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 iskeyword @,48-57,- + \\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 /^\s*#.*/ contains=@Spell + \\ + \\hi def link ghosttyConfigComment Comment + \\hi def link ghosttyConfigKeyword Keyword + \\ + \\let &cpo = s:cpo_save + \\unlet s:cpo_save + \\ + ); +} + +test { + _ = syntax; +} diff --git a/vendor/libghostty-vt/src/extra/zsh.zig b/vendor/libghostty-vt/src/extra/zsh.zig new file mode 100644 index 00000000..376db807 --- /dev/null +++ b/vendor/libghostty-vt/src/extra/zsh.zig @@ -0,0 +1,231 @@ +const std = @import("std"); + +const Config = @import("../config/Config.zig"); +const Action = @import("../cli.zig").ghostty.Action; + +/// A zsh completions configuration that contains all the available commands +/// and options. +pub const completions = comptimeGenerateZshCompletions(); + +const equals_required = "=-:::"; + +fn comptimeGenerateZshCompletions() []const u8 { + comptime { + @setEvalBranchQuota(50000); + var counter: std.Io.Writer.Discarding = .init(&.{}); + try writeZshCompletions(&counter.writer); + + var buf: [counter.count]u8 = undefined; + var writer: std.Io.Writer = .fixed(&buf); + try writeZshCompletions(&writer); + const final = buf; + return final[0..writer.end]; + } +} + +fn writeZshCompletions(writer: *std.Io.Writer) !void { + try writer.writeAll( + \\#compdef ghostty + \\ + \\_fonts () { + \\ local font_list=$(ghostty +list-fonts | grep -Z '^[A-Z]') + \\ local fonts=(${(f)font_list}) + \\ _describe -t fonts 'fonts' fonts + \\} + \\ + \\_themes() { + \\ local theme_list=$(ghostty +list-themes | sed -E 's/^(.*) \(.*$/\1/') + \\ local themes=(${(f)theme_list}) + \\ _describe -t themes 'themes' themes + \\} + \\ + ); + + try writer.writeAll("_config() {\n"); + try writer.writeAll(" _arguments \\\n"); + try writer.writeAll(" \"--help\" \\\n"); + try writer.writeAll(" \"--version\" \\\n"); + for (@typeInfo(Config).@"struct".fields) |field| { + if (field.name[0] == '_') continue; + try writer.writeAll(" \"--"); + try writer.writeAll(field.name); + + if (std.mem.startsWith(u8, field.name, "font-family")) { + try writer.writeAll(equals_required); + try writer.writeAll("_fonts"); + } else if (std.mem.eql(u8, "theme", field.name)) { + try writer.writeAll(equals_required); + try writer.writeAll("_themes"); + } else if (std.mem.eql(u8, "working-directory", field.name)) { + try writer.writeAll(equals_required); + try writer.writeAll("{_files -/}"); + } else if (field.type == Config.RepeatablePath) { + try writer.writeAll(equals_required); + try writer.writeAll("_files"); // todo check if this is needed + } else { + switch (@typeInfo(field.type)) { + .bool => {}, + .@"enum" => |info| { + try writer.writeAll(equals_required); + try writer.writeAll("("); + for (info.fields, 0..) |f, i| { + if (i > 0) try writer.writeAll(" "); + try writer.writeAll(f.name); + } + try writer.writeAll(")"); + }, + .@"struct" => |info| { + try writer.writeAll(equals_required); + if (!@hasDecl(field.type, "parseCLI") and info.layout == .@"packed") { + try writer.writeAll("("); + for (info.fields, 0..) |f, i| { + if (i > 0) try writer.writeAll(" "); + try writer.writeAll(f.name); + try writer.writeAll(" no-"); + try writer.writeAll(f.name); + } + try writer.writeAll(")"); + } else { + //resize-overlay-duration + //keybind + //window-padding-x ...-y + //link + //palette + //background + //foreground + //font-variation* + //font-feature + try writer.writeAll("( )"); + } + }, + else => { + try writer.writeAll(equals_required); + try writer.writeAll("( )"); + }, + } + } + + try writer.writeAll("\" \\\n"); + } + try writer.writeAll("\n}\n\n"); + + try writer.writeAll( + \\_ghostty() { + \\ typeset -A opt_args + \\ local context state line + \\ local opt=('-e' '--help' '--version') + \\ + \\ _arguments -C \ + \\ '1:actions:->actions' \ + \\ '*:: :->rest' \ + \\ + \\ if [[ "$line[1]" == "--help" || "$line[1]" == "--version" || "$line[1]" == "-e" ]]; then + \\ return + \\ fi + \\ + \\ if [[ "$line[1]" == -* ]]; then + \\ _config + \\ return + \\ fi + \\ + \\ case "$state" in + \\ (actions) + \\ local actions; actions=( + \\ + ); + + { + // how to get 'commands' + var count: usize = 0; + const padding = " "; + for (@typeInfo(Action).@"enum".fields) |field| { + try writer.writeAll(padding ++ "'+"); + try writer.writeAll(field.name); + try writer.writeAll("'\n"); + count += 1; + } + } + + try writer.writeAll( + \\ ) + \\ _describe '' opt + \\ _describe -t action 'action' actions + \\ ;; + \\ (rest) + \\ if [[ "$line[2]" == "--help" ]]; then + \\ return + \\ fi + \\ + \\ local help=('--help') + \\ _describe '' help + \\ + \\ case $line[1] in + \\ + ); + { + const padding = " "; + for (@typeInfo(Action).@"enum".fields) |field| { + const options = @field(Action, field.name).options(); + // assumes options will never be created with only <_name> members + if (@typeInfo(options).@"struct".fields.len == 0) continue; + + try writer.writeAll(padding ++ "(+" ++ field.name ++ ")\n"); + try writer.writeAll(padding ++ " _arguments \\\n"); + for (@typeInfo(options).@"struct".fields) |opt| { + if (opt.name[0] == '_') continue; + + try writer.writeAll(padding ++ " '--"); + try writer.writeAll(opt.name); + + switch (@typeInfo(opt.type)) { + .bool => {}, + .@"enum" => |info| { + try writer.writeAll(equals_required); + try writer.writeAll("("); + for (info.fields, 0..) |f, i| { + if (i > 0) try writer.writeAll(" "); + try writer.writeAll(f.name); + } + try writer.writeAll(")"); + }, + .optional => |optional| { + try writer.writeAll(equals_required); + switch (@typeInfo(optional.child)) { + .@"enum" => |info| { + try writer.writeAll("("); + for (info.fields, 0..) |f, i| { + if (i > 0) try writer.writeAll(" "); + try writer.writeAll(f.name); + } + try writer.writeAll(")"); + }, + else => { + if (std.mem.eql(u8, "config-file", opt.name)) { + try writer.writeAll("_files"); + } else try writer.writeAll("( )"); + }, + } + }, + else => { + try writer.writeAll(equals_required); + if (std.mem.eql(u8, "config-file", opt.name)) { + try writer.writeAll("_files"); + } else try writer.writeAll("( )"); + }, + } + + try writer.writeAll("' \\\n"); + } + try writer.writeAll(padding ++ ";;\n"); + } + } + try writer.writeAll( + \\ esac + \\ ;; + \\ esac + \\} + \\ + \\_ghostty "$@" + \\ + ); +} |
