diff --git a/docs/ide-integration.md b/docs/ide-integration.md index 9dcde7e9fc..52be179b95 100644 --- a/docs/ide-integration.md +++ b/docs/ide-integration.md @@ -102,6 +102,8 @@ let $PATH = $HOME . '/.local/share/mise/shims:' . $PATH vim.env.PATH = vim.env.HOME .. "/.local/share/mise/shims:" .. vim.env.PATH ``` +For a better Treesitter and LSP integration, check out the [neovim cookbook](./mise-cookbook/neovim.md). + ## emacs ### Traditional shims way diff --git a/docs/mise-cookbook/index.md b/docs/mise-cookbook/index.md index 8dfc78fac7..79b567a841 100644 --- a/docs/mise-cookbook/index.md +++ b/docs/mise-cookbook/index.md @@ -8,6 +8,7 @@ Here we are sharing a few mise setups that other people have found useful. - [Python](python.md) - [Ruby](ruby.md) - [Terraform](terraform.md) +- [Neovim](neovim.md) Finally, here is how to create [presets](presets.md) and some [shell tricks](shell-tricks.md) you might find useful. diff --git a/docs/mise-cookbook/neovim.md b/docs/mise-cookbook/neovim.md new file mode 100644 index 0000000000..cf37a01df5 --- /dev/null +++ b/docs/mise-cookbook/neovim.md @@ -0,0 +1,102 @@ +# Mise + Neovim Cookbook + +Here are some tips for an improved mise workflow with [Neovim](https://github.com/neovim/neovim). + +## Code highlight for run commands + +Use [Treesitter](https://github.com/nvim-treesitter/nvim-treesitter) to highlight code in the run commands of your mise files as shown on the left side of the image: + +![image](https://github.com/user-attachments/assets/2961163b-1e6b-4ff6-b2e6-29eb53afc7e5) + +In your neovim config, create a `after/queries/toml/injections.scm` file with these queries: + +```scm +; extends + +(pair + (bare_key) @key (#eq? @key "run") + (string) @injection.content @injection.language + + (#is-mise?) + (#match? @injection.language "^\"\"\"\n*#!(/\\w+)+/env\\s+\\w+") ; multiline shebang using env + (#gsub! @injection.language "^.*#!/.*/env%s+([^%s]+).*" "%1") ; extract lang + (#offset! @injection.content 0 3 0 -3) ; rm quotes +) + +(pair + (bare_key) @key (#eq? @key "run") + (string) @injection.content @injection.language + + (#is-mise?) + (#match? @injection.language "^\"\"\"\n*#!(/\\w+)+\s*\n") ; multiline shebang + (#gsub! @injection.language "^.*#!/.*/([^/%s]+).*" "%1") ; extract lang + (#offset! @injection.content 0 3 0 -3) ; rm quotes +) + +(pair + (bare_key) @key (#eq? @key "run") + (string) @injection.content + + (#is-mise?) + (#match? @injection.content "^\"\"\"\n*.*") ; multiline + (#not-match? @injection.content "^\"\"\"\n*#!") ; no shebang + (#offset! @injection.content 0 3 0 -3) ; rm quotes + (#set! injection.language "bash") ; default to bash +) + +(pair + (bare_key) @key (#eq? @key "run") + (string) @injection.content + + (#is-mise?) + (#not-match? @injection.content "^\"\"\"") ; not multiline + (#offset! @injection.content 0 1 0 -1) ; rm quotes + (#set! injection.language "bash") ; default to bash +) +``` + +To only apply the highlighting on mise files instead of all toml files, the `is-mise?` predicate is used. If you don't care for this distinction, the lines containing `(#is-mise?)` can be removed. +Otherwise, make sure to also create the predicate somewhere in your neovim config. + +For example, using [`lazy.nvim`](https://github.com/folke/lazy.nvim): + +```lua +{ + "nvim-treesitter/nvim-treesitter", + init = function() + require("vim.treesitter.query").add_predicate("is-mise?", function(_, _, bufnr, _) + local filepath = vim.api.nvim_buf_get_name(tonumber(bufnr) or 0) + local filename = vim.fn.fnamemodify(filepath, ":t") + return string.match(filename, ".*mise.*%.toml$") + end, { force = true, all = false }) + end, +}, +``` + +This will consider any `toml` file containing `mise` in its name as a mise file. + +## Enable LSP for embedded lang in run commands + +Use [`otter.nvim`](https://github.com/jmbuhr/otter.nvim) to enable LSP features and code completion for code embedded in your mise files. + +Again using [`lazy.nvim`](https://github.com/folke/lazy.nvim): + +```lua +{ + "jmbuhr/otter.nvim", + dependencies = { + "nvim-treesitter/nvim-treesitter", + }, + config = function() + vim.api.nvim_create_autocmd({ "FileType" }, { + pattern = { "toml" }, + group = vim.api.nvim_create_augroup("EmbedToml", {}), + callback = function() + require("otter").activate() + end, + }) + end, +}, +``` + +This will only work if the [TS injection queries](#code-highlight-for-run-commands) are also set up.