├── .editorconfig ├── .gitignore ├── .stylua.toml ├── LICENSE ├── README.md ├── assets └── logo.svg └── lua └── nvim-emmet └── init.lua /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.lua] 2 | indent_style = space 3 | indent_size = 4 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/macos,linux,windows,lua,vim 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=macos,linux,windows,lua,vim 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### Lua ### 20 | # Compiled Lua sources 21 | luac.out 22 | 23 | # luarocks build files 24 | *.src.rock 25 | *.zip 26 | *.tar.gz 27 | 28 | # Object files 29 | *.o 30 | *.os 31 | *.ko 32 | *.obj 33 | *.elf 34 | 35 | # Precompiled Headers 36 | *.gch 37 | *.pch 38 | 39 | # Libraries 40 | *.lib 41 | *.a 42 | *.la 43 | *.lo 44 | *.def 45 | *.exp 46 | 47 | # Shared objects (inc. Windows DLLs) 48 | *.dll 49 | *.so 50 | *.so.* 51 | *.dylib 52 | 53 | # Executables 54 | *.exe 55 | *.out 56 | *.app 57 | *.i*86 58 | *.x86_64 59 | *.hex 60 | 61 | 62 | ### macOS ### 63 | # General 64 | .DS_Store 65 | .AppleDouble 66 | .LSOverride 67 | 68 | # Icon must end with two \r 69 | Icon 70 | 71 | 72 | # Thumbnails 73 | ._* 74 | 75 | # Files that might appear in the root of a volume 76 | .DocumentRevisions-V100 77 | .fseventsd 78 | .Spotlight-V100 79 | .TemporaryItems 80 | .Trashes 81 | .VolumeIcon.icns 82 | .com.apple.timemachine.donotpresent 83 | 84 | # Directories potentially created on remote AFP share 85 | .AppleDB 86 | .AppleDesktop 87 | Network Trash Folder 88 | Temporary Items 89 | .apdisk 90 | 91 | ### macOS Patch ### 92 | # iCloud generated files 93 | *.icloud 94 | 95 | ### Vim ### 96 | # Swap 97 | [._]*.s[a-v][a-z] 98 | !*.svg # comment out if you don't need vector files 99 | [._]*.sw[a-p] 100 | [._]s[a-rt-v][a-z] 101 | [._]ss[a-gi-z] 102 | [._]sw[a-p] 103 | 104 | # Session 105 | Session.vim 106 | Sessionx.vim 107 | 108 | # Temporary 109 | .netrwhist 110 | # Auto-generated tag files 111 | tags 112 | # Persistent undo 113 | [._]*.un~ 114 | 115 | ### Windows ### 116 | # Windows thumbnail cache files 117 | Thumbs.db 118 | Thumbs.db:encryptable 119 | ehthumbs.db 120 | ehthumbs_vista.db 121 | 122 | # Dump file 123 | *.stackdump 124 | 125 | # Folder config file 126 | [Dd]esktop.ini 127 | 128 | # Recycle Bin used on file shares 129 | $RECYCLE.BIN/ 130 | 131 | # Windows Installer files 132 | *.cab 133 | *.msi 134 | *.msix 135 | *.msm 136 | *.msp 137 | 138 | # Windows shortcuts 139 | *.lnk 140 | 141 | # End of https://www.toptal.com/developers/gitignore/api/macos,linux,windows,lua,vim 142 | -------------------------------------------------------------------------------- /.stylua.toml: -------------------------------------------------------------------------------- 1 | indent_type = "Spaces" 2 | indent_width = 4 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-present José Olórtegui 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 | 2 |
3 | 4 |

nvim-emmet

5 |

A plugin that adds integration between Neovim and emmet-language-server.

6 |
7 | 8 | --- 9 | 10 | ### Features 11 | 12 | > [!NOTE] 13 | > If you have an idea of a possible feature, let me know with an issue. 14 | 15 | - Wrap in normal, visual and visual block mode with emmet abbreviation. 16 | 17 | ### Installation 18 | 19 | > [!WARNING] 20 | > This plugin requires [emmet-language-server](https://github.com/olrtg/emmet-language-server) (v2.2.0 and above) so make sure you have it setup correctly first. 21 | 22 | **[lazy.nvim](https://github.com/folke/lazy.nvim)** 23 | 24 | ```lua 25 | { 26 | "olrtg/nvim-emmet", 27 | config = function() 28 | vim.keymap.set({ "n", "v" }, 'xe', require('nvim-emmet').wrap_with_abbreviation) 29 | end, 30 | }, 31 | ``` 32 | -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Emmet Logo 4 | 5 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /lua/nvim-emmet/init.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local utils = { 4 | trim = function(text) 5 | return (text:gsub("^%s*(.-)%s*$", "%1")) 6 | end, 7 | --- Function to press escape key programmatically. Created so neovim can 8 | --- update the marks for visual mode. 9 | press_escape = function() 10 | local keys = vim.api.nvim_replace_termcodes("", true, false, true) 11 | vim.api.nvim_feedkeys(keys, "x", false) 12 | end, 13 | } 14 | 15 | M.wrap_with_abbreviation = function() 16 | --- @param to_replace string 17 | --- @param callback function 18 | local request_abbreviation = function(to_replace, callback) 19 | local abbreviation = vim.fn.input("Abbreviation: ") --[[@as string]] 20 | 21 | if abbreviation == "" then 22 | return 23 | end 24 | 25 | local opts = { text = utils.trim(to_replace) } 26 | 27 | vim.lsp.buf_request( 28 | 0, 29 | "emmet/expandAbbreviation", 30 | { abbreviation = abbreviation, language = vim.bo.filetype, options = opts }, 31 | --- @param result string 32 | function(_, result, _, _) 33 | if not result then 34 | return 35 | end 36 | 37 | callback(result) 38 | end 39 | ) 40 | end 41 | 42 | local for_visual_mode = function() 43 | utils.press_escape() 44 | 45 | local start_mark = vim.api.nvim_buf_get_mark(0, "<") 46 | local end_mark = vim.api.nvim_buf_get_mark(0, ">") 47 | 48 | local current_lines = 49 | vim.api.nvim_buf_get_text(0, start_mark[1] - 1, start_mark[2], end_mark[1] - 1, end_mark[2] + 1, {}) 50 | 51 | request_abbreviation( 52 | table.concat(current_lines, "\n"), 53 | --- @param result string 54 | function(result) 55 | local lines = vim.split(result, "\n") 56 | vim.api.nvim_buf_set_text(0, start_mark[1] - 1, start_mark[2], end_mark[1] - 1, end_mark[2] + 1, lines) 57 | end 58 | ) 59 | end 60 | 61 | local for_visual_block_mode = function() 62 | utils.press_escape() 63 | 64 | local start_mark = vim.api.nvim_buf_get_mark(0, "<") 65 | local end_mark = vim.api.nvim_buf_get_mark(0, ">") 66 | 67 | local current_lines = vim.api.nvim_buf_get_lines(0, start_mark[1] - 1, end_mark[1], false) 68 | 69 | request_abbreviation( 70 | table.concat(current_lines, "\n"), 71 | --- @param result string 72 | function(result) 73 | local lines = vim.split(result, "\n") 74 | vim.api.nvim_buf_set_lines(0, start_mark[1] - 1, end_mark[1], false, lines) 75 | end 76 | ) 77 | end 78 | 79 | local for_normal_mode = function() 80 | local current_line = vim.api.nvim_get_current_line() 81 | local current_row = vim.api.nvim_win_get_cursor(0)[1] 82 | 83 | request_abbreviation( 84 | current_line, 85 | --- @param result string 86 | function(result) 87 | local lines = vim.split(result, "\n") 88 | vim.api.nvim_buf_set_lines(0, current_row - 1, current_row, false, lines) 89 | end 90 | ) 91 | end 92 | 93 | local mode = vim.api.nvim_get_mode().mode --[[@as "i" | "n" | "v" | "V" | "x"]] 94 | 95 | if mode == "v" then 96 | for_visual_mode() 97 | return 98 | end 99 | 100 | if mode == "V" then 101 | for_visual_block_mode() 102 | return 103 | end 104 | 105 | for_normal_mode() 106 | end 107 | 108 | return M 109 | --------------------------------------------------------------------------------