├── LICENSE ├── README.md ├── lua └── tinyunit │ ├── config.lua │ ├── init.lua │ ├── state.lua │ └── ui.lua └── plugin └── tinyunit.vim /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Átila de Freitas 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 | # TinyUnit 2 | 3 | TinyUnit is a minimalist unit converter for Neovim, designed to seamlessly convert between different CSS units directly within your editor. Perfect for frontend developers who want to quickly convert measurements without leaving their editor. 4 | 5 | https://github.com/user-attachments/assets/451ed70b-f771-447a-8186-d2cba03b32ee 6 | 7 | ## 🚀 Features 8 | 9 | - 🪟 Convert units in a clean **floating window** 10 | - 📏 Support for common CSS units (px, rem, em, vh, vw, mm, cm, in, pt) 11 | - 🎯 Visual selection support for direct conversion 12 | - ⚡ Fast and lightweight 13 | - 🎨 Adapts to your Neovim **colorscheme** 14 | - 🛠️ Compatible with **Lazy.nvim** for effortless installation 15 | 16 | ## 📦 Installation 17 | 18 | ### Prerequisites 19 | 20 | - Neovim >= 0.8.0 21 | - [Lazy.nvim](https://github.com/folke/lazy.nvim) as your plugin manager 22 | 23 | ### Using Lazy.nvim 24 | 25 | ```lua 26 | return { 27 | "atiladefreitas/tinyunit", 28 | config = function() 29 | require("tinyunit").setup({ 30 | -- your custom config here (optional) 31 | }) 32 | end, 33 | } 34 | ``` 35 | 36 | ### Default Configuration 37 | 38 | TinyUnit comes with sensible defaults that you can override: 39 | 40 | 41 | ```lua 42 | { 43 | window = { 44 | width = 30, -- Width of the floating window 45 | height = 15, -- Height of the floating window 46 | border = "rounded", -- Border style 47 | input_title = "Enter Value", 48 | }, 49 | keymap = { 50 | open = "tc", -- Toggle converter window 51 | close = "q", -- Close window 52 | convert = "", -- Convert value 53 | escape = "", -- Close window 54 | }, 55 | units = { 56 | "px", 57 | "rem", 58 | "em", 59 | "vh", 60 | "vw", 61 | "mm", 62 | "cm", 63 | "in", 64 | "pt", 65 | }, 66 | font = { 67 | base_size = 16, -- Base font size in pixels (default: 16) 68 | }, 69 | } 70 | ``` 71 | 72 | ## 🔑 Usage 73 | 74 | ### Basic Usage 75 | 76 | 1. Press `tc` to open the converter window 77 | 2. Enter a value with unit (e.g., "16px") 78 | 3. Press `` to see all possible conversions 79 | 4. Select a converted value and press `` to replace the original value 80 | 81 | ### Visual Selection 82 | 83 | 1. Select a value in your code (e.g., "16px") 84 | 2. Press `tc` 85 | 3. The converter will automatically convert the selected value 86 | 4. Choose a conversion and press `` to replace the selected text 87 | 88 | ## 🔄 Supported Conversions 89 | 90 | TinyUnit supports conversions between the following units: 91 | 92 | - px (pixels) 93 | - rem (root em) 94 | - em (relative to parent font size) 95 | - vh (viewport height) 96 | - vw (viewport width) 97 | - mm (millimeters) 98 | - cm (centimeters) 99 | - in (inches) 100 | - pt (points) 101 | 102 | ## 📥 Roadmap 103 | 104 | - [ ] Custom conversion formulas 105 | - [ ] More unit types (deg, rad, etc.) 106 | - [x] Configuration for base font size 107 | - [ ] Support for calc() expressions 108 | - [ ] Unit conversion history 109 | 110 | ## 📝 License 111 | 112 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 113 | 114 | ## 🤝 Contributing 115 | 116 | Contributions are welcome! Feel free to: 117 | 118 | - Submit issues for bugs or feature requests 119 | - Create pull requests with improvements 120 | - Share feedback and suggestions 121 | 122 | ## 🌟 Acknowledgments 123 | 124 | Special thanks to: 125 | - The Neovim community 126 | - [Lazy.nvim](https://github.com/folke/lazy.nvim) 127 | - All contributors and users 128 | 129 | ## All my plugins 130 | | Repository | Description | Stars | 131 | |------------|-------------|-------| 132 | | [LazyClip](https://github.com/atiladefreitas/lazyclip) | A Simple Clipboard Manager | ![Stars](https://img.shields.io/github/stars/atiladefreitas/lazyclip?style=social) | 133 | | [Dooing](https://github.com/atiladefreitas/dooing) | A Minimalist Todo List Manager | ![Stars](https://img.shields.io/github/stars/atiladefreitas/dooing?style=social) | 134 | | [TinyUnit](https://github.com/atiladefreitas/tinyunit) | A Practical CSS Unit Converter | ![Stars](https://img.shields.io/github/stars/atiladefreitas/tinyunit?style=social) | 135 | -------------------------------------------------------------------------------- /lua/tinyunit/config.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | -- Default font size constant 4 | local DEFAULT_FONT_SIZE = 16 5 | 6 | M.defaults = { 7 | window = { 8 | width = 30, 9 | height = 15, 10 | border = "rounded", 11 | input_title = "Enter Value", 12 | font = { 13 | base_size = DEFAULT_FONT_SIZE, 14 | parent_size = DEFAULT_FONT_SIZE, 15 | }, 16 | }, 17 | keymap = { 18 | open = "tc", 19 | close = "q", 20 | convert = "", 21 | escape = "", 22 | }, 23 | units = { 24 | "px", 25 | "rem", 26 | "em", 27 | "vh", 28 | "vw", 29 | "mm", 30 | "cm", 31 | "in", 32 | "pt", 33 | }, 34 | -- Simplified font configuration 35 | font = { 36 | base_size = DEFAULT_FONT_SIZE, -- Base font size in pixels, always defaults to 16 37 | }, 38 | } 39 | 40 | M.options = { 41 | base_font_size = DEFAULT_FONT_SIZE, 42 | parent_font_size = DEFAULT_FONT_SIZE, 43 | } 44 | 45 | function M.setup(opts) 46 | -- Deep merge of defaults and user options 47 | M.options = vim.tbl_deep_extend("force", {}, M.defaults, opts or {}) 48 | 49 | -- Ensure base font size is set and valid 50 | if not M.options.font or not M.options.font.base_size or M.options.font.base_size <= 0 then 51 | vim.notify("Invalid font size configuration. Using default: 16px", vim.log.levels.WARN) 52 | M.options.font = M.options.font or {} 53 | M.options.font.base_size = DEFAULT_FONT_SIZE 54 | end 55 | 56 | -- Set parent font size to base size if not specified 57 | M.options.font.parent_size = M.options.font.parent_size or M.options.font.base_size 58 | 59 | -- Update both font sizes 60 | M.options.base_font_size = M.options.font.base_size 61 | M.options.parent_font_size = M.options.font.parent_size 62 | end 63 | 64 | -- Add function to update parent font size 65 | function M.set_parent_font_size(size) 66 | if type(size) == "number" and size > 0 then 67 | M.options.parent_font_size = size 68 | M.options.font.parent_size = size 69 | return true 70 | end 71 | vim.notify("Invalid parent font size. Must be a positive number.", vim.log.levels.ERROR) 72 | return false 73 | end 74 | 75 | return M 76 | -------------------------------------------------------------------------------- /lua/tinyunit/init.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local function setup_commands() 4 | vim.api.nvim_create_user_command("TinyUnitParent", function(opts) 5 | local size = tonumber(opts.args) 6 | if require("tinyunit.config").set_parent_font_size(size) then 7 | vim.notify(string.format("Parent font size set to %dpx", size), vim.log.levels.INFO) 8 | end 9 | end, { 10 | nargs = 1, 11 | desc = "Set parent font size for em calculations", 12 | }) 13 | end 14 | 15 | function M.setup(opts) 16 | local config = require("tinyunit.config") 17 | config.setup(opts) 18 | 19 | local keymap_opts = { 20 | noremap = true, 21 | silent = true, 22 | desc = "Open TinyUnit converter", 23 | } 24 | 25 | vim.keymap.set("n", config.options.keymap.open, function() 26 | require("tinyunit.ui").open_converter() 27 | end, keymap_opts) 28 | 29 | vim.keymap.set("x", config.options.keymap.open, function() 30 | vim.cmd('noau normal! "vy"') 31 | local selected_text = vim.fn.getreg("v") 32 | vim.fn.setreg("v", {}) 33 | 34 | if selected_text and selected_text ~= "" then 35 | require("tinyunit.ui").open_converter(selected_text:match("^%s*(.-)%s*$")) 36 | end 37 | end, keymap_opts) 38 | 39 | setup_commands() 40 | end 41 | 42 | return M 43 | -------------------------------------------------------------------------------- /lua/tinyunit/state.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | local config = require("tinyunit.config") 3 | 4 | -- get base font size 5 | local function get_base_font_size() 6 | return config.options.base_font_size or 16 7 | end 8 | 9 | local function get_parent_font_size() 10 | return config.options.parent_font_size or get_base_font_size() 11 | end 12 | 13 | M.base_units = { 14 | "px", 15 | "rem", 16 | "em", 17 | "mm", 18 | "cm", 19 | "in", 20 | "pt", 21 | "vh", 22 | "vw", 23 | } 24 | 25 | local CONSTANTS = { 26 | PX_PER_INCH = 96, 27 | PT_PER_INCH = 72, 28 | MM_PER_INCH = 25.4, 29 | CM_PER_INCH = 2.54, 30 | } 31 | 32 | M.conversions = { 33 | px = { 34 | to_rem = function(value) 35 | return value / get_base_font_size() 36 | end, 37 | to_em = function(value) 38 | return value / get_parent_font_size() 39 | end, 40 | to_mm = function(value) 41 | return (value / CONSTANTS.PX_PER_INCH) * CONSTANTS.MM_PER_INCH 42 | end, 43 | to_cm = function(value) 44 | return (value / CONSTANTS.PX_PER_INCH) * CONSTANTS.CM_PER_INCH 45 | end, 46 | to_in = function(value) 47 | return value / CONSTANTS.PX_PER_INCH 48 | end, 49 | to_pt = function(value) 50 | return (value / CONSTANTS.PX_PER_INCH) * CONSTANTS.PT_PER_INCH 51 | end, 52 | }, 53 | rem = { 54 | to_px = function(value) 55 | return value * get_base_font_size() 56 | end, 57 | to_em = function(value) 58 | return (value * get_base_font_size()) / get_parent_font_size() 59 | end, 60 | to_mm = function(value) 61 | return (value * get_base_font_size() / CONSTANTS.PX_PER_INCH) * CONSTANTS.MM_PER_INCH 62 | end, 63 | to_cm = function(value) 64 | return (value * get_base_font_size() / CONSTANTS.PX_PER_INCH) * CONSTANTS.CM_PER_INCH 65 | end, 66 | to_in = function(value) 67 | return (value * get_base_font_size()) / CONSTANTS.PX_PER_INCH 68 | end, 69 | to_pt = function(value) 70 | return (value * get_base_font_size() / CONSTANTS.PX_PER_INCH) * CONSTANTS.PT_PER_INCH 71 | end, 72 | }, 73 | em = { 74 | to_px = function(value) 75 | return value * get_base_font_size() 76 | end, 77 | to_rem = function(value) 78 | return (value * get_parent_font_size()) / get_base_font_size() 79 | end, 80 | to_mm = function(value) 81 | return (value * get_base_font_size() / CONSTANTS.PX_PER_INCH) * CONSTANTS.MM_PER_INCH 82 | end, 83 | to_cm = function(value) 84 | return (value * get_base_font_size() / CONSTANTS.PX_PER_INCH) * CONSTANTS.CM_PER_INCH 85 | end, 86 | to_in = function(value) 87 | return (value * get_base_font_size()) / CONSTANTS.PX_PER_INCH 88 | end, 89 | to_pt = function(value) 90 | return (value * get_base_font_size() / CONSTANTS.PX_PER_INCH) * CONSTANTS.PT_PER_INCH 91 | end, 92 | }, 93 | mm = { 94 | to_px = function(value) 95 | return (value / CONSTANTS.MM_PER_INCH) * CONSTANTS.PX_PER_INCH 96 | end, 97 | to_rem = function(value) 98 | return ((value / CONSTANTS.MM_PER_INCH) * CONSTANTS.PX_PER_INCH) / get_base_font_size() 99 | end, 100 | to_em = function(value) 101 | return ((value / CONSTANTS.MM_PER_INCH) * CONSTANTS.PX_PER_INCH) / get_base_font_size() 102 | end, 103 | to_cm = function(value) 104 | return value / 10 105 | end, 106 | to_in = function(value) 107 | return value / CONSTANTS.MM_PER_INCH 108 | end, 109 | to_pt = function(value) 110 | return (value / CONSTANTS.MM_PER_INCH) * CONSTANTS.PT_PER_INCH 111 | end, 112 | }, 113 | cm = { 114 | to_px = function(value) 115 | return (value / CONSTANTS.CM_PER_INCH) * CONSTANTS.PX_PER_INCH 116 | end, 117 | to_rem = function(value) 118 | return ((value / CONSTANTS.CM_PER_INCH) * CONSTANTS.PX_PER_INCH) / get_base_font_size() 119 | end, 120 | to_em = function(value) 121 | return ((value / CONSTANTS.CM_PER_INCH) * CONSTANTS.PX_PER_INCH) / get_base_font_size() 122 | end, 123 | to_mm = function(value) 124 | return value * 10 125 | end, 126 | to_in = function(value) 127 | return value / CONSTANTS.CM_PER_INCH 128 | end, 129 | to_pt = function(value) 130 | return (value / CONSTANTS.CM_PER_INCH) * CONSTANTS.PT_PER_INCH 131 | end, 132 | }, 133 | ["in"] = { 134 | to_px = function(value) 135 | return value * CONSTANTS.PX_PER_INCH 136 | end, 137 | to_rem = function(value) 138 | return (value * CONSTANTS.PX_PER_INCH) / get_base_font_size() 139 | end, 140 | to_em = function(value) 141 | return (value * CONSTANTS.PX_PER_INCH) / get_base_font_size() 142 | end, 143 | to_mm = function(value) 144 | return value * CONSTANTS.MM_PER_INCH 145 | end, 146 | to_cm = function(value) 147 | return value * CONSTANTS.CM_PER_INCH 148 | end, 149 | to_pt = function(value) 150 | return value * CONSTANTS.PT_PER_INCH 151 | end, 152 | }, 153 | pt = { 154 | to_px = function(value) 155 | return (value / CONSTANTS.PT_PER_INCH) * CONSTANTS.PX_PER_INCH 156 | end, 157 | to_rem = function(value) 158 | return ((value / CONSTANTS.PT_PER_INCH) * CONSTANTS.PX_PER_INCH) / get_base_font_size() 159 | end, 160 | to_em = function(value) 161 | return ((value / CONSTANTS.PT_PER_INCH) * CONSTANTS.PX_PER_INCH) / get_base_font_size() 162 | end, 163 | to_mm = function(value) 164 | return (value / CONSTANTS.PT_PER_INCH) * CONSTANTS.MM_PER_INCH 165 | end, 166 | to_cm = function(value) 167 | return (value / CONSTANTS.PT_PER_INCH) * CONSTANTS.CM_PER_INCH 168 | end, 169 | to_in = function(value) 170 | return value / CONSTANTS.PT_PER_INCH 171 | end, 172 | }, 173 | } 174 | 175 | function M.parse_value(input) 176 | if not input or input == "" then 177 | return nil, nil 178 | end 179 | local value, unit = string.match(input, "([%d%.]+)(%a+)") 180 | return tonumber(value), unit 181 | end 182 | 183 | local function format_number(num) 184 | if math.floor(num) == num then 185 | return string.format("%d", num) 186 | else 187 | return string.format("%.4f", num):gsub("%.?0+$", "") 188 | end 189 | end 190 | 191 | function M.convert_value(value, from_unit) 192 | local results = {} 193 | if not value or not from_unit then 194 | return results 195 | end 196 | 197 | local conversions = M.conversions[from_unit] 198 | if not conversions then 199 | return results 200 | end 201 | 202 | for conv_name, converter in pairs(conversions) do 203 | local to_unit = conv_name:match("to_(.+)") 204 | if to_unit then 205 | local converted = converter(value) 206 | table.insert(results, format_number(converted) .. to_unit) 207 | end 208 | end 209 | 210 | table.sort(results) 211 | return results 212 | end 213 | 214 | return M 215 | -------------------------------------------------------------------------------- /lua/tinyunit/ui.lua: -------------------------------------------------------------------------------- 1 | local api = vim.api 2 | local config = require("tinyunit.config") 3 | local state = require("tinyunit.state") 4 | 5 | local M = {} 6 | local input_win_id = nil 7 | local input_buf_id = nil 8 | local results_win_id = nil 9 | local results_buf_id = nil 10 | local original_selection = { 11 | start_pos = nil, 12 | end_pos = nil, 13 | text = nil, 14 | } 15 | 16 | local function center_of_screen() 17 | local ui = vim.api.nvim_list_uis()[1] 18 | return math.floor(ui.width / 2), math.floor(ui.height / 2) 19 | end 20 | 21 | local function update_results_window_title() 22 | if results_win_id and api.nvim_win_is_valid(results_win_id) then 23 | local parent_size = config.options.parent_font_size 24 | local title = string.format(" Unit Converter (Parent: %dpx) ", parent_size) 25 | api.nvim_win_set_config(results_win_id, { 26 | title = title, 27 | }) 28 | end 29 | end 30 | 31 | local function create_windows() 32 | local opts = config.options.window 33 | local width = opts.width 34 | local height = opts.height 35 | local center_x, center_y = center_of_screen() 36 | 37 | update_results_window_title() 38 | 39 | input_buf_id = api.nvim_create_buf(false, true) 40 | local input_win_opts = { 41 | relative = "editor", 42 | width = width, 43 | height = 1, 44 | row = center_y - 6, 45 | col = center_x - math.floor(width / 2), 46 | style = "minimal", 47 | border = "rounded", 48 | title = opts.input_title, 49 | title_pos = "center", 50 | } 51 | input_win_id = api.nvim_open_win(input_buf_id, true, input_win_opts) 52 | 53 | results_buf_id = api.nvim_create_buf(false, true) 54 | local results_win_opts = { 55 | relative = "editor", 56 | width = width, 57 | height = height, 58 | row = center_y - 4, 59 | col = center_x - math.floor(width / 2), 60 | style = "minimal", 61 | border = "rounded", 62 | title = " Unit Converter ", 63 | title_pos = "center", 64 | footer = " to paste ", 65 | footer_pos = "center", 66 | } 67 | results_win_id = api.nvim_open_win(results_buf_id, false, results_win_opts) 68 | 69 | for _, buf_id in ipairs({ input_buf_id, results_buf_id }) do 70 | api.nvim_buf_set_option(buf_id, "modifiable", true) 71 | api.nvim_buf_set_option(buf_id, "buftype", "nofile") 72 | api.nvim_buf_set_option(buf_id, "bufhidden", "wipe") 73 | end 74 | 75 | local input_keymap_opts = { noremap = true, silent = true, buffer = input_buf_id } 76 | vim.keymap.set("i", config.options.keymap.convert, function() 77 | local value = api.nvim_get_current_line() 78 | vim.cmd("stopinsert") 79 | api.nvim_win_close(input_win_id, true) 80 | api.nvim_set_current_win(results_win_id) 81 | M.convert_value(value) 82 | end, input_keymap_opts) 83 | 84 | vim.keymap.set("i", config.options.keymap.escape, function() 85 | M.close_windows() 86 | end, input_keymap_opts) 87 | 88 | local results_keymap_opts = { noremap = true, silent = true, buffer = results_buf_id } 89 | vim.keymap.set("n", config.options.keymap.convert, function() 90 | M.select_and_replace() 91 | end, results_keymap_opts) 92 | 93 | vim.keymap.set("n", config.options.keymap.close, function() 94 | M.close_windows() 95 | end, results_keymap_opts) 96 | 97 | vim.keymap.set("n", config.options.keymap.escape, function() 98 | M.close_windows() 99 | end, results_keymap_opts) 100 | 101 | vim.cmd("startinsert") 102 | end 103 | 104 | function M.close_windows() 105 | if input_win_id and api.nvim_win_is_valid(input_win_id) then 106 | api.nvim_win_close(input_win_id, true) 107 | end 108 | if results_win_id and api.nvim_win_is_valid(results_win_id) then 109 | api.nvim_win_close(results_win_id, true) 110 | end 111 | end 112 | 113 | function M.convert_value(input) 114 | local value, unit = state.parse_value(input) 115 | if value and unit then 116 | local conversions = state.convert_value(value, unit) 117 | api.nvim_buf_set_lines(results_buf_id, 0, -1, false, conversions) 118 | end 119 | end 120 | 121 | function M.select_and_replace() 122 | local cursor = vim.api.nvim_win_get_cursor(results_win_id) 123 | local selected_value = vim.api.nvim_buf_get_lines(results_buf_id, cursor[1] - 1, cursor[1], false)[1] 124 | 125 | if selected_value then 126 | -- Copy to clipboard 127 | vim.fn.setreg("+", selected_value) 128 | vim.fn.setreg('"', selected_value) 129 | 130 | local target_win = nil 131 | for _, win in ipairs(vim.api.nvim_list_wins()) do 132 | local buf = vim.api.nvim_win_get_buf(win) 133 | if buf ~= input_buf_id and buf ~= results_buf_id then 134 | target_win = win 135 | break 136 | end 137 | end 138 | 139 | if target_win then 140 | vim.api.nvim_set_current_win(target_win) 141 | -- Execute normal mode paste command 142 | vim.cmd('normal! viw"_dP') 143 | end 144 | 145 | M.close_windows() 146 | end 147 | end 148 | 149 | function M.open_converter(initial_value) 150 | if input_win_id and api.nvim_win_is_valid(input_win_id) then 151 | M.close_windows() 152 | end 153 | 154 | if vim.fn.mode() == "v" or vim.fn.mode() == "V" then 155 | vim.cmd('noau normal! "vy"') 156 | local selected_text = vim.fn.getreg("v") 157 | vim.fn.setreg("v", {}) 158 | 159 | if selected_text and selected_text ~= "" then 160 | original_selection.start_pos = vim.fn.getpos("'<") 161 | original_selection.end_pos = vim.fn.getpos("'>") 162 | original_selection.text = selected_text:match("^%s*(.-)%s*$") 163 | initial_value = original_selection.text 164 | end 165 | else 166 | original_selection.start_pos = nil 167 | original_selection.end_pos = nil 168 | original_selection.text = nil 169 | end 170 | 171 | create_windows() 172 | 173 | if initial_value then 174 | api.nvim_buf_set_lines(input_buf_id, 0, -1, false, { initial_value }) 175 | M.convert_value(initial_value) 176 | end 177 | end 178 | 179 | return M 180 | -------------------------------------------------------------------------------- /plugin/tinyunit.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_tinyunit') | finish | endif 2 | let g:loaded_tinyunit = 1 3 | lua require('tinyunit').setup() 4 | --------------------------------------------------------------------------------