diff --git a/common/home/neovim/.editorconfig b/common/home/neovim/.editorconfig new file mode 100644 index 0000000..cb0dfb1 --- /dev/null +++ b/common/home/neovim/.editorconfig @@ -0,0 +1,107 @@ +# see https://github.com/CppCXY/EmmyLuaCodeStyle +[*.lua] +# [basic] +indent_style = space +indent_size = 4 +quote_style = single + +max_line_length = 120 +end_of_line = lf + +table_separator_style = comma +trailing_table_separator = smart + +call_arg_parentheses = keep + +# [space] +space_around_table_field_list = true +space_before_attribute = true +space_before_function_open_parenthesis = false +space_before_function_call_open_parenthesis = false +space_before_closure_open_parenthesis = false +space_before_function_call_single_arg = false +space_before_open_square_bracket = false +space_inside_function_call_parentheses = false +space_inside_function_param_list_parentheses = false +space_inside_square_brackets = false + +# like t[#t+1] = 1 +space_around_table_append_operator = false +ignore_spaces_inside_function_call = false + +# detail number or 'keep' +space_before_inline_comment = 1 + +# convert '---' to '--- ' or '--' to '-- ' +space_after_comment_dash = false + +# [operator space] +space_around_math_operator = true +space_around_math_operator.exponent = false +space_around_concat_operator = true +space_around_logical_operator = true +space_around_assign_operator = true + +space_after_comma = true +space_after_comma_in_for_statement = true + +# [align] +align_call_args = false +align_function_params = true +align_continuous_assign_statement = true +align_continuous_rect_table_field = true +align_continuous_line_space = 2 +align_if_branch = false + +# option none / always / contain_curly/ +align_array_table = true + +align_continuous_similar_call_args = false + +align_continuous_inline_comment = true +# option none / always / only_call_stmt +align_chain_expr = none + +# [indent] +never_indent_before_if_condition = false +never_indent_comment_on_if_branch = false +keep_indents_on_empty_lines = false +allow_non_indented_comments = false + +# [line space] + +# The following configuration supports four expressions +# keep +# fixed(n) +# min(n) +# max(n) +# for eg. min(2) + +line_space_after_if_statement = keep + +line_space_after_do_statement = keep + +line_space_after_while_statement = keep + +line_space_after_repeat_statement = keep + +line_space_after_for_statement = keep + +line_space_after_local_or_assign_statement = keep + +line_space_after_function_statement = fixed(2) + +line_space_after_expression_statement = keep + +line_space_after_comment = keep + +line_space_around_block = fixed(1) + +# [line break] +break_all_list_when_line_exceed = false +auto_collapse_lines = false +break_before_braces = false + +# [preference] +ignore_space_after_colon = false +end_statement_with_semicolon = always diff --git a/common/home/neovim/langs/lua.nix b/common/home/neovim/langs/lua.nix index b208fe9..364d049 100644 --- a/common/home/neovim/langs/lua.nix +++ b/common/home/neovim/langs/lua.nix @@ -25,6 +25,11 @@ in lua */ '' + vim.api.nvim_create_autocmd('FileType', { + pattern = 'lua', + command = 'setlocal ts=4 sw=4 sts=0 expandtab', + }); + -- IMPORTANT: make sure to setup neodev BEFORE lspconfig require("neodev").setup({ override = function(root_dir, library) diff --git a/common/home/neovim/neotree.lua b/common/home/neovim/neotree.lua deleted file mode 100644 index 38fc971..0000000 --- a/common/home/neovim/neotree.lua +++ /dev/null @@ -1,63 +0,0 @@ --- Override netrw -vim.g.loaded_netrw = 0; -vim.g.loaded_netrwPlugin = 0; - -require('neo-tree').setup({ - close_if_last_window = true, - enable_refresh_on_write = true, - - window = { - width = 22, - }, - - filesystem = { - use_libuv_file_watcher = true, - group_empty_dirs = true, - - filtered_items = { - visible = false, - hide_dotfiles = false, - hide_gitignored = true, - hide_by_name = {}, - hide_by_pattern = {}, - always_show = {}, - never_show = {}, - never_show_by_pattern = {}, - }, - }, - - source_selector = { - winbar = true, - statusline = false, - }, - - follow_current_file = { - enabled = true, - leave_dirs_open = true, - }, -}); - -local function is_neotree_open() - local manager = require("neo-tree.sources.manager"); - local renderer = require("neo-tree.ui.renderer"); - local state = manager.get_state("filesystem"); - return renderer.window_exists(state); -end - --- Auto open Neo-Tree on big enough window -vim.api.nvim_create_autocmd({ 'VimEnter', 'VimResized' }, { - pattern = '*', - callback = function() - if vim.api.nvim_eval([[&columns]]) > 100 then - if is_neotree_open() == false then - vim.cmd [[Neotree show]]; - vim.cmd [[Neotree close]]; - vim.cmd [[Neotree show]]; - end - else - if is_neotree_open() then - vim.cmd [[Neotree close]]; - end - end - end, -}); diff --git a/common/home/neovim/plugins/heirline.lua b/common/home/neovim/plugins/heirline.lua new file mode 100644 index 0000000..83ed1ed --- /dev/null +++ b/common/home/neovim/plugins/heirline.lua @@ -0,0 +1,443 @@ +-- Modified from https://github.com/lauranaujokat/nvim/blob/4102c789d05667f636107e3dae4ac589053ee88d/lua/setups/heirline.lua#L4 + +local conditions = require('heirline.conditions'); +local utils = require('heirline.utils'); + +---@class Palette +---@field [string] any +local dracula = require('dracula').colors(); + +local colors = { + bright_bg = dracula.selection, + dark_bg = dracula.menu, + bright_fg = dracula.fg, + red = dracula.red, + dark_red = utils.get_highlight('DiffDelete').bg, + green = dracula.green, + blue = dracula.blue, + gray = utils.get_highlight('NonText').fg, + orange = utils.get_highlight('Constant').fg, + purple = utils.get_highlight('Statement').fg, + cyan = dracula.cyan, + diag_warn = utils.get_highlight('DiagnosticWarn').fg, + diag_error = utils.get_highlight('DiagnosticError').fg, + diag_hint = utils.get_highlight('DiagnosticHint').fg, + diag_info = utils.get_highlight('DiagnosticInfo').fg, + git_del = utils.get_highlight('GitSignsDelete').fg, + git_add = utils.get_highlight('GitSignsAdd').fg, + git_change = utils.get_highlight('GitSignsChange').fg, +}; + +require('heirline').load_colors(colors); + +local ViMode = { + -- get vim current mode, this information will be required by the provider + -- and the highlight functions, so we compute it only once per component + -- evaluation and store it as a component attribute + init = function(self) + self.mode = vim.fn.mode(1); + + -- execute this only once, this is required if you want the ViMode + -- component to be updated on operator pending mode + if not self.once then + vim.api.nvim_create_autocmd('ModeChanged', { + pattern = '*:*o', + command = 'redrawstatus', + }); + self.once = true; + end; + end, + + static = { + mode_names = { + n = 'N', + no = 'N?', + nov = 'N?', + noV = 'N?', + ['no\22'] = 'N?', + niI = 'Ni', + niR = 'Nr', + niV = 'Nv', + nt = 'Nt', + v = 'V', + vs = 'Vs', + V = 'V_', + Vs = 'Vs', + ['\22'] = '^V', + ['\22s'] = '^V', + s = 'S', + S = 'S_', + ['\19'] = '^S', + i = 'I', + ic = 'Ic', + ix = 'Ix', + R = 'R', + Rc = 'Rc', + Rx = 'Rx', + Rv = 'Rv', + Rvc = 'Rv', + Rvx = 'Rv', + c = 'C', + cv = 'Ex', + r = '...', + rm = 'M', + ['r?'] = '?', + ['!'] = '!', + t = 'T', + }, + + mode_colors = { + n = 'red', + i = 'green', + v = 'cyan', + V = 'cyan', + ['\22'] = 'cyan', + c = 'orange', + s = 'purple', + S = 'purple', + ['\19'] = 'purple', + R = 'orange', + r = 'orange', + ['!'] = 'red', + t = 'red', + }, + }, + + -- To be extra meticulous, we can also add some vim statusline syntax to + -- control the padding and make sure our string is always at least 2 + -- characters long. Plus a nice Icon. + provider = function(self) + return ' ' .. self.mode_names[self.mode] .. '%)'; + end, + + -- Same goes for the highlight. Now the foreground will change according to the current mode. + hl = function(self) + local mode = self.mode:sub(1, 1); -- get only the first mode character + return { fg = self.mode_colors[mode], bold = true }; + end, + + -- Re-evaluate the component only on ModeChanged event + update = { + 'ModeChanged', + }, +}; + +local FileNameBlock = { + init = function(self) + self.filename = vim.api.nvim_buf_get_name(0); + end, +}; + +-- FileNameBlock children +local FileIcon = { + init = function(self) + local filename = self.filename; + local extension = vim.fn.fnamemodify(filename, ':e'); + self.icon, self.icon_color = + require('nvim-web-devicons').get_icon_color(filename, extension, { default = true }); + end, + + provider = function(self) + return self.icon and (self.icon .. ' '); + end, + + hl = function(self) + return { fg = self.icon_color }; + end, +}; + +local FileName = { + provider = function(self) + -- first, trim the pattern relative to the current directory. For other + -- options, see :h filename-modifers + local filename = vim.fn.fnamemodify(self.filename, ':.'); + if filename == '' then + return '[No Name]'; + end; + -- now, if the filename would occupy more than 1/4th of the available + -- space, we trim the file path to its initials + -- See Flexible Components section below for dynamic truncation + if not conditions.width_percent_below(#filename, 0.25) then + filename = vim.fn.pathshorten(filename); + end; + return filename; + end, + + hl = { fg = utils.get_highlight('Directory').fg }, +}; + +local FileFlags = { + { + condition = function() + return vim.bo.modified; + end, + provider = '[+]', + hl = { fg = 'green' }, + }, + { + condition = function() + return not vim.bo.modifiable or vim.bo.readonly; + end, + provider = '', + hl = { fg = 'orange' }, + }, +}; + +local FileNameModifer = { + hl = function() + if vim.bo.modified then + -- use `force` because we need to override the child's hl foreground + return { fg = 'cyan', bold = true, force = true }; + end; + end, +}; + +-- let's add the children to our FileNameBlock component +FileNameBlock = utils.insert( + FileNameBlock, + FileIcon, + utils.insert(FileNameModifer, FileName), -- a new table where FileName is a child of FileNameModifier + unpack(FileFlags), -- A small optimisation, since their parent does nothing + { provider = '%<' } -- this means that the statusline is cut here when there's not enough space +); + +local Ruler = { + provider = ' line: %l col: %c', + hl = { fg = 'green', bold = false }, +}; + +local ScrollRuler = { + -- %l = current line number + -- %L = number of lines in the buffer + -- %c = column number + -- %P = percentage through file of displayed window + provider = '%P', +}; + +local ScrollBar = { + static = { + sbar = { '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█' }, + -- sbar = { '🭶', '🭷', '🭸', '🭹', '🭺', '🭻' } + }, + + provider = function(self) + local curr_line = vim.api.nvim_win_get_cursor(0)[1]; + local lines = vim.api.nvim_buf_line_count(0); + local i = math.floor((curr_line - 1) / lines * #self.sbar) + 1; + return string.rep(self.sbar[i], 2); + end, + + hl = { fg = 'cyan', bg = 'bright_bg' }, +}; + +local LSPActive = { + condition = conditions.lsp_attached, + update = { 'LspAttach', 'LspDetach' }, + + provider = function() + local names = {}; + for _, server in pairs(vim.lsp.get_clients()) do + table.insert(names, server.name); + end; + return ' [' .. table.concat(names, ' ') .. '] '; + end, + + hl = { fg = 'green', bold = false }, +}; + +local spinner_frames = { '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏' }; + +-- From https://github.com/mhartington/dotfiles/blob/5961460e3a492f7815259a692fca5ca2a1df924a/config/nvim/lua/mh/statusline/lsp_status.lua#L4 +local function get_lsp_progress() + local messages = require('lsp-status/messaging').messages; + local buf_messages = messages(); + local msgs = {}; + + for _, msg in ipairs(buf_messages) do + local contents; + + if msg.progress then + contents = msg.title; + + if msg.spinner then + contents = spinner_frames[(msg.spinner % #spinner_frames) + 1] .. ' ' .. contents; + end; + elseif msg.status then + contents = msg.content; + + if msg.uri then + local space = math.min(60, math.floor(0.6 * vim.fn.winwidth(0))); + local filename = vim.uri_to_fname(msg.uri); + + filename = vim.fn.fnamemodify(filename, ':~:.'); + + if #filename > space then + filename = vim.fn.pathshorten(filename); + end; + + contents = '(' .. filename .. ') ' .. contents; + end; + else + contents = msg.content; + end; + + table.insert(msgs, contents); + end; + + return table.concat(msgs, ' '); +end; + +local LSPMessages = { + provider = function() + local progress = get_lsp_progress(); + + if progress == '' then + return ''; + else + return ' ' .. progress; + end; + end, + hl = { fg = 'purple' }, +}; + +local Diagnostics = { + condition = conditions.has_diagnostics, + + static = { + error_icon = '  ', + warn_icon = '  ', + info_icon = '  ', + hint_icon = '  ', + }, + + init = function(self) + self.errors = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.ERROR }); + self.warnings = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.WARN }); + self.hints = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.HINT }); + self.info = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.INFO }); + end, + + update = { 'DiagnosticChanged', 'BufEnter' }, + + { + provider = function(self) + -- 0 is just another output, we can decide to print it or not! + return self.errors > 0 and (self.error_icon .. self.errors); + end, + hl = { fg = 'diag_error' }, + }, + { + provider = function(self) + return self.warnings > 0 and (self.warn_icon .. self.warnings); + end, + hl = { fg = 'diag_warn' }, + }, + { + provider = function(self) + return self.info > 0 and (self.info_icon .. self.info); + end, + hl = { fg = 'diag_info' }, + }, + { + provider = function(self) + return self.hints > 0 and (self.hint_icon .. self.hints); + end, + hl = { fg = 'diag_hint' }, + }, +}; + +local Git = { + condition = conditions.is_git_repo, + + init = function(self) + self.status_dict = vim.b.gitsigns_status_dict; + self.has_changes = self.status_dict.added ~= 0 or + self.status_dict.removed ~= 0 or + self.status_dict.changed ~= 0; + end, + + hl = { fg = 'orange' }, + + { -- git branch name + provider = function(self) + return ' ' .. self.status_dict.head; + end, + hl = { bold = true }, + }, + -- You could handle delimiters, icons and counts similar to Diagnostics + { + condition = function(self) + return self.has_changes; + end, + provider = '(', + }, + { + provider = function(self) + local count = self.status_dict.added or 0; + return count > 0 and ('+' .. count); + end, + hl = { fg = 'git_add' }, + }, + { + provider = function(self) + local count = self.status_dict.removed or 0; + return count > 0 and ('-' .. count); + end, + hl = { fg = 'git_del' }, + }, + { + provider = function(self) + local count = self.status_dict.changed or 0; + return count > 0 and ('~' .. count); + end, + hl = { fg = 'git_change' }, + }, + { + condition = function(self) + return self.has_changes; + end, + provider = ')', + }, +}; + +local Align = { provider = '%=' }; +local Space = { provider = ' ' }; + +Left = utils.surround({ '', '' }, 'bright_bg', { ViMode, Diagnostics, LSPMessages }); +Middle = utils.surround({ '', '' }, 'bright_bg', { LSPActive, FileNameBlock, Ruler }); +Right = utils.surround({ '', '' }, 'bright_bg', { Git, Space, ScrollRuler, Space, ScrollBar }); + +local DefaultStatusline = { + hl = { bg = 'dark_bg' }, + condition = function() + return true; + end, + Left, + Align, + Middle, + Align, + Right, +}; + +local StatusLines = { + hl = function() + if conditions.is_active() then + return 'StatusLine'; + else + return 'StatusLineNC'; + end; + end, + + -- the first statusline with no condition, or which condition returns true is used. + -- think of it as a switch case with breaks to stop fallthrough. + fallthrough = false, + + DefaultStatusline, +}; + +-- Make it global +vim.opt.laststatus = 3; + +require('heirline').setup({ + statusline = StatusLines, +}); diff --git a/common/home/neovim/plugins/neotree.lua b/common/home/neovim/plugins/neotree.lua new file mode 100644 index 0000000..33e80ec --- /dev/null +++ b/common/home/neovim/plugins/neotree.lua @@ -0,0 +1,63 @@ +-- Override netrw +vim.g.loaded_netrw = 0; +vim.g.loaded_netrwPlugin = 0; + +require('neo-tree').setup({ + close_if_last_window = true, + enable_refresh_on_write = true, + + window = { + width = 22, + }, + + filesystem = { + use_libuv_file_watcher = true, + group_empty_dirs = true, + + filtered_items = { + visible = false, + hide_dotfiles = false, + hide_gitignored = true, + hide_by_name = {}, + hide_by_pattern = {}, + always_show = {}, + never_show = {}, + never_show_by_pattern = {}, + }, + }, + + source_selector = { + winbar = true, + statusline = false, + }, + + follow_current_file = { + enabled = true, + leave_dirs_open = true, + }, +}); + +local function is_neotree_open() + local manager = require('neo-tree.sources.manager'); + local renderer = require('neo-tree.ui.renderer'); + local state = manager.get_state('filesystem'); + return renderer.window_exists(state); +end; + +-- Auto open Neo-Tree on big enough window +vim.api.nvim_create_autocmd({ 'VimEnter', 'VimResized' }, { + pattern = '*', + callback = function() + if vim.api.nvim_eval([[&columns]]) > 100 then + if is_neotree_open() == false then + vim.cmd[[Neotree show]]; + vim.cmd[[Neotree close]]; + vim.cmd[[Neotree show]]; + end; + else + if is_neotree_open() then + vim.cmd[[Neotree close]]; + end; + end; + end, +}); diff --git a/common/home/neovim/theme.nix b/common/home/neovim/theme.nix index 8eea73d..d45935e 100644 --- a/common/home/neovim/theme.nix +++ b/common/home/neovim/theme.nix @@ -64,13 +64,13 @@ in { local hooks = require('ibl.hooks'); hooks.register(hooks.type.HIGHLIGHT_SETUP, function() - vim.api.nvim_set_hl(0, "RainbowRed", { fg = "#E06C75" }) - vim.api.nvim_set_hl(0, "RainbowYellow", { fg = "#E5C07B" }) - vim.api.nvim_set_hl(0, "RainbowBlue", { fg = "#61AFEF" }) - vim.api.nvim_set_hl(0, "RainbowOrange", { fg = "#D19A66" }) - vim.api.nvim_set_hl(0, "RainbowGreen", { fg = "#98C379" }) - vim.api.nvim_set_hl(0, "RainbowViolet", { fg = "#C678DD" }) - vim.api.nvim_set_hl(0, "RainbowCyan", { fg = "#56B6C2" }) + vim.api.nvim_set_hl(0, "RainbowRed", { fg = "#E06C75" }); + vim.api.nvim_set_hl(0, "RainbowYellow", { fg = "#E5C07B" }); + vim.api.nvim_set_hl(0, "RainbowBlue", { fg = "#61AFEF" }); + vim.api.nvim_set_hl(0, "RainbowOrange", { fg = "#D19A66" }); + vim.api.nvim_set_hl(0, "RainbowGreen", { fg = "#98C379" }); + vim.api.nvim_set_hl(0, "RainbowViolet", { fg = "#C678DD" }); + vim.api.nvim_set_hl(0, "RainbowCyan", { fg = "#56B6C2" }); end); require('ibl').setup({ @@ -81,31 +81,21 @@ in { }); ''; } + + # Deps of heirline config + vimPlugins.nvim-navic + vimPlugins.nvim-web-devicons { - plugin = vimPlugins.lualine-nvim; + plugin = vimPlugins.heirline-nvim; type = "lua"; - config = - /* - lua - */ - '' - require('lualine').setup({ - options = { - theme = 'dracula', - globalstatus = true, - }, - sections = { - lualine_x = { "require('lsp-status').status()", 'bo:filetype' }, - }, - }); - ''; + config = fileContents ./plugins/heirline.lua; } ] ++ optionals neovimIde [ { plugin = vimPlugins.neo-tree-nvim; type = "lua"; - config = fileContents ./neotree.lua; + config = fileContents ./plugins/neotree.lua; } { plugin = vimPlugins.codewindow-nvim;