├── LICENSE ├── README.md ├── doc └── stylua-nvim.txt ├── lua └── stylua-nvim.lua └── stylua.toml /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Chris Kipp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stylua-nvim 2 | 3 | stylua-nvim is a minimal wrapper around the Lua code formatter, 4 | [StyLua](https://github.com/JohnnyMorganz/StyLua). It does pretty much what 5 | you'd expect it to do, format your Lua file using Stylua. 6 | 7 | ### Install 8 | Make sure you have StyLua installed and then install this plugin: 9 | 10 | ```lua 11 | use({"ckipp01/stylua-nvim"}) 12 | ``` 13 | 14 | If you would like your plugin manager to automatically download Stylua for you, run the Stylua install command using your plugin managers hooks. For example in Packer, you can use the following: 15 | 16 | ```lua 17 | use({"ckipp01/stylua-nvim", run = "cargo install stylua"}) 18 | ``` 19 | 20 | ### Docs 21 | 22 | Everything you need should be in the [help 23 | docs](https://github.com/ckipp01/stylua-nvim/blob/main/doc/stylua-nvim.txt). 24 | -------------------------------------------------------------------------------- /doc/stylua-nvim.txt: -------------------------------------------------------------------------------- 1 | *stylua-nvim.txt* stylua-nvim 2 | 3 | A minimal wrapper around https://github.com/JohnnyMorganz/StyLua to provide a 4 | way to format Lua in an opinionated way while in Nvim, because no one wants to 5 | spend time discussing how you should format. 6 | 7 | STYLUA-NVIM REFERENCE MANUAL 8 | 9 | CONTENTS *stylua-nvim* 10 | 11 | 1. Prerequisites......... |stylua-nvim-prerequisites| 12 | 2. Getting Started....... |stylua-nvim-getting-started| 13 | 3. Lua API............... |stylua-nvim-lua-api| 14 | 4. Example Usage......... |stylua-nvim-example-usage| 15 | 16 | ================================================================================ 17 | PREREQUISITES *stylua-nvim-prerequisites* 18 | 19 | - Nvim v0.5.x 20 | - Make sure to have StyLua installed. You can find instructions here: 21 | https://github.com/JohnnyMorganz/StyLua 22 | 23 | ================================================================================ 24 | GETTING STARTED *stylua-nvim-getting-started* 25 | 26 | Install via your favorite package manager. 27 | > 28 | use({"ckipp01/stylua-nvim"}) 29 | < 30 | 31 | This plugin does not require that setup be called, however it is possible to 32 | provide additional configuration using the setup function. 33 | > 34 | use({"ckipp01/stylua-nvim"}, 35 | config = function() 36 | require("stylua-nvim").setup{config_file = "stylua.toml"} 37 | end) 38 | < 39 | 40 | Available setup options: 41 | 42 | config_file Specifies a configuration file to use for the StylLua 43 | linter. This can be an absolute or relative path. The 44 | default value is nothing, which means the linter will 45 | search for a stylua.toml file using the 46 | `--search-parent-directories` option of the linter. 47 | 48 | error_display_strategy The mechanism to display errors encountered during 49 | linting. Allowed values are 'loclist' or 'none'. Default 50 | value is 'loclist'. 51 | 52 | ================================================================================ 53 | LUA API *stylua-nvim-lua-api* 54 | 55 | 56 | *format_file(config)* 57 | format_file(config) Use to format the current buffer. If any issues are 58 | found, they will be opened in your loclist. 59 | 60 | Takes an optional configuration argument 61 | { 62 | error_display_strategy = 63 | } 64 | 65 | options currently are: 66 | * "loclist": display errors in a location list 67 | * "none": do not display stylua errors 68 | 69 | ================================================================================ 70 | Example Usage *stylua-nvim-example-usage* 71 | 72 | 73 | Via a mapping: > 74 | local opts = { noremap=true, silent=true } 75 | buf_set_keymap("n", "f", [[lua require("stylua-nvim").format_file()]], opts) 76 | < 77 | 78 | Usage via nvim-lspconfig and sumneko_lua to be able to use `:Format`: > 79 | 80 | local lsp_config = require("lspconfig") 81 | lsp_config.sumneko_lua.setup({ 82 | commands = { 83 | Format = { 84 | function() 85 | require("stylua-nvim").format_file() 86 | end, 87 | }, 88 | }, 89 | ... 90 | }) 91 | < 92 | 93 | vim:tw=80:ts=2:ft=help: 94 | -------------------------------------------------------------------------------- /lua/stylua-nvim.lua: -------------------------------------------------------------------------------- 1 | local api = vim.api 2 | local fn = vim.fn 3 | 4 | local M = {} 5 | 6 | local state = { 7 | had_format_err = false, 8 | } 9 | 10 | local config = { 11 | error_display_strategy = "loclist", 12 | } 13 | 14 | local function buf_get_full_text(bufnr) 15 | local text = table.concat(api.nvim_buf_get_lines(bufnr, 0, -1, true), "\n") 16 | if api.nvim_buf_get_option(bufnr, "eol") then 17 | text = text .. "\n" 18 | end 19 | return text 20 | end 21 | 22 | local function create_flags() 23 | if config.config_file then 24 | return "--config-path " .. config.config_file 25 | end 26 | return "--search-parent-directories" 27 | end 28 | 29 | local function no_errors(output, input) 30 | if output ~= input then 31 | local new_lines = vim.fn.split(output, "\n") 32 | api.nvim_buf_set_lines(0, 0, -1, false, new_lines) 33 | end 34 | -- We try a little bit to make sure we aren't closing a loclist that we didn't create. 35 | -- This isn't perfect in the case of long sessions, but probably better than nothing. 36 | if config.error_display_strategy == "loclist" and state.had_format_err then 37 | vim.fn.setloclist(0, {}) 38 | vim.cmd("lclose") 39 | end 40 | end 41 | 42 | local function handle_errors(error_file, bufnr) 43 | local errors = table.concat(vim.fn.readfile(error_file), " ") 44 | 45 | -- Error messages from stylua have been observed in two general formats: 46 | -- 47 | -- Parsing error: 48 | -- error: failed to format from stdin: error parsing: unexpected token `{`. (starting from line 4, character 11 and ending on line 4, character 12) 49 | -- 50 | -- Execution error: 51 | -- error: Found argument '--config-path/Users/jsimpson/dotfiles/nvim/language/stylua.toml' which wasn't expected, or isn't valid in this context 52 | 53 | -- The following approach is sufficient for the observed error messages, but a little fragile as 54 | -- it assumes that the first two numerical values in the error message are the row and column of 55 | -- the error. Generally, parsing related errors will contain the following substring in the error 56 | -- message: 57 | -- (starting from line 32, character 2 and ending on line 32, character 5) 58 | -- So we assume that: 59 | -- - locations[1] = start line 60 | -- - locations[2] = start col 61 | -- - locations[3] = end line 62 | -- - locations[4] = end col 63 | local locations = {} 64 | for num in errors:gmatch("%d+") do 65 | table.insert(locations, num) 66 | end 67 | 68 | if config.error_display_strategy == "loclist" then 69 | -- Error messages where location information could not be parsed will be given (0, 0) as a 70 | -- location. 71 | vim.fn.setloclist(0, { { bufnr = bufnr, lnum = locations[1] or 0, col = locations[2] or 0, text = errors } }) 72 | vim.cmd("lopen") 73 | end 74 | state.had_format_err = true 75 | end 76 | 77 | M.format_file = function(user_config, extra_flags) 78 | if user_config and user_config.error_display_strategy then 79 | config.error_display_strategy = user_config.error_display_strategy 80 | end 81 | local error_file = fn.tempname() 82 | local flags = create_flags() 83 | 84 | local stylua_command = string.format("stylua %s %s - 2> %s", flags, extra_flags or "", error_file) 85 | 86 | local bufnr = vim.fn.bufnr("%") 87 | local input = buf_get_full_text(bufnr) 88 | local output = fn.system(stylua_command, input) 89 | 90 | if fn.empty(output) == 0 then 91 | no_errors(output, input) 92 | else 93 | handle_errors(error_file, bufnr) 94 | end 95 | 96 | fn.delete(error_file) 97 | end 98 | 99 | M.format_range = function(start, stop, user_config) 100 | local extra_flags = ("--range-start %d"):format(fn.line2byte(start) - 1) 101 | if stop == api.nvim_buf_line_count(0) then 102 | M.format_file(user_config, extra_flags) 103 | else 104 | M.format_file(user_config, extra_flags .. (" --range-end %d"):format(fn.line2byte(stop + 1) - 1)) 105 | end 106 | end 107 | 108 | M.setup = function(opt) 109 | opt = opt or {} 110 | config.config_file = opt.config_file 111 | config.error_display_strategy = opt.error_display_strategy 112 | end 113 | 114 | return M 115 | -------------------------------------------------------------------------------- /stylua.toml: -------------------------------------------------------------------------------- 1 | indent_type = "Spaces" 2 | indent_width = 2 3 | --------------------------------------------------------------------------------