From 524673abfc39918dd5704ce7dca68c3e97536d76 Mon Sep 17 00:00:00 2001 From: Jonas Hahn Date: Fri, 29 Aug 2025 09:39:04 +0200 Subject: [PATCH] Init from other configuration repository. This is just a backup and will be refactored soon --- init.lua | 12 ++ lazy-lock.json | 28 ++++ lazyvim.json | 9 ++ lua/config/autocmds.lua | 86 +++++++++++ lua/config/colorscheme.lua | 0 lua/config/init.lua | 8 + lua/config/keymaps.lua | 292 +++++++++++++++++++++++++++++++++++++ lua/config/lazy.lua | 48 ++++++ lua/config/lsp.lua | 109 ++++++++++++++ lua/config/options.lua | 23 +++ lua/custom/journal.lua | 66 +++++++++ lua/custom/todo.lua | 140 ++++++++++++++++++ lua/custom/uni.lua | 151 +++++++++++++++++++ lua/helpers/after.lua | 247 +++++++++++++++++++++++++++++++ lua/helpers/functions.lua | 214 +++++++++++++++++++++++++++ lua/helpers/linker.lua | 256 ++++++++++++++++++++++++++++++++ lua/plugins/diff.lua | 27 ++++ lua/plugins/init.lua | 9 ++ lua/plugins/main.lua | 238 ++++++++++++++++++++++++++++++ 19 files changed, 1963 insertions(+) create mode 100644 init.lua create mode 100644 lazy-lock.json create mode 100644 lazyvim.json create mode 100644 lua/config/autocmds.lua create mode 100644 lua/config/colorscheme.lua create mode 100644 lua/config/init.lua create mode 100644 lua/config/keymaps.lua create mode 100644 lua/config/lazy.lua create mode 100644 lua/config/lsp.lua create mode 100644 lua/config/options.lua create mode 100644 lua/custom/journal.lua create mode 100644 lua/custom/todo.lua create mode 100644 lua/custom/uni.lua create mode 100644 lua/helpers/after.lua create mode 100644 lua/helpers/functions.lua create mode 100644 lua/helpers/linker.lua create mode 100644 lua/plugins/diff.lua create mode 100644 lua/plugins/init.lua create mode 100644 lua/plugins/main.lua diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..1764e03 --- /dev/null +++ b/init.lua @@ -0,0 +1,12 @@ +-- Nvim config by Jonas Hahn + +-- set a diff flag +-- this stands for diff mode +if vim.o.diff then + vim.g.diffm = true +else + vim.g.diffm = false +end + +require("config.init") + diff --git a/lazy-lock.json b/lazy-lock.json new file mode 100644 index 0000000..97e4759 --- /dev/null +++ b/lazy-lock.json @@ -0,0 +1,28 @@ +{ + "LuaSnip": { "branch": "master", "commit": "458560534a73f7f8d7a11a146c801db00b081df0" }, + "aerial.nvim": { "branch": "master", "commit": "c7cbbad40c2065fccfd1f1863bb2c08180c0533d" }, + "barbar.nvim": { "branch": "master", "commit": "53b5a2f34b68875898f0531032fbf090e3952ad7" }, + "cmp-buffer": { "branch": "main", "commit": "b74fab3656eea9de20a9b8116afa3cfc4ec09657" }, + "cmp-nvim-lsp": { "branch": "main", "commit": "bd5a7d6db125d4654b50eeae9f5217f24bb22fd3" }, + "cmp-path": { "branch": "main", "commit": "c642487086dbd9a93160e1679a1327be111cbc25" }, + "cmp_luasnip": { "branch": "master", "commit": "98d9cb5c2c38532bd9bdb481067b20fea8f32e90" }, + "fzf-lua": { "branch": "main", "commit": "bebc84e7ffc8fd86103f6ed6c590df72d524d342" }, + "gitsigns.nvim": { "branch": "main", "commit": "6e3c66548035e50db7bd8e360a29aec6620c3641" }, + "gruvbox.nvim": { "branch": "main", "commit": "12c2624287dc827edb5d72b2bc4c9619e692a554" }, + "harpoon": { "branch": "master", "commit": "1bc17e3e42ea3c46b33c0bbad6a880792692a1b3" }, + "lazy.nvim": { "branch": "main", "commit": "6c3bda4aca61a13a9c63f1c1d1b16b9d3be90d7a" }, + "lazygit.nvim": { "branch": "main", "commit": "3c524ebec6072568064235c407195e9f9fd0cb8a" }, + "lspsaga.nvim": { "branch": "main", "commit": "8efe00d6aed9db6449969f889170f1a7e43101a1" }, + "lualine.nvim": { "branch": "master", "commit": "b8c23159c0161f4b89196f74ee3a6d02cdc3a955" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "1ec4da522fa49dcecee8d190efda273464dd2192" }, + "mason.nvim": { "branch": "main", "commit": "7dc4facca9702f95353d5a1f87daf23d78e31c2a" }, + "nvim-cmp": { "branch": "main", "commit": "b5311ab3ed9c846b585c0c15b7559be131ec4be9" }, + "nvim-lspconfig": { "branch": "master", "commit": "52364267cd7edbc0e9b25ab3bfb1c8f45dd58fde" }, + "nvim-tree.lua": { "branch": "master", "commit": "fefa335f1c8f690eb668a1efd18ee4fc6d64cd3e" }, + "nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" }, + "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, + "telekasten.nvim": { "branch": "main", "commit": "b3ac2b07f2df504bb80112fec349714086a80037" }, + "telescope.nvim": { "branch": "master", "commit": "a0bbec21143c7bc5f8bb02e0005fa0b982edc026" }, + "toggleterm.nvim": { "branch": "main", "commit": "9a88eae817ef395952e08650b3283726786fb5fb" }, + "which-key.nvim": { "branch": "main", "commit": "370ec46f710e058c9c1646273e6b225acf47cbed" } +} diff --git a/lazyvim.json b/lazyvim.json new file mode 100644 index 0000000..a28f5eb --- /dev/null +++ b/lazyvim.json @@ -0,0 +1,9 @@ +{ + "extras": [ + + ], + "news": { + "NEWS.md": "10960" + }, + "version": 8 +} \ No newline at end of file diff --git a/lua/config/autocmds.lua b/lua/config/autocmds.lua new file mode 100644 index 0000000..98338ef --- /dev/null +++ b/lua/config/autocmds.lua @@ -0,0 +1,86 @@ + +-- Autocommands + +vim.cmd(':colorscheme gruvbox') + +if vim.g.diffm then +-- vim.api.nvim_create_autocmd("VimEnter", { +-- callback = function() +-- -- Create a new empty buffer +-- vim.cmd("enew") +-- +-- -- Your multiline message +-- local lines = { +-- "Welcome to Neovim!", +-- "", +-- "You are in Diff Mode!", +-- "Press do to open the Difftab.", +-- "", +-- "Good luck!" +-- } +-- +-- -- Get dimensions +-- local width = vim.api.nvim_get_option("columns") +-- local height = vim.api.nvim_get_option("lines") +-- +-- -- Center vertically +-- local start_line = math.floor((height - #lines) / 3) +-- +-- -- Insert empty lines at the top +-- for _ = 1, start_line do +-- vim.api.nvim_buf_set_lines(0, -1, -1, false, {""}) +-- end +-- +-- -- Center horizontally and insert text +-- for _, line in ipairs(lines) do +-- local padding = math.floor((width - #line) / 2) +-- local padded_line = string.rep(" ", math.max(padding, 0)) .. line +-- vim.api.nvim_buf_set_lines(0, -1, -1, false, {padded_line}) +-- end +-- +-- -- Make buffer not modifiable +-- vim.bo.modifiable = false +-- vim.bo.buflisted = false +-- end +-- }) + +end + + +vim.api.nvim_create_user_command("Ex", function() + if vim.opt.diff:get() then + -- require("diffview").open() + print("running with diff view mode -> No ex") + else + -- fallback if not in diff mode (optional) + -- vim.cmd("Explore") -- or do nothing + -- Just disable EX + print("You have tree view (no ex anymore)") + end +end, {}) + + +-- Save the last file on exit +vim.api.nvim_create_autocmd("VimLeave", { + callback = function() + -- Save the last file path to a file + local last_file = vim.fn.expand('%:p') -- Get the absolute path of the current file + if last_file ~= "" then + local file = io.open(vim.fn.stdpath('data') .. "/lastfile.txt", "w") + if file then + file:write(last_file) + file:close() + end + end + end, +}) + +-- Setting a transparent background +function Transparent(color) + color = color or "gruvbox" + vim.cmd.colorscheme(color) + vim.api.nvim_set_hl(0, "Normal", { bg = "none" }) + vim.api.nvim_set_hl(0, "NormalFloat", { bg = "none" }) +end +Transparent() + diff --git a/lua/config/colorscheme.lua b/lua/config/colorscheme.lua new file mode 100644 index 0000000..e69de29 diff --git a/lua/config/init.lua b/lua/config/init.lua new file mode 100644 index 0000000..e0dfb1a --- /dev/null +++ b/lua/config/init.lua @@ -0,0 +1,8 @@ +-- Load lazy first +require('config.lazy') + +-- General settings +require('config.options') +require('config.keymaps') +require('config.autocmds') +require('config.lsp') diff --git a/lua/config/keymaps.lua b/lua/config/keymaps.lua new file mode 100644 index 0000000..66c7409 --- /dev/null +++ b/lua/config/keymaps.lua @@ -0,0 +1,292 @@ +-- ########################### +-- the heart of neovim ####### +-- ########################### + +require("helpers.functions") + +-- gloabal settings +vim.keymap.set('n', 'q', function() + local success, _ = pcall(function() + vim.cmd('wa') -- Write (save) all buffers + end) + vim.cmd('qa!') -- Quit all buffers forcefully +end) + +vim.keymap.set("n", "w", "w") + +vim.keymap.set('v', 'p', function() + vim.cmd('normal! "+p') +end, { desc = 'Yank to clipboard and keep the selection' }) + +-- branching depeding on diff mode +if vim.g.diffm then + -- diff view commands + vim.keymap.set('n', 'do', ":DiffviewClose:DiffviewOpen") + vim.keymap.set('n', 'df', ":DiffviewClose:DiffviewFileHistory") + vim.keymap.set('n', 'dt', ":DiffviewToggleFiles") + vim.keymap.set('n', 'dc', ":DiffviewClose") + vim.keymap.set('n', 'dl', ":DiffviewLog") + + -- vim.keymap.set("n", "e", "ww") +else + -- not in diff mode + -- TODO: make this dynamic + local season = "S2" + + local links = require("helpers.linker") -- replace with real file path + local user = vim.fn.system('whoami'):gsub('\n', '') + local api = require("nvim-tree.api") + local builtin = require('telescope.builtin') + local current_date = os.date("%Y-%m-%d") + local week_number = os.date("%W") + 1 -- Week number (starting from Sunday) + local day_of_week = os.date("%a") -- Abbreviated weekday name (e.g., Mon, Tue) + + -- this is how to access global vars + function set_obs() + -- _G is the global table. this creates variable 'obs' attached to + -- the global table with the value 'some text value' + _G.season = season + end + + + --------------------- NORMAL ------------------------- + + + -- vim.keymap.set("i", "", "", { silent = true }) + + + vim.keymap.set("n", "L", ":BufferNext", { silent = true }) -- also update the root with the bang + vim.keymap.set("n", "n", "nzz", { silent = true }) -- also update the root with the bang + vim.keymap.set("n", "N", "Nzz", { silent = true }) -- also update the root with the bang + vim.keymap.set("n", "H", ":BufferPrevious", { silent = true }) -- also update the root with the bang + vim.keymap.set("n", "", "zz", { silent = true }) -- also update the root with the bang + vim.keymap.set("n", "", "zz", { silent = true }) -- also update the root with the bang + vim.keymap.set("n", "", "zz", { silent = true }) -- also update the root with the bang + vim.keymap.set("n", "", "zz", { silent = true }) -- also update the root with the bang + + vim.keymap.set('n', 'a', 'm9ggVG"+y`9') + vim.keymap.set('n', 'va', 'ggVG') + + -- Launch panel if nothing is typed after z + vim.keymap.set("n", "z", "Telekasten panel") + + -- Most used functions + vim.keymap.set("n", "zf", "Telekasten find_notes") + vim.keymap.set("n", "zg", "Telekasten search_notes") + vim.keymap.set('n', 'zq', ':e ~/synced/brainstore/zettelkasten/input.txt`.zz') + vim.keymap.set("n", "zd", "Telekasten goto_today") + vim.keymap.set("n", "zr", "Telekasten rename_note") + vim.keymap.set("n", "zz", "Telekasten follow_link") + vim.keymap.set("n", "zn", "Telekasten new_note") + vim.keymap.set("n", "zb", "Telekasten show_backlinks") + vim.keymap.set("n", "zw", "Telekasten find_weekly_notes") + vim.keymap.set("n", "zI", "Telekasten insert_img_link") + + vim.keymap.set("n", "me", ":mes") + vim.keymap.set("n", "", ":ToggleTerm") + vim.keymap.set("t", "", ":ToggleTerm") + + vim.keymap.set("n", "snt", "set nu") + vim.keymap.set("n", "snf", "set nonu") + + + -- Call insert link automatically when we start typing a link + vim.keymap.set("n", "il", "Telekasten insert_link") + + require("custom.uni") + vim.keymap.set("n", "nv", function() + + select_course_directory() + --pick_unicourse("/home/jonas/projects/university/S2") -- Change path accordingly + end, { desc = "Open UniCourse menu" }) + + + vim.keymap.set('n', 'ca', 'ggVGd') + vim.keymap.set("n", "bd", ":BufferDelete", { silent = true }) -- also update the root with the bang + + -- Typstar stuff + vim.keymap.set("n", "ti", ":TypstarInsertRnote", { silent = true }) -- also update the root with the bang + vim.keymap.set("n", "to", ":TypstarOpenDrawing", { silent = true }) -- also update the root with the bang + + + -- Get a ready to use terminal + vim.keymap.set('n', 'tr', ':tabnew:termi') + vim.keymap.set("n", "tt", ":Telescope", { desc = "Follow Link" }) + vim.keymap.set('n', 'tw', watch_and_open, { noremap = true, silent = true }) + + -- This needs to be refined for quick access to a new file or a recently edited one + vim.keymap.set('n', 'ov', open_vorlesung) + -- new quick note file + -- TODO: make this smarter + vim.keymap.set("n", "nn", ":e ~/synced/brainstore/zettelkasten/quick", { silent = true }) -- also update the root with the bang + + vim.keymap.set("n", "r", set_root) + + -- Custom journal plugin disable temporary + -- local journal = require("custom.journal") + -- vim.keymap.set("n", "jt", journal.open_today, { desc = "Open Today's Journal" }) + -- vim.keymap.set("n", "ja", journal.list_all_journals, { desc = "Open Today's Journal" }) + -- vim.keymap.set("n", "jm", journal.search_this_month, { desc = "Search This Month's Journals" }) + + -- Quickly open some buffers + -- Open all the vim configs instant + vim.keymap.set('n', 'occ', ':e ~/.config/nvim/init.lua`.zz') + vim.keymap.set('n', 'oct', ':e ~/synced/vault/contacts/contacts.txt`.zz') + vim.keymap.set('n', 'ock', ':e ~/.config/nvim/lua/config/keymaps.lua`.zz') + vim.keymap.set('n', 'ocd', ':e ~/.config/nvim/lua/config/autocmds.lua`.zz') + vim.keymap.set('n', 'oco', ':e ~/.config/nvim/lua/config/options.lua`.zz') + vim.keymap.set('n', 'ocl', ':e ~/.config/nvim/lua/config/lazy.lua`.zz') + vim.keymap.set('n', 'oczl', ':e ~/.config/nvim/lua/config/lsp.lua`.zz') + vim.keymap.set('n', 'ocp', ':e ~/.config/nvim/lua/plugins/main.lua`.zz') + vim.keymap.set('n', 'ocf', ':e ~/.config/nvim/lua/helpers/functions.lua`.zz') + vim.keymap.set('n', 'oca', ':e ~/.config/nvim/lua/helpers/after.lua`.zz') + vim.keymap.set('n', 'oq', ':e ~/synced/brainstore/input.txt`.zz') + vim.keymap.set('n', 'ohh', ':e ~/configuration/nixos/users/' .. user .. '/home.nix`.zz') + vim.keymap.set('n', 'op', ':e ~/configuration/nixos/users/' .. user .. '/packages.nix`.zz') + vim.keymap.set('n', 'on', ':e ~/configuration/nixos/configuration.nix`.zz') + vim.keymap.set('n', 'om', ':e ~/configuration/nixos/modules') + vim.keymap.set('n', 'ow', ':e ~/synced/brainstore/waste.txt') + vim.keymap.set('n', 'oho', ':e ~/configuration/nixos/hosts') + vim.keymap.set('n', 'os', ':e ~/configuration/nixos/modules/server') + vim.keymap.set('n', 'ot', ':e ~/synced/brainstore/todos/todo.txt`.zz') + vim.keymap.set('n', 'od', ':e ~/synced/brainstore/todos/done.txt`.zz') + vim.keymap.set('n', 'ou', ':e ~/projects/university/' .. season .. '/input.txt`.zz') + vim.keymap.set('n', 'oz', ':e ~/.zshrc`.zz') + vim.keymap.set('n', 'oaa', ':e ~/.common_shell`.zz') + -- Map the function to a keybinding (e.g., lf to open the last file) + vim.keymap.set("n", "or", "lua open_last_file()", { noremap = true, silent = true }) + -- open the calendar + -- + function open_cal() + local current_date = os.date("%Y-%m-%d") + local week_number = os.date("%V") + local day_of_week = os.date("%a") + local path = "~/synced/brainstore/calendar/calendar_" .. os.date("%Y") .. ".txt" + local keys = ":e " .. path .. "/" .. current_date .. " w" .. tonumber(week_number) .. " " .. day_of_week .. "$" + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(keys, true, false, true), 'n', true) + end + + vim.keymap.set('n', 'ok', open_cal) + ------------------------------------------------------------------------------------- + + vim.keymap.set("n", "lf", links.insert_brainstore_link, { desc = "Link Brainstore file" }) + vim.keymap.set("n", "lm", links.insert_mail_link, { desc = "Link Mail" }) + vim.keymap.set('n', 'll', ':Lazy') + vim.keymap.set("n", "lp", links.insert_project_link, { desc = "Link Project" }) + vim.keymap.set("n", "lc", links.insert_contact_link, { desc = "Link Contact" }) + vim.keymap.set("n", "ld", links.insert_date_link, { desc = "Link Contact" }) + + + -- nvim tree + vim.keymap.set("n", "e", function() + api.tree.toggle({ find_file = true, update_root = true, focus = true, }) + + end, { silent = true }) -- also update the root with the bang + + vim.keymap.set('n', 'ia', 'gg=Gzz') + vim.keymap.set('n', 'ya', 'ggVG"+y') + + -- Map q to save and quit all buffers with error handling + -- Dangerous but feels good + + vim.keymap.set('n', 'ss', ':wa') + vim.keymap.set('n', 'sw', function() + local word = vim.fn.expand("") + local replacement = vim.fn.input("Replace '" .. word .. "' with: ") + if replacement ~= "" then + vim.cmd(string.format("%%s/\\<%s\\>/%s/gI", vim.fn.escape(word, '\\/'), vim.fn.escape(replacement, '\\/'))) + end + end, { desc = "Substitute word under cursor (prompt)" }) + vim.keymap.set('v', 'sv', function() + -- Save the current selection + local save_reg = vim.fn.getreg('"') + local save_regtype = vim.fn.getregtype('"') + + -- Yank the visual selection into the " register + vim.cmd('normal! ""y') + + local selection = vim.fn.getreg('"') + -- Escape magic characters for the search + selection = vim.fn.escape(selection, '\\/.*$^~[]') + + -- Prompt for the replacement text + local replacement = vim.fn.input("Replace '" .. selection .. "' with: ") + if replacement ~= "" then + vim.cmd(string.format("%%s/%s/%s/gI", selection, replacement)) + end + + -- Restore previous register + vim.fn.setreg('"', save_reg, save_regtype) + end, { desc = "Substitute selection in file" }) + -- vim.keymap.set('n', 'sl', search_brain_links) + + vim.keymap.set('n', 'pp', function() + vim.api.nvim_command('normal! "+p') + end, { desc = 'Paste from system clipboard' }) + + -- vim.keymap.set('n', 'fg', builtin.live_grep, { desc = 'Telescope live grep' }) + vim.keymap.set('n', 'fr', function() + require('telescope.builtin').oldfiles({ + disable_devicons = true, + }) + end, { noremap = true, silent = true }) + vim.keymap.set('n', 'fb', builtin.buffers, { desc = 'Telescope buffers' }) + vim.keymap.set('n', 'fh', builtin.help_tags, { desc = 'Telescope help tags' }) + vim.keymap.set("n", "fl", links.follow_link, { desc = "Follow Link" }) + + + vim.keymap.set('n', 'g', function() + require('telescope.builtin').live_grep({ + disable_devicons = true, + cwd = vim.fn.getcwd(), -- set the starting directory + additional_args = function() + return { '--hidden', '--glob', '!.git/*' } -- include hidden files but exclude .git + end, + }) + end, { noremap = true, silent = true }) + + vim.keymap.set('n', '', find_eff, { desc = 'Telescope find files (with dotfiles and folders but excluding .git, .cache, .local, and large files)' }) + + ------------------------ VISUAL ------------------ + + vim.keymap.set('v', 'p', function() + local unnamed_content = vim.fn.getreg('""') + vim.api.nvim_command('normal! p') + vim.fn.setreg('""', unnamed_content) + end, { desc = 'Paste from unnamed register (don\'t overwrite it) in visual mode' }) + vim.keymap.set('v', 'y', function() + vim.cmd('normal! "+y') + vim.cmd('normal! gv') + end, { desc = 'Yank to clipboard and keep the selection' }) + + + ---------------------------- INSERT --------------------------- + + vim.keymap.set('i', '', function() + local col = vim.fn.col('.') + local line = vim.fn.line('.') + local line_len = vim.fn.col('$') - 1 + if col <= line_len then + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, false, true), 'n', true) + else + if line < vim.fn.line('$') then + vim.cmd('normal! j^') + end + end + end) + -- Move left with wrapping + vim.keymap.set('i', '', function() + local col = vim.fn.col('.') + local line = vim.fn.line('.') + if col > vim.fn.indent(line) + 1 then + -- not at very beginning (after indent), move left + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, false, true), 'n', true) + else + if line > 1 then + vim.cmd('normal! k$') + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, false, true), 'n', true) + end + end + end, { noremap = true, silent = true }) +end + diff --git a/lua/config/lazy.lua b/lua/config/lazy.lua new file mode 100644 index 0000000..89a7003 --- /dev/null +++ b/lua/config/lazy.lua @@ -0,0 +1,48 @@ +-- Bootstrap lazy.nvim +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" +if not (vim.uv or vim.loop).fs_stat(lazypath) then + local lazyrepo = "https://github.com/folke/lazy.nvim.git" + local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) + if vim.v.shell_error ~= 0 then + vim.api.nvim_echo({ + { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, + { out, "WarningMsg" }, + { "\nPress any key to exit..." }, + }, true, {}) + vim.fn.getchar() + os.exit(1) + end +end +vim.opt.rtp:prepend(lazypath) + +-- Make sure to setup `mapleader` and `maplocalleader` before +-- loading lazy.nvim so that mappings are correct. +-- This is also a good place to setup other settings (vim.opt) +vim.g.mapleader = " " +vim.g.maplocalleader = "\\" + +-- Setup lazy.nvim +require("lazy").setup({ + spec = { + -- import your plugins + -- { import = "plugins" }, + require("plugins") + }, + -- Configure any other settings here. See the documentation for more details. + -- colorscheme that will be used when installing plugins. + install = { colorscheme = { "gruvbox" } }, + -- automatically check for plugin updates + checker = { enabled = false }, + dev = { + path = "~/projects", + fallback = true, + }, + change_detection = { + enabled = false, -- disable automatic reloading + notify = false, -- optional: also disable notification when it would reload + }, +}) + +-- after lazy did its job +require("helpers.after") + diff --git a/lua/config/lsp.lua b/lua/config/lsp.lua new file mode 100644 index 0000000..45bd719 --- /dev/null +++ b/lua/config/lsp.lua @@ -0,0 +1,109 @@ +-- lsp.lua +local lspconfig = require("lspconfig") +local cmp = require("cmp") + + +require("lspconfig").clangd.setup({ +}) + + +-- nvim-cmp setup +cmp.setup({ + snippet = { + expand = function(args) require("luasnip").lsp_expand(args.body) end, + }, + mapping = cmp.mapping.preset.insert({ + [""] = cmp.mapping.complete(), + [""] = cmp.mapping.confirm({ select = true }), + [""] = cmp.mapping.select_next_item(), + [""] = cmp.mapping.select_prev_item(), + }), + sources = cmp.config.sources({ + { name = "nvim_lsp" }, + { name = "luasnip" }, + }, { + { name = "buffer" }, + { name = "path" }, + }), +}) + +-- Capabilities for nvim-cmp +local capabilities = require("cmp_nvim_lsp").default_capabilities() + + +-- Example servers +local servers = { "gopls", "pyright", "lua_ls", "rust_analyzer", "clangd" } + + +require("mason-lspconfig").setup({ + ensure_installed = servers +}) +for _, lsp in ipairs(servers) do + local config = { + capabilities = capabilities, + on_attach = function(_, bufnr) + local opts = { buffer = bufnr, noremap = true, silent = true } + + -- LSP core + vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts) -- Jump to definition + vim.keymap.set("n", "gD", vim.lsp.buf.declaration, opts) -- Jump to declaration + vim.keymap.set("n", "gr", vim.lsp.buf.references, opts) -- Find references + vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts) -- Go to implementation + vim.keymap.set("n", "gt", vim.lsp.buf.type_definition, opts) -- Go to type definition + vim.keymap.set("n", "K", vim.lsp.buf.hover, opts) -- Hover docs + vim.keymap.set("n", "", vim.lsp.buf.signature_help, opts) -- Signature help + + -- Refactor + vim.keymap.set("n", "rn", vim.lsp.buf.rename, opts) -- Rename symbol + vim.keymap.set("n", "ca", vim.lsp.buf.code_action, opts) -- Code actions + + -- Diagnostics + vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, opts) -- Previous diagnostic + vim.keymap.set("n", "]d", vim.diagnostic.goto_next, opts) -- Next diagnostic + vim.keymap.set("n", "e", vim.diagnostic.open_float, opts) -- Show diagnostic + vim.keymap.set("n", "lq", vim.diagnostic.setloclist, opts) -- List diagnostics + + -- Workspace + vim.keymap.set("n", "wa", vim.lsp.buf.add_workspace_folder, opts) + vim.keymap.set("n", "wr", vim.lsp.buf.remove_workspace_folder, opts) + vim.keymap.set("n", "wl", function() + print(vim.inspect(vim.lsp.buf.list_workspace_folders())) + end, opts) + + -- Formatting + vim.keymap.set("n", "fff", function() + vim.lsp.buf.format({ async = true }) + end, opts) + end + } + if lsp == "lua_ls" then + config.settings = { + Lua = { + diagnostics = { + globals = { "vim" }, + }, + }, + } + end + + if lsp == "clangd" then + config.cmd = { + "clangd", + "--query-driver=/run/current-system/sw/bin/clang", + "--compile-commands-dir=build", + } + end + + lspconfig[lsp].setup(config) +end +-- Diagnostic config (inline virtual text + signs + underlines) +vim.diagnostic.config({ + virtual_text = { + prefix = "●", -- could be '●', '▎', 'x' + spacing = 2, + }, + signs = true, + underline = true, + update_in_insert = false, + severity_sort = true, +}) diff --git a/lua/config/options.lua b/lua/config/options.lua new file mode 100644 index 0000000..3a7ba4c --- /dev/null +++ b/lua/config/options.lua @@ -0,0 +1,23 @@ + +-- vim.o.textwidth = 80 +-- vim.o.wrap = true; +vim.o.shiftwidth = 4; +vim.o.tabstop = 4; +vim.o.number = true; +vim.o.ignorecase = true; +vim.o.mouse= ""; + +-- this stands for undofile and should be always used because why not? +vim.o.udf = true; + +-- optionally enable 24-bit colour +vim.opt.termguicolors = true + +if vim.g.diffm then + vim.g.loaded_netrw = 0 + vim.g.loaded_netrwPlugin = 0 +else + vim.g.loaded_netrw = 1 + vim.g.loaded_netrwPlugin = 1 +end +vim.opt.signcolumn = "yes" diff --git a/lua/custom/journal.lua b/lua/custom/journal.lua new file mode 100644 index 0000000..59ce1a6 --- /dev/null +++ b/lua/custom/journal.lua @@ -0,0 +1,66 @@ +local M = {} + +local journal_base_raw = "~/management/brainstore/knowledge/journal" +local journal_base = vim.fn.expand(journal_base_raw) + +M.open_today = function() + local date = os.date("*t") + local day = os.date("%d") + local month = os.date("%m") + local year = tostring(date.year) + + -- Define the filename and full path + local filename = string.format("%s.%s.md", day, month) + local full_path = string.format("%s/%s/%s", journal_base, year, filename) + + -- Create the year folder if it doesn't exist + vim.fn.system({ "mkdir", "-p", journal_base .. "/" .. year }) + + -- Check if the file exists and create it if not + local file = io.open(full_path, "r") + if not file then + -- If the file does not exist, create and write the header + local header = string.format("# Journal Entry - [[date:%s]]\n\n", os.date("%d.%m.%y")) + file = io.open(full_path, "w") + file:write(header) + file:close() + end + + -- Open the file for editing + vim.cmd("edit " .. full_path) + vim.cmd("normal! G") +end + + +M.search_this_month = function() + local date = os.date("*t") + + local month = os.date("%m") + local year = tostring(date.year) + + local path = string.format("%s/%s", journal_base, year) + + -- Use telescope or fzf-lua + require('telescope.builtin').find_files { + prompt_title = "Journal Entries This Month", + cwd = path, + find_command = { + "rg", "--files", "--glob", "*.md", "-e", string.format("^\\d\\d.%s.md", month) + }, + } +end + + +M.list_all_journals = function() + -- Use telescope or fzf-lua + require('telescope.builtin').find_files { + prompt_title = "All Journal Entries", + cwd = journal_base, -- Start from the base folder + find_command = { + "rg", "--files", "--glob", "*/??.??.md", + }, + } +end + +return M + diff --git a/lua/custom/todo.lua b/lua/custom/todo.lua new file mode 100644 index 0000000..29b2478 --- /dev/null +++ b/lua/custom/todo.lua @@ -0,0 +1,140 @@ +-- custom module for todo file editing support in neovim +-- inspired by a older plugin that does basically the same + +local M = {} + +local function is_todo_file() + return vim.fn.expand("%:t") == "todo.txt" +end + +function M.set_priority(letter) + if not is_todo_file() then return end + local line = vim.api.nvim_get_current_line() + line = line:gsub("^%(%u%)%s*", "") + vim.api.nvim_set_current_line(string.format("(%s) %s", letter:upper(), line)) +end + +-- Remove priority +function M.remove_priority() + if not is_todo_file() then return end + local line = vim.api.nvim_get_current_line() + line = line:gsub("^%(%u%)%s*", "") + vim.api.nvim_set_current_line(line) +end + +local function strip_ansi(s) + return s:gsub("\27%[[0-9;]*m", "") +end + +function M.mark_done() + if not is_todo_file() then return end + + --local line = vim.api.nvim_get_current_line():match("^%s*(.-)%s*$") + + --local tasks = vim.fn.systemlist("todo.sh list") + --for _, task in ipairs(tasks) do + -- -- + -- local num,_, desc = task:match("^(%d+)%s(?:%(%S%)%s+)?(.+)$") + -- if desc == line then + -- id = num + -- break + -- end + --end + + print("Marked todo as done! (just deleted)") + vim.cmd("normal! dd") +end + +-- Util: remove empty lines +local function strip_blank_lines(lines) + local cleaned = {} + for _, line in ipairs(lines) do + if line:match("%S") then + table.insert(cleaned, line) + end + end + return cleaned +end + +-- Grouped sort logic +local function grouped_sort(key_fn) + if not is_todo_file() then return end + local lines = strip_blank_lines(vim.api.nvim_buf_get_lines(0, 0, -1, false)) + local buckets = {} + + for _, line in ipairs(lines) do + local key = key_fn(line) + if not buckets[key] then + buckets[key] = {} + end + table.insert(buckets[key], line) + end + + local sorted_keys = {} + for key in pairs(buckets) do table.insert(sorted_keys, key) end + table.sort(sorted_keys) + + local final_lines = {} + for _, key in ipairs(sorted_keys) do + for _, line in ipairs(buckets[key]) do + table.insert(final_lines, line) + end + table.insert(final_lines, "") -- add blank line after group + end + + -- Remove final blank line if it exists + if final_lines[#final_lines] == "" then + table.remove(final_lines) + end + + vim.api.nvim_buf_set_lines(0, 0, -1, false, final_lines) +end + +-- Key extractors +local function get_priority_key(line) + local p = line:match("^%((%u)%)") + return p and p or "~" -- tilde = sorts after all letters +end + +local function get_context_key(line) + local c = line:match("@(%w+)") + return c and c or "~" +end + +local function get_project_key(line) + local p = line:match("%+(%w+)") + return p and p or "~" +end + +-- Sorters +function M.sort_by_priority() + grouped_sort(get_priority_key) +end + +function M.sort_by_context() + grouped_sort(get_context_key) +end + +function M.sort_by_project() + grouped_sort(get_project_key) +end + +function M.setup() + local opts = { noremap = true, silent = true } + + for i = string.byte("a"), string.byte("z") do + local letter = string.char(i) + vim.keymap.set("n", "p" .. letter, function() M.set_priority(letter) end, opts) + end + + vim.keymap.set("n", "p", M.remove_priority, opts) + + vim.keymap.set("n", "sp", M.sort_by_priority, opts) + vim.keymap.set("n", "sc", M.sort_by_context, opts) + vim.keymap.set("n", "sr", M.sort_by_project, opts) + + -- New keymap for marking todo as done + vim.keymap.set("n", "td", M.mark_done, opts) +end + +return M diff --git a/lua/custom/uni.lua b/lua/custom/uni.lua new file mode 100644 index 0000000..9d57ee2 --- /dev/null +++ b/lua/custom/uni.lua @@ -0,0 +1,151 @@ +local fzf = require("fzf-lua") +local fn = vim.fn +local uv = vim.loop +local current_season = "S3" + +-- Function to scan for .unicourse files and get their course directories +function get_course_directories() + local dirs = {} + local function scan_dir(dir) + for _, entry in ipairs(fn.glob(dir .. "/*", true, true)) do + if fn.isdirectory(entry) == 1 then + local unicourse_file = entry .. "/.unicourse" + if fn.filereadable(unicourse_file) == 1 then + local course_info = {} + for line in io.lines(unicourse_file) do + if line:match("^name: ") then + course_info.name = line:sub(7) + elseif line:match("^short: ") then + course_info.short = line:sub(8) + end + end + if course_info.name and course_info.short then + table.insert(dirs, { name = course_info.name, short = course_info.short, path = entry }) + end + end + end + end + end + + scan_dir("/home/jonas/projects/university/" .. current_season) -- Assuming all your courses are under the S2 folder + return dirs +end + +-- Function to show the fzf menu for selecting a course directory +function select_course_directory() + local courses = get_course_directories() + local course_names = {} + + for _, course in ipairs(courses) do + table.insert(course_names, course.name .. " (" .. course.short .. ")") + end + + fzf.fzf_exec(course_names, { + prompt = "Select a course > ", + actions = { + ["default"] = function(selected) + for _, course in ipairs(courses) do + if selected[1] == (course.name .. " (" .. course.short .. ")") then + show_course_menu(course) + break + end + end + end, + }, + }) +end + +-- Function to show the fzf menu for actions on a selected course folder +function show_course_menu(course) + local files = {} + -- Collect all VL files in the Vorlesungen directory + for _, file in ipairs(fn.glob(course.path .. "/VL/*", true, true)) do + if file:match("%.typ$") then + table.insert(files, file) + end + end + + -- Collect options + -- TODO: implement zettel (Hausaufgaben) management + -- For example creation of new ones and quick opening of the pdfs + local options = { + "Open the newest VL file", + "Create a new VL", + "Open the course folder", + "Open a specific file", + } + + fzf.fzf_exec(options, { + prompt = "Choose an action > ", + actions = { + ["default"] = function(selected) + if selected[1] == "Open the newest VL file" then + local newest_file = get_newest_vl_file(files) + vim.cmd("edit " .. newest_file) + elseif selected[1] == "Create a new VL" then + create_new_vl(course) + elseif selected[1] == "Open the course folder" then + vim.cmd("edit " .. course.path) + elseif selected[1] == "Open a specific file" then + fzf.fzf_exec(fn.glob(course.path .. "/*", true, true), { + prompt = "Pick a file to open > ", + actions = { + ["default"] = function(file) + vim.cmd("edit " .. file[1]) + end, + }, + }) + end + end, + }, + }) +end + +-- Function to get the newest VL file based on modification time +function get_newest_vl_file(files) + local newest_file = nil + local newest_time = 0 + for _, file in ipairs(files) do + local stat = fn.getftime(file) + if stat > newest_time then + newest_time = stat + newest_file = file + end + end + return newest_file +end + +-- Function to create a new VL file based on the template and incrementing the number +function create_new_vl(course) + local vl_dir = course.path .. "/VL" + local success, _ = pcall(function() + vim.fn.mkdir(vl_dir) + end) + -- Hard coded this + local template_path = vim.fn.expand("~/projects/university/data/template.typ") + if fn.filereadable(template_path) == 1 then + -- Find the latest VL number in the folder + local latest_num = 0 + for _, file in ipairs(fn.glob(vl_dir .. "/*", true, true)) do + if file:match(course.short .. "VL(%d+).typ$") then + local num = tonumber(file:match(course.short .. "VL(%d+).typ$")) + if num > latest_num then + latest_num = num + end + end + end + + -- Create new VL file with incremented number + local new_vl_name = string.format("%sVL%d.typ", course.short, latest_num + 1) + local new_vl_path = vl_dir .. "/" .. new_vl_name + + -- Copy the template if it exists + vim.fn.system({"cp", template_path, new_vl_path}) + + -- Open the new VL file + vim.cmd("edit " .. new_vl_path) + else + print("Template file (template.typ) not found!") + end +end + diff --git a/lua/helpers/after.lua b/lua/helpers/after.lua new file mode 100644 index 0000000..c060be0 --- /dev/null +++ b/lua/helpers/after.lua @@ -0,0 +1,247 @@ +-- Disable lsp stuff +-- xzl +-- setup mason +-- xzl +--require("mason").setup() +--require("mason-lspconfig").setup({ +-- ensure_installed = { "rust_analyzer", "pyright" }, -- Example LSPs +--}) + +-- Example: Configure a server +-- TODO: this has to be done better and automatically +--local lspconfig = require("lspconfig") +--lspconfig.rust_analyzer.setup({}) +--lspconfig.pyright.setup({}) + + +if vim.g.diffm then + -- setup tree + require("nvim-tree").setup({ + sort_by = "case_sensitive", + view = { + width = 35, + }, + disable_netrw = false, + }) +else + -- stuff for only main + require 'telescope'.setup { + extensions = { + }, + } + + -- load custom todo plugin + require("custom.todo").setup() + + + -- configure a workflow that integrates image support in documents and a quick opening of them + local base_zet = "~/synced/brainstore/zettelkasten" + require('telekasten').setup({ + home = vim.fn.expand(base_zet), -- Put the name of your notes directory here + dailies = vim.fn.expand(base_zet .. "/daily"), + -- how to change the defualt media folder? + image_subdir = vim.fn.expand(base_zet .. "/media"), + weeklies = vim.fn.expand(base_zet .. "/weekly"), + templates = vim.fn.expand(base_zet .. "/templates"), + template_new_note = vim.fn.expand(base_zet .. "/templates/note.md"), + template_new_daily = vim.fn.expand(base_zet .. "/templates/daily.md"), + template_new_weekly = vim.fn.expand(base_zet .. "/templates/weekly.md"), + + -- auto_set_filetype = false, + -- Important part: + filename_format = "%Y%m%d%H%M-%title%", -- This adds the timestamp + slugged title + new_note_filename = "uuid-title", -- Set naming convention to use uuid first + uuid_type = "%Y%m%d%H%M", -- Timestamp as UUID + uuid_separator = "-", + }) + + -- setup tree + require("nvim-tree").setup({ + sort_by = "case_sensitive", + -- open_on_tab = true, + + view = { + width = 35, + side = "right", + preserve_window_proportions = true, + number = false, + relativenumber = false, + }, + update_focused_file = { + enable = false, + }, + + renderer = { + group_empty = true, + highlight_git = true, + highlight_opened_files = "name", + indent_markers = { + enable = true, + }, + icons = { + show = { + file = false, + folder = false, + folder_arrow = true, + git = false, + modified = false, + hidden = false, + diagnostics = false, + }, + }, + }, + + filters = { + dotfiles = false, -- << SHOW dotfiles by default + git_clean = false, + no_buffer = false, + custom = { ".DS_Store", ".git" }, -- Mac stuff you probably don't need + }, + + git = { + enable = true, + ignore = false, -- so it shows even ignored files + }, + + actions = { + open_file = { + quit_on_open = false, -- keep tree open after opening a file + resize_window = true, + }, + }, + + }) +end + +-- stuff for both + +-- lualine mode for the current workingdir +local function get_cwd() + local cwd = vim.fn.getcwd() + local home = os.getenv("HOME") + + -- Check if the current directory starts with the home directory path + if cwd:sub(1, #home) == home then + return "~" .. cwd:sub(#home + 1) + else + return cwd + end +end + +require('lualine').setup { + options = { + icons_enabled = false, + theme = 'gruvbox', + -- think those icons are okay + component_separators = { left = '', right = '' }, + section_separators = { left = '', right = '' }, + always_divide_middle = true, + always_show_tabline = true, + globalstatus = false, + refresh = { + statusline = 300, + tabline = 300, + winbar = 300, + } + }, + sections = { + lualine_a = { 'mode' }, + lualine_b = { 'branch', 'diff', 'diagnostics' }, + lualine_c = { get_cwd, '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 = {} + }, + extensions = { "nvim-tree" } +} + + + +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 + + + map('n', ']c', function() + if vim.wo.diff then + vim.cmd.normal({ ']c', bang = true }) + else + gitsigns.nav_hunk('next') + end + vim.cmd("normal! zz") -- center cursor + end, { silent = true }) + + map('n', '[c', function() + if vim.wo.diff then + vim.cmd.normal({ '[c', bang = true }) + else + gitsigns.nav_hunk('prev') + end + vim.cmd("normal! zz") -- center cursor + end, { silent = true }) + + -- Actions + map('n', 'hs', gitsigns.stage_hunk) + map('n', 'hr', gitsigns.reset_hunk) + + map('v', 'hs', function() + gitsigns.stage_hunk({ vim.fn.line('.'), vim.fn.line('v') }) + end) + + map('v', 'hr', function() + gitsigns.reset_hunk({ vim.fn.line('.'), vim.fn.line('v') }) + end) + + map('n', 'hS', gitsigns.stage_buffer) + map('n', 'hR', gitsigns.reset_buffer) + map('n', 'hp', gitsigns.preview_hunk) + map('n', 'hi', gitsigns.preview_hunk_inline) + + + map('n', 'hb', function() + gitsigns.blame_line({ full = true }) + end) + + map('n', 'hd', gitsigns.diffthis) + + map('n', 'hD', function() + gitsigns.diffthis('~') + end) + + map('n', 'hQ', function() gitsigns.setqflist('all') end) + map('n', 'hq', gitsigns.setqflist) + + -- Toggles + map('n', 'tb', gitsigns.toggle_current_line_blame) + map('n', 'tw', gitsigns.toggle_word_diff) + + -- Text object + map({ 'o', 'x' }, 'ih', gitsigns.select_hunk) + end +} + +require("lspsaga").setup({ + lightbulb = { + enable = false, + enable_in_insert = false, -- don’t show in insert mode + sign = false, + + virtual_text = false, + }, + ui = { + } +}) diff --git a/lua/helpers/functions.lua b/lua/helpers/functions.lua new file mode 100644 index 0000000..47ff290 --- /dev/null +++ b/lua/helpers/functions.lua @@ -0,0 +1,214 @@ +-- General helper functions + +function sleep(n) + os.execute("sleep " .. tonumber(n)) +end + + +-- branching depeding on diff mode +if vim.g.diffm then + -- diffmode +else + -- Function to open NvimTree based on current file or Git root + local api = require("nvim-tree.api") + function open_tree_based_on_file() + local file_path = vim.fn.expand("%:p") + local git_root = vim.fn.system("git rev-parse --show-toplevel"):gsub("\n", "") + local dir = vim.fn.filereadable(file_path) and vim.fn.fnamemodify(file_path, ":p:h") or "" + + -- If inside a Git repo, use the Git root as the base directory + local open_dir = git_root ~= "" and git_root or dir + + -- Open NvimTree in that directory + api.tree.open({ path = open_dir }) + end + + function open_vorlesung() + local mapss = require("config.keymaps") + -- get globals + set_obs() + local uni_dir = vim.fn.expand("~/projects/university/" .. _G.season) + + require('telescope.builtin').find_files { + prompt_title = "Select Vorlesung in " .. _G.season, + cwd = uni_dir, + find_command = { + "eza", "-1", "-D" + }, + } + + end + + -- TODO: fix not putting the pdf in another dir then the current workdir + -- when in a uni folder + -- Open and watch typst + local watch_job_id = nil + local watch_buf_id = nil + function watch_and_open() + local input = vim.fn.expand("%:p") + if not input:match("%.typ$") then + vim.notify("Not a Typst file", vim.log.levels.WARN) + return + end + + local dir = vim.fn.fnamemodify(input, ":h") -- directory of the Typst file + local filename = vim.fn.expand("%:t:r") .. ".pdf" -- filename without extension + .pdf + + -- Get the underlying unicourse dir + local one_up = vim.fn.fnamemodify(dir, ":h") + + print(one_up) + local pdf_dir = nil + if vim.fn.filereadable(one_up .. "/.unicourse") == 1 then + pdf_dir = one_up .. "/../../pdfs" + else + pdf_dir = dir + end + + vim.fn.mkdir(pdf_dir, "p") + local output = pdf_dir .. "/" .. filename + + -- Check if a watcher is already running for this file + if watch_job_id then + vim.notify("Typst watcher already running - please close zathura", vim.log.levels.INFO) + return + end + + + + -- Start typst watch + local cwd = vim.fn.getcwd() -- set the starting directory + -- TODO: root setting does not work + local watch_cmd = { "typst", "watch", "--root", cwd, input, output } + watch_job_id = vim.fn.jobstart(watch_cmd, { + stdout_buffered = false, + stderr_buffered = false, -- Ensure stderr is unbuffered for real-time error output + on_stderr = function(_, data) + if data then + if not watch_tab_id then + pre_tab = vim.api.nvim_get_current_tabpage() -- Get the current tab ID + vim.cmd('tabnew') -- Open a new tab + watch_tab_id = vim.api.nvim_get_current_tabpage() -- Get the current tab ID + watch_buf_id = vim.api.nvim_get_current_buf() -- Get the buffer ID of the new tab + vim.api.nvim_buf_set_option(watch_buf_id, "swapfile", false) + vim.api.nvim_buf_set_name(watch_buf_id, "/tmp/TypstLog") + vim.api.nvim_buf_set_lines(watch_buf_id, 0, 0, false, { "Watching: " .. input }) -- Insert at the top + vim.cmd('write!') + vim.api.nvim_set_current_tabpage(pre_tab) + end + -- Write stdout data to the same buffer + for _, line in ipairs(data) do + if line ~= "" then + vim.api.nvim_buf_set_lines(watch_buf_id, -1, -1, false, { "[LOG] " .. line }) + end + end + end + end, + on_exit = function(_, exit_code) + -- Ensure to close the tab that holds the logs + --if watch_tab_id then + -- -- Switch to the tab holding the log buffer and close it + -- vim.api.nvim_set_current_tabpage(watch_tab_id) + -- vim.cmd('tabclose') -- Close the tab holding the log buffer + --end + if exit_code == 0 then + vim.notify("Typst watch stopped successfully", vim.log.levels.INFO) + else + vim.notify("Typst watch stopped with errors", vim.log.levels.ERROR) + end + watch_job_id = nil + end, + }) + vim.notify("Started Typst watch", vim.log.levels.INFO) + + -- Start sioyek with the --new-window flag and stop watch when it exits + -- ensure that there is no sioyek + vim.fn.system("killall .zathura-wrapped") + sleep(0.5) + vim.fn.jobstart({ "zathura", output }, { + on_exit = function() + if watch_job_id then + vim.fn.jobstop(watch_job_id) + end + watch_job_id = nil + end, + }) + end + +end + + +function find_eff() + require('telescope.builtin').find_files({ + hidden = true, -- show hidden files (dotfiles) + no_ignore = true, -- respect .gitignore (ignore files listed in .gitignore) + follow = true, -- follow symlinks + disable_devicons = true, + + -- Additional filtering to exclude .git, .cache, .local, and large files + prompt_title = "Find Files - custom", + find_command = { + "rg", "--files", + "--glob", "!**/.git/*", + "--glob", "!**/.cache/*", + "--glob", "!**/.local/*", + "--glob", "!**/bigfiles/*", -- exclude large files folder + "--glob", "!**/*.{jpg,png,gif,mp4,mkv,tar,zip,iso}" -- exclude some large file types + } + }) +end + + + +-- TODO: implement this +--function search_brain_links() +-- local fzf = require('fzf') +-- local cmd = "grep -oP '\\[\\[.*:' " .. vim.fn.expand('%') -- grep pattern to search for [[.*: +-- fzf.fzf(cmd, { +-- preview = "bat --style=numbers --color=always --line-range :500", -- preview with bat (optional) +-- sink = function(selected) +-- if selected and #selected > 0 then +-- local line = vim.fn.search(selected[1], 'n') -- jump to the match +-- if line > 0 then +-- vim.api.nvim_win_set_cursor(0, {line, 0}) +-- end +-- end +-- end +-- }) +--end + + +function set_root() + local current_file = vim.fn.expand('%:p:h') -- get directory of current file + local cmd = 'git -C ' .. vim.fn.fnameescape(current_file) .. ' status' + vim.fn.system(cmd) + if vim.v.shell_error == 0 then + local git_root = vim.fn.systemlist('git -C ' .. vim.fn.fnameescape(current_file) .. ' rev-parse --show-toplevel')[1] + vim.cmd('cd ' .. vim.fn.fnameescape(git_root)) + else + vim.cmd('cd ' .. vim.fn.fnameescape(current_file)) + end +end + + +-- Function to open the last file +function open_last_file() + local last_file_path = vim.fn.stdpath('data') .. "/lastfile.txt" + local file = io.open(last_file_path, "r") + if file then + local last_file = file:read("*line") + file:close() + if last_file and vim.fn.filereadable(last_file) == 1 then + vim.cmd("edit " .. last_file) + local success, _ = pcall(function() + vim.cmd('normal! `.') -- Go to the last edit position + vim.cmd('normal! zz') -- Center the cursor on the screen + end) + else + print("Last file does not exist or is not readable") + end + else + print("No last file found") + end +end + diff --git a/lua/helpers/linker.lua b/lua/helpers/linker.lua new file mode 100644 index 0000000..0df3c6c --- /dev/null +++ b/lua/helpers/linker.lua @@ -0,0 +1,256 @@ +-- this is the linker logic for nvim + +local M = {} + +local brainstore_dir = "~/synced/brainstore" +local projects_dir = "~/projects" +local mail_dir = "~/mail/plain_emails" +local contacts_file = "~/synced/vault/contacts/contacts.txt" +local cal_dir = "~/synced/brainstore/calendar" + +function fzf_select(options, prompt, callback) + local fzf = require("fzf-lua") + fzf.fzf_exec(options, { + prompt = prompt .. "> ", + actions = { + ["default"] = function(selected) + if selected and selected[1] then + callback(selected[1]) + end + end, + }, + }) +end + +function M.insert_brainstore_link() + require('telescope.builtin').find_files({ + hidden = true, + no_ignore = true, + follow = true, + prompt_title = "Things in Brain", + cwd = vim.fn.expand(brainstore_dir), + find_command = { + "rg", "--files", + "--hidden", + "--glob", "!**/.git/*", + "--glob", "!**/*.{jpg,png,gif,mp4,mkv,tar,zip,iso}", + }, + attach_mappings = function(prompt_bufnr, map) + local actions = require('telescope.actions') + local action_state = require('telescope.actions.state') + + local function insert_link() + local selection = action_state.get_selected_entry() + if not selection then + return + end + local selected = selection.path or selection.filename or selection[1] + if selected then + actions.close(prompt_bufnr) -- CLOSE with prompt_bufnr + local link = "[[brain:" .. selected:gsub(vim.fn.expand(brainstore_dir) .. "/", "") .. "]]" + vim.cmd("normal! h") + vim.api.nvim_put({link}, "c", true, true) + end + end + + map('i', '', insert_link) + map('n', '', insert_link) + + return true + end + }) +end + +-- fetches new send mail and creates a link to a selected mail +-- the link can the like any other link followed +function M.insert_mail_link() + -- TODO: real parsing of the mails when there are multiple in one file + vim.fn.system("python " .. vim.fn.expand("~/projects/scripts/extract_mail.py")) + vim.fn.system("find " .. mail_dir .. " -type f > /tmp/mail_files") + local mails = vim.fn.readfile("/tmp/mail_files") + + fzf_select(mails, "Mails", function(selected) + local link = "[[mail:" .. selected:gsub(vim.fn.expand(mail_dir) .. "/", "") .. "]]" + vim.api.nvim_put({link}, "c", true, true) + end) +end + +function M.insert_contact_link() + local contacts = vim.fn.readfile(vim.fn.expand(contacts_file)) + + fzf_select(contacts, "Contacts", function(selected) + local name = selected:match("^(.-)%s") or selected -- get first word as contact name + local link = "[[contact:" .. name .. "]]" + vim.api.nvim_put({link}, "c", true, true) + end) +end + +function M.insert_date_link() + local year = os.date("%y") -- get current year (e.g., "25" for 2025) + local text = string.format("[[date:.%s]]", year) + + vim.api.nvim_put({ text }, "c", true, true) + + -- Move cursor back inside the brackets before the year + local row, col = unpack(vim.api.nvim_win_get_cursor(0)) + -- Move left by 2 + length of year (e.g., 2 + 2 = 4 for "25") + vim.api.nvim_win_set_cursor(0, { row, col - 4 }) + vim.cmd("startinsert") +end + +function M.insert_project_link() + require('telescope.builtin').find_files({ + hidden = true, + no_ignore = true, + disable_devicons = true, + follow = true, + prompt_title = "List of projects", + cwd = vim.fn.expand(projects_dir), + find_command = { + "eza", "-1", "-D", + }, + attach_mappings = function(prompt_bufnr, map) + local actions = require('telescope.actions') + local action_state = require('telescope.actions.state') + + local function insert_link() + local selection = action_state.get_selected_entry() + if not selection then + return + end + local selected = selection.path or selection.filename or selection[1] + if selected then + actions.close(prompt_bufnr) + local project = selected:gsub(vim.fn.expand(projects_dir) .. "/", "") + + + require('telescope.builtin').find_files({ + hidden = true, + no_ignore = true, + follow = true, + disable_devicons = true, + prompt_title = "Pick a file. Press to link just " .. project .. ".", + cwd = vim.fn.expand(selected), + find_command = { + "rg", "--files", + "--hidden", + "--glob", "!**/.git/*", + }, + attach_mappings = function(prompt_bufnr, map) + local actions = require('telescope.actions') + local action_state = require('telescope.actions.state') + + local function insert_link() + local selection = action_state.get_selected_entry() + if not selection then + return + end + local selected = selection.path or selection.filename or selection[1] + if selected then + actions.close(prompt_bufnr) + local link = "[[project:" .. selected:gsub(vim.fn.expand(projects_dir) .. "/", "") .. "]]" + vim.api.nvim_put({link}, "c", true, true) + end + end + + local function insert_link_top() + actions.close(prompt_bufnr) + local link = "[[project:" .. project .. "]]" + vim.api.nvim_put({link}, "c", true, true) + end + + map('i', '', insert_link) + map('n', '', insert_link) + + map('i', '', insert_link_top) + map('n', '', insert_link_top) + + + return true + end + }) + + + + end + end + + map('i', '', insert_link) + map('n', '', insert_link) + + return true + end + }) +end + + +local function spliting(inputstr, sep) + if sep == nil then + sep = "%s" + end + local t = {} + for str in string.gmatch(inputstr, "([^"..sep.."]+)") do + table.insert(t, str) + end + return t +end + +local function pad2(n) + n = tonumber(n) + if n < 10 then + return "0" .. n + else + return tostring(n) + end +end + +-- The heart of this project following +-- Remember to go back with C-O +function M.follow_link() + local line = vim.api.nvim_get_current_line() + local link = line:match("%[%[(.-)%]%]") + if not link then + print("No link found on this line.") + return + end + + local kind, target = link:match("^(.-):(.*)$") + if not kind or not target then + print("Invalid link format.") + return + end + + + -- List of all kinds that are available + -- Here brainstore and projects are kind of the same but I keep them separated + if kind == "brain" then + vim.cmd("edit " .. brainstore_dir .. "/" .. target) + elseif kind == "mail" then + vim.cmd("edit " .. mail_dir .. "/" .. target) + elseif kind == "contact" then + vim.cmd("vsplit " .. contacts_file) + vim.cmd("/" .. target) + elseif kind == "project" then + vim.cmd("edit " .. projects_dir .. "/" .. target) + elseif kind == "date" then + -- target: "4.3.25" or "03.04.2034" + local splits = spliting(target, '.') + local day = pad2(splits[1]) + local month = pad2(splits[2]) + local year = splits[3] + + -- Normalize year: if 4 digits, cut to last two + if #year == 4 then + year = year:sub(3, 4) + end + + vim.cmd("edit " .. cal_dir .. "/calendar_20" .. year .. ".txt") + vim.cmd("/" .. "20" .. year .. "-" .. month .. "-" .. day) + vim.cmd("normal! zz") + else + print("Unknown link type: " .. kind .. ". Must be one of: " .. "mail, contact, project, brain, date.") + end +end + +return M + diff --git a/lua/plugins/diff.lua b/lua/plugins/diff.lua new file mode 100644 index 0000000..b39c93a --- /dev/null +++ b/lua/plugins/diff.lua @@ -0,0 +1,27 @@ +return { + {"sindrets/diffview.nvim", + dependencies = { + "nvim-lua/plenary.nvim", + "nvim-tree/nvim-web-devicons", + }, + }, + { + -- this is the nvim tree but I dont use it yet + "nvim-tree/nvim-tree.lua", + }, + { + 'nvim-lualine/lualine.nvim', + -- dependencies = { 'nvim-tree/nvim-web-devicons' } + }, + { + "ellisonleao/gruvbox.nvim", + }, + { + "folke/which-key.nvim", + event = "VeryLazy", + opts = { + icons = {mappings = false,}, + delay = 1500, + }, + }, +}; diff --git a/lua/plugins/init.lua b/lua/plugins/init.lua new file mode 100644 index 0000000..a4b4e64 --- /dev/null +++ b/lua/plugins/init.lua @@ -0,0 +1,9 @@ +local plugins = {} + +if vim.g.diffm then + vim.list_extend(plugins, require("plugins.diff")) +else + vim.list_extend(plugins, require("plugins.main")) +end + +return plugins diff --git a/lua/plugins/main.lua b/lua/plugins/main.lua new file mode 100644 index 0000000..d362890 --- /dev/null +++ b/lua/plugins/main.lua @@ -0,0 +1,238 @@ +return { + { + "ThePrimeagen/harpoon", + }, + { "akinsho/toggleterm.nvim", config = true }, + { "nvimdev/lspsaga.nvim", config = true }, + { + "kdheepak/lazygit.nvim", + lazy = true, + cmd = { + "LazyGit", + "LazyGitConfig", + "LazyGitCurrentFile", + "LazyGitFilter", + "LazyGitFilterCurrentFile", + }, + -- optional for floating window border decoration + dependencies = { + "nvim-lua/plenary.nvim", + }, + -- setting the keybinding for LazyGit with 'keys' is recommended in + -- order to load the plugin when the command is run for the first time + keys = { + { "lg", "LazyGit", desc = "LazyGit" } + }}, + { + -- treesitter + "nvim-treesitter/nvim-treesitter", + build = ":TSUpdate", + -- prio is needed for this + -- + -- not needed cmd = { "NvimTreeToggle", "NvimTreeOpen" }, -- load only when you call these commands + priority = 1000, + config = function () + local configs = require("nvim-treesitter.configs") + configs.setup({ + ensure_installed = {"css", "typst", "bash", "markdown", "lua", "python", "rust", "c", "nix"}, + sync_install = false, + highlight = { enable = true }, + indent = { enable = true }, + }) + end + }, + { + -- great typstar works only with luasnip + ft = {"typst"}, + "Ascyii/typstar", + dev = true, + config = function() + require("typstar").setup({ + typstarRoot = "~/projects/typstar", + rnote = { + assetsDir = 'assets', + -- can be modified to e.g. export full pages; default is to try to export strokes only and otherwise export the entire document + exportCommand = 'rnote-cli export selection --no-background --no-pattern --on-conflict overwrite --output-file %s all %s || rnote-cli export doc --no-background --no-pattern --on-conflict overwrite --output-file %s %s', + filename = 'drawing-%Y-%m-%d-%H-%M-%S', + fileExtension = '.rnote', + fileExtensionInserted = '.rnote.svg', -- valid rnote export type + uriOpenCommand = 'xdg-open', -- see comment above for excalidraw + templatePath = {}, + }, + }) + end, + }, + {'romgrk/barbar.nvim', + dependencies = { + 'lewis6991/gitsigns.nvim', -- OPTIONAL: for git status + --'nvim-tree/nvim-web-devicons', -- OPTIONAL: for file icons + }, + init = function() vim.g.barbar_auto_setup = false end, + cmd = {"BufferNext", "BufferPrevious" }, + opts = { + clickable = false, + tabpages = false, + animations = false, + icons = { filetype = { enabled = false } } + + }, + version = '^1.0.0', -- optional: only update when a new 1.x version is released + }, + -- Does not work in nvim ? + + -- {"freitass/todo.txt-vim"}, + + -- { + -- 'windwp/nvim-autopairs', + -- enable = false, + -- event = "InsertEnter", + -- config = true + -- -- use opts = {} for passing setup options + -- -- this is equivalent to setup({}) function + -- }, + { + 'nvim-lualine/lualine.nvim', + -- dependencies = { 'nvim-tree/nvim-web-devicons' } + }, + { + "ibhagwan/fzf-lua", + -- optional for icon support + -- dependencies = { "nvim-tree/nvim-web-devicons" }, + -- or if using mini.icons/mini.nvim + -- dependencies = { "echasnovski/mini.icons" }, + opts = {}, + cmd = { "FzfLua" }, -- load when you call :Telekasten + }, + { + -- this is the nvim tree but I dont use it yet + "nvim-tree/nvim-tree.lua", + }, + { + "nvim-telescope/telescope.nvim", tag = '0.1.8', + dependencies = { "nvim-lua/plenary.nvim" }, + }, + { + "ellisonleao/gruvbox.nvim", + }, + -- Will see how this integrates with the existing workflow and what features I can impleemtn by + -- { + -- "nvim-neorg/neorg", + -- lazy = false, -- Disable lazy loading as some `lazy.nvim` distributions set `lazy = true` by default + -- version = "*", -- Pin Neorg to the latest stable release + -- config = true, + -- }, + -- Disable lsp stuff + --{ + -- -- lsp stuff + -- "williamboman/mason.nvim", + -- -- TODO: implement things like rename variables and stuff + -- "williamboman/mason-lspconfig.nvim", + -- "neovim/nvim-lspconfig", + --}, + { + -- LuaSnip configuration + "L3MON4D3/LuaSnip", + version = "v2.*", + build = "make install_jsregexp", + event = "InsertEnter", + config = function() + local ls = require("luasnip") + ls.config.setup({ + enable_autosnippets = true, + store_selection_keys = '', + }) + vim.keymap.set({"i", "s"}, "", function() ls.jump(1) end, {silent = true}) + vim.keymap.set({"i", "s"}, "", function() ls.jump(-1) end, {silent = true}) + end, + }, + -- { + -- "hrsh7th/nvim-cmp", + -- event = "InsertEnter", + -- dependencies = { + -- "hrsh7th/cmp-nvim-lsp", + -- "hrsh7th/cmp-buffer", + -- "hrsh7th/cmp-path", + -- "hrsh7th/cmp-cmdline", + -- "L3MON4D3/LuaSnip", + -- "saadparwaiz1/cmp_luasnip", + -- }, + -- config = function() + -- local cmp = require("cmp") + -- local luasnip = require("luasnip") + -- + -- cmp.setup({ + -- completion = { + -- autocomplete = false, + -- }, + -- snippet = { + -- expand = function(args) + -- require("luasnip").lsp_expand(args.body) + -- end, + -- }, + -- mapping = { + -- [""] = cmp.mapping(function(fallback) + -- if cmp.visible() then + -- cmp.select_next_item() + -- elseif luasnip.expand_or_jumpable() then + -- luasnip.expand_or_jump() + -- else + -- cmp.complete() + -- vim.defer_fn(function() + -- if cmp.visible() then cmp.select_next_item() end + -- end, 10) + -- end + -- end, { "i", "s" }), + -- [""] = cmp.mapping(function(fallback) + -- if cmp.visible() then + -- cmp.select_prev_item() + -- elseif luasnip.jumpable(-1) then + -- luasnip.jump(-1) + -- else + -- fallback() + -- end + -- end, { "i", "s" }), + -- [""] = cmp.mapping.confirm({ select = true }), + -- }, + -- sources = cmp.config.sources({ + -- { name = "nvim_lsp" }, + -- { name = "luasnip" }, + -- }, { + -- { name = "buffer" }, + -- }), + -- }) + -- end, + -- }, + { + 'Ascyii/telekasten.nvim', + dev = true, + }, + { + "folke/which-key.nvim", + event = "VeryLazy", + opts = { + -- your configuration comes here + -- or leave it empty to use the default settings + -- refer to the configuration section below + icons = {mappings = false,}, + -- set this delay so that its only used for + delay = 1500, + }, + }, + -- LSP support + { "neovim/nvim-lspconfig" }, + { "stevearc/aerial.nvim", opts = {} }, + { "williamboman/mason.nvim", config = true }, + { "williamboman/mason-lspconfig.nvim" }, + + -- Autocompletion + { "hrsh7th/nvim-cmp" }, + { "hrsh7th/cmp-nvim-lsp" }, + { "hrsh7th/cmp-buffer" }, + { "hrsh7th/cmp-path" }, + { "saadparwaiz1/cmp_luasnip" }, + + -- UI improvements + --{ "nvimdev/lspsaga.nvim", config = true }, + --{ "folke/trouble.nvim", opts = {} }, + --{ "j-hui/fidget.nvim", tag = "legacy", config = true }, +};