diff --git a/colors/tools/check_colors.vim b/colors/tools/check_colors.vim index de77a382..5257d273 100644 --- a/colors/tools/check_colors.vim +++ b/colors/tools/check_colors.vim @@ -1,232 +1,209 @@ -" This script tests a color scheme for some errors and lists potential errors. -" Load the scheme and source this script, like this: -" :edit colors/desert.vim | :so colors/tools/check_colors.vim +vim9script +# This script tests a color scheme for some errors and lists potential errors. +# Load the scheme and source this script, like this: +# :edit colors/desert.vim | :ru colors/tools/check_colors.vim -let s:save_cpo= &cpo +var save_cpo = &cpo set cpo&vim -func! Test_check_colors() - let l:savedview = winsaveview() - call cursor(1,1) - let err = {} +def Test_check_colors() + var savedview = winsaveview() + cursor(1, 1) + var err = {} - " 1) Check g:colors_name is existing - if !search('\<\%(g:\)\?colors_name\>', 'cnW') - let err['colors_name'] = 'g:colors_name not set' - else - let err['colors_name'] = 'OK' - endif - - " 2) Check for some well-defined highlighting groups - let hi_groups = [ - \ 'ColorColumn', - \ 'Comment', - \ 'Conceal', - \ 'Constant', - \ 'Cursor', - \ 'CursorColumn', - \ 'CursorLine', - \ 'CursorLineNr', - \ 'DiffAdd', - \ 'DiffChange', - \ 'DiffDelete', - \ 'DiffText', - \ 'Directory', - \ 'EndOfBuffer', - \ 'Error', - \ 'ErrorMsg', - \ 'FoldColumn', - \ 'Folded', - \ 'Identifier', - \ 'Ignore', - \ 'IncSearch', - \ 'LineNr', - \ 'MatchParen', - \ 'ModeMsg', - \ 'MoreMsg', - \ 'NonText', - \ 'Normal', - \ 'Pmenu', - \ 'PmenuSbar', - \ 'PmenuSel', - \ 'PmenuThumb', - \ 'PreProc', - \ 'Question', - \ 'QuickFixLine', - \ 'Search', - \ 'SignColumn', - \ 'Special', - \ 'SpecialKey', - \ 'SpellBad', - \ 'SpellCap', - \ 'SpellLocal', - \ 'SpellRare', - \ 'Statement', - \ 'StatusLine', - \ 'StatusLineNC', - \ 'StatusLineTerm', - \ 'StatusLineTermNC', - \ 'TabLine', - \ 'TabLineFill', - \ 'TabLineSel', - \ 'Title', - \ 'Todo', - \ 'ToolbarButton', - \ 'ToolbarLine', - \ 'Type', - \ 'Underlined', - \ 'VertSplit', - \ 'Visual', - \ 'VisualNOS', - \ 'WarningMsg', - \ 'WildMenu', - \ ] - let groups = {} - for group in hi_groups - if search('\c@suppress\s\+\<' .. group .. '\>', 'cnW') - " skip check, if the script contains a line like - " @suppress Visual: - continue - endif - if search('hi\%[ghlight]!\= \+link \+' .. group, 'cnW') " Linked group - continue - endif - if !search('hi\%[ghlight] \+\<' .. group .. '\>', 'cnW') - let groups[group] = 'No highlight definition for ' .. group - continue - endif - if !search('hi\%[ghlight] \+\<' .. group .. '\>.*[bf]g=', 'cnW') - let groups[group] = 'Missing foreground or background color for ' .. group - continue - endif - if search('hi\%[ghlight] \+\<' .. group .. '\>.*guibg=', 'cnW') && - \ !search('hi\%[ghlight] \+\<' .. group .. '\>.*ctermbg=', 'cnW') - \ && group != 'Cursor' - let groups[group] = 'Missing bg terminal color for ' .. group - continue - endif - if !search('hi\%[ghlight] \+\<' .. group .. '\>.*guifg=', 'cnW') - \ && group !~ '^Diff' - let groups[group] = 'Missing guifg definition for ' .. group - continue - endif - if !search('hi\%[ghlight] \+\<' .. group .. '\>.*ctermfg=', 'cnW') - \ && group !~ '^Diff' - \ && group != 'Cursor' - let groups[group] = 'Missing ctermfg definition for ' .. group - continue + # 1) Check g:colors_name is existing + if !search('\<\%(g:\)\?colors_name\>', 'cnW') + err['colors_name'] = 'g:colors_name not set' + else + err['colors_name'] = 'OK' endif - " do not check for background colors, they could be intentionally left out - call cursor(1,1) - endfor - let err['highlight'] = groups - " 3) Check, that it does not set background highlighting - " Doesn't ':hi Normal ctermfg=253 ctermfg=233' also set the background sometimes? - let bg_set = '\(set\?\|setl\(ocal\)\?\) .*\(background\|bg\)=\(dark\|light\)' - let bg_let = 'let \%([&]\%([lg]:\)\?\)\%(background\|bg\)\s*=\s*\([''"]\?\)\w\+\1' - let bg_pat = '\%(' .. bg_set .. '\|' .. bg_let .. '\)' - let line = search(bg_pat, 'cnW') - if search(bg_pat, 'cnW') - exe line - if search('hi \U\w\+\s\+\S', 'cbnW') - let err['background'] = 'Should not set background option after :hi statement' + # 2) Check for some well-defined highlighting groups + var hi_groups = [ + 'ColorColumn', + 'Comment', + 'Conceal', + 'Constant', + 'Cursor', + 'CursorColumn', + 'CursorLine', + 'CursorLineNr', + 'DiffAdd', + 'DiffChange', + 'DiffDelete', + 'DiffText', + 'Directory', + 'EndOfBuffer', + 'Error', + 'ErrorMsg', + 'FoldColumn', + 'Folded', + 'Identifier', + 'Ignore', + 'IncSearch', + 'LineNr', + 'LineNrAbove', + 'LineNrBelow', + 'MatchParen', + 'ModeMsg', + 'MoreMsg', + 'NonText', + 'Normal', + 'Pmenu', + 'PmenuSbar', + 'PmenuSel', + 'PmenuThumb', + 'PreProc', + 'Question', + 'QuickFixLine', + 'Search', + 'SignColumn', + 'Special', + 'SpecialKey', + 'SpellBad', + 'SpellCap', + 'SpellLocal', + 'SpellRare', + 'Statement', + 'StatusLine', + 'StatusLineNC', + 'StatusLineTerm', + 'StatusLineTermNC', + 'TabLine', + 'TabLineFill', + 'TabLineSel', + 'Title', + 'Todo', + 'ToolbarButton', + 'ToolbarLine', + 'Type', + 'Underlined', + 'VertSplit', + 'Visual', + 'VisualNOS', + 'WarningMsg', + 'WildMenu', + 'debugPC', + 'debugBreakpoint', + ] + var groups = {} + for group in hi_groups + if search('\c@suppress\s\+\<' .. group .. '\>', 'cnW') != 0 + # skip check, if the script contains a line like + # @suppress Visual: + continue + endif + if search('hi\%[ghlight]!\= \+link \+' .. group, 'cnW') != 0 # Linked group + continue + endif + if search('hi\%[ghlight] \+\<' .. group .. '\>', 'cnW') == 0 + groups[group] = 'No highlight definition for ' .. group + continue + endif + if search('hi\%[ghlight] \+\<' .. group .. '\>.*[bf]g=', 'cnW') == 0 + groups[group] = 'Missing foreground or background color for ' .. group + continue + endif + if search('hi\%[ghlight] \+\<' .. group .. '\>.*guibg=', 'cnW') != 0 + && search('hi\%[ghlight] \+\<' .. group .. '\>.*ctermbg=', 'cnW') == 0 + && group != 'Cursor' + groups[group] = 'Missing bg terminal color for ' .. group + continue + endif + if search('hi\%[ghlight] \+\<' .. group .. '\>.*guifg=', 'cnW') == 0 + && group !~ '^Diff' + groups[group] = 'Missing guifg definition for ' .. group + continue + endif + if search('hi\%[ghlight] \+\<' .. group .. '\>.*ctermfg=', 'cnW') == 0 + && group !~ '^Diff' + && group != 'Cursor' + groups[group] = 'Missing ctermfg definition for ' .. group + continue + endif + # do not check for background colors, they could be intentionally left out + cursor(1, 1) + endfor + err['highlight'] = groups + + # 3) Check, that it does not set background highlighting + # Doesn't ':hi Normal ctermfg=253 ctermfg=233' also set the background sometimes? + var bg_set = '\(set\?\|setl\(ocal\)\?\) .*\(background\|bg\)=\(dark\|light\)' + var bg_let = 'let \%([&]\%([lg]:\)\?\)\%(background\|bg\)\s*=\s*\([''"]\?\)\w\+\1' + var bg_pat = '\%(' .. bg_set .. '\|' .. bg_let .. '\)' + var line = search(bg_pat, 'cnW') + if search(bg_pat, 'cnW') != 0 + exe ":" .. line + if search('hi \U\w\+\s\+\S', 'cbnW') != 0 + err['background'] = 'Should not set background option after :hi statement' + endif + else + err['background'] = 'OK' endif - else - let err['background'] = 'OK' - endif - call cursor(1,1) + cursor(1, 1) - " 4) Check, that t_Co is checked - let pat = '[&]t_Co\s*[<>=]=\?\s*\d\+' - if !search(pat, 'ncW') - let err['t_Co'] = 'Does not check terminal for capable colors' - endif - - " 5) Initializes correctly, e.g. should have a section like - " hi clear - " if exists("syntax_on") - " syntax reset - " endif - let pat = 'hi\%[ghlight]\s*clear\n\s*if\s*exists(\([''"]\)syntax_on\1)\n\s*syn\%[tax]\s*reset\n\s*endif' - if !search(pat, 'cnW') - let err['init'] = 'No initialization' - endif - - " 6) Does not use :syn on - if search('syn\%[tax]\s\+on', 'cnW') - let err['background'] = 'Should not issue :syn on' - endif - - " 7) Does not define filetype specific groups like vimCommand, htmlTag, - let hi_groups = filter(getcompletion('', 'filetype'), { _,v -> v !~# '\%[no]syn\%(color\|load\|tax\)' }) - let ft_groups = [] - " let group = '\%('.join(hi_groups, '\|').'\)' " More efficient than a for loop, but less informative - for group in hi_groups - let pat = '\Chi\%[ghlight]!\= *\%[link] \+\zs' .. group .. '\w\+\>\ze \+.' " Skips `hi clear` - if search(pat, 'cW') - call add(ft_groups, matchstr(getline('.'), pat)) + # 4) Check, that t_Co is checked + var pat = '[&]t_Co\s*[<>=]=\?\s*\d\+' + if search(pat, 'ncW') == 0 + err['t_Co'] = 'Does not check terminal for capable colors' endif - call cursor(1,1) - endfor - if !empty(ft_groups) - let err['filetype'] = get(err, 'filetype', 'Should not define: ') . join(uniq(sort(ft_groups))) - endif - " 8) Were debugPC and debugBreakpoint defined? - for group in ['debugPC', 'debugBreakpoint'] - let pat = '\Chi\%[ghlight]!\= *\%[link] \+\zs' .. group .. '\>' - if search(pat, 'cnW') - let line = search(pat, 'cW') - let err['filetype'] = get(err, 'filetype', 'Should not define: ') . matchstr(getline('.'), pat). ' ' + # 5) Initializes correctly, e.g. should have at least: + # hi clear + pat = '^\s*hi\%[ghlight]\s*clear\s*$' + if search(pat, 'cnW') == 0 + err['init'] = 'No initialization' endif - call cursor(1,1) - endfor - - " 9) Normal should be defined first, not use reverse, fg or bg - call cursor(1,1) - let pat = 'hi\%[light] \+\%(link\|clear\)\@!\w\+\>' - call search(pat, 'cW') " Look for the first hi def, skipping `hi link` and `hi clear` - if getline('.') !~# '\m\' - let err['highlight']['Normal'] = 'Should be defined first' - elseif getline('.') =~# '\m\%(=\%(fg\|bg\)\)' - let err['highlight']['Normal'] = "Should not use 'fg' or 'bg'" - elseif getline('.') =~# '\m=\%(inv\|rev\)erse' - let err['highlight']['Normal'] = 'Should not use reverse mode' - endif - - call winrestview(l:savedview) - let g:err = err - " print Result - call Result(err) -endfu + # 6) Does not use :syn on + if search('syn\%[tax]\s\+on', 'cnW') != 0 + err['background'] = 'Should not issue :syn on' + endif -fu! Result(err) - let do_groups = 0 - echohl Title|echomsg "---------------"|echohl Normal - for key in sort(keys(a:err)) - if key is# 'highlight' - let do_groups = !empty(a:err[key]) - continue - else - if a:err[key] !~ 'OK' - echohl Title - endif - echomsg printf("%15s: %s", key, a:err[key]) - echohl Normal + # 7) Normal should be defined first, not use reverse, fg or bg + cursor(1, 1) + pat = 'hi\%[light] \+\%(link\|clear\)\@!\w\+\>' + search(pat, 'cW') # Look for the first hi def, skipping `hi link` and `hi clear` + if getline('.') !~# '\m\' + err['highlight']['Normal'] = 'Should be defined first' + elseif getline('.') =~# '\m\%(=\%(fg\|bg\)\)' + err['highlight']['Normal'] = "Should not use 'fg' or 'bg'" + elseif getline('.') =~# '\m=\%(inv\|rev\)erse' + err['highlight']['Normal'] = 'Should not use reverse mode' endif - endfor - echohl Title|echomsg "---------------"|echohl Normal - if do_groups - echohl Title | echomsg "Groups" | echohl Normal - for v1 in sort(keys(a:err['highlight'])) - echomsg printf("%25s: %s", v1, a:err['highlight'][v1]) + + # 8) TODO: XXX: Check if g:terminal_ansi_colors are defined + + winrestview(savedview) + g:err = err + + Result(err) +enddef + +def Result(err: any) + var do_groups: bool = v:false + echohl Title | echomsg "---------------" | echohl Normal + for key in sort(keys(err)) + if key is 'highlight' + do_groups = !empty(err[key]) + continue + else + if err[key] !~ 'OK' + echohl Title + endif + echomsg printf("%15s: %s", key, err[key]) + echohl Normal + endif endfor - endif -endfu + echohl Title | echomsg "---------------" | echohl Normal + if do_groups + echohl Title | echomsg "Groups" | echohl Normal + for v1 in sort(keys(err['highlight'])) + echomsg printf("%25s: %s", v1, err['highlight'][v1]) + endfor + endif +enddef -call Test_check_colors() +Test_check_colors() -let &cpo = s:save_cpo -unlet s:save_cpo +&cpo = save_cpo