123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- " colorizer.vim Colorize all text in the form #rrggbb or #rgb; autoload functions
- " Maintainer: lilydjwg <lilydjwg@gmail.com>
- " Version: 1.4.2
- " License: Vim License (see vim's :help license)
- "
- " See plugin/colorizer.vim for more info.
- let s:keepcpo = &cpo
- set cpo&vim
- function! s:FGforBG(bg) "{{{1
- " takes a 6hex color code and returns a matching color that is visible
- let pure = substitute(a:bg,'^#','','')
- let r = str2nr(pure[0:1], 16)
- let g = str2nr(pure[2:3], 16)
- let b = str2nr(pure[4:5], 16)
- let fgc = g:colorizer_fgcontrast
- if r*30 + g*59 + b*11 > 12000
- return s:predefined_fgcolors['dark'][fgc]
- else
- return s:predefined_fgcolors['light'][fgc]
- end
- endfunction
- function! s:Rgb2xterm(color) "{{{1
- " selects the nearest xterm color for a rgb value like #FF0000
- let best_match=0
- let smallest_distance = 10000000000
- let r = str2nr(a:color[1:2], 16)
- let g = str2nr(a:color[3:4], 16)
- let b = str2nr(a:color[5:6], 16)
- let colortable = s:GetXterm2rgbTable()
- for c in range(0,254)
- let d = pow(colortable[c][0]-r,2) + pow(colortable[c][1]-g,2) + pow(colortable[c][2]-b,2)
- if d<smallest_distance
- let smallest_distance = d
- let best_match = c
- endif
- endfor
- return best_match
- endfunction
- "" the 6 value iterations in the xterm color cube {{{1
- let s:valuerange = [0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF]
- "" 16 basic colors {{{1
- let s:basic16 = [
- \ [0x00, 0x00, 0x00], [0xCD, 0x00, 0x00],
- \ [0x00, 0xCD, 0x00], [0xCD, 0xCD, 0x00],
- \ [0x00, 0x00, 0xEE], [0xCD, 0x00, 0xCD],
- \ [0x00, 0xCD, 0xCD], [0xE5, 0xE5, 0xE5],
- \ [0x7F, 0x7F, 0x7F], [0xFF, 0x00, 0x00],
- \ [0x00, 0xFF, 0x00], [0xFF, 0xFF, 0x00],
- \ [0x5C, 0x5C, 0xFF], [0xFF, 0x00, 0xFF],
- \ [0x00, 0xFF, 0xFF], [0xFF, 0xFF, 0xFF]]
- function! s:Xterm2rgb(color) "{{{1
- " 16 basic colors
- let r = 0
- let g = 0
- let b = 0
- if a:color<16
- let r = s:basic16[a:color][0]
- let g = s:basic16[a:color][1]
- let b = s:basic16[a:color][2]
- endif
- " color cube color
- if a:color>=16 && a:color<=232
- let l:color=a:color-16
- let r = s:valuerange[(l:color/36)%6]
- let g = s:valuerange[(l:color/6)%6]
- let b = s:valuerange[l:color%6]
- endif
- " gray tone
- if a:color>=233 && a:color<=253
- let r=8+(a:color-232)*0x0a
- let g=r
- let b=r
- endif
- let rgb=[r,g,b]
- return rgb
- endfunction
- function! s:SetMatcher(color, pat) "{{{1
- " "color" is the converted color and "pat" is what to highlight
- let group = 'Color' . strpart(a:color, 1)
- if !hlexists(group) || s:force_group_update
- let fg = g:colorizer_fgcontrast < 0 ? a:color : s:FGforBG(a:color)
- if &t_Co == 256
- exe 'hi '.group.' ctermfg='.s:Rgb2xterm(fg).' ctermbg='.s:Rgb2xterm(a:color)
- endif
- " Always set gui* as user may switch to GUI version and it's cheap
- exe 'hi '.group.' guifg='.fg.' guibg='.a:color
- endif
- if !exists("w:colormatches[a:pat]")
- let w:colormatches[a:pat] = matchadd(group, a:pat)
- endif
- endfunction
- " Color Converters {{{1
- function! s:RgbBgColor() "{{{2
- let bg = synIDattr(synIDtrans(hlID("Normal")), "bg")
- let r = str2nr(bg[1:2], 16)
- let g = str2nr(bg[3:4], 16)
- let b = str2nr(bg[5:6], 16)
- return [r,g,b]
- endfunction
- function! s:Hexa2Rgba(hex,alpha) "{{{2
- let r = str2nr(a:hex[1:2], 16)
- let g = str2nr(a:hex[3:4], 16)
- let b = str2nr(a:hex[5:6], 16)
- let alpha = printf("%.2f", str2float(str2nr(a:alpha,16)) / 255.0)
- return [r,g,b,alpha]
- endfunction
- function! s:Rgba2Rgb(r,g,b,alpha,percent,rgb_bg) "{{{2
- " converts matched r,g,b values and percentages to [0:255]
- " if possible, overlays r,g,b with alpha on given rgb_bg color
- if a:percent
- let r = a:r * 255 / 100
- let g = a:g * 255 / 100
- let b = a:b * 255 / 100
- else
- let r = a:r
- let g = a:g
- let b = a:b
- endif
- if r > 255 || g > 255 || b > 255
- return []
- endif
- if empty(a:rgb_bg)
- return [r,g,b]
- endif
- let alpha = str2float(a:alpha)
- if alpha < 0
- let alpha = 0.0
- elseif alpha > 1
- let alpha = 1.0
- endif
- if alpha == 1.0
- return [r,g,b]
- endif
- let r = float2nr(ceil(r * alpha) + ceil(a:rgb_bg[0] * (1 - alpha)))
- let g = float2nr(ceil(g * alpha) + ceil(a:rgb_bg[1] * (1 - alpha)))
- let b = float2nr(ceil(b * alpha) + ceil(a:rgb_bg[2] * (1 - alpha)))
- if r > 255
- let r = 255
- endif
- if g > 255
- let g = 255
- endif
- if b > 255
- let b = 255
- endif
- return [r,g,b]
- endfunction
- "ColorFinders {{{1
- function! s:HexCode(str, lineno) "{{{2
- " finds RGB: #00f #0000ff and RGBA: #00f8 #0000ff88 (or ARGB: #800f #880000ff)
- if has("gui_running")
- let rgb_bg = s:RgbBgColor()
- else
- " translucent colors would display incorrectly, so ignore the alpha value
- let rgb_bg = []
- endif
- let ret = []
- let place = 0
- let colorpat = '#[0-9A-Fa-f]\{3\}\>\|#[0-9A-Fa-f]\{6\}\>\|#[0-9A-Fa-f]\{8\}\>\|#[0-9A-Fa-f]\{4\}\>'
- while 1
- let foundcolor = matchstr(a:str, colorpat, place)
- if foundcolor == ''
- break
- endif
- let place = matchend(a:str, colorpat, place)
- let pat = foundcolor . '\>'
- let colorlen = len(foundcolor)
- if get(g:, 'colorizer_hex_alpha_first') == 1
- if colorlen == 4 || colorlen == 5
- let ha = tolower(foundcolor[1])
- let hr = tolower(foundcolor[2])
- let hg = tolower(foundcolor[3])
- let hb = tolower(foundcolor[4])
- let foundcolor = substitute(foundcolor, '[[:xdigit:]]', '&&', 'g')
- else
- let ha = tolower(foundcolor[1:2])
- let hr = tolower(foundcolor[3:4])
- let hg = tolower(foundcolor[5:6])
- let hb = tolower(foundcolor[7:8])
- endif
- if len(foundcolor) == 9
- let alpha = foundcolor[1:2]
- let foundcolor = '#'.foundcolor[3:8]
- else
- let alpha = 'ff'
- endif
- if empty(rgb_bg)
- if colorlen == 5
- let pat = printf('\c#\x\zs%s%s%s\ze\>', hr,hg,hb)
- elseif colorlen == 9
- let pat = printf('\c#\x\x\zs%s%s%s\ze\>', hr,hg,hb)
- endif
- endif
- else
- if colorlen == 4 || colorlen == 5
- let hr = tolower(foundcolor[1])
- let hg = tolower(foundcolor[2])
- let hb = tolower(foundcolor[3])
- let ha = tolower(foundcolor[4])
- let foundcolor = substitute(foundcolor, '[[:xdigit:]]', '&&', 'g')
- else
- let hr = tolower(foundcolor[1:2])
- let hg = tolower(foundcolor[3:4])
- let hb = tolower(foundcolor[5:6])
- let ha = tolower(foundcolor[7:8])
- endif
- if len(foundcolor) == 9
- let alpha = foundcolor[7:8]
- let foundcolor = foundcolor[0:6]
- else
- let alpha = 'ff'
- endif
- if empty(rgb_bg)
- if colorlen == 5
- let pat = printf('\c#%s%s%s\ze\x\>', hr,hg,hb)
- elseif colorlen == 9
- let pat = printf('\c#%s%s%s\ze\x\x\>', hr,hg,hb)
- endif
- endif
- endif
- if empty(rgb_bg) || tolower(alpha) == 'ff'
- call add(ret, [foundcolor, pat])
- else
- let rgba = s:Hexa2Rgba(foundcolor, alpha)
- let rgb = s:Rgba2Rgb(rgba[0], rgba[1], rgba[2], rgba[3], 0, rgb_bg)
- let l:color = printf('#%02x%02x%02x', rgb[0], rgb[1], rgb[2])
- call add(ret, [l:color, pat])
- endif
- endwhile
- return ret
- endfunction
- function! s:RgbColor(str, lineno) "{{{2
- let ret = []
- let place = 0
- let colorpat = '\<rgb(\v\s*(\d+(\%)?)\s*,\s*(\d+%(\2))\s*,\s*(\d+%(\2))\s*\)'
- while 1
- let foundcolor = matchlist(a:str, colorpat, place)
- if empty(foundcolor)
- break
- endif
- let place = matchend(a:str, colorpat, place)
- if foundcolor[2] == '%'
- let r = foundcolor[1] * 255 / 100
- let g = foundcolor[3] * 255 / 100
- let b = foundcolor[4] * 255 / 100
- else
- let r = foundcolor[1]
- let g = foundcolor[3]
- let b = foundcolor[4]
- endif
- if r > 255 || g > 255 || b > 255
- break
- endif
- let pat = printf('\<rgb(\v\s*%s\s*,\s*%s\s*,\s*%s\s*\)', foundcolor[1], foundcolor[3], foundcolor[4])
- if foundcolor[2] == '%'
- let pat = substitute(pat, '%', '\\%', 'g')
- endif
- let l:color = printf('#%02x%02x%02x', r, g, b)
- call add(ret, [l:color, pat])
- endwhile
- return ret
- endfunction
- function! s:RgbaColor(str, lineno) "{{{2
- if has("gui_running")
- let rgb_bg = s:RgbBgColor()
- else
- " translucent colors would display incorrectly, so ignore the alpha value
- let rgb_bg = []
- endif
- let ret = []
- let place = 0
- let percent = 0
- let colorpat = '\<rgba(\v\s*(\d+(\%)?)\s*,\s*(\d+%(\2))\s*,\s*(\d+%(\2))\s*,\s*(-?[.[:digit:]]+)\s*\)'
- while 1
- let foundcolor = matchlist(a:str, colorpat, place)
- if empty(foundcolor)
- break
- endif
- if foundcolor[2] == '%'
- let percent = 1
- endif
- let rgb = s:Rgba2Rgb(foundcolor[1], foundcolor[3], foundcolor[4], foundcolor[5], percent, rgb_bg)
- if empty(rgb)
- break
- endif
- let place = matchend(a:str, colorpat, place)
- if empty(rgb_bg)
- let pat = printf('\<rgba(\v\s*%s\s*,\s*%s\s*,\s*%s\s*,\ze\s*(-?[.[:digit:]]+)\s*\)', foundcolor[1], foundcolor[3], foundcolor[4])
- else
- let pat = printf('\<rgba(\v\s*%s\s*,\s*%s\s*,\s*%s\s*,\s*%s0*\s*\)', foundcolor[1], foundcolor[3], foundcolor[4], foundcolor[5])
- endif
- if percent
- let pat = substitute(pat, '%', '\\%', 'g')
- endif
- let l:color = printf('#%02x%02x%02x', rgb[0], rgb[1], rgb[2])
- call add(ret, [l:color, pat])
- endwhile
- return ret
- endfunction
- function! s:PreviewColorInLine(where) "{{{1
- let line = getline(a:where)
- for Func in s:ColorFinder
- let ret = Func(line, a:where)
- " returned a list of a list: color as #rrggbb, text pattern to highlight
- for r in ret
- call s:SetMatcher(r[0], r[1])
- endfor
- endfor
- endfunction
- function! s:CursorMoved() "{{{1
- if !exists('w:colormatches')
- return
- endif
- if exists('b:colorizer_last_update')
- if b:colorizer_last_update == b:changedtick
- " Nothing changed
- return
- endif
- endif
- call s:PreviewColorInLine('.')
- let b:colorizer_last_update = b:changedtick
- endfunction
- function! s:TextChanged() "{{{1
- if !exists('w:colormatches')
- return
- endif
- echomsg "TextChanged"
- call s:PreviewColorInLine('.')
- endfunction
- function! colorizer#ColorHighlight(update, ...) "{{{1
- if exists('w:colormatches')
- if !a:update
- return
- endif
- call s:ClearMatches()
- endif
- if (g:colorizer_maxlines > 0) && (g:colorizer_maxlines <= line('$'))
- return
- end
- let w:colormatches = {}
- if g:colorizer_fgcontrast != s:saved_fgcontrast || (exists("a:1") && a:1 == '!')
- let s:force_group_update = 1
- endif
- for i in range(1, line("$"))
- call s:PreviewColorInLine(i)
- endfor
- let s:force_group_update = 0
- let s:saved_fgcontrast = g:colorizer_fgcontrast
- augroup Colorizer
- au!
- if exists('##TextChanged')
- autocmd TextChanged * silent call s:TextChanged()
- if v:version > 704 || v:version == 704 && has('patch143')
- autocmd TextChangedI * silent call s:TextChanged()
- else
- " TextChangedI does not work as expected
- autocmd CursorMovedI * silent call s:CursorMoved()
- endif
- else
- autocmd CursorMoved,CursorMovedI * silent call s:CursorMoved()
- endif
- " rgba handles differently, so need updating
- autocmd GUIEnter * silent call colorizer#ColorHighlight(1)
- autocmd BufEnter * silent call colorizer#ColorHighlight(1)
- autocmd WinEnter * silent call colorizer#ColorHighlight(1)
- autocmd ColorScheme * let s:force_group_update=1 | silent call colorizer#ColorHighlight(1)
- augroup END
- endfunction
- function! colorizer#ColorClear() "{{{1
- augroup Colorizer
- au!
- augroup END
- augroup! Colorizer
- let save_tab = tabpagenr()
- let save_win = winnr()
- tabdo windo call s:ClearMatches()
- exe 'tabn '.save_tab
- exe save_win . 'wincmd w'
- endfunction
- function! s:ClearMatches() "{{{1
- if !exists('w:colormatches')
- return
- endif
- for i in values(w:colormatches)
- try
- call matchdelete(i)
- catch /.*/
- " matches have been cleared in other ways, e.g. user has called clearmatches()
- endtry
- endfor
- unlet w:colormatches
- endfunction
- function! colorizer#ColorToggle() "{{{1
- if exists('#Colorizer')
- call colorizer#ColorClear()
- echomsg 'Disabled color code highlighting.'
- else
- call colorizer#ColorHighlight(0)
- echomsg 'Enabled color code highlighting.'
- endif
- endfunction
- function! colorizer#AlphaPositionToggle() "{{{1
- if exists('#Colorizer')
- if get(g:, 'colorizer_hex_alpha_first') == 1
- let g:colorizer_hex_alpha_first = 0
- else
- let g:colorizer_hex_alpha_first = 1
- endif
- call colorizer#ColorHighlight(1)
- endif
- endfunction
- function! s:GetXterm2rgbTable() "{{{1
- if !exists('s:table_xterm2rgb')
- let s:table_xterm2rgb = []
- for c in range(0, 254)
- let s:color = s:Xterm2rgb(c)
- call add(s:table_xterm2rgb, s:color)
- endfor
- endif
- return s:table_xterm2rgb
- endfun
- " Setups {{{1
- let s:ColorFinder = [function('s:HexCode'), function('s:RgbColor'), function('s:RgbaColor')]
- let s:force_group_update = 0
- let s:predefined_fgcolors = {}
- let s:predefined_fgcolors['dark'] = ['#444444', '#222222', '#000000']
- let s:predefined_fgcolors['light'] = ['#bbbbbb', '#dddddd', '#ffffff']
- if !exists("g:colorizer_fgcontrast")
- " Default to black / white
- let g:colorizer_fgcontrast = len(s:predefined_fgcolors['dark']) - 1
- elseif g:colorizer_fgcontrast >= len(s:predefined_fgcolors['dark'])
- echohl WarningMsg
- echo "g:colorizer_fgcontrast value invalid, using default"
- echohl None
- let g:colorizer_fgcontrast = len(s:predefined_fgcolors['dark']) - 1
- endif
- let s:saved_fgcontrast = g:colorizer_fgcontrast
- " Restoration and modelines {{{1
- let &cpo = s:keepcpo
- unlet s:keepcpo
- " vim:ft=vim:fdm=marker:fmr={{{,}}}:ts=8:sw=2:sts=2:et
|