├── .gitignore ├── README.md ├── assets └── images │ ├── debug.png │ ├── features.png │ ├── lsp.png │ ├── lsp_linux.png │ ├── preview.png │ ├── startup_legion.jpeg │ └── startup_mbp.png ├── init.lua ├── lsp ├── clangd.lua ├── pyright.lua ├── ruff.lua ├── texlab.lua ├── typescript-language-server.lua └── vscode-eslint-language-server.lua ├── lua ├── colors.lua ├── diagnostics.lua ├── keymaps.lua ├── lsp.lua ├── options.lua ├── plugins │ ├── autopairs.lua │ ├── bbye.lua │ ├── blankline.lua │ ├── blink.lua │ ├── gitsigns.lua │ ├── init.lua │ ├── molten.lua │ ├── nvim-dap.lua │ ├── nvim-tree.lua │ ├── otter.lua │ ├── terminal.lua │ ├── treesitter.lua │ └── vimtex.lua └── statusline.lua ├── projects └── terminal │ └── lua │ └── terminal.lua ├── queries └── python │ ├── folds.scm │ └── highlights.scm └── snippets ├── markdown.json ├── python.json ├── quarto.json └── tex.json /.gitignore: -------------------------------------------------------------------------------- 1 | plugin/ 2 | 3 | lazy-lock.json 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 16 |
17 |
18 |

19 | The configuration uses as few plugins as possible to improves robustness against breaking changes and makes it easier to maintain. 20 | Although the config uses only 12 plugins, it has all essential IDE features: 21 |

22 | 29 |

30 | That being said, if you are a Neovim user, I hope you see something interesting to adopt to your own config. If you are still considering Neovim, I hope you become a part of our community soon! 31 |

32 |
33 | 34 |
35 |

Dependencies

36 |

37 | The config requires neovim v.0.11.x or newer. 38 | In addition, users are expected to install the required language servers, e.g., Pyright, and debug adapter protocol implementations, e.g., debugpy, themselves. 39 | Unlike many Neovim configs, this project does not require Nerd Fonts because it does not use any icon. 40 |

41 |
42 | 43 |
44 |

How to Use

45 |

46 | During startup, nvim looks for a configuration file inside the nvim directory, which is typically '~/.config/nvim/'. 47 | To use the project, you can simply clone the repository using Git: 48 |

49 |
git clone https://github.com/rezhaTanuharja/minimalistNVIM.git ~/.config/nvim
52 |

53 | Subsequently, simply start Neovim and Lazy will automatically install all of the plugins. 54 | Keep in mind that if you have not installed the required language servers or debug adapter protocol implementations, you may encounter errors. 55 |

56 |
57 |
58 |

How It Looks

59 |

60 | The colors are mostly (not all!) grayscale. 61 | A typical Lua code with lua-language-server's hover capability looks like the following image. 62 | An autocmd sets cursorline only in the focused window so it is easier to keep track of where the cursor is in a multi-window layout. 63 |

64 |
65 | Preview 66 |
67 |
68 |

69 | The colors are deliberately chosen to look decent and non-distracting in both transparent and opague terminal windows. 70 | The previous image shows Neovim in iTerm2 on MacOS. 71 | The following image shows an identical layout in an opague Alacritty window on EndeavourOS: 72 |

73 |
74 | Preview 75 |
76 |
77 |

78 | The following image shows how Neovim looks like with the nvim-tree window toggled open. 79 | It also shows how a diagnostic error is displayed inside the buffer and in the tree view. 80 | The TODO item is highlighted and the contextual location of the cursor is shown in the statusline thanks to nvim-treesitter. 81 |

82 |
83 | Preview 84 |
85 |
86 |

87 | The following image shows another essential IDE feature: a debugging capability, thanks to nvim-dap. 88 | Slightly different from other configs, this project does not use nvim-dap-ui, nvim-dap-python, etc.. 89 | Instead, we rely completely on what nvim-dap offers. 90 |

91 |
92 | Preview 93 |
94 |
95 |

96 | By default, only the normal buffer window is shown, with red dash(es) indicating breakpoint location(s) and a blue arrow indicating the current position in program execution. 97 | All widgets such as the call stack (bottom left), the scopes (top right), and REPL (bottom right) only appear when the user toggles them. 98 | This is deliberate, since not all widgets are used all the time and will simply be a distraction if they are always present. 99 |

100 |
101 |
102 |

Others

103 |

104 | While we do not think startup time matters, some people apparently do care. 105 | Last time we check, our startup time is ~7-15 ms on a maxed-out Lenovo Legion Pro 7i 2024, as shown below by Lazy's profile. 106 |

107 |
108 | Preview 109 |
110 |

111 | The startup time is still very short in older hardwares. 112 | On our 2015 MacBook Pro with Arch, it is around ~28-35ms as shown below 113 |

114 |
115 | Preview 116 |
117 |
118 | -------------------------------------------------------------------------------- /assets/images/debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rezhaTanuharja/minimalistNVIM/8e3deaee5bf8d121d0ec62f7360c90a27557a232/assets/images/debug.png -------------------------------------------------------------------------------- /assets/images/features.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rezhaTanuharja/minimalistNVIM/8e3deaee5bf8d121d0ec62f7360c90a27557a232/assets/images/features.png -------------------------------------------------------------------------------- /assets/images/lsp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rezhaTanuharja/minimalistNVIM/8e3deaee5bf8d121d0ec62f7360c90a27557a232/assets/images/lsp.png -------------------------------------------------------------------------------- /assets/images/lsp_linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rezhaTanuharja/minimalistNVIM/8e3deaee5bf8d121d0ec62f7360c90a27557a232/assets/images/lsp_linux.png -------------------------------------------------------------------------------- /assets/images/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rezhaTanuharja/minimalistNVIM/8e3deaee5bf8d121d0ec62f7360c90a27557a232/assets/images/preview.png -------------------------------------------------------------------------------- /assets/images/startup_legion.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rezhaTanuharja/minimalistNVIM/8e3deaee5bf8d121d0ec62f7360c90a27557a232/assets/images/startup_legion.jpeg -------------------------------------------------------------------------------- /assets/images/startup_mbp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rezhaTanuharja/minimalistNVIM/8e3deaee5bf8d121d0ec62f7360c90a27557a232/assets/images/startup_mbp.png -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file init.lua 3 | -- 4 | -- @brief 5 | -- The starting point of the Neovim config 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-10-12 9 | -- 10 | 11 | 12 | -- list of all unnecessary providers 13 | 14 | local disabled_providers = { 15 | "node", 16 | "perl", 17 | "ruby", 18 | } 19 | 20 | for _, provider in pairs(disabled_providers) do 21 | vim.g["loaded_" .. provider .. "_provider"] = 0 22 | end 23 | 24 | 25 | -- list of all config files 26 | 27 | local config_files = { 28 | "options", 29 | "keymaps", 30 | "colors", 31 | "diagnostics", 32 | "statusline", 33 | "plugins", 34 | "lsp", 35 | } 36 | 37 | for _, file in pairs(config_files) do 38 | 39 | local success = pcall(require, file) 40 | if not success then 41 | vim.notify("Failed to load a config file " .. file) 42 | break 43 | end 44 | 45 | end 46 | -------------------------------------------------------------------------------- /lsp/clangd.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lsp/clangd.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the clangd LSP 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2025-03-28 9 | -- 10 | 11 | 12 | return { 13 | 14 | filetypes = {"c", "cpp"}, 15 | 16 | cmd = {"clangd", "--background-index", "--clang-tidy", "--log=verbose"}, 17 | 18 | root_markers = { ".git", "compile_commands.json" }, 19 | 20 | init_options = { 21 | fallbackFlag = {"-std=c++17"}, 22 | }, 23 | 24 | settings = {}, 25 | 26 | } 27 | -------------------------------------------------------------------------------- /lsp/pyright.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lsp/pyright.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the Pyright LSP 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2025-03-28 9 | -- 10 | 11 | 12 | return { 13 | 14 | filetypes = { "python" }, 15 | 16 | cmd = {"pyright-langserver", "--stdio"}, 17 | 18 | root_markers = { ".git", "pyproject.toml" }, 19 | 20 | settings = { 21 | pyright = { 22 | disableOrganizeImports = true, 23 | }, 24 | python = { 25 | analysis = { 26 | autoImportCompletions= true, 27 | autoSeachPaths = false, 28 | diagnosticMode = "openFilesOnly", 29 | typeCheckingMode = "basic", 30 | diagnosticSeverityOverrides = { 31 | reportPrivateImportUsage = "none", 32 | }, 33 | } 34 | }, 35 | }, 36 | 37 | } 38 | -------------------------------------------------------------------------------- /lsp/ruff.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lsp/ruff.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the Ruff LSP 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2025-03-28 9 | -- 10 | 11 | 12 | return { 13 | 14 | filetypes = { "python" }, 15 | 16 | cmd = { "ruff", "server" }, 17 | 18 | root_markers = { ".git", "pyproject.toml" }, 19 | 20 | init_options = { 21 | settings = { 22 | organizeImports = true, 23 | lint = { 24 | extendSelect = { 25 | "A", 26 | "ARG", 27 | "B", 28 | "COM", 29 | "C4", 30 | "DOC", 31 | "FBT", 32 | "I", 33 | "ICN", 34 | "N", 35 | "PERF", 36 | "PL", 37 | "Q", 38 | "RET", 39 | "RUF", 40 | "SIM", 41 | "SLF", 42 | "TID", 43 | "W", 44 | }, 45 | }, 46 | }, 47 | }, 48 | 49 | settings = {}, 50 | 51 | } 52 | -------------------------------------------------------------------------------- /lsp/texlab.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lsp/ruff.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the TexLab LSP 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2025-03-28 9 | -- 10 | 11 | 12 | return { 13 | 14 | filetypes = { "tex", "plaintex", "bib" }, 15 | 16 | cmd = { "texlab" }, 17 | 18 | root_markers = { ".git", "main.tex" }, 19 | 20 | settings = { 21 | 22 | texlab = { 23 | 24 | bibtexFormatter = "texlab", 25 | 26 | build = { 27 | onSave = false, 28 | onType = false, 29 | }, 30 | 31 | diagnosticDelay = 100, 32 | formatterLineLength = 80, 33 | 34 | forwardSearch = { 35 | args = {}, 36 | }, 37 | 38 | } 39 | 40 | }, 41 | 42 | single_file_support = true, 43 | 44 | } 45 | -------------------------------------------------------------------------------- /lsp/typescript-language-server.lua: -------------------------------------------------------------------------------- 1 | return { 2 | 3 | filetypes = { "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx" }, 4 | 5 | cmd = {"typescript-language-server", "--stdio"}, 6 | 7 | root_markers = { ".git", "package.json" }, 8 | 9 | init_options = { 10 | hostInfo = "neovim", 11 | }, 12 | 13 | settings = {}, 14 | 15 | } 16 | -------------------------------------------------------------------------------- /lsp/vscode-eslint-language-server.lua: -------------------------------------------------------------------------------- 1 | 2 | return { 3 | 4 | filetypes = { "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx" }, 5 | 6 | cmd = {"vscode-eslint-language-server", "--stdio"}, 7 | 8 | root_markers = { ".git", "package.json" }, 9 | 10 | on_attach = function(client, bufnr) 11 | vim.api.nvim_create_autocmd("BufWritePost", { 12 | buffer = bufnr, 13 | command = "silent !npx prettier % --write", 14 | }) 15 | end, 16 | 17 | settings = { 18 | codeAction = { 19 | disableRuleComment = { 20 | enable = true, 21 | location = "separateLine" 22 | }, 23 | showDocumentation = { 24 | enable = true 25 | } 26 | }, 27 | codeActionOnSave = { 28 | enable = false, 29 | mode = "all" 30 | }, 31 | experimental = { 32 | useFlatConfig = false 33 | }, 34 | format = true, 35 | nodePath = "", 36 | onIgnoredFiles = "off", 37 | problems = { 38 | shortenToSingleLine = false 39 | }, 40 | quiet = false, 41 | rulesCustomizations = {}, 42 | run = "onType", 43 | useESLintClass = false, 44 | validate = "on", 45 | workingDirectory = { 46 | mode = "location" 47 | } 48 | }, 49 | 50 | } 51 | -------------------------------------------------------------------------------- /lua/colors.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/colors.lua @brief 3 | -- Change some of the highlight groups 4 | -- 5 | -- @author Tanuharja, R.A. 6 | -- @date 2024-12-20 7 | -- 8 | 9 | 10 | local group_styles = { 11 | 12 | ["Normal"] = { fg = "#CCCCCC", bg = "None" }, 13 | ["NormalFloat"] = { fg = "#CCCCCC", bg = "None" }, 14 | 15 | ["String"] = { fg = "#D6DFD4" }, 16 | ["Comment"] = { fg = "#777777" }, 17 | 18 | ["Identifier"] = { fg = "#DDDDDD", bold = true }, 19 | ["Statement"] = { fg = "#EEEEEE", bold = true }, 20 | ["Special"] = { fg = "#999ECF", bold = false }, 21 | 22 | ["Function"] = { fg = "#999ECF" }, 23 | ["Constant"] = { fg = "#CCCCCC" }, 24 | 25 | ["DiffAdd"] = { fg = "NvimLightYellow" }, 26 | ["DiffDelete"] = { fg = "#666666" }, 27 | ["DiffText"] = { fg = "NvimLightYellow", bg = "None" }, 28 | ["DiffChange"] = { fg = "None", bg = "None" }, 29 | 30 | ["Changed"] = { fg = "#EEEEEE", bg = "None" }, 31 | 32 | ["Error"] = { fg = "#FFFFFF", bg = "None", bold = true }, 33 | 34 | ["QuickFixLine"] = { fg = "#CCCCCC", bold = true }, 35 | 36 | ["Pmenu"] = { fg = "#DDDDDD", bg = "#222222" }, 37 | ["PmenuSel"] = { fg = "#CCCCCC", bg = "#444444" }, 38 | 39 | ["Question"] = { fg = "#666666" }, 40 | ["Directory"] = { fg = "#777777" }, 41 | 42 | ["MsgSeparator"] = { fg = "#EEEEEE", bg = "#444444" }, 43 | ["MoreMsg"] = { fg = "#EEEEEE", bg = "#444444" }, 44 | 45 | ["StatusLine"] = { fg = "#EEEEEE", bg = "#333333" }, 46 | 47 | ["Folded"] = { fg = "#444444" }, 48 | ["MatchParen"] = { fg = "#FFFFFF", bold = true }, 49 | ["WinSeparator"] = { fg = "#444444" }, 50 | 51 | ["Search"] = { fg = "#000000", bg = "#777777" }, 52 | ["CurSearch"] = { fg = "#000000", bg = "#AAAAAA" }, 53 | 54 | ["DiagnosticUnnecessary"] = { fg = "#888888" }, 55 | 56 | ["Todo"] = { fg = "NvimLightYellow", bg = "None", bold = true }, 57 | 58 | ["@variable"] = { fg = "#CCCCCC" }, 59 | ["@string.documentation"] = { fg = "#777777" }, 60 | ["@comment.warning"] = { fg = "#000000", bg = "NvimLightYellow", bold = true }, 61 | ["@comment.error"] = { fg = "#000000", bg = "NvimLightRed", bold = true }, 62 | ["@comment.note"] = { fg = "#000000", bg = "#D3EDE7", bold = true }, 63 | 64 | ["LspSignatureActiveParameter"] = { bg = "None" }, 65 | 66 | } 67 | 68 | for group, style in pairs(group_styles) do 69 | vim.api.nvim_set_hl(0, group, style) 70 | end 71 | -------------------------------------------------------------------------------- /lua/diagnostics.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/diagnostics.lua 3 | -- 4 | -- @brief 5 | -- Configure the behaviour of diagnostics 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-12-20 9 | -- 10 | 11 | 12 | vim.diagnostic.config { 13 | 14 | virtual_text = false, 15 | severity_sort = true, 16 | update_in_insert = false, 17 | 18 | signs = { 19 | 20 | text = { 21 | [vim.diagnostic.severity.ERROR] = "", 22 | [vim.diagnostic.severity.WARN] = "", 23 | [vim.diagnostic.severity.HINT] = "", 24 | [vim.diagnostic.severity.INFO] = "", 25 | }, 26 | 27 | linehl = { 28 | [vim.diagnostic.severity.ERROR] = "ErrorMsg", 29 | [vim.diagnostic.severity.WARN] = "None", 30 | [vim.diagnostic.severity.HINT] = "None", 31 | [vim.diagnostic.severity.INFO] = "None", 32 | }, 33 | 34 | numhl = { 35 | [vim.diagnostic.severity.ERROR] = "ErrorMsg", 36 | [vim.diagnostic.severity.WARN] = "WarningMsg", 37 | [vim.diagnostic.severity.HINT] = "DiagnosticHint", 38 | [vim.diagnostic.severity.INFO] = "DiagnosticHint", 39 | }, 40 | 41 | }, 42 | 43 | float = { 44 | title = " Diagnostic ", 45 | header = "", 46 | border = "single", 47 | scope = "line", 48 | }, 49 | 50 | } 51 | 52 | vim.opt["signcolumn"] = "yes" 53 | 54 | vim.keymap.set("n", "gl", vim.diagnostic.open_float) 55 | vim.keymap.set("n", "gq", vim.diagnostic.setqflist) 56 | 57 | -- removes underline 58 | vim.api.nvim_set_hl(0, "DiagnosticUnderlineError", { sp = "None" } ) 59 | vim.api.nvim_set_hl(0, "DiagnosticUnderlineWarn", { sp = "None" } ) 60 | vim.api.nvim_set_hl(0, "DiagnosticUnderlineHint", { sp = "None" } ) 61 | vim.api.nvim_set_hl(0, "DiagnosticUnderlineInfo", { sp = "None" } ) 62 | -------------------------------------------------------------------------------- /lua/keymaps.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/keymaps.lua 3 | -- 4 | -- @brief 5 | -- The file to set general keymaps 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-10-12 9 | -- 10 | 11 | 12 | vim.g.mapleader = " " 13 | vim.g.maplocalleader = " " 14 | 15 | vim.keymap.set("", "", "", { desc = "space is only a leader key now" }) 16 | 17 | local mode_keymaps = { 18 | 19 | normal = { 20 | 21 | ["x"] = { action = '"_x', desc = 'delete a character without storing it in the clipboard' }, 22 | 23 | ["qq"] = { action = vim.cmd.quit, desc = "close the current window" }, 24 | ["w"] = { action = vim.cmd.write, desc = "save changes in the current buffer" }, 25 | 26 | [""] = { action = "h", desc = "move focus to the pane on the left" }, 27 | [""] = { action = "j", desc = "move focus to the pane below" }, 28 | [""] = { action = "k", desc = "move focus to the pane above" }, 29 | [""] = { action = "l", desc = "move focus to the pane on the right" }, 30 | 31 | [""] = { action = vim.cmd.bprev, desc = "switch to the prev buffer" }, 32 | [""] = { action = vim.cmd.bnext, desc = "switch to the next buffer" }, 33 | 34 | ["v"] = { action = vim.cmd.split, desc = "horizontal split" }, 35 | ["h"] = { action = vim.cmd.vsplit, desc = "vertical split" }, 36 | 37 | [""] = { action = "vertical resize -2", desc = "decrease rows in the current window" }, 38 | [""] = { action = "vertical resize +2", desc = "increase rows in the current window" }, 39 | [""] = { action = "horizontal resize -2", desc = "decrease columns in the current window" }, 40 | [""] = { action = "horizontal resize +2", desc = "increase columns in the current window" }, 41 | 42 | ["r"] = { action = "zR", desc = "unfold everything" }, 43 | ["m"] = { action = "zM", desc = "fold everything" }, 44 | 45 | [""] = { action = vim.cmd.nohlsearch, desc = "remove highlight from search results" }, 46 | 47 | ["j"] = { action = vim.cmd.copen, desc = "open the quickfix list" }, 48 | ["J"] = { action = vim.cmd.cclose, desc = "close the quickfix list" }, 49 | 50 | ["qj"] = { 51 | action = function() 52 | local success = pcall(vim.cmd, "cnext") 53 | if not success then 54 | local _ = pcall(vim.cmd, "cfirst") 55 | end 56 | end, 57 | desc = "navigate to the next quickfix item" 58 | }, 59 | 60 | ["qk"] = { 61 | action = function() 62 | local success = pcall(vim.cmd, "cprev") 63 | if not success then 64 | local _ = pcall(vim.cmd, "clast") 65 | end 66 | end, 67 | desc = "navigate to the prev quickfix item" 68 | }, 69 | 70 | ["ql"] = { 71 | action = function() 72 | local _ = pcall(vim.cmd, "cnewer") 73 | end, 74 | desc = "navigate to the next quickfix list" 75 | }, 76 | 77 | ["qh"] = { 78 | action = function() 79 | local _ = pcall(vim.cmd, "colder") 80 | end, 81 | desc = "navigate to the prev quickfix list" 82 | }, 83 | 84 | ["sd"] = { action = 'call setqflist([], " ")', desc = "create an empty quickfix list" }, 85 | ["sf"] = { 86 | action = function() 87 | local filename = vim.fn.expand("%") 88 | local line_number = vim.fn.line(".") 89 | local column_number = vim.fn.col(".") 90 | local line_text = vim.fn.getline(".") 91 | 92 | local entry = { 93 | filename = filename, 94 | lnum = line_number, 95 | col = column_number, 96 | text = line_text, 97 | } 98 | 99 | vim.fn.setqflist( {entry}, "a" ) 100 | end, 101 | desc = "add a line into the current quickfix list" 102 | }, 103 | 104 | }, 105 | 106 | visual = { 107 | 108 | ["H"] = { action = "i"] = { action = ":s/\\(\\s*\\)/\\1", desc = "spawn multiple cursors at the start of highlighted lines" }, 114 | ["a"] = { action = ":s/$/", desc = "spawn multiple cursors at the end of highlighted lines" }, 115 | 116 | ['"'] = { action = 'c""P', desc = "put highlighted text inside pairing chars" }, 117 | ["["] = { action = "c[]P", desc = "put highlighted text inside pairing chars" }, 118 | ["("] = { action = "c()P", desc = "put highlighted text inside pairing chars" }, 119 | ["{"] = { action = "c{}P", desc = "put highlighted text inside pairing chars" }, 120 | ["'"] = { action = "c''P", desc = "put highlighted text inside pairing chars" }, 121 | ["`"] = { action = "c``P", desc = "put highlighted text inside pairing chars" }, 122 | 123 | }, 124 | 125 | } 126 | 127 | for mode, keymaps in pairs(mode_keymaps) do 128 | 129 | local mode_initial = mode:sub(1, 1) 130 | 131 | for key, maps in pairs(keymaps) do 132 | vim.keymap.set( mode_initial, key, maps.action, { noremap = true, silent = true, desc = maps.desc } ) 133 | end 134 | 135 | end 136 | -------------------------------------------------------------------------------- /lua/lsp.lua: -------------------------------------------------------------------------------- 1 | servers = { 2 | "clangd", 3 | "pyright", 4 | "ruff", 5 | "texlab", 6 | "typescript-language-server", 7 | "vscode-eslint-language-server", 8 | } 9 | 10 | for _, server in pairs(servers) do 11 | if vim.fn.executable(server) == 1 then 12 | vim.lsp.enable(server) 13 | end 14 | end 15 | 16 | local function refresh() 17 | 18 | vim.lsp.stop_client(vim.lsp.get_clients(), true) 19 | 20 | vim.defer_fn( 21 | function() 22 | local window_buffer_map = {} 23 | for _, window_id in pairs(vim.api.nvim_tabpage_list_wins(0)) do 24 | local buffer_id = vim.api.nvim_win_get_buf(window_id) 25 | table.insert(window_buffer_map, { window_id = window_id, buffer_id = buffer_id}) 26 | end 27 | 28 | if #window_buffer_map > 0 then 29 | vim.cmd("bufdo if &modifiable | write | edit | endif") 30 | end 31 | 32 | for _, entry in pairs(window_buffer_map) do 33 | vim.api.nvim_win_set_buf(entry.window_id, entry.buffer_id) 34 | end 35 | end, 36 | 100 37 | ) 38 | 39 | end 40 | 41 | vim.keymap.set("n", "gn", refresh) 42 | 43 | vim.lsp.config( "*", { 44 | 45 | on_init = function(client) 46 | client.offset_encoding = "utf-8" 47 | end, 48 | 49 | on_attach = function(client, buffer) 50 | 51 | vim.bo[buffer].formatexpr = "v:lua.vim.lsp.formatexpr" 52 | 53 | if client.name == 'ruff' then 54 | client.server_capabilities.hoverProvider = false 55 | end 56 | 57 | if client:supports_method("textDocument/formatting") then 58 | 59 | vim.api.nvim_create_autocmd("BufWritePre", { 60 | buffer = buffer, 61 | callback = function() 62 | vim.lsp.buf.format({ buffer = buffer, id = client.id }) 63 | end, 64 | }) 65 | 66 | end 67 | 68 | end, 69 | }) 70 | 71 | vim.api.nvim_create_autocmd("FileType", { 72 | pattern = "markdown", 73 | callback = function() 74 | 75 | local query = [[ 76 | (backslash_escape) @escape 77 | ]] 78 | 79 | vim.treesitter.query.set("markdown_inline", "conceal_backslash", query) 80 | 81 | local function conceal_backslash() 82 | local bufnr = vim.api.nvim_get_current_buf() 83 | local parser = vim.treesitter.get_parser(bufnr, "markdown_inline") 84 | local tree = parser:parse()[1] 85 | local query_obj = vim.treesitter.query.get("markdown_inline", "conceal_backslash") 86 | 87 | for _, node in query_obj:iter_captures(tree:root(), bufnr, 0, -1) do 88 | local start_row, start_col, end_row, end_col = node:range() 89 | vim.api.nvim_buf_set_extmark( 90 | bufnr, vim.api.nvim_create_namespace("conceal"), start_row, start_col, { 91 | end_col = start_col + 1, 92 | conceal = '', 93 | } 94 | ) 95 | end 96 | end 97 | 98 | vim.api.nvim_buf_attach(0, false, { 99 | on_lines = function() 100 | vim.schedule(conceal_backslash) 101 | end, 102 | }) 103 | conceal_backslash() 104 | end, 105 | }) 106 | 107 | vim.api.nvim_set_hl(0, "@string.escape.markdown_inline", { link = "@spell"}) 108 | -------------------------------------------------------------------------------- /lua/options.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/options.lua 3 | -- 4 | -- @brief 5 | -- The file to set general Neovim behaviours 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-10-12 9 | -- 10 | 11 | 12 | local options = { 13 | 14 | -- user interface 15 | 16 | termguicolors = true, -- enable 24-bit RGB color 17 | mouse = "", -- disable mouse in neovim 18 | clipboard = "unnamedplus", -- makes neovim use the system clipboard 19 | winborder = "single", -- all floating window has a single border 20 | cursorline = true, -- highlight the row where the cursor is 21 | showtabline = 0, -- hide tabline 22 | inccommand = "split", -- when performing substitution, show preview at the bottom 23 | timeoutlen = 300, -- time for user to finish a key combination 24 | updatetime = 200, -- faster completion 25 | virtualedit = "block", -- enable highlighting empty spaces 26 | splitbelow = true, -- when splitting horizontally, new window goes below 27 | splitright = true, -- when splitting vertically, new window goes to the right 28 | showmode = false, -- mode will be shown by statusline instead 29 | cmdheight = 0, -- hide the command line when not typing command 30 | path = ".,,**", -- find-like operations works recursively 31 | 32 | -- tabs and indentations 33 | 34 | expandtab = true, -- convert tabs into spaces 35 | shiftwidth = 2, -- the number of spaces for each indentation 36 | tabstop = 2, -- the number of spaces for each tab 37 | 38 | -- number columns 39 | 40 | relativenumber = false, -- don't display relative line numbers 41 | number = true, -- display the current line number 42 | numberwidth = 3, -- the column width to display line numbers 43 | 44 | -- text display 45 | 46 | foldlevelstart = 99, -- open files with all folds open 47 | foldtext = "", -- keep the first line of folded section visible 48 | foldmethod = "expr", -- assign fold based on expressions 49 | 50 | foldexpr = "nvim_treesitter#foldexpr()", 51 | 52 | wrap = false, -- do not wrap lines because it looks ugly and inconsistent 53 | smartindent = true, -- automatic indentations 54 | scrolloff = 99, -- keep cursorline in the middle 55 | sidescrolloff = 6, -- minimul number of columns to the left and right of cursor 56 | 57 | fillchars = { 58 | eob = " ", -- removes annoying tilde at the bottom of short files 59 | fold = "-", -- replace dots with horizontal line to indicate folded sections 60 | stl = "-", -- fill empty spaces in the statusline with this 61 | }, 62 | 63 | pumheight = 8, -- specify the max height of pop-up menu 64 | pumwidth = 20, -- specify the min width of pop-up menu 65 | pumblend = 15, -- semi transparent pop-up menu 66 | 67 | -- text search 68 | 69 | ignorecase = true, -- make search case-insensitive 70 | smartcase = true, -- but if our search contains uppercase(s), it becomes case-sensitive 71 | 72 | -- miscellaneous 73 | 74 | backup = false, -- do not create a backup file 75 | swapfile = false, -- do not create a swap file 76 | undofile = false, -- undo is limited to the current session 77 | fileencoding = "utf-8", -- the encoding written to a file 78 | 79 | } 80 | 81 | for parameter, value in pairs(options) do 82 | vim.opt[parameter] = value 83 | end 84 | -------------------------------------------------------------------------------- /lua/plugins/autopairs.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/plugins/autopairs.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the plugin autopairs 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-08-31 9 | -- 10 | 11 | 12 | return { 13 | 14 | "windwp/nvim-autopairs", 15 | 16 | event = "InsertEnter", 17 | 18 | opts = { 19 | 20 | check_ts = true, 21 | 22 | ts_config = { 23 | lua = { "string" }, 24 | python = { "string" }, 25 | }, 26 | 27 | disable_filetype = { "TelescopePrompt", "spectre_panel" }, 28 | 29 | fast_wrap = { 30 | map = "", 31 | chars = { "{", "[", "(", '"', "'" }, 32 | pattern = [=[[%'%"%>%]%)%}%,]]=], 33 | offset = 0, 34 | end_key = "k", 35 | keys = "qwertyuiopzxcvbnmasdfghjkl", 36 | check_comma = true, 37 | highlight = "PmenuSel", 38 | highlight_grey = "LineNr", 39 | }, 40 | 41 | }, 42 | 43 | } 44 | -------------------------------------------------------------------------------- /lua/plugins/bbye.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/plugins/bbye.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the plugin bbye 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-08-31 9 | -- 10 | 11 | 12 | return { 13 | 14 | "moll/vim-bbye", 15 | 16 | event = "UIEnter", 17 | 18 | config = function() 19 | vim.keymap.set("n", "c", "Bdelete!") 20 | vim.keymap.set("n", "n", "bufdo :Bdelete!") 21 | end 22 | 23 | } 24 | -------------------------------------------------------------------------------- /lua/plugins/blankline.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/plugins/blankline.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the plugin blankline 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-08-31 9 | -- 10 | 11 | 12 | return { 13 | 14 | "lukas-reineke/indent-blankline.nvim", 15 | 16 | ft = { "python", "lua", "typescript", "typescriptreact" }, 17 | 18 | config = function() 19 | 20 | local success, blankline = pcall(require, "ibl") 21 | if not success then 22 | vim.notify("Failed to load plugin: blankline") 23 | return 24 | end 25 | 26 | blankline.setup { 27 | 28 | indent = {char = "│"}, 29 | exclude = { 30 | filetypes = { "tex", "plaintex", "bib" }, 31 | }, 32 | 33 | scope = { 34 | enabled = true, 35 | show_start = false, 36 | show_end = true, 37 | }, 38 | 39 | } 40 | 41 | end, 42 | 43 | } 44 | -------------------------------------------------------------------------------- /lua/plugins/blink.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/plugins/blink.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the plugin blink 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-11-02 9 | -- 10 | 11 | 12 | return { 13 | 14 | "saghen/blink.cmp", 15 | 16 | event = "UIEnter", 17 | 18 | version = "1.*", 19 | 20 | opts = { 21 | 22 | keymap = { 23 | 24 | [""] = { "accept", "fallback" }, 25 | [""] = { "show", "show_documentation", "hide_documentation" }, 26 | 27 | [""] = { "select_prev", "fallback" }, 28 | [""] = { "select_next", "fallback" }, 29 | 30 | [""] = { "snippet_forward", "fallback" }, 31 | [""] = { "snippet_backward", "fallback" }, 32 | 33 | }, 34 | 35 | completion = { 36 | 37 | accept = { 38 | auto_brackets = { enabled = false }, 39 | }, 40 | 41 | documentation = { 42 | 43 | auto_show = false, 44 | 45 | window = { 46 | 47 | min_width = 10, 48 | max_width = 60, 49 | max_height = 20, 50 | border = "single", 51 | scrollbar = false, 52 | 53 | winhighlight = "Normal:NormalFloat,FloatBorder:FloatBorder,Search:None,Pmenu:Normal", 54 | 55 | direction_priority = { 56 | menu_north = { "e", "w", "n", "s" }, 57 | menu_south = { "e", "w", "s", "n" }, 58 | } 59 | 60 | }, 61 | 62 | 63 | }, 64 | 65 | ghost_text = { 66 | enabled = false, 67 | }, 68 | 69 | keyword = { 70 | range = "full" 71 | }, 72 | 73 | list = { 74 | selection = { 75 | preselect = true, 76 | auto_insert = true, 77 | }, 78 | }, 79 | 80 | menu = { 81 | 82 | auto_show = true, 83 | min_width = 15, 84 | max_height = 10, 85 | border = "single", 86 | 87 | scrollbar = false, 88 | 89 | winhighlight = "Normal:NormalFloat,FloatBorder:FloatBorder,Search:None,Pmenu:Normal", 90 | 91 | direction_priority = { "s", "n" }, 92 | 93 | draw = { 94 | columns = { 95 | { "label", "kind", gap = 1 }, 96 | }, 97 | }, 98 | 99 | }, 100 | 101 | }, 102 | 103 | sources = { 104 | 105 | default = { 106 | "snippets", 107 | "lsp", 108 | "path", 109 | "buffer", 110 | }, 111 | 112 | providers = { 113 | 114 | lsp = { 115 | 116 | name = "LSP", 117 | module = "blink.cmp.sources.lsp", 118 | 119 | enabled = true, 120 | transform_items = nil, 121 | should_show_items = true, 122 | max_items = nil, 123 | min_keyword_length = 0, 124 | fallbacks = { "buffer", "path", }, 125 | score_offset = 0, 126 | override = nil, 127 | 128 | }, 129 | 130 | path = { 131 | 132 | name = "Path", 133 | module = "blink.cmp.sources.path", 134 | min_keyword_length = 2, 135 | score_offset = 0, 136 | 137 | opts = { 138 | trailing_slash = false, 139 | label_trailing_slash = true, 140 | get_cwd = function(context) return vim.fn.expand( ("#%d:p:h"):format(context.bufnr) ) end, 141 | show_hidden_files_by_default = false, 142 | } 143 | 144 | }, 145 | 146 | snippets = { 147 | 148 | name = "Snippets", 149 | module = "blink.cmp.sources.snippets", 150 | min_keyword_length = 2, 151 | score_offset = 3, 152 | 153 | opts = { 154 | friendly_snippets = true, 155 | search_paths = { vim.fn.stdpath("config") .. "/snippets" }, 156 | global_snippets = { "all" }, 157 | extended_filetypes = {}, 158 | ignored_filetypes = {}, 159 | } 160 | 161 | }, 162 | 163 | buffer = { 164 | 165 | name = "Buffer", 166 | module = "blink.cmp.sources.buffer", 167 | min_keyword_length = 5, 168 | 169 | }, 170 | }, 171 | 172 | }, 173 | 174 | fuzzy = { 175 | 176 | implementation = "prefer_rust_with_warning", 177 | 178 | use_frecency = true, 179 | use_proximity = false, 180 | 181 | sorts = { 182 | "exact", 183 | "score", 184 | "sort_text" 185 | }, 186 | 187 | prebuilt_binaries = { 188 | download = true, 189 | }, 190 | 191 | 192 | }, 193 | 194 | 195 | }, 196 | 197 | } 198 | -------------------------------------------------------------------------------- /lua/plugins/gitsigns.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/plugins/gitsigns.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the plugin gitsigns 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-08-31 9 | -- 10 | 11 | 12 | return { 13 | 14 | "lewis6991/gitsigns.nvim", 15 | 16 | event = "UIEnter", 17 | 18 | config = function() 19 | 20 | local success, gitsigns = pcall(require, "gitsigns") 21 | if not success then 22 | vim.notify("Error loading plugin: gitsigns") 23 | return 24 | end 25 | 26 | gitsigns.setup { 27 | 28 | signs = { 29 | add = {text = "+"}, 30 | change = {text = "*"}, 31 | delete = {text = "-"}, 32 | topdelete = {text = "-"}, 33 | changedelete = {text = "*"}, 34 | }, 35 | 36 | signcolumn = true, 37 | numhl = false, 38 | linehl = false, 39 | word_diff = false, 40 | 41 | watch_gitdir = { 42 | interval = 1000, 43 | follow_files = true, 44 | }, 45 | 46 | attach_to_untracked = true, 47 | current_line_blame = false, 48 | 49 | current_line_blame_opts = { 50 | virt_text = true, 51 | virt_text_pos = "eol", 52 | delay = 1000, 53 | ignore_whitespace = true, 54 | }, 55 | 56 | sign_priority = 6, 57 | update_debounce = 100, 58 | status_formatter = nil, 59 | max_file_length = 10000, 60 | 61 | preview_config = { 62 | border = "single", 63 | style = "minimal", 64 | relative = "cursor", 65 | row = 0, 66 | col = 1, 67 | }, 68 | 69 | } 70 | 71 | vim.keymap.set("n", "k", gitsigns.preview_hunk) 72 | vim.keymap.set("n", "u", gitsigns.reset_hunk) 73 | vim.keymap.set("n", "x", gitsigns.diffthis) 74 | vim.keymap.set("n", "z", "wincmd p | q") 75 | 76 | vim.keymap.set("n", "", gitsigns.stage_hunk) 77 | vim.keymap.set("n", "", gitsigns.stage_buffer) 78 | vim.keymap.set("n", "", gitsigns.blame_line) 79 | 80 | vim.keymap.set("n", "gnh", function() gitsigns.nav_hunk("next") end) 81 | vim.keymap.set("n", "gph", function() gitsigns.nav_hunk("prev") end) 82 | 83 | vim.api.nvim_set_hl(0, "GitSignsAddInline", { fg = "#EEEEEE", bg = "#444444" }) 84 | vim.api.nvim_set_hl(0, "GitSignsDeleteInline", { fg = "#AAAAAA", bg = "#333333" }) 85 | vim.api.nvim_set_hl(0, "GitSignsStagedAdd", { fg = "#AAAAAA" }) 86 | vim.api.nvim_set_hl(0, "GitSignsStagedChange", { fg = "#AAAAAA" }) 87 | vim.api.nvim_set_hl(0, "GitSignsStagedChangeDelete", { fg = "#AAAAAA" }) 88 | 89 | end 90 | 91 | } 92 | -------------------------------------------------------------------------------- /lua/plugins/init.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/plugins/init.lua 3 | -- 4 | -- @brief 5 | -- The initialization file to load external plugins 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-08-31 9 | -- 10 | 11 | 12 | local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" 13 | 14 | -- install lazy from github repository if it is not installed 15 | if not (vim.uv or vim.loop).fs_stat(lazypath) then 16 | 17 | -- github repository for lazy 18 | local lazyrepo = "https://github.com/folke/lazy.nvim.git" 19 | 20 | -- command to clone repository 21 | local out = vim.fn.system({ 22 | "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath 23 | }) 24 | 25 | if vim.v.shell_error ~= 0 then 26 | vim.api.nvim_echo({ 27 | { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, 28 | { out, "WarningMsg" }, 29 | { "\nPress any key to exit..." }, 30 | }, true, {}) 31 | vim.fn.getchar() 32 | os.exit(1) 33 | end 34 | 35 | end 36 | 37 | vim.opt.rtp:prepend(lazypath) 38 | 39 | -- use protected call to load lazy 40 | local success, lazy = pcall(require, "lazy") 41 | if not success then 42 | vim.notify("Failed to load plugin: lazy") 43 | return 44 | end 45 | 46 | -- all plugin settings are in this directory 47 | local location = "plugins." 48 | 49 | -- specify manually the plugins to load 50 | lazy.setup { 51 | 52 | dev = { 53 | path = "~/.config/nvim/projects", 54 | fallback = false, 55 | }, 56 | 57 | lockfile = nil, 58 | 59 | rocks = { 60 | enabled = false, 61 | hererocks = false, 62 | }, 63 | 64 | ui = { 65 | border = "single", 66 | icons = { 67 | cmd = "", 68 | config = "", 69 | event = "", 70 | favorite = "", 71 | ft = "", 72 | init = "", 73 | import = "", 74 | keys = "", 75 | lazy = "", 76 | loaded = "●", 77 | not_loaded = "○", 78 | plugin = "", 79 | runtime = "", 80 | require = "", 81 | source = "", 82 | start = "", 83 | task = "✔ ", 84 | list = { 85 | "●", 86 | "➜", 87 | "★", 88 | "‒", 89 | }, 90 | }, 91 | }, 92 | 93 | change_detection = { 94 | enabled = false, 95 | notify = false, 96 | }, 97 | 98 | performance = { 99 | 100 | cache = { 101 | enabled = true, 102 | }, 103 | 104 | reset_packpath = true, 105 | 106 | rtp = { 107 | reset = true, 108 | disabled_plugins = { 109 | "editorconfig", 110 | "gzip", 111 | "man", 112 | "netrwPlugin", 113 | "spellfile", 114 | "tarPlugin", 115 | "tohtml", 116 | "tutor", 117 | "zipPlugin", 118 | }, 119 | }, 120 | 121 | }, 122 | 123 | spec = { 124 | 125 | { import = location .. "blink" }, 126 | { import = location .. "gitsigns" }, 127 | { import = location .. "autopairs" }, 128 | { import = location .. "treesitter" }, 129 | { import = location .. "bbye" }, 130 | { import = location .. "blankline" }, 131 | { import = location .. "nvim-tree" }, 132 | { import = location .. "nvim-dap" }, 133 | { import = location .. "vimtex" }, 134 | 135 | { import = location .. "terminal" }, 136 | 137 | { import = location .. "molten" }, 138 | { import = location .. "otter" }, 139 | 140 | }, 141 | 142 | install = { colorscheme = { "default" } }, 143 | 144 | } 145 | -------------------------------------------------------------------------------- /lua/plugins/molten.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "benlubas/molten-nvim", 3 | version = "^1.0.0", 4 | 5 | ft = {"python", "quarto"}, 6 | 7 | dependencies = { 8 | 9 | "3rd/image.nvim", 10 | 11 | opts = { 12 | backend = "kitty", 13 | integrations = {}, 14 | max_width = 100, 15 | max_height = 40, 16 | max_height_window_percentage = math.huge, 17 | max_width_window_percentage = math.huge, 18 | window_overlap_clear_enabled = false, 19 | window_overlap_clear_ft_ignore = {}, 20 | }, 21 | 22 | }, 23 | 24 | build = ":UpdateRemotePlugins", 25 | 26 | init = function() 27 | vim.g.molten_image_provider = "image.nvim" 28 | vim.g.molten_output_win_max_height = 40 29 | vim.g.molten_use_border = true 30 | vim.g.molten_auto_open_output = false 31 | vim.g.molten_image_location = "float" 32 | vim.g.molten_tick_rate = 200 33 | end, 34 | 35 | config = function() 36 | 37 | vim.keymap.set("n", "ai", "MoltenInit", { noremap = true, silent = true, desc = "initialize molten"}) 38 | 39 | local run_block = function() 40 | local node = vim.treesitter.get_node() 41 | local start_row, _, end_row, _ = vim.treesitter.get_node_range(node) 42 | vim.fn.MoltenEvaluateRange(start_row + 1, end_row) 43 | end 44 | 45 | vim.api.nvim_create_autocmd("User", { 46 | pattern = "MoltenInitPost", 47 | callback = function(arg) 48 | 49 | vim.opt_local.colorcolumn="80" 50 | 51 | vim.keymap.set("n", "ar", run_block, { buffer = arg.buf, desc = "reevaluate the current block"}) 52 | 53 | vim.keymap.set("n", "am", "MoltenReevaluateCell", { buffer = arg.buf, desc = "rerun cell"}) 54 | vim.keymap.set("v", "am", ":MoltenEvaluateVisual", { buffer = arg.buf, desc = "run highlighted code"}) 55 | 56 | vim.keymap.set("n", "ao", "MoltenShowOutput", { buffer = arg.buf, desc = "show outputs from the current cell"}) 57 | vim.keymap.set("n", "ah", "MoltenHideOutput", { buffer = arg.buf, desc = "hide outputs from the current cell"}) 58 | vim.keymap.set("n", "al", "MoltenEvaluateLine", { buffer = arg.buf, desc = "evaluate the current line"}) 59 | vim.keymap.set("n", "an", "MoltenNext", { buffer = arg.buf, desc = "move to the next cell"}) 60 | vim.keymap.set("n", "ap", "MoltenPrev", { buffer = arg.buf, desc = "move to the prev cell"}) 61 | vim.keymap.set("n", "aa", "MoltenReevaluateAll", { buffer = arg.buf, desc = "reevaluate all cells"}) 62 | vim.keymap.set("n", "ae", ":noautocmd MoltenEnterOutput", { buffer = arg.buf, desc = "enter the output window"}) 63 | vim.keymap.set("n", "af", "MoltenImagePopup", { buffer = arg.buf, desc = "open image in a new window"}) 64 | vim.keymap.set("n", "as", "MoltenDeinit", { buffer = arg.buf, desc = "stop molten"}) 65 | 66 | vim.keymap.set( 67 | "n", 68 | "ad", 69 | function() 70 | vim.cmd("MoltenEvaluateArgument import debugpy") 71 | vim.cmd("MoltenEvaluateArgument _ = debugpy.listen(('localhost', 5678))") 72 | end, 73 | { buffer = arg.buf, desc = "initialize debugger"} 74 | ) 75 | 76 | vim.keymap.set("n", "dd", "MoltenEvaluateArgument debugpy.breakpoint()", { buffer = arg.buf, desc = "enter virtual breakpoint"}) 77 | 78 | end, 79 | }) 80 | 81 | vim.api.nvim_create_autocmd("User", { 82 | pattern = "MoltenDeinitPost", 83 | callback = function(arg) 84 | 85 | vim.opt_local.colorcolumn="" 86 | 87 | vim.keymap.del("n", "ar", { buffer = arg.buf }) 88 | 89 | vim.keymap.del("n", "am", { buffer = arg.buf }) 90 | vim.keymap.del("v", "am", { buffer = arg.buf }) 91 | 92 | vim.keymap.del("n", "ao", { buffer = arg.buf }) 93 | vim.keymap.del("n", "ah", { buffer = arg.buf }) 94 | vim.keymap.del("n", "al", { buffer = arg.buf }) 95 | vim.keymap.del("n", "an", { buffer = arg.buf }) 96 | vim.keymap.del("n", "ap", { buffer = arg.buf }) 97 | vim.keymap.del("n", "aa", { buffer = arg.buf }) 98 | vim.keymap.del("n", "ae", { buffer = arg.buf }) 99 | vim.keymap.del("n", "af", { buffer = arg.buf }) 100 | vim.keymap.del("n", "as", { buffer = arg.buf }) 101 | 102 | vim.keymap.del("n", "ad", { buffer = arg.buf }) 103 | vim.keymap.del("n", "dd", { buffer = arg.buf }) 104 | 105 | end, 106 | }) 107 | 108 | end, 109 | 110 | } 111 | -------------------------------------------------------------------------------- /lua/plugins/nvim-dap.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/plugins/nvim-dap.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the plugin nvim-dap 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-10-13 9 | -- 10 | 11 | 12 | return { 13 | 14 | "mfussenegger/nvim-dap", 15 | 16 | ft = {"python", "c", "cpp"}, 17 | 18 | config = function() 19 | 20 | local dap = require("dap") 21 | 22 | dap.adapters.python = function(callback, config) 23 | 24 | if config.request == "launch" then 25 | 26 | callback({ 27 | type = "executable", 28 | command = "python3", 29 | args = { "-m", "debugpy.adapter" }, 30 | }) 31 | 32 | elseif config.request == "attach" then 33 | 34 | local port = config.connect.port 35 | local host = config.connect.host 36 | 37 | callback({ 38 | type = "server", 39 | port = port, 40 | host = host, 41 | options = { 42 | source_filetype = "python" 43 | } 44 | }) 45 | 46 | end 47 | 48 | end 49 | 50 | dap.configurations.python = { 51 | 52 | { 53 | type = "python", 54 | request = "launch", 55 | name = "Launch a debugging session", 56 | program = "${file}", 57 | pythonPath = function() 58 | return "python3" 59 | end, 60 | console = "integratedTerminal", 61 | }, 62 | 63 | { 64 | type = "python", 65 | request = "attach", 66 | name = "Attach a debugging session", 67 | connect = function() 68 | local host = vim.fn.input("Host: ") 69 | local port = tonumber(vim.fn.input("Port: ")) 70 | return {host = host, port = port} 71 | end, 72 | console = "integratedTerminal", 73 | }, 74 | 75 | { 76 | type = "python", 77 | request = "launch", 78 | name = "Launch a debugging session with arguments", 79 | program = "${file}", 80 | args = function() 81 | local args_string = vim.fn.input("Arguments: ") 82 | local utils = require("dap.utils") 83 | if utils.splitstr and vim.fn.has("nvim-0.10") == 1 then 84 | return utils.splitstr(args_string) 85 | end 86 | return vim.split(args_string, " +") 87 | end, 88 | pythonPath = function() 89 | return "python3" 90 | end, 91 | console = "integratedTerminal", 92 | }, 93 | 94 | } 95 | 96 | dap.configurations.quarto = { 97 | { 98 | type = "python", 99 | request = "attach", 100 | name = "Attach a debugging session", 101 | connect = { 102 | host = "127.0.0.1", 103 | port = "5678" 104 | }, 105 | console = "integratedTerminal", 106 | }, 107 | } 108 | 109 | dap.adapters.cpp = { 110 | type = "executable", 111 | command = "lldb-dap", 112 | name = "lldb", 113 | } 114 | 115 | dap.configurations.cpp = { 116 | { 117 | name = "Launch LLDB", 118 | type = "cpp", 119 | request = "launch", 120 | program = function() 121 | return vim.fn.input("Path to executable: ", vim.fn.getcwd() .. "/", "file") 122 | end, 123 | cwd = '${workspaceFolder}', 124 | stopOnEntry = false, 125 | args = {}, 126 | runInTerminal = false, 127 | } 128 | } 129 | 130 | vim.fn.sign_define( 131 | "DapBreakpoint", { 132 | text = "--", 133 | texthl = "DiagnosticError", 134 | numhl = "" 135 | } 136 | ) 137 | 138 | vim.fn.sign_define( 139 | "DapStopped", { 140 | text = "->", 141 | texthl = "DiagnosticHint", 142 | numhl = "" 143 | } 144 | ) 145 | 146 | -- configure widgets 147 | 148 | local widgets = require("dap.ui.widgets") 149 | 150 | -- set scopes as right pane 151 | local scopes = widgets.sidebar(widgets.scopes, {}, "vsplit") 152 | 153 | -- set frames as bottom pane 154 | local frames = widgets.sidebar(widgets.frames, {height = 10}, "belowright split") 155 | 156 | vim.keymap.set("n", "dj", dap.continue) 157 | vim.keymap.set("n", "dm", dap.step_over) 158 | vim.keymap.set("n", "di", dap.step_into) 159 | vim.keymap.set("n", "dk", dap.toggle_breakpoint) 160 | vim.keymap.set("n", "dn", dap.clear_breakpoints) 161 | vim.keymap.set("n", "dt", dap.terminate) 162 | 163 | local repl = require("dap.repl") 164 | 165 | vim.keymap.set( 166 | "n", "da", 167 | function() 168 | return repl.toggle({}, "belowright split") 169 | end 170 | ) 171 | 172 | vim.keymap.set("n", "ds", scopes.toggle) 173 | vim.keymap.set("n", "du", frames.toggle) 174 | vim.keymap.set("n", "dh", widgets.hover) 175 | 176 | end 177 | 178 | } 179 | -------------------------------------------------------------------------------- /lua/plugins/nvim-tree.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/plugins/nvim-tree.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the plugin nvim-tree 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-08-31 9 | -- 10 | 11 | 12 | return { 13 | 14 | "kyazdani42/nvim-tree.lua", 15 | 16 | keys = { 17 | { "ee", "NvimTreeToggle" }, 18 | { "eo", "NvimTreeFindFile" }, 19 | }, 20 | 21 | config = function() 22 | 23 | local success, nvim_tree = pcall(require, "nvim-tree") 24 | if not success then 25 | vim.notify("Failed to load plugin: nvim-tree") 26 | return 27 | end 28 | 29 | nvim_tree.setup { 30 | 31 | update_focused_file = { 32 | enable = false, 33 | update_cwd = false, 34 | }, 35 | 36 | renderer = { 37 | 38 | root_folder_modifier = ":t", 39 | 40 | icons = { 41 | 42 | diagnostics_placement = "signcolumn", 43 | git_placement = "after", 44 | 45 | glyphs = { 46 | 47 | default = "x", 48 | symlink = "s", 49 | 50 | folder = { 51 | arrow_open = "", 52 | arrow_closed = "", 53 | default = "[x]", 54 | open = "]x[", 55 | empty = "[ ]", 56 | empty_open = "] [", 57 | symlink = "[s]", 58 | symlink_open = "]s[", 59 | }, 60 | 61 | git = { 62 | unstaged = "*", 63 | staged = "", 64 | deleted = "", 65 | unmerged = "", 66 | renamed = "", 67 | untracked = "", 68 | ignored = "", 69 | }, 70 | 71 | }, 72 | 73 | }, 74 | 75 | }, 76 | 77 | diagnostics = { 78 | 79 | enable = true, 80 | show_on_dirs = true, 81 | show_on_open_dirs = false, 82 | 83 | icons = { 84 | hint = "?", 85 | info = "*", 86 | warning = "!", 87 | error = "!", 88 | }, 89 | 90 | }, 91 | 92 | git = { 93 | 94 | enable = false, 95 | show_on_dirs = false, 96 | show_on_open_dirs = false, 97 | 98 | }, 99 | 100 | -- adjust the window size 101 | view = { 102 | width = 32, 103 | side = "left", 104 | }, 105 | 106 | -- do not show hidden files 107 | filters = { 108 | dotfiles = true, 109 | custom = { ".*cache.*" }, 110 | }, 111 | 112 | } 113 | 114 | vim.api.nvim_set_hl(0, "NvimTreeFolderIcon", { fg = "#777777"}) 115 | 116 | 117 | local api = require("nvim-tree.api") 118 | 119 | vim.keymap.set( 120 | "n", "er", 121 | function() 122 | api.tree.collapse_all() 123 | end, 124 | { desc = "collapse all node on the file tree" } 125 | ) 126 | 127 | vim.keymap.set( 128 | "n", "et", 129 | function() 130 | local node = api.tree.get_node_under_cursor() 131 | vim.cmd("argadd " .. node.absolute_path) 132 | end, 133 | { desc = "add file under cursor to the arglist, to open multi files" } 134 | ) 135 | 136 | end, 137 | } 138 | -------------------------------------------------------------------------------- /lua/plugins/otter.lua: -------------------------------------------------------------------------------- 1 | local convert_to_normal_script = function() 2 | 3 | local filename = "temp.py" 4 | 5 | local query = vim.treesitter.query.parse('markdown', [[ 6 | ((code_fence_content) @code) 7 | ]]) 8 | 9 | local parser = vim.treesitter.get_parser(0, "markdown") 10 | local tree = parser:parse()[1] 11 | local root = tree:root() 12 | 13 | local lines = {} 14 | 15 | for _, node in query:iter_captures(root, 0) do 16 | 17 | local text = vim.treesitter.get_node_text(node, 0) 18 | 19 | for _, line in ipairs(vim.fn.split(text, '\n')) do 20 | table.insert(lines, line) 21 | end 22 | 23 | end 24 | 25 | local file = io.open(filename, "w") 26 | 27 | for _, line in ipairs(lines) do 28 | file:write(line .. "\n") 29 | end 30 | 31 | file:close() 32 | 33 | vim.cmd("edit " .. filename) 34 | 35 | end 36 | 37 | local move_imports_to_top = function() 38 | local bufnr = 0 39 | local root = vim.treesitter.get_parser(bufnr, "python"):parse()[1]:root() 40 | 41 | local query = vim.treesitter.query.parse("python", [[ 42 | (import_statement) @imp 43 | (import_from_statement) @imp 44 | ]]) 45 | 46 | local import_nodes = {} 47 | for _, node in query:iter_captures(root, bufnr) do 48 | table.insert(import_nodes, node) 49 | end 50 | 51 | table.sort(import_nodes, function(a,b) return a:start() < b:start() end) 52 | 53 | local lines_to_remove = {} 54 | local import_texts = {} 55 | 56 | for _, node in ipairs(import_nodes) do 57 | local s, _, e, _ = node:range() 58 | for i = s, e do lines_to_remove[i] = true end 59 | table.insert(import_texts, vim.treesitter.get_node_text(node, bufnr)) 60 | end 61 | 62 | local buf_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) 63 | for i = #buf_lines - 1, 0, -1 do 64 | if lines_to_remove[i] then table.remove(buf_lines, i + 1) end 65 | end 66 | 67 | local imports_lines = {} 68 | for _, text in ipairs(import_texts) do 69 | for line in text:gmatch("[^\r\n]+") do 70 | table.insert(imports_lines, line) 71 | end 72 | end 73 | table.insert(imports_lines, "") 74 | 75 | for i = #imports_lines, 1, -1 do 76 | table.insert(buf_lines, 1, imports_lines[i]) 77 | end 78 | 79 | vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, buf_lines) 80 | end 81 | 82 | 83 | return { 84 | 85 | 'jmbuhr/otter.nvim', 86 | 87 | ft = { "markdown", "quarto" }, 88 | 89 | dependencies = { 90 | 'nvim-treesitter/nvim-treesitter', 91 | }, 92 | 93 | config = function() 94 | 95 | local success, otter = pcall(require, "otter") 96 | if not success then 97 | vim.notify("Error loading plugin: otter") 98 | return 99 | end 100 | 101 | 102 | otter.setup{ 103 | 104 | lsp = { 105 | diagnostic_update_events = { "InsertLeave", "TextChanged" }, 106 | root_dir = function(_, bufnr) 107 | return vim.fs.root(bufnr or 0, { 108 | ".git", 109 | "_quarto.yml", 110 | "package.json", 111 | }) or vim.fn.getcwd(0) 112 | end, 113 | }, 114 | 115 | buffers = { 116 | set_filetype = true, 117 | write_to_disk = false, 118 | preambles = {}, 119 | postambles = {}, 120 | ignore_pattern = { 121 | python = "^(%s*[%%!].*)", 122 | }, 123 | }, 124 | 125 | strip_wrapping_quote_characters = { "'", '"', "`" }, 126 | handle_leading_whitespace = true, 127 | extensions = {}, 128 | debug = false, 129 | 130 | verbose = { 131 | no_code_found = false 132 | }, 133 | } 134 | 135 | vim.api.nvim_set_hl(0, "@markup.raw.block.markdown", {}) 136 | vim.api.nvim_set_hl(0, "@label.markdown", { fg = "#555555" }) 137 | 138 | vim.keymap.set("n", "op", 139 | function() 140 | otter.activate( 141 | { "python" }, 142 | true, 143 | true, 144 | nil 145 | ) 146 | end, 147 | { desc = "start otter for Python with language server and completion" } 148 | ) 149 | 150 | vim.treesitter.language.register("markdown", "quarto") 151 | 152 | 153 | vim.keymap.set("n", "aj", convert_to_normal_script) 154 | vim.keymap.set("n", "ak", move_imports_to_top) 155 | 156 | vim.api.nvim_create_autocmd( 157 | { "BufEnter", "BufWinEnter", "TextChanged", "InsertLeave" }, 158 | { 159 | pattern = { "*.md", "*.qmd" }, 160 | callback = function() 161 | local bufnr = vim.api.nvim_get_current_buf() 162 | local ns_id = vim.api.nvim_create_namespace("codeblock_hr") 163 | vim.api.nvim_buf_clear_namespace(bufnr, ns_id, 0, -1) 164 | 165 | for i = 0, vim.api.nvim_buf_line_count(bufnr) - 1 do 166 | local line = vim.api.nvim_buf_get_lines(bufnr, i, i + 1, false)[1] 167 | if line:match("^```.*$") then 168 | vim.api.nvim_buf_set_extmark(bufnr, ns_id, i, 0, { 169 | virt_text = { { string.rep("─", 79), "Comment" } }, 170 | virt_text_pos = "overlay", 171 | }) 172 | end 173 | end 174 | end, 175 | } 176 | ) 177 | 178 | vim.api.nvim_set_hl(0, "@spell", { fg = "#888888" }) 179 | 180 | end 181 | 182 | } 183 | -------------------------------------------------------------------------------- /lua/plugins/terminal.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/plugins/terminal.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the terminal plugin 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-12-23 9 | -- 10 | 11 | 12 | local opts = {} 13 | 14 | opts.keymaps = { 15 | 16 | terminal = "t", 17 | find_file = "f", 18 | find_buffer = "y", 19 | live_grep = "g", 20 | 21 | normal_mode = "", 22 | 23 | goto_file = "gf", 24 | 25 | } 26 | 27 | opts.window = { 28 | 29 | width = function() return math.floor(vim.o.columns * 0.8) end, 30 | height = function() return math.floor(vim.o.lines * 0.8) end, 31 | 32 | style = "minimal", 33 | border = "single", 34 | 35 | } 36 | 37 | opts.fzf = { 38 | 39 | executable = "fzf", 40 | 41 | args = { 42 | "--layout=reverse", 43 | }, 44 | 45 | } 46 | 47 | opts.rg = { 48 | 49 | executable = "rg", 50 | 51 | args = { 52 | "--ignore-case", 53 | }, 54 | 55 | } 56 | 57 | opts.fd = { 58 | 59 | executable = "fd", 60 | 61 | args = { 62 | "--type f", 63 | '--exclude "*.png"', 64 | '--exclude "*.pdf"', 65 | '--exclude "*.jp*g"', 66 | '--exclude "*.aux"', 67 | 68 | '--exclude "**/build/**"', 69 | }, 70 | } 71 | 72 | return { 73 | 74 | "terminal", dev = true, 75 | 76 | event = "UIEnter", 77 | opts = opts, 78 | 79 | } 80 | -------------------------------------------------------------------------------- /lua/plugins/treesitter.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/plugins/treesitter.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the plugin treesitter 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-08-31 9 | -- 10 | 11 | 12 | return { 13 | 14 | "nvim-treesitter/nvim-treesitter", 15 | 16 | event = "UIEnter", 17 | 18 | build = ":TSUpdate", 19 | main = "nvim-treesitter.configs", 20 | 21 | config = function() 22 | 23 | local success, treesitter = pcall(require, "nvim-treesitter.configs") 24 | if not success then 25 | vim.notify("Failed to load plugin: treesitter") 26 | return 27 | end 28 | 29 | treesitter.setup { 30 | 31 | ensure_installed = { "lua", "python", "cpp", "javascript", "markdown", "markdown_inline" }, 32 | sync_install = true, 33 | ignore_install = {}, 34 | 35 | highlight = { 36 | enable = true, 37 | disable = function(_, bufnr) 38 | return vim.api.nvim_buf_line_count(bufnr) > 2000 39 | end, 40 | }, 41 | 42 | indent = { enable = true }, 43 | 44 | fold = { 45 | enable = { "python" }, 46 | }, 47 | 48 | incremental_selection = { 49 | enable = true, 50 | keymaps = { 51 | init_selection = "gnn", 52 | node_incremental = "grn", 53 | scope_incremental = "grc", 54 | node_decremental = "grm", 55 | }, 56 | }, 57 | 58 | } 59 | 60 | vim.g._ts_force_sync_parsing = true 61 | 62 | end 63 | 64 | } 65 | -------------------------------------------------------------------------------- /lua/plugins/vimtex.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/plugins/vimtex.lua 3 | -- 4 | -- @brief 5 | -- The configuration file for the plugin vimtex 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2025-01-03 9 | -- 10 | 11 | 12 | return { 13 | 14 | "lervag/vimtex", 15 | lazy = false, 16 | 17 | init = function() 18 | 19 | vim.g.vimtex_view_method = "zathura" 20 | 21 | vim.g.vimtex_compiler_method = "latexmk" 22 | vim.g.vimtex_compiler_latexmk = { 23 | out_dir = "build", 24 | options = { "-pdf", "-interaction=nonstopmode", "-synctex=1"}, 25 | } 26 | 27 | vim.g.vimtex_doc_enabled = 0 28 | vim.g.vimtex_complete_enabled = 0 29 | vim.g.vimtex_syntax_enabled = 0 30 | vim.g.vimtex_imaps_enabled = 0 31 | 32 | vim.g.vimtex_view_forward_search_on_start = 0 33 | 34 | vim.keymap.set("n", "ll", function() vim.cmd("VimtexCompile") end) 35 | 36 | end 37 | } 38 | -------------------------------------------------------------------------------- /lua/statusline.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file lua/statusline.lua 3 | -- 4 | -- @brief 5 | -- Configure the statusline 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-12-20 9 | -- 10 | 11 | 12 | -- a function to obtain and format the current git branch 13 | 14 | local function git_branch() 15 | 16 | local branch = vim.b.gitsigns_head 17 | 18 | if branch == nil then 19 | return " -- " 20 | end 21 | 22 | local added = vim.b.gitsigns_status_dict.added or 0 23 | local changed = vim.b.gitsigns_status_dict.changed or 0 24 | local removed = vim.b.gitsigns_status_dict.removed or 0 25 | 26 | return "%#statusline_branch# " .. branch .. " +" .. added .. " -" .. removed .. " ~" .. changed .. " " 27 | 28 | end 29 | 30 | -- a function to obtain and format the file name 31 | 32 | local function file_name() 33 | 34 | local filename = vim.fn.expand("%:t") 35 | if filename == "" then 36 | filename = "[no name]" 37 | end 38 | 39 | if string.match(filename, "NvimTree") then 40 | filename = "NvimTree" 41 | end 42 | 43 | if vim.bo.buftype == "terminal" then 44 | filename = "terminal" 45 | end 46 | 47 | -- change highlight group based on if the file has been modified 48 | local highlight_group = vim.bo.modified and filename ~= "[no name]" and "statusline_modifiedfile" or "statusline_file" 49 | 50 | return "%#" .. highlight_group .. "# " .. filename .. " " 51 | 52 | end 53 | 54 | -- a function to obtain and format the current mode 55 | 56 | local function current_mode() 57 | 58 | local mode = vim.fn.mode() 59 | 60 | local mode_aliases = { 61 | n = "n", 62 | i = "i", 63 | v = "v", 64 | V = "v", 65 | t = "t", 66 | c = "c", 67 | s = "s", 68 | [""] = "v", 69 | } 70 | 71 | mode = mode and mode_aliases[mode] and mode_aliases[mode]:upper() or "?" 72 | 73 | return "%#statusline_mode# " .. mode .. " " 74 | 75 | end 76 | 77 | -- a function to obtain and format the diagnostics 78 | 79 | local function diagnostics() 80 | 81 | local num_warning = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.WARN }) 82 | local num_error = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.ERROR }) 83 | local num_hint = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.HINT }) 84 | 85 | return "%#statusline_diagnostics# " .. "E" .. num_error .. " W" .. num_warning .. " H" .. num_hint .. " " 86 | 87 | end 88 | 89 | -- a function to display the current class or function in the statusline 90 | 91 | local function contexts() 92 | 93 | if vim.bo.filetype ~= "python" then 94 | return "" 95 | end 96 | 97 | local success, treesitter = pcall(require, "nvim-treesitter") 98 | if not success then 99 | return "" 100 | end 101 | 102 | local context = treesitter.statusline { 103 | 104 | type_patterns = { "class", "function", "method" }, 105 | 106 | transform_fn = function(line) 107 | 108 | line = line:gsub("class%s*", "") 109 | line = line:gsub("def%s*", "") 110 | line = line:gsub(":", "") 111 | 112 | return line:gsub("%s*[%(%{%[].*[%]%}%)]*%s*$", "") 113 | 114 | end, 115 | 116 | separator = " -> ", 117 | 118 | allow_duplicates = false, 119 | 120 | } 121 | 122 | if context == nil then 123 | return "" 124 | end 125 | 126 | return "%#statusline_contexts# " .. context .. " " 127 | 128 | end 129 | 130 | -- a function to assign highlight group to the separator 131 | 132 | local function separator() 133 | 134 | local highlight_group = "statusline_separator" 135 | return "%#" .. highlight_group .. "#%=" 136 | 137 | end 138 | 139 | -- a function to call and place the statusline components 140 | 141 | function Status_line() 142 | 143 | return table.concat({ 144 | 145 | file_name(), 146 | diagnostics(), 147 | contexts(), 148 | 149 | separator(), 150 | 151 | git_branch(), 152 | current_mode(), 153 | 154 | }) 155 | 156 | end 157 | 158 | -- default with statusline but can be toggled with s 159 | 160 | vim.opt["laststatus"] = 3 161 | 162 | vim.keymap.set( "n", "s", 163 | 164 | function() 165 | 166 | if vim.o.laststatus == 0 then 167 | vim.cmd("set laststatus=3") 168 | else 169 | vim.cmd("set laststatus=0") 170 | end 171 | 172 | end 173 | 174 | ) 175 | 176 | vim.cmd("set statusline=%!v:lua.Status_line()") 177 | 178 | vim.cmd([[ 179 | augroup Statusline 180 | au! 181 | au WinEnter,BufEnter * setlocal cursorline 182 | au WinLeave,BufLeave * setlocal nocursorline 183 | ]]) 184 | 185 | 186 | -- set colors for each statusline components 187 | 188 | local group_styles = { 189 | 190 | ["statusline_file"] = { fg = "#EEEEEE", bg = "#333333", bold = true }, 191 | ["statusline_modifiedfile"] = { fg = "#000000", bg = "#CCCCCC", bold = true }, 192 | ["statusline_diagnostics"] = { fg = "#EEEEEE", bg = "#222222" }, 193 | ["statusline_contexts"] = { fg = "#CCCCCC", bg = "None" }, 194 | 195 | ["statusline_separator"] = { fg = "#333333", bg = "None" }, 196 | 197 | ["statusline_branch"] = { fg = "#EEEEEE", bg = "#222222" }, 198 | ["statusline_mode"] = { fg = "#EEEEEE", bg = "#333333", bold = true }, 199 | 200 | } 201 | 202 | for group, style in pairs(group_styles) do 203 | vim.api.nvim_set_hl(0, group, style) 204 | end 205 | -------------------------------------------------------------------------------- /projects/terminal/lua/terminal.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- @file projects/terminal/lua/terminal.lua 3 | -- 4 | -- @brief 5 | -- The plugin file for terminal 6 | -- 7 | -- @author Tanuharja, R.A. 8 | -- @date 2024-12-23 9 | -- 10 | 11 | 12 | local M = {} 13 | 14 | M.state = { 15 | buffer = -1, 16 | win = -1, 17 | } 18 | 19 | local get_fzf_output = function(buffer) 20 | 21 | local lines = vim.api.nvim_buf_get_lines(buffer, 0, -1, false) 22 | local output = "" 23 | 24 | for row = 1, #lines do 25 | 26 | if lines[row] == "" then 27 | return output 28 | end 29 | 30 | output = output .. lines[row] 31 | 32 | end 33 | 34 | end 35 | 36 | M.setup = function(opts) 37 | 38 | M.create_floating_window = function(buf) 39 | 40 | buf = buf or -1 41 | 42 | local width = opts.window.width() 43 | local height = opts.window.height() 44 | 45 | local col = math.floor((vim.o.columns - width) / 2) 46 | local row = math.floor((vim.o.lines - height) / 2) 47 | 48 | local buffer = nil 49 | if vim.api.nvim_buf_is_valid(buf) then 50 | buffer = buf 51 | else 52 | buffer = vim.api.nvim_create_buf(false, true) end 53 | 54 | local win_config = { 55 | relative = "editor", 56 | width = width, 57 | height = height, 58 | col = col, 59 | row = row, 60 | style = opts.window.style, 61 | border =opts.window.border, 62 | } 63 | 64 | local win = vim.api.nvim_open_win(buffer, true, win_config) 65 | 66 | return { buffer = buffer, win = win } 67 | 68 | end 69 | 70 | local fzf_command = opts.fzf.executable 71 | 72 | for _, arg in pairs(opts.fzf.args) do 73 | fzf_command = fzf_command .. " " .. arg 74 | end 75 | 76 | local fd_command = opts.fd.executable 77 | 78 | for _, arg in pairs(opts.fd.args) do 79 | fd_command = fd_command .. " " .. arg 80 | end 81 | 82 | local rg_command = opts.rg.executable .. " --line-number --color=never" 83 | 84 | for _, arg in pairs(opts.rg.args) do 85 | rg_command = rg_command .. " " .. arg 86 | end 87 | 88 | M.toggle_find_file = function() 89 | 90 | local picker = M.create_floating_window() 91 | 92 | vim.fn.jobstart(fd_command .. " | " .. fzf_command, { 93 | term = true, 94 | on_exit = function(_, exit_code) 95 | 96 | if exit_code == 0 then 97 | 98 | local file_name = get_fzf_output(picker.buffer) 99 | local found_file = vim.fn.findfile(file_name, vim.o.path) 100 | 101 | vim.api.nvim_win_close(picker.win, true) 102 | 103 | if found_file ~= "" then 104 | vim.cmd("edit " .. vim.fn.fnameescape(found_file)) 105 | end 106 | 107 | 108 | else 109 | vim.api.nvim_win_close(picker.win, true) 110 | end 111 | 112 | end 113 | }) 114 | 115 | vim.cmd("startinsert") 116 | 117 | end 118 | 119 | M.toggle_find_buffer = function() 120 | 121 | local picker = M.create_floating_window() 122 | local file_name = "" 123 | 124 | vim.cmd("redir! > .out | silent ls | redir END") 125 | 126 | vim.fn.jobstart([[sed -n 's/.*"\(.*\)".*/\1/p' .out | grep -v -E "term:|No Name" | ]] .. fzf_command, { 127 | term = true, 128 | on_exit = function(_, exit_code) 129 | 130 | if exit_code == 0 then 131 | 132 | local file_name = get_fzf_output(picker.buffer) 133 | local found_file = vim.fn.findfile(file_name, vim.o.path) 134 | 135 | vim.api.nvim_win_close(picker.win, true) 136 | 137 | if found_file ~= "" then 138 | vim.cmd("edit " .. vim.fn.fnameescape(found_file)) 139 | end 140 | 141 | else 142 | vim.api.nvim_win_close(picker.win, true) 143 | end 144 | 145 | vim.cmd("silent! !rm .out") 146 | 147 | end 148 | }) 149 | 150 | vim.cmd("startinsert") 151 | 152 | end 153 | 154 | M.toggle_live_grep = function() 155 | 156 | local picker = M.create_floating_window() 157 | 158 | vim.fn.jobstart(fzf_command .. ' --bind "change:reload(' .. rg_command .. ' {q} || true)" --ansi', { 159 | term = true, 160 | on_exit = function(_, exit_code) 161 | 162 | if exit_code == 0 then 163 | 164 | local output = get_fzf_output(picker.buffer) 165 | local file_name, line_num = output:match("([^:]+):(%d+)") 166 | local found_file = vim.fn.findfile(file_name, ".") 167 | 168 | vim.api.nvim_win_close(picker.win, true) 169 | 170 | if found_file ~= "" then 171 | vim.cmd("edit " .. vim.fn.fnameescape(found_file)) 172 | vim.api.nvim_win_set_cursor(0, {tonumber(line_num), 0}) 173 | end 174 | 175 | else 176 | vim.api.nvim_win_close(picker.win, true) 177 | end 178 | 179 | end 180 | }) 181 | 182 | vim.cmd("startinsert") 183 | 184 | end 185 | 186 | M.toggle_terminal = function() 187 | 188 | if not vim.api.nvim_win_is_valid(M.state.win) then 189 | M.state = M.create_floating_window(M.state.buffer) 190 | 191 | if vim.bo[M.state.buffer].buftype ~= "terminal" then 192 | 193 | vim.cmd.terminal() 194 | 195 | local is_keyword = vim.bo[M.state.buffer].iskeyword 196 | vim.bo[M.state.buffer].iskeyword = is_keyword .. ",.,/,-" 197 | 198 | end 199 | else 200 | vim.api.nvim_win_hide(M.state.win) 201 | end 202 | 203 | end 204 | 205 | M.goto_file = function() 206 | local file_name = vim.fn.expand("") 207 | local found_file = vim.fn.findfile(file_name, ".") 208 | if found_file ~= "" then 209 | vim.api.nvim_win_hide(M.state.win) 210 | vim.cmd("edit " .. vim.fn.fnameescape(found_file)) 211 | end 212 | end 213 | 214 | vim.keymap.set("n", opts.keymaps.terminal, M.toggle_terminal) 215 | vim.keymap.set("n", opts.keymaps.find_file, M.toggle_find_file) 216 | vim.keymap.set("n", opts.keymaps.live_grep, M.toggle_live_grep) 217 | vim.keymap.set("n", opts.keymaps.find_buffer, M.toggle_find_buffer) 218 | vim.keymap.set("t", opts.keymaps.normal_mode, "") 219 | vim.keymap.set("n", opts.keymaps.goto_file, M.goto_file, { buffer = M.state.buffer }) 220 | end 221 | 222 | return M 223 | -------------------------------------------------------------------------------- /queries/python/folds.scm: -------------------------------------------------------------------------------- 1 | ;; fold docstring 2 | (function_definition 3 | body: (block 4 | (expression_statement 5 | (string) @fold 6 | ) 7 | ) 8 | ) 9 | 10 | (class_definition 11 | body: (block 12 | (expression_statement 13 | (string) @fold 14 | ) 15 | ) 16 | ) 17 | -------------------------------------------------------------------------------- /queries/python/highlights.scm: -------------------------------------------------------------------------------- 1 | ;; extends 2 | (((comment) @comment (#contains? @comment "TODO")) @comment.warning (#set! priority 150)) 3 | (((comment) @comment (#contains? @comment "WARN")) @comment.warning (#set! priority 150)) 4 | (((comment) @comment (#contains? @comment "BUGS")) @comment.error (#set! priority 150)) 5 | (((comment) @comment (#contains? @comment "FIXME")) @comment.error (#set! priority 150)) 6 | (((comment) @comment (#contains? @comment "NOTE")) @comment.note (#set! priority 150)) 7 | 8 | (function_definition 9 | body: (block 10 | (expression_statement 11 | (string) @comment (#set! priority 125) 12 | 13 | ) 14 | ) 15 | ) 16 | 17 | (class_definition 18 | body: (block 19 | (expression_statement 20 | (string) @comment (#set! priority 125) 21 | ) 22 | ) 23 | ) 24 | -------------------------------------------------------------------------------- /snippets/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Python code block": { 3 | "prefix": "code", 4 | "body": "```python\n$0\n```", 5 | "description": "A code block inside a markdown file" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /snippets/python.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "Aliased import": { 4 | "prefix": "import", 5 | "body": "import ${1:module} as ${2:alias}\n$0", 6 | "description": "Import a module and assign an alias to it" 7 | }, 8 | 9 | "Partial import": { 10 | "prefix": "from", 11 | "body": "from ${1:module} import ${2:item}\n$0", 12 | "description": "Import specific item(s) from a module" 13 | }, 14 | 15 | "Function definition": { 16 | "prefix": "def", 17 | "body": [ 18 | "def ${1:function_name}(${2:args}):", 19 | "\t", 20 | "\t${3:pass}", 21 | "$0" 22 | ], 23 | "description": "Define a new function" 24 | }, 25 | 26 | "Class definition": { 27 | "prefix": "class", 28 | "body": [ 29 | "class ${1:class_name}:", 30 | "\t", 31 | "\tdef __init__(${2:self}):", 32 | "\t\t${3:pass}", 33 | "$0" 34 | ], 35 | "description": "Define a new class" 36 | }, 37 | 38 | "Main function definition": { 39 | "prefix": "main", 40 | "body": [ 41 | "def main():", 42 | "\t", 43 | "\t${1:pass}$0", 44 | " ", 45 | " ", 46 | "if __name__ == \"__main__\":", 47 | "\t", 48 | "\tmain()" 49 | ], 50 | "description": "Create a common Python script structure" 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /snippets/quarto.json: -------------------------------------------------------------------------------- 1 | { 2 | "Python code block": { 3 | "prefix": "python", 4 | "body": "```{python}\n$0\n```", 5 | "description": "A python code block inside a quarto file" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /snippets/tex.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "Skeleton": { 4 | "prefix": "skeleton", 5 | "body": [ 6 | "\\documentclass{${1:type}}", 7 | " ", 8 | "${2:% preambles}", 9 | " ", 10 | "\\begin{document}", 11 | " ", 12 | "$0", 13 | " ", 14 | "\\end{document}" 15 | ], 16 | "description": "Create a document skeleton" 17 | }, 18 | 19 | "Package": { 20 | "prefix": "package", 21 | "body": "\\usepackage{${1:package_name}}\n$0", 22 | "description": "Import a LaTeX package" 23 | }, 24 | 25 | "Environment": { 26 | "prefix": "environment", 27 | "body": "\\begin{${1:env}}\n\t$0\n\\end{${1}}", 28 | "description": "Create the start and end of an environment" 29 | } 30 | 31 | } 32 | --------------------------------------------------------------------------------