├── LICENSE ├── README.md ├── autoload └── hugohelper.vim └── plugin └── hugohelper.vim /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Robert Basic 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 | # vim-hugo-helper 2 | 3 | A small Vim plugin to help me with writing posts with [Hugo](https://gohugo.io). 4 | 5 | # Helpers 6 | 7 | The following helpers are available: 8 | 9 | ## Draft 10 | 11 | `:HugoHelperDraft` drafts the current post. 12 | 13 | ## Undraft 14 | 15 | `:HugoHelperUndraft` undrafts the current post. 16 | 17 | ## Date is now 18 | 19 | `:HugoHelperDateIsNow` sets the date and time of the current post to current date and time. 20 | 21 | ## Highlight 22 | 23 | `:HugoHelperHighlight language` inserts the `highlight` block for "language" in to the current post. 24 | 25 | ## Link 26 | 27 | `:HugoHelperLink` helps with adding links to a document. Visually select the word(s) you want to be a link, enter `:HugoHelperLink https://gohugo.io` and it will turn the selected word(s) to `[selected words](https://gohugo.io)`. 28 | 29 | ![link helper in action](http://i.imgur.com/mVPqgXs.gif) 30 | 31 | Probably works only for markdown documents. 32 | 33 | ## Spell check 34 | 35 | `:HugoHelperSpellCheck` toggles the spell check for the current language. Running it once, turns the spell check on. Running it again, turns it off. 36 | 37 | You can set the language by setting the following in your `.vimrc` file: 38 | 39 | ``` 40 | let g:hugohelper_spell_check_lang = 'en_us' 41 | ``` 42 | 43 | By default it is set to `en_us`. 44 | 45 | ## Title to slug 46 | 47 | `:HugoHelperTitleToSlug` turns the title of the Hugo post to the slug. It assumes the following two lines are present in the frontmatter: 48 | 49 | ``` 50 | +++ 51 | // frontmatter 52 | title = "Title of the post" 53 | // frontmatter 54 | slug = "" 55 | // frontmatter 56 | +++ 57 | ``` 58 | 59 | It will turn it into: 60 | 61 | ``` 62 | +++ 63 | // frontmatter 64 | title = "Title of the post" 65 | // frontmatter 66 | slug = "title-of-the-post" 67 | // frontmatter 68 | +++ 69 | ``` 70 | 71 | # Installation 72 | 73 | ## [vim-plug](https://github.com/junegunn/vim-plug) 74 | 75 | `Plug 'robertbasic/vim-hugo-helper'` 76 | 77 | ## [Vundle](https://github.com/VundleVim/Vundle.vim) 78 | 79 | `PluginInstall 'robertbasic/vim-hugo-helper'` 80 | -------------------------------------------------------------------------------- /autoload/hugohelper.vim: -------------------------------------------------------------------------------- 1 | function! hugohelper#SpellCheck() 2 | exe "setlocal spell! spelllang=" . g:hugohelper_spell_check_lang 3 | endfun 4 | 5 | function! hugohelper#TitleToSlug() 6 | normal gg 7 | exe '/^title' 8 | normal! vi"y 9 | exe '/^slug' 10 | normal! f"pVu 11 | " Not sure why I can't make \%V work here 12 | exe ':s/ /-/g' 13 | exe 'normal! f-r f-r ' 14 | endfun 15 | 16 | function! hugohelper#TitleCase() 17 | normal gg 18 | exe '/^title' 19 | normal! vi"u~ 20 | endfun 21 | 22 | function! hugohelper#Draft() 23 | call s:set_key('draft', 'true') 24 | endfun 25 | 26 | function! hugohelper#Undraft() 27 | call s:set_key('draft', 'false') 28 | endfun 29 | 30 | function! hugohelper#DateIsNow() 31 | call s:set_key('date', s:hugo_now()) 32 | endfun 33 | 34 | function! hugohelper#LastmodIsNow() 35 | call s:set_key('lastmod', s:hugo_now()) 36 | endfun 37 | 38 | function! hugohelper#Highlight(language) 39 | normal! I{{< highlight language_placeholder >}} 40 | exe 's/language_placeholder/' . a:language . '/' 41 | normal! o{{< /highlight >}} 42 | endfun 43 | 44 | function! hugohelper#Link(link) 45 | let l:selection = s:get_visual_selection() 46 | exe ':s/\%V\(.*\)\%V\(.\)/[\0]/' 47 | exe "normal! gv\ef]a(link_placeholder)\e" 48 | exe 's/link_placeholder/' . escape(a:link, '\\/.*^~[]') . '/' 49 | exe "normal! gv\ef)" 50 | endfun 51 | 52 | function! hugohelper#HasFrontMatter() 53 | try 54 | call s:front_matter_format() 55 | return 1 56 | catch 57 | endtry 58 | return 0 59 | endfun 60 | 61 | function! s:get_visual_selection() 62 | " From http://stackoverflow.com/a/6271254/794380 63 | let [lnum1, col1] = getpos("'<")[1:2] 64 | let [lnum2, col2] = getpos("'>")[1:2] 65 | let lines = getline(lnum1, lnum2) 66 | let lines[-1] = lines[-1][: col2 - (&selection == 'inclusive' ? 1 : 2)] 67 | let lines[0] = lines[0][col1 - 1:] 68 | return join(lines, "\n") 69 | endfun 70 | 71 | function! s:front_matter_format() 72 | let l:line = getline(1) 73 | if l:line =~ '+++' 74 | return 'toml' 75 | elseif l:line =~ '---' 76 | return 'yaml' 77 | else 78 | throw "Could not determine Hugo front matter format. Looking for +++ or ---. JSON not supported." 79 | endif 80 | endfun 81 | 82 | function! s:set_key(key, value) 83 | let l:format = s:front_matter_format() 84 | if l:format == 'toml' 85 | exe '1;/+++/substitute/^' . a:key . '\s*=.*/' . a:key . ' = ' . a:value 86 | elseif l:format == 'yaml' 87 | exe '1;/---/substitute/^' . a:key . '\s*:.*/' . a:key . ': ' . a:value 88 | else 89 | throw "Can't set key, value pair for unknown format " . l:format 90 | endif 91 | endfun 92 | 93 | function! s:hugo_now() 94 | " Contrust a time string using the format: 2018-09-18T19:41:32-07:00 95 | let l:time = strftime("%FT%T%z") 96 | return l:time[:-3] . ':' . l:time[-2:] 97 | endfun 98 | 99 | " vim: expandtab shiftwidth=4 100 | -------------------------------------------------------------------------------- /plugin/hugohelper.vim: -------------------------------------------------------------------------------- 1 | if exists('g:hugohelper_plugin_loaded') || &cp 2 | finish 3 | endif 4 | let g:hugohelper_plugin_loaded = 1 5 | 6 | let g:hugohelper_plugin_path = expand(':p:h') 7 | 8 | if !exists('g:hugohelper_spell_check_lang') 9 | let g:hugohelper_spell_check_lang = 'en_us' 10 | endif 11 | 12 | if !exists('g:hugohelper_update_lastmod_on_write') 13 | let g:hugohelper_update_lastmod_on_write = 0 14 | endif 15 | 16 | if !exists('g:hugohelper_content_dir') 17 | let g:hugohelper_content_dir = 'content' 18 | endif 19 | 20 | if !exists('g:hugohelper_site_config') 21 | " List of site configuration files vim-hugo-helper uses to detemine 22 | " the root of the hugo site. 23 | " For more information, see: https://gohugo.io/getting-started/configuration/ 24 | let g:hugohelper_site_config = [ 'config.toml', 'config.yaml', 'config.json' ] 25 | endif 26 | 27 | 28 | 29 | command! -nargs=0 HugoHelperSpellCheck call hugohelper#SpellCheck() 30 | command! -nargs=0 HugoHelperDraft call hugohelper#Draft() 31 | command! -nargs=0 HugoHelperUndraft call hugohelper#Undraft() 32 | command! -nargs=0 HugoHelperDateIsNow call hugohelper#DateIsNow() 33 | command! -nargs=0 HugoHelperLastmodIsNow call hugohelper#LastmodIsNow() 34 | command! -nargs=0 HugoHelperTitleToSlug call hugohelper#TitleToSlug() 35 | command! -nargs=0 HugoHelperTitleCase call hugohelper#TitleCase() 36 | command! -nargs=1 HugoHelperHighlight call hugohelper#Highlight() 37 | command! -range -nargs=1 HugoHelperLink call hugohelper#Link() 38 | 39 | function! HugoHelperFrontMatterReorder() 40 | exe 'g/^draft/m 1' 41 | exe 'g/^date/m 2' 42 | exe 'g/^title/m 3' 43 | exe 'g/^slug/m 4' 44 | exe 'g/^description/m 5' 45 | exe 'g/^tags/m 6' 46 | exe 'g/^categories/m 7' 47 | " create date taxonomy 48 | exe 'g/^date/co 8' 49 | exe ':9' 50 | exe ':s/.*\(\d\{4\}\)-\(\d\{2\}\).*/\1 = ["\2"]' 51 | endfun 52 | 53 | augroup vim-hugo-helper 54 | autocmd BufWritePre *.md call s:UpdateLastMod() 55 | augroup end 56 | 57 | " Update lastmod on save. 58 | function! s:UpdateLastMod() 59 | if s:ShouldUpdateLastMod() 60 | let save_cursor = getcurpos() 61 | call hugohelper#LastmodIsNow() 62 | call setpos('.', save_cursor) 63 | endif 64 | endfunction 65 | 66 | function! s:ShouldUpdateLastMod() 67 | if !g:hugohelper_update_lastmod_on_write 68 | return v:false 69 | endif 70 | 71 | if hugohelper#HasFrontMatter() == 0 72 | return v:false 73 | endif 74 | 75 | " Only update lastmod in markdown in the content directory. In particular, archetypes 76 | " should not be automatically updated. 77 | return s:IsFileInHugoContentDirectory(expand('')) 78 | endfunction 79 | 80 | function! s:IsFileInHugoContentDirectory(filepath) 81 | let l:mods = ':p:h' 82 | let l:dirname = 'dummy' 83 | while !empty(l:dirname) 84 | let l:path = fnamemodify(a:filepath, l:mods) 85 | let l:mods .= ':h' 86 | let l:dirname = fnamemodify(l:path, ':t') 87 | if l:dirname == g:hugohelper_content_dir 88 | " Check if the parent of the content directory contains a config file. 89 | let l:parent = fnamemodify(l:path, ":h") 90 | if s:HasHugoConfigFile(l:parent) 91 | return v:true 92 | endif 93 | endif 94 | endwhile 95 | 96 | return v:false 97 | endfunction 98 | 99 | function! s:HasHugoConfigFile(dir) 100 | " :p adds the final path separator if a:dir is a directory. 101 | let l:dirpath = fnamemodify(a:dir, ':p') 102 | for config in g:hugohelper_site_config 103 | let l:file = l:dirpath . config 104 | if filereadable(l:file) 105 | return v:true 106 | endif 107 | endfor 108 | return v:false 109 | endfunction 110 | 111 | " vim: expandtab shiftwidth=4 112 | --------------------------------------------------------------------------------