;;; init.fnl - primary init file ;; Helpful keymaping functions (macro bind! [mode key cmd ?a1 ?a2] (let [desc (or ?a2 ?a1) buf (if (and ?a1 ?a2) ?a1 ?a2) opts { :noremap true :silent true :buffer buf }] (when desc (tset opts :desc desc)) `(vim.keymap.set ,mode ,key ,cmd ,opts))) ;; Make space leader (set vim.g.mapleader " ") (bind! :n : :) ;; Enable lua filetype (set vim.g.do_filetype_lua true) ;; Some options ; Make the mouse work (set vim.opt.mouse :a) (set vim.opt.mousemodel :extend) ; Ignore case when a query is all lower case (set vim.opt.ignorecase true) (set vim.opt.smartcase true) ; Enable line numbering (set vim.opt.number true) ; Make insert 4 spaces (set vim.opt.expandtab true) (set vim.opt.tabstop 4) (set vim.opt.shiftwidth 4) (set vim.opt.shiftround true) ; Auto-indent (set vim.opt.autoindent true) (set vim.opt.smartindent true) ; Give context while scrolling (set vim.opt.scrolloff 4) (set vim.opt.sidescrolloff 8) ; Make splitting better (set vim.opt.splitbelow true) (set vim.opt.splitright true) ; 24 bit color support (set vim.opt.termguicolors true) ; Shell like completions (set vim.opt.wildmode [ :list :longest ]) ; Set completion options (set vim.opt.completeopt [ :menu :menuone :noselect ]) ; Make buffers hide when abandoned (set vim.opt.hidden true) ; Save undo data (set vim.opt.undofile true) ; Text width (set vim.opt.textwidth 80) ; Spell options (set vim.opt.spelllang :en_us) (set vim.opt.spelloptions :camel) ; Allow more freedom with the cursor (set vim.opt.virtualedit :block) ;; Disable netrw (set vim.g.loaded_netrw 1) (set vim.g.loaded_netrwPlugin 1) ;; Remove trailing whitespace (fn remove_trailing_whitespace [] "Remove trailing whitespace from the whole file." (let [res (pcall vim.cmd "%s/ \\+$//gc")] (vim.cmd.nohlsearch) (when (not res) (print "File is clean")))) (vim.api.nvim_create_user_command :RemoveTrailingWhitespace remove_trailing_whitespace {}) (bind! :n :ws remove_trailing_whitespace) ;; Spell keybindings (bind! :n :l (fn [] (let [new_spell (not (vim.opt_local.spell:get))] (set vim.opt_local.spell new_spell) (print (if new_spell "Enabled Spellcheck" "Disabled Spellcheck"))))) (fn jump_or_open_terminal [] "If no terminal buffer exists, create one. Otherwise, open new one." (var term_count 0) (var last_id 0) (var terms [ ]) (each [_ id (pairs (vim.api.nvim_list_bufs))] (let [name (vim.api.nvim_buf_get_name id)] (when (vim.startswith name "term://") (table.insert terms name) (set term_count (+ term_count 1)) (set last_id id)))) (if (= term_count 0) (vim.cmd.terminal) (= term_count 1) (vim.cmd.buffer last_id) (vim.ui.select terms { :prompt "Terminal Buffers" } (fn [choice] (when choice (vim.cmd.buffer choice)))))) (bind! :n :t jump_or_open_terminal) ;; Some keybindings for diagnostics (bind! :n :e vim.diagnostic.open_float) (bind! :n "[d" vim.diagnostic.goto_prev) (bind! :n "]d" vim.diagnostic.goto_next) (bind! :n :q vim.diagnostic.setloclist) ;; Plugins (with packer.nvim) (fn packer_init_callback [use] ;; Nicer macro for use (macro use! [repo ...] (local output [ repo ]) (var last_key nil) (each [_ val (ipairs [...])] (if last_key (do (tset output last_key val) (set last_key nil)) (set last_key val))) `(use ,output)) ;; Can be passed to :config of `use!' ;; to call a plugin's `setup' function (macro setup! [pkg ...] (local output [ ]) (var last_key nil) (each [_ val (ipairs [...])] (if last_key (do (tset output last_key val) (set last_key nil)) (set last_key val))) (let [req_var (gensym)] `((. (require ,pkg) :setup) ,output))) ;; Packer (use! "wbthomason/packer.nvim") ;; Treesitter (use! "nvim-treesitter/nvim-treesitter" :config #(setup! "nvim-treesitter.configs" :ensure_installed :all :sync_install false :auto_install true :highlight { :enable true :additional_vim_regex_highlighting false } :indent { :enable true })) ;; nightfox.nvim (colorscheme) (use! "EdenEast/nightfox.nvim" :after "nvim-treesitter" :config #(vim.cmd.colorscheme :carbonfox)) ;; Devicons (use! "kyazdani42/nvim-web-devicons") ;; lualine.nvim (use! "nvim-lualine/lualine.nvim" :after [ "nightfox.nvim" "nvim-web-devicons" ] :config #(setup! :lualine :options { :section_separators "" :component_separators "│" } :sections { :lualine_x [ { 1 (fn [] (.. "recording @" (vim.fn.reg_recording))) :cond (fn [] (not= (# (vim.fn.reg_recording)) 0)) } :encoding :fileformat :filetype ]})) ;; bufferline.nvim (use! "akinsho/bufferline.nvim" :after [ "nvim-web-devicons" "nightfox.nvim" ] :config #(setup! :bufferline :options { :always_show_bufferline false :mode :tabs :numbers :buffer-id :show_buffer_close_icons false :show_close_icon false })) ;; noice.nvim (ui overhaul) (use! "folke/noice.nvim" :config (fn [] (setup! :noice :lsp { :override { "vim.lsp.util.convert_input_to_markdown_lines" true "vim.lsp.util.stylize_markdown" true "cmp.entry.get_documentation" true }} :presets { :bottom_search true :command_palette false :long_message_to_split true :inc_rename false :lsp_doc_border false } :cmdline { :view :cmdline }) )) ;; dressing.nvim (better prmpts) (use! "stevearc/dressing.nvim" :after "telescope.nvim" :config #(setup! :dressing :input { :insert_only true })) ;; Telescope (use! "nvim-telescope/telescope.nvim" :requires "nvim-lua/plenary.nvim" :after "noice.nvim" :config (fn [] (setup! :telescope :defaults { :mappings { :i { : :close : :move_selection_next : :move_selection_previous } :n { : :move_selection_next : :move_selection_previous }}} :pickers { :buffers { :sort_lastused true }} :extensions { :fzf { :fuzzy true :override_generic_sorter true :override_file_sorter true :case_mode :smart_case }}) (let [builtin (require :telescope.builtin)] (bind! :n :fq builtin.quickfix) (bind! :n :fr builtin.registers) (bind! :n :fj builtin.jumplist) (bind! :n :fa builtin.marks) (bind! :n :fh builtin.help_tags) (bind! :n :g builtin.live_grep) (bind! :n :fg builtin.live_grep) (bind! :n :G builtin.grep_string) (bind! :n :fG builtin.grep_string) (bind! :n :b builtin.buffers) (bind! :n :gb builtin.buffers) (bind! :n :fu builtin.git_status) (bind! :n :fm builtin.man_pages) (bind! :n :fe builtin.diagnostics) (bind! :n :fp builtin.spell_suggest) (bind! :n :i builtin.find_files) (bind! :n :z= builtin.spell_suggest) (local repo_check_cmd "git rev-parse --is-inside-work-tree >/dev/null 2>&1") (bind! :n :ff (fn [] (let [code (os.execute repo_check_cmd)] (if (= code 0) (builtin.git_files) (builtin.find_files)))))) ((. (require :telescope) :load_extension) :noice))) ;; Telescope fzf (use! "nvim-telescope/telescope-fzf-native.nvim" :after "telescope.nvim" :run "make" :config #((. (require :telescope) :load_extension) :fzf)) ;; Nvim surround (use! "kylechui/nvim-surround" :config #(setup! :nvim-surround)) ;; Leap (use! "ggandor/leap.nvim" :after "nvim-treesitter" :config (fn [] ((. (require :leap) :add_default_mappings)) (bind! :o :z "(leap-forward-to)") (bind! :o :Z "(leap-backward-to)") (vim.api.nvim_set_hl 0 :LeapBackdrop { :link :Comment }))) ;; Leap spooky (remote operations) (use! "ggandor/leap-spooky.nvim" :after "leap.nvim" :config #(setup! :leap-spooky)) ;; Flit (leap for 'till' and 'forward' motions) (use! "ggandor/flit.nvim" :after "leap.nvim" :config #(setup! :flit)) ;; Snippy (use! "dcampos/nvim-snippy" :config (fn [] (let [map (require :snippy.mapping)] (bind! [ :i :s ] : ((. map :next) :)) (bind! [ :i :s ] : (map.previous :))))) ;; nvim-cmp (autocomplete) (use! "hrsh7th/nvim-cmp" :requires [ "hrsh7th/cmp-buffer" "hrsh7th/cmp-path" "hrsh7th/cmp-cmdline" ] :after [ "nvim-snippy" "telescope.nvim" ] :config (fn [] (let [cmp (require :cmp) compare (require :cmp.config.compare)] (cmp.setup { :snippet { :expand #((. (require :snippy) :expand_snippet) $1.body) } :mapping { : (cmp.mapping (cmp.mapping.scroll_docs -4) [ :i :c ]) : (cmp.mapping (cmp.mapping.scroll_docs 4) [ :i :c ]) : (cmp.mapping (cmp.mapping.complete) [ :i :c ]) : (cmp.mapping (cmp.mapping.abort) [ :i :c ]) : (cmp.mapping (cmp.mapping.confirm { :select false }) [ :i :c ]) : (cmp.mapping (cmp.mapping.select_next_item { :behavior cmp.SelectBehavior.Select }) [ :i :c ]) : (cmp.mapping (cmp.mapping.select_prev_item { :behavior cmp.SelectBehavior.Select }) [ :i :c ]) : (cmp.mapping (cmp.mapping.select_next_item { :behavior cmp.SelectBehavior.Select }) [ :i :c ]) : (cmp.mapping (cmp.mapping.select_prev_item { :behavior cmp.SelectBehavior.Select }) [ :i :c ]) : (cmp.mapping (cmp.mapping.select_next_item { :behavior cmp.SelectBehavior.Select }) [ :i :c ]) : (cmp.mapping (cmp.mapping.select_prev_item { :behavior cmp.SelectBehavior.Select }) [ :i :c ]) } :sources (cmp.config.sources {{ :name :nivm_lsp :priority 2 } { :name :snippy :priority 1 } { :name :buffer :priority 0 } { :name :path :priority 0 }}) :sorting { :priority_weight 2 :comparators [ compare.score compare.locality compare.recently_used compare.offset compare.order ; compare.scopes ; compare.exact ; compare.sort_text ; compare.kind ; compare.length ]}}) (cmp.setup.cmdline :/ { :mapping (cmp.mapping.preset.cmdline) :sources (cmp.config.sources [{ :name :buffer }])}) (cmp.setup.cmdline :: { :mapping (cmp.mapping.preset.cmdline) :sources (cmp.config.sources [{ :name :cmdline} { :name :path }])})))) ;; lspconfig (fn [] lsp_config_callback (fn get_data_dir [server root] (let [resolved_path (vim.fn.resolve root) joined_path (vim.fn.substitute resolved_path "\\/" "@" :g)] (.. (vim.fn.fnamemodify (.. "~/.local/nvim/lsp-cache/" server "/" :p)) joined_path))) (fn on_attach [_ buf] (bind! :n :gD vim.lsp.buf.declaration buf) (bind! :n :gd vim.lsp.buf.definition buf) (bind! :n :K vim.lsp.buf.hover buf) (bind! :n :gI vim.lsp.buf.implementation buf) (bind! :n : vim.lsp.buf.signature_help buf) (bind! :n :wa vim.lsp.buf.add_workspace_folder buf) (bind! :n :wr vim.lsp.buf.remove_workspace_folder buf) (bind! :n :wl #(print (vim.inspect (vim.lsp.buf.list_workspace_folders))) buf) (bind! :n :D vim.lsp.buf.type_definition buf) (bind! :n :rn vim.lsp.buf.rename buf) (bind! :n :cn vim.lsp.buf.code_action buf) ; (bind! :n :gr vim.lsp.buf.references buf) (bind! :n :o #(vim.lsp.buf.format { :async true }) buf) ;; Some telescope commands (let [builtin (require :telescope.builtin)] (bind! :n :gr builtin.lsp_references buf) (bind! :n :s builtin.lsp_dynamic_workspace_symbols buf) (bind! :n :fs builtin.lsp_dynamic_workspace_symbols buf) (bind! :n :fS builtin.lsp_workspace_symbols buf) (bind! :n :d builtin.lsp_document_symbols buf) (bind! :n :fd builtin.lsp_document_symbols buf))) (let [lsp (require :lspconfig) lsp_cap ((. (require :cmp_nvim_lsp) :default_capabilities)) default_config { :on_attach on_attach :capabilities lsp_cap }] nil)) (use! "neovim/nvim-lspconfig" :requires "hrsh7th/cmp-nvim-lsp" :after "nvim-cmp" :config lsp_config_callback)) (vim.cmd.packadd "packer.nvim") (let [packer (require :packer)] (packer.startup packer_init_callback))