feat(config): add ghostty terminal and refactor neovim configuration

- Add ghostty terminal configuration with custom themes and settings
- Add multiple color themes (ayu-dark, catppuccin variants, moonfly)
- Configure ghostty appearance: font, opacity, keybindings
- Refactor nvim basic setup to use modern vim.opt API
- Modernize LSP configuration with LspAttach autocmd
- Update nvim-tree configuration for latest API
- Simplify codecompanion plugin setup
- Pin nvim-treesitter to main branch
- Improve sway-dbus script with XDG runtime checks
This commit is contained in:
jay 2026-05-12 11:14:13 +08:00
parent 36a51d8127
commit 45e1e6f235
13 changed files with 353 additions and 201 deletions

View File

@ -0,0 +1,63 @@
# This is the configuration file for Ghostty.
#
# This template file has been automatically created at the following
# path since Ghostty couldn't find any existing config files on your system:
#
# /home/jay/.config/ghostty/config
#
# The template does not set any default options, since Ghostty ships
# with sensible defaults for all options. Users should only need to set
# options that they want to change from the default.
#
# Run `ghostty +show-config --default --docs` to view a list of
# all available config options and their default values.
#
# Additionally, each config option is also explained in detail
# on Ghostty's website, at https://ghostty.org/docs/config.
#
# Ghostty can reload the configuration while running by using the menu
# options or the bound key (default: Command + Shift + comma on macOS and
# Control + Shift + comma on other platforms). Not all config options can be
# reloaded while running; some only apply to new windows and others may require
# a full restart to take effect.
# Config syntax crash course
# ==========================
# # The config file consists of simple key-value pairs,
# # separated by equals signs.
font-family = "FiraMono Nerd Font Mono"
font-size = 10
#window-padding-x = 2
#window-padding-y = 2
#
# # Spacing around the equals sign does not matter.
# # All of these are identical:
# key=value
# key= value
# key =value
# key = value
#
# # Any line beginning with a # is a comment. It's not possible to put
# # a comment after a config option, since it would be interpreted as a
# # part of the value. For example, this will have a value of "#123abc":
# background = #123abc
#
# # Empty values are used to reset config keys to default.
# key =
#
# # Some config options have unique syntaxes for their value,
# # which is explained in the docs for that config option.
# # Just for example:
# resize-overlay-duration = 4s 200ms
theme = "moonfly-default"
background-opacity = 0.9
confirm-close-surface = false
app-notifications = no-clipboard-copy,config-reload
keybind = ctrl+,=unbind

View File

@ -0,0 +1,22 @@
background = #0b0e14
foreground = #bfbdb6
selection-background = #1b3a5b
selection-foreground = #bfbdb6
cursor-color = #bfbdb6
cursor-text = #0b0e14
palette = 0=#1e232b
palette = 1=#ea6c73
palette = 2=#7fd962
palette = 3=#f9af4f
palette = 4=#53bdfa
palette = 5=#cda1fa
palette = 6=#90e1c6
palette = 7=#c7c7c7
palette = 8=#686868
palette = 9=#f07178
palette = 10=#aad94c
palette = 11=#ffb454
palette = 12=#59c2ff
palette = 13=#d2a6ff
palette = 14=#95e6cb
palette = 15=#ffffff

View File

@ -0,0 +1,23 @@
palette = 0=#51576d
palette = 1=#e78284
palette = 2=#a6d189
palette = 3=#e5c890
palette = 4=#8caaee
palette = 5=#f4b8e4
palette = 6=#81c8be
palette = 7=#a5adce
palette = 8=#626880
palette = 9=#e78284
palette = 10=#a6d189
palette = 11=#e5c890
palette = 12=#8caaee
palette = 13=#f4b8e4
palette = 14=#81c8be
palette = 15=#b5bfe2
background = 303446
foreground = c6d0f5
cursor-color = f2d5cf
cursor-text = 232634
selection-background = 44495d
selection-foreground = c6d0f5
split-divider-color = 414559

View File

@ -0,0 +1,23 @@
palette = 0=#5c5f77
palette = 1=#d20f39
palette = 2=#40a02b
palette = 3=#df8e1d
palette = 4=#1e66f5
palette = 5=#ea76cb
palette = 6=#179299
palette = 7=#acb0be
palette = 8=#6c6f85
palette = 9=#d20f39
palette = 10=#40a02b
palette = 11=#df8e1d
palette = 12=#1e66f5
palette = 13=#ea76cb
palette = 14=#179299
palette = 15=#bcc0cc
background = eff1f5
foreground = 4c4f69
cursor-color = dc8a78
cursor-text = eff1f5
selection-background = d8dae1
selection-foreground = 4c4f69
split-divider-color = ccd0da

View File

@ -0,0 +1,23 @@
palette = 0=#494d64
palette = 1=#ed8796
palette = 2=#a6da95
palette = 3=#eed49f
palette = 4=#8aadf4
palette = 5=#f5bde6
palette = 6=#8bd5ca
palette = 7=#a5adcb
palette = 8=#5b6078
palette = 9=#ed8796
palette = 10=#a6da95
palette = 11=#eed49f
palette = 12=#8aadf4
palette = 13=#f5bde6
palette = 14=#8bd5ca
palette = 15=#b8c0e0
background = 24273a
foreground = cad3f5
cursor-color = f4dbd6
cursor-text = 181926
selection-background = 3a3e53
selection-foreground = cad3f5
split-divider-color = 363a4f

View File

@ -0,0 +1,23 @@
palette = 0=#45475a
palette = 1=#f38ba8
palette = 2=#a6e3a1
palette = 3=#f9e2af
palette = 4=#89b4fa
palette = 5=#f5c2e7
palette = 6=#94e2d5
palette = 7=#a6adc8
palette = 8=#585b70
palette = 9=#f38ba8
palette = 10=#a6e3a1
palette = 11=#f9e2af
palette = 12=#89b4fa
palette = 13=#f5c2e7
palette = 14=#94e2d5
palette = 15=#bac2de
background = 1e1e2e
foreground = cdd6f4
cursor-color = f5e0dc
cursor-text = 11111b
selection-background = 353749
selection-foreground = cdd6f4
split-divider-color = 313244

View File

@ -0,0 +1,22 @@
background = #080808
foreground = #bdbdbd
selection-background = #b2ceee
selection-foreground = #080808
cursor-color = #9e9e9e
cursor-text = #080808
palette = 0=#323437
palette = 1=#ff5454
palette = 2=#8cc85f
palette = 3=#e3c78a
palette = 4=#80a0ff
palette = 5=#cf87e8
palette = 6=#79dac8
palette = 7=#c6c6c6
palette = 8=#949494
palette = 9=#ff5189
palette = 10=#36c692
palette = 11=#c6c684
palette = 12=#74b2ff
palette = 13=#ae81ff
palette = 14=#85dc85
palette = 15=#e4e4e4

View File

@ -1,51 +1,40 @@
-- HELPERS ----------------------------------------------------
local cmd = vim.cmd -- to execute Vim commands e.g. cmd('pwd')
local fn = vim.fn -- to call Vim functions e.g. fn.bufnr()
local g = vim.g -- a table to access global variables
local scopes = {o = vim.o, b = vim.bo, w = vim.wo}
local opt = vim.opt
-- SYNTAX & FILETYPE ------------------------------------------
vim.cmd "syntax on"
vim.cmd "filetype plugin indent on"
cmd "syntax on"
-- 相對行號顯示
-- cmd "set relativenumber"
-- 絕對行號顯示
-- cmd "set number"
-- 混合模式,同時顯示相對行號和絕對行號
cmd "set number relativenumber"
cmd "set tabstop=2"
cmd "set shiftwidth=2"
cmd "set expandtab"
cmd "set nofoldenable"
-- BASIC SETTINGS ---------------------------------------------
opt.number = true -- 顯示行號
opt.relativenumber = true -- 顯示相對行號
opt.tabstop = 2 -- Tab 寬度
opt.shiftwidth = 2 -- 縮排寬度
opt.expandtab = true -- 將 Tab 轉為空格
opt.foldenable = false -- 預設不折疊
-- always show status
cmd "set laststatus=2"
opt.laststatus = 2 -- 始終顯示狀態列
opt.ruler = true -- 顯示游標位置
opt.cursorline = true -- 高亮當前行
opt.cursorcolumn = true -- 高亮當前列
opt.hlsearch = true -- 高亮搜尋結果
opt.wrap = false -- 不自動換行
-- show cursor position
cmd "set ruler"
cmd "set cursorline"
cmd "set cursorcolumn"
cmd "set hlsearch"
opt.backspace = { "indent", "eol", "start" }
opt.encoding = "utf-8"
opt.completeopt = { "menu", "menuone", "noselect" }
opt.swapfile = false -- 不產生 swap 檔案
opt.mouse = "" -- 禁用滑鼠
-- no wrap line
cmd "set nowrap"
opt.background = "dark"
-- enable backspace
cmd "set backspace=indent,eol,start"
cmd "set encoding=utf-8"
cmd "set completeopt=menu,menuone,noselect"
cmd "set noswapfile"
cmd "set mouse="
cmd "set background=dark"
cmd "filetype indent on"
cmd "filetype on"
cmd "filetype plugin on"
-- 自動命令 (Auto-commands) -----------------------------------
-- 處理配色方案與背景透明度
vim.api.nvim_create_autocmd("ColorScheme", {
pattern = "*",
callback = function()
cmd([[
vim.cmd([[
highlight clear CursorLine
highlight Normal ctermbg=none
highlight LineNr ctermbg=none
@ -58,17 +47,16 @@ vim.api.nvim_create_autocmd("ColorScheme", {
end,
})
-- chezmoi 自動套用
vim.api.nvim_create_autocmd("BufWritePost", {
pattern = "~/.local/share/chezmoi/*",
pattern = vim.fn.expand("~/.local/share/chezmoi/*"),
command = [[ ! chezmoi apply --source-path % ]],
})
vim.diagnostic.get(0, { severity = {
vim.diagnostic.severity.ERROR,
vim.diagnostic.severity.WARN,
} })
vim.diagnostic.config({virtual_text = false, signs = true})
-- 診斷設定
vim.diagnostic.config({ virtual_text = false, signs = true })
-- 特定語言設定
vim.api.nvim_create_autocmd("FileType", {
pattern = "rust",
callback = function()

View File

@ -30,54 +30,52 @@ return {
},
},
},
"ravitemer/mcphub.nvim"
},
config = function ()
local codecompanion = require("codecompanion")
codecompanion.setup({
ignore_warnings = true,
display = {
action_palette = {
width = 95,
height = 10,
prompt = "Prompt ",
provider = "default",
opts = {
show_default_actions = true,
show_default_prompt_library = true,
title = "CodeCompanion actions",
},
},
},
memory = {
codecompanion.setup({
ignore_warnings = true,
display = {
action_palette = {
width = 95,
height = 10,
prompt = "Prompt ",
provider = "default",
opts = {
chat = { enabled = true, },
show_default_actions = true,
show_default_prompt_library = true,
title = "CodeCompanion actions",
},
},
adapters = {
http = {
copilot = function()
return require('codecompanion.adapters').extend('copilot', {
schema = {
model = {
-- default = 'claude-sonnet-4.5',
default = 'claude-haiku-4.5',
},
},
})
end,
}
},
memory = {
opts = {
chat = { enabled = true, },
},
extensions = {
mcphub = {
callback = "mcphub.extensions.codecompanion",
opts = {
make_vars = true,
make_slash_commands = true,
show_result_in_chat = true
}
}
},
strategies = {
chat = {
adapter = "copilot",
},
inline = {
adapter = "copilot",
},
},
adapters = {
http = {
copilot = function()
return require('codecompanion.adapters').extend('copilot', {
schema = {
model = {
default = 'claude-sonnet-4.5',
-- default = 'claude-haiku-4.5',
},
},
})
end,
}
})
},
})
end,
}

View File

@ -75,7 +75,10 @@ return {
require('plugins.bufferline'),
--require('plugins.indent_blankline'),
"nvim-treesitter/nvim-treesitter",
{
"nvim-treesitter/nvim-treesitter",
branch = "main",
},
{
"bluz71/vim-nightfly-colors",

View File

@ -1,100 +1,60 @@
return {
"neovim/nvim-lspconfig",
dependencies = {
{
"hrsh7th/cmp-nvim-lsp",
},
"hrsh7th/cmp-nvim-lsp",
},
config = function ()
config = function()
local capabilities = require('cmp_nvim_lsp').default_capabilities()
local on_attach = function (client, bufnr)
local lspSig = require('lsp_signature')
local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end
lspSig.on_attach()
-- 統一處理 LspAttach (當 LSP 連接到緩衝區時觸發)
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('UserLspConfig', {}),
callback = function(ev)
local bufnr = ev.buf
local client = vim.lsp.get_client_by_id(ev.data.client_id)
-- enable completion triggered by <c-x><c-o>
buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
-- 啟動 lsp_signature
require('lsp_signature').on_attach({}, bufnr)
-- mappings
local opts = { noremap=true, silent=true }
-- 啟用 omnifunc
vim.bo[bufnr].omnifunc = 'v:lua.vim.lsp.omnifunc'
-- See `:help vim.lsp.*` for documentation on any of the below functions
-- buf_set_keymap('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)
buf_set_keymap('n', '<leader>gd', '<cmd>lua vim.lsp.buf.definition()<CR>', opts)
buf_set_keymap('n', '<leader>gt', '<cmd>tab split<CR><cmd>lua vim.lsp.buf.definition()<CR>', opts)
buf_set_keymap('n', '<leader>gv', '<cmd>vsplit<CR><cmd>lua vim.lsp.buf.definition()<CR>', opts)
buf_set_keymap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)
buf_set_keymap('n', '<leader>gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
-- buf_set_keymap('n', '<space>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
-- buf_set_keymap('n', '<space>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
-- buf_set_keymap('n', '<space>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
buf_set_keymap('n', '<leader>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
buf_set_keymap('n', '<leader>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
buf_set_keymap('n', '<leader>ca', '<cmd>lua vim.lsp.buf.code_action()<CR>', opts)
buf_set_keymap('n', '<leader>gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
buf_set_keymap('n', '<leader>ge', '<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>', opts)
buf_set_keymap('n', '<leader>do', '<cmd>lua vim.lsp.diagnostic.open_float()<CR>', opts)
buf_set_keymap('n', '<leader>d[', '<cmd>lua vim.lsp.diagnostic.goto_prev()<CR>', opts)
buf_set_keymap('n', '<leader>d]', '<cmd>lua vim.lsp.diagnostic.goto_next()<CR>', opts)
-- buf_set_keymap('n', '<space>q', '<cmd>lua vim.lsp.diagnostic.set_loclist()<CR>', opts)
buf_set_keymap('n', '<leader>gf', '<cmd>lua vim.lsp.buf.format()<CR>', opts)
end
-- 按鍵對映優化
local opts = { buffer = bufnr, noremap = true, silent = true }
local map = vim.keymap.set
vim.lsp.config('gopls', {
capabilities = capabilities,
on_attach = on_attach,
})
vim.lsp.config('ts_ls', {
capabilities = capabilities,
on_attach = on_attach,
})
vim.lsp.config('rust_analyzer', {
capabilities = capabilities,
on_attach = on_attach,
})
vim.lsp.config('bashls', {
capabilities = capabilities,
on_attach = on_attach,
})
vim.lsp.config('svelte', {
capabilities = capabilities,
on_attach = on_attach,
})
vim.lsp.config('pylsp', {
capabilities = capabilities,
on_attach = on_attach,
})
vim.lsp.config('zls', {
capabilities = capabilities,
on_attach = on_attach,
})
vim.lsp.config('lua_ls', {
capabilities = capabilities,
on_attach = on_attach,
})
vim.lsp.config('clangd', {
capabilities = capabilities,
on_attach = on_attach,
})
vim.lsp.config('pyright', {
capabilities = capabilities,
on_attach = on_attach,
})
map('n', '<leader>gd', vim.lsp.buf.definition, opts)
map('n', '<leader>gt', '<cmd>tab split<CR><cmd>lua vim.lsp.buf.definition()<CR>', opts)
map('n', '<leader>gv', '<cmd>vsplit<CR><cmd>lua vim.lsp.buf.definition()<CR>', opts)
map('n', 'K', vim.lsp.buf.hover, opts)
map('n', '<leader>gi', vim.lsp.buf.implementation, opts)
map('n', '<C-k>', vim.lsp.buf.signature_help, opts)
map('n', '<leader>D', vim.lsp.buf.type_definition, opts)
map('n', '<leader>rn', vim.lsp.buf.rename, opts)
map('n', '<leader>ca', vim.lsp.buf.code_action, opts)
map('n', '<leader>gr', vim.lsp.buf.references, opts)
map('n', '<leader>ge', vim.diagnostic.open_float, opts) -- 使用現代 API
map('n', '<leader>do', vim.diagnostic.open_float, opts)
map('n', '<leader>d[', vim.diagnostic.goto_prev, opts)
map('n', '<leader>d]', vim.diagnostic.goto_next, opts)
map('n', '<leader>gf', function() vim.lsp.buf.format { async = true } end, opts)
end,
})
vim.lsp.enable('gopls')
vim.lsp.enable('ts_ls')
vim.lsp.enable('rust_analyzer')
vim.lsp.enable('bashls')
vim.lsp.enable('svelte')
vim.lsp.enable('pylsp')
vim.lsp.enable('zls')
vim.lsp.enable('lua_ls')
vim.lsp.enable('clangd')
vim.lsp.enable('pyright')
-- 伺服器列表
local servers = {
'gopls', 'ts_ls', 'rust_analyzer', 'bashls', 'svelte',
'pylsp', 'zls', 'lua_ls', 'clangd', 'pyright'
}
-- 批量配置伺服器能力
for _, lsp in ipairs(servers) do
vim.lsp.config(lsp, {
capabilities = capabilities,
})
end
-- 批量啟用伺服器
vim.lsp.enable(servers)
end
}

View File

@ -1,18 +1,16 @@
return {
"kyazdani42/nvim-tree.lua",
"nvim-tree/nvim-tree.lua",
keys = {
{"<leader>me", ':NvimTreeToggle<CR>', desc = 'open / close nvim tree', mode = 'n'},
{"<F3>", ':NvimTreeToggle<CR>', desc = 'open / close nvim tree', mode = 'n'}
{"<leader>me", '<cmd>NvimTreeToggle<CR>', desc = 'open / close nvim tree', mode = 'n'},
{"<F3>", '<cmd>NvimTreeToggle<CR>', desc = 'open / close nvim tree', mode = 'n'}
},
opts = {
auto_reload_on_write = true,
disable_netrw = false,
hijack_cursor = false,
hijack_netrw = true,
hijack_unnamed_buffer_when_opening = false,
open_on_tab = false,
sort_by = "name",
update_cwd = false,
sort = {
sorter = "name",
},
view = {
width = 40,
side = "left",
@ -27,6 +25,7 @@ return {
icons = {
corner = "",
edge = "",
item = "",
none = " ",
},
},
@ -37,13 +36,9 @@ return {
},
update_focused_file = {
enable = false,
update_cwd = false,
update_root = false,
ignore_list = {},
},
system_open = {
cmd = nil,
args = {},
},
filters = {
dotfiles = false,
custom = {},

View File

@ -6,25 +6,34 @@ export XDG_CURRENT_DESKTOP=sway # xdg-desktop-portal
export XDG_SESSION_DESKTOP=sway # systemd
export XDG_SESSION_TYPE=wayland # xdg/systemd
#if command -v dbus-update-activation-environment >/dev/null; then
# dbus-update-activation-environment XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE
#fi
# without this, systemd starts xdg-desktop-portal without these environment variables,
# and the xdg-desktop-portal does not start xdg-desktop-portal-wrl as expected
# https://github.com/emersion/xdg-desktop-portal-wlr/issues/39#issuecomment-638752975
#systemctl --user import-environment XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE
if [ -d "$HOME/.config/environment.d" ]; then
for f in "$HOME"/.config/environment.d/*.conf; do
[ -f "$f" ] || continue
while IFS= read -r line || [ -n "$line" ]; do
# Skip empty lines and comments
case "$line" in
'' | '#'*) continue ;;
esac
# Export the variable
export "$line"
done <"$f"
done
fi
# use systemd-run here, because systemd units inherit variables from ~/.config/environment.d
# shellcheck disable=SC2068
#systemd-run --quiet --unit=sway --user --wait sway $@
#systemctl --user stop sway-session.target
max_attempts=50
attempt=0
while [ ! -d "/run/user/$(id -u)" ]; do
if [ "$attempt" -ge "$max_attempts" ]; then
echo "Error: XDG_RUNTIME_DIR not available after $max_attempts attempts" >&2
exit 1
fi
sleep 0.2
attempt=$((attempt + 1))
done
#systemctl --user unset-environment DISPLAY SWAYSOCK WAYLAND_DISPLAY XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE
#if command -v dbus-update-activation-environment >/dev/null; then
# dbus-update-activation-environment XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE
#fi
#dbus-launch --exit-with-session sway
dbus-run-session sway
export XDG_RUNTIME_DIR="/run/user/$(id -u)"
dbus-run-session sway "$@"
# this teardown makes it easier to switch between compositors
unset DISPLAY SWAYSOCK WAYLAND_DISPLAY XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE