├── .github └── workflows │ └── test.yml ├── .gitignore ├── .nixd.json ├── README.md ├── cheatsheet.md ├── default.nix ├── flake.lock ├── flake.nix ├── init.lua ├── pwnvim ├── abbreviations.lua ├── filetypes.lua ├── mappings.lua ├── markdown.lua ├── options.lua ├── plugins.lua ├── plugins │ ├── bufferline.lua │ ├── gitsigns.lua │ ├── indent-blankline.lua │ ├── lualine.lua │ ├── nvim-tree.lua │ ├── todo-comments.lua │ └── treesitter.lua ├── signs.lua └── tasks.lua └── update.sh /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: Test 4 | 5 | # Controls when the workflow will run 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the "main" branch 8 | push: 9 | branches: ["main"] 10 | pull_request: 11 | branches: ["main"] 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 17 | jobs: 18 | tests: 19 | runs-on: ${{ matrix.os }} 20 | strategy: 21 | matrix: 22 | build: 23 | - linux64 24 | - linuxarm 25 | - macos-x64 26 | - macos-arm 27 | include: 28 | - build: linux64 29 | os: ubuntu-latest 30 | target: x86_64-unknown-linux-musl 31 | - build: linuxarm 32 | os: ubuntu-latest 33 | target: arm-unknown-linux-gnu 34 | - build: macos-x64 35 | os: macos-latest 36 | - build: macos-arm 37 | os: macos-latest 38 | target: aarch64-apple-darwin 39 | steps: 40 | - uses: actions/checkout@v3 41 | - uses: cachix/install-nix-action@v22 42 | with: 43 | nix_path: nixpkgs=channel:nixos-unstable 44 | - uses: cachix/cachix-action@v12 45 | with: 46 | name: zmre 47 | authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" 48 | - run: nix build 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | result 2 | -------------------------------------------------------------------------------- /.nixd.json: -------------------------------------------------------------------------------- 1 | { 2 | "eval": { 3 | "target": { 4 | "args": ["-f", "default.nix"], 5 | "installable": "pwnvim" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pwnvim - my portable nvim setup 2 | 3 | This repo is for [nix](https://nixos.org/) users. If that doesn't mean anything to you, you're probably in the wrong place. Although I rather enjoy the name of this being "pwn vim", it is really my initials, "pw" and "nvim" that drove the name choice. If you're worried that running this will pwn your machine, then you should just use it as inspiration for building your own. I doubt my config will work exactly how you'd like it to anyway. 4 | 5 | ## Background 6 | 7 | One of the awesome thing about nix is that you can track your vim/neovim config and change it along with changes to the versions of plugins and neovim itself. This makes me very happy. I used to use different dot-file configs so I could get my settings onto new machines quickly, but these days I'm all in on nix and [home-manager](https://github.com/nix-community/home-manager). Prior to this project, my neovim configs were embedded in my home-manager configs. 8 | 9 | But one of the reasons I started using Nix in the first place was one of [Burke Libbey's videos](https://www.youtube.com/channel/UCSW5DqTyfOI9sUvnFoCjBlQ/videos) on the topic (I forget which one) showing how he could develop on someone else's machine using his familiar editor and settings without modifying or messing up anything on their machine. It was a sweet demo and it made an impression even though I almost never find myself trying to write code on someone else's machine. 10 | 11 | But Burke's approach to nix is quite different from mine. Perhaps his has evolved since he made his videos. Regardless, my preferred approach is to drive everything installed on my machine off of [declarative config files](https://github.com/zmre/nix-config). I'm also a huge fan of [flakes](https://nixos.wiki/wiki/Flakes). If I want to install something permanently (as opposed to in a temporary shell), I edit my config files and run a command to make my system match the files. It's great. 12 | 13 | Recently I was helping someone else with their config and I really missed having my neovim setup -- not just my preferred basic settings, but also my nix code formatter and LSP helpers and such. So I was motivated to make a version of my config that didn't read the configs out of the usual `~/.config/neovim` folder, but instead was sandboxed so it could be ephemeral and used from any nix machine independent of home-manager or global config files. 14 | 15 | The only example I could find of doing this in a flake was in [Jordan Isaacs](https://github.com/jordanisaacs/neovim-flake) setup, which showed me this would be possible. But it worked a bit differently than I wanted and I wasn't able to easily adapt it. His is nicely modular with various switches, which mine is not at this point, so you might be interested in checking out what he's done there. 16 | 17 | Think of this repo as an extremely opinionated and not readily customizable [LunarVim](https://github.com/lunarVim/LunarVim/) (or AstroNvim or Nyoom.nvim or whatever) but built specifically for nix where you don't have to run commands or install things for it to work. And hopefully there are no version mismatch things causing weird bugs. 18 | 19 | ## What's Included 20 | 21 | As of the writing of this README, it will give nice syntax highlighting to almost anything, but full nice environments for rust, typescript, svelte, nix, lua, and markdown. I will probably add to these as I dust off old projects or pick up new things. But this is sort of a warning that it might not work ideally for you if you're programming in perl, php, java, or something else outside of my present-day wheelhouse. 22 | 23 | It includes git symbols, fugitive, nice status lines and tab bars for buffers, file choosers via telescope, autocomplete, and much more. Take a look at the [flake.nix](./flake.nix) file to get a full picture. 24 | 25 | ## Using It 26 | 27 | Most of the key bindings have descriptions and discoverability via which-key. The leader key is comma so hitting comma and waiting a second will help guide you. Or you can look at my [cheatsheet](./cheatsheet.md) which has keys I want to remember, some of which are built-in and others of which are specific to this config. 28 | 29 | From a system with nix installed, you can simply do this: 30 | 31 | `nix run github:zmre/pwnvim` 32 | 33 | to try it out. 34 | 35 | There are a few ways to install a flake in your own config if you want it to be more permanent. I add it as an overlay in my config so it's available as a package. So in `flake.nix` you'd have something like this (note, this won't work as-is, but is meant to be a general guide): 36 | 37 | ```nix 38 | { 39 | inputs = { 40 | nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 41 | # ... 42 | pwnvim.url = "github:zmre/pwnvim"; 43 | pwneovide.url = "github:zmre/pwneovide"; 44 | } 45 | outputs = inputs@{ pwnvim, pwneovide, ... }: { 46 | pkgs = import nixpkgs { 47 | inherit system; 48 | overlays = [ 49 | (final: prev: { 50 | pwnvim = inputs.pwnvim.packages.${final.system}.pwnvim; 51 | pwneovide = inputs.pwneovide.packages.${final.system}.pwneovide; 52 | }) 53 | ]; 54 | }; 55 | } 56 | } 57 | ``` 58 | 59 | And later in your config you'd specify `pkgs.pwnvim` as something to install. 60 | 61 | When you want to run it, just use `nvim` and not `pwnvim` though I may make both work later. I'm not sure what will happen if you also have `pkgs.neovim` setup -- probably works but they'll fight for the alias? 62 | 63 | ## TODO 64 | 65 | * [ ] Setup some testing so a build fails if there are errors on load or if LSP breaks for some programming language 66 | * Seriously, if anyone has a good way to test neovim configs especially as part of nix builds, I'd love to hear it 67 | * [ ] Make some alternate flake targets that produce other outputs such as a lightweight one (no programming stuff), 68 | * [x] and one that works in terminals without fancy fonts and with only 16 colors (this is now done though it's a bit ugly, but I have used it a lot) 69 | -------------------------------------------------------------------------------- /cheatsheet.md: -------------------------------------------------------------------------------- 1 | # Cheatsheet pwnvim Hotkeys Reference 2 | 3 | _This is a combination of built-in universal keys and things that are specific to my config._ 4 | 5 | ## Misc 6 | * `gx` to open a URL 7 | * `gf` to open the file path under the cursor (in vim) 8 | * `gv` to **reselect** last selection 9 | * `gi` to go back to last insertion point and insert 10 | * `,P` paste markdown url (auto lookup the title of the page) 11 | * `:PasteImg` will save image to subdir if it is on clipboard 12 | * On mac, use `ctrl` modifier on screenshot like `cmd-ctrl-shift-4` to put screenshot on clipboard 13 | * `g ctrl-g` show cursor col, line, word, byte offsets 14 | * `g~`_m_ switch case of _movement_ 15 | * `'"` go to position before last edit 16 | * `';` go to last edited line 17 | * `g;`, `g,` go forward/backward in change list 18 | * `di(`, `di"` delete within parents/quotes. Do `a` instead of `i` for taking out the delimiters 19 | * `"_c`_m_ change _movement_ but blackhole the deletion so you can use the `"` register or paste 20 | * Alt: use `v`_m_`p` to select that which you want to change and paste over it (or use `cmd-v` instead of `p`) 21 | * `,cd` change dir to current file's path 22 | * `,lcd` change dir for cur buffer only to current file's path 23 | * `,q` open quicklist with any errors 24 | * `q:` opens command mode but in editor 25 | * `` is equivalent but launches from command mode 26 | * `F2`, `,e` Show/hide file explorer 27 | * `F3` Quick grep with results to loclist (not live) 28 | * `F4` Toggle showing invisible characters 29 | * `F7` Show tags or file outline drawer 30 | * `F8` Insert current date 31 | * `F9` Focus mode for writing 32 | * `F10` Quicklook preview file 33 | * `F12` Reset syntax parsing 34 | 35 | ## Windowing 36 | * `,x` close current buffer 37 | * `^Ws` `:split` horiz window split 38 | * `^Wv` `:vsplit` vert window split 39 | * `^Wn` `:new` horz split with new 40 | * `^Wo` `:only` make current window only one 41 | * `^Wr` rotate windows 42 | * `^Wc` close current window pane 43 | * `:sb `_n_ Split the buffer window and populate new split with buffer _n_ 44 | * `H`, `L` goto prev/next buffer 45 | * `[1`, `]1` jump to first buffer/tab (or second with 2, etc.) 46 | 47 | ## Folds 48 | * `zf`_m_ create fold of movement _m_ 49 | * `zf/`_string_ create fold to match 50 | * `:`_r_`fo` create fold for range _r_ 51 | * `zo`, `zc` open, close one fold 52 | * `zO`, `zC` open, close folds recursively 53 | * `zr`, `zm` open, close one fold level entire doc 54 | * `zR`, `zM` open, close all folds 55 | * `[z`, `]z` navigate between folds 56 | * `za`, `` toggle fold under cursor 57 | 58 | ## Completion 59 | * `^N`, `^P` word completion _(INSERT)_ 60 | * `^X^L` line completion _(INSERT)_ 61 | * `^X^O` word completion _(INSERT)_ 62 | * `^X^U` to complete :emoji: symbols (then use `,e` to turn it into a symbol if desired) 63 | * `^e` to cancel autocomplete (my config) 64 | 65 | ## Digraphs 66 | * `^k` to insert digraph with two char code 67 | * ✓ = OK 68 | * ✗ = XX 69 | * ™ = TM 70 | * © = Co 71 | * → = -> 72 | * `ga` view code of char under cursor (note the digraph code at the end) 73 | * `:help digraph-table` to view all 74 | 75 | ## Spelling 76 | * `[s`, `]s` prev/next misspelled word 77 | * `[S`, `]S` prev/next "bad" word (skips rare words) 78 | * `zg` add to word list 79 | * `zw` add to the bad word list 80 | * `z=` suggest words 81 | * `1z=` auto take first suggested word 82 | * `^X^K` Autocomplete from dictionary 83 | * Thesaurus 84 | * https://raw.githubusercontent.com/moshahmed/vim/master/thesaurus/thesaurii.txt or http://www.gutenberg.org/files/3202/files/mthesaur.txt 85 | * set thesaurus+=/Users/yanis/thesaurus/words.txt 86 | * `^X^T` show synonyms 87 | 88 | ## Programming (many require lsp server) 89 | * `,c ` (c space) comment, uncomment current line or selection 90 | * `gc`_m_ comment for motion or `gcc` for current line 91 | * `gb`_m_ comment blockwise for motion (or visual selection) 92 | * `,lD` goto implementation 93 | * `,ld` goto definition 94 | * `,le` show line errors 95 | * `,lf` fixit code actions menu 96 | * `,li` info hover 97 | * `,ll` toggle virtual text lines 98 | * `,lr` show references 99 | * `,lsd` find symbols in document 100 | * `,lsw` find symbols in workspace 101 | * `,lt` show signature 102 | 103 | * When available 104 | * `,lR` rename symbol 105 | * `,l=` format current line or selection 106 | * `,lI` telescope implementations 107 | 108 | * For rust 109 | * `,rr` run menu of options (tests, etc) 110 | * `,re` expand macro 111 | * `,rh` hover actions 112 | * `,ra` rust code actions 113 | 114 | * Indentation 115 | * `,i1` use tab for indent 116 | * `,i2` use two spaces for indent 117 | * `,i4` use four spaces for indent 118 | * `,ir` retab to current setting 119 | 120 | ## Git 121 | * `,gs` browse git status and jump to selected file 122 | * `,gb` browse git branches and switch to selected 123 | * `,gc` browse git commits 124 | * `,g-` reset (unstage) current hunk 125 | * `,g+` stage current hunk 126 | * `,gu` undo stage hunk 127 | * `,gS` stage buffer 128 | * `,gR` reset buffer 129 | * `,gp` preview hunk 130 | * `,gB` blame hunk popup 131 | * `,gd` diff this to index 132 | * `,gD` diff this to previous 133 | 134 | * Worktrees 135 | * `,gws` switch worktree 136 | * `,gwn` new worktree 137 | 138 | * Toggles 139 | * `,gtb` toggle current line blame 140 | * `,gtd` toggle show deleted 141 | 142 | Motion 143 | * _action_`ih` select the current git hunk 144 | 145 | * `]c`, `[c` next/prev change 146 | * `]n`, `[n` next/prev conflict 147 | 148 | * Fugitive 149 | * `:G`, `:GStatus` 150 | * Use `ctrl + n` / `ctrl + p` to jump between files 151 | * Press `-` on a file to toggle whether it is added (`git add` or `git reset` depending) 152 | * Press `p` on a file to walk through hunks of changes and selectively add parts of a file 153 | * Press `` to view it and then `:Gdiff` to see changes 154 | * Press `cc` to commit 155 | * Press `ca` to amend last commit 156 | * `gq` to close status buffer 157 | * `=` toggle inline diff of file under cursor (preferred) 158 | * Or `dp` to invoke git diff on the file under the cursor 159 | * `:Gdiff` 160 | * index on left (git added or last committed), working copy on right 161 | * `:diffget` will pull changes from opposite window in allowing to undo changes 162 | * Press `s` to stage a hunk 163 | * Press `u` to unstage a hunk 164 | * Press `-` to toggle staging of hunk 165 | * Use `]c` and `[c` to jump between hunks 166 | * `:Gcommit` 167 | * `:GBrowse` to launch current file in github in browser 168 | * "In commit messages, GitHub issues, issue URLs, and collaborators can be omni-completed (``, see :help compl-omni). This makes inserting those `Closes #123` remarks slightly easier than copying and pasting from the browser. 169 | * `:Gedit :0` 170 | * Open index version of current file in a tmp buffer. index file is the git added version. 171 | * `:Gedit` 172 | * Explore git objects to navigate commits and old versions of the tree without changing anything 173 | * Can hit enter on parent (prev commit) or tree (state of all files at this point) and then select other files 174 | * Get into this better with `:Gclog` 175 | * When looking at a commit, hit enter on a diff line to see how things changed 176 | * Capital `C` will jump you from a tmp file or whatever up to related commit 177 | * `:Git mergetool` load current conflicts into quickfix list (TODO: try `ri` on the git status screen to initiate rebase) 178 | * Navigate through the conflicted files (use the unimpaired `[q` and `]q`) 179 | * Launch the 3-way merge tool with `:Gvdiffsplit!` (the `!` is for 3-way and `v` for vertical split) 180 | * Now put cursor in the middle window. 181 | * Left pane, "2", is local, right pane is remote, "3". For rebase though, left seems to be master and right the local branch. 182 | * Use `d2o` or `d3o` to pull changes from left or right for current chunk. 183 | * Navigate between chunks with `]c` and `[c` 184 | * When a file is good, use `:Gw` and move on 185 | * When finished you get to the end of the quickfix list, use `:G` to check status then `cc` to commit. 186 | * After commit, use `rr` in the status screen or `:G rebase --contine` and hope you don't get a fresh set of conflicts, but if you do, repeat from the top. 187 | 188 | ## Notes 189 | * `,ng` spawn grammar checker 190 | * `,nn` use zk to add new note under $ZK_NOTEBOOK_DIR/Notes (prompt for dir) 191 | * `,no` use zk to open note by heading or filename 192 | * `,nt` use zk to find notes by tag 193 | * `,nf` use zk to find notes 194 | * `,nm` use zk to make new meeting note in $ZK_NOTEBOOK_DIR/Notes/meetings 195 | * `,nd` use zk to make new diary note in $ZK_NOTEBOOK_DIR/Calendar 196 | * `,nh` open hotsheet note 197 | * `gt` turn url under cursor into titled link 198 | * in open markdown note only 199 | * `,np` new peer note in same folder as this one 200 | * `,nl` show outbound links 201 | * `,nr` show reference (inbound) links 202 | * `,ni` show info preview 203 | * `K` over link to preview linked note 204 | 205 | ## Plugin: Telescope 206 | Fuzzy finder via Telescope 207 | 208 | * `,ff` fuzzy search files 209 | * `,fg` fuzzy grep files (live) 210 | * `,fb` fuzzy find buffer 211 | * `,fh` fuzzy search history of open files 212 | * `,fq` fuzzy browse quickfix 213 | * `,fl` fuzzy browse location list 214 | * `,fz` fuzzy browse zoxide 215 | * `,fp` fuzzy browse projects 216 | * `,fk` fuzzy browse keymaps 217 | * `,fd` fuzzy browse document symbols 218 | * Inside the popup window: 219 | * `ctrl + p` on selection to paste selection at cursor 220 | * `ctrl + y` on selection to copy selection 221 | * `ctrl + o` on selection call `open` on it 222 | * ctrl + q to put results in quick fix list 223 | * `ctrl + e` create new file in current dir or creates dir if name contains trailing slash or subdirs like `dir/subdir/file` 224 | 225 | ### Plugin: Unimpaired 226 | * `[a`, `]a` prev/next file if multiple specified on cli 227 | * `[A`, `]A` first/last file if multiple specified on cli 228 | * `[b`, `]b` prev/next buffer 229 | * `[B`, `]B` first/last buffer 230 | * `[l`, `]l` prev/next location list 231 | * `[L`, `]L` first/last location list 232 | * `[q`, `]q` prev/next quickfix errors list 233 | * `[Q`, `]Q` first/last quickfix errors list 234 | * `[o`, `]o` prev/next file in dir by alpha 235 | * `[n`, `]n` prev/next git conflict 236 | * `[`, `]` add line above/below 237 | * `[e`, `]e` exchange line with above/below 238 | * `[x`_m_ xml encode (<) movement _m_ or _VISUAL_ 239 | * `]x`_m_ xml decode (<) movement _m_ or _VISUAL_ 240 | * `[u`_m_ url encode (%20) movement _m_ or _VISUAL_ 241 | * `]u`_m_ url decode (%20) movement _m_ or _VISUAL_ 242 | * `[y`_m_ c encode (\") movement _m_ or _VISUAL_ 243 | * `]y`_m_ c decode (\") movement _m_ or _VISUAL_ 244 | * Pasting 245 | * `>p` Paste after linewise, increasing indent. 246 | * `>P` Paste before linewise, increasing indent. 247 | * `` and `-` next/prev file with conflicts 270 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | ( 2 | # For nixd from: https://github.com/nix-community/nixd/tree/main/docs/examples/flake 3 | import 4 | ( 5 | let 6 | lock = builtins.fromJSON (builtins.readFile ./flake.lock); 7 | in 8 | fetchTarball { 9 | url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; 10 | sha256 = lock.nodes.flake-compat.locked.narHash; 11 | } 12 | ) 13 | {src = ./.;} 14 | ) 15 | .defaultNix 16 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "clipboard-image": { 4 | "flake": false, 5 | "locked": { 6 | "lastModified": 1713280083, 7 | "narHash": "sha256-tmehpn1NVxRsktLh8qN6J/6EsE5qk4Dvlajhavfm54A=", 8 | "owner": "postfen", 9 | "repo": "clipboard-image.nvim", 10 | "rev": "4ab6f7f1fa4ea97866c0e0f6160f6a36ef174438", 11 | "type": "github" 12 | }, 13 | "original": { 14 | "owner": "postfen", 15 | "repo": "clipboard-image.nvim", 16 | "type": "github" 17 | } 18 | }, 19 | "conform-nvim": { 20 | "flake": false, 21 | "locked": { 22 | "lastModified": 1747182398, 23 | "narHash": "sha256-9pjZLQnFCQLBH+zLLN/pNijwD2+V+MObbq8OoVSert0=", 24 | "owner": "stevearc", 25 | "repo": "conform.nvim", 26 | "rev": "2b2b30260203af3b93a7470ac6c8457ddd6e32d9", 27 | "type": "github" 28 | }, 29 | "original": { 30 | "owner": "stevearc", 31 | "repo": "conform.nvim", 32 | "type": "github" 33 | } 34 | }, 35 | "fenix": { 36 | "inputs": { 37 | "nixpkgs": [ 38 | "nixpkgs" 39 | ], 40 | "rust-analyzer-src": "rust-analyzer-src" 41 | }, 42 | "locked": { 43 | "lastModified": 1747291057, 44 | "narHash": "sha256-9Wir6aLJAeJKqdoQUiwfKdBn7SyNXTJGRSscRyVOo2Y=", 45 | "owner": "nix-community", 46 | "repo": "fenix", 47 | "rev": "76ffc1b7b3ec8078fe01794628b6abff35cbda8f", 48 | "type": "github" 49 | }, 50 | "original": { 51 | "owner": "nix-community", 52 | "repo": "fenix", 53 | "type": "github" 54 | } 55 | }, 56 | "flake-compat": { 57 | "flake": false, 58 | "locked": { 59 | "lastModified": 1687265871, 60 | "narHash": "sha256-P8AOiQk/XN8/ia4289hDHlTfWB70cRQ5pc9GRfmEdpc=", 61 | "owner": "inclyc", 62 | "repo": "flake-compat", 63 | "rev": "70e56389c58bbd300d11778913b255477ebbae22", 64 | "type": "github" 65 | }, 66 | "original": { 67 | "owner": "inclyc", 68 | "repo": "flake-compat", 69 | "type": "github" 70 | } 71 | }, 72 | "flake-utils": { 73 | "inputs": { 74 | "systems": "systems" 75 | }, 76 | "locked": { 77 | "lastModified": 1731533236, 78 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 79 | "owner": "numtide", 80 | "repo": "flake-utils", 81 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 82 | "type": "github" 83 | }, 84 | "original": { 85 | "owner": "numtide", 86 | "repo": "flake-utils", 87 | "type": "github" 88 | } 89 | }, 90 | "nixpkgs": { 91 | "locked": { 92 | "lastModified": 1747312588, 93 | "narHash": "sha256-MmJvj6mlWzeRwKGLcwmZpKaOPZ5nJb/6al5CXqJsgjo=", 94 | "owner": "nixos", 95 | "repo": "nixpkgs", 96 | "rev": "b1bebd0fe266bbd1820019612ead889e96a8fa2d", 97 | "type": "github" 98 | }, 99 | "original": { 100 | "owner": "nixos", 101 | "ref": "nixpkgs-unstable", 102 | "repo": "nixpkgs", 103 | "type": "github" 104 | } 105 | }, 106 | "root": { 107 | "inputs": { 108 | "clipboard-image": "clipboard-image", 109 | "conform-nvim": "conform-nvim", 110 | "fenix": "fenix", 111 | "flake-compat": "flake-compat", 112 | "flake-utils": "flake-utils", 113 | "nixpkgs": "nixpkgs" 114 | } 115 | }, 116 | "rust-analyzer-src": { 117 | "flake": false, 118 | "locked": { 119 | "lastModified": 1746889290, 120 | "narHash": "sha256-h3LQYZgyv2l3U7r+mcsrEOGRldaK0zJFwAAva4hV/6g=", 121 | "owner": "rust-lang", 122 | "repo": "rust-analyzer", 123 | "rev": "2bafe9d96c6734aacfd49e115f6cf61e7adc68bc", 124 | "type": "github" 125 | }, 126 | "original": { 127 | "owner": "rust-lang", 128 | "ref": "nightly", 129 | "repo": "rust-analyzer", 130 | "type": "github" 131 | } 132 | }, 133 | "systems": { 134 | "locked": { 135 | "lastModified": 1681028828, 136 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 137 | "owner": "nix-systems", 138 | "repo": "default", 139 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 140 | "type": "github" 141 | }, 142 | "original": { 143 | "owner": "nix-systems", 144 | "repo": "default", 145 | "type": "github" 146 | } 147 | } 148 | }, 149 | "root": "root", 150 | "version": 7 151 | } 152 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "PW's Neovim (pwnvim) Configuration"; 3 | nixConfig = { 4 | extra-substituters = [ 5 | "https://cache.nixos.org" 6 | "https://nix-community.cachix.org" 7 | "https://zmre.cachix.org" 8 | ]; 9 | extra-trusted-public-keys = [ 10 | "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" 11 | "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" 12 | "zmre.cachix.org-1:WIE1U2a16UyaUVr+Wind0JM6pEXBe43PQezdPKoDWLE=" 13 | ]; 14 | }; 15 | inputs = { 16 | nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 17 | flake-utils.url = "github:numtide/flake-utils"; 18 | flake-compat = { 19 | # Needed along with default.nix in root to allow nixd lsp to do completions 20 | # See: https://github.com/nix-community/nixd/tree/main/docs/examples/flake 21 | url = "github:inclyc/flake-compat"; 22 | flake = false; 23 | }; 24 | fenix.url = "github:nix-community/fenix"; 25 | fenix.inputs.nixpkgs.follows = "nixpkgs"; 26 | # ekickx doesn't seem to be maintaing. postfen's fork worth using for now. TODO: revisit 27 | # Note: dfendr's fork could also be one to use. 28 | # clipboard-image.url = "github:ekickx/clipboard-image.nvim"; 29 | clipboard-image.url = "github:postfen/clipboard-image.nvim"; 30 | clipboard-image.flake = false; 31 | conform-nvim.url = "github:stevearc/conform.nvim"; 32 | conform-nvim.flake = false; 33 | }; 34 | outputs = inputs @ { 35 | self, 36 | nixpkgs, 37 | flake-utils, 38 | ... 39 | }: 40 | flake-utils.lib.eachDefaultSystem (system: let 41 | pkgs = import nixpkgs { 42 | inherit system; 43 | config = {allowUnfree = true;}; 44 | overlays = [ 45 | (self: super: { 46 | languagetool = super.languagetool.overrideAttrs (old: rec { 47 | version = "5.9"; # grammarous doesn't support 6+ 48 | src = super.fetchzip { 49 | url = "https://www.languagetool.org/download/${old.pname}-${version}.zip"; 50 | sha256 = "sha256-x4xGgYeMi7KbD2WGHOd/ixmZ+5EY5g6CLd7/CBYldNQ="; 51 | }; 52 | }); 53 | }) 54 | (self: super: { 55 | vimPlugins = 56 | super.vimPlugins 57 | // { 58 | clipboard-image = super.vimUtils.buildVimPlugin { 59 | name = "clipboard-image.nvim"; 60 | pname = "clipboard-image.nvim"; 61 | src = inputs.clipboard-image; 62 | # buildInputs = [ super.curl ]; 63 | }; 64 | conform-nvim = super.vimUtils.buildVimPlugin { 65 | name = "conform-nvim"; 66 | pname = "conform-nvim"; 67 | src = inputs.conform-nvim; 68 | }; 69 | }; 70 | }) 71 | ]; 72 | }; 73 | 74 | dependencies = with pkgs; 75 | [ 76 | fd 77 | ripgrep 78 | fzy 79 | zoxide 80 | bat # previewer for telescope for now 81 | zk # lsp for markdown notes in zk folders 82 | #markdown-oxide # lsp for any markdown 83 | marksman # lsp for any markdown 84 | zsh # terminal requires it 85 | git 86 | curl # needed to fetch titles from urls 87 | # todo: research https://github.com/artempyanykh/marksman 88 | vale # linter for prose 89 | proselint # ditto 90 | luaformatter # ditto for lua 91 | #prisma-engines # ditto for schema.prisma files # TODO: bring back when rust compile issues are fixed 2024-08-26 92 | # Nix language servers summary 2023-11-23 93 | # rnix-lsp -- seems abandoned 94 | # nil -- way better than rnix and generally great, but 95 | nixd # -- damn good at completions referencing back to nixpkgs, for example 96 | # at least provided you do some weird gymnastics in flakes: 97 | # https://github.com/nix-community/nixd/blob/main/docs/user-guide.md#faq 98 | # using this one for now 99 | #nixfmt # nix formatter 100 | alejandra # better nix formatter alternative 101 | statix # linter for nix 102 | shellcheck 103 | languagetool # needed by grammarous, but must be v5.9 (see overlay) 104 | # luajitPackages.lua-lsp 105 | lua-language-server 106 | pyright # python lsp (written in node? so weird) 107 | vscode-langservers-extracted # lsp servers for json, html, css, eslint 108 | nodePackages.eslint_d # js/ts code formatter and linter 109 | nodePackages.prettier # ditto 110 | #nodePackages.prisma # dependency prisma-engines not compiling right now 2024-08-26 111 | nodePackages.svelte-language-server 112 | nodePackages.diagnostic-languageserver 113 | nodePackages.typescript-language-server 114 | nodePackages.bash-language-server 115 | nodePackages."@tailwindcss/language-server" 116 | #nodePackages_latest.grammarly-languageserver # besides being a privacy issue if triggered, we have these issues: 117 | # https://github.com/znck/grammarly/issues/411 grammarly sdk deprecated 118 | # https://github.com/NixOS/nixpkgs/issues/293172 requires node16, which is EOL 119 | yaml-language-server 120 | # jinja-lsp # jinja is an html template language; i'm using zola right now which uses the tera language, which is a lot like jinja 121 | mypy # static typing for python used by null-ls 122 | ruff # python linter used by null-ls 123 | black # python formatter 124 | rust-analyzer # lsp for rust 125 | # rust-analyzer is currently in a partially broken state as it cannot find rust sources so can't 126 | # help with native language things, which sucks. Here are some issues to track: 127 | # https://github.com/rust-lang/rust/issues/95736 - FIXED 128 | # https://github.com/rust-lang/rust-analyzer/issues/13393 - CLOSED NOT RESOLVED 129 | # https://github.com/mozilla/nixpkgs-mozilla/issues/238 130 | # - suggestion to do export RUST_SRC_PATH="$(rustc --print sysroot)/lib/rustlib/src/rust/src" which is like what we're doing below in customRC, I think 131 | # https://github.com/rust-lang/cargo/issues/10096 132 | rustfmt 133 | cargo # have this as a fallback when a local flake isn't in place 134 | rustc # have this as a fallback when a local flake isn't in place 135 | vscode-extensions.vadimcn.vscode-lldb.adapter # for debugging rust 136 | (python3.withPackages (ps: with ps; [debugpy])) # required for debugging python, but better if that's per project installed since we don't have python 137 | 138 | metals # lsp for scala 139 | # imagemagick # for image-nvim plugin 140 | ] 141 | ++ pkgs.lib.optionals pkgs.stdenv.isLinux [ 142 | ueberzug 143 | xclip # needed by vim clipboard-image plugin 144 | wl-clipboard # needed by vim clipboard-image plugin 145 | ] 146 | ++ pkgs.lib.optionals pkgs.stdenv.isDarwin 147 | [pngpaste]; # needed by vim clipboard-image plugin 148 | 149 | customRC = 150 | '' 151 | lua << EOF 152 | package.path = "${self}/?.lua;" .. package.path 153 | rustsrc_path = "${pkgs.rustPlatform.rustLibSrc}/core/Cargo.toml" 154 | prettier_path = "${pkgs.nodePackages.prettier}/bin/prettier" 155 | lldb_path_base = "${pkgs.vscode-extensions.vadimcn.vscode-lldb}" 156 | vim.env.RUST_SRC_PATH = "${pkgs.rustPlatform.rustLibSrc}" 157 | vim.env.RA_LOG = "info,salsa::derived::slot=warn,chalk_recursive=warn,hir_ty::traits=warn,flycheck=trace,rust_analyzer::main_loop=warn,ide_db::apply_change=warn,project_model=debug,proc_macro_api=debug,hir_expand::db=error,ide_assists=debug,ide=debug" 158 | rustanalyzer_path = "${pkgs.rust-analyzer}/bin/rust-analyzer" 159 | vim.g.loaded_python3_provider = 0 160 | '' 161 | + pkgs.lib.readFile ./init.lua 162 | + '' 163 | EOF 164 | ''; 165 | 166 | requiredPlugins = with pkgs.vimPlugins; 167 | [ 168 | # Common dependencies of other plugins 169 | popup-nvim # dependency of some other plugins 170 | plenary-nvim # Library for lua plugins; used by many plugins here 171 | 172 | # Syntax / Language Support ########################## 173 | # Removing 2022-11-30 as it is slow and treesitter generally does the same thing 174 | # Reinstating 2024-09-10 so I get fallbacks again 175 | # Removing again 2024-12-12 because it isn't respecting the ftdetect disable and is overriding my detections 176 | #vim-polyglot # lazy load all the syntax plugins for all the languages 177 | rustaceanvim # lsp stuff and more for rust; replaces rust-tools-nvim which is now archived 178 | nvim-lspconfig # setup LSP for intelligent coding 179 | nvim-lint # replace null-ls for linting bits 180 | conform-nvim # replace null-ls and lsp-format-nvim for formatting 181 | trouble-nvim # navigate all warnings and errors in quickfix-like window 182 | nvim-dap # debugging functionality used by rust-tools-nvim 183 | nvim-dap-ui # ui for debugging 184 | nvim-dap-python 185 | nvim-nio # needed by dap-ui 186 | neotest 187 | neotest-rust 188 | neodev-nvim # help for neovim lua api 189 | SchemaStore-nvim # json schemas 190 | vim-matchup # replaces built-in matchit and matchparen with better matching and faster 191 | nvim-lightbulb # show code actions available 192 | 193 | # UI ################################################# 194 | onedarkpro-nvim # colorscheme 195 | catppuccin-nvim # colorscheme 196 | ir_black # colorscheme for basic terminals 197 | #zephyr-nvim # alternate colorscheme 198 | telescope-nvim # da best popup fuzzy finder 199 | telescope-fzy-native-nvim # with fzy gives better results 200 | # telescope-frecency-nvim # and frecency comes in handy too 201 | #sqlite-lua # needed by frecency plugin -- beta support to remove dep 202 | dressing-nvim # dresses up vim.ui.input and vim.ui.select and uses telescope 203 | nvim-colorizer-lua # color over CSS like #00ff00 204 | nvim-web-devicons # makes things pretty; used by many plugins below 205 | oil-nvim # file navigator 206 | git-worktree-nvim # jump between worktrees 207 | gitsigns-nvim # git status in gutter 208 | # symbols-outline-nvim # navigate the current file better 209 | lualine-nvim # nice status bar at bottom 210 | vim-bbye # fix bdelete buffer stuff needed with bufferline 211 | # bufferline-nvim # tabs at top 212 | dropbar-nvim # replacing the now archived barbecue (sad!) 213 | nvim-navbuddy # use same lsp symbols to navigate in popup 214 | nvim-ufo # allow use of lsp as source for folding 215 | promise-async # required by nvim-ufo 216 | indent-blankline-nvim # visual indent 217 | toggleterm-nvim # better terminal management 218 | playground # treesitter playground 219 | nvim-treesitter-textobjects # jump around and select based on syntax (class, function, etc.) 220 | nvim-treesitter-textsubjects # adds "smart" text objects 221 | lf-vim 222 | nui-nvim # needed by noice 223 | nvim-notify # needed by noice 224 | noice-nvim # show progress and add other UI improvements 225 | marks-nvim # show marks in the gutter 226 | yazi-nvim # another file manager which i've started using; not replacing oil yet so side by side for now 227 | 228 | # Editor Features #################################### 229 | vim-abolish # better abbreviations / spelling fixer 230 | nvim-surround # .... updated lua-based alternative to tpope's surround 231 | vim-unimpaired # bunch of convenient navigation key mappings 232 | vim-repeat # supports all of the above so you can use . 233 | #nvim-ts-context-commentstring # makes kommentary contextual for embedded languages 234 | vim-eunuch # brings cp/mv type commands. :Rename and :Move are particularly handy 235 | vim-speeddating # allows ctrl-x and ctrl-a to increment/decrement dates 236 | flash-nvim 237 | 238 | # Database interactions 239 | # vim-dadbod 240 | # vim-dadbod-ui 241 | # vim-dadbod-completion 242 | 243 | # Autocompletion 244 | nvim-cmp # generic autocompleter 245 | cmp-nvim-lsp # use lsp as source for completions 246 | cmp-nvim-lua # makes vim config editing better with completions 247 | cmp-buffer # any text in open buffers 248 | cmp-path # complete paths 249 | cmp-cmdline # completing in :commands 250 | cmp-emoji # complete :emojis: 251 | cmp-nvim-lsp-signature-help # help complete function call by showing args 252 | cmp-npm # complete node packages in package.json 253 | codecompanion-nvim 254 | nvim-autopairs # balances parens as you type 255 | nvim-ts-autotag # balance or rename html 256 | vim-emoji # TODO: redundant now? 257 | #luasnip # snippets driver 258 | #cmp_luasnip # snippets completion 259 | #friendly-snippets # actual library of snippets used by luasnip 260 | 261 | # writing 262 | zk-nvim # lsp for a folder of notes for searching/linking/etc. 263 | true-zen-nvim # distraction free, width constrained writing mode 264 | # twilight-nvim # dim text outside of current scope 265 | 266 | # Misc 267 | vim-fugitive # git management 268 | diffview-nvim 269 | project-nvim 270 | vim-tmux-navigator # navigate vim and tmux panes together 271 | impatient-nvim # speeds startup times by caching lua bytecode 272 | which-key-nvim 273 | vim-startuptime 274 | 275 | # Something was obliterating rtp and making grammars disappear. Putting this on the bottom of the list 276 | # fixes the issue for me 2024-09-10. 277 | nvim-treesitter.withAllGrammars 278 | #(nvim-treesitter.withPlugins (_: pkgs.tree-sitter.allGrammars)) # better code coloring 279 | ] 280 | ++ pkgs.lib.optionals (!pkgs.stdenv.isDarwin) [ 281 | telescope-media-files-nvim # only works on linux, requires ueberzug, but gives image preview 282 | ]; 283 | optionalPlugins = with pkgs.vimPlugins; [ 284 | # grammar check 285 | vim-grammarous 286 | # see note about hologram in markdown.lua file. commented out 2023-01-19 287 | #hologram-nvim # images inline for markdown (only in terminal) 288 | direnv-vim # auto-execute nix direnv setups -- currently my slowest plugin; enabled by programming filetype 289 | clipboard-image # only loaded in markdown files 290 | comment-nvim # code commenter 291 | crates-nvim # inline intelligence for Cargo.toml 292 | todo-comments-nvim # highlight comments like NOTE 293 | render-markdown-nvim # prettier markdown files 294 | # image-nvim 295 | ]; 296 | 297 | recursiveMerge = attrList: let 298 | f = attrPath: 299 | builtins.zipAttrsWith (n: values: 300 | if pkgs.lib.tail values == [] 301 | then pkgs.lib.head values 302 | else if pkgs.lib.all pkgs.lib.isList values 303 | then pkgs.lib.unique (pkgs.lib.concatLists values) 304 | else if pkgs.lib.all pkgs.lib.isAttrs values 305 | then f (attrPath ++ [n]) values 306 | else pkgs.lib.last values); 307 | in 308 | f [] attrList; 309 | 310 | augmentedNeovim = recursiveMerge [ 311 | (pkgs.neovim-unwrapped.overrideAttrs (oldAddrs: { 312 | # This should help compile dependencies with debug symbols 313 | preConfigure = 314 | '' 315 | export DEBUG=1 316 | '' 317 | + oldAddrs.preConfigure; 318 | # Options for built type are: RelWithDebInfo, Release, and Debug 319 | cmakeFlags = ["-DCMAKE_BUILD_TYPE=RelWithDebInfo"]; 320 | })) 321 | {buildInputs = dependencies;} 322 | ]; 323 | extraPythonPkgs = ps: 324 | with ps; [ 325 | debugpy 326 | jupyter 327 | ipython 328 | ipykernel 329 | sentence-transformers 330 | numpy 331 | pip 332 | pandas 333 | scipy 334 | tokenizers 335 | sympy 336 | pyarrow 337 | python-dotenv 338 | pynvim 339 | jupyter-client 340 | cairosvg 341 | pnglatex 342 | plotly 343 | pyperclip 344 | ]; 345 | pythonEnv = pkgs.python310.withPackages extraPythonPkgs; 346 | 347 | augmentedNeovimPython = recursiveMerge [ 348 | (pkgs.neovim-unwrapped.overrideAttrs (oldAddrs: { 349 | # This should help compile dependencies with debug symbols 350 | preConfigure = 351 | '' 352 | export DEBUG=1 353 | '' 354 | + oldAddrs.preConfigure; 355 | # Options for built type are: RelWithDebInfo, Release, and Debug 356 | cmakeFlags = oldAddrs.cmakeFlags ++ ["-DCMAKE_BUILD_TYPE=RelWithDebInfo"]; 357 | })) 358 | { 359 | buildInputs = 360 | dependencies 361 | ++ [ 362 | pythonEnv 363 | pkgs.libffi 364 | pkgs.imagemagick 365 | ]; 366 | } 367 | ]; 368 | in rec { 369 | packages.pwnvim = (pkgs.wrapNeovim pkgs.neovim-unwrapped { 370 | viAlias = true; 371 | vimAlias = true; 372 | withNodeJs = false; 373 | withPython3 = false; 374 | withRuby = false; 375 | extraLuaPackages = ps: [ps.lua-curl]; 376 | extraMakeWrapperArgs = ''--prefix PATH : "${pkgs.lib.makeBinPath dependencies}"''; 377 | # make sure impatient is loaded before everything else to speed things up 378 | configure = { 379 | inherit customRC; 380 | packages.myPlugins = { 381 | start = requiredPlugins; 382 | opt = optionalPlugins; 383 | }; 384 | }; 385 | } 386 | // {buildInputs = dependencies;}) # this last line is needed so neovide can pull in same ones 387 | .overrideAttrs (old: { 388 | name = "pwnvim"; 389 | version = old.version + "-" + self.lastModifiedDate; 390 | }); 391 | packages.pwnvim-python = 392 | (pkgs.wrapNeovim augmentedNeovimPython { 393 | viAlias = false; 394 | vimAlias = false; 395 | withNodeJs = false; 396 | withPython3 = true; 397 | extraLuaPackages = ps: [ps.magick]; 398 | extraPython3Packages = extraPythonPkgs; 399 | # python3Env = pythonEnv; 400 | withRuby = false; 401 | extraMakeWrapperArgs = ''--prefix PATH : "${pkgs.lib.makeBinPath dependencies}"''; 402 | # make sure impatient is loaded before everything else to speed things up 403 | configure = { 404 | customRC = 405 | customRC 406 | + '' 407 | lua << EOF 408 | vim.g.molten_image_provider = "image.nvim" 409 | vim.g.molten_output_win_max_height = 20 410 | vim.g.molten_auto_open_output = false 411 | vim.g.loaded_python3_provider = nil 412 | vim.g.python3_host_prog = "${pythonEnv}/bin/python" 413 | require("image").setup({ 414 | backend = "kitty", 415 | max_width = 100, 416 | max_height = 12, 417 | max_height_window_percentage = math.huge, 418 | max_width_window_percentage = math.huge, 419 | window_overlap_clear_enabled = true, 420 | window_overlap_clear_ft_ignore = { "cmp_menu", "cmp_docs", "" } 421 | }) 422 | EOF 423 | ''; 424 | packages.myPlugins = { 425 | start = 426 | requiredPlugins 427 | ++ (with pkgs.vimPlugins; [ 428 | molten-nvim # jupyter notebook runner inside vim 429 | image-nvim # display images in kitty inside nvim for markdown and jupyter notebooks -- to experiment with 430 | ]); 431 | opt = optionalPlugins; 432 | }; 433 | }; 434 | }) 435 | .overrideAttrs (old: { 436 | name = "pwnvim-python-" + old.version + "-" + self.lastModifiedDate; 437 | }); 438 | apps.pwnvim = flake-utils.lib.mkApp { 439 | drv = 440 | packages.pwnvim; 441 | name = "pwnvim"; 442 | exePath = "/bin/nvim"; 443 | }; 444 | packages.default = packages.pwnvim; 445 | apps.default = apps.pwnvim; 446 | devShell = pkgs.mkShell { 447 | buildInputs = [packages.pwnvim] ++ dependencies; 448 | }; 449 | # apps.pwnvim-python = flake-utils.lib.mkApp { 450 | # drv = 451 | # 452 | # }; 453 | }); 454 | } 455 | -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | -- Neovide needs this defined very early 2 | if vim.fn.has('mac') == 1 then 3 | vim.opt.guifont = "Hasklug Nerd Font:h18" 4 | else 5 | vim.opt.guifont = "Hasklug Nerd Font:h9" 6 | end 7 | vim.g.loaded_matchit = 1 -- disable early 8 | require('impatient') 9 | require('impatient').enable_profile() 10 | require('pwnvim.filetypes').config() 11 | require('pwnvim.options').defaults() 12 | if vim.g.neovide then 13 | require('pwnvim.options').colors_onedark() 14 | else 15 | require('pwnvim.options').colors_cat() 16 | end 17 | require('pwnvim.options').gui() 18 | require('pwnvim.mappings').config() 19 | require('pwnvim.abbreviations') 20 | require('pwnvim.plugins').ui() 21 | require('pwnvim.plugins').diagnostics() 22 | require('pwnvim.plugins').telescope() 23 | require('pwnvim.plugins').completions() 24 | require('pwnvim.plugins').llms() 25 | require('pwnvim.plugins').notes() 26 | require('pwnvim.plugins').misc() 27 | -------------------------------------------------------------------------------- /pwnvim/abbreviations.lua: -------------------------------------------------------------------------------- 1 | vim.cmd([[ 2 | ab jjcheck ✓ 3 | ab Ironcore IronCore 4 | ab Hubspot HubSpot 5 | ab jjheart ♥ 6 | ab jjcomm ⌘ 7 | ab accidant accident 8 | ab accomodate accommodate 9 | ab accross across 10 | ab acheive achieve 11 | ab accomodate accommodate 12 | ab acomodate accommodate 13 | ab andthe and the 14 | ab apparant apparent 15 | ab aquisition acquisition 16 | ab assistent assistant 17 | ab asthe as the 18 | ab atthe at the 19 | ab beutiful beautiful 20 | ab cemetary cemetery 21 | ab changeing changing 22 | ab convertable convertible 23 | ab defendent defendant 24 | ab embarass embarrass 25 | ab equivalant equivalent 26 | ab guage gauge 27 | ab harrass harass 28 | ab hte the 29 | ab teh the 30 | ab judgment judgement 31 | ab liason liaison 32 | ab lieutenent lieutenant 33 | ab performence performance 34 | ab permanant permanent 35 | ab questionaire questionnaire 36 | ab recieve receive 37 | ab relevent relevant 38 | ab rythm rhythm 39 | ab seperate separate 40 | ab shouldnt shouldn't 41 | ab couldnt couldn't 42 | ab supercede supersede 43 | ab taht that 44 | ab threshhold threshold 45 | ab tomorow tomorrow 46 | ab transfered transferred 47 | ab vacume vacuum 48 | ab wierd weird 49 | ab wouldnt wouldn't 50 | ab independant independent 51 | ab independance independence 52 | ab occured occurred 53 | ab occurence occurrence 54 | ab occurance occurrence 55 | ab occurrance occurrence 56 | ab reccomend recommend 57 | ab reccommend recommend 58 | ab monday Monday 59 | ab tuesday Tuesday 60 | ab wednesday Wednesday 61 | ab thursday Thursday 62 | ab friday Friday 63 | ab saturday Saturday 64 | ab sunday Sunday 65 | ]]) 66 | -------------------------------------------------------------------------------- /pwnvim/filetypes.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.config = function() 4 | -- Make detection of zola templates with jinja2-like syntax automatic 5 | -- See :h vim.filetype.add 6 | vim.filetype.add({ 7 | pattern = { 8 | ['.*templates/.*%.html'] = { 9 | function(path, bufnr) 10 | -- vim.notify("executing pat " .. path) 11 | local content = vim.api.nvim_buf_get_lines(bufnr, 0, 1, false)[1] or '' 12 | if vim.regex([[{%]]):match_str(content) ~= nil then 13 | -- vim.notify("detected jinja pat " .. path) 14 | return 'twig' 15 | end 16 | end, 17 | { priority = math.huge }, 18 | }, 19 | }, 20 | }) 21 | local filetypes = vim.api.nvim_create_augroup("filetypes", { clear = true }) 22 | local autocmd = vim.api.nvim_create_autocmd 23 | autocmd("BufRead", { 24 | pattern = { "*.markdown", "*.md" }, 25 | command = "setlocal filetype=markdown", 26 | group = filetypes 27 | }) 28 | autocmd("BufRead", { 29 | pattern = { "*.sbt" }, 30 | command = "setlocal filetype=scala", 31 | group = filetypes 32 | }) 33 | autocmd("BufRead", { 34 | pattern = { "~/mail/*", "/tmp/mutt*", "~/.signature*" }, 35 | command = "setlocal filetype=mail", 36 | group = filetypes 37 | }) 38 | autocmd("BufRead", { 39 | pattern = { "~/.mutt/*" }, 40 | command = "setlocal filetype=muttrc", 41 | group = filetypes 42 | }) 43 | -- autocmd("BufRead", { 44 | -- pattern = { "*.*html*" }, 45 | -- command = "setlocal filetype=html", 46 | -- group = filetypes 47 | -- }) 48 | -- autocmd("BufRead", { 49 | -- pattern = { "*.css*" }, 50 | -- command = "setlocal filetype=css", 51 | -- group = filetypes 52 | -- }) 53 | autocmd("BufRead", { 54 | pattern = { "*.rss" }, 55 | command = "setlocal filetype=xml", 56 | group = filetypes 57 | }) 58 | autocmd("BufRead", { 59 | pattern = { "flake.lock" }, 60 | command = "setlocal filetype=json", 61 | group = filetypes 62 | }) 63 | 64 | -- autocmd("FileType", { 65 | -- pattern = {"sql", "mysql", "plsql"}, 66 | -- callback = function() 67 | -- require('cmp').setup.buffer({ 68 | -- enabled = true, 69 | -- sources = {{name = 'vim-dadbod-completion'}} 70 | -- }) 71 | -- end, 72 | -- group = filetypes 73 | -- }) 74 | autocmd("FileType", { 75 | pattern = { 76 | "c", "ruby", "php", "php3", "perl", "python", "mason", "vim", "sh", "zsh", 77 | "scala", "javascript", "javascriptreact", "typescript", "typescriptreact", 78 | "html", "svelte", "css", "nix", "toml", "svelte", "toml", "yaml" 79 | }, 80 | callback = require('pwnvim.options').programming, 81 | group = filetypes 82 | }) 83 | autocmd("FileType", { 84 | pattern = { "python" }, 85 | callback = function() require("dap-python").setup("python3") end, 86 | group = filetypes 87 | }) 88 | autocmd("FileType", { 89 | pattern = { "gitcommit" }, -- markdown, but we don't want most markdown things setup, just our shortcuts 90 | callback = function(ev) 91 | local bufnr = ev.buf 92 | require('pwnvim.markdown').setupmappings(bufnr) 93 | end, 94 | group = filetypes 95 | 96 | }) 97 | autocmd("FileType", { 98 | pattern = { "oil" }, 99 | command = "syntax enable", -- fix issue where IDs weren't always hidden, particularly if no programming files had been opened previously 100 | group = filetypes, 101 | }) 102 | autocmd("FileType", { 103 | pattern = { "lua", "xml" }, 104 | callback = require('pwnvim.filetypes').lua, 105 | group = filetypes 106 | }) 107 | autocmd("FileType", { 108 | pattern = { "fugitive" }, 109 | command = "syntax on", 110 | group = filetypes 111 | }) 112 | autocmd("FileType", { 113 | pattern = { "md", "markdown", "vimwiki" }, 114 | callback = require('pwnvim.markdown').setup, 115 | group = filetypes 116 | }) 117 | autocmd("FileType", { 118 | pattern = { "rust" }, 119 | callback = require('pwnvim.filetypes').rust, 120 | group = filetypes 121 | }) 122 | autocmd("FileType", { 123 | pattern = { "Outline" }, 124 | command = "setlocal nospell", 125 | group = filetypes 126 | }) 127 | 128 | autocmd("TermOpen", 129 | { pattern = { "*" }, command = "setlocal nospell", group = filetypes }) 130 | -- Run when page pager is invoked 131 | autocmd('User', { 132 | pattern = { 'PageOpen', 'PageOpenFile' }, 133 | group = filetypes, 134 | callback = require('pwnvim.filetypes').page 135 | }) 136 | end 137 | 138 | M.rust = function(ev) 139 | require('pwnvim.options').programming(ev) 140 | require('pwnvim.options').fourspaceindent() 141 | vim.cmd("compiler cargo") 142 | vim.bo.makeprg = "cargo --color never $*" 143 | vim.bo.errorformat = [[%Eerror: %\%%(aborting %\|could not compile%\)%\@!%m,]] 144 | .. [[%Eerror[E%n]: %m,]] 145 | .. [[%Inote: %m,]] 146 | .. [[%Wwarning: %\%%(%.%# warning%\)%\@!%m,]] 147 | .. [[%C %#--> %f:%l:%c,]] 148 | .. [[%E left:%m,%C right:%m %f:%l:%c,%Z,]] 149 | .. [[%.%#panicked at \'%m\'\, %f:%l:%c]] 150 | local bufnr = ev.buf 151 | local mapnviclocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapnvic) 152 | mapnviclocal("", "make build", "Build rust program") 153 | 154 | 155 | vim.cmd("syntax on") 156 | vim.g.rustfmt_autosave = 1 157 | vim.g.rust_fold = 1 158 | vim.api.nvim_exec2([[ 159 | augroup rustquickfix 160 | autocmd! 161 | autocmd BufReadPost quickfix setlocal foldmethod=expr 162 | autocmd BufReadPost quickfix setlocal foldexpr=getline(v:lnum)[0:1]=='\|\|' 163 | autocmd BufEnter quickfix setlocal foldexpr=getline(v:lnum)[0:1]=='\|\|' 164 | autocmd BufReadPost quickfix setlocal foldlevel=0 165 | augroup END 166 | ]], { output = false }) 167 | end 168 | 169 | M.c = function(ev) 170 | require('pwnvim.options').programming(ev) 171 | require('pwnvim.options').fourspaceindent() 172 | vim.bo.makeprg = "make" 173 | end 174 | 175 | M.lua = function(ev) 176 | require('pwnvim.options').programming(ev) 177 | require('pwnvim.options').twospaceindent() 178 | end 179 | 180 | M.page = function() 181 | -- disable status bar -- handled in config 182 | -- map space to ctrl-f 183 | vim.api.nvim_buf_set_keymap(0, 'n', '', '', {}) 184 | end 185 | 186 | M.reloadFile = function() 187 | require("plenary.reload").reload_module '%' 188 | vim.cmd("luafile %") 189 | end 190 | 191 | return M 192 | -------------------------------------------------------------------------------- /pwnvim/mappings.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local startswith = function(haystack, prefix) 4 | return string.sub(string.lower(haystack), 1, #prefix) == string.lower(prefix) 5 | end 6 | 7 | local addcommand = function(rhs) 8 | -- the string.sub trick avoids searching the entire string to figure out startswith; see https://programming-idioms.org/idiom/96/check-string-prefix/1882/lua 9 | -- purpose here is to add the "" prefix and "" as best practice, but only if "" wasn't already provided 10 | if type(rhs) == "string" and not startswith(rhs, "") and not startswith(rhs, ":") and not startswith(rhs, "") then 11 | rhs = ("%s"):format(rhs) 12 | end 13 | return rhs 14 | end 15 | M.map = function(mode, lhs, rhs, desc, opts) 16 | opts = opts or { silent = true, noremap = true } 17 | opts["desc"] = desc or "" 18 | vim.keymap.set( 19 | mode or "n", -- can also be a map like {"n", "c"} 20 | lhs, -- key to bind 21 | rhs, -- string or function 22 | opts 23 | ) 24 | end 25 | M.mapn = function(lhs, rhs, desc, opts) 26 | M.map("n", lhs, addcommand(rhs), desc, opts) 27 | end 28 | M.mapv = function(lhs, rhs, desc, opts) 29 | M.map("v", lhs, addcommand(rhs), desc, opts) 30 | end 31 | M.mapnv = function(lhs, rhs, desc, opts) 32 | M.map({ "n", "v" }, lhs, addcommand(rhs), desc, opts) 33 | end 34 | M.mapic = function(lhs, rhs, desc, opts) 35 | -- in insert/command mode, don't assume as we might be using keystrokes in insert mode on purpose 36 | M.map({ "i", "c" }, lhs, rhs, desc, opts) 37 | end 38 | M.mapnvic = function(lhs, rhs, desc, opts) 39 | M.map({ "n", "v", "i", "c" }, lhs, addcommand(rhs), desc, opts) 40 | end 41 | M.mapnvict = function(lhs, rhs, desc, opts) 42 | M.map({ "n", "v", "i", "c", "t" }, lhs, addcommand(rhs), desc, opts) 43 | end 44 | M.mapi = function(lhs, rhs, desc, opts) 45 | -- in insert mode, don't assume as we might be using keystrokes in insert mode on purpose 46 | M.map("i", lhs, rhs, desc, opts) 47 | end 48 | M.mapox = function(lhs, rhs, desc, opts) 49 | -- in operator pending mode, don't assume as we might be using keystrokes in insert mode on purpose 50 | M.map({ "o", "x" }, lhs, rhs, desc, opts) 51 | end 52 | M.mapt = function(lhs, rhs, desc, opts) 53 | M.map("t", lhs, addcommand(rhs), desc, opts) 54 | end 55 | M.mapleadern = function(lhs, rhs, desc, opts) 56 | M.mapn("" .. lhs, rhs, desc, opts) 57 | end 58 | M.mapleaderv = function(lhs, rhs, desc, opts) 59 | M.mapv("" .. lhs, rhs, desc, opts) 60 | end 61 | M.mapleadernv = function(lhs, rhs, desc, opts) 62 | M.mapnv("" .. lhs, rhs, desc, opts) 63 | end 64 | 65 | M.makelocalmap = function(bufnr, mapfunc) 66 | return function(lhs, rhs, desc, opts) 67 | opts = opts or { silent = true, noremap = true } 68 | opts["buffer"] = bufnr 69 | mapfunc(lhs, rhs, desc, opts) 70 | end 71 | end 72 | 73 | M.config = function() 74 | -- We use which-key in mappings, which is loaded before plugins, so set up here 75 | local which_key = require("which-key") 76 | local enter = vim.api.nvim_replace_termcodes("", true, false, true) 77 | 78 | 79 | which_key.setup({ 80 | notify = false, -- don't warn me about overlapping keys, which are at least sometimes intentional 81 | plugins = { 82 | marks = true, -- shows a list of your marks on ' and ` 83 | registers = true, -- shows your registers on " in NORMAL or in INSERT mode 84 | spelling = { 85 | enabled = true, -- enabling this will show WhichKey when pressing z= to select spelling suggestions 86 | suggestions = 20 -- how many suggestions should be shown in the list? 87 | }, 88 | -- the presets plugin, adds help for a bunch of default keybindings in Neovim 89 | -- No actual key bindings are created 90 | presets = { 91 | operators = false, -- adds help for operators like d, y, ... and registers them for motion / text object completion 92 | motions = false, -- adds help for motions 93 | text_objects = true, -- help for text objects triggered after entering an operator 94 | windows = true, -- default bindings on 95 | nav = true, -- misc bindings to work with windows 96 | z = true, -- bindings for folds, spelling and others prefixed with z 97 | g = true -- bindings for prefixed with g 98 | } 99 | }, 100 | -- hidden = { 101 | -- "", "", "", "", "", "", "call", "lua", "^:", 102 | -- "^ " 103 | -- }, -- hide mapping boilerplate 104 | show_help = true, -- show help message on the command line when the popup is visible 105 | triggers = { 106 | { "", mode = "nixsotc" }, -- automatically setup triggers 107 | }, 108 | -- triggers = {""} 109 | -- triggers_nowait = {"'", '"', "y", "d"} 110 | }) 111 | 112 | which_key.add({ 113 | mode = { "n", "v" }, 114 | { "]", group = "next" }, 115 | { "[", group = "prev" }, 116 | { "d", group = "debug" }, 117 | { "f", group = "find" }, 118 | { "q", group = "trouble" }, 119 | { "g", group = "git" }, 120 | { "gt", group = "git toggle" }, 121 | { "gw", group = "git workspace" }, 122 | { "h", group = "hunk" }, 123 | { "i", group = "indent" }, 124 | { "l", group = "lsp" }, 125 | { "ls", group = "symbols" }, 126 | { "lc", group = "change" }, 127 | { "n", group = "notes" }, 128 | { "t", group = "tasks" }, 129 | { "cc", group = "codecompanion ai" }, 130 | }) 131 | 132 | -- This file is for mappings that will work regardless of filetype. Always available. 133 | 134 | -- ALL MODE (EXCEPT OPERATOR) MAPPINGS 135 | -- Make F1 act like escape for accidental hits 136 | M.map({ "n", "v", "i", "c" }, "", "", "Escape") 137 | -- Make F2 bring up a file browser 138 | M.mapnvic("", "Oil .", "Toggle file browser") 139 | -- Use F3 for a quick grep with Trouble to show results 140 | M.mapnvic("", function() 141 | vim.ui.input({ prompt = "Regex: " }, function(needle) 142 | if needle then 143 | vim.cmd(table.concat({ "lgrep -i ", '"', needle, '"' })) 144 | require("trouble").toggle({ mode = "loclist", position = "bottom" }) 145 | end 146 | end) 147 | end) 148 | -- Make F4 toggle invisible characters (locally) 149 | M.mapnvic("", function() 150 | if vim.opt_local.list:get() then 151 | vim.opt_local.list = false 152 | vim.opt_local.conceallevel = 2 153 | vim.cmd("IBLEnable") 154 | else 155 | vim.opt_local.list = true 156 | vim.opt_local.conceallevel = 0 157 | vim.cmd("IBLDisable") -- indent lines hide some chars like tab 158 | end 159 | end, "Toggle show invisible chars") 160 | -- Make ctrl-p open a file finder 161 | -- When using ctrl-p, screen out media files that we probably don't want 162 | -- to open in vim. And if we really want, then we can use ,ff 163 | M.mapnv("", require("telescope.builtin").find_files, "Find files") 164 | M.mapnvic("", "TZAtaraxis", "Focus mode") 165 | -- Make F10 quicklook. Not sure how to do this best in linux so mac only for now 166 | M.mapnvic("", 'silent !qlmanage -p "%"', "Quicklook (mac)") 167 | M.mapnvic("", 'syntax sync fromstart', "Restart highlighting") 168 | -- Pane navigation integrated with tmux 169 | M.mapnvic("", "TmuxNavigateLeft", "Pane left") 170 | M.mapnvic("", "TmuxNavigateDown", "Pane down") 171 | M.mapnvic("", "TmuxNavigateUp", "Pane up") 172 | M.mapnvic("", "TmuxNavigateRight", "Pane right") 173 | M.mapnvic("", "Bdelete", "Close buffer") 174 | M.mapnvic("", "Bdelete", "Close buffer") 175 | M.mapnvic("", "Bdelete", "Close buffer") 176 | M.mapnvic("", "enew", "New buffer") 177 | M.mapnvic("", "tabnew", "New tab") 178 | M.mapnvic("", "write", "Save buffer") 179 | M.mapnvic("", "quit", "Quit") 180 | -- Magic buffer-picking mode 181 | -- M.mapnvic("", "BufferLinePick", "Pick buffer by letter") 182 | 183 | -- Copy and paste ops mainly for neovide / gui apps 184 | if require("pwnvim.options").isGuiRunning() then 185 | M.mapn("", 'normal "+p', "Paste") 186 | M.mapv("", 'normal "+ygv', "Copy") 187 | M.mapv("", 'normal "+p', "Paste") 188 | M.mapic("", '+', "Paste", { noremap = true, silent = false }) 189 | M.map("t", "", '"+pa', "Paste") 190 | 191 | -- Adjust font sizes 192 | local function get_font() 193 | local guifont = vim.api.nvim_get_option("guifont") 194 | local curr_font = {} 195 | curr_font.name = guifont:match("^(.*)%:") 196 | curr_font.size = tonumber(guifont:match("%:h(%d+)")) 197 | return curr_font 198 | end 199 | local function change_font(name, size) 200 | vim.opt.guifont = name .. ":h" .. size 201 | end 202 | local function increase_font() 203 | local curr_font = get_font() 204 | local new_size = tostring(curr_font.size + 1) 205 | change_font(curr_font.name, new_size) 206 | end 207 | local function decrease_font() 208 | local curr_font = get_font() 209 | local new_size = tostring(curr_font.size - 1) 210 | change_font(curr_font.name, new_size) 211 | end 212 | local function reset_font() 213 | local curr_font = get_font() 214 | local new_size = require("pwnvim.options").defaultFontSize() 215 | change_font(curr_font.name, new_size) 216 | end 217 | local function increase_nvscale() 218 | vim.g.neovide_scale_factor = vim.g.neovide_scale_factor * 1.1 219 | end 220 | local function decrease_nvscale() 221 | vim.g.neovide_scale_factor = vim.g.neovide_scale_factor * 0.9 222 | end 223 | local function reset_nvscale() 224 | vim.g.neovide_scale_factor = 1.0 225 | end 226 | if vim.g.neovide then 227 | M.mapnvic("", increase_nvscale, "Increase font size") 228 | M.mapnvic("", decrease_nvscale, "Decrease font size") 229 | M.mapnvic("", reset_nvscale, "Reset font size") 230 | M.mapnvic("", increase_nvscale, "Increase font size") 231 | M.mapnvic("", decrease_nvscale, "Decrease font size") 232 | M.mapnvic("", reset_nvscale, "Reset font size") 233 | else 234 | M.mapnvic("", increase_font, "Increase font size") 235 | M.mapnvic("", decrease_font, "Decrease font size") 236 | M.mapnvic("", reset_font, "Reset font size") 237 | M.mapnvic("", increase_font, "Increase font size") 238 | M.mapnvic("", decrease_font, "Decrease font size") 239 | M.mapnvic("", reset_font, "Reset font size") 240 | end 241 | end 242 | 243 | -- NORMAL MODE ONLY MAPPINGS 244 | M.map("n", "", "[e", "Move line up") 245 | M.map("n", "", "]e", "Move line down") 246 | M.mapn("zi", function() -- override default fold toggle behavior to fix fold columns and scan 247 | if vim.wo.foldenable then 248 | -- Disable completely 249 | vim.wo.foldenable = false 250 | vim.wo.foldmethod = 251 | "manual" -- seeing weird things where folds are off, but expression being run anyway. this should fix. 252 | vim.wo.foldcolumn = "0" 253 | else 254 | vim.wo.foldenable = true 255 | -- TODO: maybe save this value above and set back to last value? 256 | vim.wo.foldmethod = "expr" 257 | vim.wo.foldcolumn = "auto:4" 258 | vim.cmd("normal zx") -- reset folds 259 | end 260 | end, "Toggle folding" 261 | ) 262 | M.map("n", "", '"=strftime("%Y-%m-%d")P', "Insert date") 263 | M.mapic("", '=strftime("%Y-%m-%d")', "Insert date at cursor", { noremap = true, silent = false }) 264 | M.map("n", "", "<<", "Outdent") 265 | M.map("n", "", ">>", "Indent") 266 | M.map("n", "n", "nzzzv", "Center search hits vertically on screen and expand folds if hit is inside") 267 | M.map("n", "N", "Nzzzv", "Center search hits vertically on screen and expand folds if hit is inside") 268 | M.map("n", "", "zz", "Half scroll down keep cursor center screen") 269 | M.map("n", "", "zz", "Half scroll up keep cursor center screen") 270 | -- gx is a built-in to open URLs under the cursor, but when 271 | -- not using netrw, it doesn't work right. Or maybe it's just me 272 | -- but anyway this command works great. 273 | -- /Users/pwalsh/Documents/md2rtf-style.html 274 | -- ../README.md 275 | -- ~/Desktop/Screen Shot 2018-04-06 at 5.19.32 PM.png 276 | -- [abc](https://github.com/adsr/mle/commit/e4dc4314b02a324701d9ae9873461d34cce041e5.patch) 277 | -- M.mapn("gx", ':silent !open "" || xdg-open ""', "Launch URL or path") 278 | M.mapn("*", 279 | function() 280 | local text = "\\<" .. string.gsub(vim.fn.expand(""), "/", "\\/") .. 281 | "\\>" 282 | -- Can't find a way to have flash jump keep going past what's visible on the screen 283 | vim.api.nvim_feedkeys("/\\V" .. text .. enter, 'n', false) 284 | end, "Find word under cursor forward" 285 | ) 286 | M.mapn("#", 287 | function() 288 | local text = "\\<" .. string.gsub(vim.fn.expand(""), "?", "\\?") .. 289 | "\\>" 290 | vim.api.nvim_feedkeys("?\\V" .. text .. enter, 'n', false) 291 | end, "Find word under cursor backward" 292 | ) 293 | M.mapn("g*", 294 | function() 295 | -- Same as above, but don't qualify as full word only 296 | local text = string.gsub(vim.fn.expand(""), "/", "\\/") 297 | vim.api.nvim_feedkeys("/\\V" .. text .. enter, 'n', false) 298 | end, "Find partial word under cursor forward" 299 | ) 300 | M.mapn("g#", 301 | function() 302 | -- Same as above, but don't qualify as full word only 303 | local text = string.gsub(vim.fn.expand(""), "?", "\\?") 304 | vim.api.nvim_feedkeys("?" .. text .. enter, 'n', false) 305 | -- vim.cmd("?\\V" .. text) -- works, but doesn't trigger flash 306 | end, "Find partial word under cursor backward" 307 | ) 308 | M.map("n", "", [[@=(foldlevel('.')?'za':"\")]], "Toggle folds if enabled") 309 | 310 | 311 | M.mapn("p", 'normal "*p', "Paste") 312 | -- M.mapn("[0", "BufferLinePick", "Pick buffer by letter") 313 | -- M.mapn("]0", "BufferLinePick", "Pick buffer by letter") 314 | 315 | -- M.map("v", "gx", '"0y:silent !open "0" || xdg-open "0"gv', "Launch selected URL or path") 316 | -- When pasting over selected text, keep original register value 317 | M.map("v", "p", '"_dP', "Paste over selected no store register") 318 | -- keep visual block so you can move things repeatedly 319 | M.map("v", "<", "", ">gv", "Indent and preserve block") 321 | M.mapi("", "", "Outdent") 322 | M.mapi("", "", "Indent") 323 | M.map("v", "", "", ">gv", "Indent and preserve block") 325 | M.map("v", "", "[egv", "Move line up preserve block") 326 | M.map("v", "", "]egv", "Move line down preserve block") 327 | 328 | -- emacs bindings to jump around in lines 329 | M.mapi("", "A", "Jump to end of line") 330 | M.mapi("", "I", "Jump to start of line") 331 | 332 | -- Send cursor somewhere on screen and pick a text object from it. 333 | -- Uses operator pending mode so you start it with something like `yr` then 334 | -- after jump pick the text object like `iw` and you'll copy that other thing 335 | -- and be back where you were at the start. 336 | M.map("o", "R", require("flash").remote, "Remote operation via Flash") 337 | M.map("o", "", require("flash").jump, "Flash select") 338 | M.map("o", "r", require("flash").treesitter, "Flash select") 339 | -- 340 | -- Move visually selected lines up and down 341 | -- vim.keymap.set("v", "J", ":m '>+1gv=gv") 342 | -- vim.keymap.set("v", "K", ":m '<-2gv=gv") 343 | 344 | M.mapleadernv("e", "Oil", "Find current file in file browser") 345 | M.mapleadernv("/", "nohlsearch", "Clear highlight") 346 | M.mapleadernv("x", "Bdelete!", "Close buffer") 347 | 348 | -- Trouble windows 349 | M.mapleadernv("qq", "Trouble qflist toggle", "Quicklist (Trouble)") 350 | M.mapleadernv("ql", "Trouble loclist toggle", "Location list (Trouble)") 351 | M.mapleadernv("qd", "Trouble diagnostics toggle", "Diagnostics (Trouble)") 352 | M.mapleadernv("qe", "Trouble diagnostics toggle filter.buf=0", "Buffer Diagnostics (Trouble)") 353 | M.mapleadernv("qs", "Trouble symbols toggle focus=false", "Symbols (Trouble)") 354 | M.mapleadernv("qs", "Trouble lsp toggle focus=false win.position=right", "LSP Defs/Refs/... (Trouble)") 355 | 356 | -- Find group 357 | M.mapleadernv("fb", 358 | function() require('telescope.builtin').buffers(require('telescope.themes').get_dropdown { previewer = false }) end, 359 | "Buffers") 360 | M.mapleadernv("fc", function() require('telescope.builtin').live_grep({ search_dirs = { vim.fn.expand('%:p:h') } }) end, 361 | "Grep from dir of current file") 362 | M.mapleadernv("fd", require('telescope.builtin').lsp_document_symbols, "Document symbols search") 363 | M.mapleadernv("ff", require('telescope.builtin').find_files, "Files") 364 | 365 | M.mapleadernv("fg", require('telescope.builtin').live_grep, "Grep") 366 | M.mapleadernv("fh", function() 367 | require('telescope.builtin').oldfiles { only_cwd = true } 368 | end, "History local") 369 | M.mapleadernv("fk", require('telescope.builtin').keymaps, "Keymaps") 370 | M.mapleadernv("fl", require('telescope.builtin').loclist, "Loclist") 371 | M.mapleadernv("fn", function() require('zk.commands').get("ZkNotes")({ sort = { 'modified' } }) end, "Find notes") 372 | M.mapleadernv("fo", require('telescope.builtin').oldfiles, "Old file history global") 373 | M.mapleadernv("fp", require("telescope").extensions.projects.projects, "Projects") 374 | M.mapleadernv("fq", require('telescope.builtin').quickfix, "Quickfix") 375 | -- ,fs mapping done inside lsp attach functions 376 | M.mapleadernv("ft", 377 | 'lua require(\'telescope.builtin\').grep_string{search = "^\\\\s*[*-] \\\\[ \\\\]", previewer = false, glob_pattern = "*.md", use_regex = true, disable_coordinates=true}', 378 | "Todos") 379 | M.mapleadernv("fz", function() 380 | require("pwnvim.plugins").telescope_get_folder_common_folders({ 381 | ".config", "src/sideprojects", "src/icl", "src/icl/website.worktree", "src/personal", "src/gh", 382 | "Sync/Private", "Sync/Private/Finances", "Sync/IronCore Docs", "Sync/IronCore Docs/Legal", 383 | "Sync/IronCore Docs/Finances", "Sync/IronCore Docs/Design", 384 | "Notes", "Notes/Notes", "Notes/Notes/meetings" 385 | }, 1, function(folder) 386 | vim.cmd.lcd(folder) 387 | require("oil").open(folder) -- if we bail on picking a file, we have the file browser as fallback 388 | require("telescope.builtin").find_files() 389 | end) 390 | end, "Open folder") 391 | 392 | -- Quickly change indent defaults in a file 393 | M.mapleadernv("i1", require('pwnvim.options').tabindent, "Tab") 394 | M.mapleadernv("i2", require('pwnvim.options').twospaceindent, "Two Space") 395 | M.mapleadernv("i4", require('pwnvim.options').fourspaceindent, "Four Space") 396 | M.mapleadernv("ir", "%retab!", "Change existing indent to current with retab") 397 | 398 | -- Git bindings 399 | -- Browse git things 400 | M.mapleadernv("gs", require('telescope.builtin').git_status, "Status") 401 | M.mapleadernv("gb", require('telescope.builtin').git_branches, "Branches") 402 | M.mapleadernv("gm", require('telescope.builtin').git_commits, "Commits") 403 | -- Worktree stuff 404 | M.mapleadernv("gws", require('telescope').extensions.git_worktree.git_worktree, "Switch worktree") 405 | M.mapleadernv("gwn", require('telescope').extensions.git_worktree.create_git_worktree, "New worktree") 406 | -- Bunch more will be mapped locally with gitsigns when it loads. See ./gitsigns.lua 407 | 408 | -- Codecompanion bindings 409 | M.mapleadernv("ccl", "CodeCompanion", "AI Inline") 410 | M.mapi("", "CodeCompanion", "AI Inline") 411 | M.mapleadernv("ccc", "CodeCompanionChat Toggle", "AI Chat") 412 | M.mapleadernv("cca", "CodeCompanionActions", "AI Actions") 413 | M.mapleaderv("cce", function() require("codecompanion").prompt("explain") end, "AI Explain") 414 | M.mapleaderv("ccs", function() require("codecompanion").prompt("summarize") end, "AI Summarize") 415 | M.mapleaderv("cct", function() require("codecompanion").prompt("tests") end, "AI Generate Unit Tests") 416 | M.mapleaderv("ccf", function() require("codecompanion").prompt("fix") end, "AI Fix Code") 417 | M.mapleadernv("ccd", function() require("codecompanion").prompt("lsp") end, "AI Explain Diagnostics") 418 | M.mapleadernv("ccg", function() require("codecompanion").prompt("commit") end, "AI Gen Commit Message From Diff") 419 | M.mapleadernv("ccm", 420 | function() 421 | vim.ui.select({ "ollamacode", "ollamaprose", "copilot", "openai" }, { prompt = 'Pick a service:' }, 422 | function(choice) vim.g.codecompanion_adapter = choice end) 423 | end, "Choose an AI service") 424 | 425 | -- M.mapv("ga", "CodeCompanionChat Add", "AI add code block") 426 | 427 | -- Set cwd to current file's dir 428 | M.mapleadernv("lcd", "lcd %:h", "Change local dir to path of current file") 429 | M.mapleadernv("cd", "cd %:h", "Change global dir to path of current file") 430 | 431 | -- note shortcuts 432 | M.mapleadernv("nd", require("pwnvim.markdown").newDailyNote, "New diary") 433 | M.mapleadern("ne", '!mv "" "=expand(\'%:p:h\')/"', "Embed file moving to current file's folder") 434 | M.mapleaderv("ne", 'normal "0y:!mv "0" "=expand(\'%:p:h\')/"', 435 | "Embed file moving to current file's folder") 436 | M.mapleadern("nf", "ZkNotes { sort = { 'modified' }}", "Find") 437 | M.map({ "v" }, "nf", ":'<,'>ZkMatch", "Find Selected") 438 | 439 | M.mapleadernv("ng", require('pwnvim.plugins').grammar_check, "Check Grammar") 440 | M.mapleadernv("nh", "edit ~/Notes/Notes/HotSheet.md", "Open HotSheet") 441 | M.mapleadernv("nm", require("pwnvim.markdown").newMeetingNote, "New meeting") 442 | M.mapleadernv("nn", require("pwnvim.markdown").newGeneralNote, "New") 443 | M.mapleadernv("nt", "ZkTags", "Open by tag") 444 | 445 | -- note insert shortcuts 446 | M.mapleadernv("nic", 447 | "r!/opt/homebrew/bin/icalBuddy --bullet '* ' --timeFormat '\\%H:\\%M' --dateFormat '' --noPropNames --noCalendarNames --excludeAllDayEvents --includeCals 'IC - Work' --includeEventProps datetime,title,attendees,location --propertyOrder datetime,title,attendees,location --propertySeparators '| |\\n * |\\n * | |' eventsToday", 448 | "Insert today's calendar") 449 | M.mapleadernv("nio", "r!gtm-okr goals", "Insert OKRs") 450 | M.mapleadernv("nij", 451 | "r!( (curl -s https://icanhazdadjoke.com/ | grep '\\\"subtitle\\\"') || curl -s https://icanhazdadjoke.com/ ) | sed 's/<[^>]*>//g' | sed -z 's/\\n/ /'", 452 | "Insert joke") 453 | -- in open note (defined in plugins.lua as local-only shortcuts) via LSPs: 454 | -- ,np: new peer note 455 | -- ,nl: show outbound links 456 | -- ,nr: show outbound links 457 | -- ,ni: info preview 458 | 459 | M.mapleadern("sd", [[echo map(synstack(line('.'), col('.')), 'synIDattr(v:val, "name")')]], "Debug syntax files") 460 | 461 | M.mapn("", "normal gj", "Down screen line") 462 | M.mapn("", "normal gk", "Up screen line") 463 | M.mapn("", "normal g$", "End of screen line") 464 | M.mapn("", "normal g^", "Beginning of screen line") 465 | -- Visually select the text that was last edited/pasted 466 | -- Similar to gv but works after paste 467 | M.map({ "n" }, "gV", "`[v`]", "Visually select the text last edited (after paste)") 468 | M.map({ "n" }, "Y", "y$", "Yank to end of line") 469 | M.mapnv("-", "Oil", "Find current file in file browser") 470 | M.mapnv("_", "Oil .", "File browser from project root") 471 | M.mapleadernv("-", require("yazi").yazi, "Open Yazi") 472 | 473 | -- TODO Have ctrl-l continue to do what it did, but also temp clear search match highlighting 474 | 475 | -- Make nvim terminal more sane 476 | -- Big change! Switching the escape/alt-escape meanings 2025-01-01 477 | M.map({ "t" }, "", [[]], "Get to normal mode in terminal") 478 | --M.map({ "t" }, "", "", "Send escape to terminal") 479 | -- M.map({ "t" }, "", "", "Send escape to terminal") 480 | M.map({ "t" }, "", [[]], "Get to normal mode in terminal") 481 | M.mapt("", "wincmd j", "Move one window down") 482 | M.mapt("", "wincmd h", "Move one window left") 483 | M.mapt("", "wincmd k", "Move one window up") 484 | M.mapt("", "wincmd l", "Move one window right") 485 | M.map("t", "", "", "Send c-j to terminal") 486 | M.map("t", "", "", "Send c-h to terminal") 487 | M.map("t", "", "", "Send c-k to terminal") 488 | M.map("t", "", "", "Send c-l to terminal") 489 | 490 | 491 | -- Setup tpope unimpaired-like forward/backward shortcuts reminders 492 | which_key.add({ 493 | { "[A", desc = "First file arg" }, 494 | { "[a", desc = "Prev file arg" }, 495 | { "]a", desc = "Next file arg" }, 496 | { "]A", desc = "Last file arg" }, 497 | { "[B", desc = "First buffer" }, 498 | { "]B", desc = "Last buffer" }, 499 | { "[b", "bprev", desc = "Prev buffer" }, 500 | { "]b", "bnext", desc = "Next buffer" }, 501 | -- ["[b"] = { "BufferLineCyclePrev", "Prev buffer" }, 502 | -- ["]b"] = { "BufferLineCycleNext", "Next buffer" }, 503 | { "[c", desc = "Prev git hunk" }, 504 | { "]c", desc = "Next git hunk" }, 505 | { "[f", desc = "Prev file in dir of cur file" }, 506 | { "]f", desc = "Next file in dir of cur file" }, 507 | { "[L", desc = "First loclist item" }, 508 | { "[l", desc = "Prev loclist item" }, 509 | { "]l", desc = "Next loclist item" }, 510 | { "]L", desc = "Last loclist item" }, 511 | { "[Q", desc = "First quicklist item" }, 512 | { "[q", desc = "Prev quicklist item" }, 513 | { "]q", desc = "Next quicklist item" }, 514 | { "]Q", desc = "Last quicklist item" }, 515 | { "]p", desc = "Put below" }, 516 | { "]P", desc = "Put below" }, 517 | { "[t", "tabprevious", desc = "Prev tab" }, 518 | { "[T", "tabfirst", desc = "First tab" }, 519 | { "]t", "tabnext", desc = "Next tab" }, 520 | { "]T", "tablast", desc = "Last tab" }, 521 | { "[n", desc = "Prev conflict" }, 522 | { "]n", desc = "Next conflict" }, 523 | { "[ ", desc = "Add blank line before" }, 524 | { "] ", desc = "Add blank line after" }, 525 | { "[e", desc = "Swap line with previous" }, 526 | { "]e", desc = "Swap line with next" }, 527 | { "[x", desc = "XML encode" }, 528 | { "]x", desc = "XML decode" }, 529 | { "[u", desc = "URL encode" }, 530 | { "]u", desc = "URL decode" }, 531 | { "[y", desc = "C escape" }, 532 | { "]y", desc = "C unescape" }, 533 | { "[d", vim.diagnostic.goto_prev, desc = "Prev diagnostic" }, 534 | { "]d", vim.diagnostic.goto_next, desc = "Next diagnostic" }, 535 | -- ["[1"] = { "BufferLineGoToBuffer 1", "Go to buffer 1" }, 536 | -- ["]1"] = { "BufferLineGoToBuffer 1", "Go to buffer 1" }, 537 | -- ["[2"] = { "BufferLineGoToBuffer 2", "Go to buffer 2" }, 538 | -- ["]2"] = { "BufferLineGoToBuffer 2", "Go to buffer 2" }, 539 | -- ["[3"] = { "BufferLineGoToBuffer 3", "Go to buffer 3" }, 540 | -- ["]3"] = { "BufferLineGoToBuffer 3", "Go to buffer 3" }, 541 | -- ["[4"] = { "BufferLineGoToBuffer 4", "Go to buffer 4" }, 542 | -- ["]4"] = { "BufferLineGoToBuffer 4", "Go to buffer 4" }, 543 | -- ["[5"] = { "BufferLineGoToBuffer 5", "Go to buffer 5" }, 544 | -- ["]5"] = { "BufferLineGoToBuffer 5", "Go to buffer 5" }, 545 | -- ["[6"] = { "BufferLineGoToBuffer 6", "Go to buffer 6" }, 546 | -- ["]6"] = { "BufferLineGoToBuffer 6", "Go to buffer 6" }, 547 | -- ["[7"] = { "BufferLineGoToBuffer 7", "Go to buffer 7" }, 548 | -- ["]7"] = { "BufferLineGoToBuffer 7", "Go to buffer 7" }, 549 | -- ["[8"] = { "BufferLineGoToBuffer 8", "Go to buffer 8" }, 550 | -- ["]8"] = { "BufferLineGoToBuffer 8", "Go to buffer 8" }, 551 | -- ["[9"] = { "BufferLineGoToBuffer 9", "Go to buffer 9" }, 552 | -- ["]9"] = { "BufferLineGoToBuffer 9", "Go to buffer 9" }, 553 | { "", "bn", desc = "Go to next buffer" }, 554 | { "", "bp", desc = "Go to prev buffer" }, 555 | -- [""] = { "BufferLineCyclePrev", "Go to next buffer" }, 556 | -- [""] = { "BufferLineCycleNext", "Go to prev buffer" }, 557 | }, { mode = "n", silent = true }) 558 | 559 | 560 | -- Flash mappings 561 | -- Note: the regular mappings mess up surround plugin and various modes 562 | -- Flash automatically enhances search (with / or ?) and char search (f, F, t, T) 563 | 564 | -- ctrl-s will toggle that enhancement for search when in the midst of searching 565 | which_key.add({ 566 | { "", require("flash").toggle, desc = "Toggle Flash Search" } 567 | }, { mode = "c" }) 568 | 569 | -- Start visual mode and then adjust selection by treesitter nodes with s 570 | -- so `vs` or `vjjs` or whatever should allow selecting a treesitter node 571 | -- or expanding/contracting it with `;` and `,` 572 | -- ctrl-s will do general screen jump otherwise 573 | M.mapn("", function() require("flash").jump({ jump = { autojump = true } }) end, "Flash Search") 574 | M.mapleadern("fj", function() require("flash").jump({ jump = { autojump = true } }) end, "Jump on screen") 575 | M.mapox("", require("flash").jump, "Visual Extend via Flash") 576 | M.mapox("r", require("flash").treesitter, "Visual Extend to Treesitter block") 577 | end 578 | 579 | return M 580 | -------------------------------------------------------------------------------- /pwnvim/markdown.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.mdFoldLevel = function(lnum) 4 | if not lnum then lnum = vim.v.lnum end 5 | local line = vim.fn.getline(lnum) 6 | local heading = string.match(line, "^#+ ") 7 | if heading then 8 | return ">" .. (string.len(heading) - 1) -- start off fold 9 | else 10 | return "=" -- continue previous fold level 11 | end 12 | end 13 | 14 | M.setup = function(ev) 15 | -- local bufnr = vim.api.nvim_get_current_buf() 16 | local bufnr = ev.buf 17 | vim.g.joinspaces = true 18 | vim.wo.number = false 19 | vim.wo.relativenumber = false 20 | vim.wo.spell = true 21 | vim.wo.list = false 22 | 23 | -- Treesitter is pretty good, but includes folds for bullet lists and code in code blocks 24 | -- which could be great, but more often annoys me. I'm not sure how to tune it, so 25 | -- just making my own function to collapse on headings instead 26 | -- vim.wo.foldexpr = "v:lua.vim.treesitter.foldexpr()" 27 | vim.wo.foldexpr = "v:lua.require('pwnvim.markdown').mdFoldLevel(v:lnum)" 28 | vim.wo.foldenable = true 29 | vim.wo.foldlevel = 20 30 | vim.wo.foldcolumn = "auto:5" 31 | vim.wo.foldmethod = "expr" 32 | 33 | -- vim.bo.formatoptions = "jcroqln" 34 | vim.bo.formatoptions = 'jtqlnr' -- no c (insert comment char on wrap), with r (indent) 35 | vim.bo.comments = 'b:>,b:*,b:+,b:-' 36 | vim.bo.suffixesadd = '.md' 37 | 38 | vim.bo.syntax = "off" -- we use treesitter exclusively on markdown now 39 | -- except temp off until https://github.com/MDeiml/tree-sitter-markdown/issues/114 40 | 41 | require('pwnvim.markdown').markdownsyntax() 42 | require('pwnvim.markdown').setupmappings(bufnr) 43 | 44 | vim.diagnostic.config({ virtual_lines = false }) -- no need to see this in markdown -- wavy underlines good enough 45 | 46 | -- no idea why the lua version of adding the command is failing 47 | -- vim.api.nvim_buf_add_user_command(0, 'PasteUrl', function(opts) require('pwnvim.markdown').pasteUrl() end, {}) 48 | vim.cmd("command! PasteUrl lua require('pwnvim.markdown').pasteUrl()") 49 | 50 | vim.cmd('packadd render-markdown.nvim') 51 | require('render-markdown').setup({ 52 | file_types = { 'markdown', "codecompanion" } 53 | }) 54 | require('render-markdown').enable() 55 | 56 | -- Image plugin still slow and buggy 2024-12-01 57 | -- if os.getenv("TERM") == "wezterm" or os.getenv("TERM") == "kitty" then 58 | -- vim.cmd('packadd image.nvim') 59 | -- require("image").setup({ 60 | -- backend = "kitty", 61 | -- processor = "magick_rock", -- or "magick_cli" 62 | -- integrations = { 63 | -- markdown = { 64 | -- enabled = true, 65 | -- clear_in_insert_mode = false, 66 | -- download_remote_images = true, 67 | -- only_render_image_at_cursor = false, 68 | -- filetypes = { "markdown", "vimwiki" }, -- markdown extensions (ie. quarto) can go here 69 | -- }, 70 | -- neorg = { 71 | -- enabled = true, 72 | -- filetypes = { "norg" }, 73 | -- }, 74 | -- typst = { 75 | -- enabled = true, 76 | -- filetypes = { "typst" }, 77 | -- }, 78 | -- html = { 79 | -- enabled = false, 80 | -- }, 81 | -- css = { 82 | -- enabled = false, 83 | -- }, 84 | -- }, 85 | -- max_width = nil, 86 | -- max_height = nil, 87 | -- max_width_window_percentage = nil, 88 | -- max_height_window_percentage = 50, 89 | -- window_overlap_clear_enabled = false, -- toggles images when windows are overlapped 90 | -- window_overlap_clear_ft_ignore = { "cmp_menu", "cmp_docs", "" }, 91 | -- editor_only_render_when_focused = false, -- auto show/hide images when the editor gains/looses focus 92 | -- tmux_show_only_in_active_window = false, -- auto show/hide images in the correct Tmux window (needs visual-activity off) 93 | -- hijack_file_patterns = { "*.png", "*.jpg", "*.jpeg", "*.gif", "*.webp", "*.avif" }, -- render image files as images when opened 94 | -- }) 95 | -- end 96 | 97 | -- Hologram displays image thumbnails in-terminal while editing markdown in vim 98 | -- This is wonderful when it's working, but I sometimes get too many open files errors that seem to come from this plugin. Plus 99 | -- some weirdness where my entire terminal (kitty) completely hangs for a time. Especially when typing in an alt description. 100 | -- So, sadly, commenting out for now. 2023-01-19 101 | -- if vim.env.KITTY_INSTALLATION_DIR and not vim.g.neovide then 102 | -- vim.cmd('packadd hologram.nvim') 103 | -- require('hologram').setup { 104 | -- auto_display = true -- WIP automatic markdown image display, may be prone to breaking 105 | -- } 106 | -- end 107 | vim.cmd('packadd clipboard-image.nvim') 108 | -- note: PasteImg is just require'clipboard-image.paste'.paste_img() 109 | require 'clipboard-image'.setup { 110 | default = { 111 | img_name = function() 112 | vim.fn.inputsave() 113 | local name = vim.fn.input({ prompt = "Name: " }) 114 | -- TODO: swap spaces out for dashes 115 | vim.fn.inputrestore() 116 | return os.date('%Y-%m-%d') .. "-" .. name 117 | end, 118 | img_dir = { "%:p:h", "%:t:r:s?$?_attachments?" }, 119 | img_dir_txt = "%:t:r:s?$?_attachments?", 120 | -- TODO: can I put the name as the title somehow? 121 | affix = "![image](%s)" 122 | } 123 | } 124 | 125 | vim.cmd('packadd todo-comments.nvim') 126 | require("pwnvim.plugins.todo-comments") -- show todo's in markdown, too 127 | if require("todo-comments.config").options["highlight"] ~= nil then 128 | require("todo-comments.config").options.highlight.comments_only = false 129 | else 130 | require("todo-comments.config").options["highlight"] = { 131 | comments_only = false 132 | } 133 | end 134 | 135 | local autocmd = vim.api.nvim_create_autocmd 136 | local mdsave = vim.api.nvim_create_augroup("mdsave", { clear = true }) 137 | -- markdown processors can optionally create smart quotes and stuff, but we want the source clean 138 | -- so spell check and other things work as expected 139 | autocmd("BufWritePre", { 140 | pattern = { "*.markdown", "*.md" }, 141 | desc = "Remove smart quotes from markdown files", 142 | group = mdsave, 143 | callback = function() 144 | local curpos = vim.api.nvim_win_get_cursor(0) 145 | vim.cmd([[keeppatterns %s/[‘’′]/'/eg]]) 146 | vim.cmd([[keeppatterns %s/[“”“”″]/"/eg]]) 147 | vim.api.nvim_win_set_cursor(0, curpos) 148 | end 149 | }) 150 | 151 | -- I have historically always used spaces for indents wherever possible including markdown 152 | -- Changing now to use tabs because NotePlan 3 can't figure out nested lists that are space 153 | -- indented and I go back and forth between that and nvim (mainly for iOS access to notes). 154 | -- So, for now, this is the compatibility compromise. 2022-09-27 155 | -- UPDATE 2023-08-18: going to do ugly stateful things and check the CWD and only 156 | -- use tabs when in a Notes directory so I stop screwing up READMEs. 157 | if (string.find(vim.fn.getcwd(), "Notes") or 158 | string.find(vim.fn.getcwd(), "noteplan")) then 159 | require('pwnvim.options').tabindent() 160 | --require('pwnvim.options').retab() -- turn spaces to tabs when markdown file is opened 161 | else 162 | require('pwnvim.options').twospaceindent() 163 | -- require('pwnvim.options').retab() -- turn tabs to spaces when markdown file is opened 164 | end 165 | -- Temporary workaround for https://github.com/nvim-telescope/telescope.nvim/issues/559 166 | -- which prevents folds from being calculated initially when launching from telescope 167 | -- Has the lousy side-effect of calculating them twice if not launched from telescope 168 | vim.cmd("normal zx") 169 | end 170 | 171 | M.setupmappings = function(bufnr) 172 | -- normal mode mappings 173 | local mapnlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapn) 174 | local mapilocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapi) 175 | local mapvlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapv) 176 | local mapnvlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapnv) 177 | 178 | mapnlocal("m", ':silent !open -a Marked\\ 2.app "%:p"', "Open Marked preview") 179 | mapnlocal("gl*", [[let p=getcurpos('.'):s/^\([ \t]*\)/\1* /:nohlsearch:call setpos('.', p)2l]], 180 | "Add bullets") 181 | mapnlocal("gl>", [[let p=getcurpos('.'):s/^/> /:nohlsearch:call setpos('.', p)2l]], 182 | "Add block quote") 183 | mapnlocal("gl[", [[let p=getcurpos('.'):s/^\([ \t]*\)/\1* [ ] /:nohlsearch:call setpos('.', p)5l]], 184 | "Add task") 185 | mapnlocal("gt", require('pwnvim.markdown').transformUrlUnderCursorToMdLink, "Convert URL to link") 186 | mapnlocal("P", require('pwnvim.markdown').pasteUrl, "Paste URL as link") 187 | mapnlocal("", require('pwnvim.markdown').pasteUrl, "Paste URL as link") 188 | mapnlocal("", 'ysiwe', "Bold") 189 | mapnlocal("b", 'ysiwe', "Bold") 190 | mapnlocal("", 'ysiw_', "Italic") 191 | mapnlocal("i", 'ysiw_', "Italic") 192 | mapnlocal("", 'ysiw`', "Code block") 193 | mapnlocal("`", 'ysiw`', "Code block") 194 | mapnlocal("", 'ysiW]%a(`', "Link") 195 | 196 | -- insert mode mappings 197 | mapilocal("", require('pwnvim.markdown').pasteUrl, "Paste URL as link") 198 | mapilocal("", "****h", "Bold") 199 | mapilocal("", [[__h]], "Italic") 200 | mapilocal("", [[``h]], "Code block") 201 | mapilocal("", require('pwnvim.markdown').indent, "Indent") 202 | mapilocal("", require('pwnvim.markdown').outdent, "Outdent") 203 | 204 | -- mapnviclocal("", function() 205 | -- vim.cmd("lvimgrep /^#/ %") 206 | -- require("trouble").toggle({ mode = "loclist", position = "right" }) 207 | -- end, "Show doc outline") 208 | 209 | -- visual mode mappings 210 | mapvlocal("gl*", [[let p=getcurpos('.'):s/^\([ \t]*\)/\1* /:nohlsearch:call setpos('.', p)gv]], 211 | "Add bullets") 212 | mapvlocal("gl>", [[let p=getcurpos('.'):s/^/> /:nohlsearch:call setpos('.', p)gv]], "Add quotes") 213 | mapvlocal("gl[", [[let p=getcurpos('.'):s/^\([ \t]*)/\1* [ ] /:nohlsearch:call setpos('.', p)gv]], 214 | "Add task") 215 | mapvlocal("gt", "lua require('pwnvim.markdown').transformUrlUnderCursorToMdLink()", "Convert URL to link") 216 | mapvlocal("", "(nvim-surround-visual)e", "Bold") 217 | mapvlocal("b", "(nvim-surround-visual)e", "Bold") 218 | mapvlocal("", "(nvim-surround-visual)_", "Italic") 219 | mapvlocal("i", "(nvim-surround-visual)_", "Italic") 220 | mapvlocal("", "(nvim-surround-visual)`", "Code ticks") 221 | mapvlocal("`", "(nvim-surround-visual)_", "Code ticks") 222 | mapvlocal("", "(nvim-surround-visual)]%a(", "Code ticks") 223 | 224 | -- task shortcuts 225 | mapvlocal("ta", [[grep "^\s*[*-] \[ \] ":Trouble quickfix]], "All tasks quickfix") 226 | mapnlocal("td", require("pwnvim.tasks").completeTaskDirect, "Task done") 227 | mapvlocal("td", ":luado return require('pwnvim.tasks').completeTask(line)", "Done") 228 | mapnlocal("tc", require("pwnvim.tasks").createTaskDirect, "Task create") 229 | mapnlocal("ts", require("pwnvim.tasks").scheduleTaskPrompt, "Task schedule") 230 | mapvlocal("ts", require("pwnvim.tasks").scheduleTaskBulk, "Schedule") 231 | mapnlocal("tt", require("pwnvim.tasks").scheduleTaskTodayDirect, "Task move today") 232 | mapvlocal("tt", ":luado return require('pwnvim.tasks').scheduleTaskToday(line)", "Today") 233 | 234 | -- Even when zk LSP doesn't connect, we can have formatters (including vale) give feedback -- ensure we have a way to see it 235 | mapnlocal("le", vim.diagnostic.open_float, "Show Line Diags") 236 | end 237 | 238 | M.markdownsyntax = function() 239 | vim.api.nvim_exec2([[ 240 | let m = matchadd("bareLink", "\\\\] .\\+") 244 | " below is because Noteplan uses capital X and default styling is a link on [X] so this will at least make it green 245 | let m = matchadd("@text.todo.checked", "[*-] \\[[xX]\\] ") 246 | let m = matchadd("markdownTag", '#\w\+') 247 | let m = matchadd("markdownStrikethrough", "\\~\\~[^~]*\\~\\~") 248 | let m = matchadd("doneTag", '@done(20[^)]*)') 249 | let m = matchadd("highPrioTask", "[*-] \\[ \\] .\\+!!!") 250 | ]], { output = false }) 251 | end 252 | 253 | local check_backspace = function() 254 | local col = vim.fn.col "." - 1 255 | return col == 0 or vim.fn.getline(vim.fn.line(".")):sub(col, col):match "%s" 256 | end 257 | 258 | M.indent = function() 259 | local line = vim.api.nvim_get_current_line() 260 | if line:match("^%s*[*-]") then 261 | local ctrlt = vim.api.nvim_replace_termcodes("", true, false, true) 262 | vim.api.nvim_feedkeys(ctrlt, "n", false) 263 | elseif check_backspace() then 264 | -- we are at first col or there is whitespace immediately before cursor 265 | -- send through regular tab character at current position 266 | vim.api.nvim_feedkeys("\t", "n", false) 267 | else 268 | require 'cmp'.mapping.complete({}) 269 | end 270 | end 271 | 272 | M.outdent = function() 273 | local line = vim.api.nvim_get_current_line() 274 | if line:match("^%s*[*-]") then 275 | local ctrld = vim.api.nvim_replace_termcodes("", true, false, true) 276 | vim.api.nvim_feedkeys(ctrld, "n", false) 277 | end 278 | end 279 | 280 | M.getTitleFor = function(url) 281 | local curl = require "plenary.curl" 282 | if not string.match(url, "^https?:[^%s]*$") then 283 | return "" -- doesn't look like a URL -- avoid curl sadness 284 | end 285 | local res = curl.request { 286 | url = url, 287 | method = "get", 288 | accept = "text/html", 289 | raw = { "-L" } -- follow redirects 290 | } 291 | local title = "" 292 | if res then 293 | title = string.match(res.body, "]*>([^<]+)") 294 | if not title then title = string.match(res.body, "]*>([^<]+)") end 295 | end 296 | if not title then 297 | title = "could not get title" -- TODO: put domain here 298 | end 299 | return title 300 | end 301 | 302 | M.transformUrlUnderCursorToMdLink = function() 303 | -- local url = vim.fn.expand("") 304 | local url = vim.fn.expand("") 305 | local title = require("pwnvim.markdown").getTitleFor(url) 306 | vim.cmd("normal! ciW[" .. title .. "](" .. url .. ")") 307 | end 308 | 309 | M.pasteUrl = function() 310 | local url = vim.fn.getreg('*') 311 | local title = require("pwnvim.markdown").getTitleFor(url) 312 | vim.cmd("normal! a[" .. title .. "](" .. url .. ")") 313 | -- cursor ends up one to the left, so move over right one if possible 314 | local right = vim.api.nvim_replace_termcodes("", true, false, true) 315 | vim.api.nvim_feedkeys(right, "n", false) 316 | end 317 | 318 | M.newMeetingNote = function() 319 | local zk = require("zk.commands") 320 | M.telescope_get_folder_and_title(vim.env.ZK_NOTEBOOK_DIR, 'Notes/meetings', function(folder, title) 321 | zk.get('ZkNew')({ dir = folder, title = title }) 322 | end) 323 | end 324 | 325 | M.newGeneralNote = function() 326 | local zk = require("zk.commands") 327 | local zkfolder = require("zk.util").notebook_root(vim.api.nvim_buf_get_name(0)) 328 | local subdir = "" 329 | if not zkfolder then 330 | zkfolder = vim.env.ZK_NOTEBOOK_DIR 331 | subdir = 'Notes' 332 | else 333 | if vim.fn.isdirectory(zkfolder .. "/Notes") == 1 then 334 | subdir = 'Notes' 335 | elseif vim.fn.isdirectory(zkfolder .. "/content") == 1 then 336 | subdir = "content" 337 | end 338 | end 339 | 340 | M.telescope_get_folder_and_title(zkfolder, subdir, function(folder, title) 341 | zk.get('ZkNew')({ dir = folder, title = title }) 342 | end) 343 | end 344 | 345 | M.newDailyNote = function() 346 | local zk = require("zk.commands") 347 | zk.get("ZkNew")({ dir = vim.env.ZK_NOTEBOOK_DIR .. '/Calendar', title = os.date("%Y%m%d") }) 348 | end 349 | 350 | M.telescope_get_folder_and_title = function(base, subdir, callback) 351 | M.telescope_get_folder(base, subdir, function(folder) 352 | vim.ui.input({ prompt = 'Title: ', default = '' }, function(input) 353 | if input ~= nil then 354 | callback(folder, input) 355 | end 356 | end) 357 | end) 358 | end 359 | 360 | M.telescope_get_folder = function(base, subdir, callback) 361 | local pickers = require "telescope.pickers" 362 | local finders = require "telescope.finders" 363 | local sorters = require "telescope.sorters" 364 | local themes = require "telescope.themes" 365 | local action_state = require "telescope.actions.state" 366 | local actions = require "telescope.actions" 367 | 368 | local entry = function(a) 369 | local display = (string.gsub(a, base .. '/' .. subdir, '')) 370 | if (display == '') then display = '/' end 371 | return { 372 | value = a, 373 | display = display, 374 | ordinal = a 375 | } 376 | end 377 | local scan = require 'plenary.scandir' 378 | local full_path_folders = scan.scan_dir(base .. '/' .. subdir, { 379 | add_dirs = true, 380 | only_dirs = true, 381 | respect_gitignore = true, 382 | depth = 3, 383 | }) 384 | table.insert(full_path_folders, 1, base .. '/' .. subdir) 385 | 386 | local finder = finders.new_table({ 387 | results = full_path_folders, 388 | entry_maker = entry 389 | }) 390 | pickers.new({}, { 391 | cwd = base, 392 | prompt_title = "Pick Folder", 393 | finder = finder, 394 | sorter = sorters.fuzzy_with_index_bias(), 395 | theme = themes.get_dropdown(), 396 | attach_mappings = 397 | function(prompt_bufnr) 398 | actions.select_default:replace(function() 399 | local folder = action_state.get_selected_entry() 400 | -- print(vim.inspect(folder)) 401 | if folder ~= nil then 402 | actions.close(prompt_bufnr) 403 | callback(folder["value"]) 404 | end 405 | end) 406 | return true 407 | end 408 | }):find() 409 | end 410 | 411 | return M 412 | -------------------------------------------------------------------------------- /pwnvim/options.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | SimpleUI = (os.getenv("SIMPLEUI") == "1" or os.getenv("TERM_PROGRAM") == 4 | "Apple_Terminal" or os.getenv("TERM") == "linux") and 5 | not vim.g.neovide 6 | 7 | M.defaults = function() 8 | -- disable builtin vim plugins 9 | vim.g.loaded_gzip = 0 10 | vim.g.loaded_tar = 0 11 | vim.g.loaded_tarPlugin = 0 12 | vim.g.loaded_zipPlugin = 0 13 | vim.g.loaded_2html_plugin = 0 14 | vim.g.loaded_netrw = 1 -- disable netrw 15 | vim.g.loaded_netrwPlugin = 1 -- disable netrw 16 | -- we just use lua plugins here so disable others 17 | vim.g.loaded_perl_provider = 0 18 | vim.g.loaded_node_provider = 0 19 | -- vim.g.loaded_python3_provider = 0 -- moved to flake for different modes 20 | vim.g.loaded_ruby_provider = 0 21 | -- vim.g.loaded_matchit = 0 22 | -- vim.g.loaded_matchparen = 1 -- to disable built in paren matching 23 | vim.g.loaded_spec = 0 24 | vim.g.vim_markdown_no_default_key_mappings = 1 25 | -- vim.g.markdown_folding = 1 26 | vim.g.vim_markdown_strikethrough = 1 27 | vim.g.vim_markdown_auto_insert_bullets = 1 28 | vim.g.vim_markdown_new_list_item_indent = 0 29 | vim.g.vim_markdown_conceal = 1 30 | vim.g.vim_markdown_math = 0 31 | vim.g.vim_markdown_conceal_code_blocks = 0 32 | vim.g.vim_markdown_frontmatter = 1 33 | 34 | 35 | -- my shada is so large it takes up half of startup time to process; constraining what it keeps here 36 | -- previous value: !,'100,<50,s10,h' 37 | vim.opt.shada = { "'50", "<0", ":5", "/0", '"0', "@5", "f10", "h", "s10" } 38 | -- The "'#" option remembers some number of marks, but actually controls how many files in the oldfiles list 39 | -- this would allow spaces in filenames for commands like `gf` but results are really mixed. 40 | -- commenting for now 2022-12-22 41 | -- vim.opt.isfname:append { "32" } 42 | 43 | vim.opt.foldenable = false 44 | 45 | vim.opt.grepprg = "rg --vimgrep --no-heading --hidden --smart-case --color never" 46 | vim.opt.grepformat = "%f:%l:%c:%m,%f:%l:%m,%f" 47 | 48 | -- ignore completions and menus for the below 49 | vim.opt.wildignore = 50 | "*/node_modules/*,_site,*/__pycache__/,*/venv/*,*/target/*,*/.vim$,\\~$,*/.log,*/.aux,*/.cls,*/.aux,*/.bbl,*/.blg,*/.fls,*/.fdb*/,*/.toc,*/.out,*/.glo,*/.log,*/.ist,*/.fdb_latexmk,*.bak,*.o,*.a,*.sw?,.git/,*.class,.direnv/,.DS_Store,*/Backups/*" 51 | vim.opt.wildmenu = true -- cmd line completion a-la zsh 52 | vim.opt.wildmode = "list:longest" -- matches mimic that of bash or zsh 53 | 54 | vim.opt.cmdheight = 1 55 | vim.opt.cmdwinheight = 5 56 | 57 | vim.opt.swapfile = true -- I've lived without them for years, but recent crashes have me reconsidering 58 | -- The swap files will be wiped on reboot (cuz /tmp), which could mean lost work on system crash; nvim will create 59 | -- the dir if it doesn't exist. The double slash ending means filenames will include full path to original file. 60 | vim.opt.directory = "/tmp/nvim-swap//" 61 | vim.opt.spell = true 62 | vim.opt.spelllang = "en_us" 63 | vim.opt.ruler = true -- show the cursor position all the time 64 | vim.opt.cursorline = true -- add indicator for current line 65 | vim.opt.secure = true -- don't execute shell cmds in .vimrc not owned by me 66 | vim.opt.history = 50 -- keep 50 lines of command line history 67 | vim.opt.shell = "zsh" 68 | vim.opt.modelines = 0 -- Don't allow vim settings embedded in text files for security reasons 69 | vim.opt.showcmd = true -- display incomplete commands 70 | vim.opt.showmode = true -- display current mode 71 | -- with backup off and writebackup on: backup current file, deleted afterwards 72 | vim.opt.backup = false 73 | vim.opt.writebackup = true 74 | vim.opt.backupcopy = "auto" 75 | vim.opt.hidden = true 76 | vim.opt.cf = true -- jump to errors based on error files 77 | vim.o.listchars = 78 | "tab:⇥ ,trail:␣,multispace:␣,extends:⇉,precedes:⇇,nbsp:·" --,eol:↴" -- ,space:⋅" 79 | vim.opt.list = false -- render special chars (tabs, trails, ...) 80 | vim.opt.ttyfast = true 81 | vim.opt.expandtab = true 82 | vim.opt.splitbelow = true -- allow splits below 83 | vim.opt.splitright = true -- and to the right 84 | vim.opt.dictionary:append { '/usr/share/dict/words', '~/.aspell.english.pws' } 85 | vim.opt.complete = vim.opt.complete + { 'k', ']' } 86 | vim.opt.complete = vim.opt.complete - { 'i' } 87 | vim.opt.encoding = "utf-8" 88 | vim.opt.backspace = "indent,eol,start" -- allow backspacing over everything in insert mode 89 | vim.opt.joinspaces = false -- don't insert two spaces after sentences on joins 90 | vim.opt.binary = false 91 | vim.opt.display = "lastline" 92 | vim.opt.viewoptions = "folds,cursor,unix,slash" -- better unix / windows compatibility 93 | vim.o.shortmess = "filnxtToSAcOF" 94 | vim.opt.foldnestmax = 5 95 | 96 | -- wrapping 97 | vim.opt.wrap = true 98 | vim.opt.sidescroll = 2 -- min number of columns to scroll from edge 99 | vim.opt.scrolloff = 8 -- when 4 away from edge start scrolling 100 | vim.opt.sidescrolloff = 8 -- keep cursor one col from end of line 101 | vim.opt.textwidth = 0 102 | vim.opt.breakindent = true 103 | vim.opt.showbreak = "» " 104 | vim.opt.breakat:remove { '/', '*', '_', '`' } 105 | vim.opt.linebreak = true -- wraps on word boundaries but only if nolist is set 106 | 107 | -- Make tabs be spaces of 4 characters by default 108 | vim.opt.tabstop = 4 109 | vim.opt.shiftwidth = 4 110 | vim.opt.softtabstop = 4 111 | vim.opt.expandtab = true -- turn tabs to spaces by default 112 | 113 | vim.opt.autoindent = true -- autoindent to same level as previous line 114 | vim.opt.smartindent = true -- indent after { and cinwords words 115 | vim.opt.smartcase = true -- intelligently ignore case in searches 116 | vim.opt.ignorecase = true -- default to not being case sensitive 117 | vim.opt.smarttab = true 118 | vim.opt.icm = "nosplit" -- show substitutions as you type 119 | vim.opt.hlsearch = true 120 | vim.opt.updatetime = 250 -- Decrease update time 121 | vim.wo.signcolumn = 'yes' 122 | vim.opt.visualbell = true 123 | vim.opt.autoread = true -- auto reload files changed on disk if not changed in buffer 124 | vim.opt.cursorline = false 125 | vim.opt.ttyfast = true 126 | vim.opt.formatoptions = 'jcroqlt' -- t=text, c=comments, q=format with "gq" 127 | vim.opt.showmatch = true -- auto hilights matching bracket or paren 128 | vim.opt.nrformats = vim.opt.nrformats - { 'octal' } 129 | vim.opt.shiftround = true 130 | vim.opt.timeout = true 131 | vim.opt.timeoutlen = 300 132 | vim.opt.ttimeout = true 133 | vim.opt.ttimeoutlen = 50 134 | vim.opt.fileformats = "unix,dos,mac" 135 | vim.o.matchpairs = "(:),{:},[:],<:>" 136 | vim.opt.number = false 137 | vim.opt.relativenumber = false 138 | -- noinsert: don't insert until selection made, noselect: don't select automatically 139 | vim.opt.completeopt = "menu,menuone,noinsert,noselect" -- needed for autocompletion stuff 140 | vim.opt.conceallevel = 2 141 | if vim.api.nvim_buf_get_option(0, 'modifiable') then 142 | vim.opt.fileencoding = "utf-8" 143 | end 144 | 145 | -- Globals 146 | vim.g.vimsyn_embed = 'l' -- Highlight Lua code inside .vim files 147 | vim.g.polyglot_disabled = { 'sensible', 'autoindent', 'ftdetect' } -- preserve in case I want to bring back polyglot 148 | vim.opt.foldlevelstart = 10 149 | 150 | -- map the leader key to , 151 | -- note: comma would typically go backwards in a f or t character search (where ; goes ahead) 152 | vim.api.nvim_set_keymap('n', ',', '', {}) -- first unset it though 153 | vim.api.nvim_set_keymap('v', ',', '', {}) -- first unset it though 154 | vim.g.mapleader = ',' -- Namespace for custom shortcuts 155 | 156 | vim.api.nvim_exec2([[ 157 | filetype plugin indent on 158 | syntax off 159 | syntax sync minlines=2000 160 | ]], { output = false }) 161 | 162 | -- Brief highlight on yank 163 | vim.api.nvim_exec2([[ 164 | augroup YankHighlight 165 | autocmd! 166 | autocmd TextYankPost * silent! lua vim.highlight.on_yank() 167 | augroup end 168 | ]], { output = false }) 169 | end 170 | 171 | M.colors_cat = function() 172 | vim.g.termguicolors = not SimpleUI 173 | vim.o.termguicolors = not SimpleUI 174 | vim.o.background = "dark" 175 | 176 | require("catppuccin").setup({ 177 | flavour = "macchiato", -- latte, frappe, macchiato, mocha 178 | background = { -- :h background 179 | light = "latte", 180 | dark = "macchiato", 181 | }, 182 | transparent_background = true, -- disables setting the background color. 183 | dim_inactive = { 184 | enabled = true, -- dims the background color of inactive window 185 | shade = "dark", 186 | percentage = 0.15, -- percentage of the shade to apply to the inactive window 187 | }, 188 | integrations = { 189 | alpha = false, 190 | cmp = true, 191 | copilot_vim = true, 192 | dropbar = { 193 | enabled = true, 194 | color_mode = true, 195 | }, 196 | dashboard = false, 197 | flash = true, 198 | gitsigns = true, 199 | gitgutter = false, 200 | illuminate = false, 201 | mini = { enabled = false }, 202 | neogit = false, 203 | nvimtree = false, 204 | treesitter = true, 205 | notify = true, 206 | nvim_surround = true, 207 | markdown = true, 208 | render_markdown = true, 209 | noice = true, 210 | ufo = true, 211 | semantic_tokens = true, 212 | treesitter_context = true, 213 | lsp_trouble = true, 214 | telescope = { enabled = true }, 215 | which_key = true, 216 | -- For more plugins integrations please scroll down (https://github.com/catppuccin/nvim#integrations) 217 | }, 218 | custom_highlights = function(colors) 219 | return { 220 | mkdLink = { fg = colors.blue, style = { "underline" } }, 221 | bareLink = { fg = colors.blue, style = { "underline" } }, 222 | mkdURL = { fg = colors.green, style = { "underline" } }, 223 | ["@markup.link.label"] = { link = "mkdLink" }, 224 | ["@markup.link.url"] = { link = "mkdURL" }, 225 | mkdInlineURL = { fg = colors.blue, style = { "underline" } }, 226 | mkdListItem = { fg = colors.teal }, 227 | markdownListMarker = { fg = colors.teal }, 228 | mkdListItemCheckbox = { fg = colors.green }, 229 | markdownCheckboxCanceled = { fg = colors.surface2, style = { "strikethrough" } }, 230 | markdownCheckboxPostponed = { fg = colors.surface2 }, 231 | markdownStrikethrough = { fg = colors.surface2, style = { "strikethrough" } }, 232 | markdownTag = { fg = colors.surface2 }, 233 | doneTag = { fg = colors.surface2, style = { "italic" } }, 234 | highPrioTask = { fg = colors.red, style = { "bold" } }, 235 | TSURI = { fg = colors.blue, style = { "underline" } }, 236 | TSPunctSpecial = { fg = colors.red }, 237 | markdownTSTitle = { fg = colors.teal, style = { "bold" } }, 238 | markdownAutomaticLink = { fg = colors.blue, style = { "underline" } }, 239 | markdownLink = { fg = colors.green, style = { "underline" } }, 240 | markdownLinkText = { fg = colors.blue, style = { "underline" } }, 241 | ["@link_text"] = { fg = colors.blue, style = { "underline", "bold" } }, 242 | markdownUrl = { fg = colors.green, style = { "underline" } }, 243 | markdownWikiLink = { fg = colors.blue, style = { "underline" } }, 244 | ["@markup.heading.1"] = { fg = colors.yellow, style = { "bold" } }, 245 | markdownH1 = { fg = colors.yellow, style = { "bold" } }, 246 | ["@markup.heading.2"] = { fg = colors.yellow, style = { "bold" } }, 247 | markdownH2 = { fg = colors.yellow, style = { "bold" } }, 248 | ["@markup.heading.3"] = { fg = colors.yellow }, 249 | markdownH3 = { fg = colors.yellow }, 250 | ["@markup.heading.4"] = { fg = colors.green, style = { "italic" } }, 251 | markdownH4 = { fg = colors.green, style = { "italic" } }, 252 | ["@markup.heading.5"] = { fg = colors.green, style = { "italic" } }, 253 | markdownH5 = { fg = colors.green, style = { "italic" } }, 254 | ["@markup.heading.6"] = { fg = colors.green, style = { "italic" } }, 255 | markdownH6 = { fg = colors.green, style = { "italic" } }, 256 | htmlH1 = { fg = colors.yellow, style = { "bold" } }, 257 | htmlH2 = { fg = colors.yellow, style = { "bold" } }, 258 | htmlH3 = { fg = colors.yellow }, 259 | htmlH4 = { fg = colors.green, style = { "italic" } }, 260 | htmlH5 = { fg = colors.green, style = { "italic" } }, 261 | htmlH6 = { fg = colors.green, style = { "italic" } }, 262 | markdownBold = { fg = "#ffffff", style = { "bold" } }, 263 | htmlBold = { fg = "#ffffff", style = { "bold" } }, 264 | markdownItalic = { fg = "#eeeeee", style = { "italic" } }, 265 | htmlItalic = { fg = "#eeeeee", style = { "italic" } }, 266 | markdownBoldItalic = { fg = "#ffffff", style = { "bold", "italic" } }, 267 | htmlBoldItalic = { fg = "#ffffff", style = { "bold", "italic" } }, 268 | SpellBad = { style = { "undercurl" }, sp = colors.red }, 269 | SpellCap = { style = { "undercurl" }, sp = colors.teal }, 270 | SpellRare = { style = { "undercurl" }, sp = colors.lavender }, 271 | SpellLocal = { style = { "undercurl" }, sp = colors.teal }, 272 | MatchParen = { bg = "#555555", style = { "italic" } }, 273 | IndentBlanklineChar = { fg = "#444444" }, 274 | -- Todo = { fg = "#282c34", bg = "${highlight}", bold = true }, 275 | VertSplit = { fg = "#202020", bg = "#606060" }, 276 | Folded = { fg = "#c0c8d0", bg = "#384058" }, 277 | ["@comment.markdown"] = { fg = colors.surface2 }, 278 | ["@field.markdown_inline"] = { fg = colors.lavender }, 279 | ["@markup.raw"] = { fg = colors.green }, 280 | ["@markup.underline"] = { style = { "underline" } }, 281 | ["@markup.strong.markdown_inline"] = { fg = "#ffffff", style = { "bold" } }, 282 | ["@markup.emphasis.markdown_inline"] = { fg = "#eeeeee", style = { "italic" } }, 283 | ["@markup.strikethrough.markdown_inline"] = { 284 | fg = colors.surface2, 285 | style = { "strikethrough" } 286 | }, 287 | ["@tag"] = { fg = colors.surface2 }, 288 | ["@block_quote.markdown"] = { fg = colors.lavender, style = { "italic" } }, 289 | ["@punctuation.special.markdown"] = { fg = colors.teal }, 290 | ["@punctuation.delimiter.markdown_inline"] = { fg = colors.peach }, 291 | ["@markup.link.url.markdown_inline"] = { fg = colors.blue }, 292 | ["@markup.list.unchecked"] = { fg = "#ffffff", bg = "", style = { "bold" } }, 293 | ["@markup.list.checked"] = { fg = colors.green, style = { "bold" } }, 294 | } 295 | end 296 | 297 | }) 298 | local cscheme 299 | if SimpleUI then 300 | cscheme = "ir_black" 301 | else 302 | cscheme = "catppuccin" 303 | end 304 | vim.cmd.colorscheme(cscheme) 305 | end 306 | 307 | M.colors_onedark = function() 308 | vim.g.termguicolors = not SimpleUI 309 | vim.o.termguicolors = not SimpleUI 310 | vim.o.background = "dark" 311 | 312 | if not SimpleUI then 313 | require("onedarkpro").setup({ 314 | -- Call :OnedarkproCache if you make changes below and to speed startups 315 | caching = true, 316 | highlights = { 317 | mkdLink = { fg = "${blue}", underline = true }, 318 | bareLink = { link = "mkdLink" }, 319 | mkdInlineURL = { link = "mkdLink" }, 320 | TSURI = { link = "mkdLink" }, 321 | mkdURL = { fg = "${green}", underline = true }, 322 | markdownAutomaticLink = { link = "mkdLink" }, 323 | markdownLink = { link = "mkdURL" }, 324 | markdownLinkText = { link = "mkdLink" }, 325 | markdownUrl = { link = "mkdURL" }, 326 | markdownWikiLink = { link = "mkdLink" }, 327 | ["@link_text.markdown_inline"] = { link = "mkdLink" }, 328 | ["@markup.link.label"] = { link = "mkdLink" }, 329 | ["@markup.link.url"] = { link = "mkdURL" }, 330 | 331 | 332 | mkdListItem = { fg = "${cyan}" }, 333 | markdownListMarker = { fg = "${cyan}" }, 334 | ["@markup.list"] = { link = "markdownListMarker" }, 335 | mkdListItemCheckbox = { fg = "${green}" }, 336 | markdownCheckboxCanceled = { fg = "${comment}", style = "strikethrough" }, 337 | markdownCheckboxPostponed = { fg = "${comment}" }, 338 | 339 | markdownTag = { fg = "${comment}" }, 340 | doneTag = { fg = "${comment}", italic = true }, 341 | highPrioTask = { fg = "${red}", bold = true }, 342 | TSPunctSpecial = { fg = "${red}" }, 343 | markdownTSTitle = { fg = "${cyan}", bold = true }, 344 | 345 | htmlH1 = { fg = "${yellow}", bold = true }, 346 | htmlH2 = { fg = "${yellow}", bold = true }, 347 | htmlH3 = { fg = "${yellow}" }, 348 | htmlH4 = { fg = "${green}", italic = true }, 349 | htmlH5 = { fg = "${green}", italic = true }, 350 | htmlH6 = { fg = "${green}", italic = true }, 351 | ["@markup.heading.1"] = { link = "htmlH1" }, 352 | markdownH1 = { link = "htmlH1" }, 353 | ["@markup.heading.2"] = { link = "htmlH2" }, 354 | markdownH2 = { link = "htmlH2" }, 355 | ["@markup.heading.3"] = { link = "htmlH3" }, 356 | markdownH3 = { link = "htmlH3" }, 357 | ["@markup.heading.4"] = { link = "htmlH4" }, 358 | markdownH4 = { link = "htmlH4" }, 359 | ["@markup.heading.5"] = { link = "htmlH5" }, 360 | markdownH5 = { link = "htmlH5" }, 361 | ["@markup.heading.6"] = { link = "htmlH6" }, 362 | markdownH6 = { link = "htmlH6" }, 363 | 364 | htmlBold = { fg = "#ffffff", bold = true }, 365 | markdownBold = { link = "htmlBold" }, 366 | ["@markup.strong"] = { link = "htmlBold" }, 367 | 368 | 369 | htmlItalic = { fg = "#eeeeee", italic = true }, 370 | markdownItalic = { link = "htmlItalic" }, 371 | ["@markup.italic"] = { link = "htmlItalic" }, 372 | 373 | htmlBoldItalic = { fg = "#ffffff", bold = true, italic = true }, 374 | markdownBoldItalic = { link = "htmlBoldItalic" }, 375 | 376 | ["@markup.underline"] = { underline = true }, 377 | 378 | markdownStrikethrough = { fg = "${comment}", style = "strikethrough" }, 379 | ["@strikethrough.markdown_inline"] = { link = "markdownStrikethrough" }, 380 | ["@markup.strikethrough"] = { link = "markdownStrikethrough" }, 381 | 382 | SpellBad = { style = "undercurl", sp = "${red}" }, 383 | SpellCap = { style = "undercurl", sp = "${cyan}" }, 384 | SpellRare = { style = "undercurl", sp = "Magenta" }, 385 | SpellLocal = { style = "undercurl", sp = "${cyan}" }, 386 | MatchParen = { bg = "#555555", italic = true }, 387 | IndentBlanklineChar = { fg = "#444444" }, 388 | -- Todo = { fg = "#282c34", bg = "${highlight}", bold = true }, 389 | VertSplit = { fg = "#202020", bg = "#606060" }, 390 | Folded = { fg = "#c0c8d0", bg = "#384058" }, 391 | ["@comment.markdown"] = { fg = "${comment}" }, 392 | ["@field.markdown_inline"] = { fg = "${purple}" }, 393 | ["@markup.raw"] = { fg = "${green}" }, 394 | ["@markup.raw.block"] = { fg = "${green}" }, 395 | 396 | 397 | ["@tag"] = { fg = "${comment}" }, 398 | ["@block_quote.markdown"] = { fg = "${purple}", italic = true }, 399 | -- ["@parameter.markdown_inline"] = { fg = theme.palette.fg }, 400 | ["@punctuation.special.markdown"] = { fg = "${cyan}" }, 401 | ["@punctuation.delimiter.markdown_inline"] = { fg = "${orange}" }, 402 | 403 | ["@markup.list.unchecked"] = { fg = "#ffffff", bg = "", bold = true }, 404 | 405 | ["@markup.list.checked"] = { fg = "${green}", bold = true }, 406 | 407 | -- TelescopeBorder = { 408 | -- fg = "${telescope_results}", 409 | -- bg = "${telescope_results}" 410 | -- }, 411 | -- TelescopePromptBorder = { 412 | -- fg = "${telescope_prompt}", 413 | -- bg = "${telescope_prompt}" 414 | -- }, 415 | -- TelescopePromptCounter = { fg = "${fg}" }, 416 | -- TelescopePromptNormal = { fg = "${fg}", bg = "${telescope_prompt}" }, 417 | -- TelescopePromptPrefix = { fg = "${purple}", bg = "${telescope_prompt}" }, 418 | -- TelescopePromptTitle = { fg = "${telescope_prompt}", bg = "${purple}" }, 419 | -- 420 | -- TelescopePreviewTitle = { fg = "${telescope_results}", bg = "${green}" }, 421 | -- TelescopeResultsTitle = { 422 | -- fg = "${telescope_results}", 423 | -- bg = "${telescope_results}" 424 | -- }, 425 | 426 | -- TelescopeMatching = { fg = "${blue}" }, 427 | -- TelescopeNormal = { bg = "#000000" }, 428 | -- TelescopeSelection = { bg = "${telescope_prompt}" }, 429 | -- PmenuSel = { blend = 0 }, 430 | }, 431 | styles = { -- Choose from "bold,italic,underline" 432 | virtual_text = "italic" -- Style that is applied to virtual text 433 | }, 434 | plugins = { all = true }, 435 | options = { 436 | bold = not SimpleUI, 437 | italic = not SimpleUI, 438 | underline = not SimpleUI, 439 | undercurl = not SimpleUI, 440 | cursorline = true, 441 | transparency = false, -- better to let neovide define 442 | terminal_colors = true, -- leave terminal windows alone 443 | highlight_inactive_windows = true 444 | }, 445 | colors = { 446 | onedark = { 447 | -- Make neovide have a more distinctive blue bg color 448 | bg = (vim.g.neovide and "#16233B" or "#282c34"), 449 | cursorline = (vim.g.neovide and "#131F34" or "#2d313b"), 450 | -- telescope_prompt = "#2e323a", 451 | -- telescope_results = "#21252d" 452 | }, 453 | -- onelight = { telescope_prompt = "#f5f5f5", telescope_results = "#eeeeee" } 454 | } 455 | }) 456 | end 457 | 458 | local cscheme 459 | if SimpleUI then 460 | cscheme = "ir_black" 461 | else 462 | cscheme = "onedark" 463 | end 464 | vim.cmd.colorscheme(cscheme) 465 | end 466 | 467 | M.defaultFontSize = function() 468 | if vim.fn.has('mac') == 1 then 469 | return "18" 470 | else 471 | return "9" 472 | end 473 | end 474 | 475 | M.isGuiRunning = function() 476 | return vim.fn.has('gui_running') > 0 or vim.g.neovide or vim.g.GuiLoaded ~= nil or vim.fn.has('gui') > 0 477 | end 478 | 479 | M.gui = function() 480 | vim.opt.title = true 481 | vim.opt.switchbuf = "useopen,usetab,newtab" 482 | -- vim.opt.guifont = "Liga DejaVuSansMono Nerd Font:h16" 483 | -- vim.opt.guifont = "FiraCode Nerd Font:h16" -- no italics 484 | -- if vim.loop.os_uname().sysname == "Darwin" then 485 | vim.opt.guifont = "Hasklug Nerd Font:h" .. M.defaultFontSize() 486 | 487 | if vim.g.neovide then 488 | vim.opt.winblend = 30 -- floating transparency amount 489 | vim.opt.pumblend = 30 -- popup menu transparency amount 490 | vim.opt.linespace = 2 491 | vim.g.neovide_opacity = 0.92 492 | -- vim.g.transparency = 0.92 493 | vim.g.neovide_cursor_animation_length = 0.01 494 | vim.g.neovide_cursor_trail_length = 0.1 495 | vim.g.neovide_cursor_antialiasing = true 496 | vim.g.neovide_refresh_rate = 60 497 | vim.g.neovide_remember_window_size = true 498 | vim.g.neovide_input_macos_alt_is_meta = false 499 | vim.g.neovide_hide_mouse_when_typing = false 500 | --vim.g.neovide_background_color = "#131F34EA" --EA -- note: for green screen purposes, try "#2a2a2aea" 501 | vim.g.neovide_input_use_logo = true -- enable cmd key on mac; is this needed now? 502 | vim.g.neovide_floating_blur_amount_x = 5.0 503 | vim.g.neovide_floating_blur_amount_y = 5.0 504 | end 505 | 506 | vim.opt.mouse = 507 | "nv" -- only use mouse in normal and visual modes (notably not insert and command) 508 | vim.opt.mousemodel = "popup_setpos" 509 | -- use the system clipboard for all unnamed yank operations 510 | vim.opt.clipboard = "unnamedplus" 511 | vim.cmd([[set guioptions="gmrLae"]]) 512 | 513 | -- nvim-qt options 514 | -- Disable GUI Tabline 515 | vim.api.nvim_exec2([[ 516 | if exists(':GuiTabline') 517 | GuiTabline 0 518 | endif 519 | ]], { output = false }) 520 | end 521 | 522 | M.twospaceindent = function() 523 | vim.bo.textwidth = 0 524 | vim.bo.tabstop = 2 525 | vim.bo.shiftwidth = 2 526 | vim.bo.softtabstop = 2 527 | vim.bo.expandtab = true -- turn tabs to spaces by default 528 | vim.bo.autoindent = true 529 | -- vim.cmd('retab') 530 | end 531 | 532 | M.fourspaceindent = function() 533 | vim.bo.textwidth = 0 534 | vim.bo.tabstop = 4 535 | vim.bo.shiftwidth = 4 536 | vim.bo.softtabstop = 4 537 | vim.bo.expandtab = true -- turn tabs to spaces by default 538 | vim.bo.autoindent = true 539 | -- vim.cmd('retab') 540 | end 541 | 542 | M.tabindent = function() 543 | vim.bo.textwidth = 0 544 | vim.bo.tabstop = 4 545 | vim.bo.shiftwidth = 4 546 | vim.bo.softtabstop = 4 547 | vim.bo.expandtab = false -- don't turn tabs to spaces 548 | vim.bo.autoindent = true 549 | end 550 | 551 | M.retab = function() vim.cmd('%retab!') end 552 | 553 | M.programming = function(ev) 554 | local bufnr = ev.buf 555 | local mapleadernv = require("pwnvim.mappings").mapleadernv 556 | local mapleadernlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapleadern) 557 | local mapleadervlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapleaderv) 558 | local mapnlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapn) 559 | local mapvlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapv) 560 | local mapnviclocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapnvic) 561 | 562 | vim.opt.number = true 563 | vim.wo.number = true 564 | vim.wo.spell = false 565 | vim.wo.relativenumber = false 566 | vim.wo.cursorline = true -- add indicator for current line 567 | vim.wo.foldexpr = "v:lua.vim.treesitter.foldexpr()" 568 | vim.wo.foldmethod = 569 | "manual" -- seeing weird treesitter cpu spikes when folds are off 570 | vim.wo.foldenable = false -- zi will turn it on 571 | vim.wo.foldcolumn = "0" 572 | 573 | M.twospaceindent() 574 | 575 | -- Could be a performance penalty on this 576 | -- Will make periodic checks to see if the file changed 577 | vim.api.nvim_exec2([[ 578 | augroup programming 579 | autocmd! 580 | autocmd CursorHold,CursorHoldI * silent! checktime 581 | augroup END 582 | ]], { output = false }) 583 | 584 | -- Load direnv when we're in a programming file as we may want 585 | -- the nix environment provided. Run explicitly since the autocmds 586 | -- might not otherwise fire. 587 | vim.g.direnv_auto = 0 588 | vim.cmd('packadd direnv.vim') 589 | local direnvgroup = vim.api.nvim_create_augroup("direnv", { clear = true }) 590 | -- Function below makes direnv impure by design. We need to keep the LSP servers and other nvim dependencies 591 | -- in our path even after direnv overwrites the path. Whatever direnv puts in place will take precedence, but 592 | -- we fall back to the various language tools installed with pwnvim using this hack 593 | local initial_path = vim.env.PATH 594 | vim.api.nvim_create_autocmd("User", { 595 | pattern = "DirenvLoaded", 596 | callback = function() 597 | if not string.find(vim.env.PATH, initial_path, 0, true) then 598 | vim.env.PATH = vim.env.PATH .. ":" .. initial_path 599 | end 600 | end, 601 | group = direnvgroup 602 | }) 603 | vim.cmd('DirenvExport') 604 | 605 | -- commenting 606 | vim.cmd('packadd comment.nvim') 607 | require("Comment").setup() 608 | mapnlocal("g/", "(comment_toggle_linewise_current)", "Toggle comments") 609 | mapvlocal("g/", "(comment_toggle_linewise_visual)", "Toggle comments") 610 | mapleadernlocal("c", "(comment_toggle_linewise_current)", "Toggle comments") 611 | mapleadervlocal("c", "(comment_toggle_linewise_visual)", "Toggle comments") 612 | 613 | mapnviclocal("", "make", "Build program") 614 | 615 | vim.cmd('packadd crates.nvim') 616 | require("crates").setup({}) 617 | 618 | vim.cmd('packadd todo-comments.nvim') 619 | require("pwnvim.plugins.todo-comments") 620 | 621 | local dap, dapui = require("dap"), require("dapui") 622 | dapui.setup() 623 | mapleadernlocal("dv", function() 624 | if dap.session() == nil then 625 | dap.continue() 626 | else 627 | dapui.toggle() 628 | end 629 | end 630 | , "Toggle dap debugger") 631 | mapleadervlocal("dv", dapui.eval, "dap debugger eval selection") 632 | local add_debugger_bindings = function() 633 | mapleadernv("dc", dap.continue, "Continue") 634 | mapleadernv("", dap.continue, "Continue") 635 | mapleadernv("do", dap.step_over, "Step over") 636 | mapleadernv("", dap.step_over, "Step over") 637 | mapleadernv("di", dap.step_into, "Step into") 638 | mapleadernv("", dap.step_into, "Step into") 639 | mapleadernv("du", dap.step_out, "Step up/out") 640 | mapleadernv("", dap.step_out, "Step up/out") 641 | mapleadernv("db", dap.toggle_breakpoint, "Toggle breakpoint") 642 | mapleadernv("dB", dap.set_breakpoint, "Set breakpoint") 643 | mapleadernv("dr", dap.repl.open, "Open REPL") 644 | mapleadernv("dl", dap.run_last, "Run last") 645 | mapleadernv("dh", require("dap.ui.widgets").hover, "Hover widget") 646 | mapleadernv("dp", require("dap.ui.widgets").preview, "Preview widget") 647 | end 648 | dap.listeners.before.attach.dapui_config = function() 649 | add_debugger_bindings() 650 | dapui.open() 651 | end 652 | dap.listeners.before.launch.dapui_config = function() 653 | add_debugger_bindings() 654 | dapui.open() 655 | end 656 | dap.listeners.before.event_terminated.dapui_config = function() 657 | dapui.close() 658 | end 659 | dap.listeners.before.event_exited.dapui_config = function() 660 | dapui.close() 661 | end 662 | end 663 | 664 | return M 665 | -------------------------------------------------------------------------------- /pwnvim/plugins.lua: -------------------------------------------------------------------------------- 1 | -- This is a mega file. Rather than make each plugin have its own config file, 2 | -- which is how I managed my packer-based nvim config prior to Nix, I'm 3 | -- putting everything in here in sections and themed functions. It just makes it 4 | -- easier for me to quickly update things and it's cleaner when there's 5 | -- interdependencies between plugins. We'll see how it goes. 6 | local M = {} 7 | 8 | local signs = require("pwnvim.signs") 9 | 10 | ----------------------- UI -------------------------------- 11 | -- Tree, GitSigns, Indent markers, Colorizer, bufferline, lualine, treesitter 12 | M.ui = function() 13 | require("pwnvim.plugins.nvim-tree") 14 | 15 | -- dadbod-ui 16 | -- vim.g.db_ui_use_nerd_fonts = not SimpleUI 17 | -- vim.g.db_ui_use_nvim_notify = true 18 | 19 | local surround_defaults = require("nvim-surround.config").default_opts 20 | require("nvim-surround").setup({ 21 | aliases = { 22 | ["e"] = "**", -- e for emphasis -- bold in markdown 23 | ["a"] = ">", 24 | ["b"] = ")", 25 | ["B"] = "}", 26 | ["r"] = "]", 27 | ["q"] = { '"', "'", "`" }, 28 | ["s"] = { "}", "]", ")", ">", '"', "'", "`" }, 29 | }, 30 | keymaps = { 31 | insert = "s", 32 | insert_line = "S", 33 | normal = "ys", 34 | -- normal_cur = "yss", 35 | normal_line = "yS", 36 | -- normal_cur_line = "ySS", 37 | visual = "S", 38 | visual_line = "gS", 39 | delete = "ds", 40 | change = "cs", 41 | change_line = "cS", 42 | }, 43 | surrounds = surround_defaults.surrounds, 44 | highlight = { duration = 1 }, 45 | move_cursor = "begin", 46 | indent_lines = surround_defaults.indent_lines 47 | }) 48 | 49 | require("pwnvim.plugins.gitsigns") 50 | require("diffview").setup({}) 51 | vim.g.git_worktree = { 52 | change_directory_command = "lcd", 53 | update_on_change = true, 54 | update_on_change_command = "e .", 55 | confirm_telescope_deletions = true, 56 | clearjumps_on_change = true, 57 | autopush = false 58 | } 59 | 60 | 61 | if not SimpleUI then 62 | require("colorizer").setup({}) 63 | require("dressing").setup({ 64 | input = { 65 | enabled = true, -- Set to false to disable the vim.ui.input implementation 66 | default_prompt = "Input:", 67 | prefer_width = 50, 68 | relative = "win", 69 | insert_only = true, -- When true, will close the modal 70 | start_in_insert = true, -- ready for input immediately 71 | }, 72 | select = { 73 | -- Set to false to disable the vim.ui.select implementation 74 | enabled = true, 75 | backend = { "telescope", "nui", "builtin" }, 76 | telescope = require('telescope.themes').get_dropdown() 77 | } 78 | 79 | }) 80 | require('marks').setup { 81 | -- whether to map keybinds or not. default true 82 | default_mappings = false, 83 | -- which builtin marks to show. default {} 84 | builtin_marks = { "<", ">", "^", ";", "'" }, 85 | -- whether movements cycle back to the beginning/end of buffer. default true 86 | cyclic = true, 87 | -- whether the shada file is updated after modifying uppercase marks. default false 88 | force_write_shada = false, 89 | -- how often (in ms) to redraw signs/recompute mark positions. 90 | -- higher values will have better performance but may cause visual lag, 91 | -- while lower values may cause performance penalties. default 150. 92 | refresh_interval = 250, 93 | -- sign priorities for each type of mark - builtin marks, uppercase marks, lowercase 94 | -- marks, and bookmarks. 95 | -- can be either a table with all/none of the keys, or a single number, in which case 96 | -- the priority applies to all marks. 97 | -- default 10. 98 | sign_priority = { lower = 10, upper = 15, builtin = 8, bookmark = 20 }, 99 | -- disables mark tracking for specific filetypes. default {} 100 | excluded_filetypes = {}, 101 | -- marks.nvim allows you to configure up to 10 bookmark groups, each with its own 102 | -- sign/virttext. Bookmarks can be used to group together positions and quickly move 103 | -- across multiple buffers. default sign is '!@#$%^&*()' (from 0 to 9), and 104 | -- default virt_text is "". 105 | -- bookmark_0 = { 106 | -- sign = "⚑", 107 | -- virt_text = "hello world", 108 | -- explicitly prompt for a virtual line annotation when setting a bookmark from this group. 109 | -- defaults to false. 110 | -- annotate = false, 111 | -- }, 112 | mappings = { 113 | -- delete_line = "dm-", 114 | -- delete = "dm", 115 | preview = "m:", 116 | next = "]'", 117 | prev = "['" 118 | } 119 | } 120 | end 121 | 122 | require("pwnvim.plugins.lualine") 123 | require("pwnvim.plugins.treesitter") 124 | -- require("pwnvim.plugins.bufferline") 125 | require("pwnvim.plugins.indent-blankline") 126 | require("flash").setup({ 127 | modes = { 128 | char = { 129 | enabled = false, -- actually slowing me down :( 130 | jump_labels = true, 131 | autohide = true, 132 | keys = { "f", "F", "t", "T", ";" }, -- needed to remove "," as that is our mapleader 133 | highlight = { backdrop = false }, 134 | char_actions = function(motion) 135 | return { 136 | [";"] = "next", -- set to `right` to always go right 137 | -- [","] = "prev", -- set to `left` to always go left 138 | [motion:lower()] = "next", 139 | [motion:upper()] = "prev" 140 | } 141 | end 142 | } 143 | } 144 | }) 145 | 146 | -- Replacement for barbecue provides breadcrumbs in top line 147 | -- catppuccin green #a6da95 148 | -- catppuccin red #ed8796 149 | -- catppuccin mauve #c6a0f6 150 | vim.api.nvim_set_hl(0, 'DropBarKindFile', { fg = '#c6a0f6', italic = false, bold = true }) 151 | vim.api.nvim_set_hl(0, 'DropBarFileNameDirty', { fg = '#ed8796', italic = true, bold = true }) 152 | require("dropbar").setup({ 153 | bar = { 154 | -- below adds dropbar to oil windows 155 | enable = function(buf, win, _) 156 | if 157 | not vim.api.nvim_buf_is_valid(buf) 158 | or not vim.api.nvim_win_is_valid(win) 159 | or vim.fn.win_gettype(win) ~= '' 160 | or vim.wo[win].winbar ~= '' 161 | or vim.bo[buf].ft == 'help' 162 | then 163 | return false 164 | end 165 | 166 | local stat = vim.uv.fs_stat(vim.api.nvim_buf_get_name(buf)) 167 | if stat and stat.size > 1024 * 1024 then 168 | return false 169 | end 170 | 171 | return vim.bo[buf].ft == 'markdown' 172 | or vim.bo[buf].ft == 'oil' -- enable in oil buffers 173 | or vim.bo[buf].ft == 'fugitive' -- enable in fugitive buffers 174 | or pcall(vim.treesitter.get_parser, buf) 175 | or not vim.tbl_isempty(vim.lsp.get_clients({ 176 | bufnr = buf, 177 | method = 'textDocument/documentSymbol', 178 | })) 179 | end, 180 | truncate = false, 181 | update_debounce = 50, 182 | update_events = { 183 | buf = { 184 | 'BufModifiedSet', 185 | 'FileChangedShellPost', 186 | 'TextChanged', 187 | --'ModeChanged', -- Don't know why modechanged is needed 188 | } 189 | }, 190 | }, 191 | 192 | sources = { 193 | path = { 194 | max_depth = 7, 195 | modified = function(sym) 196 | return sym:merge({ 197 | name = sym.name .. ' [+]', 198 | -- icon = ' ', 199 | icon = '', 200 | name_hl = 'DropBarFileNameDirty', 201 | icon_hl = 'DropBarFileNameDirty', 202 | }) 203 | end, 204 | } 205 | } 206 | }) 207 | end -- UI setup 208 | 209 | 210 | ----------------------- DIAGNOSTICS -------------------------------- 211 | M.diagnostics = function() 212 | -- IMPORTANT: make sure to setup neodev BEFORE lspconfig 213 | require("neodev").setup({ 214 | -- help for neovim lua api 215 | override = function(root_dir, library) 216 | if string.match(root_dir, "neovim") or 217 | string.match(root_dir, "pwnvim") or 218 | string.match(root_dir, "lua") then 219 | library.enabled = true 220 | library.plugins = true 221 | library.types = true 222 | library.runtime = true 223 | end 224 | end, 225 | lspconfig = true 226 | }) 227 | 228 | if not SimpleUI then 229 | require("notify").setup({ 230 | stages = "static", 231 | timeout = 5000, 232 | }) 233 | require("noice").setup({ 234 | lsp = { 235 | -- override markdown rendering so that **cmp** and other plugins use **Treesitter** 236 | override = { 237 | -- ["vim.lsp.util.convert_input_to_markdown_lines"] = true, 238 | ["vim.lsp.util.stylize_markdown"] = false, 239 | ["cmp.entry.get_documentation"] = true 240 | }, 241 | progress = { 242 | enabled = true, 243 | -- Lsp Progress is formatted using the builtins for lsp_progress. See config.format.builtin 244 | -- See the section on formatting for more details on how to customize. 245 | --- @type NoiceFormat|string 246 | format = "lsp_progress", 247 | --- @type NoiceFormat|string 248 | format_done = "lsp_progress_done", 249 | throttle = 1000 / 30, -- frequency to update lsp progress message 250 | view = "mini" 251 | }, 252 | hover = { 253 | enabled = true, 254 | silent = false, -- set to true to not show a message if hover is not available 255 | view = nil, -- when nil, use defaults from documentation 256 | ---@type NoiceViewOptions 257 | opts = {} -- merged with defaults from documentation 258 | }, 259 | documentation = { 260 | view = "hover", 261 | }, 262 | signature = { 263 | enabled = true, 264 | auto_open = { 265 | enabled = true, 266 | trigger = true, -- Automatically show signature help when typing a trigger character from the LSP 267 | luasnip = false, -- Will open signature help when jumping to Luasnip insert nodes 268 | throttle = 50 -- Debounce lsp signature help request by 50ms 269 | }, 270 | view = nil, -- when nil, use defaults from documentation 271 | ---@type NoiceViewOptions 272 | opts = {} -- merged with defaults from documentation 273 | }, 274 | message = { 275 | -- Messages shown by lsp servers 276 | enabled = true, 277 | view = "notify", 278 | opts = {} 279 | } 280 | }, 281 | -- you can enable a preset for easier configuration 282 | presets = { 283 | bottom_search = true, -- use a classic bottom cmdline for search 284 | command_palette = false, -- position the cmdline and popupmenu together 285 | long_message_to_split = true, -- long messages will be sent to a split 286 | inc_rename = false, -- enables an input dialog for inc-rename.nvim 287 | lsp_doc_border = true -- add a border to hover docs and signature help 288 | }, 289 | cmdline = { enabled = true, view = "cmdline", format = { conceal = false } }, 290 | messages = { 291 | enabled = true, 292 | view = "mini", 293 | view_error = "notify", 294 | view_warn = "notify", 295 | view_history = "messages", -- view for :messages 296 | view_search = "virtualtext" 297 | }, 298 | popupmenu = { enabled = true, backend = "nui" }, 299 | notify = { 300 | -- Noice can be used as `vim.notify` so you can route any notification like other messages 301 | -- Notification messages have their level and other properties set. 302 | -- event is always "notify" and kind can be any log level as a string 303 | -- The default routes will forward notifications to nvim-notify 304 | -- Benefit of using Noice for this is the routing and consistent history view 305 | enabled = true, 306 | view = "notify" 307 | }, 308 | routes = { 309 | { 310 | filter = { event = "msg_show", kind = "search_count" }, 311 | opts = { skip = true }, 312 | }, 313 | -- always route any messages with more than 20 lines to the split view 314 | { 315 | view = "split", 316 | filter = { event = "msg_show", min_height = 20 }, 317 | }, 318 | -- suppress "E36: Not enough room" error 319 | { filter = { event = "msg_show", find = "E36" }, opts = { skip = true } }, 320 | -- suppress "semantic_tokens.lua" error 321 | { filter = { event = "msg_show", find = "semantic_tokens.lua" }, opts = { skip = true } } 322 | }, 323 | }) 324 | end 325 | 326 | vim.diagnostic.config({ 327 | virtual_text = false, 328 | signs = { active = { signs.signs } }, 329 | update_in_insert = false, 330 | underline = true, 331 | severity_sort = true, 332 | float = { 333 | focusable = false, 334 | style = "minimal", 335 | border = "rounded", 336 | source = "always", 337 | header = "", 338 | prefix = "" 339 | } 340 | }) 341 | -- off with noice on instead now 342 | -- vim.lsp.handlers["textDocument/hover"] = vim.lsp.with( 343 | -- vim.lsp.handlers.hover, 344 | -- { border = "rounded" }) 345 | 346 | -- vim.lsp.handlers["textDocument/signatureHelp"] = 347 | -- vim.lsp.with(vim.lsp.handlers.signature_help, { border = "rounded" }) 348 | 349 | require("trouble").setup({ 350 | group = true, -- group results by file 351 | --icons = true, 352 | auto_preview = true, 353 | auto_close = true, 354 | signs = { 355 | error = signs.error, 356 | warning = signs.warn, 357 | hint = signs.hint, 358 | information = signs.info, 359 | other = "﫠" 360 | }, 361 | action_keys = { 362 | close = { "q", "" } 363 | } 364 | }) 365 | 366 | local function attached(client, bufnr) 367 | local mapleadernvlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapleadernv) 368 | local mapleadernlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapleadern) 369 | local mapleadervlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapleaderv) 370 | local mapnviclocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapnvic) 371 | local mapnlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapn) 372 | 373 | local builtin = require("telescope.builtin") 374 | 375 | vim.api.nvim_set_option_value("omnifunc", "v:lua.vim.lsp.omnifunc", { buf = bufnr }) 376 | vim.api.nvim_set_option_value("tagfunc", "v:lua.vim.lsp.tagfunc", { buf = bufnr }) 377 | 378 | mapleadernlocal("le", vim.diagnostic.open_float, "Show Line Diags") 379 | -- 380 | -- There should be a check on this for server_capabilities.inlayHint, but that doesn't exist and 381 | -- I should probably differentiate between inline hints and inline diagnostics, but for now, 382 | -- either all on or all off 383 | mapleadernvlocal("ll", function() 384 | -- the scope filter is supported in diagnostics, but not yet in inlay hints as far as I know, but 385 | -- i'm adding it so things will improve when nvim does 386 | vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled(), { bufnr = 0, scope = "line" }) 387 | vim.diagnostic.config({ virtual_text = vim.lsp.inlay_hint.is_enabled() }) 388 | end, "Toggle virtual text lines") 389 | 390 | if vim.bo[bufnr].filetype == "rust" then 391 | mapleadernlocal("rr", "RustLsp runnables", "Runnables") 392 | mapleadernlocal("rt", "RustLsp testables", "Testables") 393 | mapleadernlocal("re", "RustLsp explainError", "Explain error") 394 | mapleadernlocal("rh", "RustLsp hover actions", "Rust hover actions") 395 | mapleadervlocal("rh", "RustLsp hover range", "Rust hover") 396 | mapleadernlocal("ra", "RustLsp codeAction", "Rust code actions") 397 | mapleadernlocal("rd", "RustLsp openDocs", "Rust docs for symbol under cursor") 398 | end 399 | 400 | -- Set some keybinds conditional on server capabilities 401 | if client.server_capabilities.definitionProvider or client.server_capabilities.typeDefinitionProvider then 402 | mapleadernlocal("ld", vim.lsp.buf.definition, "Go to definition") 403 | -- override standard tag jump c-] for go to definition 404 | mapnlocal("", vim.lsp.buf.definition, "Go to definition") 405 | end 406 | 407 | if client.server_capabilities.codeActionProvider then 408 | mapleadernlocal("lf", vim.lsp.buf.code_action, "Fix code actions") 409 | -- range parameter is automatically populated in visual mode 410 | mapleadervlocal("lf", vim.lsp.buf.code_action, "Fix code actions (range)") 411 | end 412 | 413 | if client.server_capabilities.implementationProvider then 414 | mapleadernlocal("lD", vim.lsp.buf.implementation, "Implementation") 415 | end 416 | 417 | if client.server_capabilities.signatureHelpProvider then 418 | mapleadernlocal("lt", vim.lsp.buf.signature_help, "Signature") 419 | end 420 | 421 | if client.server_capabilities.hoverProvider or client.server_capabilities.hover then 422 | mapleadernlocal("li", vim.lsp.buf.hover, "Info hover") 423 | mapnlocal("K", vim.lsp.buf.hover, "Info hover") 424 | end 425 | 426 | if client.server_capabilities.documentFormattingProvider then 427 | mapleadernlocal("l=", vim.lsp.buf.format, "Format file") 428 | vim.bo.formatexpr = 'v:lua.vim.lsp.formatexpr(#{timeout_ms:500})' 429 | -- vim.api.nvim_buf_set_option(bufnr, 'formatexpr', 'v:lua.vim.lsp.formatexpr(#{timeout_ms:500})') 430 | end 431 | 432 | if client.server_capabilities.documentRangeFormattingProvider then 433 | -- range parameter is automatically populated in visual mode 434 | mapleadervlocal("l=", vim.lsp.buf.format, "Format range") 435 | end 436 | 437 | if client.server_capabilities.references or client.server_capabilities.referencesProvider then 438 | mapleadernlocal("lr", builtin.lsp_references, "References") 439 | end 440 | 441 | if client.server_capabilities.documentSymbolProvider then 442 | -- print("GOT documentSymbolProvider") 443 | require("nvim-navic").attach(client, bufnr) -- setup context showing header line 444 | require("nvim-navbuddy").attach(client, bufnr) -- setup popup for browsing symbols 445 | -- mapleadernlocal("lsd", builtin.lsp_document_symbols, "Find symbol in document") 446 | mapleadernlocal("lsd", require("nvim-navbuddy").open, "Find symbol in document") 447 | -- if vim.bo[bufnr].filetype ~= "markdown" then 448 | -- Sometimes other LSPs attach to markdown (like tailwindcss) and so we have a race to see which F7 will win... 449 | mapnviclocal("", require("nvim-navbuddy").open, "Browse document symbols") 450 | -- end 451 | end 452 | 453 | if client.server_capabilities.workspaceSymbolProvider then 454 | mapleadernlocal("lsw", builtin.lsp_workspace_symbols, "Find symbol in workspace") 455 | end 456 | 457 | if client.server_capabilities.implementationProvider or client.server_capabilities.implementation then 458 | mapleadernlocal("lI", require("telescope.builtin").lsp_implementations, "Implementations") 459 | end 460 | 461 | if client.server_capabilities.renameProvider or client.server_capabilities.rename then 462 | mapleadernlocal("lR", vim.lsp.buf.rename, "Rename") 463 | end 464 | 465 | -- Below is only possible because of nvim-ufo 466 | -- Not supported in neovim yet; see https://github.com/neovim/neovim/pull/14306 467 | if client.server_capabilities.foldingRangeProvider and vim.bo[bufnr].filetype ~= "markdown" then 468 | mapnlocal('zR', require("ufo").openAllFolds, "Open all folds") 469 | mapnlocal('zM', require("ufo").closeAllFolds, "Close all folds") 470 | mapnlocal('zr', require('ufo').openFoldsExceptKinds, "Fold less") 471 | mapnlocal('zm', require('ufo').closeFoldsWith, "Fold more") 472 | end 473 | 474 | require("which-key").add({ 475 | mode = { "n", "v" }, 476 | { "ls", group = "symbols" }, 477 | { "lc", group = "change" }, 478 | }) 479 | end 480 | 481 | -- Allow LSP based folding, then fall back to treesitter and indent 482 | -- Special handling for markdown for now 483 | require('ufo').setup({ 484 | provider_selector = function(bufnr, filetype, _) 485 | local ufoFt = { 486 | markdown = "", -- no ufo for markdown 487 | [""] = "" -- no ufo for blank docs 488 | } 489 | local function customizeSelector() 490 | local function handleFallbackException(err, providerName) 491 | if type(err) == 'string' and err:match('UfoFallbackException') then 492 | return require('ufo').getFolds(providerName, bufnr) 493 | else 494 | return require('promise').reject(err) 495 | end 496 | end 497 | 498 | return require('ufo').getFolds('lsp', bufnr):catch(function(err) 499 | return handleFallbackException(err, 'treesitter') 500 | end):catch(function(err) 501 | return handleFallbackException(err, 'indent') 502 | end) 503 | end 504 | return ufoFt[filetype] or customizeSelector 505 | end 506 | }) 507 | 508 | require('lint').linters_by_ft = { 509 | markdown = { 'vale' }, 510 | -- NOTE: prettier is no longer a stock option 511 | -- css = { 'prettier' }, 512 | -- svelte = { 'eslint_d' }, 513 | python = { "mypy", "ruff" }, 514 | nix = { "statix" }, 515 | bash = { "shellcheck" }, 516 | -- typescript = { "eslint_d", "prettier" }, 517 | -- javascript = { "eslint_d", "prettier" }, 518 | -- rust = { "rustfmt" } 519 | } 520 | 521 | require("conform").setup({ -- use formatter.nvim instead? 522 | notify_on_error = true, 523 | format_on_save = { 524 | -- These options will be passed to conform.format() 525 | timeout_ms = 800, 526 | lsp_fallback = true -- if no defined or available formatter, try lsp formatter 527 | }, 528 | formatters = { 529 | prettier = { 530 | -- below path set in init.lua which is made in flake.nix 531 | command = prettier_path, 532 | args = { "--stdin-filepath", "$FILENAME", "--tab-width", "2" } 533 | }, 534 | lua_format = { 535 | command = "lua-format", 536 | args = { "-i", "--no-use-tab", "--indent-width=2" }, 537 | stdin = true 538 | }, 539 | alejandra = { 540 | command = "alejandra", 541 | args = { "-q", "-q" } 542 | } 543 | 544 | }, 545 | formatters_by_ft = { 546 | -- lua = {{"lua_format", "stylua"}}, 547 | python = { "black" }, 548 | -- Use a sub-list to run only the first available formatter 549 | -- javascript = { "prettier", "eslint_d" }, -- handled by lsp 550 | -- javascriptreact = { "prettier", "eslint_d" }, -- handled by lsp 551 | -- typescript = { "prettier", "eslint_d" }, -- handled by lsp 552 | -- typescriptreact = { "prettier", "eslint_d" }, -- handled by lsp 553 | vue = { "prettier", "eslint_d" }, 554 | scss = { "prettier", "eslint_d" }, 555 | html = { "prettier", "eslint_d" }, 556 | css = { "prettier", "eslint_d" }, 557 | json = { "prettier", "eslint_d" }, 558 | jsonc = { "prettier", "eslint_d" }, 559 | yaml = { "prettier", "eslint_d" }, 560 | -- svelte = { { "prettier", "eslint_d" } }, -- handled by lsp 561 | nix = { "alejandra" } 562 | } 563 | }) 564 | vim.api.nvim_create_autocmd({ "BufWritePost" }, { 565 | callback = function() require("lint").try_lint() end 566 | }) 567 | 568 | local lspconfig = require("lspconfig") 569 | local cmp_nvim_lsp = require("cmp_nvim_lsp") 570 | 571 | local capabilities = vim.tbl_extend("keep", vim.lsp.protocol 572 | .make_client_capabilities(), 573 | cmp_nvim_lsp.default_capabilities()) 574 | -- Add client folding capability, which is provided by nvim-ufo 575 | capabilities.textDocument.foldingRange = { 576 | dynamicRegistration = false, 577 | lineFoldingOnly = true 578 | } 579 | vim.g.rustaceanvim = (function() 580 | local uname = vim.uv.os_uname().sysname 581 | 582 | local codelldb_path = lldb_path_base .. "/share/vscode/extensions/vadimcn.vscode-lldb/adapter/codelldb" 583 | local codelldb_lib = lldb_path_base .. 584 | "/share/vscode/extensions/vadimcn.vscode-lldb/adapter/libcodelldb" .. (uname == "Linux" and ".so" or ".dylib") 585 | local cfg = require('rustaceanvim.config') 586 | return { 587 | dap = { 588 | adapter = cfg.get_codelldb_adapter(codelldb_path, codelldb_lib), 589 | autoload_configurations = true, 590 | configuration = { 591 | stopOnEntry = true, 592 | }, 593 | load_rust_types = true, 594 | }, 595 | tools = { 596 | -- test_executor = 'background' 597 | }, 598 | server = { 599 | on_attach = attached, 600 | capabilities = capabilities, 601 | default_settings = { 602 | ["rust-analyzer"] = { 603 | files = { excludeDirs = { ".direnv" } }, 604 | cargo = { 605 | allFeatures = true, 606 | }, 607 | checkOnSave = { 608 | command = 'clippy', 609 | }, 610 | diagnostics = { 611 | enable = true, 612 | experimental = { 613 | enable = true, 614 | } 615 | } 616 | } 617 | } 618 | } 619 | } 620 | end)() 621 | 622 | -- Fix an issue with current rust analyzer by suppressing a bogus message 623 | -- See https://github.com/neovim/neovim/issues/30985 624 | for _, method in ipairs({ 'textDocument/diagnostic', 'workspace/diagnostic' }) do 625 | local default_diagnostic_handler = vim.lsp.handlers[method] 626 | vim.lsp.handlers[method] = function(err, result, context, config) 627 | if err ~= nil and err.code == -32802 then 628 | return 629 | end 630 | return default_diagnostic_handler(err, result, context, config) 631 | end 632 | end 633 | 634 | 635 | require("cmp-npm").setup({}) 636 | 637 | lspconfig.marksman.setup({ 638 | capabilities = capabilities, 639 | on_attach = attached, 640 | -- root_dir = lspconfig.util.root_pattern('nope'), -- this is a temp fix for an error in the lspconfig for this LS 641 | single_file_support = true, 642 | }) 643 | -- lspconfig.markdown_oxide.setup({ 644 | -- capabilities = capabilities, 645 | -- on_attach = attached, 646 | -- root_dir = lspconfig.util.root_pattern('nope'), -- this is a temp fix for an error in the lspconfig for this LS 647 | -- single_file_support = true, 648 | -- }) 649 | lspconfig.yamlls.setup { 650 | on_attach = attached, 651 | capabilities = capabilities, 652 | settings = { 653 | yaml = { 654 | format = { enable = true }, 655 | schemaStore = { 656 | enable = true 657 | }, 658 | schemas = { 659 | ["https://json.schemastore.org/github-workflow.json"] = "/.github/workflows/*", 660 | ["http://json.schemastore.org/ansible-playbook"] = "*play*.{yml,yaml}", 661 | ["http://json.schemastore.org/ansible-stable-2.9"] = "roles/tasks/*.{yml,yaml}", 662 | ["http://json.schemastore.org/chart"] = "Chart.{yml,yaml}", 663 | ["http://json.schemastore.org/github-action"] = ".github/action.{yml,yaml}", 664 | ["http://json.schemastore.org/github-workflow"] = ".github/workflows/*", 665 | ["http://json.schemastore.org/kustomization"] = "kustomization.{yml,yaml}", 666 | ["http://json.schemastore.org/prettierrc"] = ".prettierrc.{yml,yaml}", 667 | ["https://gitlab.com/gitlab-org/gitlab/-/raw/master/app/assets/javascripts/editor/schema/ci.json"] = "*gitlab-ci*.{yml,yaml}", 668 | ["https://json.schemastore.org/dependabot-v2"] = ".github/dependabot.{yml,yaml}", 669 | ["https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/schemas/v3.1/schema.json"] = "*api*.{yml,yaml}", 670 | ["https://raw.githubusercontent.com/argoproj/argo-workflows/master/api/jsonschema/schema.json"] = "*flow*.{yml,yaml}", 671 | ["https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json"] = "*docker-compose*.{yml,yaml}", 672 | ["https://raw.githubusercontent.com/microsoft/azure-pipelines-vscode/master/service-schema.json"] = "azure-pipelines.yml", 673 | ["kubernetes"] = "*.y{a,}ml" 674 | }, 675 | }, 676 | } 677 | } 678 | lspconfig.ts_ls 679 | .setup({ capabilities = capabilities, on_attach = attached, init_options = { preferences = { disableSuggestions = true, } } }) 680 | 681 | lspconfig.lua_ls.setup({ 682 | on_attach = attached, 683 | capabilities = capabilities, 684 | filetypes = { "lua" }, 685 | settings = { 686 | Lua = { 687 | runtime = { 688 | -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) 689 | version = "LuaJIT" 690 | }, 691 | diagnostics = { 692 | -- Get the language server to recognize the `vim` global 693 | globals = { "vim", "string", "require" } 694 | }, 695 | workspace = { 696 | -- Make the server aware of Neovim runtime files 697 | library = { vim.env.VIMRUNTIME }, 698 | checkThirdParty = false 699 | }, 700 | -- Do not send telemetry data containing a randomized but unique identifier 701 | telemetry = { enable = false }, 702 | completion = { enable = true, callSnippet = "Replace" } 703 | } 704 | } 705 | }) 706 | lspconfig.svelte.setup({ on_attach = attached, capabilities = capabilities }) 707 | -- lspconfig.jinja_lsp.setup({ filetypes = { 'jinja', 'jinja2', 'twig', 'html' } }) 708 | lspconfig.tailwindcss.setup({ 709 | on_attach = attached, 710 | capabilities = capabilities, 711 | root_dir = require("lspconfig/util").root_pattern( 712 | "tailwind.config.js", 713 | "tailwind.config.ts", 714 | "tailwind.config.cjs" 715 | ), 716 | filetypes = { "css", "html", "svelte" }, 717 | settings = { 718 | files = { exclude = { "**/.git/**", "**/node_modules/**", "**/*.md" } } 719 | } 720 | }) 721 | -- nil_ls is a nix lsp 722 | --[[ lspconfig.nil_ls.setup({ 723 | on_attach = attached, 724 | capabilities = capabilities, 725 | settings = { ["nil"] = { nix = { flake = { autoArchive = false } } } } 726 | }) ]] 727 | lspconfig.nixd.setup({ 728 | on_attach = attached, 729 | capabilities = capabilities 730 | }) 731 | lspconfig.cssls.setup({ 732 | on_attach = attached, 733 | capabilities = capabilities, 734 | settings = { css = { lint = { unknownAtRules = "ignore" } } } 735 | }) 736 | lspconfig.eslint.setup({ 737 | on_attach = attached, 738 | capabilities = capabilities, 739 | filetypes = { "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx", "vue", "astro" } -- no svelte 740 | }) 741 | lspconfig.html.setup({ on_attach = attached, capabilities = capabilities }) 742 | lspconfig.bashls.setup({ on_attach = attached, capabilities = capabilities }) 743 | -- TODO: investigate nvim-metals and remove line below 744 | lspconfig.metals.setup({ on_attach = attached, capabilities = capabilities }) -- for scala 745 | lspconfig.pyright.setup({ 746 | on_attach = attached, 747 | capabilities = capabilities, 748 | filetypes = { "python" } 749 | }) -- for python 750 | lspconfig.jsonls.setup({ 751 | on_attach = attached, 752 | settings = { 753 | json = { 754 | schemas = require("schemastore").json.schemas(), 755 | validate = { enable = true } 756 | } 757 | }, 758 | setup = { 759 | commands = { 760 | Format = { 761 | function() 762 | vim.lsp.buf.range_formatting({}, { 0, 0 }, 763 | { vim.fn.line("$"), 0 }) 764 | end 765 | } 766 | } 767 | }, 768 | capabilities = capabilities 769 | }) 770 | require("nvim-lightbulb").setup({ 771 | autocmd = { enabled = true }, 772 | sign = { enabled = true }, 773 | virtual_text = { enabled = false, }, 774 | float = { enabled = false }, 775 | action_kinds = { "quickfix", "source.fixAll" }, 776 | hide_in_unfocused_buffer = true, 777 | }) 778 | end -- Diagnostics setup 779 | 780 | M.llms = function() 781 | local constants = { 782 | LLM_ROLE = "llm", 783 | USER_ROLE = "user", 784 | SYSTEM_ROLE = "system", 785 | } 786 | local fmt = string.format 787 | 788 | -- status is true if the function ran without errors; isOllamaRunning is true if we had a successful connection 789 | -- the on_error function should avoid any errors propagating, but it seems that doesn't always work, hence the pcall 790 | local status, isOllamaRunning = pcall(function() 791 | return require("plenary.curl").get("http://localhost:11434", { 792 | timeout = 50, 793 | on_error = function(e) return { status = e.exit } end, 794 | }).status == 200 795 | end) 796 | 797 | if status and isOllamaRunning then 798 | vim.g.codecompanion_adapter = "ollamacode" 799 | else 800 | vim.g.codecompanion_adapter = "copilot" 801 | end 802 | 803 | require("codecompanion").setup({ 804 | action_palette = { 805 | provider = "telescope" 806 | }, 807 | display = { 808 | chat = { 809 | render_headers = true, 810 | show_settings = false 811 | } 812 | }, 813 | opts = { 814 | log_level = "ERROR", -- TRACE|DEBUG|ERROR|INFO 815 | language = "English", 816 | }, 817 | adapters = { 818 | ollamacode = function() 819 | return require("codecompanion.adapters").extend("ollama", { 820 | name = "ollamacode", 821 | env = { 822 | url = "http://127.0.0.1:11434", 823 | }, 824 | schema = { 825 | model = { 826 | default = "qwen2.5-coder:32b", 827 | }, 828 | }, 829 | headers = { 830 | ["Content-Type"] = "application/json", 831 | }, 832 | parameters = { 833 | sync = true, 834 | }, 835 | }) 836 | end, 837 | ollamaprose = function() 838 | return require("codecompanion.adapters").extend("ollama", { 839 | name = "ollamaprose", 840 | env = { 841 | url = "http://127.0.0.1:11434", 842 | }, 843 | schema = { 844 | model = { 845 | default = "llama3.2:3b", 846 | }, 847 | }, 848 | headers = { 849 | ["Content-Type"] = "application/json", 850 | }, 851 | parameters = { 852 | sync = true, 853 | }, 854 | }) 855 | end, 856 | copilot_o3 = function() 857 | return require("codecompanion.adapters").extend("copilot", { 858 | schema = { 859 | model = { 860 | default = "o3-mini", 861 | }, 862 | }, 863 | }) 864 | end, 865 | openai = function() 866 | return require("codecompanion.adapters").extend("openai", { 867 | schema = { 868 | model = { 869 | default = "o3-mini", 870 | }, 871 | }, 872 | env = { 873 | api_key = "cmd:security find-generic-password -l openaikey -g -w |tr -d '\n'" 874 | } 875 | }) 876 | end, 877 | opts = { 878 | allow_insecure = isOllamaRunning, -- Allow insecure connections? yes if we're using ollama 879 | }, 880 | 881 | }, 882 | strategies = { 883 | chat = { 884 | adapter = (isOllamaRunning and "ollamacode" or "openai"), 885 | }, 886 | inline = { 887 | adapter = (isOllamaRunning and "ollamacode" or "copilot_o3"), 888 | }, 889 | agent = { 890 | adapter = (isOllamaRunning and "ollamacode" or "openai"), 891 | }, 892 | }, 893 | prompt_library = { 894 | ["Summarize"] = { 895 | strategy = "chat", 896 | description = "Summarize some text", 897 | opts = { 898 | index = 3, 899 | is_default = true, 900 | modes = { "v" }, 901 | short_name = "summarize", 902 | is_slash_cmd = false, 903 | auto_submit = true, 904 | user_prompt = false, 905 | stop_context_insertion = true, 906 | }, 907 | prompts = { 908 | { 909 | role = constants.SYSTEM_ROLE, 910 | content = 911 | [[I want you to act as a senior editor at a newspaper whose job is to make short summaries of articles for search engines.]], 912 | opts = { 913 | visible = false, 914 | tag = "system_tag", 915 | }, 916 | }, 917 | { 918 | role = constants.USER_ROLE, 919 | content = function(context) 920 | local prose = require("codecompanion.helpers.actions").get_code(context.start_line, context.end_line) 921 | return fmt( 922 | [[Summarize the contents of the article that starts below the "---". Make your summary be 150 to 170 characters long to fit in a web page meta description: 923 | 924 | --- 925 | %s 926 | 927 | Summarize that in 150 characters. 928 | ]], prose 929 | ) 930 | end 931 | } 932 | }, 933 | } 934 | }, 935 | }) 936 | vim.cmd([[cab cc CodeCompanion]]) 937 | end 938 | 939 | ----------------------- TELESCOPE -------------------------------- 940 | M.telescope = function() 941 | local actions = require("telescope.actions") 942 | local action_state = require("telescope.actions.state") 943 | 944 | local function quicklook_selected_entry(_prompt_bufnr) 945 | local entry = action_state.get_selected_entry() 946 | -- actions.close(prompt_bufnr) 947 | vim.cmd("silent !qlmanage -p '" .. entry.value .. "'") 948 | end 949 | 950 | local function yank_selected_entry(prompt_bufnr) 951 | local entry = action_state.get_selected_entry() 952 | actions.close(prompt_bufnr) 953 | -- Put it in the unnamed buffer and the system clipboard both 954 | vim.api.nvim_call_function("setreg", { '"', entry.value }) 955 | vim.api.nvim_call_function("setreg", { "*", entry.value }) 956 | end 957 | 958 | local function system_open_selected_entry(prompt_bufnr) 959 | local entry = action_state.get_selected_entry() 960 | actions.close(prompt_bufnr) 961 | os.execute("open '" .. entry.value .. "'") 962 | end 963 | 964 | local trouble = require("trouble.sources.telescope") 965 | require("telescope").setup({ 966 | file_ignore_patterns = { 967 | "*.bak", ".git/", "node_modules", ".zk/", "Caches/", "Backups/" 968 | }, 969 | prompt_prefix = SimpleUI and ">" or " ", 970 | selection_caret = SimpleUI and "↪" or " ", 971 | -- path_display = { "smart" }, 972 | defaults = { 973 | winblend = 30, -- small transparency for telescope popups -- should only matter in neovide 974 | path_display = function(_, path) 975 | local tail = require("telescope.utils").path_tail(path) 976 | return string.format("%s (%s)", tail, 977 | require("telescope.utils").path_smart( 978 | path:gsub("/Users/[^/]*/", "~/"):gsub( 979 | "/[^/]*$", ""):gsub( 980 | "/Library/Containers/co.noteplan.NotePlan3/Data/Library/Application Support/co.noteplan.NotePlan3", 981 | "/NotePlan"))) 982 | end, 983 | -- path_display = { "truncate" }, 984 | mappings = { 985 | n = { 986 | [""] = trouble.open, 987 | [""] = yank_selected_entry, 988 | [""] = system_open_selected_entry, 989 | [""] = quicklook_selected_entry, 990 | ["dd"] = require("telescope.actions").delete_buffer, 991 | ["q"] = require("telescope.actions").close 992 | }, 993 | i = { 994 | [""] = trouble.open, 995 | [""] = "which_key", 996 | [""] = yank_selected_entry, 997 | [""] = quicklook_selected_entry, 998 | [""] = system_open_selected_entry 999 | } 1000 | }, 1001 | vimgrep_arguments = { 1002 | "rg", "--color=never", "--no-heading", "--with-filename", 1003 | "--line-number", "--column", "--smart-case" 1004 | }, 1005 | -- Telescope smart history 1006 | history = { 1007 | path = "~/.local/share/nvim/databases/telescope_history.sqlite3", 1008 | limit = 100 1009 | }, 1010 | layout_strategy = "flex", 1011 | layout_config = { 1012 | horizontal = { prompt_position = "bottom", preview_width = 0.55 }, 1013 | vertical = { mirror = false }, 1014 | width = 0.87, 1015 | height = 0.80, 1016 | preview_cutoff = 1 1017 | }, 1018 | color_devicons = not SimpleUI, 1019 | set_env = { ["COLORTERM"] = "truecolor" }, -- default = nil, 1020 | file_previewer = require("telescope.previewers").vim_buffer_cat.new, 1021 | grep_previewer = require("telescope.previewers").vim_buffer_vimgrep 1022 | .new, 1023 | qflist_previewer = require("telescope.previewers").vim_buffer_qflist 1024 | .new 1025 | }, 1026 | 1027 | extensions = { 1028 | fzy_native = { 1029 | override_generic_sorter = false, 1030 | override_file_sorter = true 1031 | }, 1032 | --[[ frecency = { 1033 | ignore_patterns = { "*.git/*", "*/tmp/*", ".*ignore", "*.DS_Store*", "Caches", "Backups", "/Applications", 1034 | "/bin", "*/.localized" }, 1035 | -- show the tail for "LSP", "CWD" and "FOO" 1036 | show_filter_column = { "LSP", "CWD" }, 1037 | show_scores = true, 1038 | show_unindexed = false, 1039 | use_sqlite = false 1040 | }, ]] 1041 | } 1042 | }) 1043 | require("telescope").load_extension("fzy_native") 1044 | require("telescope").load_extension("zk") 1045 | if not SimpleUI then 1046 | require("telescope").load_extension("noice") 1047 | end 1048 | -- require("telescope").load_extension("frecency") 1049 | require("telescope").load_extension("git_worktree") 1050 | if vim.fn.has("mac") ~= 1 then 1051 | -- doesn't currently work on mac 1052 | require("telescope").load_extension("media_files") 1053 | end 1054 | end -- telescope 1055 | 1056 | 1057 | ----------------------- COMPLETIONS -------------------------------- 1058 | -- cmp, luasnip 1059 | M.completions = function() 1060 | -- require("luasnip/loaders/from_vscode").lazy_load() 1061 | -- local luasnip = require("luasnip") 1062 | local check_backspace = function() 1063 | local col = vim.fn.col(".") - 1 1064 | return col == 0 or 1065 | vim.fn.getline(vim.fn.line(".")):sub(col, col):match("%s") 1066 | end 1067 | local cmp = require("cmp") 1068 | cmp.setup({ 1069 | enabled = function() 1070 | local context = require("cmp.config.context") 1071 | local buftype = vim.api.nvim_get_option_value('buftype', {}) 1072 | -- prevent completions in prompts like telescope prompt 1073 | if buftype == "prompt" then return false end 1074 | -- allow completions in command mode 1075 | if vim.api.nvim_get_mode().mode == "c" then return true end 1076 | -- forbid completions in comments 1077 | return not context.in_treesitter_capture("comment") and 1078 | not context.in_syntax_group("Comment") 1079 | end, 1080 | mapping = { 1081 | [""] = cmp.mapping.select_prev_item(), 1082 | [""] = cmp.mapping.select_next_item(), 1083 | [""] = cmp.mapping.scroll_docs(-4), 1084 | [""] = cmp.mapping.scroll_docs(4), 1085 | [""] = cmp.mapping.complete({}), 1086 | [""] = cmp.mapping.close(), 1087 | [""] = cmp.mapping.confirm({ 1088 | behavior = cmp.ConfirmBehavior.Replace, 1089 | select = false 1090 | }), 1091 | [""] = cmp.mapping(function(fallback) 1092 | if cmp.visible() then 1093 | cmp.select_next_item() 1094 | -- elseif luasnip.expandable() then 1095 | -- luasnip.expand({}) 1096 | -- elseif luasnip.expand_or_jumpable() then 1097 | -- luasnip.expand_or_jump() 1098 | elseif check_backspace() then 1099 | fallback() 1100 | else 1101 | cmp.mapping.complete({}) 1102 | -- fallback() 1103 | end 1104 | end, { "i", "s" }), 1105 | [""] = cmp.mapping(function(fallback) 1106 | if cmp.visible() then 1107 | cmp.select_prev_item() 1108 | -- elseif luasnip.jumpable(-1) then 1109 | -- luasnip.jump(-1) 1110 | else 1111 | fallback() 1112 | end 1113 | end, { "i", "s" }) 1114 | }, 1115 | -- window = { documentation = cmp.config.window.bordered() }, 1116 | sources = { 1117 | { name = "nvim_lsp" }, 1118 | -- { name = "nvim_lsp_signature_help" }, 1119 | { name = "nvim_lua" }, { name = "emoji" }, 1120 | -- { name = "luasnip" }, 1121 | { name = "path" }, { name = "crates" }, 1122 | { name = "npm", keyword_length = 3 }, 1123 | { name = "buffer", keyword_length = 3 } 1124 | }, 1125 | formatting = { 1126 | fields = { "kind", "abbr", "menu" }, 1127 | format = function(entry, vim_item) 1128 | -- Kind icons 1129 | vim_item.kind = string.format("%s", 1130 | signs.kind_icons[vim_item.kind]) 1131 | vim_item.menu = ({ 1132 | nvim_lsp = "[LSP]", 1133 | nvim_lsp_signature_help = "[LSPS]", 1134 | -- luasnip = "[Snippet]", 1135 | buffer = "[Buffer]", 1136 | path = "[Path]", 1137 | Copilot = "[Copilot]", 1138 | })[entry.source.name] 1139 | return vim_item 1140 | end 1141 | }, 1142 | -- snippet = { expand = function(args) luasnip.lsp_expand(args.body) end } 1143 | }) 1144 | --[[ cmp.setup.cmdline("/", { 1145 | mapping = cmp.mapping.preset.cmdline(), 1146 | sources = { { name = "buffer" } } 1147 | }) 1148 | cmp.setup.cmdline(":", { 1149 | mapping = cmp.mapping.preset.cmdline(), 1150 | sources = cmp.config.sources({ { name = "path" } }, { 1151 | { name = "cmdline", option = { ignore_cmds = { "Man", "!" } } } 1152 | }) 1153 | }) ]] 1154 | end -- completions 1155 | 1156 | 1157 | ----------------------- NOTES -------------------------------- 1158 | -- zk (zettelkasten lsp), taskwiki, focus mode, grammar 1159 | M.notes = function() 1160 | require("zk").setup({ 1161 | picker = "telescope", 1162 | -- automatically attach buffers in a zk notebook that match the given filetypes 1163 | lsp = { 1164 | auto_attach = { 1165 | enabled = true, 1166 | filetypes = { "markdown", "vimwiki", "md" } 1167 | }, 1168 | config = { 1169 | on_attach = function(_, bufnr) 1170 | -- print("ZK attached") 1171 | local mapleadernvlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapleadernv) 1172 | local mapleadernlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapleadern) 1173 | local mapleadervlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapleaderv) 1174 | local mapnlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapn) 1175 | 1176 | mapnlocal("K", vim.lsp.buf.hover, "Info hover") 1177 | -- Create the note in the same directory as the current buffer after asking for title 1178 | mapleadernlocal("np", "ZkNew { dir = vim.fn.expand('%:p:h'), title = vim.fn.input('Title: ') }", 1179 | "New peer note (same dir)") 1180 | mapleadernlocal("nl", "ZkLinks", "Show note links") 1181 | mapleadernlocal("nr", require("telescope.builtin").lsp_references, "References to this note") 1182 | mapleadernlocal("lr", require("telescope.builtin").lsp_references, "References to this note") -- for muscle memory 1183 | mapleadernlocal("li", vim.lsp.buf.hover, "Info hover") 1184 | mapleadernlocal("lf", vim.lsp.buf.code_action, "Fix code actions") 1185 | mapleadernlocal("le", vim.diagnostic.open_float, "Show line diags") 1186 | mapleadernvlocal("ll", function() 1187 | -- the scope filter is supported in diagnostics, but not yet in inlay hints as far as I know, but 1188 | -- i'm adding it so things will improve when nvim does 1189 | vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled(), { bufnr = 0, scope = "line" }) 1190 | vim.diagnostic.config({ virtual_text = vim.lsp.inlay_hint.is_enabled() }) 1191 | end, "Toggle virtual text lines") 1192 | mapleadervlocal("np", 1193 | function() require('zk.commands').get("ZkNewFromTitleSelection")({ dir = vim.fn.expand('%:p:h') }) end, 1194 | "New peer note (same dir) selection for title") 1195 | mapleadernlocal("nu", function() 1196 | vim.cmd("normal yiW") 1197 | require("pwnvim.markdown").pasteUrl() 1198 | end, "Turn bare URL into link") 1199 | mapleadervlocal("nu", function() 1200 | vim.cmd("normal y") 1201 | require("pwnvim.markdown").pasteUrl() 1202 | end, "Turn bare URL into link") 1203 | 1204 | 1205 | -- TODO: Make magic... 1206 | -- in normal mode, if on a link, it should open the link (note or url) 1207 | -- in visual mode, it should prompt for folder, create a note, and make a link 1208 | -- Meanwhile, just go to definition 1209 | -- vim.api.nvim_buf_set_keymap(bufnr, "n", "", 1210 | -- "lua vim.lsp.buf.definition()", 1211 | -- opts) 1212 | -- Preview a linked note. 1213 | 1214 | require("pwnvim.options").tabindent() 1215 | end 1216 | } 1217 | } 1218 | }) 1219 | 1220 | -- Focus mode dimming of text out of current block 1221 | --[[ require("twilight").setup { 1222 | dimming = { 1223 | alpha = 0.25, -- amount of dimming 1224 | -- we try to get the foreground from the highlight groups or fallback color 1225 | color = { "Normal", "#ffffff" }, 1226 | term_bg = "#000000", -- if guibg=NONE, this will be used to calculate text color 1227 | inactive = true -- when true, other windows will be fully dimmed (unless they contain the same buffer) 1228 | }, 1229 | context = 12, -- amount of lines we will try to show around the current line 1230 | treesitter = true, -- use treesitter when available for the filetype 1231 | -- treesitter is used to automatically expand the visible text, 1232 | -- but you can further control the types of nodes that should always be fully expanded 1233 | expand = { -- for treesitter, we we always try to expand to the top-most ancestor with these types 1234 | "function", "method", "table", "if_statement" 1235 | }, 1236 | exclude = {} -- exclude these filetypes 1237 | } ]] 1238 | -- Focus mode / centering 1239 | require("true-zen").setup({ 1240 | -- your config goes here 1241 | -- or just leave it empty :) 1242 | modes = { 1243 | -- configurations per mode 1244 | ataraxis = { 1245 | shade = "dark", -- if `dark` then dim the padding windows, otherwise if it's `light` it'll brighten said windows 1246 | backdrop = 0, -- percentage by which padding windows should be dimmed/brightened. Must be a number between 0 and 1. Set to 0 to keep the same background color 1247 | minimum_writing_area = { 1248 | -- minimum size of main window 1249 | width = 70, 1250 | height = 44 1251 | }, 1252 | quit_untoggles = true, -- type :q or :qa to quit Ataraxis mode 1253 | padding = { 1254 | -- padding windows 1255 | left = 52, 1256 | right = 52, 1257 | top = 0, 1258 | bottom = 0 1259 | }, 1260 | callbacks = { 1261 | -- run functions when opening/closing Ataraxis mode 1262 | open_pre = function() 1263 | vim.opt.scrolloff = 999 -- keep cursor in vertical middle of screen 1264 | end, 1265 | open_pos = nil, 1266 | close_pre = nil, 1267 | close_pos = function() 1268 | vim.opt.scrolloff = 8 1269 | end 1270 | } 1271 | }, 1272 | minimalist = { 1273 | ignored_buf_types = { "nofile" }, -- save current options from any window except ones displaying these kinds of buffers 1274 | options = { 1275 | -- options to be disabled when entering Minimalist mode 1276 | number = false, 1277 | relativenumber = false, 1278 | showtabline = 0, 1279 | signcolumn = "no", 1280 | statusline = "", 1281 | cmdheight = 1, 1282 | laststatus = 0, 1283 | showcmd = false, 1284 | showmode = false, 1285 | ruler = false, 1286 | numberwidth = 1 1287 | }, 1288 | callbacks = { 1289 | -- run functions when opening/closing Minimalist mode 1290 | open_pre = nil, 1291 | open_pos = nil, 1292 | close_pre = nil, 1293 | close_pos = nil 1294 | } 1295 | }, 1296 | narrow = { 1297 | --- change the style of the fold lines. Set it to: 1298 | --- `informative`: to get nice pre-baked folds 1299 | --- `invisible`: hide them 1300 | --- function() end: pass a custom func with your fold lines. See :h foldtext 1301 | folds_style = "informative", 1302 | run_ataraxis = true, -- display narrowed text in a Ataraxis session 1303 | callbacks = { 1304 | -- run functions when opening/closing Narrow mode 1305 | open_pre = nil, 1306 | open_pos = nil, 1307 | close_pre = nil, 1308 | close_pos = nil 1309 | } 1310 | }, 1311 | focus = { 1312 | callbacks = { 1313 | -- run functions when opening/closing Focus mode 1314 | open_pre = nil, 1315 | open_pos = nil, 1316 | close_pre = nil, 1317 | close_pos = nil 1318 | } 1319 | } 1320 | }, 1321 | integrations = { 1322 | tmux = false, -- hide tmux status bar in (minimalist, ataraxis) 1323 | kitty = { 1324 | -- increment font size in Kitty. Note: you must set `allow_remote_control socket-only` and `listen_on unix:/tmp/kitty` in your personal config (ataraxis) 1325 | enabled = false, -- disabled 2023-03-20 because it doesn't reset the font size on exit 1326 | font = "+2" 1327 | }, 1328 | twilight = false, -- enable twilight text dimming outside cursor block 1329 | lualine = true -- hide nvim-lualine (ataraxis) 1330 | } 1331 | }) 1332 | 1333 | -- Grammar 1334 | vim.g["grammarous#disabled_rules"] = { 1335 | ["*"] = { 1336 | "WHITESPACE_RULE", "EN_QUOTES", "ARROWS", "SENTENCE_WHITESPACE", 1337 | "WORD_CONTAINS_UNDERSCORE", "COMMA_PARENTHESIS_WHITESPACE", 1338 | "EN_UNPAIRED_BRACKETS", "UPPERCASE_SENTENCE_START", 1339 | "ENGLISH_WORD_REPEAT_BEGINNING_RULE", "DASH_RULE", "PLUS_MINUS", 1340 | "PUNCTUATION_PARAGRAPH_END", "MULTIPLICATION_SIGN", "PRP_CHECKOUT", 1341 | "CAN_CHECKOUT", "SOME_OF_THE", "DOUBLE_PUNCTUATION", "HELL", 1342 | "CURRENCY", "POSSESSIVE_APOSTROPHE", --"ENGLISH_WORD_REPEAT_RULE", 1343 | "NON_STANDARD_WORD" 1344 | } 1345 | } 1346 | vim.g["grammarous#languagetool_cmd"] = 'languagetool-commandline' 1347 | vim.g["grammarous#use_location_list"] = 1 1348 | vim.g["grammarous#enable_spell_check"] = 0 1349 | vim.g["grammarous#show_first_error"] = 0 1350 | -- Below is to make mapping easier for ,ng 1351 | vim.cmd( 1352 | [[command StartGrammar2 lua require('pwnvim.plugins').grammar_check()]]) 1353 | end -- notes 1354 | 1355 | M.grammar_check = function() 1356 | vim.cmd("packadd vim-grammarous") 1357 | local opts = { noremap = false, silent = true } 1358 | local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(0, ...) end 1359 | 1360 | buf_set_keymap("n", "gf", "(grammarous-fixit)", opts) 1361 | buf_set_keymap("n", "gx", "(grammarous-remove-error)", opts) 1362 | buf_set_keymap("n", "]g", "(grammarous-move-to-next-error)", opts) 1363 | buf_set_keymap("n", "[g", "(grammarous-move-to-previous-error)", opts) 1364 | vim.cmd("GrammarousCheck") 1365 | end 1366 | 1367 | ----------------------- MISC -------------------------------- 1368 | -- rooter, kommentary, autopairs, toggleterm, matchup, yazi 1369 | M.misc = function() 1370 | vim.g.lf_map_keys = 0 -- lf.vim disable default keymapping 1371 | vim.g.matchup_surround_enabled = 0 -- disallows ds type selections 1372 | vim.g.matchup_matchparen_offscreen = { method = 'popup' } 1373 | vim.g.matchup_matchparen_deferred = 1 1374 | vim.g.matchup_motion_override_Npercent = 100 1375 | vim.g.matchup_text_obj_linewise_operators = { 'd', 'y', 'c', 'v' } 1376 | 1377 | -- Change project directory using local cd only 1378 | -- vim.g.rooter_cd_cmd = 'lcd' 1379 | -- Look for these files/dirs as hints 1380 | -- vim.g.rooter_patterns = { 1381 | -- '.git', '_darcs', '.hg', '.bzr', '.svn', 'Makefile', 'package.json', 1382 | -- '.zk', 'Cargo.toml', 'build.sbt', 'Package.swift', 'Makefile.in' 1383 | -- } 1384 | 1385 | 1386 | require("nvim-autopairs").setup({}) 1387 | 1388 | vim.g.tmux_navigator_no_mappings = 1 1389 | 1390 | require("toggleterm").setup({ 1391 | open_mapping = [[]], 1392 | shade_terminals = true, 1393 | insert_mappings = true, -- from normal or insert mode 1394 | terminal_mappings = false, 1395 | start_in_insert = true, 1396 | hide_numbers = true, 1397 | direction = "vertical", 1398 | size = function(_) return vim.o.columns * 0.3 end, 1399 | close_on_exit = true 1400 | }) 1401 | -- vim.api.nvim_set_keymap("t", [[]], "ToggleTermToggleAll", { noremap = true }) 1402 | -- This is just needed so that I can switch terms when in a term, which isn't default behavior 1403 | require("pwnvim.mappings").mapt([[]], 1404 | "exe v:count1 . 'ToggleTerm'", "Toggle on or off specific terms from inside term") 1405 | require("pwnvim.mappings").mapnvict("", "ToggleTerm direction=horizontal size=30 name=bottom", 1406 | "Bottom of screen terminal window") 1407 | 1408 | 1409 | require("project_nvim").setup({ 1410 | active = true, 1411 | on_config_done = nil, 1412 | manual_mode = false, 1413 | detection_methods = { "lsp", "pattern" }, 1414 | exclude_dirs = { "/nix/store/*" }, 1415 | scope_chdir = "tab", 1416 | patterns = { 1417 | ".git", "_darcs", ".hg", ".bzr", ".svn", "Makefile", "package.json", 1418 | ".zk", "build.sbt", "Package.swift", "Makefile.in", "README.md", 1419 | "flake.nix" 1420 | }, 1421 | show_hidden = false, 1422 | silent_chdir = true, 1423 | ignore_lsp = {} 1424 | }) 1425 | require("telescope").load_extension("projects") 1426 | require("yazi").setup({ 1427 | open_for_directories = false 1428 | }) 1429 | end -- misc 1430 | 1431 | M.telescope_get_folder_common_folders = function(search_folders, depth, callback) 1432 | local pickers = require "telescope.pickers" 1433 | local finders = require "telescope.finders" 1434 | local sorters = require "telescope.sorters" 1435 | local themes = require "telescope.themes" 1436 | local action_state = require "telescope.actions.state" 1437 | local actions = require "telescope.actions" 1438 | local Job = require 'plenary.job' 1439 | 1440 | local entry = function(a) 1441 | local value = vim.env.HOME .. "/" .. a 1442 | local display = "~/" .. a -- (string.gsub(a, vim.env.HOME, '~')) 1443 | return { 1444 | value = value, 1445 | display = display, 1446 | ordinal = a 1447 | } 1448 | end 1449 | 1450 | local full_path_folders = search_folders 1451 | local args = { '--base-directory', vim.env.HOME, "--min-depth", 1, "--max-depth", depth, "-t", "d", "-L" } 1452 | for _, f in ipairs(search_folders) do 1453 | table.insert(args, "--search-path") 1454 | table.insert(args, f) 1455 | end 1456 | 1457 | Job:new({ 1458 | command = 'fd', 1459 | args = args, 1460 | cwd = vim.env.HOME, 1461 | env = { ['PATH'] = vim.env.PATH }, 1462 | on_stderr = function(err, data) 1463 | vim.notify("stderr err: " .. vim.inspect(err) .. " data: " .. vim.inspect(data)) 1464 | end, 1465 | on_stdout = function(err, data) 1466 | if (err ~= nil) then 1467 | vim.notify("stdout err: " .. vim.inspect(err) .. " data: " .. vim.inspect(data)) 1468 | else 1469 | table.insert(full_path_folders, data) 1470 | end 1471 | end, 1472 | -- on_exit = function(job,code) 1473 | -- 1474 | -- end 1475 | }):sync() -- or start() 1476 | 1477 | local finder = finders.new_table({ 1478 | results = full_path_folders, 1479 | entry_maker = entry 1480 | }) 1481 | pickers.new({}, { 1482 | cwd = vim.env.HOME, 1483 | prompt_title = "Pick Folder", 1484 | finder = finder, 1485 | sorter = sorters.fuzzy_with_index_bias(), 1486 | theme = themes.get_dropdown(), 1487 | attach_mappings = 1488 | function(prompt_bufnr) 1489 | actions.select_default:replace(function() 1490 | local folder = action_state.get_selected_entry() 1491 | -- print(vim.inspect(folder)) 1492 | if folder ~= nil then 1493 | actions.close(prompt_bufnr) 1494 | callback(folder["value"]) 1495 | end 1496 | end) 1497 | return true 1498 | end 1499 | }):find() 1500 | end 1501 | 1502 | 1503 | return M 1504 | -------------------------------------------------------------------------------- /pwnvim/plugins/bufferline.lua: -------------------------------------------------------------------------------- 1 | local bufferline = require('bufferline') 2 | bufferline.setup { 3 | ---@diagnostic disable: missing-fields 4 | options = { 5 | mode = "buffers", 6 | style_preset = bufferline.style_preset.default, -- or bufferline.style_preset.minimal, 7 | numbers = "none", -- | "ordinal" | "buffer_id" | "both" | function({ ordinal, id, lower, raise }): string, 8 | close_command = "Bdelete! %d", -- can be a string | function, see "Mouse actions" 9 | right_mouse_command = "Bdelete! %d", -- can be a string | function, see "Mouse actions" 10 | left_mouse_command = "buffer %d", -- can be a string | function, see "Mouse actions" 11 | middle_mouse_command = nil, -- can be a string | function, see "Mouse actions" 12 | indicator = { 13 | style = "icon", 14 | icon = "▎", 15 | }, 16 | -- buffer_close_icon = '', 17 | modified_icon = "●", 18 | close_icon = SimpleUI and "x" or "", 19 | left_trunc_marker = SimpleUI and "⬅️" or "", 20 | right_trunc_marker = SimpleUI and "➡️" or "", 21 | max_name_length = 40, 22 | max_prefix_length = 30, -- prefix used when a buffer is de-duplicated 23 | tab_size = 20, 24 | diagnostics = "nvim_lsp", -- | "coc", 25 | diagnostics_update_in_insert = false, 26 | custom_filter = function(buf_number, buf_numbers) 27 | if vim.bo[buf_number].filetype ~= "fugitive" then 28 | return true 29 | end 30 | return false 31 | end, 32 | offsets = { { filetype = "NvimTree", text = "", padding = 1 } }, 33 | show_buffer_close_icons = true, 34 | show_close_icon = true, 35 | show_buffer_icons = not SimpleUI, 36 | get_element_icon = function(elem) 37 | if SimpleUI then 38 | return "", "" 39 | else 40 | local icon, hl = require('nvim-web-devicons').get_icon_by_filetype(elem.filetype, { default = false }) 41 | return icon, hl 42 | end 43 | end, 44 | color_icons = not SimpleUI, 45 | buffer_close_icon = SimpleUI and "x" or "", 46 | show_tab_indicators = true, 47 | persist_buffer_sort = false, -- whether or not custom sorted buffers should persist 48 | -- can also be a table containing 2 custom separators 49 | -- [focused and unfocused]. eg: { '|', '|' } 50 | separator_style = "thick", -- | "thick" | "thin" | { 'any', 'any' }, 51 | enforce_regular_tabs = false, -- if true, all tabs same width 52 | always_show_bufferline = true 53 | }, 54 | highlights = { 55 | indicator_selected = { 56 | fg = { 57 | attribute = "fg", 58 | highlight = "LspDiagnosticsDefaultHint" 59 | }, 60 | bg = { attribute = "bg", highlight = "Normal" } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /pwnvim/plugins/gitsigns.lua: -------------------------------------------------------------------------------- 1 | require("gitsigns").setup { 2 | signs = { 3 | add = { 4 | -- hl = 'GitSignsAdd', 5 | text = '✚', 6 | -- numhl = 'GitSignsAddNr', 7 | -- linehl = 'GitSignsAddLn' 8 | }, 9 | change = { 10 | -- hl = 'GitSignsChange', 11 | text = '│', 12 | -- numhl = 'GitSignsChangeNr', 13 | -- linehl = 'GitSignsChangeLn' 14 | }, 15 | delete = { 16 | -- hl = 'GitSignsDelete', 17 | text = '_', 18 | -- numhl = 'GitSignsDeleteNr', 19 | -- linehl = 'GitSignsDeleteLn' 20 | }, 21 | topdelete = { 22 | -- hl = 'GitSignsDelete', 23 | text = '‾', 24 | -- numhl = 'GitSignsDeleteNr', 25 | -- linehl = 'GitSignsDeleteLn' 26 | }, 27 | changedelete = { 28 | -- hl = 'GitSignsChange', 29 | text = '~', 30 | -- numhl = 'GitSignsChangeNr', 31 | -- linehl = 'GitSignsChangeLn' 32 | } 33 | }, 34 | on_attach = function(bufnr) 35 | local gs = package.loaded.gitsigns 36 | 37 | local mapnlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapn) 38 | local mapoxlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapox) 39 | local mapleadernvlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapleadernv) 40 | local mapleadernlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapleadern) 41 | local mapleadervlocal = require("pwnvim.mappings").makelocalmap(bufnr, require("pwnvim.mappings").mapleaderv) 42 | 43 | -- Navigation 44 | mapnlocal(']c', function() 45 | if vim.wo.diff then return ']c' end 46 | vim.schedule(function() gs.next_hunk() end) 47 | return '' 48 | end, "Next hunk", { expr = true }) 49 | mapnlocal('[c', function() 50 | if vim.wo.diff then return '[c' end 51 | vim.schedule(function() gs.prev_hunk() end) 52 | return '' 53 | end, "Prev hunk", { expr = true }) 54 | 55 | -- DO NOT USE gs, gb, gc, gw as these are more global and not gitsigns specific 56 | -- Git toggles 57 | mapleadernvlocal("gtb", gs.toggle_current_line_blame, "Toggle current line blame") 58 | mapleadernvlocal("gtd", gs.toggle_deleted, "Toggle deleted") 59 | -- Actions -- normal mode 60 | mapleadernlocal("g-", gs.reset_hunk, "Reset hunk") 61 | mapleadernlocal("g+", gs.stage_hunk, "Stage hunk") 62 | mapleadervlocal("g-", function() gs.reset_hunk { vim.fn.line('.'), vim.fn.line('v') } end, "Reset hunk") 63 | mapleadervlocal("g+", function() gs.stage_hunk { vim.fn.line('.'), vim.fn.line('v') } end, "Stage hunk") 64 | mapleadernvlocal("gu", gs.undo_stage_hunk, "Undo stage hunk") 65 | mapleadernvlocal("gS", gs.stage_buffer, "Stage buffer") 66 | mapleadernvlocal("gR", gs.reset_buffer, "Reset buffer") 67 | mapleadernlocal("gp", gs.preview_hunk, "Preview hunk") 68 | mapleadernvlocal("gB", function() gs.blame_line { full = true } end, "Blame hunk popup") 69 | mapleadernlocal("gd", gs.diffthis, "Diff this to index") 70 | mapleadernlocal("gD", function() gs.diffthis('~') end, "Diff this to previous") 71 | -- text object for hunks 72 | mapoxlocal("ih", ':Gitsigns select_hunk', "Select git hunk") 73 | end 74 | } 75 | -------------------------------------------------------------------------------- /pwnvim/plugins/indent-blankline.lua: -------------------------------------------------------------------------------- 1 | if not SimpleUI then 2 | require('ibl').setup({ -- indent-blankline 3 | enabled = true, 4 | indent = { 5 | --char = '┊', 6 | char = '▏', 7 | }, 8 | exclude = { 9 | buftypes = { 'terminal', 'help', 'markdown', 'nofile', 'help', 'quickfix', 'prompt' }, 10 | filetypes = { 'help', 'markdown', 'nofile', 'help', 'packer', 'Trouble', 11 | "startify", "dashboard", "neogitstatus", "lspinfo", "checkhealth", "man", "", "NvimTree", "dbout" 12 | }, 13 | 14 | }, 15 | scope = { 16 | enabled = false, 17 | char = '▍', 18 | show_start = false, 19 | show_end = false, 20 | highlight = "VertSplit", 21 | }, 22 | }) 23 | end 24 | -------------------------------------------------------------------------------- /pwnvim/plugins/lualine.lua: -------------------------------------------------------------------------------- 1 | local lualine = require('lualine') 2 | 3 | -- Functions to show word count and reading time in markdown files 4 | -- Credit: https://yieldcode.blog/snippets/neovim-reading-time/ 5 | local function wordcount() 6 | return tostring(vim.fn.wordcount().words) .. ' words' 7 | end 8 | 9 | local function readingtime() 10 | return tostring(math.ceil(vim.fn.wordcount().words / 200.0)) .. ' min' 11 | end 12 | 13 | local function is_markdown() 14 | return vim.bo.filetype == "markdown" 15 | end 16 | 17 | local paper = { 18 | options = { 19 | theme = 'papercolor_light', 20 | icons_enabled = not SimpleUI, 21 | component_separators = { left = SimpleUI and '>' or '', right = SimpleUI and '<' or '' }, 22 | disabled_filetypes = { 'pager' }, 23 | section_separators = { left = SimpleUI and '>' or '', right = SimpleUI and '<' or '' }, 24 | globalstatus = true 25 | }, 26 | extensions = { 'quickfix', 'fugitive' }, 27 | sections = { 28 | lualine_a = { 'mode' }, 29 | lualine_b = { 'branch' }, 30 | lualine_c = { 'filename' }, 31 | lualine_x = { 'encoding', 'fileformat', 'filetype' }, 32 | lualine_y = { 'progress', 'location', { wordcount, cond = is_markdown }, { readingtime, cond = is_markdown } }, 33 | lualine_z = { 34 | --{ 35 | -- require("noice").api.statusline.mode.get, 36 | -- cond = require("noice").api.statusline.mode.has, 37 | --color = { fg = "#ff9e64" }, 38 | --}, 39 | { 40 | 'diagnostics', 41 | sources = { 'nvim_diagnostic' }, 42 | -- displays diagnostics from defined severity 43 | sections = { 'error', 'warn' }, 44 | color_error = "#E06C75", 45 | color_warn = "#E5C07B" 46 | } 47 | } 48 | } 49 | } 50 | -- Eviline config for lualine 51 | -- Author: shadmansaleh 52 | -- Credit: glepnir 53 | -- From: https://github.com/nvim-lualine/lualine.nvim/blob/master/examples/evil_lualine.lua 54 | 55 | -- Color table for highlights 56 | -- stylua: ignore 57 | local colors = { 58 | bg = '#202328', 59 | fg = '#bbc2cf', 60 | yellow = '#ECBE7B', 61 | cyan = '#008080', 62 | darkblue = '#081633', 63 | green = '#98be65', 64 | orange = '#FF8800', 65 | violet = '#a9a1e1', 66 | magenta = '#c678dd', 67 | blue = '#51afef', 68 | red = '#ec5f67', 69 | } 70 | 71 | local conditions = { 72 | buffer_not_empty = function() 73 | return vim.fn.empty(vim.fn.expand('%:t')) ~= 1 74 | end, 75 | hide_in_width = function() 76 | return vim.fn.winwidth(0) > 80 77 | end, 78 | check_git_workspace = function() 79 | local filepath = vim.fn.expand('%:p:h') 80 | local gitdir = vim.fn.finddir('.git', filepath .. ';') 81 | return gitdir and #gitdir > 0 and #gitdir < #filepath 82 | end, 83 | } 84 | 85 | -- Config 86 | local evil = { 87 | options = { 88 | -- Disable sections and component separators 89 | component_separators = '', 90 | section_separators = '', 91 | theme = { 92 | -- We are going to use lualine_c an lualine_x as left and 93 | -- right section. Both are highlighted by c theme . So we 94 | -- are just setting default looks o statusline 95 | normal = { c = { fg = colors.fg, bg = colors.bg } }, 96 | inactive = { c = { fg = colors.fg, bg = colors.bg } }, 97 | }, 98 | }, 99 | sections = { 100 | -- these are to remove the defaults 101 | lualine_a = {}, 102 | lualine_b = {}, 103 | lualine_y = {}, 104 | lualine_z = {}, 105 | -- These will be filled later 106 | lualine_c = {}, 107 | lualine_x = {}, 108 | }, 109 | inactive_sections = { 110 | -- these are to remove the defaults 111 | lualine_a = {}, 112 | lualine_b = {}, 113 | lualine_y = {}, 114 | lualine_z = {}, 115 | lualine_c = {}, 116 | lualine_x = {}, 117 | }, 118 | } 119 | 120 | -- Inserts a component in lualine_c at left section 121 | local function ins_left(component) 122 | table.insert(evil.sections.lualine_c, component) 123 | end 124 | 125 | -- Inserts a component in lualine_x at right section 126 | local function ins_right(component) 127 | table.insert(evil.sections.lualine_x, component) 128 | end 129 | 130 | ins_left { 131 | function() 132 | return '▊' 133 | end, 134 | color = { fg = colors.blue }, -- Sets highlighting of component 135 | padding = { left = 0, right = 1 }, -- We don't need space before this 136 | } 137 | 138 | ins_left { 139 | -- mode component 140 | function() 141 | return '' 142 | end, 143 | color = function() 144 | -- auto change color according to neovims mode 145 | local mode_color = { 146 | n = colors.red, 147 | i = colors.green, 148 | v = colors.blue, 149 | [''] = colors.blue, 150 | V = colors.blue, 151 | c = colors.magenta, 152 | no = colors.red, 153 | s = colors.orange, 154 | S = colors.orange, 155 | [''] = colors.orange, 156 | ic = colors.yellow, 157 | R = colors.violet, 158 | Rv = colors.violet, 159 | cv = colors.red, 160 | ce = colors.red, 161 | r = colors.cyan, 162 | rm = colors.cyan, 163 | ['r?'] = colors.cyan, 164 | ['!'] = colors.red, 165 | t = colors.red, 166 | } 167 | return { fg = mode_color[vim.fn.mode()] } 168 | end, 169 | padding = { right = 1 }, 170 | } 171 | 172 | ins_left { 173 | -- filesize component 174 | 'filesize', 175 | cond = conditions.buffer_not_empty, 176 | } 177 | 178 | ins_left { 179 | 'filename', 180 | cond = conditions.buffer_not_empty, 181 | color = { fg = colors.magenta, gui = 'bold' }, 182 | } 183 | 184 | ins_left { 'location' } 185 | 186 | ins_left { 'progress', color = { fg = colors.fg, gui = 'bold' } } 187 | 188 | ins_left { wordcount, cond = is_markdown, color = { fg = colors.green } } 189 | ins_left { readingtime, cond = is_markdown, color = { fg = colors.green } } 190 | ins_left { 191 | 'diagnostics', 192 | sources = { 'nvim_diagnostic' }, 193 | symbols = { error = ' ', warn = ' ', info = ' ' }, 194 | diagnostics_color = { 195 | color_error = { fg = colors.red }, 196 | color_warn = { fg = colors.yellow }, 197 | color_info = { fg = colors.cyan }, 198 | }, 199 | } 200 | 201 | -- Insert mid section. You can make any number of sections in neovim :) 202 | -- for lualine it's any number greater then 2 203 | ins_left { 204 | function() 205 | return '%=' 206 | end, 207 | } 208 | 209 | ins_left { 210 | -- Lsp server name . 211 | function() 212 | local msg = '' -- show nothing if no LSP 213 | local buf_ft = vim.api.nvim_buf_get_option(0, 'filetype') 214 | local clients = vim.lsp.get_active_clients() 215 | if next(clients) == nil then 216 | return msg 217 | end 218 | for _, client in ipairs(clients) do 219 | local filetypes = client.config.filetypes 220 | if filetypes and vim.fn.index(filetypes, buf_ft) ~= -1 then 221 | return ' ' .. client.name 222 | end 223 | end 224 | return msg 225 | end, 226 | icon = '', -- I want it blank when there's no LSP 227 | color = { fg = '#ffffff', gui = 'bold' }, 228 | } 229 | 230 | -- Add components to right sections 231 | ins_right { 232 | 'o:encoding', -- option component same as &encoding in viml 233 | fmt = string.upper, -- I'm not sure why it's upper case either ;) 234 | cond = conditions.hide_in_width, 235 | color = { fg = colors.green, gui = 'bold' }, 236 | } 237 | 238 | ins_right { 239 | 'filetype', 240 | fmt = string.upper, 241 | icons_enabled = not SimpleUI, 242 | color = { fg = colors.green, gui = 'bold' }, 243 | } 244 | 245 | ins_right { 246 | 'fileformat', 247 | fmt = string.upper, 248 | icons_enabled = not SimpleUI, 249 | color = { fg = colors.green, gui = 'bold' }, 250 | } 251 | 252 | ins_right { 253 | 'branch', 254 | icon = '', 255 | color = { fg = colors.violet, gui = 'bold' }, 256 | } 257 | 258 | ins_right { 259 | 'diff', 260 | -- Is it me or the symbol for modified us really weird 261 | symbols = { added = ' ', modified = '󰝤 ', removed = ' ' }, 262 | diff_color = { 263 | added = { fg = colors.green }, 264 | modified = { fg = colors.orange }, 265 | removed = { fg = colors.red }, 266 | }, 267 | cond = conditions.hide_in_width, 268 | } 269 | 270 | ins_right { 271 | function() 272 | return '▊' 273 | end, 274 | color = { fg = colors.blue }, 275 | padding = { left = 1 }, 276 | } 277 | 278 | -- Now don't forget to initialize lualine 279 | lualine.setup(evil) 280 | -------------------------------------------------------------------------------- /pwnvim/plugins/nvim-tree.lua: -------------------------------------------------------------------------------- 1 | require("oil").setup({ 2 | -- Oil will take over directory buffers (e.g. `vim .` or `:e src/`) 3 | -- Set to false if you still want to use netrw. 4 | default_file_explorer = true, 5 | skip_confirm_for_simple_edits = true, 6 | keymaps = { 7 | ["q"] = "actions.close", 8 | ["gd"] = function() 9 | require("oil").set_columns({ "icon", "permissions", "size", "mtime" }) 10 | end, 11 | ["ff"] = { 12 | function() 13 | require("telescope.builtin").find_files({ 14 | cwd = require("oil").get_current_dir() 15 | }) 16 | end, 17 | mode = "n", 18 | nowait = true, 19 | desc = "Find files in the current directory" 20 | }, 21 | ["fg"] = { 22 | function() 23 | require("telescope.builtin").live_grep({ 24 | cwd = require("oil").get_current_dir() 25 | }) 26 | end, 27 | mode = "n", 28 | nowait = true, 29 | desc = "Find files in the current directory" 30 | }, 31 | }, 32 | -- Id is automatically added at the beginning, and name at the end 33 | columns = { 34 | "icon", 35 | -- "permissions", 36 | -- "size", 37 | -- "mtime", 38 | }, 39 | win_options = { 40 | wrap = false, 41 | signcolumn = "no", 42 | cursorcolumn = false, 43 | foldcolumn = "0", 44 | spell = false, 45 | list = false, 46 | conceallevel = 3, 47 | concealcursor = "nvic", 48 | }, 49 | lsp_file_methods = { 50 | -- Enable or disable LSP file operations 51 | enabled = true, 52 | -- Time to wait for LSP file operations to complete before skipping 53 | timeout_ms = 1000, 54 | -- Set to true to autosave buffers that are updated with LSP willRenameFiles 55 | -- Set to "unmodified" to only save unmodified buffers 56 | autosave_changes = false, 57 | }, 58 | -- Can be "fast", true, or false. "fast" will turn it off for large directories. 59 | natural_order = true, 60 | -- Sort file and directory names case insensitive 61 | case_insensitive = true, 62 | }) 63 | -------------------------------------------------------------------------------- /pwnvim/plugins/todo-comments.lua: -------------------------------------------------------------------------------- 1 | local signs = require("pwnvim.signs") 2 | require("todo-comments").setup { 3 | -- your configuration comes here 4 | -- or leave it empty to use the default settings 5 | -- refer to the configuration section below 6 | signs = false, -- show icons in the signs column 7 | keywords = { 8 | FIX = { 9 | icon = " ", -- icon used for the sign, and in search results 10 | color = "error", -- can be a hex color, or a named color (see below) 11 | alt = { "ERROR", "FIXME", "BUG", "FIXIT", "ISSUE", "!!!" }, -- a set of other keywords that all map to this FIX keywords 12 | -- signs = false, -- configure signs for some keywords individually 13 | }, 14 | TODO = { icon = " ", color = "info", alt = { "PWTODO", "TK", "TODO" } }, 15 | HACK = { icon = " ", color = "warning" }, 16 | WARN = { icon = signs.warn, color = "warning", alt = { "WARNING", "XXX" } }, 17 | PERF = { icon = " ", alt = { "OPTIM", "PERFORMANCE", "OPTIMIZE" } }, 18 | NOTE = { icon = " ", color = "hint", alt = { "INFO" } }, 19 | TEST = { icon = "⏲ ", color = "test", alt = { "TESTING", "PASSED", "FAILED" } }, 20 | }, 21 | merge_keywords = true, -- when true, custom keywords will be merged with the defaults 22 | -- highlighting of the line containing the todo comment 23 | -- * before: highlights before the keyword (typically comment characters) 24 | -- * keyword: highlights of the keyword 25 | -- * after: highlights after the keyword (todo text) 26 | highlight = { 27 | multiline = false, 28 | before = "", -- "fg" or "bg" or empty 29 | keyword = "wide", -- "fg", "bg", "wide" or empty. (wide is the same as bg, but will also highlight surrounding characters) 30 | after = "fg", -- "fg" or "bg" or empty 31 | pattern = [[<(KEYWORDS)]], -- pattern or table of patterns, used for highlightng (vim regex) 32 | -- override this to false in markdown files 33 | comments_only = true, -- uses treesitter to match keywords in comments only 34 | max_line_len = 400, -- ignore lines longer than this 35 | exclude = {}, -- list of file types to exclude highlighting 36 | }, 37 | -- list of named colors where we try to extract the guifg from the 38 | -- list of hilight groups or use the hex color if hl not found as a fallback 39 | colors = { 40 | error = { "DiagnosticError", "ErrorMsg", "#DC2626" }, 41 | warning = { "DiagnosticWarning", "WarningMsg", "#FBBF24" }, 42 | info = { "DiagnosticInfo", "#2563EB" }, 43 | hint = { "DiagnosticHint", "#10B981" }, 44 | default = { "Identifier", "#7C3AED" }, 45 | }, 46 | search = { 47 | command = "rg", 48 | args = { 49 | "--color=never", 50 | "--no-heading", 51 | "--with-filename", 52 | "--line-number", 53 | "--column", 54 | }, 55 | -- regex that will be used to match keywords. 56 | -- don't replace the (KEYWORDS) placeholder 57 | pattern = [[\b(KEYWORDS)]], -- match without the extra colon. You'll likely get false positives 58 | }, 59 | } 60 | -------------------------------------------------------------------------------- /pwnvim/plugins/treesitter.lua: -------------------------------------------------------------------------------- 1 | require("nvim-treesitter.configs").setup({ 2 | sync_install = false, 3 | modules = {}, 4 | disable = {}, 5 | ensure_installed = {}, 6 | ignore_install = { "all" }, 7 | auto_install = false, 8 | autotag = { enable = true }, 9 | highlight = { 10 | enable = true, 11 | disable = {}, 12 | 13 | additional_vim_regex_highlighting = false 14 | }, 15 | indent = { enable = true, disable = { "yaml", "markdown", "dbout" } }, 16 | incremental_selection = { 17 | enable = true, 18 | disable = {}, 19 | is_supported = function() 20 | -- disable in command window 21 | local mode = vim.api.nvim_get_mode().mode 22 | return mode ~= "c" 23 | end 24 | }, 25 | context_commentstring = { 26 | enable = true, 27 | disable = { "dbout" }, 28 | }, 29 | matchup = { 30 | enable = true, 31 | disable = { "dbout" }, 32 | include_match_words = true 33 | }, 34 | textsubjects = { 35 | enable = true, 36 | }, 37 | textobjects = { 38 | disable = {}, 39 | select = { 40 | enable = true, 41 | lookahead = true, 42 | keymaps = { 43 | -- You can use the capture groups defined in textobjects.scm 44 | ["af"] = { query = "@function.outer", desc = "Select outer function" }, 45 | ["if"] = { query = "@function.inner", desc = "Select inner function" }, 46 | ["ac"] = { query = "@class.outer", desc = "Select outer class" }, 47 | ["ic"] = { query = "@class.inner", desc = "Select inner class" }, 48 | ["im"] = { query = "@block.inner", desc = "Select inner block" }, 49 | ["am"] = { query = "@block.outer", desc = "Select outer block" } 50 | -- ["il"] = { query = "@list.inner", desc = "Select inner list" }, 51 | -- ["al"] = { query = "@list.outer", desc = "Select outer list" }, 52 | -- ["ih"] = { query = "@section.inner", desc = "Select inner section" }, 53 | -- ["ah"] = { query = "@section.outer", desc = "Select outer section" }, 54 | } 55 | }, 56 | move = { 57 | enable = true, 58 | set_jumps = true, -- khether to set jumps in the jumplist 59 | goto_next_start = { 60 | ["]m"] = "@function.outer", 61 | ["]]"] = { query = "@class.outer", desc = "Next class start" } 62 | }, 63 | goto_next_end = { ["]M"] = "@function.outer", ["]["] = "@class.outer" }, 64 | goto_previous_start = { 65 | ["[m"] = "@function.outer", 66 | ["[["] = "@class.outer" 67 | }, 68 | goto_previous_end = { ["[M"] = "@function.outer", ["[]"] = "@class.outer" } 69 | }, 70 | lsp_interop = { 71 | enable = true, 72 | border = "none", 73 | floating_preview_opts = {}, 74 | peek_definition_code = { 75 | ["df"] = "@function.outer", 76 | ["dF"] = "@class.outer" 77 | } 78 | } 79 | } 80 | }) 81 | require('nvim-treesitter-textsubjects').configure({ 82 | prev_selection = '\'', 83 | keymaps = { 84 | ['.'] = 'textsubjects-smart', 85 | [';'] = 'textsubjects-container-outer', 86 | ['i;'] = 'textsubjects-container-inner', 87 | }, 88 | }) 89 | -------------------------------------------------------------------------------- /pwnvim/signs.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.error = SimpleUI and "🛑" or "" 4 | M.warn = SimpleUI and "⚠️" or "" 5 | M.hint = SimpleUI and "" or "" 6 | M.info = SimpleUI and "❓" or "" 7 | M.signs = { 8 | { name = "DiagnosticSignError", text = M.error }, 9 | { name = "DiagnosticSignWarn", text = M.warn }, 10 | { name = "DiagnosticSignHint", text = M.hint }, 11 | { name = "DiagnosticSignInfo", text = M.info } 12 | } 13 | if SimpleUI then 14 | M.kind_icons = { 15 | Text = "T", 16 | Method = "m", 17 | Function = "f", 18 | Constructor = "c", 19 | Field = "f", 20 | Variable = "v", 21 | Class = "", 22 | Interface = "i", 23 | Module = "m", 24 | Property = "p", 25 | Unit = "u", 26 | Value = "v", 27 | Enum = "e", 28 | Keyword = "", 29 | Snippet = "s", 30 | Color = "", 31 | File = "F", 32 | Reference = "r", 33 | Folder = "🖿", 34 | EnumMember = "em", 35 | Constant = "c", 36 | Struct = "s", 37 | Event = "e", 38 | Operator = "o", 39 | TypeParameter = "t" 40 | } 41 | else 42 | M.kind_icons = { 43 | Text = "", 44 | Method = "m", 45 | Function = "", 46 | Constructor = "", 47 | Field = "", 48 | Variable = "", 49 | Class = "", 50 | Interface = "", 51 | Module = "", 52 | Property = "", 53 | Unit = "", 54 | Value = "", 55 | Enum = "", 56 | Keyword = "", 57 | Snippet = "", 58 | Color = "", 59 | File = "", 60 | Reference = "", 61 | Folder = "", 62 | EnumMember = "", 63 | Constant = "", 64 | Struct = "", 65 | Event = "", 66 | Operator = "", 67 | TypeParameter = "" 68 | } 69 | end 70 | 71 | for _, sign in ipairs(M.signs) do 72 | vim.fn.sign_define(sign.name, 73 | { texthl = M.name, text = M.text, numhl = "" }) 74 | end 75 | 76 | 77 | return M 78 | -------------------------------------------------------------------------------- /pwnvim/tasks.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.completeTaskDirect = function() 4 | local line = vim.api.nvim_get_current_line() 5 | local nline = require("pwnvim.tasks").completeTask(line) 6 | vim.api.nvim_set_current_line(nline) 7 | end 8 | 9 | M.completeTask = function(line) 10 | local nline = line:gsub("%[[ oO]%]", "[x]", 1) 11 | if line ~= nline then -- substitution successful, now add date completed 12 | nline = nline .. ' @done(' .. os.date("%Y-%m-%d %-I:%M %p") .. ")" 13 | return nline 14 | else -- or do nothing 15 | return line 16 | end 17 | end 18 | 19 | M.scheduleTaskDirect = function(newyear, newmonth, newday) 20 | local line = vim.api.nvim_get_current_line() 21 | local nline = require("pwnvim.tasks").scheduleTask(line, newyear, newmonth, newday) 22 | vim.api.nvim_set_current_line(nline) 23 | end 24 | 25 | M.scheduleTask = function(line, newyear, newmonth, newday) 26 | newmonth = string.format("%02d", newmonth) 27 | newday = string.format("%02d", newday) 28 | local buf = vim.api.nvim_get_current_buf() 29 | local win = vim.api.nvim_get_current_win() 30 | 31 | -- Step 0: ignore tasks that are complete or canceled 32 | if line:match("%[[xX-]%] ") ~= nil then 33 | return line 34 | end 35 | 36 | -- Step 1: change current task to [>] 37 | local nline = line:gsub("%[[ oO>]%] ", "[>] ", 1) 38 | if line ~= nline then 39 | -- if we're here, this is a task 40 | -- if the line isn't a task, we're still copying it over, just without all the modifications 41 | -- Step 2: add scheduled date to end as ">YYYY-mm-dd" removing any existing ">date" tags 42 | nline = nline:gsub(">[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]?", "") 43 | nline = nline .. " >" .. newyear .. "-" .. newmonth .. "-" .. newday 44 | --vim.api.nvim_set_current_line(nline) 45 | 46 | -- Step 3: try to get the date from the current note 47 | local date = require("pwnvim.tasks").getDateFromCurrentFile() 48 | 49 | -- Step 4: add "luado return require('pwnvim.tasks').scheduleTask(line,'" .. 72 | year .. "','" .. month .. "','" .. day .. "')") 73 | end) 74 | end 75 | 76 | M.scheduleTaskPrompt = function() 77 | require("pwnvim.tasks").datePromptThen(require("pwnvim.tasks").scheduleTaskDirect) 78 | end 79 | 80 | M.datePromptThen = function(myfunc) 81 | local days = {} 82 | -- Generate dates for next two weeks with handy shortcut labels 83 | for i = 0, 14, 1 do 84 | local day 85 | if i == 0 then 86 | day = os.date("%Y-%m-%d (today)", os.time() + 86400 * i) 87 | elseif i == 1 then 88 | day = os.date("%Y-%m-%d (tomorrow)", os.time() + 86400 * i) 89 | elseif i > 7 then 90 | day = os.date("%Y-%m-%d (next %a)", os.time() + 86400 * i) 91 | else 92 | day = os.date("%Y-%m-%d (%a)", os.time() + 86400 * i) 93 | end 94 | table.insert(days, day) 95 | end 96 | -- These will pop up in telescope for quick filtering 97 | vim.ui.select(days, { prompt = 'Pick a date:' }, function(choice) 98 | if choice then 99 | local t = {} 100 | for w in string.gmatch(choice, "(%d+)") do 101 | table.insert(t, w) 102 | end 103 | if #t == 3 then 104 | myfunc(t[1], t[2], t[3]) 105 | end 106 | else 107 | -- if no choice was made, assume a desire to specify something outside the 14 days 108 | M.datePromptRawThen(myfunc) 109 | end 110 | end) 111 | end 112 | 113 | -- Just give three prompts for year/month/day 114 | M.datePromptRawThen = function(myfunc) 115 | local defaultyear = os.date("%Y") 116 | local defaultmonth = os.date("%m") 117 | local defaultday = os.date("%d") 118 | vim.ui.input({ prompt = "Enter year: ", default = defaultyear }, function(year) 119 | vim.ui.input({ prompt = "Enter month: ", default = defaultmonth }, function(month) 120 | vim.ui.input({ prompt = "Enter day: ", default = defaultday }, function(day) 121 | month = string.format("%02d", month) 122 | day = string.format("%02d", day) 123 | myfunc(year, month, day) 124 | end) 125 | end) 126 | end) 127 | end 128 | 129 | M.scheduleTaskTodayDirect = function() 130 | local year = os.date("%Y") 131 | local month = os.date("%m") 132 | local day = os.date("%d") 133 | require("pwnvim.tasks").scheduleTaskDirect(year, month, day) 134 | end 135 | 136 | M.scheduleTaskToday = function(line) 137 | local year = os.date("%Y") 138 | local month = os.date("%m") 139 | local day = os.date("%d") 140 | return require("pwnvim.tasks").scheduleTask(line, year, month, day) 141 | end 142 | 143 | M.getDateFromCurrentFile = function() 144 | local srcfilename = vim.api.nvim_buf_get_name(0) 145 | local date = srcfilename:match("%d+-%d+-%d+") 146 | -- TODO: also check for filenames that are "YYYYmmdd.md" 147 | if date == nil then 148 | local srcheader = vim.api.nvim_buf_get_lines(0, 0, 10, false) 149 | for _, l in ipairs(srcheader) do 150 | date = l:match("^[dD]ate: (%d+-%d+-%d+)") 151 | if date ~= nil then break end 152 | end 153 | end 154 | return date 155 | end 156 | 157 | M.createTask = function(line) 158 | local nline = line:gsub("^%s*[-*] ", "%0[ ] ", 1) 159 | if line == nline then 160 | nline = line:gsub("^%s*", "%0* [ ] ", 1) 161 | end 162 | return nline 163 | end 164 | 165 | M.createTaskDirect = function() 166 | local line = vim.api.nvim_get_current_line() 167 | local nline = require("pwnvim.tasks").createTask(line) 168 | vim.api.nvim_set_current_line(nline) 169 | vim.cmd("normal 4l") 170 | end 171 | 172 | 173 | local function visual_selection_range() 174 | local _, csrow, cscol, _ = unpack(vim.fn.getpos("'<")) 175 | local _, cerow, cecol, _ = unpack(vim.fn.getpos("'>")) 176 | if csrow < cerow or (csrow == cerow and cscol <= cecol) then 177 | return csrow - 1, cscol - 1, cerow - 1, cecol 178 | else 179 | return cerow - 1, cecol - 1, csrow - 1, cscol 180 | end 181 | end 182 | 183 | M.eachSelectedLine = function(myfunc) 184 | -- local rowstart, _, rowend, _ = visual_selection_range() 185 | local rowstart = vim.api.nvim_buf_get_mark(0, "<")[1] - 1 186 | local rowend = vim.api.nvim_buf_get_mark(0, ">")[1] - 1 187 | local buf = vim.api.nvim_get_current_buf() 188 | local win = vim.api.nvim_get_current_win() 189 | print("row start:" .. rowstart .. " row end:" .. rowend) 190 | 191 | for i = rowstart, rowend do 192 | print("i:" .. i) 193 | vim.api.nvim_set_current_buf(buf) 194 | vim.api.nvim_set_current_win(win) 195 | vim.api.nvim_win_set_cursor(win, { i + 1, 0 }) 196 | -- All we're really doing here is putting the cursor on each line of the selection 197 | myfunc() 198 | end 199 | end 200 | 201 | return M 202 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | OLDRESULT=$(realpath result) 4 | nix flake update 5 | nix build --json \ 6 | | jq -r '.[].outputs | to_entries[].value' \ 7 | | cachix push zmre 8 | echo "Diff with $OLDRESULT" 9 | nix store diff-closures "$OLDRESULT" ./result |grep '→' 10 | #nix store diff-closures "$OLDRESULT" ./result |grep -Ev '[∅ε]' |grep '→' 11 | 12 | --------------------------------------------------------------------------------