From 042375f4ede6b0db20edb0f13d657a6dadccd3a6 Mon Sep 17 00:00:00 2001 From: Ivar Fatland Date: Mon, 7 Sep 2026 23:16:04 +0200 Subject: [PATCH] split things out into multiple files --- nvim/.config/nvim/init.lua | 550 ++---------------- nvim/.config/nvim/lsp/basedpyright.lua | 9 + nvim/.config/nvim/lsp/gopls.lua | 14 + nvim/.config/nvim/lsp/hls.lua | 3 + nvim/.config/nvim/lsp/lua_ls.lua | 9 + nvim/.config/nvim/lsp/ols.lua | 5 + nvim/.config/nvim/lsp/sourcekit.lua | 3 + nvim/.config/nvim/lsp/zls.lua | 5 + .../nvim/plugin/auto_select_compiler.lua | 72 +++ .../plugin/filetype_specific_settings.lua | 29 + nvim/.config/nvim/plugin/split_line.lua | 164 ++++++ nvim/.config/nvim/plugin/zen_mode.lua | 109 ++++ 12 files changed, 468 insertions(+), 504 deletions(-) create mode 100644 nvim/.config/nvim/lsp/basedpyright.lua create mode 100644 nvim/.config/nvim/lsp/gopls.lua create mode 100644 nvim/.config/nvim/lsp/hls.lua create mode 100644 nvim/.config/nvim/lsp/lua_ls.lua create mode 100644 nvim/.config/nvim/lsp/ols.lua create mode 100644 nvim/.config/nvim/lsp/sourcekit.lua create mode 100644 nvim/.config/nvim/lsp/zls.lua create mode 100644 nvim/.config/nvim/plugin/auto_select_compiler.lua create mode 100644 nvim/.config/nvim/plugin/filetype_specific_settings.lua create mode 100644 nvim/.config/nvim/plugin/split_line.lua create mode 100644 nvim/.config/nvim/plugin/zen_mode.lua diff --git a/nvim/.config/nvim/init.lua b/nvim/.config/nvim/init.lua index 359b458..e099329 100644 --- a/nvim/.config/nvim/init.lua +++ b/nvim/.config/nvim/init.lua @@ -8,78 +8,67 @@ vim.g.python3_host_prog = get_python_venv_path() -- GENERAL SETTINGS {{{1 vim.cmd [=[ - set autowriteall - set exrc - set secure - set clipboard=unnamedplus - set tabstop=4 - set shiftwidth=0 - set nu - set path=** - set nowrap - set shiftround - set expandtab - set incsearch - set guicursor=n-v-c:block-Cursor - set cursorline - set noswapfile - set list - set tags+=~/tags - set grepprg=rg\ --vimgrep\ --hidden\ --smart-case\ -g\ \'!**/tags\'\ -g\ \'!**/.git\' - set grepformat=%f:%l:%c:%m - - nnoremap ,co :copen + autocmd BufEnter *__virtual* setlocal buftype=nofile bufhidden=hide noswapfile + autocmd BufWinEnter *.* silent! loadview + autocmd BufWinLeave *.* silent! mkview + autocmd FileType * setlocal indentexpr= + autocmd TextYankPost * silent! lua vim.highlight.on_yank {higroup='Visual', timeout=100} + filetype plugin off + inoremap + inoremap + nnoremap ,a + nnoremap ,cD :call setqflist(filter(getqflist(), 'v:val != getqflist()[getqflist({"idx": 0}).idx - 1]')) nnoremap ,cc :cclose + nnoremap ,co :copen nnoremap ,cq :call setqflist([]):cclose - nnoremap :cnextzz - nnoremap :cpreviouszz - nnoremap ,cu :colder nnoremap ,cr :cnewer + nnoremap ,cu :colder nnoremap ,h H nnoremap ,l L - nnoremap H ^ - nnoremap L $ - xnoremap H ^ - xnoremap L $ + nnoremap ,m :wa:make + nnoremap ,rl :checktime + nnoremap ,t vl:terminala + nnoremap ,x nnoremap nnoremap - nnoremap ,a - nnoremap ,x - nnoremap ,rl :checktime - nnoremap ,m :wa:make - nnoremap :noh - inoremap - inoremap - - nnoremap ,cD :call setqflist(filter(getqflist(), 'v:val != getqflist()[getqflist({"idx": 0}).idx - 1]')) - - nnoremap ,t vl:terminala - - " Don't include curdir, it just causes pain. - set viewoptions=folds,cursor - autocmd BufWinLeave *.* silent! mkview - autocmd BufWinEnter *.* silent! loadview - + nnoremap zz nnoremap h nnoremap j nnoremap k nnoremap l - - nnoremap zz + nnoremap :cnextzz + nnoremap :cpreviouszz nnoremap zz - + nnoremap :noh + nnoremap H ^ + nnoremap L $ + set autowriteall + set clipboard=unnamedplus + set cursorline + set expandtab + set exrc + set grepformat=%f:%l:%c:%m + set grepprg=rg\ --vimgrep\ --hidden\ --smart-case\ -g\ \'!**/tags\'\ -g\ \'!**/.git\' + set guicursor=n-v-c:block-Cursor + set incsearch + set list + set noswapfile + set nowrap + set nu + set path=** + set secure + set shiftround + set shiftwidth=0 + set tabstop=4 + set tags+=~/tags + set viewoptions=folds,cursor tnoremap c c - - autocmd TextYankPost * silent! lua vim.highlight.on_yank {higroup='Visual', timeout=100} - autocmd BufEnter *__virtual* setlocal buftype=nofile bufhidden=hide noswapfile - - " Disable STUPID default rust plugin. And others - filetype plugin off - - " remove annoying and bad indentation - autocmd FileType * setlocal indentexpr= + xnoremap H ^ + xnoremap L $ ]=] +vim.opt.completeopt = { 'menu', 'popup', 'preview', 'fuzzy' } + vim.keymap.set('n', ',cf', function() local qf = vim.fn.getqflist() for i, item in ipairs(qf) do @@ -118,226 +107,6 @@ vim.api.nvim_create_autocmd({ end }) --- FILE SPECIFIC AND AUTOCMDS {{{1 -local file_specific = { - c = function() - vim.bo.expandtab = false - end, - make = function() - vim.bo.expandtab = false - end, - tsv = function() - vim.bo.tabstop = 32 - vim.bo.expandtab = false - end, - odin = function() - vim.bo.expandtab = false - end, - go = function() - vim.bo.expandtab = false - end, - yaml = function() - vim.bo.tabstop = 2 - end -} - -vim.api.nvim_create_autocmd('BufEnter', { - callback = function() - local conf = file_specific[vim.bo.filetype] - if conf then conf() end - end, -}) - --- CENTER TEXT "zen mode" {{{1 -do - -- one shared statusline looks better for the split. - vim.o.laststatus = 3 - - local ID = '4f2de2e3-a1bf-481f-919c-7f68ec6511c9' - local function is_padding_window(win) - local ok, _ = pcall(vim.api.nvim_buf_get_var, vim.api.nvim_win_get_buf(win), ID) - return ok - end - - local function calculate_padding() - local screen_width = vim.o.columns - local padding = math.floor((screen_width / 2 - 84 / 2) + 0.5) - if padding <= 0 then - return - end - return padding - end - - local function get_padding_window() - local windows = vim.api.nvim_list_wins() - for _, win in ipairs(windows) do - if is_padding_window(win) then - return win - end - end - return nil - end - - local padding_buffer = _G[ID] - if padding_buffer == nil then - padding_buffer = vim.api.nvim_create_buf(false, true) - vim.api.nvim_set_option_value('buftype', 'nofile', {buf = padding_buffer}) - vim.api.nvim_set_option_value('modifiable', false, {buf = padding_buffer}) - vim.api.nvim_create_autocmd('WinEnter', { - callback = function() - local curr_buff = vim.api.nvim_get_current_buf() - if curr_buff == padding_buffer then - if #vim.api.nvim_list_wins() == 1 then - vim.cmd"q" - end - local padding_window = vim.api.nvim_get_current_win() - - vim.cmd"wincmd p" - local prev_win = vim.api.nvim_get_current_win() - local padding_window_info = vim.fn.getwininfo(padding_window)[1] - local prev_win_info = vim.fn.getwininfo(prev_win)[1] - if padding_window ~= prev_win and padding_window_info.wincol ~= prev_win_info.wincol then - return - end - - local windows = vim.api.nvim_list_wins() - local leftmost_non_padding_window = nil - local min_col = math.huge - for _, win in ipairs(windows) do - local info = vim.fn.getwininfo(win)[1] - if info.wincol < min_col and padding_window_info.wincol < info.wincol then - min_col = info.wincol - leftmost_non_padding_window = win - end - end - if leftmost_non_padding_window ~= nil then - vim.api.nvim_set_current_win(leftmost_non_padding_window) - end - end - end, - }) - vim.api.nvim_create_autocmd('VimResized', { - callback = function() - local padding_window = get_padding_window() - if padding_window ~= nil then - local padding = calculate_padding() - if padding == nil then - vim.api.nvim_win_close(padding_window, true) - else - vim.api.nvim_win_set_width(padding_window, padding) - end - end - vim.cmd"wincmd =" - end, - }) - vim.api.nvim_buf_set_var(padding_buffer, ID, true) - _G[ID] = padding_buffer - end - - local function toggle_padding() - local padding_window = get_padding_window() - if padding_window == nil then - vim.cmd"only" - local padding = calculate_padding() - if padding == nil then - return - end - local win = vim.api.nvim_open_win(padding_buffer, false, { - split = 'left', - win = -1, - width = padding, - }) - vim.api.nvim_set_option_value('number', false, {win = win}) - vim.api.nvim_set_option_value('relativenumber', false, {win = win}) - vim.api.nvim_set_option_value('cursorline', false, {win = win}) - vim.api.nvim_set_option_value('winfixwidth', true, {win = win}) - vim.api.nvim_set_option_value("fillchars", "eob: ", { win = win }) - vim.cmd"wincmd =" - else - vim.api.nvim_win_close(padding_window, true) - end - end - - vim.keymap.set('n', ',z', toggle_padding) -end - --- auto select compiler {{{1 -do - local compiler_mapping = { - dotnet={'*.csproj', '*.sln'}, - basedpyright={'requirements.txt', 'pyproject.toml', '.venv'}, - go={'go.mod'}, - gcc={'*.c'}, - ['g++']={'*.cpp'}, - cargo={'Cargo.toml'}, - zig={'*.zig'} - } - - ---@param dir string? - ---@param glob_pattern string - ---@return boolean - local function file_or_folder_exists(dir, glob_pattern) - if dir == nil then return false end - return vim.fn.globpath(dir, glob_pattern, false, false, false) ~= '' - end - - local all_folders_till_root = function() - local cwd = vim.fn.getcwd() - local folders = {cwd} -- array of all folders from cwd to root - for dir in vim.fs.parents(cwd) do - table.insert(folders, dir) - end - - ---@param _ any - ---@param i integer - ---@return integer? - ---@return string? - local function iter(_, i) - if file_or_folder_exists(folders[i], '.git') then - return nil - end - i = i + 1 - local f = folders[i] - if f == nil then - return nil - end - return i, f - end - - return iter, nil, 0 - end - - ---@param glob_pattern string - ---@return boolean - local function look_for_file(glob_pattern) - for _, dir in all_folders_till_root() do - if file_or_folder_exists(dir, glob_pattern) then - return true - end - end - return false - end - - local function auto_select_compiler() - for compiler, glob_patterns in pairs(compiler_mapping) do - for _, glob_pattern in ipairs(glob_patterns) do - if look_for_file(glob_pattern) then - vim.cmd('compiler! '..compiler) - end - end - end - if look_for_file('justfile') then - vim.go.makeprg = 'just' - end - end - - auto_select_compiler() - vim.api.nvim_create_autocmd('DirChanged', { - callback = auto_select_compiler, - }) -end - - -- LAZY.NVIM BOOTSTRAP {{{1 local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim' if not (vim.uv or vim.loop).fs_stat(lazypath) then @@ -588,67 +357,8 @@ require'lazy'.setup{ --{{{1 } } require'mason-lspconfig'.setup() - vim.opt.completeopt = { 'menu', 'popup', 'preview', 'fuzzy' } - - - vim.lsp.config.zls = { - before_init = function(_, _) - vim.g.zig_fmt_autosave = false -- may not be needed anymore? - end, - } - vim.lsp.config.lua_ls = { - settings = { - Lua = { runtime = { version = 'LuaJIT' } } - } - } - vim.lsp.config.gopls = { - filetypes = { -- unsure if this is entirely correct... - 'go', - 'gomod', - 'gowork', - 'gotmpl', - 'html' - }, - settings = { - gopls = { - templateExtensions = {'html', 'gotmpl'} - } - } - } - vim.lsp.config.basedpyright = { - settings = { - basedpyright = { - analysis = { - useLibraryCodeForTypes = true - }, - }, - }, - } - vim.lsp.config.sourcekit = { - filetypes = {"swift"} - } - vim.lsp.config.ols = { - settings = { - verbose=true, - } - } - - do -- turtle config - local turtle_server = vim.fn.exepath("turtle-language-server") - local node = vim.fn.exepath("node") - if turtle_server ~= "" and node ~= "" then - vim.lsp.config['turtle-language-server'] = { - cmd={ node, turtle_server, '--stdio' }, - filetypes = { 'turtle', 'ttl' }, - } - vim.lsp.enable('turtle-language-server') - end - end vim.lsp.enable('gdscript') - vim.lsp.config('hls', { - filetypes = { 'haskell', 'lhaskell', 'cabal' }, - }) vim.lsp.enable('hls') vim.lsp.enable('sourcekit') @@ -885,171 +595,3 @@ require'lazy'.setup{ --{{{1 end, }, } - -do -- split line {{{1 - local SPLIT_DELIMETERS = { -- single characters only - [','] = true, - [';'] = true, - ['|'] = true, - } - local SPLIT_BETWEEN = { -- single characters only - ['('] = ')', - ['['] = ']', - ['{'] = '}', - ['<'] = '>', - } - local SPLIT_IGNORE_BETWEEN = { --single characters only - ['"'] = '"', - ["'"] = "'", - } - - local split_line = function() - local SPLIT_WHITESPACE = ' ' - if vim.o.expandtab then - SPLIT_WHITESPACE = '' - for _ = 1, vim.o.tabstop do - SPLIT_WHITESPACE = SPLIT_WHITESPACE .. ' ' - end - end - - local line = vim.api.nvim_get_current_line() - local _, col = unpack(vim.api.nvim_win_get_cursor(0)) - col = col + 1 -- Doing this to make it 1-indexed - - ---@type integer? - local first_bracket_i = nil - for i = col, #line do - local char = line:sub(i, i) - if SPLIT_BETWEEN[char] ~= nil then - first_bracket_i = i - break - end - end - - if not first_bracket_i then - print('No opening brackets found after cursor on this line.') - return - end - - ---@type integer[] - local split_indexes = {} -- Populate this array - ---@type integer? - local last_bracket_i = nil -- And find this index - - do - ---@type string[] - local closing_bracket_stack = {} - local icon_to_close_ignore = '' - local in_ignore = false - - for i = first_bracket_i, #line do - local char = line:sub(i,i) - - if in_ignore then - in_ignore = not (char == icon_to_close_ignore) - goto continue - end - - if SPLIT_IGNORE_BETWEEN[char] ~= nil then - icon_to_close_ignore = SPLIT_IGNORE_BETWEEN[char] - in_ignore = true - goto continue - end - -- string handling complete - - if SPLIT_BETWEEN[char] ~= nil then - table.insert( - closing_bracket_stack, - SPLIT_BETWEEN[char] - ) - end - - if char == closing_bracket_stack[#closing_bracket_stack] then - table.remove(closing_bracket_stack) - end - - if #closing_bracket_stack == 1 and SPLIT_DELIMETERS[char] then - table.insert(split_indexes, i) - end - - if #closing_bracket_stack == 0 then - last_bracket_i = i - break - end - ::continue:: - end - end - - if not last_bracket_i then - print('The first opening bracket found after the cursor was not closed on this line.') - return - end - - ---@type string - local leading_whitespace = string.match(line, '^%s*') - local first_line = line:sub(1, first_bracket_i) - local last_line = leading_whitespace .. line:sub(last_bracket_i, #line) - if #split_indexes == 0 then - if (last_bracket_i - first_bracket_i == 1) then return end - local row, _ = unpack(vim.api.nvim_win_get_cursor(0)) - line = line:sub(first_bracket_i+1, last_bracket_i-1) - local leading_pattern = '^[%s' - for k, _ in pairs(SPLIT_DELIMETERS) do - leading_pattern = leading_pattern .. k - end - leading_pattern = leading_pattern .. ']*' - line = line:gsub(leading_pattern, leading_whitespace .. SPLIT_WHITESPACE, 1) - line = line:gsub('[%s]*$', '', 1) - vim.api.nvim_buf_set_lines(0, row-1, row, false, {first_line}) - vim.api.nvim_buf_set_lines(0, row, row, false, {last_line}) - vim.api.nvim_buf_set_lines(0, row, row, false, {line}) - return - end - - local middle_lines = {} - table.insert( - middle_lines, - line:sub(first_bracket_i+1, split_indexes[1]) - ) - for i = 1, #split_indexes-1 do - table.insert( - middle_lines, - line:sub(split_indexes[i], split_indexes[i+1]) - ) - end - table.insert( - middle_lines, - line:sub(split_indexes[#split_indexes], last_bracket_i-1) - ) - - local leading_pattern = '^[%s' - for k, _ in pairs(SPLIT_DELIMETERS) do - leading_pattern = leading_pattern .. k - end - leading_pattern = leading_pattern .. ']*' - - -- Cleanup step - for i, middle_line in ipairs(middle_lines) do - middle_line = middle_line:gsub(leading_pattern, leading_whitespace .. SPLIT_WHITESPACE, 1) - middle_line = middle_line:gsub('[%s]*$', '', 1) - middle_lines[i] = middle_line - end - - if middle_lines[#middle_lines]:match('^%s*$') ~= nil then - table.remove(middle_lines) - end - - local row, _ = unpack(vim.api.nvim_win_get_cursor(0)) - vim.api.nvim_buf_set_lines(0, row-1, row, false, {first_line}) - vim.api.nvim_buf_set_lines(0, row, row, false, {last_line}) - vim.api.nvim_buf_set_lines(0, row, row, false, middle_lines) - end - - vim.keymap.set( - 'n', - ',s', - split_line, - { silent = true } - ) -end - diff --git a/nvim/.config/nvim/lsp/basedpyright.lua b/nvim/.config/nvim/lsp/basedpyright.lua new file mode 100644 index 0000000..a2ad066 --- /dev/null +++ b/nvim/.config/nvim/lsp/basedpyright.lua @@ -0,0 +1,9 @@ +return { + settings = { + basedpyright = { + analysis = { + useLibraryCodeForTypes = true + }, + }, + }, +} diff --git a/nvim/.config/nvim/lsp/gopls.lua b/nvim/.config/nvim/lsp/gopls.lua new file mode 100644 index 0000000..a49060f --- /dev/null +++ b/nvim/.config/nvim/lsp/gopls.lua @@ -0,0 +1,14 @@ +return { + filetypes = { -- unsure if this is entirely correct... + 'go', + 'gomod', + 'gowork', + 'gotmpl', + 'html' + }, + settings = { + gopls = { + templateExtensions = {'html', 'gotmpl'} + } + } +} diff --git a/nvim/.config/nvim/lsp/hls.lua b/nvim/.config/nvim/lsp/hls.lua new file mode 100644 index 0000000..e23e28f --- /dev/null +++ b/nvim/.config/nvim/lsp/hls.lua @@ -0,0 +1,3 @@ +return { + filetypes = { 'haskell', 'lhaskell', 'cabal' }, +} diff --git a/nvim/.config/nvim/lsp/lua_ls.lua b/nvim/.config/nvim/lsp/lua_ls.lua new file mode 100644 index 0000000..8f0b232 --- /dev/null +++ b/nvim/.config/nvim/lsp/lua_ls.lua @@ -0,0 +1,9 @@ +return { + settings = { + Lua = { + runtime = { + version = 'LuaJIT' + } + } + } +} diff --git a/nvim/.config/nvim/lsp/ols.lua b/nvim/.config/nvim/lsp/ols.lua new file mode 100644 index 0000000..3b339b9 --- /dev/null +++ b/nvim/.config/nvim/lsp/ols.lua @@ -0,0 +1,5 @@ +return { + settings = { + verbose=true, + } +} diff --git a/nvim/.config/nvim/lsp/sourcekit.lua b/nvim/.config/nvim/lsp/sourcekit.lua new file mode 100644 index 0000000..003e782 --- /dev/null +++ b/nvim/.config/nvim/lsp/sourcekit.lua @@ -0,0 +1,3 @@ +return { + filetypes = {"swift"} +} diff --git a/nvim/.config/nvim/lsp/zls.lua b/nvim/.config/nvim/lsp/zls.lua new file mode 100644 index 0000000..a88f6fb --- /dev/null +++ b/nvim/.config/nvim/lsp/zls.lua @@ -0,0 +1,5 @@ +return { + before_init = function(_, _) + vim.g.zig_fmt_autosave = false -- may not be needed anymore? + end, +} diff --git a/nvim/.config/nvim/plugin/auto_select_compiler.lua b/nvim/.config/nvim/plugin/auto_select_compiler.lua new file mode 100644 index 0000000..9545083 --- /dev/null +++ b/nvim/.config/nvim/plugin/auto_select_compiler.lua @@ -0,0 +1,72 @@ +local compiler_mapping = { + dotnet={'*.csproj', '*.sln'}, + basedpyright={'requirements.txt', 'pyproject.toml', '.venv'}, + go={'go.mod'}, + gcc={'*.c'}, + ['g++']={'*.cpp'}, + cargo={'Cargo.toml'}, + zig={'*.zig'} +} + +---@param dir string? +---@param glob_pattern string +---@return boolean +local function file_or_folder_exists(dir, glob_pattern) + if dir == nil then return false end + return vim.fn.globpath(dir, glob_pattern, false, false, false) ~= '' +end + +local all_folders_till_root = function() + local cwd = vim.fn.getcwd() + local folders = {cwd} -- array of all folders from cwd to root + for dir in vim.fs.parents(cwd) do + table.insert(folders, dir) + end + + ---@param _ any + ---@param i integer + ---@return integer? + ---@return string? + local function iter(_, i) + if file_or_folder_exists(folders[i], '.git') then + return nil + end + i = i + 1 + local f = folders[i] + if f == nil then + return nil + end + return i, f + end + + return iter, nil, 0 +end + +---@param glob_pattern string +---@return boolean +local function look_for_file(glob_pattern) + for _, dir in all_folders_till_root() do + if file_or_folder_exists(dir, glob_pattern) then + return true + end + end + return false +end + +local function auto_select_compiler() + for compiler, glob_patterns in pairs(compiler_mapping) do + for _, glob_pattern in ipairs(glob_patterns) do + if look_for_file(glob_pattern) then + vim.cmd('compiler! '..compiler) + end + end + end + if look_for_file('justfile') then + vim.go.makeprg = 'just' + end +end + +auto_select_compiler() +vim.api.nvim_create_autocmd('DirChanged', { + callback = auto_select_compiler, +}) diff --git a/nvim/.config/nvim/plugin/filetype_specific_settings.lua b/nvim/.config/nvim/plugin/filetype_specific_settings.lua new file mode 100644 index 0000000..840062e --- /dev/null +++ b/nvim/.config/nvim/plugin/filetype_specific_settings.lua @@ -0,0 +1,29 @@ +local file_specific = { + c = function() + vim.bo.expandtab = false + end, + make = function() + vim.bo.expandtab = false + end, + tsv = function() + vim.bo.tabstop = 32 + vim.bo.expandtab = false + end, + odin = function() + vim.bo.expandtab = false + end, + go = function() + vim.bo.expandtab = false + end, + yaml = function() + vim.bo.tabstop = 2 + end +} + +vim.api.nvim_create_autocmd('BufEnter', { + callback = function() + local conf = file_specific[vim.bo.filetype] + if conf then conf() end + end, +}) + diff --git a/nvim/.config/nvim/plugin/split_line.lua b/nvim/.config/nvim/plugin/split_line.lua new file mode 100644 index 0000000..fd1bde2 --- /dev/null +++ b/nvim/.config/nvim/plugin/split_line.lua @@ -0,0 +1,164 @@ +local SPLIT_DELIMETERS = { -- single characters only + [','] = true, + [';'] = true, + ['|'] = true, +} +local SPLIT_BETWEEN = { -- single characters only + ['('] = ')', + ['['] = ']', + ['{'] = '}', + ['<'] = '>', +} +local SPLIT_IGNORE_BETWEEN = { --single characters only + ['"'] = '"', + ["'"] = "'", +} + +local split_line = function() + local SPLIT_WHITESPACE = ' ' + if vim.o.expandtab then + SPLIT_WHITESPACE = '' + for _ = 1, vim.o.tabstop do + SPLIT_WHITESPACE = SPLIT_WHITESPACE .. ' ' + end + end + + local line = vim.api.nvim_get_current_line() + local _, col = unpack(vim.api.nvim_win_get_cursor(0)) + col = col + 1 -- Doing this to make it 1-indexed + + ---@type integer? + local first_bracket_i = nil + for i = col, #line do + local char = line:sub(i, i) + if SPLIT_BETWEEN[char] ~= nil then + first_bracket_i = i + break + end + end + + if not first_bracket_i then + print('No opening brackets found after cursor on this line.') + return + end + + ---@type integer[] + local split_indexes = {} -- Populate this array + ---@type integer? + local last_bracket_i = nil -- And find this index + + do + ---@type string[] + local closing_bracket_stack = {} + local icon_to_close_ignore = '' + local in_ignore = false + + for i = first_bracket_i, #line do + local char = line:sub(i,i) + + if in_ignore then + in_ignore = not (char == icon_to_close_ignore) + goto continue + end + + if SPLIT_IGNORE_BETWEEN[char] ~= nil then + icon_to_close_ignore = SPLIT_IGNORE_BETWEEN[char] + in_ignore = true + goto continue + end + -- string handling complete + + if SPLIT_BETWEEN[char] ~= nil then + table.insert( + closing_bracket_stack, + SPLIT_BETWEEN[char] + ) + end + + if char == closing_bracket_stack[#closing_bracket_stack] then + table.remove(closing_bracket_stack) + end + + if #closing_bracket_stack == 1 and SPLIT_DELIMETERS[char] then + table.insert(split_indexes, i) + end + + if #closing_bracket_stack == 0 then + last_bracket_i = i + break + end + ::continue:: + end + end + + if not last_bracket_i then + print('The first opening bracket found after the cursor was not closed on this line.') + return + end + + ---@type string + local leading_whitespace = string.match(line, '^%s*') + local first_line = line:sub(1, first_bracket_i) + local last_line = leading_whitespace .. line:sub(last_bracket_i, #line) + if #split_indexes == 0 then + if (last_bracket_i - first_bracket_i == 1) then return end + local row, _ = unpack(vim.api.nvim_win_get_cursor(0)) + line = line:sub(first_bracket_i+1, last_bracket_i-1) + local leading_pattern = '^[%s' + for k, _ in pairs(SPLIT_DELIMETERS) do + leading_pattern = leading_pattern .. k + end + leading_pattern = leading_pattern .. ']*' + line = line:gsub(leading_pattern, leading_whitespace .. SPLIT_WHITESPACE, 1) + line = line:gsub('[%s]*$', '', 1) + vim.api.nvim_buf_set_lines(0, row-1, row, false, {first_line}) + vim.api.nvim_buf_set_lines(0, row, row, false, {last_line}) + vim.api.nvim_buf_set_lines(0, row, row, false, {line}) + return + end + + local middle_lines = {} + table.insert( + middle_lines, + line:sub(first_bracket_i+1, split_indexes[1]) + ) + for i = 1, #split_indexes-1 do + table.insert( + middle_lines, + line:sub(split_indexes[i], split_indexes[i+1]) + ) + end + table.insert( + middle_lines, + line:sub(split_indexes[#split_indexes], last_bracket_i-1) + ) + + local leading_pattern = '^[%s' + for k, _ in pairs(SPLIT_DELIMETERS) do + leading_pattern = leading_pattern .. k + end + leading_pattern = leading_pattern .. ']*' + + -- Cleanup step + for i, middle_line in ipairs(middle_lines) do + middle_line = middle_line:gsub(leading_pattern, leading_whitespace .. SPLIT_WHITESPACE, 1) + middle_line = middle_line:gsub('[%s]*$', '', 1) + middle_lines[i] = middle_line + end + + if middle_lines[#middle_lines]:match('^%s*$') ~= nil then + table.remove(middle_lines) + end + + local row, _ = unpack(vim.api.nvim_win_get_cursor(0)) + vim.api.nvim_buf_set_lines(0, row-1, row, false, {first_line}) + vim.api.nvim_buf_set_lines(0, row, row, false, {last_line}) + vim.api.nvim_buf_set_lines(0, row, row, false, middle_lines) +end + +vim.keymap.set( + 'n', + ',s', + split_line, + { silent = true } +) diff --git a/nvim/.config/nvim/plugin/zen_mode.lua b/nvim/.config/nvim/plugin/zen_mode.lua new file mode 100644 index 0000000..940f36f --- /dev/null +++ b/nvim/.config/nvim/plugin/zen_mode.lua @@ -0,0 +1,109 @@ +-- one shared statusline looks better for the split. +vim.o.laststatus = 3 + +local ID = '4f2de2e3-a1bf-481f-919c-7f68ec6511c9' +local function is_padding_window(win) + local ok, _ = pcall(vim.api.nvim_buf_get_var, vim.api.nvim_win_get_buf(win), ID) + return ok +end + +local function calculate_padding() + local screen_width = vim.o.columns + local padding = math.floor((screen_width / 2 - 84 / 2) + 0.5) + if padding <= 0 then + return + end + return padding +end + +local function get_padding_window() + local windows = vim.api.nvim_list_wins() + for _, win in ipairs(windows) do + if is_padding_window(win) then + return win + end + end + return nil +end + +local padding_buffer = _G[ID] +if padding_buffer == nil then + padding_buffer = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_option_value('buftype', 'nofile', {buf = padding_buffer}) + vim.api.nvim_set_option_value('modifiable', false, {buf = padding_buffer}) + vim.api.nvim_create_autocmd('WinEnter', { + callback = function() + local curr_buff = vim.api.nvim_get_current_buf() + if curr_buff == padding_buffer then + if #vim.api.nvim_list_wins() == 1 then + vim.cmd"q" + end + local padding_window = vim.api.nvim_get_current_win() + + vim.cmd"wincmd p" + local prev_win = vim.api.nvim_get_current_win() + local padding_window_info = vim.fn.getwininfo(padding_window)[1] + local prev_win_info = vim.fn.getwininfo(prev_win)[1] + if padding_window ~= prev_win and padding_window_info.wincol ~= prev_win_info.wincol then + return + end + + local windows = vim.api.nvim_list_wins() + local leftmost_non_padding_window = nil + local min_col = math.huge + for _, win in ipairs(windows) do + local info = vim.fn.getwininfo(win)[1] + if info.wincol < min_col and padding_window_info.wincol < info.wincol then + min_col = info.wincol + leftmost_non_padding_window = win + end + end + if leftmost_non_padding_window ~= nil then + vim.api.nvim_set_current_win(leftmost_non_padding_window) + end + end + end, + }) + vim.api.nvim_create_autocmd('VimResized', { + callback = function() + local padding_window = get_padding_window() + if padding_window ~= nil then + local padding = calculate_padding() + if padding == nil then + vim.api.nvim_win_close(padding_window, true) + else + vim.api.nvim_win_set_width(padding_window, padding) + end + end + vim.cmd"wincmd =" + end, + }) + vim.api.nvim_buf_set_var(padding_buffer, ID, true) + _G[ID] = padding_buffer +end + +local function toggle_padding() + local padding_window = get_padding_window() + if padding_window == nil then + vim.cmd"only" + local padding = calculate_padding() + if padding == nil then + return + end + local win = vim.api.nvim_open_win(padding_buffer, false, { + split = 'left', + win = -1, + width = padding, + }) + vim.api.nvim_set_option_value('number', false, {win = win}) + vim.api.nvim_set_option_value('relativenumber', false, {win = win}) + vim.api.nvim_set_option_value('cursorline', false, {win = win}) + vim.api.nvim_set_option_value('winfixwidth', true, {win = win}) + vim.api.nvim_set_option_value("fillchars", "eob: ", { win = win }) + vim.cmd"wincmd =" + else + vim.api.nvim_win_close(padding_window, true) + end +end + +vim.keymap.set('n', ',z', toggle_padding)