This repository has no description
12 kB
376 lines
1{ inputs, ... }:
2{
3 perSystem =
4 { system, pkgs, ... }:
5 {
6 packages.nvim = inputs.nixvim.legacyPackages.${system}.makeNixvim {
7 vimAlias = true;
8 colorschemes = {
9 ayu = {
10 enable = true;
11 settings = {
12 mirage = false;
13 dark = true;
14 };
15 settings.overrides = {
16 EoLSpace = {
17 bg = "#883333";
18 };
19 };
20 };
21 everforest = {
22 enable = true;
23 settings.overrides = {
24 EoLSpace = {
25 bg = "#FF2222"; # doesn't work
26 };
27 };
28 };
29 };
30 extraConfigLua = ''
31 -- Cross-platform background detection and colorscheme switching
32 local last_theme = nil
33
34 local function detect_and_set_theme()
35 local is_dark = false
36
37 if vim.fn.has("mac") == 1 then
38 -- macOS: check system appearance
39 local result = vim.fn.system("defaults read -g AppleInterfaceStyle 2>/dev/null")
40 is_dark = result:match("Dark") ~= nil
41 elseif vim.fn.has("unix") == 1 then
42 -- Linux: check if running under a dark theme
43 -- Check NixOS theme system first (always check this fresh)
44 local f = io.open("/var/theme/current_theme", "r")
45 if f then
46 local content = f:read("*all"):gsub("^%s+", ""):gsub("%s+$", "")
47 f:close()
48 is_dark = (content == "dark")
49 else
50 -- Fallback to other methods if theme file doesn't exist
51 local methods = {
52 -- GNOME/GTK
53 "gsettings get org.gnome.desktop.interface gtk-theme 2>/dev/null",
54 "gsettings get org.gnome.desktop.interface color-scheme 2>/dev/null",
55 -- KDE
56 "kreadconfig5 --file kdeglobals --group General --key ColorScheme 2>/dev/null",
57 -- Check if COLORFGBG suggests dark background
58 function()
59 local colorfgbg = vim.env.COLORFGBG
60 if colorfgbg then
61 local fg, bg = colorfgbg:match("(%d+);(%d+)")
62 if fg and bg then
63 -- If foreground is lighter than background, likely dark theme
64 return tonumber(fg) > tonumber(bg)
65 end
66 end
67 return false
68 end
69 }
70
71 for _, method in ipairs(methods) do
72 if type(method) == "function" then
73 is_dark = method()
74 if is_dark then break end
75 else
76 local result = vim.fn.system(method)
77 if result:match("[Dd]ark") or result:match("prefer%-dark") then
78 is_dark = true
79 break
80 end
81 end
82 end
83 end
84 end
85
86 local new_theme = is_dark and "dark" or "light"
87
88 if new_theme ~= last_theme then
89 last_theme = new_theme
90 vim.o.background = new_theme
91
92 if is_dark then
93 vim.cmd("colorscheme ayu")
94 else
95 vim.cmd("colorscheme everforest")
96 end
97 end
98 end
99
100 -- Set initial theme
101 vim.defer_fn(detect_and_set_theme, 100)
102
103 -- Check for theme changes every 3 seconds (less frequent to be less resource intensive)
104 local timer = vim.loop.new_timer()
105 timer:start(3000, 3000, vim.schedule_wrap(detect_and_set_theme))
106
107 -- Create a command to manually refresh theme
108 vim.api.nvim_create_user_command("RefreshTheme", detect_and_set_theme, {})
109
110 -- Configure lsp_lines to always show and disable default virtual_text
111 vim.diagnostic.config({
112 virtual_text = false,
113 virtual_lines = true,
114 })
115 '';
116 globals = {
117 mapleader = " ";
118 };
119 opts = {
120 mouse = "a";
121 number = true;
122 shiftwidth = 2;
123 clipboard = "unnamedplus";
124 # undo stuff
125 undofile = true;
126 undolevels = 10000;
127 undoreload = 10000;
128 listchars = "tab:⇥ ,extends:❯,precedes:❮,nbsp:␣,trail:·,eol:↲";
129 };
130 extraConfigVim = ''
131 set et
132
133 " show special characters
134 set list
135
136 " match trailing whitespace
137 match EoLSpace /\s\+$/
138
139 " need to use lua to expand $HOME
140 lua vim.o.undodir = vim.fs.normalize('$HOME/.vim/undodir')
141 '';
142 extraPlugins = [
143 pkgs.vimPlugins.vim-fetch
144 ];
145 keymaps = [
146 {
147 mode = "i";
148 key = "<C-p>";
149 action = "<Nop>";
150 }
151 {
152 mode = "i";
153 key = "<C-n>";
154 action = "<Nop>";
155 }
156 {
157 mode = "n";
158 key = "<C-c>";
159 action = ":q<cr>";
160 }
161 {
162 mode = "n";
163 key = "<Space>";
164 action = "<Nop>";
165 }
166 {
167 mode = [
168 "n"
169 "v"
170 ];
171 key = "<leader>cc";
172 action = ":CopilotChatOpen<cr>";
173 }
174 {
175 mode = [
176 "n"
177 "v"
178 ];
179 key = "<leader>ce";
180 action = ":CopilotChatExplain<cr>";
181 }
182 {
183 mode = [
184 "n"
185 "v"
186 ];
187 key = "<leader>cr";
188 action = ":CopilotChatReview<cr>";
189 }
190 {
191 mode = [
192 "n"
193 "v"
194 ];
195 key = "<leader>cf";
196 action = ":CopilotChatFix<cr>";
197 }
198 {
199 mode = [
200 "n"
201 "v"
202 ];
203 key = "<leader>cd";
204 action = ":CopilotChatDocs<cr>";
205 }
206 {
207 mode = [
208 "n"
209 "x"
210 ];
211 key = "p";
212 action = "<Plug>(YankyPutAfter)";
213 }
214 {
215 mode = [
216 "n"
217 "x"
218 ];
219 key = "P";
220 action = "<Plug>(YankyPutBefore)";
221 }
222 {
223 mode = [
224 "c"
225 "i"
226 "n"
227 "x"
228 ];
229 key = "<M-CR>";
230 action = ":lua vim.lsp.buf.code_action()<CR>";
231 }
232 {
233 mode = [
234 "n"
235 ];
236 key = "gd";
237 action = ":lua vim.lsp.buf.definition()<CR>";
238 }
239 {
240 mode = [
241 "n"
242 ];
243 key = "gD";
244 action = ":lua vim.lsp.buf.declaration()<CR>";
245 }
246 {
247 mode = "n";
248 key = "<leader>ll";
249 action = ":lua require('lsp_lines').toggle()<CR>";
250 options.desc = "Toggle lsp_lines";
251 }
252 ];
253 # autoCmd = [
254 # {
255 # event = "BufWritePost";
256 # desc = "run treefmt on save";
257 # # https://stackoverflow.com/questions/77466697/how-to-automatically-format-on-save
258 # callback.__raw = ''
259 # function()
260 # vim.cmd("silent !treefmt %")
261 # vim.cmd("edit")
262 # end
263 # '';
264 # }
265 # ];
266 plugins.none-ls = {
267 enable = true;
268 # sources.formatting.treefmt = {
269 # enable = true;
270 # package = pkgs.emptyDirectory;
271 # };
272 # package = pkgs.vimPlugins.none-ls-nvim.overrideAttrs (_old: {
273 # src = pkgs.fetchFromGitHub {
274 # owner = "lassulus";
275 # repo = "none-ls.nvim";
276 # rev = "292c2b5eadea0a097b9a01804aea70f5c8125200";
277 # sha256 = "sha256-nbzqXsxmYfxngdJH3NXMLmGgygh6reSEnruoc6l8t/s=";
278 # };
279 # });
280 sources.formatting.nix_flake_fmt.enable = true;
281 };
282 plugins.web-devicons.enable = true;
283 plugins.telescope.extensions.undo.enable = true;
284 plugins.telescope = {
285 enable = true;
286 keymaps = {
287 "<leader>b" = "buffers";
288 "<leader>u" = "undo";
289 "<leader>ff" = "find_files";
290 "<leader>fg" = "live_grep";
291 "<leader>fh" = "help_tags";
292 "<leader>fp" = "yank_history";
293 };
294 };
295 plugins.lsp-format.enable = true;
296 plugins.lsp-lines.enable = true;
297 plugins.lsp = {
298 enable = true;
299 servers = {
300 bashls.enable = true; # bash
301 nixd = {
302 enable = true; # nix
303 extraOptions.offset_encoding = "utf-8"; # workaround https://github.com/nix-community/nixvim/issues/2390#issuecomment-2408101568
304 };
305 ruff.enable = true; # python
306 pyright.enable = true; # python
307 jsonls.enable = true; # json
308 };
309 };
310 plugins.treesitter.enable = true;
311 plugins.copilot-cmp.enable = true;
312 plugins.copilot-lua.settings.panel.enabled = false;
313 plugins.copilot-lua.settings.suggestion.enabled = false;
314 plugins.cmp_yanky.enable = true;
315 plugins.cmp = {
316 enable = true;
317 autoEnableSources = true;
318 settings = {
319 experimental = {
320 ghost_text = true;
321 };
322 sources = [
323 { name = "nvim_lsp"; }
324 { name = "emoji"; }
325 {
326 name = "buffer"; # text within current buffer
327 option.get_bufnrs.__raw = "vim.api.nvim_list_bufs";
328 keywordLength = 2;
329 }
330 {
331 name = "copilot"; # enable copilot
332 }
333 {
334 name = "path"; # file system paths
335 keywordLength = 3;
336 }
337 { name = "cmp_yanky"; }
338 ];
339
340 mapping = {
341 "<Tab>" = "cmp.mapping.select_next_item()";
342 "<S-Tab>" = "cmp.mapping.select_prev_item()";
343 "<C-n>" = "cmp.mapping.select_next_item()";
344 "<C-p>" = "cmp.mapping.select_prev_item()";
345 "<C-e>" = "cmp.mapping.abort()";
346 "<C-b>" = "cmp.mapping.scroll_docs(-4)";
347 "<C-f>" = "cmp.mapping.scroll_docs(4)";
348 "<CR>" = ''
349 cmp.mapping({
350 i = function(fallback)
351 if cmp.visible() and cmp.get_active_entry() then
352 cmp.confirm({ behavior = cmp.ConfirmBehavior.Replace, select = false })
353 else
354 fallback()
355 end
356 end,
357 s = cmp.mapping.confirm({ select = true }),
358 c = cmp.mapping.confirm({ behavior = cmp.ConfirmBehavior.Replace, select = true }),
359 })
360 '';
361 };
362 };
363 };
364 plugins.bufferline.enable = true;
365 plugins.which-key.enable = true;
366 plugins.yanky = {
367 enable = true;
368 enableTelescope = true;
369 };
370 plugins.comment.enable = true;
371 plugins.copilot-chat.enable = true;
372 plugins.undotree.enable = true; # seems to be needed for undo history in telescope
373 plugins.gitsigns.enable = true;
374 };
375 };
376}