Files
vim-licenser/plugin/licenser.vim
T
nortega 5ffa6315de Add empty line for whitespace-only comment markers
When a license header line is empty and comment_style.middle
contains only whitespace characters, add a truly empty line
instead of the whitespace-only marker. This improves the
formatting of license headers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-10 16:07:44 +02:00

153 lines
6.2 KiB
VimL

" Zlib License
"
" Copyright (c) 2026 Nicolás A. Ortega <nicolas@ortegas.org>
"
" This software is provided 'as-is', without any express or implied warranty. In
" no event will the authors be held liable for any damages arising from the use
" of this software.
"
" Permission is granted to anyone to use this software for any purpose, including
" commercial applications, and to alter it and redistribute it freely, subject
" to the following restrictions:
"
" 1. The origin of this software must not be misrepresented; you must not claim
" that you wrote the original software. If you use this software in a product,
" an acknowledgment in the product documentation would be appreciated but is
" not required.
"
" 2. Altered source versions must be plainly marked as such, and must not be
" misrepresented as being the original software.
"
" 3. This notice may not be removed or altered from any source distribution.
" vim-licenser: A plugin for adding license headers to source code files
" Usage:
" :Licenser <license>
"
" Available licenses can be found in the licenses/ directory
if exists('g:loaded_licenser')
finish
endif
let g:loaded_licenser = 1
function! s:GetCommentStyle(filetype) abort
let ft = a:filetype
" Define comment styles for different filetypes
" - margin: if prefix and suffix should be used
" - hashbang: if the file has a hashbang line, we should skip it when
" adding the license header
" - prefix: the string to use at the beginning of the comment block
" - middle: the string to use at the beginning of each line in the comment
" - suffix: the string to use at the end of the comment block
let comment_styles = {
\ 'bash': {'margin': 0, 'hashbang': 1, 'prefix': '', 'middle': '#', 'suffix': ''},
\ 'c': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'cpp': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'csharp': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'css': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'dart': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'go': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'groovy': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'haskell': {'margin': 0, 'hashbang': 1, 'prefix': '', 'middle': '--', 'suffix': ''},
\ 'html': {'margin': 1, 'hashbang': 0, 'prefix': '<!--', 'middle': ' *', 'suffix': '-->'},
\ 'java': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'javascript': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'json': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'kotlin': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'lua': {'margin': 0, 'hashbang': 1, 'prefix': '', 'middle': '--', 'suffix': ''},
\ 'matlab': {'margin': 0, 'hashbang': 0, 'prefix': '', 'middle': '%', 'suffix': ''},
\ 'perl': {'margin': 0, 'hashbang': 1, 'prefix': '', 'middle': '#', 'suffix': ''},
\ 'php': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'python': {'margin': 0, 'hashbang': 1, 'prefix': '', 'middle': '#', 'suffix': ''},
\ 'r': {'margin': 0, 'hashbang': 0, 'prefix': '', 'middle': '#', 'suffix': ''},
\ 'ruby': {'margin': 0, 'hashbang': 1, 'prefix': '', 'middle': '#', 'suffix': ''},
\ 'rust': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'scala': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'shell': {'margin': 0, 'hashbang': 1, 'prefix': '', 'middle': '#', 'suffix': ''},
\ 'sql': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'swift': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'typescript': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'typescriptreact': {'margin': 1, 'hashbang': 0, 'prefix': '/*', 'middle': ' *', 'suffix': ' */'},
\ 'vim': {'margin': 0, 'hashbang': 0, 'prefix': '', 'middle': '"', 'suffix': ''},
\ 'xml': {'margin': 1, 'hashbang': 0, 'prefix': '<!--', 'middle': ' ', 'suffix': '-->'},
\ 'yaml': {'margin': 0, 'hashbang': 0, 'prefix': '', 'middle': '#', 'suffix': ''},
\ }
if has_key(comment_styles, ft)
return comment_styles[ft]
else
" Error message for unsupported filetypes
echohl ErrorMsg
echo 'Unsupported filetype: ' . ft
echohl None
return {'margin': 0, 'prefix': '', 'middle': '', 'suffix': ''}
endif
endfunction
function! s:AddLicenseHeader(license) abort
let plugin_dir = fnamemodify(expand('<sfile>'), ':h:h')
let license_file = plugin_dir . '/licenses/' . a:license . '.txt'
if !filereadable(license_file)
echohl ErrorMsg
echo 'License file not found: ' . license_file
echohl None
return
endif
let license_lines = readfile(license_file)
let author = get(g:, 'licenser_author', 'Author Name')
let year = strftime('%Y')
let comment_style = s:GetCommentStyle(&filetype)
let processed_lines = []
if comment_style.margin
call add(processed_lines, comment_style.prefix)
endif
for line in license_lines
let line = substitute(line, 'YEAR', year, 'g')
let line = substitute(line, 'AUTHOR', author, 'g')
if line ==# ''
if comment_style.middle =~# '^\s*$'
call add(processed_lines, '')
else
call add(processed_lines, comment_style.middle)
endif
else
call add(processed_lines, comment_style.middle . ' ' . line)
endif
endfor
if comment_style.margin
call add(processed_lines, comment_style.suffix)
endif
call append(comment_style.hashbang, processed_lines)
endfunction
function! s:CompleteFiletype(A, L, P) abort
let plugin_dir = fnamemodify(expand('<sfile>'), ':h:h')
let licenses_dir = plugin_dir . '/licenses/'
if !isdirectory(licenses_dir)
return []
endif
let licenses = []
for file in glob(licenses_dir . '*.txt', 0, 1)
let name = fnamemodify(file, ':t:r')
if name =~ '^' . a:A
call add(licenses, name)
endif
endfor
return sort(licenses)
endfunction
command! -nargs=1 -complete=customlist,s:CompleteFiletype Licenser call s:AddLicenseHeader(<q-args>)