From d276de37c8b7887bb52499d8f5adb5074b433cec Mon Sep 17 00:00:00 2001 From: Ray Andrew Date: Thu, 20 Nov 2025 00:40:44 -0600 Subject: [PATCH] change to ghostty --- home/ghostty.nix | 74 ------- home/ghostty/config/config | 48 +++++ home/ghostty/default.nix | 27 +++ home/gui.nix | 2 +- home/neovim/config/lua/compile-mode.lua | 272 +++++++++++++++--------- home/neovim/config/lua/find-file.lua | 31 ++- 6 files changed, 268 insertions(+), 186 deletions(-) delete mode 100644 home/ghostty.nix create mode 100644 home/ghostty/config/config create mode 100644 home/ghostty/default.nix diff --git a/home/ghostty.nix b/home/ghostty.nix deleted file mode 100644 index b21e8c6..0000000 --- a/home/ghostty.nix +++ /dev/null @@ -1,74 +0,0 @@ -{ - config, - pkgs, - inputs, - lib, - system-font, - ... -}: - -{ - options.custom.gui = with lib; { - ghostty = { - enable = mkEnableOption "Enable ghostty"; - }; - }; - - config = lib.mkIf config.custom.gui.ghostty.enable { - home.packages = lib.mkIf pkgs.stdenv.isLinux ( - with pkgs; - [ - inputs.ghostty.packages."${system}".default - ] - ); - xdg.configFile."ghostty/config".text = '' - gtk-single-instance = true - gtk-titlebar = false - window-decoration = server - quit-after-last-window-closed = true - # gtk-adwaita = false - font-family = ${system-font} - # font-family = Consolas - font-size = 11 - app-notifications = no-clipboard-copy - macos-option-as-alt = left - # theme = gruber-darker - # theme = xcodelighthc - # theme = zenburned - # font-family = Iosevka Nerd Font Mono - # font-size = 13 - - # background = #062329 - background = #072626 - # foreground = #d1b897 - foreground = #d3b58d - cursor-color = #ffffff - # cursor-text = #d1b897 - cursor-text = #d3b58d - # selection-background = #0000ff - # selection-foreground = #d1b897 - selection-background = #0000ff - selection-foreground = #d3b58d - # palette = 0=#062329 - palette = 0=#072626 - # palette = 1=#0b3335 - # palette = 2=#0000ff - palette = 3=#44b340 - palette = 4=#8cde94 - # palette = 5=#d1b897 - palette = 5=#d3b58d - palette = 6=#c1d1e3 - palette = 7=#ffffff - palette = 8=#626880 - palette = 9=#e67172 - palette = 10=#8ec772 - palette = 11=#d9ba73 - palette = 12=#7b9ef0 - palette = 13=#f2a4db - palette = 14=#5abfb5 - palette = 15=#b5bfe2 - - keybind = all:ctrl+shift+period=text:\x1b\x1f\x4c\x23\x1f - ''; - }; -} diff --git a/home/ghostty/config/config b/home/ghostty/config/config new file mode 100644 index 0000000..f091e3b --- /dev/null +++ b/home/ghostty/config/config @@ -0,0 +1,48 @@ +gtk-single-instance = true +gtk-titlebar = false +window-decoration = server +quit-after-last-window-closed = true +gtk-adwaita = false +# font-family = ${system-font} +font-family = Consolas +font-size = 14 +app-notifications = no-clipboard-copy +macos-option-as-alt = left +theme = nightfox +# theme = gruber-darker +# theme = xcodelighthc +# theme = zenburned +# font-family = Iosevka Nerd Font Mono +# font-size = 13 + +# # background = #062329 +# background = #072626 +# # foreground = #d1b897 +# foreground = #d3b58d +# cursor-color = #ffffff +# # cursor-text = #d1b897 +# cursor-text = #d3b58d +# # selection-background = #0000ff +# # selection-foreground = #d1b897 +# selection-background = #0000ff +# selection-foreground = #d3b58d +# # palette = 0=#062329 +# palette = 0=#072626 +# # palette = 1=#0b3335 +# # palette = 2=#0000ff +# palette = 3=#44b340 +# palette = 4=#8cde94 +# # palette = 5=#d1b897 +# palette = 5=#d3b58d +# palette = 6=#c1d1e3 +# palette = 7=#ffffff +# palette = 8=#626880 +# palette = 9=#e67172 +# palette = 10=#8ec772 +# palette = 11=#d9ba73 +# palette = 12=#7b9ef0 +# palette = 13=#f2a4db +# palette = 14=#5abfb5 +# palette = 15=#b5bfe2 + +keybind = all:ctrl+shift+period=text:\x1b\x1f\x4c\x23\x1f diff --git a/home/ghostty/default.nix b/home/ghostty/default.nix new file mode 100644 index 0000000..cba0724 --- /dev/null +++ b/home/ghostty/default.nix @@ -0,0 +1,27 @@ +{ + config, + pkgs, + inputs, + lib, + system-font, + dots, + ... +}: + +{ + options.custom.gui = with lib; { + ghostty = { + enable = mkEnableOption "Enable ghostty"; + }; + }; + + config = lib.mkIf config.custom.gui.ghostty.enable { + home.packages = lib.mkIf pkgs.stdenv.isLinux ( + with pkgs; + [ + inputs.ghostty.packages."${system}".default + ] + ); + xdg.configFile."ghostty".source = config.lib.file.mkOutOfStoreSymlink "${dots}/home/ghostty/config"; + }; +} diff --git a/home/gui.nix b/home/gui.nix index 2dbd14a..e089ff3 100644 --- a/home/gui.nix +++ b/home/gui.nix @@ -12,7 +12,7 @@ imports = [ ./i3 ./kitty.nix - ./ghostty.nix + ./ghostty ]; options.custom.gui = with lib; { diff --git a/home/neovim/config/lua/compile-mode.lua b/home/neovim/config/lua/compile-mode.lua index 39b6426..2ee1e95 100644 --- a/home/neovim/config/lua/compile-mode.lua +++ b/home/neovim/config/lua/compile-mode.lua @@ -11,11 +11,21 @@ local command_history = {} local HISTORY_FILE = vim.fn.stdpath 'data' .. '/compile_history' local MAX_HISTORY_SIZE = 200 +--- @class CompileInputKeymaps +--- @field next string? Cycle to next completion candidate +--- @field prev string? Cycle to previous completion candidate +--- @field confirm string? Confirm and run compile command +--- @field close (string|string[])? Close compile prompt +--- @field delete_component string? Delete path component +--- @field history_prev string? Previous command in history +--- @field history_next string? Next command in history + --- @class CompileConfig --- @field on_success? fun(qf_list: table) --- @field on_error? fun(qf_list: table, exit_code: number) --- @field on_exit? fun(qf_list: table, exit_code: number) ---- @field keymaps? table +--- @field buffer_keymaps? table Keymaps for compilation buffer +--- @field input_keymaps? CompileInputKeymaps Keymaps for input prompt --- @field split_mode? 'auto'|'horizontal'|'vertical-right'|'vertical-left' --- @field min_width_for_vertical? number --- @field prompt? string @@ -25,10 +35,20 @@ local config = { on_success = nil, on_error = nil, on_exit = nil, - keymaps = { + buffer_keymaps = { close = 'q', recompile = 'g', }, + input_keymaps = { + next = '', + prev = '', + complete = '', + confirm = '', + close = { '', '' }, + delete_component = '', + history_prev = '', + history_next = '', + }, split_mode = 'auto', min_width_for_vertical = 160, prompt = 'Compile command', @@ -527,17 +547,13 @@ function M.compile() local pos = #table.concat(parts, '') local max_display = 8 + -- Add opening bracket + table.insert(parts, ' [') + pos = pos + 2 + for i, match in ipairs(matches) do if i > max_display then break end - if i > 1 then - table.insert(parts, ' | ') - pos = pos + 3 - else - table.insert(parts, ' | ') - pos = pos + 3 - end - local filter_start, filter_end = nil, nil if last_word ~= '' then filter_start, filter_end = match:lower():find(last_word:lower(), 1, true) @@ -553,9 +569,22 @@ function M.compile() table.insert(parts, match) pos = pos + #match + + -- Add pipe separator between candidates (but not after the last one shown) + if i < math.min(#matches, max_display) then + table.insert(parts, ' | ') + pos = pos + 3 + end end - if #matches > max_display then table.insert(parts, ' | ...') end + -- Add ellipsis if there are more matches than max_display + if #matches > max_display then + table.insert(parts, ' | ...') + pos = pos + 6 + end + + -- Add closing bracket + table.insert(parts, ']') end local full_text = table.concat(parts, '') @@ -632,6 +661,7 @@ function M.compile() vim.schedule(function() vim.api.nvim_win_set_cursor(input_win, { 1, prompt_len + #current_input }) end) local last_input = current_input + local saved_input = nil vim.api.nvim_create_autocmd({ 'TextChanged', 'TextChangedI' }, { buffer = input_buf, @@ -655,8 +685,8 @@ function M.compile() end local input_part = line:sub(prompt_len + 1) - local pipe_pos = input_part:find ' | ' - if pipe_pos then input_part = input_part:sub(1, pipe_pos - 1) end + local bracket_pos = input_part:find ' %[' + if bracket_pos then input_part = input_part:sub(1, bracket_pos - 1) end if input_part ~= last_input then current_input = input_part @@ -687,99 +717,141 @@ function M.compile() local opts = { buffer = input_buf, nowait = true, silent = true } - vim.keymap.set('i', '', function() - if #matches == 0 then - matches = get_matches(current_input) - if #matches == 0 then return end - end - - match_index = (match_index % #matches) + 1 - local words = vim.split(current_input, '%s+') - words[#words] = matches[match_index] - current_input = table.concat(words, ' ') - last_input = current_input - vim.schedule(update_display) - end, opts) - - vim.keymap.set('i', '', function() - if #matches == 0 then - matches = get_matches(current_input) - if #matches == 0 then return end - end - - match_index = match_index - 1 - if match_index < 1 then match_index = #matches end - local words = vim.split(current_input, '%s+') - words[#words] = matches[match_index] - current_input = table.concat(words, ' ') - last_input = current_input - vim.schedule(update_display) - end, opts) - - vim.keymap.set('i', '', function() - if #command_history > 0 then - if history_index == 0 then - current_input = get_input() - last_input = current_input + -- Cycle to next completion candidate + if config.input_keymaps.next then + vim.keymap.set('i', config.input_keymaps.next, function() + if #matches == 0 then + matches = get_matches(current_input) + if #matches == 0 then return end end - if history_index < #command_history then - history_index = history_index + 1 - current_input = command_history[#command_history - history_index + 1] + + match_index = (match_index % #matches) + 1 + local words = vim.split(current_input, '%s+') + words[#words] = matches[match_index] + current_input = table.concat(words, ' ') + last_input = current_input + vim.schedule(update_display) + end, opts) + end + + -- Cycle to previous completion candidate + if config.input_keymaps.prev then + vim.keymap.set('i', config.input_keymaps.prev, function() + if #matches == 0 then + matches = get_matches(current_input) + if #matches == 0 then return end + end + + match_index = match_index - 1 + if match_index < 1 then match_index = #matches end + local words = vim.split(current_input, '%s+') + words[#words] = matches[match_index] + current_input = table.concat(words, ' ') + last_input = current_input + vim.schedule(update_display) + end, opts) + end + + -- Complete to selected candidate + if config.input_keymaps.complete then + vim.keymap.set('i', config.input_keymaps.complete, function() + if #matches == 0 then + matches = get_matches(current_input) + if #matches == 0 then return '' end + end + + local match = match_index > 0 and matches[match_index] or matches[1] + local words = vim.split(current_input, '%s+') + words[#words] = match + current_input = table.concat(words, ' ') + last_input = current_input + match_index = 0 + matches = {} + vim.schedule(update_display) + return '' + end, vim.tbl_extend('force', opts, { expr = true })) + end + + -- Previous command in history + if config.input_keymaps.history_prev then + vim.keymap.set('i', config.input_keymaps.history_prev, function() + if #command_history > 0 then + if history_index == 0 then + saved_input = get_input() + end + if history_index < #command_history then + history_index = history_index + 1 + current_input = command_history[#command_history - history_index + 1] + last_input = current_input + vim.schedule(update_display) + end + end + return '' + end, vim.tbl_extend('force', opts, { expr = true })) + end + + -- Next command in history + if config.input_keymaps.history_next then + vim.keymap.set('i', config.input_keymaps.history_next, function() + if history_index > 0 then + history_index = history_index - 1 + if history_index == 0 then + current_input = saved_input or get_input() + saved_input = nil + else + current_input = command_history[#command_history - history_index + 1] + end last_input = current_input vim.schedule(update_display) end - end - return '' - end, vim.tbl_extend('force', opts, { expr = true })) + return '' + end, vim.tbl_extend('force', opts, { expr = true })) + end - vim.keymap.set('i', '', function() - if history_index > 0 then - history_index = history_index - 1 - if history_index == 0 then - current_input = get_input() - else - current_input = command_history[#command_history - history_index + 1] + -- Confirm and run compile command + if config.input_keymaps.confirm then + vim.keymap.set('i', config.input_keymaps.confirm, function() + if current_input and current_input ~= '' then + append_to_history(current_input) + vim.schedule(function() + close() + run_compile(current_input) + end) end + return '' + end, vim.tbl_extend('force', opts, { expr = true })) + end + + -- Close compile prompt + ---@type string[] + local close_keys = type(config.input_keymaps.close) == 'table' and config.input_keymaps.close --[[@as string[] ]] or { config.input_keymaps.close } + for _, key in ipairs(close_keys) do + if key then vim.keymap.set({ 'i', 'n' }, key, function() vim.schedule(close) end, opts) end + end + + -- Delete path component + if config.input_keymaps.delete_component then + vim.keymap.set('i', config.input_keymaps.delete_component, function() + local new_pos = 0 + local found_non_sep = false + for i = #current_input, 1, -1 do + local char = current_input:sub(i, i) + local is_sep = char:match '[/%._%- ]' + + if not found_non_sep and not is_sep then + found_non_sep = true + elseif found_non_sep and is_sep then + new_pos = i + break + end + end + + current_input = current_input:sub(1, new_pos) last_input = current_input vim.schedule(update_display) - end - return '' - end, vim.tbl_extend('force', opts, { expr = true })) - - vim.keymap.set('i', '', function() - if current_input and current_input ~= '' then - append_to_history(current_input) - vim.schedule(function() - close() - run_compile(current_input) - end) - end - return '' - end, vim.tbl_extend('force', opts, { expr = true })) - - vim.keymap.set({ 'i', 'n' }, '', function() vim.schedule(close) end, opts) - vim.keymap.set({ 'i', 'n' }, '', function() vim.schedule(close) end, opts) - - vim.keymap.set('i', '', function() - local new_pos = 0 - local found_non_sep = false - for i = #current_input, 1, -1 do - local char = current_input:sub(i, i) - local is_sep = char:match '[/%._%- ]' - - if not found_non_sep and not is_sep then - found_non_sep = true - elseif found_non_sep and is_sep then - new_pos = i - break - end - end - - current_input = current_input:sub(1, new_pos) - last_input = current_input - vim.schedule(update_display) - return '' - end, vim.tbl_extend('force', opts, { expr = true })) + return '' + end, vim.tbl_extend('force', opts, { expr = true })) + end vim.cmd 'startinsert!' end @@ -811,8 +883,8 @@ function M.setup(opts) vim.api.nvim_create_autocmd('FileType', { pattern = 'compilation', callback = function() - if config.keymaps.close then vim.keymap.set('n', config.keymaps.close, 'close', { buffer = true, desc = 'Close compilation buffer' }) end - if config.keymaps.recompile then vim.keymap.set('n', config.keymaps.recompile, M.recompile, { buffer = true, desc = 'Recompile' }) end + if config.buffer_keymaps.close then vim.keymap.set('n', config.buffer_keymaps.close, 'close', { buffer = true, desc = 'Close compilation buffer' }) end + if config.buffer_keymaps.recompile then vim.keymap.set('n', config.buffer_keymaps.recompile, M.recompile, { buffer = true, desc = 'Recompile' }) end local function jump_to_error() local bufnr = vim.api.nvim_get_current_buf() diff --git a/home/neovim/config/lua/find-file.lua b/home/neovim/config/lua/find-file.lua index 4c5419f..c4bb0ba 100644 --- a/home/neovim/config/lua/find-file.lua +++ b/home/neovim/config/lua/find-file.lua @@ -199,17 +199,13 @@ function M.open_dir(start_path) if #matches > 0 and show_matches then local pos = #table.concat(parts, '') + -- Add opening bracket + table.insert(parts, ' [') + pos = pos + 2 + for i, match in ipairs(matches) do if i > config.max_matches then break end - if i > 1 then - table.insert(parts, ' | ') - pos = pos + 3 - else - table.insert(parts, ' | ') - pos = pos + 3 - end - local sep = match.type == 'directory' and '/' or '' local item = match.name .. sep @@ -229,9 +225,22 @@ function M.open_dir(start_path) table.insert(parts, item) pos = pos + #item + + -- Add pipe separator between candidates (but not after the last one shown) + if i < math.min(#matches, config.max_matches) then + table.insert(parts, ' | ') + pos = pos + 3 + end end - if #matches > config.max_matches then table.insert(parts, ' | ...') end + -- Add ellipsis if there are more matches than max_matches + if #matches > config.max_matches then + table.insert(parts, ' | ...') + pos = pos + 6 + end + + -- Add closing bracket + table.insert(parts, ']') end local full_text = table.concat(parts, '') @@ -332,8 +341,8 @@ function M.open_dir(start_path) if not line:match '^Find file: ' then return end local path_part = line:sub(12) - local pipe_pos = path_part:find ' | ' - if pipe_pos then path_part = path_part:sub(1, pipe_pos - 1) end + local bracket_pos = path_part:find ' %[' + if bracket_pos then path_part = path_part:sub(1, bracket_pos - 1) end if path_part ~= last_input then current_input = path_part