Is it possible to highlight unicode characters?

When I copy/paste a code sample I sometimes run into problems because the website uses , , or instead of - or some other characters that are hard to catch.

I'd like to get a visual indicator (e.g. a red background) that these are special characters.

I found some plugins to have the same intent but they don't work for my example:


With the help from Konfekt/vim-unicode-homoglyphs and the answers here I found this solution that works quite well and has (almost?) no performance impact:

augroup Hiunicode
  autocmd BufEnter *
      \ syntax match nonascii "[^\x00-\x7F]" |
      \ highlight nonascii ctermfg=NONE ctermbg=red
augroup END
  • Yep, this is basically what I recommended in my answer.
    – D. Ben Knoble
    Mar 2 at 19:08
  • FYI essentially a "synonym" for [^\x00-\x7F] you could use : [^[:graph:][:cntrl:][:blank:]]. That says anything that's not an ASCII printable character, ASCII control character or space/tab. Use [^[:graph:][:blank:]] if you want to see control characters, too, which probabl shouldn't be in a file.
    – B Layer
    Mar 2 at 21:35
  • (The last one won't highlight control characters representing line endings and tabs, though. That would have rendered it useless.)
    – B Layer
    Mar 2 at 21:41

I have a pretty general approach to this in ~/.vim/plugin/badwords.vim which I'll put here (word list subject to opinion). You could easily modify the list to capture the characters you care about. The file highlights all the words automatically (as long as the buffer has some syntax) and provides a global :Badsearch command to put all occurences in the quickfix list. It also supports defining g:badwords to extend the list.

Another option is to loop through the range of unicode-codepoints (or build a representative character class) and handle them in a similar way.

" ~/.vim/plugin/badwords.vim
if exists('g:loaded_badwords')
let g:loaded_badwords = 1

" obvious obviously
" basic basically
" simple simply
" of course
" clear clearly
" just
" everyone knows
" However,
" easy
" utilize utilized utilization utilizes
let s:badwords = [
      \ '\<obvious\(ly\)\?\>',
      \ '\<basic\(ally\)\?\>',
      \ '\<simpl\(e\|y\)\>',
      \ '\<of course\>',
      \ '\<clear\(ly\)\?\>',
      \ '\<just\>',
      \ '\<everyone knows\>',
      \ '\<However\>,',
      \ '\<easy\>',
      \ '\<utiliz\(e\w\?\|ation\)\>',
      \ ]

hi def link Badword ErrorMsg
function s:mark_bad(word) abort
  let l:pattern = printf('/\c%s/', a:word)
  exec 'syn match Badword' l:pattern 'containedin=ALL'

augroup Badword
  autocmd Syntax * for word in get(g:, 'badwords', []) + s:badwords | call s:mark_bad(word) | endfor
augroup END

command -bang -nargs=? -complete=file Badsearch
      \ execute 'vimgrep'
      \ '/'.join(get(g:, 'badwords', []) + s:badwords, '\|').'/'.(<bang>0 ? 'g' : '')
      \ (empty(<q-args>) ? expand('%') : <q-args>)
  • Thank you but I did not want to hunt for characters.
    – laktak
    Mar 2 at 17:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.