├── .dev └── config │ └── nvim ├── .gitignore ├── README.adoc ├── UNLICENSE ├── fnl └── magic │ ├── init.fnl │ ├── macros.fnl │ ├── plugin.fnl │ ├── plugin │ ├── ale.fnl │ ├── auto-pairs.fnl │ ├── better-default.fnl │ ├── cmp.fnl │ ├── lspconfig.fnl │ ├── lualine.fnl │ ├── material.fnl │ ├── sexp.fnl │ ├── telescope.fnl │ ├── treesitter.fnl │ ├── undotree.fnl │ └── which-key.fnl │ └── util.fnl ├── init.lua └── script ├── dev.sh └── sync.sh /.dev/config/nvim: -------------------------------------------------------------------------------- 1 | ../../ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.dev/ 2 | /lua/ 3 | /plugin/packer_compiled.lua 4 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Magic Kit 2 | 3 | Neovim starter kit for working with https://github.com/Olical/conjure[Conjure] and https://github.com/Olical/aniseed[Aniseed], contains everything you need to get started. The goal is for you to take this and modify it to fit your needs, it is _not_ a distribution I'll constantly tweak, it's a starting point you should change as you see fit. 4 | 5 | == Requirements 6 | 7 | * git (for cloning the project and managing plugins) 8 | * Neovim 0.7+ 9 | 10 | == Installation 11 | 12 | [source,bash] 13 | ---- 14 | # Clone the project into your Neovim configuration directory. 15 | # Make sure you don't have anything here already! Back it up if so! 16 | git clone git@github.com:Olical/magic-kit.git ~/.config/nvim 17 | 18 | # Perform the initial sync which will fetch all of the plugins. 19 | # Run then whenever you change the plugin configuration. 20 | ~/.config/nvim/script/sync.sh 21 | ---- 22 | 23 | Once done, have a look at `~/.config/nvim/init.lua` to learn about the bootstrap process then `~/.config/nvim/fnl/magic/init.fnl` for the real beginning of your Fennel based configuration. Good luck! Have fun! 24 | 25 | == Mappings 26 | 27 | If you press a key and then wait, https://github.com/folke/which-key.nvim[which-key] will pop up with suggestions of what you can press next. Here's a few key mappings defined in the configuration to get you started. 28 | 29 | * `` is the https://learnvimscriptthehardway.stevelosh.com/chapters/06.html#leader[leader key] (``) 30 | * `,` is the https://learnvimscriptthehardway.stevelosh.com/chapters/06.html#local-leader[local leader key] (``) 31 | * `f...` finds things with https://github.com/nvim-telescope/telescope.nvim[telescope] 32 | ** Try `ff` to find files and `fb` to find buffers, there's a bunch of mappings so you'll have to experiment and rely on which-key 33 | * `ut` opens https://github.com/mbbill/undotree[undotree] 34 | 35 | == Unlicenced 36 | 37 | > You can change this in your own repository, I don't care! Do what you want with this repository, attribution is appreciated but not required. 38 | 39 | Find the full http://unlicense.org/[unlicense] in the `UNLICENSE` file, but here's a snippet. 40 | 41 | ____ 42 | This is free and unencumbered software released into the public domain. 43 | 44 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. 45 | ____ 46 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | 26 | -------------------------------------------------------------------------------- /fnl/magic/init.fnl: -------------------------------------------------------------------------------- 1 | (module magic.init 2 | {autoload {plugin magic.plugin 3 | nvim aniseed.nvim}}) 4 | 5 | ;;; Introduction 6 | 7 | ;; Aniseed compiles this (and all other Fennel files under fnl) into the lua 8 | ;; directory. The init.lua file is configured to load this file when ready. 9 | 10 | ;; We'll use modules, macros and functions to define our configuration and 11 | ;; required plugins. We can use Aniseed to evaluate code as we edit it or just 12 | ;; restart Neovim. 13 | 14 | ;; You can learn all about Conjure and how to evaluate things by executing 15 | ;; :ConjureSchool in your Neovim. This will launch an interactive tutorial. 16 | 17 | 18 | ;;; Generic configuration 19 | 20 | (set nvim.o.termguicolors true) 21 | (set nvim.o.mouse "a") 22 | (set nvim.o.updatetime 500) 23 | (set nvim.o.timeoutlen 500) 24 | (set nvim.o.sessionoptions "blank,curdir,folds,help,tabpages,winsize") 25 | (set nvim.o.inccommand :split) 26 | 27 | (nvim.ex.set :spell) 28 | (nvim.ex.set :list) 29 | 30 | 31 | ;;; Mappings 32 | 33 | (set nvim.g.mapleader " ") 34 | (set nvim.g.maplocalleader ",") 35 | 36 | 37 | ;;; Plugins 38 | 39 | ;; Run script/sync.sh to update, install and clean your plugins. 40 | ;; Packer configuration format: https://github.com/wbthomason/packer.nvim 41 | (plugin.use 42 | :Olical/aniseed {} 43 | :Olical/conjure {} 44 | :Olical/nvim-local-fennel {} 45 | :PaterJason/cmp-conjure {} 46 | :PeterRincker/vim-argumentative {} 47 | :airblade/vim-gitgutter {} 48 | :clojure-vim/clojure.vim {} 49 | :clojure-vim/vim-jack-in {} 50 | :folke/which-key.nvim {:mod :which-key} 51 | :ggandor/lightspeed.nvim {} 52 | :guns/vim-sexp {:mod :sexp} 53 | :hrsh7th/cmp-buffer {} 54 | :hrsh7th/cmp-cmdline {} 55 | :hrsh7th/cmp-nvim-lsp {} 56 | :hrsh7th/cmp-path {} 57 | :hrsh7th/nvim-cmp {:mod :cmp} 58 | :jiangmiao/auto-pairs {:mod :auto-pairs} 59 | :lewis6991/impatient.nvim {} 60 | :liuchengxu/vim-better-default {:mod :better-default} 61 | :marko-cerovac/material.nvim {:mod :material} 62 | :mbbill/undotree {:mod :undotree} 63 | :neovim/nvim-lspconfig {:mod :lspconfig} 64 | :nvim-lualine/lualine.nvim {:mod :lualine} 65 | :nvim-telescope/telescope.nvim {:mod :telescope :requires [[:nvim-lua/popup.nvim] [:nvim-lua/plenary.nvim]]} 66 | :nvim-treesitter/nvim-treesitter {:mod :treesitter} 67 | :radenling/vim-dispatch-neovim {} 68 | :tpope/vim-abolish {} 69 | :tpope/vim-commentary {} 70 | :tpope/vim-dispatch {} 71 | :tpope/vim-eunuch {} 72 | :tpope/vim-fugitive {} 73 | :tpope/vim-repeat {} 74 | :tpope/vim-sexp-mappings-for-regular-people {} 75 | :tpope/vim-sleuth {} 76 | :tpope/vim-surround {} 77 | :tpope/vim-unimpaired {} 78 | :tpope/vim-vinegar {} 79 | :w0rp/ale {:mod :ale} 80 | :wbthomason/packer.nvim {} 81 | ) 82 | -------------------------------------------------------------------------------- /fnl/magic/macros.fnl: -------------------------------------------------------------------------------- 1 | ;; Trick vim-sleuth into using the right indentation for this file. 2 | (do 3 | true) 4 | 5 | ;; These macro functions are executed at compile time to transform our code, 6 | ;; add more expressive syntax and create domain specific languages. 7 | 8 | ;; This file is never compiled to Lua itself, it's only required by the Fennel 9 | ;; compiler. 10 | 11 | ;; Example: 12 | ; (module my.fennel.module 13 | ; {require-macros [magic.macros]}) 14 | ; (some-macro 123) 15 | 16 | ;; I consider this to be an advanced concept within Lisp languages but one you 17 | ;; should try to learn some day. Start small, copy and modify what you find 18 | ;; here. You'll get it eventually! 19 | 20 | ;; Rule of macros: Use a function instead. 21 | 22 | ;; Macros should be used with care and extremely sparingly. If you can get away 23 | ;; with a function, you should! If you're not careful they'll make your code 24 | ;; unreadable and far too "clever", use them when plain functions aren't enough 25 | ;; or are too awkward to wield for your specific problem. 26 | 27 | {;; This is just a silly example macro. 28 | ; (infix-example-macro 2 + 3) => compiles to: (+ 2 3) => evaluates to: 5 29 | :infix-example-macro 30 | (fn [x op y] 31 | `(,op ,x ,y)) 32 | 33 | ;; Create an augroup for your autocmds. 34 | ; (augroup my-group 35 | ; (nvim.ex.autocmd ...)) 36 | :augroup 37 | (fn [name ...] 38 | `(do 39 | (vim.cmd (.. "augroup " ,(tostring name) "\nautocmd!")) 40 | ,... 41 | (vim.cmd "augroup END") 42 | nil))} 43 | -------------------------------------------------------------------------------- /fnl/magic/plugin.fnl: -------------------------------------------------------------------------------- 1 | (module magic.plugin 2 | {autoload {a aniseed.core 3 | packer packer}}) 4 | 5 | (defn- safe-require-plugin-config [name] 6 | "Safely require a module under the magic.plugin.* prefix. Will catch errors 7 | and print them while continuing execution, allowing other plugins to load 8 | even if one configuration module is broken." 9 | (let [(ok? val-or-err) (pcall require (.. "magic.plugin." name))] 10 | (when (not ok?) 11 | (print (.. "Plugin config error: " val-or-err))))) 12 | 13 | (defn req [name] 14 | "A shortcut to building a require string for your plugin 15 | configuration. Intended for use with packer's config or setup 16 | configuration options. Will prefix the name with `magic.plugin.` 17 | before requiring." 18 | (.. "require('magic.plugin." name "')")) 19 | 20 | (defn use [...] 21 | "Iterates through the arguments as pairs and calls packer's use function for 22 | each of them. Works around Fennel not liking mixed associative and sequential 23 | tables as well. 24 | 25 | This is just a helper / syntax sugar function to make interacting with packer 26 | a little more concise." 27 | (let [pkgs [...]] 28 | (packer.startup 29 | (fn [use] 30 | (for [i 1 (a.count pkgs) 2] 31 | (let [name (. pkgs i) 32 | opts (. pkgs (+ i 1))] 33 | (-?> (. opts :mod) (safe-require-plugin-config)) 34 | (use (a.assoc opts 1 name))))))) 35 | 36 | nil) 37 | -------------------------------------------------------------------------------- /fnl/magic/plugin/ale.fnl: -------------------------------------------------------------------------------- 1 | (module magic.plugin.ale 2 | {autoload {nvim aniseed.nvim}}) 3 | 4 | (set nvim.g.ale_linters 5 | {:clojure [:clj-kondo :joker]}) 6 | -------------------------------------------------------------------------------- /fnl/magic/plugin/auto-pairs.fnl: -------------------------------------------------------------------------------- 1 | (module magic.plugin.auto-pairs 2 | {autoload {nvim aniseed.nvim} 3 | require-macros [magic.macros]}) 4 | 5 | (defn setup [] 6 | (let [auto-pairs nvim.g.AutoPairs] 7 | (when auto-pairs 8 | (tset auto-pairs "'" nil) 9 | (tset auto-pairs "`" nil) 10 | (set nvim.b.AutoPairs auto-pairs)))) 11 | 12 | (augroup auto-pairs-config 13 | (nvim.ex.autocmd 14 | :FileType "clojure,fennel,scheme" 15 | (.. "call v:lua.require('" *module-name* "').setup()"))) 16 | -------------------------------------------------------------------------------- /fnl/magic/plugin/better-default.fnl: -------------------------------------------------------------------------------- 1 | (module magic.plugin.better-default 2 | {autoload {nvim aniseed.nvim}}) 3 | 4 | (set nvim.g.vim_better_default_persistent_undo true) 5 | (nvim.ex.runtime_ "plugin/default.vim") 6 | 7 | (nvim.ex.set :nonumber) 8 | (nvim.ex.set :norelativenumber) 9 | (nvim.ex.set :wrap) 10 | (nvim.ex.set :nocursorline) 11 | (nvim.ex.set "wildmode=full") 12 | (nvim.ex.set "wildoptions=pum") 13 | (nvim.ex.set "listchars-=eol:↵") 14 | 15 | (set nvim.o.undodir (.. (nvim.fn.stdpath "data") "/undo")) 16 | 17 | (nvim.ex.set "clipboard-=unnamedplus") 18 | -------------------------------------------------------------------------------- /fnl/magic/plugin/cmp.fnl: -------------------------------------------------------------------------------- 1 | (module dotfiles.plugin.cmp 2 | {autoload {nvim aniseed.nvim}}) 3 | 4 | (set nvim.o.completeopt "menuone,noselect") 5 | 6 | (let [(ok? cmp) (pcall require :cmp)] 7 | (when ok? 8 | (cmp.setup 9 | {:sources [{:name "conjure"} 10 | {:name "nvim_lsp"} 11 | {:name "buffer"} 12 | {:name "path"}] 13 | :mapping (cmp.mapping.preset.insert 14 | {"" (cmp.mapping.scroll_docs -4) 15 | "" (cmp.mapping.scroll_docs 4) 16 | "" (cmp.mapping.complete) 17 | "" (cmp.mapping.abort) 18 | "" (cmp.mapping.confirm {:select true})})}))) 19 | -------------------------------------------------------------------------------- /fnl/magic/plugin/lspconfig.fnl: -------------------------------------------------------------------------------- 1 | (module magic.plugin.lspconfig 2 | {autoload {util magic.util 3 | nvim aniseed.nvim}}) 4 | 5 | (defn- map [from to] 6 | (util.nnoremap from to)) 7 | 8 | (let [(ok? lsp) (pcall #(require :lspconfig))] 9 | (when ok? 10 | (lsp.clojure_lsp.setup {}) 11 | (lsp.tsserver.setup {}) 12 | (lsp.pylsp.setup {}) 13 | (lsp.bashls.setup {}) 14 | (lsp.lua_ls.setup 15 | {:cmd ["lua-language-server"] 16 | :settings {:Lua {:telemetry {:enable false}}}}) 17 | 18 | ;; https://www.chrisatmachine.com/Neovim/27-native-lsp/ 19 | (map :gd "lua vim.lsp.buf.definition()") 20 | (map :gD "lua vim.lsp.buf.declaration()") 21 | (map :gr "lua vim.lsp.buf.references()") 22 | (map :gi "lua vim.lsp.buf.implementation()") 23 | (map :K "lua vim.lsp.buf.hover()") 24 | (map : "lua vim.lsp.buf.signature_help()") 25 | (map : "lua vim.diagnostic.goto_prev()") 26 | (map : "lua vim.diagnostic.goto_next()") 27 | 28 | (map :lr "lua vim.lsp.buf.rename()") 29 | (map :lf "lua vim.lsp.buf.format({async = true})"))) 30 | -------------------------------------------------------------------------------- /fnl/magic/plugin/lualine.fnl: -------------------------------------------------------------------------------- 1 | (module magic.plugin.lualine) 2 | 3 | (let [(ok? lualine) (pcall require :lualine)] 4 | (when ok? 5 | (lualine.setup))) 6 | -------------------------------------------------------------------------------- /fnl/magic/plugin/material.fnl: -------------------------------------------------------------------------------- 1 | (module magic.plugin.material 2 | {autoload {nvim aniseed.nvim}}) 3 | 4 | (let [(ok? material) (pcall #(require :material))] 5 | (when ok? 6 | (material.setup 7 | {:custom_highlights {:FloatBorder {:fg "#1A1A1A"}} 8 | :borders true 9 | :high_visibility {:darker true}}) 10 | 11 | (set nvim.g.material_style :darker) 12 | (nvim.ex.colorscheme :material))) 13 | -------------------------------------------------------------------------------- /fnl/magic/plugin/sexp.fnl: -------------------------------------------------------------------------------- 1 | (module magic.plugin.sexp 2 | {autoload {nvim aniseed.nvim}}) 3 | 4 | (set nvim.g.sexp_filetypes "clojure,scheme,lisp,timl,fennel,janet") 5 | -------------------------------------------------------------------------------- /fnl/magic/plugin/telescope.fnl: -------------------------------------------------------------------------------- 1 | (module magic.plugin.telescope 2 | {autoload {nvim aniseed.nvim 3 | util magic.util}}) 4 | 5 | (let [(ok? telescope) (pcall #(require :telescope))] 6 | (when ok? 7 | (telescope.setup 8 | {:defaults 9 | {:vimgrep_arguments ["rg" "--color=never" "--no-heading" 10 | "--with-filename" "--line-number" "--column" 11 | "--smart-case" "--hidden" "--follow" 12 | "-g" "!.git/"]}}) 13 | 14 | (util.lnnoremap :ff "Telescope find_files hidden=true") 15 | (util.lnnoremap :f- "Telescope file_browser") 16 | (util.lnnoremap :fg "Telescope live_grep") 17 | (util.lnnoremap :* "Telescope grep_string") 18 | (util.lnnoremap :fb "Telescope buffers") 19 | (util.lnnoremap :fH "Telescope help_tags") 20 | (util.lnnoremap :fm "Telescope keymaps") 21 | (util.lnnoremap :fM "Telescope marks") 22 | (util.lnnoremap :fh "Telescope oldfiles") 23 | (util.lnnoremap :ft "Telescope filetypes") 24 | (util.lnnoremap :fc "Telescope commands") 25 | (util.lnnoremap :fC "Telescope command_history") 26 | (util.lnnoremap :fq "Telescope quickfix") 27 | (util.lnnoremap :fl "Telescope loclist") 28 | (util.lnnoremap :fsa "Telescope lsp_code_actions") 29 | (util.lnnoremap :fsi "Telescope lsp_implementations") 30 | (util.lnnoremap :fsr "Telescope lsp_references") 31 | (util.lnnoremap :fsS "Telescope lsp_document_symbols") 32 | (util.lnnoremap :fss "Telescope lsp_workspace_symbols"))) 33 | 34 | -------------------------------------------------------------------------------- /fnl/magic/plugin/treesitter.fnl: -------------------------------------------------------------------------------- 1 | (module magic.plugin.treesitter) 2 | 3 | (let [(ok? ts) (pcall require :nvim-treesitter.configs)] 4 | (when ok? 5 | (ts.setup 6 | {:indent {:enable true} 7 | :highlight {:enable true 8 | :additional_vim_regex_highlighting false}}))) 9 | -------------------------------------------------------------------------------- /fnl/magic/plugin/undotree.fnl: -------------------------------------------------------------------------------- 1 | (module magic.plugin.undotree 2 | {autoload {nvim aniseed.nvim}}) 3 | 4 | (nvim.set_keymap 5 | :n 6 | :ut 7 | ":UndotreeShow:UndotreeFocus" 8 | {:noremap true 9 | :silent true}) 10 | -------------------------------------------------------------------------------- /fnl/magic/plugin/which-key.fnl: -------------------------------------------------------------------------------- 1 | (module magic.plugin.which-key) 2 | 3 | (let [(ok? which-key) (pcall #(require :which-key))] 4 | (when ok? 5 | (which-key.setup {}))) 6 | -------------------------------------------------------------------------------- /fnl/magic/util.fnl: -------------------------------------------------------------------------------- 1 | (module magic.util 2 | {autoload {nvim aniseed.nvim 3 | a aniseed.core}}) 4 | 5 | (defn expand [path] 6 | (nvim.fn.expand path)) 7 | 8 | (defn glob [path] 9 | (nvim.fn.glob path true true true)) 10 | 11 | (defn exists? [path] 12 | (= (nvim.fn.filereadable path) 1)) 13 | 14 | (defn lua-file [path] 15 | (nvim.ex.luafile path)) 16 | 17 | (def config-path (nvim.fn.stdpath "config")) 18 | 19 | (defn nnoremap [from to opts] 20 | (let [map-opts {:noremap true} 21 | to (.. ":" to "")] 22 | (if (a.get opts :local?) 23 | (nvim.buf_set_keymap 0 :n from to map-opts) 24 | (nvim.set_keymap :n from to map-opts)))) 25 | 26 | (defn lnnoremap [from to] 27 | (nnoremap (.. "" from) to)) 28 | -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | -- Welcome to your magic kit! 2 | -- This is the first file Neovim will load. 3 | -- We'll ensure we have a plugin manager and Aniseed. 4 | -- This will allow us to load more Fennel based code and download more plugins. 5 | 6 | -- Make some modules easier to access. 7 | local execute = vim.api.nvim_command 8 | local fn = vim.fn 9 | local fmt = string.format 10 | 11 | -- Work out where our plugins will be stored. 12 | local pack_path = fn.stdpath("data") .. "/site/pack" 13 | 14 | function ensure (user, repo) 15 | -- Ensures a given github.com/USER/REPO is cloned in the pack/packer/start directory. 16 | local install_path = fmt("%s/packer/start/%s", pack_path, repo, repo) 17 | if fn.empty(fn.glob(install_path)) > 0 then 18 | execute(fmt("!git clone https://github.com/%s/%s %s", user, repo, install_path)) 19 | execute(fmt("packadd %s", repo)) 20 | end 21 | end 22 | 23 | -- Packer is our plugin manager. 24 | ensure("wbthomason", "packer.nvim") 25 | 26 | -- Aniseed compiles our Fennel code to Lua and loads it automatically. 27 | ensure("Olical", "aniseed") 28 | 29 | -- Enable Aniseed's automatic compilation and loading of Fennel source code. 30 | -- Aniseed looks for this when it's loaded then loads the rest of your 31 | -- configuration if it's set. 32 | vim.g["aniseed#env"] = {module = "magic.init"} 33 | 34 | -- Now head to fnl/magic/init.fnl to continue your journey. 35 | -- Try pressing gf on the file path to [g]o to the [f]ile. 36 | -------------------------------------------------------------------------------- /script/dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Used for development of magic kit. 4 | 5 | # It sets the config and data directories to be local to this directory. This 6 | # allows me to run a Neovim instance loading this code as it's configuration 7 | # without replacing my custom user configuration. 8 | 9 | # I basically get a plain fresh instance based on this directory while still 10 | # having access to the one stored in my home directory. 11 | 12 | export XDG_CONFIG_HOME=.dev/config 13 | export XDG_DATA_HOME=.dev/data 14 | 15 | nvim "$@" 16 | -------------------------------------------------------------------------------- /script/sync.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | NVIM_CMD=${NVIM_CMD:-nvim} 4 | LUA_DIR=${LUA_DIR:-$HOME/.config/nvim/lua} 5 | $NVIM_CMD +qa 6 | $NVIM_CMD +"au User PackerComplete qa" +PackerSync +TSUpdateSync $@ 7 | --------------------------------------------------------------------------------