first commit

This commit is contained in:
Louis Chih-Ming Lee 2026-01-26 01:16:35 +01:00
commit 2a3ea31491
52 changed files with 2991 additions and 0 deletions

29
apps/fuzzel/default.nix Normal file
View file

@ -0,0 +1,29 @@
{ config, pkgs, lib, ... }:
let
cfg = config.my.apps.fuzzel;
in
{
options.my.apps.fuzzel = {
enable = lib.mkEnableOption "Fuzzel launcher";
package = lib.mkOption {
type = lib.types.package;
default = pkgs.fuzzel;
defaultText = "pkgs.fuzzel";
description = "Fuzzel package to install.";
};
};
config = lib.mkIf cfg.enable {
home.packages = [
cfg.package
pkgs.jetbrains-mono
];
xdg.enable = true;
# fuzzel uses ~/.config/fuzzel/fuzzel.ini
xdg.configFile."fuzzel/fuzzel.ini".source = ./fuzzel.ini;
};
}

41
apps/fuzzel/fuzzel.ini Normal file
View file

@ -0,0 +1,41 @@
# Fuzzel config
# Catppuccin Mocha-ish palette + Emacs navigation keys
[main]
font=JetBrains Mono:size=14
dpi-aware=yes
prompt=Search:
terminal=foot
layer=overlay
# Window sizing
width=45
lines=8
horizontal-pad=20
vertical-pad=16
inner-pad=10
[colors]
# Catppuccin Mocha palette
background=1e1e2eff
text=cdd6f4ff
match=cba6f7ff
selection=585b70ff
selection-text=f5e0dcff
border=cba6f7ff
[border]
width=2
radius=12
[key-bindings]
# List navigation
next=Control+n
prev=Control+p
# Optional extras
next-page=Page_Down
prev-page=Page_Up
accept=Return
cancel=Escape

View file

@ -0,0 +1 @@
require("nvim-autopairs").setup {}

View file

@ -0,0 +1,76 @@
require("catppuccin").setup({
flavour = "auto", -- latte, frappe, macchiato, mocha
background = { -- :h background
light = "latte",
dark = "mocha",
},
transparent_background = false, -- disables setting the background color.
float = {
transparent = false, -- enable transparent floating windows
solid = false, -- use solid styling for floating windows, see |winborder|
},
show_end_of_buffer = false, -- shows the '~' characters after the end of buffers
term_colors = false, -- sets terminal colors (e.g. `g:terminal_color_0`)
dim_inactive = {
enabled = false, -- dims the background color of inactive window
shade = "dark",
percentage = 0.15, -- percentage of the shade to apply to the inactive window
},
no_italic = false, -- Force no italic
no_bold = false, -- Force no bold
no_underline = false, -- Force no underline
styles = { -- Handles the styles of general hi groups (see `:h highlight-args`):
comments = { "italic" }, -- Change the style of comments
conditionals = { "italic" },
loops = {},
functions = {},
keywords = {},
strings = {},
variables = {},
numbers = {},
booleans = {},
properties = {},
types = {},
operators = {},
-- miscs = {}, -- Uncomment to turn off hard-coded styles
},
lsp_styles = { -- Handles the style of specific lsp hl groups (see `:h lsp-highlight`).
virtual_text = {
errors = { "italic" },
hints = { "italic" },
warnings = { "italic" },
information = { "italic" },
ok = { "italic" },
},
underlines = {
errors = { "underline" },
hints = { "underline" },
warnings = { "underline" },
information = { "underline" },
ok = { "underline" },
},
inlay_hints = {
background = true,
},
},
color_overrides = {},
custom_highlights = {},
default_integrations = true,
auto_integrations = false,
integrations = {
cmp = true,
gitsigns = true,
nvimtree = true,
notify = false,
mini = {
enabled = true,
indentscope_color = "",
},
telescope = {
enabled = true,
},
lsp_trouble = true,
},
})
vim.cmd.colorscheme "catppuccin"

86
apps/neovim/cmp.lua Normal file
View file

@ -0,0 +1,86 @@
-- https://github.com/hrsh7th/nvim-cmp
local cmp = require'cmp'
cmp.setup({
snippet = {
-- REQUIRED - you must specify a snippet engine
expand = function(args)
vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users.
-- require('luasnip').lsp_expand(args.body) -- For `luasnip` users.
-- require('snippy').expand_snippet(args.body) -- For `snippy` users.
-- vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users.
-- vim.snippet.expand(args.body) -- For native neovim snippets (Neovim v0.10+)
-- For `mini.snippets` users:
-- local insert = MiniSnippets.config.expand.insert or MiniSnippets.default_insert
-- insert({ body = args.body }) -- Insert at cursor
-- cmp.resubscribe({ "TextChangedI", "TextChangedP" })
-- require("cmp.config").set_onetime({ sources = {} })
end,
},
window = {
completion = cmp.config.window.bordered(),
documentation = cmp.config.window.bordered(),
},
mapping = cmp.mapping.preset.insert({
['<C-b>'] = cmp.mapping.scroll_docs(-4),
['<C-f>'] = cmp.mapping.scroll_docs(4),
['<C-j>'] = cmp.mapping.complete(),
['<C-e>'] = cmp.mapping.abort(),
['<CR>'] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
}),
sources = cmp.config.sources({
{ name = 'nvim_lsp' },
{ name = 'vsnip' }, -- For vsnip users.
-- { name = 'luasnip' }, -- For luasnip users.
-- { name = 'ultisnips' }, -- For ultisnips users.
-- { name = 'snippy' }, -- For snippy users.
}, {
{ name = 'buffer' },
})
})
-- To use git you need to install the plugin petertriho/cmp-git and uncomment lines below
-- Set configuration for specific filetype.
--[[ cmp.setup.filetype('gitcommit', {
sources = cmp.config.sources({
{ name = 'git' },
}, {
{ name = 'buffer' },
})
)
require("cmp_git").setup() ]]--
-- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore).
cmp.setup.cmdline({ '/', '?' }, {
mapping = cmp.mapping.preset.cmdline(),
sources = {
{ name = 'buffer' }
}
})
-- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore).
cmp.setup.cmdline(':', {
mapping = cmp.mapping.preset.cmdline(),
sources = cmp.config.sources({
{ name = 'path' }
}, {
{ name = 'cmdline' }
}),
matching = { disallow_symbol_nonprefix_matching = false }
})
-- Set up lspconfig.
local capabilities = require('cmp_nvim_lsp').default_capabilities()
function config_and_enable_lsp(language, extra_config)
--lsp_config = { capabilities = capabilities }
--vim.lsp.config(language, lsp_config)
vim.lsp.enable(language)
end
vim.lsp.config('*', {
capabilities = capabilities
})

113
apps/neovim/default.nix Normal file
View file

@ -0,0 +1,113 @@
{ config, pkgs, inputs, my-r,... }:
let
nvim-config-store = builtins.filterSource (path: type: baseNameOf path != "default.nix") ./.;
nvim-config-files = builtins.attrNames (builtins.readDir nvim-config-store);
nvim-config-lis = map (path: builtins.readFile "${nvim-config-store}/${path}") (nvim-config-files);
nvim-config = builtins.concatStringsSep "\n" nvim-config-lis;
in
{
programs.neovim = {
enable = true;
defaultEditor = true;
plugins = with pkgs.vimPlugins; [
nvim-treesitter.withAllGrammars
nvim-lspconfig
telescope-nvim
nvim-cmp
cmp-nvim-lsp
nvim-tree-lua
which-key-nvim
trouble-nvim
kanagawa-nvim
lazygit-nvim
quarto-nvim
otter-nvim
otter-nvim
image-nvim
molten-nvim
toggleterm-nvim
markdown-preview-nvim
lualine-nvim
gitsigns-nvim
indent-blankline-nvim
guess-indent-nvim
nvim-autopairs
catppuccin-nvim
];
extraLuaConfig = nvim-config;
extraPackages = with pkgs; [
#quarto
pyright
ripgrep
lua-language-server
rust-analyzer
lazygit
tectonic
imagemagick
jupyter
pnglatex
nil
nixfmt
rustc
cargo
rustfmt
clippy
rust-analyzer
];
extraLuaPackages = p: with p; [
magick
];
extraPython3Packages = ps: with ps; [
pynvim
jupyter-client
cairosvg
pnglatex
plotly
pyperclip
ipython
nbformat
];
};
xdg.dataFile."jupyter/kernels/ir-nix/kernel.json".text = ''
{
"argv": [
"${my-r.env}/bin/R",
"--slave",
"-e",
"IRkernel::main()",
"--args",
"{connection_file}"
],
"display_name": "R (nix)",
"language": "R"
}
'';
home.file.".Rprofile".text = ''
graphics::par(bg = "white")
options(
jupyter.rich_display = TRUE,
#jupyter.display_mimetypes = c("text/plain", "image/png", "text/latex"),
jupyter.display_mimetypes = c("text/plain", "image/png"),
jupyter.plot_mimetypes = "image/png"
)
'';
#sessionVariables = {
# EDITOR = "nvim";
# VISUAL = "nvim";
#};
}

View file

@ -0,0 +1,21 @@
local sign = function(opts)
vim.fn.sign_define(opts.name, {
texthl = opts.name,
text = opts.text,
numhl = ''
})
end
sign({name = 'DiagnosticSignError', text = ''})
sign({name = 'DiagnosticSignWarn', text = ''})
sign({name = 'DiagnosticSignHint', text = ''})
sign({name = 'DiagnosticSignInfo', text = '»'})
vim.diagnostic.config({
virtual_text = false,
severity_sort = true,
float = {
border = 'rounded',
source = 'always',
},
})

66
apps/neovim/gitsigns.lua Normal file
View file

@ -0,0 +1,66 @@
require('gitsigns').setup{
on_attach = function(bufnr)
local gitsigns = require('gitsigns')
local function map(mode, l, r, opts)
opts = opts or {}
opts.buffer = bufnr
vim.keymap.set(mode, l, r, opts)
end
-- Navigation
map('n', ']c', function()
if vim.wo.diff then
vim.cmd.normal({']c', bang = true})
else
gitsigns.nav_hunk('next')
end
end)
map('n', '[c', function()
if vim.wo.diff then
vim.cmd.normal({'[c', bang = true})
else
gitsigns.nav_hunk('prev')
end
end)
-- Actions
map('n', '<leader>hs', gitsigns.stage_hunk)
map('n', '<leader>hr', gitsigns.reset_hunk)
map('v', '<leader>hs', function()
gitsigns.stage_hunk({ vim.fn.line('.'), vim.fn.line('v') })
end)
map('v', '<leader>hr', function()
gitsigns.reset_hunk({ vim.fn.line('.'), vim.fn.line('v') })
end)
map('n', '<leader>hS', gitsigns.stage_buffer)
map('n', '<leader>hR', gitsigns.reset_buffer)
map('n', '<leader>hp', gitsigns.preview_hunk)
map('n', '<leader>hi', gitsigns.preview_hunk_inline)
map('n', '<leader>hb', function()
gitsigns.blame_line({ full = true })
end)
map('n', '<leader>hd', gitsigns.diffthis)
map('n', '<leader>hD', function()
gitsigns.diffthis('~')
end)
map('n', '<leader>hQ', function() gitsigns.setqflist('all') end)
map('n', '<leader>hq', gitsigns.setqflist)
-- Toggles
map('n', '<leader>tb', gitsigns.toggle_current_line_blame)
map('n', '<leader>tw', gitsigns.toggle_word_diff)
-- Text object
map({'o', 'x'}, 'ih', gitsigns.select_hunk)
end
}

View file

@ -0,0 +1 @@
require("guess-indent").setup {}

10
apps/neovim/ibl.lua Normal file
View file

@ -0,0 +1,10 @@
require("ibl").setup {
indent = {
char = "",
highlight = "IblIndent",
}
}
--│, ┆, ⋅, ╎
-- Use very subtle color
vim.api.nvim_set_hl(0, "IblIndent", { fg = "#3a3a3a" })

61
apps/neovim/init.lua Normal file
View file

@ -0,0 +1,61 @@
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '
vim.g.have_nerd_font = true
vim.o.number = true
vim.o.mouse = 'a'
--vim.o.showmode = false
vim.schedule(function()
vim.o.clipboard = 'unnamedplus'
end)
vim.o.breakindent = true
vim.o.undofile = true
vim.o.ignorecase = true
vim.o.smartcase = true
vim.o.signcolumn = 'yes'
vim.o.colorcolumn = "80"
vim.o.updatetime = 250
vim.o.timeoutlen = 300
vim.o.splitright = true
vim.o.splitbelow = true
vim.o.list = true
vim.opt.listchars = { tab = '» ', trail = '·', nbsp = '' }
vim.o.inccommand = 'split'
vim.o.cursorline = true
vim.o.scrolloff = 15
vim.o.confirm = true
vim.keymap.set('i', 'jk', '<Escape>')
vim.keymap.set('i', 'kj', '<Escape>')
--vim.keymap.set('i', 'jf', '<Escape>')
-- See `:help wincmd` for a list of all window commands
vim.keymap.set('n', '<C-h>', '<C-w><C-h>', { desc = 'Move focus to the left window' })
vim.keymap.set('n', '<C-l>', '<C-w><C-l>', { desc = 'Move focus to the right window' })
vim.keymap.set('n', '<C-j>', '<C-w><C-j>', { desc = 'Move focus to the lower window' })
vim.keymap.set('n', '<C-k>', '<C-w><C-k>', { desc = 'Move focus to the upper window' })
vim.o.tabstop = 2
vim.o.smartindent = true
vim.o.shiftwidth = 2
vim.o.expandtab = true

14
apps/neovim/lazygit.lua Normal file
View file

@ -0,0 +1,14 @@
vim.g.lazygit_floating_window_winblend = 0 -- transparency of floating window
vim.g.lazygit_floating_window_scaling_factor = 0.9 -- scaling factor for floating window
vim.g.lazygit_floating_window_border_chars = {'','', '', '', '','', '', ''} -- customize lazygit popup window border characters
vim.g.lazygit_floating_window_use_plenary = 0 -- use plenary.nvim to manage floating window if available
vim.g.lazygit_use_neovim_remote = 1 -- fallback to 0 if neovim-remote is not installed
vim.g.lazygit_use_custom_config_file_path = 0 -- config file path is evaluated if this value is 1
vim.g.lazygit_config_file_path = '' -- custom config file path
-- OR
vim.g.lazygit_config_file_path = {} -- table of custom config file paths
vim.g.lazygit_on_exit_callback = nil -- optional function callback when exiting lazygit (useful for example to refresh some UI elements after lazy git has made some changes)
vim.keymap.set("n", "<Leader>gg", ":LazyGit<CR>", { desc = "LazyGit" })

101
apps/neovim/lsp.lua Normal file
View file

@ -0,0 +1,101 @@
local lspconfig = require('lspconfig')
vim.lsp.config('lua_ls', { cmd = { 'lua-language-server' },
settings = {
Lua = {
runtime = {
version = 'LuaJIT',
path = vim.split(package.path, ';'),
},
diagnostics = {
globals = { 'vim' },
},
},
},
})
vim.lsp.config('rust_analyzer', {
settings = {
['rust-analyzer'] = {
diagnostics = {
enable = true;
};
};
}
})
local languages = {
'rust_analyzer',
'r_language_server',
'lua_ls',
'quarto',
'nil_ls',
'pyright'
}
for _, language in ipairs(languages) do
vim.lsp.enable(language)
end
vim.diagnostic.config {
severity_sort = true,
float = { border = 'rounded', source = 'if_many' },
underline = { severity = vim.diagnostic.severity.ERROR },
signs = vim.g.have_nerd_font and {
text = {
[vim.diagnostic.severity.ERROR] = '󰅚 ',
[vim.diagnostic.severity.WARN] = '󰀪 ',
[vim.diagnostic.severity.INFO] = '󰋽 ',
[vim.diagnostic.severity.HINT] = '󰌶 ',
},
} or {},
virtual_text = {
source = 'if_many',
spacing = 2,
format = function(diagnostic)
local diagnostic_message = {
[vim.diagnostic.severity.ERROR] = diagnostic.message,
[vim.diagnostic.severity.WARN] = diagnostic.message,
[vim.diagnostic.severity.INFO] = diagnostic.message,
[vim.diagnostic.severity.HINT] = diagnostic.message,
}
return diagnostic_message[diagnostic.severity]
end,
},
}
vim.api.nvim_create_autocmd("LspAttach", {
callback = function(event)
local buf = event.buf
local opts = function(desc)
return { buffer = buf, desc = desc }
end
-- Jumping + finding
vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts("[G]oto Definition"))
vim.keymap.set("n", "gD", vim.lsp.buf.declaration, opts("Goto [D]eclaration"))
vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts("[G]oto [I]mplementation"))
vim.keymap.set("n", "gr", vim.lsp.buf.references, opts("[G]oto [R]eferences"))
-- Info + documentation
vim.keymap.set("n", "K", vim.lsp.buf.hover, opts("Hover Documentation"))
vim.keymap.set("n", "<C-k>", vim.lsp.buf.signature_help, opts("Signature Help"))
-- Actions + rename
vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, opts("[R]e[n]ame"))
vim.keymap.set({ "n", "v" }, "<leader>ca", vim.lsp.buf.code_action, opts("[C]ode [A]ction"))
-- Diagnostics navigation
vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, opts("Prev Diagnostic"))
vim.keymap.set("n", "]d", vim.diagnostic.goto_next, opts("Next Diagnostic"))
vim.keymap.set("n", "<leader>e", vim.diagnostic.open_float, opts("Show Error"))
vim.keymap.set("n", "<leader>q", vim.diagnostic.setloclist, opts("Diagnostic Quickfix"))
-- Formatting
vim.keymap.set("n", "<leader>f", function()
vim.lsp.buf.format({ async = true })
end, opts("[F]ormat Buffer"))
end,
})

54
apps/neovim/lua-line.lua Normal file
View file

@ -0,0 +1,54 @@
require('lualine').setup {
options = {
icons_enabled = true,
theme = 'auto',
component_separators = { left = '', right = ''},
section_separators = { left = '', right = ''},
disabled_filetypes = {
statusline = {},
winbar = {},
},
ignore_focus = {},
always_divide_middle = true,
always_show_tabline = true,
globalstatus = false,
refresh = {
statusline = 1000,
tabline = 1000,
winbar = 1000,
refresh_time = 16, -- ~60fps
events = {
'WinEnter',
'BufEnter',
'BufWritePost',
'SessionLoadPost',
'FileChangedShellPost',
'VimResized',
'Filetype',
'CursorMoved',
'CursorMovedI',
'ModeChanged',
},
}
},
sections = {
lualine_a = {'mode'},
lualine_b = {'branch', 'diff', 'diagnostics'},
lualine_c = {'filename'},
lualine_x = {'encoding', 'fileformat', 'filetype'},
lualine_y = {'progress'},
lualine_z = {'location'}
},
inactive_sections = {
lualine_a = {},
lualine_b = {},
lualine_c = {'filename'},
lualine_x = {'location'},
lualine_y = {},
lualine_z = {}
},
tabline = {},
winbar = {},
inactive_winbar = {},
extensions = {}
}

48
apps/neovim/molten.lua Normal file
View file

@ -0,0 +1,48 @@
vim.g.molten_auto_open_output = true
vim.g.molten_wrap_output = true
vim.g.molten_output_show_exec_time = true
vim.g.molten_output_win_hide_on_leave = false
vim.g.molten_use_border_highlights = true
vim.g.molten_virt_text_output = true
vim.g.molten_image_provider = "image.nvim"
vim.g.molten_image_location = "both"
vim.g.molten_output_virt_lines = true
vim.g.molten_cover_empty_lines = true
vim.g.molten_output_truncate = "bottom"
vim.g.molten_virt_text_max_lines = 20
--vim.g.molten_output = "pane"
vim.api.nvim_set_hl(0, "NormalFloat", { bg = "#1e1e2e" })
vim.api.nvim_set_hl(0, "FloatBorder", { bg = "#1e1e2e" })
-- vim.api.nvim_set_hl(0, "MoltenVirtualText", {
-- bg = "#ae0606",
-- fg = "#ffd787",
-- italic = true,
-- })
require("image").setup({
editor = {
-- force a visible background for plots
background = "white", -- or "#ffffff" or "black"
inline = {
enable = true,
};
},
})
vim.keymap.set("n", "<localleader>mi", ":MoltenInit<CR>",
{ silent = true, desc = "Initialize the plugin" })
vim.keymap.set("n", "<localleader>e", ":MoltenEvaluateOperator<CR>",
{ silent = true, desc = "run operator selection" })
vim.keymap.set("n", "<localleader>rl", ":MoltenEvaluateLine<CR>",
{ silent = true, desc = "evaluate line" })
vim.keymap.set("n", "<localleader>rr", ":MoltenReevaluateCell<CR>",
{ silent = true, desc = "re-evaluate cell" })
vim.keymap.set("v", "<localleader>r", ":<C-u>MoltenEvaluateVisual<CR>gv",
{ silent = true, desc = "evaluate visual selection" })
vim.keymap.set("n", "<localleader>rd", ":MoltenDelete<CR>",
{ silent = true, desc = "molten delete cell" })
vim.keymap.set("n", "<localleader>oh", ":MoltenHideOutput<CR>",
{ silent = true, desc = "hide output" })
vim.keymap.set("n", "<localleader>os", ":noautocmd MoltenEnterOutput<CR>",
{ silent = true, desc = "show/enter output" })

25
apps/neovim/nvim-tree.lua Normal file
View file

@ -0,0 +1,25 @@
-- disable netrw at the very start of your init.lua
vim.g.loaded_netrw = 1
vim.g.loaded_netrwPlugin = 1
-- optionally enable 24-bit colour
vim.opt.termguicolors = true
-- OR setup with some options
require("nvim-tree").setup({
sort = {
sorter = "case_sensitive",
},
view = {
width = 30,
},
renderer = {
group_empty = true,
},
filters = {
dotfiles = true,
},
})
vim.keymap.set('n', '<Leader>d', ':NvimTreeToggle<CR>', { desc = 'Open or close the tree' })

5
apps/neovim/otter.lua Normal file
View file

@ -0,0 +1,5 @@
require("otter").setup({
buffers = {
write_to_disk = true,
},
})

37
apps/neovim/quarto.lua Normal file
View file

@ -0,0 +1,37 @@
local quarto = require('quarto')
require('quarto').setup{
debug = true,
lspFeatures = {
enabled = true,
hover = true,
chunks = "curly",
languages = { "r", "python", "julia", "bash", "html" },
diagnostics = {
enabled = false,
lint_cache = false,
triggers = { "BufWritePost" },
},
completion = {
enabled = true,
},
},
codeRunner = {
enabled = true,
default_method = "molten", -- "molten", "slime", "iron" or <function>
ft_runners = { r = "molten", python = "molten" }, -- filetype to runner, ie. `{ python = "molten" }`.
-- Takes precedence over `default_method`
never_run = { 'yaml' }, -- filetypes which are never sent to a code runner
},
}
vim.keymap.set('n', '<leader>qp', quarto.quartoPreview, { silent = true, noremap = true })
local runner = require("quarto.runner")
vim.keymap.set("n", "<localleader>rr", runner.run_cell, { desc = "run cell", silent = true })
vim.keymap.set("n", "<localleader>ra", runner.run_above, { desc = "run cell and above", silent = true })
vim.keymap.set("n", "<localleader>rR", runner.run_all, { desc = "run all cells", silent = true })
vim.keymap.set("n", "<localleader>rl", runner.run_line, { desc = "run line", silent = true })
vim.keymap.set("v", "<localleader>r", runner.run_range, { desc = "run visual range", silent = true })
vim.keymap.set("n", "<localleader>RA", function()
runner.run_all(true)
end, { desc = "run all cells of all languages", silent = true })

36
apps/neovim/telescope.lua Normal file
View file

@ -0,0 +1,36 @@
local builtin = require('telescope.builtin')
vim.keymap.set('n', '<leader>ff', builtin.find_files, { desc = 'Telescope find files' })
vim.keymap.set('n', '<leader>fg', builtin.live_grep, { desc = 'Telescope live grep' })
vim.keymap.set('n', '<leader>fb', builtin.buffers, { desc = 'Telescope buffers' })
vim.keymap.set('n', '<leader>fh', builtin.help_tags, { desc = 'Telescope help tags' })
require('telescope').setup{
defaults = {
-- Default configuration for telescope goes here:
-- config_key = value,
mappings = {
i = {
-- map actions.which_key to <C-h> (default: <C-/>)
-- actions.which_key shows the mappings for your picker,
-- e.g. git_{create, delete, ...}_branch for the git_branches picker
["<C-h>"] = "which_key"
}
}
},
pickers = {
-- Default configuration for builtin pickers goes here:
-- picker_name = {
-- picker_config_key = value,
-- ...
-- }
-- Now the picker_config_key will be applied every time you call this
-- builtin picker
},
extensions = {
-- Your extension configuration goes here:
-- extension_name = {
-- extension_config_key = value,
-- }
-- please take a look at the readme of the extension you want to configure
}
}

View file

@ -0,0 +1,5 @@
require("toggleterm").setup()
vim.keymap.set("n", "<Leader>tt", '<cmd>ToggleTerm direction=float<CR>', { noremap = ture, silent = true })
vim.keymap.set("n", "<Leader>tv", '<cmd>ToggleTerm direction=vertical<CR>', { noremap = ture, silent = true })
vim.keymap.set("n", "<Leader>th", '<cmd>ToggleTerm direction=horizontal<CR>', { noremap = ture, silent = true })

View file

@ -0,0 +1,23 @@
vim.api.nvim_create_autocmd("FileType", {
pattern = "*",
callback = function()
local ft = vim.bo.filetype
local lang = vim.treesitter.language.get_lang(ft)
if not lang or not vim.treesitter.language.add(lang) then
return
end
vim.treesitter.start()
-- Set folding if available
if vim.treesitter.query.get(lang, "folds") then
vim.wo.foldexpr = "v:lua.vim.treesitter.foldexpr()"
end
-- Set indentation if available (overrides traditional indent)
if vim.treesitter.query.get(lang, "indents") then
vim.bo.indentexpr = "nvim_treesitter#indent()"
end
end
})

204
apps/neovim/trouble.lua Normal file
View file

@ -0,0 +1,204 @@
---@class trouble.Mode: trouble.Config,trouble.Section.spec
---@field desc? string
---@field sections? string[]
---@class trouble.Config
---@field mode? string
---@field config? fun(opts:trouble.Config)
---@field formatters? table<string,trouble.Formatter> custom formatters
---@field filters? table<string, trouble.FilterFn> custom filters
---@field sorters? table<string, trouble.SorterFn> custom sorters
local defaults = {
auto_close = false, -- auto close when there are no items
auto_open = false, -- auto open when there are items
auto_preview = true, -- automatically open preview when on an item
auto_refresh = true, -- auto refresh when open
auto_jump = false, -- auto jump to the item when there's only one
focus = false, -- Focus the window when opened
restore = true, -- restores the last location in the list when opening
follow = true, -- Follow the current item
indent_guides = true, -- show indent guides
max_items = 200, -- limit number of items that can be displayed per section
multiline = true, -- render multi-line messages
pinned = false, -- When pinned, the opened trouble window will be bound to the current buffer
warn_no_results = true, -- show a warning when there are no results
open_no_results = false, -- open the trouble window when there are no results
---@type trouble.Window.opts
win = {}, -- window options for the results window. Can be a split or a floating window.
-- Window options for the preview window. Can be a split, floating window,
-- or `main` to show the preview in the main editor window.
---@type trouble.Window.opts
preview = {
type = "main",
-- when a buffer is not yet loaded, the preview window will be created
-- in a scratch buffer with only syntax highlighting enabled.
-- Set to false, if you want the preview to always be a real loaded buffer.
scratch = true,
},
-- Throttle/Debounce settings. Should usually not be changed.
---@type table<string, number|{ms:number, debounce?:boolean}>
throttle = {
refresh = 20, -- fetches new data when needed
update = 10, -- updates the window
render = 10, -- renders the window
follow = 100, -- follows the current item
preview = { ms = 100, debounce = true }, -- shows the preview for the current item
},
-- Key mappings can be set to the name of a builtin action,
-- or you can define your own custom action.
---@type table<string, trouble.Action.spec|false>
keys = {
["?"] = "help",
r = "refresh",
R = "toggle_refresh",
q = "close",
o = "jump_close",
["<esc>"] = "cancel",
["<cr>"] = "jump",
["<2-leftmouse>"] = "jump",
["<c-s>"] = "jump_split",
["<c-v>"] = "jump_vsplit",
-- go down to next item (accepts count)
-- j = "next",
["}"] = "next",
["]]"] = "next",
-- go up to prev item (accepts count)
-- k = "prev",
["{"] = "prev",
["[["] = "prev",
dd = "delete",
d = { action = "delete", mode = "v" },
i = "inspect",
p = "preview",
P = "toggle_preview",
zo = "fold_open",
zO = "fold_open_recursive",
zc = "fold_close",
zC = "fold_close_recursive",
za = "fold_toggle",
zA = "fold_toggle_recursive",
zm = "fold_more",
zM = "fold_close_all",
zr = "fold_reduce",
zR = "fold_open_all",
zx = "fold_update",
zX = "fold_update_all",
zn = "fold_disable",
zN = "fold_enable",
zi = "fold_toggle_enable",
gb = { -- example of a custom action that toggles the active view filter
action = function(view)
view:filter({ buf = 0 }, { toggle = true })
end,
desc = "Toggle Current Buffer Filter",
},
s = { -- example of a custom action that toggles the severity
action = function(view)
local f = view:get_filter("severity")
local severity = ((f and f.filter.severity or 0) + 1) % 5
view:filter({ severity = severity }, {
id = "severity",
template = "{hl:Title}Filter:{hl} {severity}",
del = severity == 0,
})
end,
desc = "Toggle Severity Filter",
},
},
---@type table<string, trouble.Mode>
modes = {
-- sources define their own modes, which you can use directly,
-- or override like in the example below
lsp_references = {
-- some modes are configurable, see the source code for more details
params = {
include_declaration = true,
},
},
-- The LSP base mode for:
-- * lsp_definitions, lsp_references, lsp_implementations
-- * lsp_type_definitions, lsp_declarations, lsp_command
lsp_base = {
params = {
-- don't include the current location in the results
include_current = false,
},
},
-- more advanced example that extends the lsp_document_symbols
symbols = {
desc = "document symbols",
mode = "lsp_document_symbols",
focus = false,
win = { position = "right" },
filter = {
-- remove Package since luals uses it for control flow structures
["not"] = { ft = "lua", kind = "Package" },
any = {
-- all symbol kinds for help / markdown files
ft = { "help", "markdown" },
-- default set of symbol kinds
kind = {
"Class",
"Constructor",
"Enum",
"Field",
"Function",
"Interface",
"Method",
"Module",
"Namespace",
"Package",
"Property",
"Struct",
"Trait",
},
},
},
},
},
-- stylua: ignore
icons = {
---@type trouble.Indent.symbols
indent = {
top = "",
middle = "├╴",
last = "└╴",
-- last = "-╴",
-- last = "╰╴", -- rounded
fold_open = "",
fold_closed = "",
ws = " ",
},
folder_closed = "",
folder_open = "",
kinds = {
Array = "",
Boolean = "󰨙 ",
Class = "",
Constant = "󰏿 ",
Constructor = "",
Enum = "",
EnumMember = "",
Event = "",
Field = "",
File = "",
Function = "󰊕 ",
Interface = "",
Key = "",
Method = "󰊕 ",
Module = "",
Namespace = "󰦮 ",
Null = "",
Number = "󰎠 ",
Object = "",
Operator = "",
Package = "",
Property = "",
String = "",
Struct = "󰆼 ",
TypeParameter = "",
Variable = "󰀫 ",
},
},
}

View file

@ -0,0 +1 @@
local wk = require("which-key")

175
apps/sway/default.nix Normal file
View file

@ -0,0 +1,175 @@
{ config, pkgs, lib, ... }:
let
mod = "Mod4";
terminal = "ghostty";
menu = "fuzzel";
pactl = "${pkgs.pulseaudio}/bin/pactl";
light = "${pkgs.brightnessctl}/bin/brightnessctl";
grim = "${pkgs.grim}/bin/grim";
slurp = "${pkgs.slurp}/bin/slurp";
wlcopy = "${pkgs.wl-clipboard}/bin/wl-copy";
colors = {
base = "#1e1e2e";
surface0 = "#313244";
surface1 = "#45475a";
text = "#cdd6f4";
subtext = "#bac2de";
blue = "#89b4fa";
yellow = "#f9e2af";
peach = "#fab387";
red = "#f38ba8";
};
in
{
wayland.windowManager.sway = {
enable = true;
config = {
modifier = mod;
terminal = terminal;
menu = menu;
bars = [ ];
fonts = {
names = [ "sans-serif" ];
size = 10.0;
};
window = {
border = 3;
titlebar = false;
};
gaps = {
inner = 0;
outer = 0;
smartGaps = false;
smartBorders = "on";
};
colors = {
focused = {
border = colors.yellow;
background = colors.yellow;
text = colors.base;
indicator = colors.yellow;
childBorder = colors.yellow;
};
focusedInactive = {
border = colors.surface1;
background = colors.surface1;
text = colors.text;
indicator = colors.surface1;
childBorder = colors.surface1;
};
unfocused = {
border = colors.surface1;
background = colors.surface1;
text = colors.text;
indicator = colors.surface1;
childBorder = colors.surface1;
};
urgent = {
border = colors.red;
background = colors.red;
text = colors.base;
indicator = colors.red;
childBorder = colors.red;
};
};
keybindings = lib.mkOptionDefault {
# launcher
"${mod}+Return" = "exec ${terminal}";
"${mod}+d" = "exec ${menu}";
# basic
"${mod}+Shift+q" = "kill";
"${mod}+Shift+r" = "reload";
"${mod}+Shift+e" = "exec swaynag -t warning -m 'Exit sway?' -b 'Yes, exit' 'swaymsg exit'";
# focus movement
"${mod}+h" = "focus left";
"${mod}+j" = "focus down";
"${mod}+k" = "focus up";
"${mod}+l" = "focus right";
# move windows
"${mod}+Shift+h" = "move left";
"${mod}+Shift+j" = "move down";
"${mod}+Shift+k" = "move up";
"${mod}+Shift+l" = "move right";
# split/layout
"${mod}+b" = "splith";
"${mod}+v" = "splitv";
"${mod}+e" = "layout toggle split";
"${mod}+s" = "layout stacking";
"${mod}+w" = "layout tabbed";
"${mod}+f" = "fullscreen toggle";
"${mod}+space" = "floating toggle";
"${mod}+a" = "focus parent";
# workspaces 1..10
"${mod}+1" = "workspace number 1";
"${mod}+2" = "workspace number 2";
"${mod}+3" = "workspace number 3";
"${mod}+4" = "workspace number 4";
"${mod}+5" = "workspace number 5";
"${mod}+6" = "workspace number 6";
"${mod}+7" = "workspace number 7";
"${mod}+8" = "workspace number 8";
"${mod}+9" = "workspace number 9";
"${mod}+0" = "workspace number 10";
"${mod}+Shift+1" = "move container to workspace number 1";
"${mod}+Shift+2" = "move container to workspace number 2";
"${mod}+Shift+3" = "move container to workspace number 3";
"${mod}+Shift+4" = "move container to workspace number 4";
"${mod}+Shift+5" = "move container to workspace number 5";
"${mod}+Shift+6" = "move container to workspace number 6";
"${mod}+Shift+7" = "move container to workspace number 7";
"${mod}+Shift+8" = "move container to workspace number 8";
"${mod}+Shift+9" = "move container to workspace number 9";
"${mod}+Shift+0" = "move container to workspace number 10";
# screenshots
"Print" = "exec ${grim} - | ${wlcopy}";
"Shift+Print" = "exec ${grim} -g \"$(${slurp})\" - | ${wlcopy}";
# audio keys
"XF86AudioRaiseVolume" = "exec ${pactl} set-sink-volume @DEFAULT_SINK@ +5%";
"XF86AudioLowerVolume" = "exec ${pactl} set-sink-volume @DEFAULT_SINK@ -5%";
"XF86AudioMute" = "exec ${pactl} set-sink-mute @DEFAULT_SINK@ toggle";
"XF86AudioMicMute" = "exec ${pactl} set-source-mute @DEFAULT_SOURCE@ toggle";
# brightness keys
"XF86MonBrightnessUp" = "exec ${light} set +5%";
"XF86MonBrightnessDown" = "exec ${light} set 5%-";
};
startup = [
{
command = "mako";
always = true;
}
{
command = "fcitx5";
always = true;
}
#{ command = "waybar"; always = true; }
];
};
#extraConfig = '''';
};
}

91
apps/waybar/config.jsonc Normal file
View file

@ -0,0 +1,91 @@
{
"layer": "top",
"position": "top",
"height": 25,
"spacing": 1,
"modules-left": ["sway/workspaces", "sway/mode"],
"modules-right": ["cpu", "memory", "network", "pulseaudio","battery", "clock"],
"sway/workspaces": {
"disable-scroll": true,
},
"sway/window": {
"max-length": 60
},
"network": {
"interval": 5,
"format-alt": "{icon} ↓{bandwidthDownBits} ↑{bandwidthUpBits}",
"format-wifi": "{icon} {signalStrength}%",
"format-icons": ["󰤯 ", "󰤟 ", "󰤢 ", "󰤥 ", "󰤨 "],
"format-ethernet": "󰈀 ",
"format-disconnected": "󰤭 ",
"tooltip": true,
"tooltip-format": "{essid} {ipaddr}"
},
"pulseaudio": {
"format": "{icon} {volume}%",
"format-muted": " 0%",
"format-icons": {
"default": [" "],
},
"on-click": "pactl set-sink-mute @DEFAULT_SINK@ toggle",
},
"battery": {
"format": "{icon} {capacity}%",
"format-alt": "{icon} {time} 󱐋 {power}W",
"format-charging": "{icon} {capacity}%",
"states": {
"warning": 25,
"critical": 10
},
"format-icons": {
"default": ["󰂃", "󰁻", "󰁼", "󰁽", "󰁾", "󰁿", "󰂀", "󰂁", "󰂂", "󰁹"],
"charging": ["󰢜 ", "󰂆 ", "󰂇 ", "󰂈 ", "󰢝 ", "󰂉 ", "󰢞 ", "󰂊 ", "󰂋 ", "󰂅 "],
}
},
"clock": {
"format": "󰥔 {:%H:%M}",
"tooltip-format": "{:%a %d %b %Y}"
},
"cpu": {
"interval": 2,
"format": " {usage}%",
"format-alt":" {usage}% {icon0}{icon1}{icon2}{icon3}{icon4}{icon5}{icon6}{icon7}{icon8}{icon9}{icon10}{icon11}{icon12}{icon13}{icon14}{icon15}  {avg_frequency} GHz",
"states": {
"warning": 60,
"critical": 85,
},
"format-icons": [
"<span color='#b4befe'>▁</span>", // lavender (cool)
"<span color='#89b4fa'>▂</span>", // blue
"<span color='#cdd6f4'>▃</span>", // text
"<span color='#cdd6f4'>▄</span>", // text
"<span color='#f9e2af'>▅</span>", // yellow (warm)
"<span color='#f9e2af'>▆</span>", // yellow
"<span color='#fab387'>▇</span>", // peach (hot)
"<span color='#f38ba8'>█</span>" // red (very hot)
],
"tooltip": true
},
"memory": {
"interval": 5,
"format": " {percentage}%",
"format-alt": " {used}GiB / {avail}GiB",
"states": {
"warning": 70,
"critical": 90,
},
"tooltip": true
}
}

12
apps/waybar/default.nix Normal file
View file

@ -0,0 +1,12 @@
{ config, pkgs, ... }:
{
programs.waybar = {
enable = true;
systemd.enable = true;
};
xdg.configFile = {
"waybar/config.jsonc".source = ./config.jsonc;
"waybar/style.css".source = ./style.css;
};
}

150
apps/waybar/style.css Normal file
View file

@ -0,0 +1,150 @@
/* =========================================================
Waybar style.css Catppuccin Mocha (GTK-safe)
Unified palette + consistent workspaces + severity states
========================================================= */
/* ---------- Catppuccin Mocha palette ---------- */
@define-color base #1e1e2e;
@define-color mantle #181825;
@define-color crust #11111b;
@define-color text #cdd6f4;
@define-color subtext #bac2de;
@define-color muted #9399b2;
@define-color surface0 #313244;
@define-color surface1 #45475a;
/* Accents */
@define-color blue #89b4fa;
@define-color green #a6e3a1;
@define-color peach #fab387;
@define-color yellow #f9e2af;
@define-color red #f38ba8;
@define-color teal #94e2d5;
@define-color lavender #b4befe;
/* Bar + state backgrounds */
@define-color bar_bg rgba(30, 30, 46, 0.88);
@define-color warn_bg rgba(249, 226, 175, 0.28);
@define-color crit_bg rgba(243, 139, 168, 0.38);
/* Workspace backgrounds */
@define-color ws_hover rgba(137, 180, 250, 0.16);
@define-color ws_focus rgba(137, 180, 250, 0.26);
/* ---------- Global reset ---------- */
* {
border: none;
border-radius: 0;
min-height: 0;
box-shadow: none;
}
/* ---------- Bar ---------- */
window#waybar {
background: @bar_bg;
color: @text;
font-size: 12px;
}
/* =========================================================
Workspaces
========================================================= */
#workspaces {
padding: 0 5px;
}
#workspaces button {
padding: 0 5px;
margin: 0px 0px;
color: @subtext;
background: transparent;
}
#workspaces button.focused {
color: @text;
background: @ws_focus;
}
#workspaces button:hover {
background: @ws_hover;
}
#workspaces button.urgent {
color: @text;
background: @crit_bg;
}
#mode {
padding: 0 12px;
background: #f9e2af; /* fully opaque yellow */
color: #1e1e2e; /* dark text */
font-weight: 600;
}
/* =========================================================
Modules (shared)
========================================================= */
#network,
#pulseaudio,
#battery,
#clock,
#cpu,
#memory {
padding: 0 5px; /* literal spacing — GTK-safe */
margin: 0px 0px;
background: transparent;
color: @text;
}
/* Identity colors */
#network { color: @blue; }
#pulseaudio { color: @peach; }
#battery { color: @green; }
#clock { color: @text; font-weight: 500; }
#cpu { color: @lavender; }
#memory { color: @teal; }
/* =========================================================
Severity states (single, consistent approach)
========================================================= */
#battery.warning {
background: @warn_bg;
color: @text;
}
#battery.critical {
background: @crit_bg;
color: @text;
}
#network.disconnected {
background: @crit_bg;
color: @text;
}
#cpu.warning {
background: @warn_bg;
color: @text;
}
#cpu.critical {
background: @crit_bg;
color: @text;
}
#memory.warning {
background: @warn_bg;
color: @text;
}
#memory.critical {
background: @crit_bg;
color: @text;
}