diff --git a/CSApprox.vim b/CSApprox.vim new file mode 100755 index 0000000..68f92d8 --- /dev/null +++ b/CSApprox.vim @@ -0,0 +1,921 @@ +" CSApprox: Make gvim-only colorschemes Just Work terminal vim +" Maintainer: Matthew Wozniski (godlygeek@gmail.com) +" Date: Fri, 14 Sep 2012 01:12:13 -0400 +" Version: 4.00 +" History: :help csapprox-changelog +" +" Long Description: +" It's hard to find colorschemes for terminal Vim. Most colorschemes are +" written to only support GVim, and don't work at all in terminal Vim. +" +" This plugin makes GVim-only colorschemes Just Work in terminal Vim, as long +" as the terminal supports 88 or 256 colors - and most do these days. This +" usually requires no user interaction (but see below for what to do if things +" don't Just Work). After getting this plugin happily installed, any time you +" use :colorscheme it will do its magic and make the colorscheme Just Work. +" +" Whenever you change colorschemes using the :colorscheme command this script +" will be executed. It will take the colors that the scheme specified for use +" in the GUI and use an approximation algorithm to try to gracefully degrade +" them to the closest color available in your terminal. If you are running in +" a GUI or if your terminal doesn't support 88 or 256 colors, no changes are +" made. Also, no changes will be made if the colorscheme seems to have been +" high color already. +" +" License: +" Copyright (c) 2012, Matthew J. Wozniski +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" * Redistributions of source code must retain the above copyright +" notice, this list of conditions and the following disclaimer. +" * Redistributions in binary form must reproduce the above copyright +" notice, this list of conditions and the following disclaimer in the +" documentation and/or other materials provided with the distribution. +" * The names of the contributors may not be used to endorse or promote +" products derived from this software without specific prior written +" permission. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY +" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +" {>1} Basic plugin setup + +" {>2} Check preconditions +" Quit if the user doesn't want or need us or is missing the gui feature. We +" need +gui to be able to check the gui color settings; vim doesn't bother to +" store them if it is not built with +gui. +if exists('g:CSApprox_loaded') + finish +elseif !has('gui') && v:version < 703 + " Vim versions less than < 7.3.0 need +gui. + " Warn unless the user set g:CSApprox_verbose_level to zero. + if get(g:, 'CSApprox_verbose_level', 1) + echomsg "CSApprox needs gui support - not loading." + echomsg " See :help |csapprox-+gui| for possible workarounds." + endif + + finish +endif + +" {1} Mark us as loaded, and disable all compatibility options for now. +let g:CSApprox_loaded = 1 + +let s:savecpo = &cpo +set cpo&vim + +" {>1} Collect info for the set highlights + +" {>2} Determine if synIDattr is usable +" synIDattr() couldn't support 'guisp' until 7.2.052. This function returns +" true if :redir is needed to find the 'guisp' attribute, false if synIDattr() +" is functional. This test can be overridden by setting the global variable +" g:CSApprox_redirfallback to 1 (to force use of :redir) or to 0 (to force use +" of synIDattr()). +function! s:NeedRedirFallback() + if !exists("g:CSApprox_redirfallback") + let g:CSApprox_redirfallback = (v:version == 702 && !has('patch52')) + \ || v:version < 702 + endif + return g:CSApprox_redirfallback +endfunction + +" {>2} Collect and store the highlights +" Get a dictionary containing information for every highlight group not merely +" linked to another group. Return value is a dictionary, with highlight group +" numbers for keys and values that are dictionaries with four keys each, +" 'name', 'term', 'cterm', and 'gui'. 'name' holds the group name, and each +" of the others holds highlight information for that particular mode. +function! s:Highlights(modes) + let rv = {} + + let i = 0 + while 1 + let i += 1 + + " Only interested in groups that exist and aren't linked + if synIDtrans(i) == 0 + break + endif + + " Handle vim bug allowing groups with name == "" to be created + if synIDtrans(i) != i || len(synIDattr(i, "name")) == 0 + continue + endif + + let rv[i] = {} + let rv[i].name = synIDattr(i, "name") + + for where in a:modes + let rv[i][where] = {} + for attr in s:PossibleAttributes() + let rv[i][where][attr] = synIDattr(i, attr, where) + endfor + + for attr in [ "fg", "bg" ] + let rv[i][where][attr] = synIDattr(i, attr.'#', where) + endfor + + if where == "gui" + let rv[i][where]["sp"] = s:SynGuiSp(i, rv[i].name) + else + let rv[i][where]["sp"] = -1 + endif + + for attr in [ "fg", "bg", "sp" ] + if rv[i][where][attr] == -1 + let rv[i][where][attr] = '' + endif + endfor + endfor + endwhile + + return rv +endfunction + +" {>2} Retrieve guisp + +" Get guisp using whichever method is specified by _redir_fallback +function! s:SynGuiSp(idx, name) + if !s:NeedRedirFallback() + return s:SynGuiSpAttr(a:idx) + else + return s:SynGuiSpRedir(a:name) + endif +endfunction + +" {>3} Implementation for retrieving guisp with redir hack +function! s:SynGuiSpRedir(name) + redir => temp + exe 'sil hi ' . a:name + redir END + let temp = matchstr(temp, 'guisp=\zs.*') + if len(temp) == 0 || temp[0] =~ '\s' + let temp = "" + else + " Make sure we can handle guisp='dark red' + let temp = substitute(temp, '[\x00].*', '', '') + let temp = substitute(temp, '\s*\(c\=term\|gui\).*', '', '') + let temp = substitute(temp, '\s*$', '', '') + endif + return temp +endfunction + +" {>3} Implementation for retrieving guisp with synIDattr() +function! s:SynGuiSpAttr(idx) + return synIDattr(a:idx, 'sp#', 'gui') +endfunction + +" {>1} Handle color names + +" Place to store rgb.txt name to color mappings - lazy loaded if needed +let s:rgb = {} + +" {>2} Builtin gui color names +" gui_x11.c and gui_gtk_x11.c have some default colors names that are searched +" if the x server doesn't know about a color. If 'showrgb' is available, +" we'll default to using these color names and values, and overwrite them with +" other values if 'showrgb' tells us about those colors. +let s:rgb_defaults = { "lightred" : "#FFBBBB", + \ "lightgreen" : "#88FF88", + \ "lightmagenta" : "#FFBBFF", + \ "darkcyan" : "#008888", + \ "darkblue" : "#0000BB", + \ "darkred" : "#BB0000", + \ "darkmagenta" : "#BB00BB", + \ "darkgrey" : "#BBBBBB", + \ "darkyellow" : "#BBBB00", + \ "gray10" : "#1A1A1A", + \ "grey10" : "#1A1A1A", + \ "gray20" : "#333333", + \ "grey20" : "#333333", + \ "gray30" : "#4D4D4D", + \ "grey30" : "#4D4D4D", + \ "gray40" : "#666666", + \ "grey40" : "#666666", + \ "gray50" : "#7F7F7F", + \ "grey50" : "#7F7F7F", + \ "gray60" : "#999999", + \ "grey60" : "#999999", + \ "gray70" : "#B3B3B3", + \ "grey70" : "#B3B3B3", + \ "gray80" : "#CCCCCC", + \ "grey80" : "#CCCCCC", + \ "gray90" : "#E5E5E5", + \ "grey90" : "#E5E5E5" } + +" {>2} Colors that vim will use by name in one of the default schemes, either +" for bg=light or for bg=dark. This lets us avoid loading the entire rgb.txt +" database when the scheme itself doesn't ask for colors by name. +let s:rgb_presets = { "black" : "#000000", + \ "blue" : "#0000ff", + \ "brown" : "#a52a2a", + \ "cyan" : "#00ffff", + \ "darkblue" : "#00008b", + \ "darkcyan" : "#008b8b", + \ "darkgrey" : "#a9a9a9", + \ "darkmagenta" : "#8b008b", + \ "green" : "#00ff00", + \ "grey" : "#bebebe", + \ "grey40" : "#666666", + \ "grey90" : "#e5e5e5", + \ "lightblue" : "#add8e6", + \ "lightcyan" : "#e0ffff", + \ "lightgrey" : "#d3d3d3", + \ "lightmagenta" : "#ffbbff", + \ "magenta" : "#ff00ff", + \ "red" : "#ff0000", + \ "seagreen" : "#2e8b57", + \ "white" : "#ffffff", + \ "yellow" : "#ffff00" } + +" {>2} Find available color names +" Find the valid named colors. By default, use our own rgb list, but try to +" retrieve the system's list if g:CSApprox_use_showrgb is set to true. Store +" the color names and color values to the dictionary s:rgb - the keys are +" color names (in lowercase), the values are strings representing color values +" (as '#rrggbb'). +function! s:UpdateRgbHash() + try + if !exists("g:CSApprox_use_showrgb") || !g:CSApprox_use_showrgb + throw "Not using showrgb" + endif + + " We want to use the 'showrgb' program, if it's around + let lines = split(system('showrgb'), '\n') + + if v:shell_error || !exists('lines') || empty(lines) + throw "'showrgb' didn't give us an rgb.txt" + endif + + let s:rgb = copy(s:rgb_defaults) + + " fmt is (blanks?)(red)(blanks)(green)(blanks)(blue)(blanks)(name) + let parsepat = '^\s*\(\d\+\)\s\+\(\d\+\)\s\+\(\d\+\)\s\+\(.*\)$' + + for line in lines + let v = matchlist(line, parsepat) + if len(v) < 0 + throw "CSApprox: Bad RGB line: " . string(line) + endif + let s:rgb[tolower(v[4])] = printf("#%02x%02x%02x", v[1], v[2], v[3]) + endfor + catch + try + let s:rgb = csapprox#rgb() + catch + echohl ErrorMsg + echomsg "Can't call rgb() from autoload/csapprox.vim" + echomsg "Named colors will not be available!" + echohl None + endtry + endtry + + return 0 +endfunction + +" {>1} Derive and set cterm attributes + +" {>2} List of all possible attributes +function! s:PossibleAttributes() + return [ "bold", "italic", "reverse", "underline", "undercurl" ] +endfunction + +" {>2} Attribute overrides +" Allow the user to override a specified attribute with another attribute. +" For example, the default is to map 'italic' to 'underline' (since many +" terminals cannot display italic text, and gvim itself will replace italics +" with underlines where italicizing is impossible), and to replace 'sp' with +" 'fg' (since terminals can't use one color for the underline and another for +" the foreground, we color the entire word). This default can of course be +" overridden by the user, by setting g:CSApprox_attr_map. This map must be +" a dictionary of string keys, representing the same attributes that synIDattr +" can look up, to string values, representing the attribute mapped to or an +" empty string to disable the given attribute entirely. +function! s:attr_map(attr) + let rv = get(g:CSApprox_attr_map, a:attr, a:attr) + + return rv +endfunction + +function! s:NormalizeAttrMap(map) + let old = copy(a:map) + let new = filter(a:map, '0') + + let valid_attrs = [ 'bg', 'fg', 'sp' ] + s:PossibleAttributes() + + let colorattrs = [ 'fg', 'bg', 'sp' ] + + for olhs in keys(old) + if olhs ==? 'inverse' + let nlhs = 'reverse' + endif + + let orhs = old[olhs] + + if orhs ==? 'inverse' + let nrhs = 'reverse' + endif + + let nlhs = tolower(olhs) + let nrhs = tolower(orhs) + + try + if index(valid_attrs, nlhs) == -1 + echomsg "CSApprox: Bad attr map (removing unrecognized attribute " . olhs . ")" + elseif nrhs != '' && index(valid_attrs, nrhs) == -1 + echomsg "CSApprox: Bad attr map (removing unrecognized attribute " . orhs . ")" + elseif nrhs != '' && !!(index(colorattrs, nlhs)+1) != !!(index(colorattrs, nrhs)+1) + echomsg "CSApprox: Bad attr map (removing " . olhs . "; type mismatch with " . orhs . ")" + elseif nrhs == 'sp' + echomsg "CSApprox: Bad attr map (removing " . olhs . "; can't map to 'sp')" + else + let new[nlhs] = nrhs + endif + catch + echo v:exception + endtry + endfor +endfunction + +" {>2} Normalize the GUI settings of a highlight group +" If the Normal group is cleared, set it to gvim's default, black on white +" Though this would be a really weird thing for a scheme to do... *shrug* +function! s:FixupGuiInfo(highlights) + if a:highlights[s:hlid_normal].gui.bg == '' + let a:highlights[s:hlid_normal].gui.bg = 'white' + endif + + if a:highlights[s:hlid_normal].gui.fg == '' + let a:highlights[s:hlid_normal].gui.fg = 'black' + endif +endfunction + +" {>2} Map gui settings to cterm settings +" Given information about a highlight group, replace the cterm settings with +" the mapped gui settings, applying any attribute overrides along the way. In +" particular, this gives special treatment to the 'reverse' attribute and the +" 'guisp' attribute. In particular, if the 'reverse' attribute is set for +" gvim, we unset it for the terminal and instead set ctermfg to match guibg +" and vice versa, since terminals can consider a 'reverse' flag to mean using +" default-bg-on-default-fg instead of current-bg-on-current-fg. We also +" ensure that the 'sp' attribute is never set for cterm, since no terminal can +" handle that particular highlight. If the user wants to display the guisp +" color, he should map it to either 'fg' or 'bg' using g:CSApprox_attr_map. +function! s:FixupCtermInfo(highlights) + for hl in values(a:highlights) + + if !has_key(hl, 'cterm') + let hl["cterm"] = {} + endif + + " Find attributes to be set in the terminal + for attr in s:PossibleAttributes() + let hl.cterm[attr] = '' + if hl.gui[attr] == 1 + if s:attr_map(attr) != '' + let hl.cterm[ s:attr_map(attr) ] = 1 + endif + endif + endfor + + for color in [ "bg", "fg" ] + let eff_color = color + if hl.cterm['reverse'] + let eff_color = (color == 'bg' ? 'fg' : 'bg') + endif + + let hl.cterm[color] = get(hl.gui, s:attr_map(eff_color), '') + endfor + + if hl.gui['sp'] != '' && s:attr_map('sp') != '' + let hl.cterm[s:attr_map('sp')] = hl.gui['sp'] + endif + + if exists("g:CSApprox_fake_reverse") && g:CSApprox_fake_reverse + if hl.cterm['reverse'] && hl.cterm.bg == '' + let hl.cterm.bg = 'fg' + endif + + if hl.cterm['reverse'] && hl.cterm.fg == '' + let hl.cterm.fg = 'bg' + endif + + if hl.cterm['reverse'] + let hl.cterm.reverse = '' + endif + endif + endfor +endfunction + +" {>2} Kludge around inability to reference autoload functions +function! s:DefaultApproximator(...) + return call('csapprox#per_component#Approximate', a:000) +endfunction + +" {>2} Set cterm colors for a highlight group +" Given the information for a single highlight group (ie, the value of +" one of the items in s:Highlights() already normalized with s:FixupCtermInfo +" and s:FixupGuiInfo), handle matching the gvim colors to the closest cterm +" colors by calling the appropriate approximator as specified with the +" g:CSApprox_approximator_function variable and set the colors and attributes +" appropriately to match the gui. +function! s:SetCtermFromGui(hl) + let hl = a:hl + + " Set up the default approximator function, if needed + if !exists("g:CSApprox_approximator_function") + let g:CSApprox_approximator_function = function("s:DefaultApproximator") + endif + + " Clear existing highlights + exe 'hi ' . hl.name . ' cterm=NONE ctermbg=NONE ctermfg=NONE' + + for which in [ 'bg', 'fg' ] + let val = hl.cterm[which] + + " Skip unset colors + if val == -1 || val == "" + continue + endif + + " Try translating anything but 'fg', 'bg', #rrggbb, and rrggbb from an + " rgb.txt color to a #rrggbb color + if val !~? '^[fb]g$' && val !~ '^#\=\x\{6}$' + try + " First see if it is in our preset-by-vim rgb list + let val = s:rgb_presets[tolower(val)] + catch + " Then try loading and checking our real rgb list + if empty(s:rgb) + call s:UpdateRgbHash() + endif + try + let val = s:rgb[tolower(val)] + catch + " And then barf if we still haven't found it + if &verbose + echomsg "CSApprox: Colorscheme uses unknown color \"" . val . "\"" + endif + continue + endtry + endtry + endif + + if val =~? '^[fb]g$' + exe 'hi ' . hl.name . ' cterm' . which . '=' . val + let hl.cterm[which] = val + elseif val =~ '^#\=\x\{6}$' + let val = substitute(val, '^#', '', '') + let r = str2nr(val[0:1], 16) + let g = str2nr(val[2:3], 16) + let b = str2nr(val[4:5], 16) + let hl.cterm[which] = g:CSApprox_approximator_function(r, g, b) + exe 'hi ' . hl.name . ' cterm' . which . '=' . hl.cterm[which] + else + throw "Internal error handling color: " . val + endif + endfor + + " Finally, set the attributes + let attrs = s:PossibleAttributes() + call filter(attrs, 'hl.cterm[v:val] == 1') + + if !empty(attrs) + exe 'hi ' . hl.name . ' cterm=' . join(attrs, ',') + endif +endfunction + + +" {>1} Top-level control + +" Cache the highlight ID of the normal group; it's used often and won't change +let s:hlid_normal = hlID('Normal') + +" {>2} Builtin cterm color names above 15 +" Vim defines some color name to high color mappings internally (see +" syntax.c:do_highlight). Since we don't want to overwrite a colorscheme that +" was actually written for a high color terminal with our choices, but have no +" way to tell if a colorscheme was written for a high color terminal, we fall +" back on guessing. If any highlight group has a cterm color set to 16 or +" higher, we assume that the user has used a high color colorscheme - unless +" that color is one of the below, which vim can set internally when a color is +" requested by name. +let s:presets_88 = [] +let s:presets_88 += [32] " Brown +let s:presets_88 += [72] " DarkYellow +let s:presets_88 += [84] " Gray +let s:presets_88 += [84] " Grey +let s:presets_88 += [82] " DarkGray +let s:presets_88 += [82] " DarkGrey +let s:presets_88 += [43] " LightBlue +let s:presets_88 += [61] " LightGreen +let s:presets_88 += [63] " LightCyan +let s:presets_88 += [74] " LightRed +let s:presets_88 += [75] " LightMagenta +let s:presets_88 += [78] " LightYellow + +let s:presets_256 = [] +let s:presets_256 += [130] " Brown +let s:presets_256 += [130] " DarkYellow +let s:presets_256 += [248] " Gray +let s:presets_256 += [248] " Grey +let s:presets_256 += [242] " DarkGray +let s:presets_256 += [242] " DarkGrey +let s:presets_256 += [ 81] " LightBlue +let s:presets_256 += [121] " LightGreen +let s:presets_256 += [159] " LightCyan +let s:presets_256 += [224] " LightRed +let s:presets_256 += [225] " LightMagenta +let s:presets_256 += [229] " LightYellow + +" {>2} Wrapper around :exe to allow :executing multiple commands. +" "cmd" is the command to be :executed. +" If the variable is a String, it is :executed. +" If the variable is a List, each element is :executed. +function! s:exe(cmd) + if type(a:cmd) == type('') + exe a:cmd + else + for cmd in a:cmd + call s:exe(cmd) + endfor + endif +endfunction + +" {>2} Function to handle hooks +" Prototype: HandleHooks(type [, scheme]) +" "type" is the type of hook to be executed, ie. "pre" or "post" +" "scheme" is the name of the colorscheme that is currently active, if known +" +" If the variables g:CSApprox_hook_{type} and g:CSApprox_hook_{scheme}_{type} +" exist, this will :execute them in that order. If one does not exist, it +" will silently be ignored. +" +" If the scheme name contains characters that are invalid in a variable name, +" they will simply be removed. Ie, g:colors_name = "123 foo_bar-baz456" +" becomes "foo_barbaz456" +" +" NOTE: Exceptions will be printed out, rather than end processing early. The +" rationale is that it is worse for the user to fix the hook in an editor with +" broken colors. :) +function! s:HandleHooks(type, ...) + let type = a:type + let scheme = (a:0 == 1 ? a:1 : "") + let scheme = substitute(scheme, '[^[:alnum:]_]', '', 'g') + let scheme = substitute(scheme, '^\d\+', '', '') + + for cmd in [ 'g:CSApprox_hook_' . type, + \ 'g:CSApprox_' . scheme . '_hook_' . type, + \ 'g:CSApprox_hook_' . scheme . '_' . type ] + if exists(cmd) + try + call s:exe(eval(cmd)) + catch + echomsg "Error processing " . cmd . ":" + echomsg v:exception + endtry + endif + endfor +endfunction + +" {>2} Main function +" Wrapper around the actual implementation to make it easier to ensure that +" all temporary settings are restored by the time we return, whether or not +" something was thrown. Additionally, sets the 'verbose' option to the max of +" g:CSApprox_verbose_level (default 1) and &verbose for the duration of the +" main function. This allows us to default to a message whenever any error, +" even a recoverable one, occurs, meaning the user quickly finds out when +" something's wrong, but makes it very easy for the user to make us silent. +function! s:CSApprox(...) + try + if a:0 == 1 && a:1 + if !exists('s:inhibit_hicolor_test') + let s:inhibit_hicolor_test = 0 + endif + let s:inhibit_hicolor_test += 1 + endif + + let savelz = &lz + + set lz + + if exists("g:CSApprox_attr_map") && type(g:CSApprox_attr_map) == type({}) + call s:NormalizeAttrMap(g:CSApprox_attr_map) + else + let g:CSApprox_attr_map = { 'italic' : 'underline', 'sp' : 'fg' } + endif + + " colors_name must be unset and reset, or vim will helpfully reload the + " colorscheme when we set the background for the Normal group. + " See the help entries ':hi-normal-cterm' and 'g:colors_name' + if exists("g:colors_name") + let colors_name = g:colors_name + unlet g:colors_name + endif + + " Similarly, the global variable "syntax_cmd" must be set to something vim + " doesn't recognize, lest vim helpfully switch all colors back to the + " default whenever the Normal group is changed (in syncolor.vim)... + if exists("g:syntax_cmd") + let syntax_cmd = g:syntax_cmd + endif + let g:syntax_cmd = "PLEASE DON'T CHANGE ANY COLORS!!!" + + " Set up our verbosity level, if needed. + " Default to 1, so the user can know if something's wrong. + if !exists("g:CSApprox_verbose_level") + let g:CSApprox_verbose_level = 1 + endif + + call s:HandleHooks("pre", (exists("colors_name") ? colors_name : "")) + + let old_bg = &bg + + " Set 'verbose' set to the maximum of &verbose and CSApprox_verbose_level + exe max([&vbs, g:CSApprox_verbose_level]) 'verbose call s:CSApproxImpl()' + + let &bg = old_bg + + call s:HandleHooks("post", (exists("colors_name") ? colors_name : "")) + finally + if exists("colors_name") + let g:colors_name = colors_name + endif + + unlet g:syntax_cmd + if exists("syntax_cmd") + let g:syntax_cmd = syntax_cmd + endif + + let &lz = savelz + + if a:0 == 1 && a:1 + let s:inhibit_hicolor_test -= 1 + if s:inhibit_hicolor_test == 0 + unlet s:inhibit_hicolor_test + endif + endif + endtry +endfunction + +" {>2} CSApprox implementation +" Verifies that the user has not started the gui, and that vim recognizes his +" terminal as having enough colors for us to go on, then gathers the existing +" highlights and sets the cterm colors to match the gui colors for all those +" highlights (unless the colorscheme was already high-color). +function! s:CSApproxImpl() + " Return if not running in an 88/256 color terminal + if &t_Co != 256 && &t_Co != 88 + if &verbose && &t_Co != '' + echomsg "CSApprox skipped; terminal only has" &t_Co "colors, not 88/256" + echomsg "Try checking :help csapprox-terminal for workarounds" + endif + + return + endif + + " Get the current highlight colors + let highlights = s:Highlights(["gui"]) + + let hinums = keys(highlights) + + " Make sure that the script is not already 256 color by checking to make + " sure that no groups are set to a value above 256, unless the color they're + " set to can be set internally by vim (gotten by scraping + " color_numbers_{88,256} in syntax.c:do_highlight) + " + " XXX: s:inhibit_hicolor_test allows this test to be skipped for snapshots + if !exists("s:inhibit_hicolor_test") || !s:inhibit_hicolor_test + for hlid in hinums + for type in [ 'bg', 'fg' ] + let color = synIDattr(hlid, type, 'cterm') + + if color > 15 && index(s:presets_{&t_Co}, str2nr(color)) < 0 + " The value is set above 15, and wasn't set by vim. + if &verbose >= 2 + echomsg 'CSApprox: Exiting - high' type 'color found for' highlights[hlid].name + endif + return + endif + endfor + endfor + endif + + call s:FixupGuiInfo(highlights) + call s:FixupCtermInfo(highlights) + + " We need to set the Normal group first so 'bg' and 'fg' work as colors + call insert(hinums, remove(hinums, index(hinums, string(s:hlid_normal)))) + + " then set each color's cterm attributes to match gui + for hlid in hinums + call s:SetCtermFromGui(highlights[hlid]) + endfor +endfunction + +" {>2} Write out the current colors to an 88/256 color colorscheme file. +" "file" - destination filename +" "overwrite" - overwrite an existing file +function! s:CSApproxSnapshot(file, overwrite) + let force = a:overwrite + let file = fnamemodify(a:file, ":p") + + if empty(file) + throw "Bad file name: \"" . file . "\"" + elseif (filewritable(fnamemodify(file, ':h')) != 2) + throw "Cannot write to directory \"" . fnamemodify(file, ':h') . "\"" + elseif (glob(file) || filereadable(file)) && !force + " TODO - respect 'confirm' here and prompt if it's set. + echohl ErrorMsg + echomsg "E13: File exists (add ! to override)" + echohl None + return + endif + + " Sigh... This is basically a bug, but one that I have no chance of fixing. + " Vim decides that Pmenu should be highlighted in 'LightMagenta' in terminal + " vim and as 'Magenta' in gvim... And I can't ask it what color it actually + " *wants*. As far as I can see, there's no way for me to learn that + " I should output 'Magenta' when 'LightMagenta' is provided by vim for the + " terminal. + if !has('gui_running') + echohl WarningMsg + echomsg "Warning: The written colorscheme may have incorrect colors" + echomsg " when CSApproxSnapshot is used in terminal vim!" + echohl None + endif + + let save_t_Co = &t_Co + let s:inhibit_hicolor_test = 1 + if exists("g:CSApprox_konsole") + let save_CSApprox_konsole = g:CSApprox_konsole + endif + if exists("g:CSApprox_eterm") + let save_CSApprox_eterm = g:CSApprox_eterm + endif + + " Needed just like in CSApprox() + if exists("g:colors_name") + let colors_name = g:colors_name + unlet g:colors_name + endif + + " Needed just like in CSApprox() + if exists("g:syntax_cmd") + let syntax_cmd = g:syntax_cmd + endif + let g:syntax_cmd = "PLEASE DON'T CHANGE ANY COLORS!!!" + + try + let lines = [] + let lines += [ '" This scheme was created by CSApproxSnapshot' ] + let lines += [ '" on ' . strftime("%a, %d %b %Y") ] + let lines += [ '' ] + let lines += [ 'hi clear' ] + let lines += [ 'if exists("syntax_on")' ] + let lines += [ ' syntax reset' ] + let lines += [ 'endif' ] + let lines += [ '' ] + let lines += [ 'if v:version < 700' ] + let lines += [ ' let g:colors_name = expand(":t:r")' ] + let lines += [ ' command! -nargs=+ CSAHi exe "hi" substitute(substitute(, "undercurl", "underline", "g"), "guisp\\S\\+", "", "g")' ] + let lines += [ 'else' ] + let lines += [ ' let g:colors_name = expand(":t:r")' ] + let lines += [ ' command! -nargs=+ CSAHi exe "hi" ' ] + let lines += [ 'endif' ] + let lines += [ '' ] + let lines += [ 'function! s:old_kde()' ] + let lines += [ ' " Konsole only used its own palette up til KDE 4.2.0' ] + let lines += [ " if executable('kde4-config') && system('kde4-config --kde-version') =~ '^4\.[10]\.'" ] + let lines += [ ' return 1' ] + let lines += [ " elseif executable('kde-config') && system('kde-config --version') =~# 'KDE: 3\.'" ] + let lines += [ ' return 1' ] + let lines += [ ' else' ] + let lines += [ ' return 0' ] + let lines += [ ' endif' ] + let lines += [ 'endfunction' ] + let lines += [ '' ] + + + let lines += [ 'if 0' ] + for round in [ 'konsole', 'eterm', 'xterm', 'urxvt' ] + sil! unlet g:CSApprox_eterm + sil! unlet g:CSApprox_konsole + + if round == 'konsole' + let g:CSApprox_konsole = 1 + elseif round == 'eterm' + let g:CSApprox_eterm = 1 + endif + + if round == 'urxvt' + set t_Co=88 + else + set t_Co=256 + endif + + call s:CSApprox() + + let highlights = s:Highlights(["term", "cterm", "gui"]) + call s:FixupGuiInfo(highlights) + + if round == 'konsole' || round == 'eterm' + if round == 'konsole' + let term_matches_round = '(&term =~? "^konsole" && s:old_kde())' + else + let term_matches_round = '&term =~? "^' . round . '"' + endif + + let lines += [ 'elseif has("gui_running") || (&t_Co == ' . &t_Co + \ . ' && (&term ==# "xterm" || &term =~# "^screen")' + \ . ' && exists("g:CSApprox_' . round . '")' + \ . ' && g:CSApprox_' . round . ')' + \ . ' || ' . term_matches_round ] + else + let lines += [ 'elseif has("gui_running") || &t_Co == ' . &t_Co ] + endif + + let hinums = keys(highlights) + + call insert(hinums, remove(hinums, index(hinums, string(s:hlid_normal)))) + + for hlnum in hinums + let hl = highlights[hlnum] + let line = ' CSAHi ' . hl.name + for type in [ 'term', 'cterm', 'gui' ] + let attrs = s:PossibleAttributes() + call filter(attrs, 'hl[type][v:val] == 1') + let line .= ' ' . type . '=' . (empty(attrs) ? 'NONE' : join(attrs, ',')) + if type != 'term' + let line .= ' ' . type . 'bg=' . (len(hl[type].bg) ? hl[type].bg : 'bg') + let line .= ' ' . type . 'fg=' . (len(hl[type].fg) ? hl[type].fg : 'fg') + if type == 'gui' && hl.gui.sp !~ '^\s*$' + let line .= ' ' . type . 'sp=' . hl[type].sp + endif + endif + endfor + let lines += [ line ] + endfor + endfor + let lines += [ 'endif' ] + let lines += [ '' ] + let lines += [ 'if 1' ] + let lines += [ ' delcommand CSAHi' ] + let lines += [ 'endif' ] + call writefile(lines, file) + finally + let &t_Co = save_t_Co + + if exists("save_CSApprox_konsole") + let g:CSApprox_konsole = save_CSApprox_konsole + endif + if exists("save_CSApprox_eterm") + let g:CSApprox_eterm = save_CSApprox_eterm + endif + + if exists("colors_name") + let g:colors_name = colors_name + endif + + unlet g:syntax_cmd + if exists("syntax_cmd") + let g:syntax_cmd = syntax_cmd + endif + + call s:CSApprox() + + unlet s:inhibit_hicolor_test + endtry +endfunction + +" {>2} Snapshot user command +command! -bang -nargs=1 -complete=file -bar CSApproxSnapshot + \ call s:CSApproxSnapshot(, strlen("")) + +" {>2} Manual updates +command -bang -bar CSApprox call s:CSApprox(strlen("")) + +" {>1} Autocmds +" Set up an autogroup to hook us on the completion of any :colorscheme command +augroup CSApprox + au! + au ColorScheme * call s:CSApprox() + "au User CSApproxPost highlight Normal ctermbg=none | highlight NonText ctermbg=None +augroup END + +" {>1} Restore compatibility options +let &cpo = s:savecpo +unlet s:savecpo + + +" {0} vim:sw=2:sts=2:et:fdm=expr:fde=substitute(matchstr(getline(v\:lnum),'^\\s*"\\s*{\\zs.\\{-}\\ze}'),'^$','=','') diff --git a/CSApprox/autoload/csapprox.vim b/CSApprox/autoload/csapprox.vim new file mode 100755 index 0000000..a8fbcf6 --- /dev/null +++ b/CSApprox/autoload/csapprox.vim @@ -0,0 +1,835 @@ +" Copyright (c) 2012, Matthew J. Wozniski +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" * Redistributions of source code must retain the above copyright +" notice, this list of conditions and the following disclaimer. +" * Redistributions in binary form must reproduce the above copyright +" notice, this list of conditions and the following disclaimer in the +" documentation and/or other materials provided with the distribution. +" * The names of the contributors may not be used to endorse or promote +" products derived from this software without specific prior written +" permission. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY +" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +let s:rgb = {} + +let s:rgb["alice blue"] = "#f0f8ff" +let s:rgb["aliceblue"] = "#f0f8ff" +let s:rgb["antique white"] = "#faebd7" +let s:rgb["antiquewhite"] = "#faebd7" +let s:rgb["antiquewhite1"] = "#ffefdb" +let s:rgb["antiquewhite2"] = "#eedfcc" +let s:rgb["antiquewhite3"] = "#cdc0b0" +let s:rgb["antiquewhite4"] = "#8b8378" +let s:rgb["aquamarine"] = "#7fffd4" +let s:rgb["aquamarine1"] = "#7fffd4" +let s:rgb["aquamarine2"] = "#76eec6" +let s:rgb["aquamarine3"] = "#66cdaa" +let s:rgb["aquamarine4"] = "#458b74" +let s:rgb["azure"] = "#f0ffff" +let s:rgb["azure1"] = "#f0ffff" +let s:rgb["azure2"] = "#e0eeee" +let s:rgb["azure3"] = "#c1cdcd" +let s:rgb["azure4"] = "#838b8b" +let s:rgb["beige"] = "#f5f5dc" +let s:rgb["bisque"] = "#ffe4c4" +let s:rgb["bisque1"] = "#ffe4c4" +let s:rgb["bisque2"] = "#eed5b7" +let s:rgb["bisque3"] = "#cdb79e" +let s:rgb["bisque4"] = "#8b7d6b" +let s:rgb["black"] = "#000000" +let s:rgb["blanched almond"] = "#ffebcd" +let s:rgb["blanchedalmond"] = "#ffebcd" +let s:rgb["blue violet"] = "#8a2be2" +let s:rgb["blue"] = "#0000ff" +let s:rgb["blue1"] = "#0000ff" +let s:rgb["blue2"] = "#0000ee" +let s:rgb["blue3"] = "#0000cd" +let s:rgb["blue4"] = "#00008b" +let s:rgb["blueviolet"] = "#8a2be2" +let s:rgb["brown"] = "#a52a2a" +let s:rgb["brown1"] = "#ff4040" +let s:rgb["brown2"] = "#ee3b3b" +let s:rgb["brown3"] = "#cd3333" +let s:rgb["brown4"] = "#8b2323" +let s:rgb["burlywood"] = "#deb887" +let s:rgb["burlywood1"] = "#ffd39b" +let s:rgb["burlywood2"] = "#eec591" +let s:rgb["burlywood3"] = "#cdaa7d" +let s:rgb["burlywood4"] = "#8b7355" +let s:rgb["cadet blue"] = "#5f9ea0" +let s:rgb["cadetblue"] = "#5f9ea0" +let s:rgb["cadetblue1"] = "#98f5ff" +let s:rgb["cadetblue2"] = "#8ee5ee" +let s:rgb["cadetblue3"] = "#7ac5cd" +let s:rgb["cadetblue4"] = "#53868b" +let s:rgb["chartreuse"] = "#7fff00" +let s:rgb["chartreuse1"] = "#7fff00" +let s:rgb["chartreuse2"] = "#76ee00" +let s:rgb["chartreuse3"] = "#66cd00" +let s:rgb["chartreuse4"] = "#458b00" +let s:rgb["chocolate"] = "#d2691e" +let s:rgb["chocolate1"] = "#ff7f24" +let s:rgb["chocolate2"] = "#ee7621" +let s:rgb["chocolate3"] = "#cd661d" +let s:rgb["chocolate4"] = "#8b4513" +let s:rgb["coral"] = "#ff7f50" +let s:rgb["coral1"] = "#ff7256" +let s:rgb["coral2"] = "#ee6a50" +let s:rgb["coral3"] = "#cd5b45" +let s:rgb["coral4"] = "#8b3e2f" +let s:rgb["cornflower blue"] = "#6495ed" +let s:rgb["cornflowerblue"] = "#6495ed" +let s:rgb["cornsilk"] = "#fff8dc" +let s:rgb["cornsilk1"] = "#fff8dc" +let s:rgb["cornsilk2"] = "#eee8cd" +let s:rgb["cornsilk3"] = "#cdc8b1" +let s:rgb["cornsilk4"] = "#8b8878" +let s:rgb["cyan"] = "#00ffff" +let s:rgb["cyan1"] = "#00ffff" +let s:rgb["cyan2"] = "#00eeee" +let s:rgb["cyan3"] = "#00cdcd" +let s:rgb["cyan4"] = "#008b8b" +let s:rgb["dark blue"] = "#00008b" +let s:rgb["dark cyan"] = "#008b8b" +let s:rgb["dark goldenrod"] = "#b8860b" +let s:rgb["dark gray"] = "#a9a9a9" +let s:rgb["dark green"] = "#006400" +let s:rgb["dark grey"] = "#a9a9a9" +let s:rgb["dark khaki"] = "#bdb76b" +let s:rgb["dark magenta"] = "#8b008b" +let s:rgb["dark olive green"] = "#556b2f" +let s:rgb["dark orange"] = "#ff8c00" +let s:rgb["dark orchid"] = "#9932cc" +let s:rgb["dark red"] = "#8b0000" +let s:rgb["dark salmon"] = "#e9967a" +let s:rgb["dark sea green"] = "#8fbc8f" +let s:rgb["dark slate blue"] = "#483d8b" +let s:rgb["dark slate gray"] = "#2f4f4f" +let s:rgb["dark slate grey"] = "#2f4f4f" +let s:rgb["dark turquoise"] = "#00ced1" +let s:rgb["dark violet"] = "#9400d3" +let s:rgb["dark yellow"] = "#bbbb00" +let s:rgb["darkblue"] = "#00008b" +let s:rgb["darkcyan"] = "#008b8b" +let s:rgb["darkgoldenrod"] = "#b8860b" +let s:rgb["darkgoldenrod1"] = "#ffb90f" +let s:rgb["darkgoldenrod2"] = "#eead0e" +let s:rgb["darkgoldenrod3"] = "#cd950c" +let s:rgb["darkgoldenrod4"] = "#8b6508" +let s:rgb["darkgray"] = "#a9a9a9" +let s:rgb["darkgreen"] = "#006400" +let s:rgb["darkgrey"] = "#a9a9a9" +let s:rgb["darkkhaki"] = "#bdb76b" +let s:rgb["darkmagenta"] = "#8b008b" +let s:rgb["darkolivegreen"] = "#556b2f" +let s:rgb["darkolivegreen1"] = "#caff70" +let s:rgb["darkolivegreen2"] = "#bcee68" +let s:rgb["darkolivegreen3"] = "#a2cd5a" +let s:rgb["darkolivegreen4"] = "#6e8b3d" +let s:rgb["darkorange"] = "#ff8c00" +let s:rgb["darkorange1"] = "#ff7f00" +let s:rgb["darkorange2"] = "#ee7600" +let s:rgb["darkorange3"] = "#cd6600" +let s:rgb["darkorange4"] = "#8b4500" +let s:rgb["darkorchid"] = "#9932cc" +let s:rgb["darkorchid1"] = "#bf3eff" +let s:rgb["darkorchid2"] = "#b23aee" +let s:rgb["darkorchid3"] = "#9a32cd" +let s:rgb["darkorchid4"] = "#68228b" +let s:rgb["darkred"] = "#8b0000" +let s:rgb["darksalmon"] = "#e9967a" +let s:rgb["darkseagreen"] = "#8fbc8f" +let s:rgb["darkseagreen1"] = "#c1ffc1" +let s:rgb["darkseagreen2"] = "#b4eeb4" +let s:rgb["darkseagreen3"] = "#9bcd9b" +let s:rgb["darkseagreen4"] = "#698b69" +let s:rgb["darkslateblue"] = "#483d8b" +let s:rgb["darkslategray"] = "#2f4f4f" +let s:rgb["darkslategray1"] = "#97ffff" +let s:rgb["darkslategray2"] = "#8deeee" +let s:rgb["darkslategray3"] = "#79cdcd" +let s:rgb["darkslategray4"] = "#528b8b" +let s:rgb["darkslategrey"] = "#2f4f4f" +let s:rgb["darkturquoise"] = "#00ced1" +let s:rgb["darkviolet"] = "#9400d3" +let s:rgb["darkyellow"] = "#bbbb00" +let s:rgb["deep pink"] = "#ff1493" +let s:rgb["deep sky blue"] = "#00bfff" +let s:rgb["deeppink"] = "#ff1493" +let s:rgb["deeppink1"] = "#ff1493" +let s:rgb["deeppink2"] = "#ee1289" +let s:rgb["deeppink3"] = "#cd1076" +let s:rgb["deeppink4"] = "#8b0a50" +let s:rgb["deepskyblue"] = "#00bfff" +let s:rgb["deepskyblue1"] = "#00bfff" +let s:rgb["deepskyblue2"] = "#00b2ee" +let s:rgb["deepskyblue3"] = "#009acd" +let s:rgb["deepskyblue4"] = "#00688b" +let s:rgb["dim gray"] = "#696969" +let s:rgb["dim grey"] = "#696969" +let s:rgb["dimgray"] = "#696969" +let s:rgb["dimgrey"] = "#696969" +let s:rgb["dodger blue"] = "#1e90ff" +let s:rgb["dodgerblue"] = "#1e90ff" +let s:rgb["dodgerblue1"] = "#1e90ff" +let s:rgb["dodgerblue2"] = "#1c86ee" +let s:rgb["dodgerblue3"] = "#1874cd" +let s:rgb["dodgerblue4"] = "#104e8b" +let s:rgb["firebrick"] = "#b22222" +let s:rgb["firebrick1"] = "#ff3030" +let s:rgb["firebrick2"] = "#ee2c2c" +let s:rgb["firebrick3"] = "#cd2626" +let s:rgb["firebrick4"] = "#8b1a1a" +let s:rgb["floral white"] = "#fffaf0" +let s:rgb["floralwhite"] = "#fffaf0" +let s:rgb["forest green"] = "#228b22" +let s:rgb["forestgreen"] = "#228b22" +let s:rgb["gainsboro"] = "#dcdcdc" +let s:rgb["ghost white"] = "#f8f8ff" +let s:rgb["ghostwhite"] = "#f8f8ff" +let s:rgb["gold"] = "#ffd700" +let s:rgb["gold1"] = "#ffd700" +let s:rgb["gold2"] = "#eec900" +let s:rgb["gold3"] = "#cdad00" +let s:rgb["gold4"] = "#8b7500" +let s:rgb["goldenrod"] = "#daa520" +let s:rgb["goldenrod1"] = "#ffc125" +let s:rgb["goldenrod2"] = "#eeb422" +let s:rgb["goldenrod3"] = "#cd9b1d" +let s:rgb["goldenrod4"] = "#8b6914" +let s:rgb["gray"] = "#bebebe" +let s:rgb["gray0"] = "#000000" +let s:rgb["gray1"] = "#030303" +let s:rgb["gray10"] = "#1a1a1a" +let s:rgb["gray100"] = "#ffffff" +let s:rgb["gray11"] = "#1c1c1c" +let s:rgb["gray12"] = "#1f1f1f" +let s:rgb["gray13"] = "#212121" +let s:rgb["gray14"] = "#242424" +let s:rgb["gray15"] = "#262626" +let s:rgb["gray16"] = "#292929" +let s:rgb["gray17"] = "#2b2b2b" +let s:rgb["gray18"] = "#2e2e2e" +let s:rgb["gray19"] = "#303030" +let s:rgb["gray2"] = "#050505" +let s:rgb["gray20"] = "#333333" +let s:rgb["gray21"] = "#363636" +let s:rgb["gray22"] = "#383838" +let s:rgb["gray23"] = "#3b3b3b" +let s:rgb["gray24"] = "#3d3d3d" +let s:rgb["gray25"] = "#404040" +let s:rgb["gray26"] = "#424242" +let s:rgb["gray27"] = "#454545" +let s:rgb["gray28"] = "#474747" +let s:rgb["gray29"] = "#4a4a4a" +let s:rgb["gray3"] = "#080808" +let s:rgb["gray30"] = "#4d4d4d" +let s:rgb["gray31"] = "#4f4f4f" +let s:rgb["gray32"] = "#525252" +let s:rgb["gray33"] = "#545454" +let s:rgb["gray34"] = "#575757" +let s:rgb["gray35"] = "#595959" +let s:rgb["gray36"] = "#5c5c5c" +let s:rgb["gray37"] = "#5e5e5e" +let s:rgb["gray38"] = "#616161" +let s:rgb["gray39"] = "#636363" +let s:rgb["gray4"] = "#0a0a0a" +let s:rgb["gray40"] = "#666666" +let s:rgb["gray41"] = "#696969" +let s:rgb["gray42"] = "#6b6b6b" +let s:rgb["gray43"] = "#6e6e6e" +let s:rgb["gray44"] = "#707070" +let s:rgb["gray45"] = "#737373" +let s:rgb["gray46"] = "#757575" +let s:rgb["gray47"] = "#787878" +let s:rgb["gray48"] = "#7a7a7a" +let s:rgb["gray49"] = "#7d7d7d" +let s:rgb["gray5"] = "#0d0d0d" +let s:rgb["gray50"] = "#7f7f7f" +let s:rgb["gray51"] = "#828282" +let s:rgb["gray52"] = "#858585" +let s:rgb["gray53"] = "#878787" +let s:rgb["gray54"] = "#8a8a8a" +let s:rgb["gray55"] = "#8c8c8c" +let s:rgb["gray56"] = "#8f8f8f" +let s:rgb["gray57"] = "#919191" +let s:rgb["gray58"] = "#949494" +let s:rgb["gray59"] = "#969696" +let s:rgb["gray6"] = "#0f0f0f" +let s:rgb["gray60"] = "#999999" +let s:rgb["gray61"] = "#9c9c9c" +let s:rgb["gray62"] = "#9e9e9e" +let s:rgb["gray63"] = "#a1a1a1" +let s:rgb["gray64"] = "#a3a3a3" +let s:rgb["gray65"] = "#a6a6a6" +let s:rgb["gray66"] = "#a8a8a8" +let s:rgb["gray67"] = "#ababab" +let s:rgb["gray68"] = "#adadad" +let s:rgb["gray69"] = "#b0b0b0" +let s:rgb["gray7"] = "#121212" +let s:rgb["gray70"] = "#b3b3b3" +let s:rgb["gray71"] = "#b5b5b5" +let s:rgb["gray72"] = "#b8b8b8" +let s:rgb["gray73"] = "#bababa" +let s:rgb["gray74"] = "#bdbdbd" +let s:rgb["gray75"] = "#bfbfbf" +let s:rgb["gray76"] = "#c2c2c2" +let s:rgb["gray77"] = "#c4c4c4" +let s:rgb["gray78"] = "#c7c7c7" +let s:rgb["gray79"] = "#c9c9c9" +let s:rgb["gray8"] = "#141414" +let s:rgb["gray80"] = "#cccccc" +let s:rgb["gray81"] = "#cfcfcf" +let s:rgb["gray82"] = "#d1d1d1" +let s:rgb["gray83"] = "#d4d4d4" +let s:rgb["gray84"] = "#d6d6d6" +let s:rgb["gray85"] = "#d9d9d9" +let s:rgb["gray86"] = "#dbdbdb" +let s:rgb["gray87"] = "#dedede" +let s:rgb["gray88"] = "#e0e0e0" +let s:rgb["gray89"] = "#e3e3e3" +let s:rgb["gray9"] = "#171717" +let s:rgb["gray90"] = "#e5e5e5" +let s:rgb["gray91"] = "#e8e8e8" +let s:rgb["gray92"] = "#ebebeb" +let s:rgb["gray93"] = "#ededed" +let s:rgb["gray94"] = "#f0f0f0" +let s:rgb["gray95"] = "#f2f2f2" +let s:rgb["gray96"] = "#f5f5f5" +let s:rgb["gray97"] = "#f7f7f7" +let s:rgb["gray98"] = "#fafafa" +let s:rgb["gray99"] = "#fcfcfc" +let s:rgb["green yellow"] = "#adff2f" +let s:rgb["green"] = "#00ff00" +let s:rgb["green1"] = "#00ff00" +let s:rgb["green2"] = "#00ee00" +let s:rgb["green3"] = "#00cd00" +let s:rgb["green4"] = "#008b00" +let s:rgb["greenyellow"] = "#adff2f" +let s:rgb["grey"] = "#bebebe" +let s:rgb["grey0"] = "#000000" +let s:rgb["grey1"] = "#030303" +let s:rgb["grey10"] = "#1a1a1a" +let s:rgb["grey100"] = "#ffffff" +let s:rgb["grey11"] = "#1c1c1c" +let s:rgb["grey12"] = "#1f1f1f" +let s:rgb["grey13"] = "#212121" +let s:rgb["grey14"] = "#242424" +let s:rgb["grey15"] = "#262626" +let s:rgb["grey16"] = "#292929" +let s:rgb["grey17"] = "#2b2b2b" +let s:rgb["grey18"] = "#2e2e2e" +let s:rgb["grey19"] = "#303030" +let s:rgb["grey2"] = "#050505" +let s:rgb["grey20"] = "#333333" +let s:rgb["grey21"] = "#363636" +let s:rgb["grey22"] = "#383838" +let s:rgb["grey23"] = "#3b3b3b" +let s:rgb["grey24"] = "#3d3d3d" +let s:rgb["grey25"] = "#404040" +let s:rgb["grey26"] = "#424242" +let s:rgb["grey27"] = "#454545" +let s:rgb["grey28"] = "#474747" +let s:rgb["grey29"] = "#4a4a4a" +let s:rgb["grey3"] = "#080808" +let s:rgb["grey30"] = "#4d4d4d" +let s:rgb["grey31"] = "#4f4f4f" +let s:rgb["grey32"] = "#525252" +let s:rgb["grey33"] = "#545454" +let s:rgb["grey34"] = "#575757" +let s:rgb["grey35"] = "#595959" +let s:rgb["grey36"] = "#5c5c5c" +let s:rgb["grey37"] = "#5e5e5e" +let s:rgb["grey38"] = "#616161" +let s:rgb["grey39"] = "#636363" +let s:rgb["grey4"] = "#0a0a0a" +let s:rgb["grey40"] = "#666666" +let s:rgb["grey41"] = "#696969" +let s:rgb["grey42"] = "#6b6b6b" +let s:rgb["grey43"] = "#6e6e6e" +let s:rgb["grey44"] = "#707070" +let s:rgb["grey45"] = "#737373" +let s:rgb["grey46"] = "#757575" +let s:rgb["grey47"] = "#787878" +let s:rgb["grey48"] = "#7a7a7a" +let s:rgb["grey49"] = "#7d7d7d" +let s:rgb["grey5"] = "#0d0d0d" +let s:rgb["grey50"] = "#7f7f7f" +let s:rgb["grey51"] = "#828282" +let s:rgb["grey52"] = "#858585" +let s:rgb["grey53"] = "#878787" +let s:rgb["grey54"] = "#8a8a8a" +let s:rgb["grey55"] = "#8c8c8c" +let s:rgb["grey56"] = "#8f8f8f" +let s:rgb["grey57"] = "#919191" +let s:rgb["grey58"] = "#949494" +let s:rgb["grey59"] = "#969696" +let s:rgb["grey6"] = "#0f0f0f" +let s:rgb["grey60"] = "#999999" +let s:rgb["grey61"] = "#9c9c9c" +let s:rgb["grey62"] = "#9e9e9e" +let s:rgb["grey63"] = "#a1a1a1" +let s:rgb["grey64"] = "#a3a3a3" +let s:rgb["grey65"] = "#a6a6a6" +let s:rgb["grey66"] = "#a8a8a8" +let s:rgb["grey67"] = "#ababab" +let s:rgb["grey68"] = "#adadad" +let s:rgb["grey69"] = "#b0b0b0" +let s:rgb["grey7"] = "#121212" +let s:rgb["grey70"] = "#b3b3b3" +let s:rgb["grey71"] = "#b5b5b5" +let s:rgb["grey72"] = "#b8b8b8" +let s:rgb["grey73"] = "#bababa" +let s:rgb["grey74"] = "#bdbdbd" +let s:rgb["grey75"] = "#bfbfbf" +let s:rgb["grey76"] = "#c2c2c2" +let s:rgb["grey77"] = "#c4c4c4" +let s:rgb["grey78"] = "#c7c7c7" +let s:rgb["grey79"] = "#c9c9c9" +let s:rgb["grey8"] = "#141414" +let s:rgb["grey80"] = "#cccccc" +let s:rgb["grey81"] = "#cfcfcf" +let s:rgb["grey82"] = "#d1d1d1" +let s:rgb["grey83"] = "#d4d4d4" +let s:rgb["grey84"] = "#d6d6d6" +let s:rgb["grey85"] = "#d9d9d9" +let s:rgb["grey86"] = "#dbdbdb" +let s:rgb["grey87"] = "#dedede" +let s:rgb["grey88"] = "#e0e0e0" +let s:rgb["grey89"] = "#e3e3e3" +let s:rgb["grey9"] = "#171717" +let s:rgb["grey90"] = "#e5e5e5" +let s:rgb["grey91"] = "#e8e8e8" +let s:rgb["grey92"] = "#ebebeb" +let s:rgb["grey93"] = "#ededed" +let s:rgb["grey94"] = "#f0f0f0" +let s:rgb["grey95"] = "#f2f2f2" +let s:rgb["grey96"] = "#f5f5f5" +let s:rgb["grey97"] = "#f7f7f7" +let s:rgb["grey98"] = "#fafafa" +let s:rgb["grey99"] = "#fcfcfc" +let s:rgb["honeydew"] = "#f0fff0" +let s:rgb["honeydew1"] = "#f0fff0" +let s:rgb["honeydew2"] = "#e0eee0" +let s:rgb["honeydew3"] = "#c1cdc1" +let s:rgb["honeydew4"] = "#838b83" +let s:rgb["hot pink"] = "#ff69b4" +let s:rgb["hotpink"] = "#ff69b4" +let s:rgb["hotpink1"] = "#ff6eb4" +let s:rgb["hotpink2"] = "#ee6aa7" +let s:rgb["hotpink3"] = "#cd6090" +let s:rgb["hotpink4"] = "#8b3a62" +let s:rgb["indian red"] = "#cd5c5c" +let s:rgb["indianred"] = "#cd5c5c" +let s:rgb["indianred1"] = "#ff6a6a" +let s:rgb["indianred2"] = "#ee6363" +let s:rgb["indianred3"] = "#cd5555" +let s:rgb["indianred4"] = "#8b3a3a" +let s:rgb["ivory"] = "#fffff0" +let s:rgb["ivory1"] = "#fffff0" +let s:rgb["ivory2"] = "#eeeee0" +let s:rgb["ivory3"] = "#cdcdc1" +let s:rgb["ivory4"] = "#8b8b83" +let s:rgb["khaki"] = "#f0e68c" +let s:rgb["khaki1"] = "#fff68f" +let s:rgb["khaki2"] = "#eee685" +let s:rgb["khaki3"] = "#cdc673" +let s:rgb["khaki4"] = "#8b864e" +let s:rgb["lavender blush"] = "#fff0f5" +let s:rgb["lavender"] = "#e6e6fa" +let s:rgb["lavenderblush"] = "#fff0f5" +let s:rgb["lavenderblush1"] = "#fff0f5" +let s:rgb["lavenderblush2"] = "#eee0e5" +let s:rgb["lavenderblush3"] = "#cdc1c5" +let s:rgb["lavenderblush4"] = "#8b8386" +let s:rgb["lawn green"] = "#7cfc00" +let s:rgb["lawngreen"] = "#7cfc00" +let s:rgb["lemon chiffon"] = "#fffacd" +let s:rgb["lemonchiffon"] = "#fffacd" +let s:rgb["lemonchiffon1"] = "#fffacd" +let s:rgb["lemonchiffon2"] = "#eee9bf" +let s:rgb["lemonchiffon3"] = "#cdc9a5" +let s:rgb["lemonchiffon4"] = "#8b8970" +let s:rgb["light blue"] = "#add8e6" +let s:rgb["light coral"] = "#f08080" +let s:rgb["light cyan"] = "#e0ffff" +let s:rgb["light goldenrod yellow"] = "#fafad2" +let s:rgb["light goldenrod"] = "#eedd82" +let s:rgb["light gray"] = "#d3d3d3" +let s:rgb["light green"] = "#90ee90" +let s:rgb["light grey"] = "#d3d3d3" +let s:rgb["light magenta"] = "#ffbbff" +let s:rgb["light pink"] = "#ffb6c1" +let s:rgb["light red"] = "#ffbbbb" +let s:rgb["light salmon"] = "#ffa07a" +let s:rgb["light sea green"] = "#20b2aa" +let s:rgb["light sky blue"] = "#87cefa" +let s:rgb["light slate blue"] = "#8470ff" +let s:rgb["light slate gray"] = "#778899" +let s:rgb["light slate grey"] = "#778899" +let s:rgb["light steel blue"] = "#b0c4de" +let s:rgb["light yellow"] = "#ffffe0" +let s:rgb["lightblue"] = "#add8e6" +let s:rgb["lightblue1"] = "#bfefff" +let s:rgb["lightblue2"] = "#b2dfee" +let s:rgb["lightblue3"] = "#9ac0cd" +let s:rgb["lightblue4"] = "#68838b" +let s:rgb["lightcoral"] = "#f08080" +let s:rgb["lightcyan"] = "#e0ffff" +let s:rgb["lightcyan1"] = "#e0ffff" +let s:rgb["lightcyan2"] = "#d1eeee" +let s:rgb["lightcyan3"] = "#b4cdcd" +let s:rgb["lightcyan4"] = "#7a8b8b" +let s:rgb["lightgoldenrod"] = "#eedd82" +let s:rgb["lightgoldenrod1"] = "#ffec8b" +let s:rgb["lightgoldenrod2"] = "#eedc82" +let s:rgb["lightgoldenrod3"] = "#cdbe70" +let s:rgb["lightgoldenrod4"] = "#8b814c" +let s:rgb["lightgoldenrodyellow"] = "#fafad2" +let s:rgb["lightgray"] = "#d3d3d3" +let s:rgb["lightgreen"] = "#90ee90" +let s:rgb["lightgrey"] = "#d3d3d3" +let s:rgb["lightmagenta"] = "#ffbbff" +let s:rgb["lightpink"] = "#ffb6c1" +let s:rgb["lightpink1"] = "#ffaeb9" +let s:rgb["lightpink2"] = "#eea2ad" +let s:rgb["lightpink3"] = "#cd8c95" +let s:rgb["lightpink4"] = "#8b5f65" +let s:rgb["lightred"] = "#ffbbbb" +let s:rgb["lightsalmon"] = "#ffa07a" +let s:rgb["lightsalmon1"] = "#ffa07a" +let s:rgb["lightsalmon2"] = "#ee9572" +let s:rgb["lightsalmon3"] = "#cd8162" +let s:rgb["lightsalmon4"] = "#8b5742" +let s:rgb["lightseagreen"] = "#20b2aa" +let s:rgb["lightskyblue"] = "#87cefa" +let s:rgb["lightskyblue1"] = "#b0e2ff" +let s:rgb["lightskyblue2"] = "#a4d3ee" +let s:rgb["lightskyblue3"] = "#8db6cd" +let s:rgb["lightskyblue4"] = "#607b8b" +let s:rgb["lightslateblue"] = "#8470ff" +let s:rgb["lightslategray"] = "#778899" +let s:rgb["lightslategrey"] = "#778899" +let s:rgb["lightsteelblue"] = "#b0c4de" +let s:rgb["lightsteelblue1"] = "#cae1ff" +let s:rgb["lightsteelblue2"] = "#bcd2ee" +let s:rgb["lightsteelblue3"] = "#a2b5cd" +let s:rgb["lightsteelblue4"] = "#6e7b8b" +let s:rgb["lightyellow"] = "#ffffe0" +let s:rgb["lightyellow1"] = "#ffffe0" +let s:rgb["lightyellow2"] = "#eeeed1" +let s:rgb["lightyellow3"] = "#cdcdb4" +let s:rgb["lightyellow4"] = "#8b8b7a" +let s:rgb["lime green"] = "#32cd32" +let s:rgb["limegreen"] = "#32cd32" +let s:rgb["linen"] = "#faf0e6" +let s:rgb["magenta"] = "#ff00ff" +let s:rgb["magenta1"] = "#ff00ff" +let s:rgb["magenta2"] = "#ee00ee" +let s:rgb["magenta3"] = "#cd00cd" +let s:rgb["magenta4"] = "#8b008b" +let s:rgb["maroon"] = "#b03060" +let s:rgb["maroon1"] = "#ff34b3" +let s:rgb["maroon2"] = "#ee30a7" +let s:rgb["maroon3"] = "#cd2990" +let s:rgb["maroon4"] = "#8b1c62" +let s:rgb["medium aquamarine"] = "#66cdaa" +let s:rgb["medium blue"] = "#0000cd" +let s:rgb["medium orchid"] = "#ba55d3" +let s:rgb["medium purple"] = "#9370db" +let s:rgb["medium sea green"] = "#3cb371" +let s:rgb["medium slate blue"] = "#7b68ee" +let s:rgb["medium spring green"] = "#00fa9a" +let s:rgb["medium turquoise"] = "#48d1cc" +let s:rgb["medium violet red"] = "#c71585" +let s:rgb["mediumaquamarine"] = "#66cdaa" +let s:rgb["mediumblue"] = "#0000cd" +let s:rgb["mediumorchid"] = "#ba55d3" +let s:rgb["mediumorchid1"] = "#e066ff" +let s:rgb["mediumorchid2"] = "#d15fee" +let s:rgb["mediumorchid3"] = "#b452cd" +let s:rgb["mediumorchid4"] = "#7a378b" +let s:rgb["mediumpurple"] = "#9370db" +let s:rgb["mediumpurple1"] = "#ab82ff" +let s:rgb["mediumpurple2"] = "#9f79ee" +let s:rgb["mediumpurple3"] = "#8968cd" +let s:rgb["mediumpurple4"] = "#5d478b" +let s:rgb["mediumseagreen"] = "#3cb371" +let s:rgb["mediumslateblue"] = "#7b68ee" +let s:rgb["mediumspringgreen"] = "#00fa9a" +let s:rgb["mediumturquoise"] = "#48d1cc" +let s:rgb["mediumvioletred"] = "#c71585" +let s:rgb["midnight blue"] = "#191970" +let s:rgb["midnightblue"] = "#191970" +let s:rgb["mint cream"] = "#f5fffa" +let s:rgb["mintcream"] = "#f5fffa" +let s:rgb["misty rose"] = "#ffe4e1" +let s:rgb["mistyrose"] = "#ffe4e1" +let s:rgb["mistyrose1"] = "#ffe4e1" +let s:rgb["mistyrose2"] = "#eed5d2" +let s:rgb["mistyrose3"] = "#cdb7b5" +let s:rgb["mistyrose4"] = "#8b7d7b" +let s:rgb["moccasin"] = "#ffe4b5" +let s:rgb["navajo white"] = "#ffdead" +let s:rgb["navajowhite"] = "#ffdead" +let s:rgb["navajowhite1"] = "#ffdead" +let s:rgb["navajowhite2"] = "#eecfa1" +let s:rgb["navajowhite3"] = "#cdb38b" +let s:rgb["navajowhite4"] = "#8b795e" +let s:rgb["navy blue"] = "#000080" +let s:rgb["navy"] = "#000080" +let s:rgb["navyblue"] = "#000080" +let s:rgb["old lace"] = "#fdf5e6" +let s:rgb["oldlace"] = "#fdf5e6" +let s:rgb["olive drab"] = "#6b8e23" +let s:rgb["olivedrab"] = "#6b8e23" +let s:rgb["olivedrab1"] = "#c0ff3e" +let s:rgb["olivedrab2"] = "#b3ee3a" +let s:rgb["olivedrab3"] = "#9acd32" +let s:rgb["olivedrab4"] = "#698b22" +let s:rgb["orange red"] = "#ff4500" +let s:rgb["orange"] = "#ffa500" +let s:rgb["orange1"] = "#ffa500" +let s:rgb["orange2"] = "#ee9a00" +let s:rgb["orange3"] = "#cd8500" +let s:rgb["orange4"] = "#8b5a00" +let s:rgb["orangered"] = "#ff4500" +let s:rgb["orangered1"] = "#ff4500" +let s:rgb["orangered2"] = "#ee4000" +let s:rgb["orangered3"] = "#cd3700" +let s:rgb["orangered4"] = "#8b2500" +let s:rgb["orchid"] = "#da70d6" +let s:rgb["orchid1"] = "#ff83fa" +let s:rgb["orchid2"] = "#ee7ae9" +let s:rgb["orchid3"] = "#cd69c9" +let s:rgb["orchid4"] = "#8b4789" +let s:rgb["pale goldenrod"] = "#eee8aa" +let s:rgb["pale green"] = "#98fb98" +let s:rgb["pale turquoise"] = "#afeeee" +let s:rgb["pale violet red"] = "#db7093" +let s:rgb["palegoldenrod"] = "#eee8aa" +let s:rgb["palegreen"] = "#98fb98" +let s:rgb["palegreen1"] = "#9aff9a" +let s:rgb["palegreen2"] = "#90ee90" +let s:rgb["palegreen3"] = "#7ccd7c" +let s:rgb["palegreen4"] = "#548b54" +let s:rgb["paleturquoise"] = "#afeeee" +let s:rgb["paleturquoise1"] = "#bbffff" +let s:rgb["paleturquoise2"] = "#aeeeee" +let s:rgb["paleturquoise3"] = "#96cdcd" +let s:rgb["paleturquoise4"] = "#668b8b" +let s:rgb["palevioletred"] = "#db7093" +let s:rgb["palevioletred1"] = "#ff82ab" +let s:rgb["palevioletred2"] = "#ee799f" +let s:rgb["palevioletred3"] = "#cd6889" +let s:rgb["palevioletred4"] = "#8b475d" +let s:rgb["papaya whip"] = "#ffefd5" +let s:rgb["papayawhip"] = "#ffefd5" +let s:rgb["peach puff"] = "#ffdab9" +let s:rgb["peachpuff"] = "#ffdab9" +let s:rgb["peachpuff1"] = "#ffdab9" +let s:rgb["peachpuff2"] = "#eecbad" +let s:rgb["peachpuff3"] = "#cdaf95" +let s:rgb["peachpuff4"] = "#8b7765" +let s:rgb["peru"] = "#cd853f" +let s:rgb["pink"] = "#ffc0cb" +let s:rgb["pink1"] = "#ffb5c5" +let s:rgb["pink2"] = "#eea9b8" +let s:rgb["pink3"] = "#cd919e" +let s:rgb["pink4"] = "#8b636c" +let s:rgb["plum"] = "#dda0dd" +let s:rgb["plum1"] = "#ffbbff" +let s:rgb["plum2"] = "#eeaeee" +let s:rgb["plum3"] = "#cd96cd" +let s:rgb["plum4"] = "#8b668b" +let s:rgb["powder blue"] = "#b0e0e6" +let s:rgb["powderblue"] = "#b0e0e6" +let s:rgb["purple"] = "#a020f0" +let s:rgb["purple1"] = "#9b30ff" +let s:rgb["purple2"] = "#912cee" +let s:rgb["purple3"] = "#7d26cd" +let s:rgb["purple4"] = "#551a8b" +let s:rgb["red"] = "#ff0000" +let s:rgb["red1"] = "#ff0000" +let s:rgb["red2"] = "#ee0000" +let s:rgb["red3"] = "#cd0000" +let s:rgb["red4"] = "#8b0000" +let s:rgb["rosy brown"] = "#bc8f8f" +let s:rgb["rosybrown"] = "#bc8f8f" +let s:rgb["rosybrown1"] = "#ffc1c1" +let s:rgb["rosybrown2"] = "#eeb4b4" +let s:rgb["rosybrown3"] = "#cd9b9b" +let s:rgb["rosybrown4"] = "#8b6969" +let s:rgb["royal blue"] = "#4169e1" +let s:rgb["royalblue"] = "#4169e1" +let s:rgb["royalblue1"] = "#4876ff" +let s:rgb["royalblue2"] = "#436eee" +let s:rgb["royalblue3"] = "#3a5fcd" +let s:rgb["royalblue4"] = "#27408b" +let s:rgb["saddle brown"] = "#8b4513" +let s:rgb["saddlebrown"] = "#8b4513" +let s:rgb["salmon"] = "#fa8072" +let s:rgb["salmon1"] = "#ff8c69" +let s:rgb["salmon2"] = "#ee8262" +let s:rgb["salmon3"] = "#cd7054" +let s:rgb["salmon4"] = "#8b4c39" +let s:rgb["sandy brown"] = "#f4a460" +let s:rgb["sandybrown"] = "#f4a460" +let s:rgb["sea green"] = "#2e8b57" +let s:rgb["seagreen"] = "#2e8b57" +let s:rgb["seagreen1"] = "#54ff9f" +let s:rgb["seagreen2"] = "#4eee94" +let s:rgb["seagreen3"] = "#43cd80" +let s:rgb["seagreen4"] = "#2e8b57" +let s:rgb["seashell"] = "#fff5ee" +let s:rgb["seashell1"] = "#fff5ee" +let s:rgb["seashell2"] = "#eee5de" +let s:rgb["seashell3"] = "#cdc5bf" +let s:rgb["seashell4"] = "#8b8682" +let s:rgb["sienna"] = "#a0522d" +let s:rgb["sienna1"] = "#ff8247" +let s:rgb["sienna2"] = "#ee7942" +let s:rgb["sienna3"] = "#cd6839" +let s:rgb["sienna4"] = "#8b4726" +let s:rgb["sky blue"] = "#87ceeb" +let s:rgb["skyblue"] = "#87ceeb" +let s:rgb["skyblue1"] = "#87ceff" +let s:rgb["skyblue2"] = "#7ec0ee" +let s:rgb["skyblue3"] = "#6ca6cd" +let s:rgb["skyblue4"] = "#4a708b" +let s:rgb["slate blue"] = "#6a5acd" +let s:rgb["slate gray"] = "#708090" +let s:rgb["slate grey"] = "#708090" +let s:rgb["slateblue"] = "#6a5acd" +let s:rgb["slateblue1"] = "#836fff" +let s:rgb["slateblue2"] = "#7a67ee" +let s:rgb["slateblue3"] = "#6959cd" +let s:rgb["slateblue4"] = "#473c8b" +let s:rgb["slategray"] = "#708090" +let s:rgb["slategray1"] = "#c6e2ff" +let s:rgb["slategray2"] = "#b9d3ee" +let s:rgb["slategray3"] = "#9fb6cd" +let s:rgb["slategray4"] = "#6c7b8b" +let s:rgb["slategrey"] = "#708090" +let s:rgb["snow"] = "#fffafa" +let s:rgb["snow1"] = "#fffafa" +let s:rgb["snow2"] = "#eee9e9" +let s:rgb["snow3"] = "#cdc9c9" +let s:rgb["snow4"] = "#8b8989" +let s:rgb["spring green"] = "#00ff7f" +let s:rgb["springgreen"] = "#00ff7f" +let s:rgb["springgreen1"] = "#00ff7f" +let s:rgb["springgreen2"] = "#00ee76" +let s:rgb["springgreen3"] = "#00cd66" +let s:rgb["springgreen4"] = "#008b45" +let s:rgb["steel blue"] = "#4682b4" +let s:rgb["steelblue"] = "#4682b4" +let s:rgb["steelblue1"] = "#63b8ff" +let s:rgb["steelblue2"] = "#5cacee" +let s:rgb["steelblue3"] = "#4f94cd" +let s:rgb["steelblue4"] = "#36648b" +let s:rgb["tan"] = "#d2b48c" +let s:rgb["tan1"] = "#ffa54f" +let s:rgb["tan2"] = "#ee9a49" +let s:rgb["tan3"] = "#cd853f" +let s:rgb["tan4"] = "#8b5a2b" +let s:rgb["thistle"] = "#d8bfd8" +let s:rgb["thistle1"] = "#ffe1ff" +let s:rgb["thistle2"] = "#eed2ee" +let s:rgb["thistle3"] = "#cdb5cd" +let s:rgb["thistle4"] = "#8b7b8b" +let s:rgb["tomato"] = "#ff6347" +let s:rgb["tomato1"] = "#ff6347" +let s:rgb["tomato2"] = "#ee5c42" +let s:rgb["tomato3"] = "#cd4f39" +let s:rgb["tomato4"] = "#8b3626" +let s:rgb["turquoise"] = "#40e0d0" +let s:rgb["turquoise1"] = "#00f5ff" +let s:rgb["turquoise2"] = "#00e5ee" +let s:rgb["turquoise3"] = "#00c5cd" +let s:rgb["turquoise4"] = "#00868b" +let s:rgb["violet red"] = "#d02090" +let s:rgb["violet"] = "#ee82ee" +let s:rgb["violetred"] = "#d02090" +let s:rgb["violetred1"] = "#ff3e96" +let s:rgb["violetred2"] = "#ee3a8c" +let s:rgb["violetred3"] = "#cd3278" +let s:rgb["violetred4"] = "#8b2252" +let s:rgb["wheat"] = "#f5deb3" +let s:rgb["wheat1"] = "#ffe7ba" +let s:rgb["wheat2"] = "#eed8ae" +let s:rgb["wheat3"] = "#cdba96" +let s:rgb["wheat4"] = "#8b7e66" +let s:rgb["white smoke"] = "#f5f5f5" +let s:rgb["white"] = "#ffffff" +let s:rgb["whitesmoke"] = "#f5f5f5" +let s:rgb["yellow green"] = "#9acd32" +let s:rgb["yellow"] = "#ffff00" +let s:rgb["yellow1"] = "#ffff00" +let s:rgb["yellow2"] = "#eeee00" +let s:rgb["yellow3"] = "#cdcd00" +let s:rgb["yellow4"] = "#8b8b00" +let s:rgb["yellowgreen"] = "#9acd32" + +if has('mac') && !has('macunix') + let s:rgb["dark gray"] = "0x808080" + let s:rgb["darkgray"] = "0x808080" + let s:rgb["dark grey"] = "0x808080" + let s:rgb["darkgrey"] = "0x808080" + let s:rgb["gray"] = "0xc0c0c0" + let s:rgb["grey"] = "0xc0c0c0" + let s:rgb["light gray"] = "0xe0e0e0" + let s:rgb["lightgray"] = "0xe0e0e0" + let s:rgb["light grey"] = "0xe0e0e0" + let s:rgb["lightgrey"] = "0xe0e0e0" + let s:rgb["dark red"] = "0x800000" + let s:rgb["darkred"] = "0x800000" + let s:rgb["red"] = "0xdd0806" + let s:rgb["light red"] = "0xffa0a0" + let s:rgb["lightred"] = "0xffa0a0" + let s:rgb["dark blue"] = "0x000080" + let s:rgb["darkblue"] = "0x000080" + let s:rgb["blue"] = "0x0000d4" + let s:rgb["light blue"] = "0xa0a0ff" + let s:rgb["lightblue"] = "0xa0a0ff" + let s:rgb["dark green"] = "0x008000" + let s:rgb["darkgreen"] = "0x008000" + let s:rgb["green"] = "0x006411" + let s:rgb["light green"] = "0xa0ffa0" + let s:rgb["lightgreen"] = "0xa0ffa0" + let s:rgb["dark cyan"] = "0x008080" + let s:rgb["darkcyan"] = "0x008080" + let s:rgb["cyan"] = "0x02abea" + let s:rgb["light cyan"] = "0xa0ffff" + let s:rgb["lightcyan"] = "0xa0ffff" + let s:rgb["dark magenta"] = "0x800080" + let s:rgb["darkmagenta"] = "0x800080" + let s:rgb["magenta"] = "0xf20884" + let s:rgb["light magenta"] = "0xf0a0f0" + let s:rgb["lightmagenta"] = "0xf0a0f0" + let s:rgb["brown"] = "0x804040" + let s:rgb["yellow"] = "0xfcf305" + let s:rgb["light yellow"] = "0xffffa0" + let s:rgb["lightyellow"] = "0xffffa0" + let s:rgb["orange"] = "0xfc8000" + let s:rgb["purple"] = "0xa020f0" + let s:rgb["slateblue"] = "0x6a5acd" + let s:rgb["violet"] = "0x8d38c9" +endif + +function! csapprox#rgb() + return s:rgb +endfunction diff --git a/CSApprox/autoload/csapprox/common.vim b/CSApprox/autoload/csapprox/common.vim new file mode 100755 index 0000000..cf61379 --- /dev/null +++ b/CSApprox/autoload/csapprox/common.vim @@ -0,0 +1,78 @@ +" Copyright (c) 2012, Matthew J. Wozniski +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" * Redistributions of source code must retain the above copyright +" notice, this list of conditions and the following disclaimer. +" * Redistributions in binary form must reproduce the above copyright +" notice, this list of conditions and the following disclaimer in the +" documentation and/or other materials provided with the distribution. +" * The names of the contributors may not be used to endorse or promote +" products derived from this software without specific prior written +" permission. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY +" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +let s:xterm_colors = [ 0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF ] +let s:eterm_colors = [ 0x00, 0x2A, 0x55, 0x7F, 0xAA, 0xD4 ] +let s:konsole_colors = [ 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF ] +let s:xterm_greys = [ 0x08, 0x12, 0x1C, 0x26, 0x30, 0x3A, + \ 0x44, 0x4E, 0x58, 0x62, 0x6C, 0x76, + \ 0x80, 0x8A, 0x94, 0x9E, 0xA8, 0xB2, + \ 0xBC, 0xC6, 0xD0, 0xDA, 0xE4, 0xEE ] + +let s:urxvt_colors = [ 0x00, 0x8B, 0xCD, 0xFF ] +let s:urxvt_greys = [ 0x2E, 0x5C, 0x73, 0x8B, + \ 0xA2, 0xB9, 0xD0, 0xE7 ] + +" Uses &term to determine which cube should be use. If &term is set to +" "xterm" or begins with "screen", the variables g:CSApprox_eterm and +" g:CSApprox_konsole can be used to select a different palette. +function! csapprox#common#PaletteType() + if &t_Co == 88 + let type = 'urxvt' + elseif &term ==# 'xterm' || &term =~# '^screen' || &term==# 'builtin_gui' + if exists('g:CSApprox_konsole') && g:CSApprox_konsole + let type = 'konsole' + elseif exists('g:CSApprox_eterm') && g:CSApprox_eterm + let type = 'eterm' + else + let type = 'xterm' + endif + elseif &term =~? '^konsole' + " Konsole only used its own palette up til KDE 4.2.0 + if executable('kde4-config') && system('kde4-config --kde-version') =~ '^4\.[10]\.' + let type = 'konsole' + elseif executable('kde-config') && system('kde-config --version') =~# 'KDE: 3\.' + let type = 'konsole' + else + let type = 'xterm' + endif + elseif &term =~? '^eterm' + let type = 'eterm' + else + let type = 'xterm' + endif + + return type +endfunction + +" Retrieve the list of greyscale ramp colors for the current palette +function! csapprox#common#Greys() + return (&t_Co == 88 ? s:urxvt_greys : s:xterm_greys) +endfunction + +" Retrieve the list of non-greyscale ramp colors for the current palette +function! csapprox#common#Colors() + return s:{csapprox#common#PaletteType()}_colors +endfunction diff --git a/CSApprox/autoload/csapprox/per_component.vim b/CSApprox/autoload/csapprox/per_component.vim new file mode 100755 index 0000000..1059dc8 --- /dev/null +++ b/CSApprox/autoload/csapprox/per_component.vim @@ -0,0 +1,91 @@ +" Copyright (c) 2012, Matthew J. Wozniski +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" * Redistributions of source code must retain the above copyright +" notice, this list of conditions and the following disclaimer. +" * Redistributions in binary form must reproduce the above copyright +" notice, this list of conditions and the following disclaimer in the +" documentation and/or other materials provided with the distribution. +" * The names of the contributors may not be used to endorse or promote +" products derived from this software without specific prior written +" permission. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY +" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +" Integer comparator used to sort the complete list of possible colors +function! s:IntCompare(i1, i2) + return a:i1 == a:i2 ? 0 : a:i1 > a:i2 ? 1 : -1 +endfunc + +" Color comparator to find the nearest element to a given one in a given list +function! s:NearestElemInList(elem, list) + let len = len(a:list) + for i in range(len-1) + if (a:elem <= (a:list[i] + a:list[i+1]) / 2) + return a:list[i] + endif + endfor + return a:list[len-1] +endfunction + +" Takes 3 decimal values for r, g, and b, and returns the closest cube number. +" +" This approximator considers closeness based upon the individiual components. +" For each of r, g, and b, it finds the closest cube component available on +" the cube. If the three closest matches can combine to form a valid color, +" this color is used, otherwise we repeat the search with the greys removed, +" meaning that the three new matches must make a valid color when combined. +function! csapprox#per_component#Approximate(r,g,b) + let hex = printf("%02x%02x%02x", a:r, a:g, a:b) + + let colors = csapprox#common#Colors() + let greys = csapprox#common#Greys() + let type = csapprox#common#PaletteType() + + if !exists('s:approximator_cache_'.type) + let s:approximator_cache_{type} = {} + endif + + let rv = get(s:approximator_cache_{type}, hex, -1) + if rv != -1 + return rv + endif + + " Only obtain sorted list once + if !exists("s:".type."_greys_colors") + let s:{type}_greys_colors = sort(greys + colors, "s:IntCompare") + endif + + let greys_colors = s:{type}_greys_colors + + let r = s:NearestElemInList(a:r, greys_colors) + let g = s:NearestElemInList(a:g, greys_colors) + let b = s:NearestElemInList(a:b, greys_colors) + + let len = len(colors) + if (r == g && g == b && index(greys, r) != -1) + let rv = 16 + len * len * len + index(greys, r) + else + let r = s:NearestElemInList(a:r, colors) + let g = s:NearestElemInList(a:g, colors) + let b = s:NearestElemInList(a:b, colors) + let rv = index(colors, r) * len * len + \ + index(colors, g) * len + \ + index(colors, b) + \ + 16 + endif + + let s:approximator_cache_{type}[hex] = rv + return rv +endfunction diff --git a/CSApprox/plugin/CSApprox.vim b/CSApprox/plugin/CSApprox.vim new file mode 100755 index 0000000..68f92d8 --- /dev/null +++ b/CSApprox/plugin/CSApprox.vim @@ -0,0 +1,921 @@ +" CSApprox: Make gvim-only colorschemes Just Work terminal vim +" Maintainer: Matthew Wozniski (godlygeek@gmail.com) +" Date: Fri, 14 Sep 2012 01:12:13 -0400 +" Version: 4.00 +" History: :help csapprox-changelog +" +" Long Description: +" It's hard to find colorschemes for terminal Vim. Most colorschemes are +" written to only support GVim, and don't work at all in terminal Vim. +" +" This plugin makes GVim-only colorschemes Just Work in terminal Vim, as long +" as the terminal supports 88 or 256 colors - and most do these days. This +" usually requires no user interaction (but see below for what to do if things +" don't Just Work). After getting this plugin happily installed, any time you +" use :colorscheme it will do its magic and make the colorscheme Just Work. +" +" Whenever you change colorschemes using the :colorscheme command this script +" will be executed. It will take the colors that the scheme specified for use +" in the GUI and use an approximation algorithm to try to gracefully degrade +" them to the closest color available in your terminal. If you are running in +" a GUI or if your terminal doesn't support 88 or 256 colors, no changes are +" made. Also, no changes will be made if the colorscheme seems to have been +" high color already. +" +" License: +" Copyright (c) 2012, Matthew J. Wozniski +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" * Redistributions of source code must retain the above copyright +" notice, this list of conditions and the following disclaimer. +" * Redistributions in binary form must reproduce the above copyright +" notice, this list of conditions and the following disclaimer in the +" documentation and/or other materials provided with the distribution. +" * The names of the contributors may not be used to endorse or promote +" products derived from this software without specific prior written +" permission. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY +" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +" {>1} Basic plugin setup + +" {>2} Check preconditions +" Quit if the user doesn't want or need us or is missing the gui feature. We +" need +gui to be able to check the gui color settings; vim doesn't bother to +" store them if it is not built with +gui. +if exists('g:CSApprox_loaded') + finish +elseif !has('gui') && v:version < 703 + " Vim versions less than < 7.3.0 need +gui. + " Warn unless the user set g:CSApprox_verbose_level to zero. + if get(g:, 'CSApprox_verbose_level', 1) + echomsg "CSApprox needs gui support - not loading." + echomsg " See :help |csapprox-+gui| for possible workarounds." + endif + + finish +endif + +" {1} Mark us as loaded, and disable all compatibility options for now. +let g:CSApprox_loaded = 1 + +let s:savecpo = &cpo +set cpo&vim + +" {>1} Collect info for the set highlights + +" {>2} Determine if synIDattr is usable +" synIDattr() couldn't support 'guisp' until 7.2.052. This function returns +" true if :redir is needed to find the 'guisp' attribute, false if synIDattr() +" is functional. This test can be overridden by setting the global variable +" g:CSApprox_redirfallback to 1 (to force use of :redir) or to 0 (to force use +" of synIDattr()). +function! s:NeedRedirFallback() + if !exists("g:CSApprox_redirfallback") + let g:CSApprox_redirfallback = (v:version == 702 && !has('patch52')) + \ || v:version < 702 + endif + return g:CSApprox_redirfallback +endfunction + +" {>2} Collect and store the highlights +" Get a dictionary containing information for every highlight group not merely +" linked to another group. Return value is a dictionary, with highlight group +" numbers for keys and values that are dictionaries with four keys each, +" 'name', 'term', 'cterm', and 'gui'. 'name' holds the group name, and each +" of the others holds highlight information for that particular mode. +function! s:Highlights(modes) + let rv = {} + + let i = 0 + while 1 + let i += 1 + + " Only interested in groups that exist and aren't linked + if synIDtrans(i) == 0 + break + endif + + " Handle vim bug allowing groups with name == "" to be created + if synIDtrans(i) != i || len(synIDattr(i, "name")) == 0 + continue + endif + + let rv[i] = {} + let rv[i].name = synIDattr(i, "name") + + for where in a:modes + let rv[i][where] = {} + for attr in s:PossibleAttributes() + let rv[i][where][attr] = synIDattr(i, attr, where) + endfor + + for attr in [ "fg", "bg" ] + let rv[i][where][attr] = synIDattr(i, attr.'#', where) + endfor + + if where == "gui" + let rv[i][where]["sp"] = s:SynGuiSp(i, rv[i].name) + else + let rv[i][where]["sp"] = -1 + endif + + for attr in [ "fg", "bg", "sp" ] + if rv[i][where][attr] == -1 + let rv[i][where][attr] = '' + endif + endfor + endfor + endwhile + + return rv +endfunction + +" {>2} Retrieve guisp + +" Get guisp using whichever method is specified by _redir_fallback +function! s:SynGuiSp(idx, name) + if !s:NeedRedirFallback() + return s:SynGuiSpAttr(a:idx) + else + return s:SynGuiSpRedir(a:name) + endif +endfunction + +" {>3} Implementation for retrieving guisp with redir hack +function! s:SynGuiSpRedir(name) + redir => temp + exe 'sil hi ' . a:name + redir END + let temp = matchstr(temp, 'guisp=\zs.*') + if len(temp) == 0 || temp[0] =~ '\s' + let temp = "" + else + " Make sure we can handle guisp='dark red' + let temp = substitute(temp, '[\x00].*', '', '') + let temp = substitute(temp, '\s*\(c\=term\|gui\).*', '', '') + let temp = substitute(temp, '\s*$', '', '') + endif + return temp +endfunction + +" {>3} Implementation for retrieving guisp with synIDattr() +function! s:SynGuiSpAttr(idx) + return synIDattr(a:idx, 'sp#', 'gui') +endfunction + +" {>1} Handle color names + +" Place to store rgb.txt name to color mappings - lazy loaded if needed +let s:rgb = {} + +" {>2} Builtin gui color names +" gui_x11.c and gui_gtk_x11.c have some default colors names that are searched +" if the x server doesn't know about a color. If 'showrgb' is available, +" we'll default to using these color names and values, and overwrite them with +" other values if 'showrgb' tells us about those colors. +let s:rgb_defaults = { "lightred" : "#FFBBBB", + \ "lightgreen" : "#88FF88", + \ "lightmagenta" : "#FFBBFF", + \ "darkcyan" : "#008888", + \ "darkblue" : "#0000BB", + \ "darkred" : "#BB0000", + \ "darkmagenta" : "#BB00BB", + \ "darkgrey" : "#BBBBBB", + \ "darkyellow" : "#BBBB00", + \ "gray10" : "#1A1A1A", + \ "grey10" : "#1A1A1A", + \ "gray20" : "#333333", + \ "grey20" : "#333333", + \ "gray30" : "#4D4D4D", + \ "grey30" : "#4D4D4D", + \ "gray40" : "#666666", + \ "grey40" : "#666666", + \ "gray50" : "#7F7F7F", + \ "grey50" : "#7F7F7F", + \ "gray60" : "#999999", + \ "grey60" : "#999999", + \ "gray70" : "#B3B3B3", + \ "grey70" : "#B3B3B3", + \ "gray80" : "#CCCCCC", + \ "grey80" : "#CCCCCC", + \ "gray90" : "#E5E5E5", + \ "grey90" : "#E5E5E5" } + +" {>2} Colors that vim will use by name in one of the default schemes, either +" for bg=light or for bg=dark. This lets us avoid loading the entire rgb.txt +" database when the scheme itself doesn't ask for colors by name. +let s:rgb_presets = { "black" : "#000000", + \ "blue" : "#0000ff", + \ "brown" : "#a52a2a", + \ "cyan" : "#00ffff", + \ "darkblue" : "#00008b", + \ "darkcyan" : "#008b8b", + \ "darkgrey" : "#a9a9a9", + \ "darkmagenta" : "#8b008b", + \ "green" : "#00ff00", + \ "grey" : "#bebebe", + \ "grey40" : "#666666", + \ "grey90" : "#e5e5e5", + \ "lightblue" : "#add8e6", + \ "lightcyan" : "#e0ffff", + \ "lightgrey" : "#d3d3d3", + \ "lightmagenta" : "#ffbbff", + \ "magenta" : "#ff00ff", + \ "red" : "#ff0000", + \ "seagreen" : "#2e8b57", + \ "white" : "#ffffff", + \ "yellow" : "#ffff00" } + +" {>2} Find available color names +" Find the valid named colors. By default, use our own rgb list, but try to +" retrieve the system's list if g:CSApprox_use_showrgb is set to true. Store +" the color names and color values to the dictionary s:rgb - the keys are +" color names (in lowercase), the values are strings representing color values +" (as '#rrggbb'). +function! s:UpdateRgbHash() + try + if !exists("g:CSApprox_use_showrgb") || !g:CSApprox_use_showrgb + throw "Not using showrgb" + endif + + " We want to use the 'showrgb' program, if it's around + let lines = split(system('showrgb'), '\n') + + if v:shell_error || !exists('lines') || empty(lines) + throw "'showrgb' didn't give us an rgb.txt" + endif + + let s:rgb = copy(s:rgb_defaults) + + " fmt is (blanks?)(red)(blanks)(green)(blanks)(blue)(blanks)(name) + let parsepat = '^\s*\(\d\+\)\s\+\(\d\+\)\s\+\(\d\+\)\s\+\(.*\)$' + + for line in lines + let v = matchlist(line, parsepat) + if len(v) < 0 + throw "CSApprox: Bad RGB line: " . string(line) + endif + let s:rgb[tolower(v[4])] = printf("#%02x%02x%02x", v[1], v[2], v[3]) + endfor + catch + try + let s:rgb = csapprox#rgb() + catch + echohl ErrorMsg + echomsg "Can't call rgb() from autoload/csapprox.vim" + echomsg "Named colors will not be available!" + echohl None + endtry + endtry + + return 0 +endfunction + +" {>1} Derive and set cterm attributes + +" {>2} List of all possible attributes +function! s:PossibleAttributes() + return [ "bold", "italic", "reverse", "underline", "undercurl" ] +endfunction + +" {>2} Attribute overrides +" Allow the user to override a specified attribute with another attribute. +" For example, the default is to map 'italic' to 'underline' (since many +" terminals cannot display italic text, and gvim itself will replace italics +" with underlines where italicizing is impossible), and to replace 'sp' with +" 'fg' (since terminals can't use one color for the underline and another for +" the foreground, we color the entire word). This default can of course be +" overridden by the user, by setting g:CSApprox_attr_map. This map must be +" a dictionary of string keys, representing the same attributes that synIDattr +" can look up, to string values, representing the attribute mapped to or an +" empty string to disable the given attribute entirely. +function! s:attr_map(attr) + let rv = get(g:CSApprox_attr_map, a:attr, a:attr) + + return rv +endfunction + +function! s:NormalizeAttrMap(map) + let old = copy(a:map) + let new = filter(a:map, '0') + + let valid_attrs = [ 'bg', 'fg', 'sp' ] + s:PossibleAttributes() + + let colorattrs = [ 'fg', 'bg', 'sp' ] + + for olhs in keys(old) + if olhs ==? 'inverse' + let nlhs = 'reverse' + endif + + let orhs = old[olhs] + + if orhs ==? 'inverse' + let nrhs = 'reverse' + endif + + let nlhs = tolower(olhs) + let nrhs = tolower(orhs) + + try + if index(valid_attrs, nlhs) == -1 + echomsg "CSApprox: Bad attr map (removing unrecognized attribute " . olhs . ")" + elseif nrhs != '' && index(valid_attrs, nrhs) == -1 + echomsg "CSApprox: Bad attr map (removing unrecognized attribute " . orhs . ")" + elseif nrhs != '' && !!(index(colorattrs, nlhs)+1) != !!(index(colorattrs, nrhs)+1) + echomsg "CSApprox: Bad attr map (removing " . olhs . "; type mismatch with " . orhs . ")" + elseif nrhs == 'sp' + echomsg "CSApprox: Bad attr map (removing " . olhs . "; can't map to 'sp')" + else + let new[nlhs] = nrhs + endif + catch + echo v:exception + endtry + endfor +endfunction + +" {>2} Normalize the GUI settings of a highlight group +" If the Normal group is cleared, set it to gvim's default, black on white +" Though this would be a really weird thing for a scheme to do... *shrug* +function! s:FixupGuiInfo(highlights) + if a:highlights[s:hlid_normal].gui.bg == '' + let a:highlights[s:hlid_normal].gui.bg = 'white' + endif + + if a:highlights[s:hlid_normal].gui.fg == '' + let a:highlights[s:hlid_normal].gui.fg = 'black' + endif +endfunction + +" {>2} Map gui settings to cterm settings +" Given information about a highlight group, replace the cterm settings with +" the mapped gui settings, applying any attribute overrides along the way. In +" particular, this gives special treatment to the 'reverse' attribute and the +" 'guisp' attribute. In particular, if the 'reverse' attribute is set for +" gvim, we unset it for the terminal and instead set ctermfg to match guibg +" and vice versa, since terminals can consider a 'reverse' flag to mean using +" default-bg-on-default-fg instead of current-bg-on-current-fg. We also +" ensure that the 'sp' attribute is never set for cterm, since no terminal can +" handle that particular highlight. If the user wants to display the guisp +" color, he should map it to either 'fg' or 'bg' using g:CSApprox_attr_map. +function! s:FixupCtermInfo(highlights) + for hl in values(a:highlights) + + if !has_key(hl, 'cterm') + let hl["cterm"] = {} + endif + + " Find attributes to be set in the terminal + for attr in s:PossibleAttributes() + let hl.cterm[attr] = '' + if hl.gui[attr] == 1 + if s:attr_map(attr) != '' + let hl.cterm[ s:attr_map(attr) ] = 1 + endif + endif + endfor + + for color in [ "bg", "fg" ] + let eff_color = color + if hl.cterm['reverse'] + let eff_color = (color == 'bg' ? 'fg' : 'bg') + endif + + let hl.cterm[color] = get(hl.gui, s:attr_map(eff_color), '') + endfor + + if hl.gui['sp'] != '' && s:attr_map('sp') != '' + let hl.cterm[s:attr_map('sp')] = hl.gui['sp'] + endif + + if exists("g:CSApprox_fake_reverse") && g:CSApprox_fake_reverse + if hl.cterm['reverse'] && hl.cterm.bg == '' + let hl.cterm.bg = 'fg' + endif + + if hl.cterm['reverse'] && hl.cterm.fg == '' + let hl.cterm.fg = 'bg' + endif + + if hl.cterm['reverse'] + let hl.cterm.reverse = '' + endif + endif + endfor +endfunction + +" {>2} Kludge around inability to reference autoload functions +function! s:DefaultApproximator(...) + return call('csapprox#per_component#Approximate', a:000) +endfunction + +" {>2} Set cterm colors for a highlight group +" Given the information for a single highlight group (ie, the value of +" one of the items in s:Highlights() already normalized with s:FixupCtermInfo +" and s:FixupGuiInfo), handle matching the gvim colors to the closest cterm +" colors by calling the appropriate approximator as specified with the +" g:CSApprox_approximator_function variable and set the colors and attributes +" appropriately to match the gui. +function! s:SetCtermFromGui(hl) + let hl = a:hl + + " Set up the default approximator function, if needed + if !exists("g:CSApprox_approximator_function") + let g:CSApprox_approximator_function = function("s:DefaultApproximator") + endif + + " Clear existing highlights + exe 'hi ' . hl.name . ' cterm=NONE ctermbg=NONE ctermfg=NONE' + + for which in [ 'bg', 'fg' ] + let val = hl.cterm[which] + + " Skip unset colors + if val == -1 || val == "" + continue + endif + + " Try translating anything but 'fg', 'bg', #rrggbb, and rrggbb from an + " rgb.txt color to a #rrggbb color + if val !~? '^[fb]g$' && val !~ '^#\=\x\{6}$' + try + " First see if it is in our preset-by-vim rgb list + let val = s:rgb_presets[tolower(val)] + catch + " Then try loading and checking our real rgb list + if empty(s:rgb) + call s:UpdateRgbHash() + endif + try + let val = s:rgb[tolower(val)] + catch + " And then barf if we still haven't found it + if &verbose + echomsg "CSApprox: Colorscheme uses unknown color \"" . val . "\"" + endif + continue + endtry + endtry + endif + + if val =~? '^[fb]g$' + exe 'hi ' . hl.name . ' cterm' . which . '=' . val + let hl.cterm[which] = val + elseif val =~ '^#\=\x\{6}$' + let val = substitute(val, '^#', '', '') + let r = str2nr(val[0:1], 16) + let g = str2nr(val[2:3], 16) + let b = str2nr(val[4:5], 16) + let hl.cterm[which] = g:CSApprox_approximator_function(r, g, b) + exe 'hi ' . hl.name . ' cterm' . which . '=' . hl.cterm[which] + else + throw "Internal error handling color: " . val + endif + endfor + + " Finally, set the attributes + let attrs = s:PossibleAttributes() + call filter(attrs, 'hl.cterm[v:val] == 1') + + if !empty(attrs) + exe 'hi ' . hl.name . ' cterm=' . join(attrs, ',') + endif +endfunction + + +" {>1} Top-level control + +" Cache the highlight ID of the normal group; it's used often and won't change +let s:hlid_normal = hlID('Normal') + +" {>2} Builtin cterm color names above 15 +" Vim defines some color name to high color mappings internally (see +" syntax.c:do_highlight). Since we don't want to overwrite a colorscheme that +" was actually written for a high color terminal with our choices, but have no +" way to tell if a colorscheme was written for a high color terminal, we fall +" back on guessing. If any highlight group has a cterm color set to 16 or +" higher, we assume that the user has used a high color colorscheme - unless +" that color is one of the below, which vim can set internally when a color is +" requested by name. +let s:presets_88 = [] +let s:presets_88 += [32] " Brown +let s:presets_88 += [72] " DarkYellow +let s:presets_88 += [84] " Gray +let s:presets_88 += [84] " Grey +let s:presets_88 += [82] " DarkGray +let s:presets_88 += [82] " DarkGrey +let s:presets_88 += [43] " LightBlue +let s:presets_88 += [61] " LightGreen +let s:presets_88 += [63] " LightCyan +let s:presets_88 += [74] " LightRed +let s:presets_88 += [75] " LightMagenta +let s:presets_88 += [78] " LightYellow + +let s:presets_256 = [] +let s:presets_256 += [130] " Brown +let s:presets_256 += [130] " DarkYellow +let s:presets_256 += [248] " Gray +let s:presets_256 += [248] " Grey +let s:presets_256 += [242] " DarkGray +let s:presets_256 += [242] " DarkGrey +let s:presets_256 += [ 81] " LightBlue +let s:presets_256 += [121] " LightGreen +let s:presets_256 += [159] " LightCyan +let s:presets_256 += [224] " LightRed +let s:presets_256 += [225] " LightMagenta +let s:presets_256 += [229] " LightYellow + +" {>2} Wrapper around :exe to allow :executing multiple commands. +" "cmd" is the command to be :executed. +" If the variable is a String, it is :executed. +" If the variable is a List, each element is :executed. +function! s:exe(cmd) + if type(a:cmd) == type('') + exe a:cmd + else + for cmd in a:cmd + call s:exe(cmd) + endfor + endif +endfunction + +" {>2} Function to handle hooks +" Prototype: HandleHooks(type [, scheme]) +" "type" is the type of hook to be executed, ie. "pre" or "post" +" "scheme" is the name of the colorscheme that is currently active, if known +" +" If the variables g:CSApprox_hook_{type} and g:CSApprox_hook_{scheme}_{type} +" exist, this will :execute them in that order. If one does not exist, it +" will silently be ignored. +" +" If the scheme name contains characters that are invalid in a variable name, +" they will simply be removed. Ie, g:colors_name = "123 foo_bar-baz456" +" becomes "foo_barbaz456" +" +" NOTE: Exceptions will be printed out, rather than end processing early. The +" rationale is that it is worse for the user to fix the hook in an editor with +" broken colors. :) +function! s:HandleHooks(type, ...) + let type = a:type + let scheme = (a:0 == 1 ? a:1 : "") + let scheme = substitute(scheme, '[^[:alnum:]_]', '', 'g') + let scheme = substitute(scheme, '^\d\+', '', '') + + for cmd in [ 'g:CSApprox_hook_' . type, + \ 'g:CSApprox_' . scheme . '_hook_' . type, + \ 'g:CSApprox_hook_' . scheme . '_' . type ] + if exists(cmd) + try + call s:exe(eval(cmd)) + catch + echomsg "Error processing " . cmd . ":" + echomsg v:exception + endtry + endif + endfor +endfunction + +" {>2} Main function +" Wrapper around the actual implementation to make it easier to ensure that +" all temporary settings are restored by the time we return, whether or not +" something was thrown. Additionally, sets the 'verbose' option to the max of +" g:CSApprox_verbose_level (default 1) and &verbose for the duration of the +" main function. This allows us to default to a message whenever any error, +" even a recoverable one, occurs, meaning the user quickly finds out when +" something's wrong, but makes it very easy for the user to make us silent. +function! s:CSApprox(...) + try + if a:0 == 1 && a:1 + if !exists('s:inhibit_hicolor_test') + let s:inhibit_hicolor_test = 0 + endif + let s:inhibit_hicolor_test += 1 + endif + + let savelz = &lz + + set lz + + if exists("g:CSApprox_attr_map") && type(g:CSApprox_attr_map) == type({}) + call s:NormalizeAttrMap(g:CSApprox_attr_map) + else + let g:CSApprox_attr_map = { 'italic' : 'underline', 'sp' : 'fg' } + endif + + " colors_name must be unset and reset, or vim will helpfully reload the + " colorscheme when we set the background for the Normal group. + " See the help entries ':hi-normal-cterm' and 'g:colors_name' + if exists("g:colors_name") + let colors_name = g:colors_name + unlet g:colors_name + endif + + " Similarly, the global variable "syntax_cmd" must be set to something vim + " doesn't recognize, lest vim helpfully switch all colors back to the + " default whenever the Normal group is changed (in syncolor.vim)... + if exists("g:syntax_cmd") + let syntax_cmd = g:syntax_cmd + endif + let g:syntax_cmd = "PLEASE DON'T CHANGE ANY COLORS!!!" + + " Set up our verbosity level, if needed. + " Default to 1, so the user can know if something's wrong. + if !exists("g:CSApprox_verbose_level") + let g:CSApprox_verbose_level = 1 + endif + + call s:HandleHooks("pre", (exists("colors_name") ? colors_name : "")) + + let old_bg = &bg + + " Set 'verbose' set to the maximum of &verbose and CSApprox_verbose_level + exe max([&vbs, g:CSApprox_verbose_level]) 'verbose call s:CSApproxImpl()' + + let &bg = old_bg + + call s:HandleHooks("post", (exists("colors_name") ? colors_name : "")) + finally + if exists("colors_name") + let g:colors_name = colors_name + endif + + unlet g:syntax_cmd + if exists("syntax_cmd") + let g:syntax_cmd = syntax_cmd + endif + + let &lz = savelz + + if a:0 == 1 && a:1 + let s:inhibit_hicolor_test -= 1 + if s:inhibit_hicolor_test == 0 + unlet s:inhibit_hicolor_test + endif + endif + endtry +endfunction + +" {>2} CSApprox implementation +" Verifies that the user has not started the gui, and that vim recognizes his +" terminal as having enough colors for us to go on, then gathers the existing +" highlights and sets the cterm colors to match the gui colors for all those +" highlights (unless the colorscheme was already high-color). +function! s:CSApproxImpl() + " Return if not running in an 88/256 color terminal + if &t_Co != 256 && &t_Co != 88 + if &verbose && &t_Co != '' + echomsg "CSApprox skipped; terminal only has" &t_Co "colors, not 88/256" + echomsg "Try checking :help csapprox-terminal for workarounds" + endif + + return + endif + + " Get the current highlight colors + let highlights = s:Highlights(["gui"]) + + let hinums = keys(highlights) + + " Make sure that the script is not already 256 color by checking to make + " sure that no groups are set to a value above 256, unless the color they're + " set to can be set internally by vim (gotten by scraping + " color_numbers_{88,256} in syntax.c:do_highlight) + " + " XXX: s:inhibit_hicolor_test allows this test to be skipped for snapshots + if !exists("s:inhibit_hicolor_test") || !s:inhibit_hicolor_test + for hlid in hinums + for type in [ 'bg', 'fg' ] + let color = synIDattr(hlid, type, 'cterm') + + if color > 15 && index(s:presets_{&t_Co}, str2nr(color)) < 0 + " The value is set above 15, and wasn't set by vim. + if &verbose >= 2 + echomsg 'CSApprox: Exiting - high' type 'color found for' highlights[hlid].name + endif + return + endif + endfor + endfor + endif + + call s:FixupGuiInfo(highlights) + call s:FixupCtermInfo(highlights) + + " We need to set the Normal group first so 'bg' and 'fg' work as colors + call insert(hinums, remove(hinums, index(hinums, string(s:hlid_normal)))) + + " then set each color's cterm attributes to match gui + for hlid in hinums + call s:SetCtermFromGui(highlights[hlid]) + endfor +endfunction + +" {>2} Write out the current colors to an 88/256 color colorscheme file. +" "file" - destination filename +" "overwrite" - overwrite an existing file +function! s:CSApproxSnapshot(file, overwrite) + let force = a:overwrite + let file = fnamemodify(a:file, ":p") + + if empty(file) + throw "Bad file name: \"" . file . "\"" + elseif (filewritable(fnamemodify(file, ':h')) != 2) + throw "Cannot write to directory \"" . fnamemodify(file, ':h') . "\"" + elseif (glob(file) || filereadable(file)) && !force + " TODO - respect 'confirm' here and prompt if it's set. + echohl ErrorMsg + echomsg "E13: File exists (add ! to override)" + echohl None + return + endif + + " Sigh... This is basically a bug, but one that I have no chance of fixing. + " Vim decides that Pmenu should be highlighted in 'LightMagenta' in terminal + " vim and as 'Magenta' in gvim... And I can't ask it what color it actually + " *wants*. As far as I can see, there's no way for me to learn that + " I should output 'Magenta' when 'LightMagenta' is provided by vim for the + " terminal. + if !has('gui_running') + echohl WarningMsg + echomsg "Warning: The written colorscheme may have incorrect colors" + echomsg " when CSApproxSnapshot is used in terminal vim!" + echohl None + endif + + let save_t_Co = &t_Co + let s:inhibit_hicolor_test = 1 + if exists("g:CSApprox_konsole") + let save_CSApprox_konsole = g:CSApprox_konsole + endif + if exists("g:CSApprox_eterm") + let save_CSApprox_eterm = g:CSApprox_eterm + endif + + " Needed just like in CSApprox() + if exists("g:colors_name") + let colors_name = g:colors_name + unlet g:colors_name + endif + + " Needed just like in CSApprox() + if exists("g:syntax_cmd") + let syntax_cmd = g:syntax_cmd + endif + let g:syntax_cmd = "PLEASE DON'T CHANGE ANY COLORS!!!" + + try + let lines = [] + let lines += [ '" This scheme was created by CSApproxSnapshot' ] + let lines += [ '" on ' . strftime("%a, %d %b %Y") ] + let lines += [ '' ] + let lines += [ 'hi clear' ] + let lines += [ 'if exists("syntax_on")' ] + let lines += [ ' syntax reset' ] + let lines += [ 'endif' ] + let lines += [ '' ] + let lines += [ 'if v:version < 700' ] + let lines += [ ' let g:colors_name = expand(":t:r")' ] + let lines += [ ' command! -nargs=+ CSAHi exe "hi" substitute(substitute(, "undercurl", "underline", "g"), "guisp\\S\\+", "", "g")' ] + let lines += [ 'else' ] + let lines += [ ' let g:colors_name = expand(":t:r")' ] + let lines += [ ' command! -nargs=+ CSAHi exe "hi" ' ] + let lines += [ 'endif' ] + let lines += [ '' ] + let lines += [ 'function! s:old_kde()' ] + let lines += [ ' " Konsole only used its own palette up til KDE 4.2.0' ] + let lines += [ " if executable('kde4-config') && system('kde4-config --kde-version') =~ '^4\.[10]\.'" ] + let lines += [ ' return 1' ] + let lines += [ " elseif executable('kde-config') && system('kde-config --version') =~# 'KDE: 3\.'" ] + let lines += [ ' return 1' ] + let lines += [ ' else' ] + let lines += [ ' return 0' ] + let lines += [ ' endif' ] + let lines += [ 'endfunction' ] + let lines += [ '' ] + + + let lines += [ 'if 0' ] + for round in [ 'konsole', 'eterm', 'xterm', 'urxvt' ] + sil! unlet g:CSApprox_eterm + sil! unlet g:CSApprox_konsole + + if round == 'konsole' + let g:CSApprox_konsole = 1 + elseif round == 'eterm' + let g:CSApprox_eterm = 1 + endif + + if round == 'urxvt' + set t_Co=88 + else + set t_Co=256 + endif + + call s:CSApprox() + + let highlights = s:Highlights(["term", "cterm", "gui"]) + call s:FixupGuiInfo(highlights) + + if round == 'konsole' || round == 'eterm' + if round == 'konsole' + let term_matches_round = '(&term =~? "^konsole" && s:old_kde())' + else + let term_matches_round = '&term =~? "^' . round . '"' + endif + + let lines += [ 'elseif has("gui_running") || (&t_Co == ' . &t_Co + \ . ' && (&term ==# "xterm" || &term =~# "^screen")' + \ . ' && exists("g:CSApprox_' . round . '")' + \ . ' && g:CSApprox_' . round . ')' + \ . ' || ' . term_matches_round ] + else + let lines += [ 'elseif has("gui_running") || &t_Co == ' . &t_Co ] + endif + + let hinums = keys(highlights) + + call insert(hinums, remove(hinums, index(hinums, string(s:hlid_normal)))) + + for hlnum in hinums + let hl = highlights[hlnum] + let line = ' CSAHi ' . hl.name + for type in [ 'term', 'cterm', 'gui' ] + let attrs = s:PossibleAttributes() + call filter(attrs, 'hl[type][v:val] == 1') + let line .= ' ' . type . '=' . (empty(attrs) ? 'NONE' : join(attrs, ',')) + if type != 'term' + let line .= ' ' . type . 'bg=' . (len(hl[type].bg) ? hl[type].bg : 'bg') + let line .= ' ' . type . 'fg=' . (len(hl[type].fg) ? hl[type].fg : 'fg') + if type == 'gui' && hl.gui.sp !~ '^\s*$' + let line .= ' ' . type . 'sp=' . hl[type].sp + endif + endif + endfor + let lines += [ line ] + endfor + endfor + let lines += [ 'endif' ] + let lines += [ '' ] + let lines += [ 'if 1' ] + let lines += [ ' delcommand CSAHi' ] + let lines += [ 'endif' ] + call writefile(lines, file) + finally + let &t_Co = save_t_Co + + if exists("save_CSApprox_konsole") + let g:CSApprox_konsole = save_CSApprox_konsole + endif + if exists("save_CSApprox_eterm") + let g:CSApprox_eterm = save_CSApprox_eterm + endif + + if exists("colors_name") + let g:colors_name = colors_name + endif + + unlet g:syntax_cmd + if exists("syntax_cmd") + let g:syntax_cmd = syntax_cmd + endif + + call s:CSApprox() + + unlet s:inhibit_hicolor_test + endtry +endfunction + +" {>2} Snapshot user command +command! -bang -nargs=1 -complete=file -bar CSApproxSnapshot + \ call s:CSApproxSnapshot(, strlen("")) + +" {>2} Manual updates +command -bang -bar CSApprox call s:CSApprox(strlen("")) + +" {>1} Autocmds +" Set up an autogroup to hook us on the completion of any :colorscheme command +augroup CSApprox + au! + au ColorScheme * call s:CSApprox() + "au User CSApproxPost highlight Normal ctermbg=none | highlight NonText ctermbg=None +augroup END + +" {>1} Restore compatibility options +let &cpo = s:savecpo +unlet s:savecpo + + +" {0} vim:sw=2:sts=2:et:fdm=expr:fde=substitute(matchstr(getline(v\:lnum),'^\\s*"\\s*{\\zs.\\{-}\\ze}'),'^$','=','') diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9076601 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +SCRIPT=ftplugin/csv.vim +DOC=doc/ft-csv.txt +PLUGIN=csv +VERSION=$(shell sed -n '/Version:/{s/^.*\(\S\.\S\+\)$$/\1/;p}' $(SCRIPT)) +.PHONY : csv.vmb csv + + +all: vimball + +release: $(PLUGIN) $(PLUGIN).vmb + +clean: + find . -type f \( -name "*.vba" -o -name "*.vmb" -o -name "*.orig" \ + -o -name "*.~*" -o -name ".VimballRecord" -o -name ".*.un~" \ + -o -name "*.sw*" -o -name tags \) -delete + +dist-clean: clean + +vimball: $(PLUGIN).vmb install + +install: + vim -N -u NONE -i NONE -c 'ru! plugin/vimballPlugin.vim' -c 'ru! vimballPlugin.vim' -c':so %' -c':q!' ${PLUGIN}.vmb + +uninstall: + vim -N -u NONE -i NONE -c 'ru! plugin/vimballPlugin.vim' -c 'ru! vimballPlugin.vim' -c':RmVimball ${PLUGIN}.vmb' + +undo: + for i in */*.orig; do mv -f "$$i" "$${i%.*}"; done + +csv.vmb: + vim -N -u NONE -i NONE -c 'ru! plugin/vimballPlugin.vim' -c ':let g:vimball_home=getcwd()' -c ':call append("0", ["ftplugin/csv.vim", "doc/ft-csv.txt", "syntax/csv.vim", "ftdetect/csv.vim", "plugin/csv.vim"])' -c '$$d' -c ':%MkVimball! ${PLUGIN}' -c':q!' + ln -f $(PLUGIN).vmb $(PLUGIN)-$(VERSION).vmb + +csv: + rm -f ${PLUGIN}.vmb + perl -i.orig -pne 'if (/Version:/) {s/\.(\d+)*/sprintf(".%d", 1+$$1)/e}' ${SCRIPT} + perl -i -pne 'if (/GetLatestVimScripts:/) {s/(\d+)\s+:AutoInstall:/sprintf("%d :AutoInstall:", 1+$$1)/e}' ${SCRIPT} + perl -i -pne 'if (/Last Change:/) {s/(:\s+).*\n$$/sprintf(": %s", `date -R`)/e}' ${SCRIPT} + perl -i -pne 'if (/Last Change:/) {s/(:\s+).*\n$$/sprintf(": %s", `LC_TIME=C date +"%a, %d %b %Y"`)/e}' ${DOC} + perl -i.orig -pne 'if (/Version:/) {s/\.(\d+).*/sprintf(".%d", 1+$$1)/e}' ${DOC} + cp -f $(DOC) README diff --git a/README b/README new file mode 100644 index 0000000..c73fc44 --- /dev/null +++ b/README @@ -0,0 +1,1707 @@ +*ft-csv.txt* For Vim version 7.4 Last Change: Thu, 15 Jan 2015 + +Author: Christian Brabandt +Version: 0.31 +Homepage: http://www.vim.org/scripts/script.php?script_id=2830 + +The VIM LICENSE applies to the CSV filetype plugin (see |copyright|). +NO WARRANTY, EXPRESS OR IMPLIED. USE AT-YOUR-OWN-RISK. + *csv-toc* +1. Introduction.................................|csv-intro| +2. Installation.................................|csv-installation| +3. CSV Commands.................................|csv-commands| + 3.1 WhatColumn..............................|WhatColumn_CSV| + 3.2 NrColumns...............................|NrColumns_CSV| + 3.3 SearchInColumn..........................|SearchInColumn_CSV| + 3.4 HiColumn................................|HiColumn_CSV| + 3.5 ArrangeColumn...........................|ArrangeColumn_CSV| + 3.6 UnArrangeColumn.........................|UnArrangeColumn_CSV| + 3.7 DeleteColumn............................|DeleteColumn_CSV| + 3.8 InitCSV.................................|InitCSV| + 3.9 Header..................................|Header_CSV| + 3.10 Sort...................................|Sort_CSV| + 3.11 CopyColumn.............................|Copy_CSV| + 3.12 MoveColumn.............................|MoveCol_CSV| + 3.13 Sum of a column........................|SumCol_CSV| + 3.14 Create new records ....................|NewRecord_CSV| + 3.15 Change the delimiter...................|NewDelimiter_CSV| + 3.16 Check for duplicate records............|Duplicate_CSV| + 3.17 Normal mode commands...................|csv-mapping| + 3.18 Convert CSV file.......................|csv-convert| + 3.19 Dynamic filters........................|csv-filter| + 3.20 Analyze a column.......................|csv-analyze| + 3.21 Vertical Folding.......................|csv-vertfold| + 3.22 Transposing columns....................|csv-transpose| + 3.23 Transforming into a table..............|csv-tabularize| + 3.24 Add new empty columns..................|AddColumn_CSV| + 3.25 Substitute in columns..................|Substitute_CSV| +4. CSV Filetype configuration...................|csv-configuration| + 4.1 Delimiter...............................|csv-delimiter| + 4.2 Column..................................|csv-column| + 4.3 HiGroup.................................|csv-higroup| + 4.4 Strict Columns..........................|csv-strict| + 4.5 Concealing..............................|csv-conceal| + 4.6 Newlines................................|csv-newline| + 4.7 Highlight column automatically..........|csv-hicol| + 4.8 Fixed width columns.....................|csv-fixedwidth| + 4.8.1 Manual setup + 4.8.2 Setup using a Wizard + 4.9 CSV Header lines........................|csv-header| + 4.10 Number format..........................|csv-nrformat| + 4.11 Move folded lines......................|csv-move-folds| + 4.12 Using Comments.........................|csv-comments| +5. Functions....................................|CSV-Functions| + 5.1 CSVPat()................................|CSVPat()| + 5.2 CSVField()..............................|CSVField()| + 5.3 CSVCol()................................|CSVCol()| + 5.4 CSVSum()................................|CSVSum()| +6. CSV Tips and Tricks..........................|csv-tips| + 6.1 Statusline..............................|csv-stl| + 6.2 Slow CSV plugin.........................|csv-slow| + 6.3 Defining custom aggregate functions.....|csv-aggregate-functions| + 6.4 Autocommand on opening/closing files....|csv-arrange-autocmd| + 6.5 CSV Syntax error........................|csv-syntax-error| + 6.6 Calculating new column values...........|csv-calculate-column| +7. CSV Changelog................................|csv-changelog| + +============================================================================== +1. Introduction *csv-intro* + +This plugin is used for handling column separated data with Vim. Usually those +files are called csv files and use the ',' as delimiter, though sometimes they +use e.g. the '|' or ';' as delimiter and there also exists fixedwidth columns. +The aim of this plugin is to ease handling these kinds of files. + +This is a filetype plugin for CSV files. It was heavily influenced by +the Vim Wiki Tip667 (http://vim.wikia.com/wiki/VimTip667), though it +works differently. For instructions on installing this file, type +:help add-local-help |add-local-help| inside Vim. For a screenshot, of +how the plugin can be used, see http://www.256bit.org/~chrisbra/csv.gif + +============================================================================== +2. Installation *csv-installation* + +In order to have vim automatically detect csv files, you need to have +|ftplugins| enabled (e.g. by having this line in your |.vimrc| file: > + + :filetype plugin on + +< +The plugin already sets up some logic to detect CSV files. By default, +the plugin recognizes *.csv and *.dat files as CSV filetype. In order that the +CSV filetype plugin is loaded correctly, vim needs to be enabled to load +|filetype-plugins|. This can be ensured by putting a line like this in your +|.vimrc|: > + :filetype plugin on +< +(see also |filetype-plugin-on|). + +In case this did not work, you need to setup vim like this: + +To have Vim automatically detect csv files, you need to do the following. + + 1) Create your user runtime directory if you do not have one yet. This + directory needs to be in your 'runtime' path. In Unix this would + typically the ~/.vim directory, while in Windows this is usually your + ~/vimfiles directory. Use :echo expand("~") to find out, what Vim thinks + your user directory is. + To create this directory, you can do: > + + :!mkdir ~/.vim +< + for Unix and > + + :!mkdir ~/vimfiles +< + for Windows. + + 2) In that directory you create a file that will detect csv files. > + + if exists("did_load_csvfiletype") + finish + endif + let did_load_csvfiletype=1 + + augroup filetypedetect + au! BufRead,BufNewFile *.csv,*.dat setfiletype csv + augroup END +< + You save this file as "filetype.vim" in your user runtime diretory: > + + :w ~/.vim/filetype.vim +< + 3) To be able to use your new filetype.vim detection, you need to restart + Vim. Vim will then load the csv filetype plugin for all files whose + names end with .csv. + +============================================================================== +3. Commands *csv-commands* + +The CSV ftplugin provides several Commands. All commands are also provided +with the prefix :CSV (e.g. |:CSVNrColumns|) + + *:CSVWhatColumn* +3.1 WhatColumn *WhatColumn_CSV* +-------------- + +If you would like to know, on which column the cursor is, use > + :WhatColumn +< +or > + :CSVWhatColumn +< +Use the bang attribute, if you have a heading in the first line and you want +to know the name of the column in which the cursor is: > + :WhatColumn! +< + *:CSVNrColumns* +3.2 NrColumns *NrColumns_CSV* +-------------- + +`:NrColumns` and `:CSVNrColumns` outputs the maximum number of columns +available. It does this by testing the first 10 lines for the number of +columns. This usually should be enough. If you use the '!' attribute, it +outputs the number of columns in the current line. + + *:CSVSearchInColumn* +3.3 SearchInColumn *SearchInColumn_CSV* +------------------ + +Use `:SearchInColumn` or `:CSVSearchInColumn` to search for a pattern within a +specific column. The usage is: > + + :SearchInColumn [] /{pat}/ +< + +So if you would like to search in Column 1 for the word foobar, you enter > + + :SearchInColumn 1 /foobar/ + +Instead of / as delimiter, you can use any other delimiter you like. If you +don't enter a column, the current column will be used. + + *:CSVHiColumn* +3.4 HiColumn *HiColumn_CSV* +------------ + +`:HiColumn` or `:CSVHiColumn` can be used to highlight Column . +Currently the plugin uses the WildMenu Highlight Group. If you would like to +change this, you need to define the variable |g:csv_hiGroup|. + +If you do not specify a , HiColumn will highlight the column on which the +cursor is. Use > + + :HiColumn! + +to remove any highlighting. + +If you want to automatically highlight a column, see |csv-hicol| + + *:ArrangeColumn* *:CSVArrangeColumn* +3.5 ArrangeColumn *ArrangeColumn_CSV* +----------------- + +If you would like all columns to be visually arranged, you can use the +`:ArrangeColumn` or `:CSVArrangeColumn` command: > + + :[range]ArrangeColumn[!] + +Beware, that this will change your file and depending on the size of +your file may slow down Vim significantly. This is highly experimental. +:ArrangeCommand will try to vertically align all columns by their maximum +column size. + +Use the bang attribute to force recalculating the column width. This is +slower, but especially if you have modified the file, this will correctly +calculate the width of each column so that they can be correctly aligned. If +no column width has been calculated before, the width will be calculated, even +if the '!' has not been given. + +If [range] is not given, it defaults to the current line. + +By default, the columns will be righ-aligned. If you want them to be +left-aligned, set the buffer variable b:csv_arrange_leftalign = 1 for that +particular buffer, e.g. > + + :let b:csv_arrange_leftalign = 1 +< +Note, arranging the columns can be very slow on large files or many columns (see +|csv-slow| on how to increase performance for this command). To prevent you +from accidently changing your csv file, the buffer will be set 'readonly' +afterwards. Note: this command does not work for fixed width columns +|csv-fixedwidth| + +See also |csv-arrange-autocmd| on how to have vim automaticaly arrange a CSV +file upon entering it. + + *:CSVUnArrangeColumn* +3.6 UnArrangeColumn *UnArrangeColumn_CSV* +----------------- + +If you would like to undo a previous :ArrangeColumn command, you can use this +`:UnArrangeColumn` or `:CSVUnArrangeColumn` command: > + + :[range]UnArrangeColumn + +Beware, that is no exact undo of the :ArrangeColumn command, since it strips +away all leading blanks for each column. So if previously a column contained +only some blanks, this command will strip all blanks. + +If [range] is given, it defaults to the current line. + + *:CSVDeleteColumn* +3.7 DeleteColumn *DeleteColumn_CSV* +---------------- + +The command `:DeleteColumn` or `:CSVDeleteColumn` can be used to delete a specific column. > + + :DeleteColumn 2 + +will delete column 2. + +If you don't specify a column number, it will delete the column on which the +cursor is. Alternatively, you can also specify a search string. The plugin +will then delete all columns that match the pattern: > + + :DeleteColumn /foobar +< +will delete all columns where the pattern "foobar" matches. + + *:CSVInitCSV* +3.8 InitCSV *InitCSV* +----------- +Reinitialize the Plugin. Use this, if you have changed the configuration +of the plugin (see |csv-configuration| ). + + *:CSVHeader* +3.9 Header lines *Header_CSV* +---------------- +The `:Header` or `:CSVHeader` command splits the csv-buffer and adds a window, +that holds a small fraction of the csv file. This is useful, if the first line +contains some kind of a heading and you want always to display it. This works +similar to fixing a certain line at the top. As optional argument, you can +give the number of columns from the top, that shall be displayed. By default, +1 is used (You can define youre own default by setting the b:csv_headerline +variable, see |csv-header|). Use the '!' to close this window. So this > + + :Header 3 + +opens at the top a split window, that holds the first 3 lines, is fixed +and horizontally 'scrollbind'ed to the csv window and highlighted using the +CSVHeaderLine highlighting. +To close the header window, use > + + :Header! + +Note, this won't work with linebreaks in the column. + +Note also, that if you already have a horizontal header window (|VHeader_CSV|), +this command will close the horizontal Header window. This is because of a +limitation of Vim itsself, which doesn't allow to sync the scrolling between +two windows horizontally and at the same time have another window only sync +its scrolling vertically. + +Note: this command does not work for fixed width columns |csv-fixedwidth| + + *:CSVVHeader* *VHeader_CSV* +If you want a vertical header line, use `:VHeader` or `:CSVVHeader`. This works +similar to the |Header_CSV| command, except that it will open a vertical split +window with the first column always visible. It will always open the first +column in the new split window. Use the '!' to close the window. If you +specify a count, that many columns will be visible (default: the first). + +Note, this won't work with linebreaks in the column. +Note also: this command does not work for fixed width columns |csv-fixedwidth| + + + *:CSVVHeaderToggle* *:CSVHeaderToggle* + *VHeaderToggle_CSV* *HeaderToggle_CSV* +Use the `:HeaderToggle` and `:VHeaderToggle` command to toggle displaying the +horizontal or vertical header line. Alternatively, use `:CSVHeaderToggle` or +`:CSVVHeaderToggle` + + + *:CSVSort* +3.10 Sort *Sort_CSV* +--------- +The command `:Sort` or `:CSVSort` can be used to sort the csv file on a +certain column. If no range is given, is sorts the whole file. Specify the +column number to sort on as argument. Use the '!' attribute to reverse the +sort order. For example, the following command sorts line 1 til 10 on the 3 +column > + + :1,10Sort 3 + +While this command > + + :1,10Sort! 3 + +reverses the order based on column 3. + +Instead of a column, you can give the flag 'n' to have it sort numerically. +When no column number is given, it will sort by the column, on which the +cursor is currently. + + *:CSVColumn* +3.11 Copy Column *Copy_CSV* +---------------- +If you need to copy a specific column, you can use the command `:CSVColumn` or +`:Column` > + + :[N]Column [a] + +Copy column N into register a. This will copy all the values, that are +not folded-away (|csv-filter|) and skip comments. + +If you don't specify N, the column of the current cursor position is used. +If no register is given, the default register +|quotequote| is used. + + *:CSVMoveCol* +3.12 Move A Column *MoveCol_CSV* +------------------ +You can move one column to the right of another column by using the +`:CSVMoveColumn` or `:MoveColumn` command > + + :[range]MoveColumn [source] [dest] + +This moves the column number source to the right of column nr destination. If +both arguments are not given, move the column on which the cursor is to the +right of the current last column. If [range] is not given, MoveColumn moves +the entire column, otherwise, it moves the columns only for the lines within +the range, e.g. given that your first line is a header line, which you don't +want to change > + + :2,$MoveColumn 1 $ + +this would move column 1 behind the last column, while keeping the header line +as is. + + + *:CSVSumCol* +3.13 Sum of a Column *SumCol_CSV* +-------------------- +You can let Vim output the sum of a column using the `:CSVSumCol` or `:SumCol` +command > + + :[range]SumCol [nr] [/format/] + +This outputs the result of the column within the range given. If no range +is given, this will calculate the sum of the whole column. If is not +given, this calculates the sum for the column the cursor is on. Note, that the +delimiter will be stripped away from each value and also empty values won't be +considered. + +By default, Vim uses the a numerica format that uses the '.' as decimal +separator while there is no thousands separator. If youre file contains +the numbers in a different format, you can use the /format/ option to specify +a different thousands separator or a different decimal separator. The format +needs to be specified like this: + /x:y/ +where 'x' defines the thousands separator and y defines the decimal +separator and each one is optional. This means, that > + + :SumCol 1 /:,/ + +uses the default thousands separator and ',' as the decimal separator and > + + :SumCol 2 / :./ + +uses the Space as thousands separator and the '.' as decimal separator. + +Note, if you Vim is compiled without floating point number format (|+float|), +Vim will only aggregate the integer part and therefore won't use the 'y' +argument in the /format/ specifier. + +See also |csv-aggregate-functions| + + *:CSVNewRecord* +3.14 Create new Records *NewRecord_CSV* +----------------------- +If you want to create one or several records, you can use the `:NewRecord` or +`:CSVNewRecord` command: > + + :[range]NewRecord [count] + +This will create in each line given by range [count] number of new empty +records. If [range] is not specified, creates a new line below the line the +cursor is on and if count is not given, it defaults to 1. + + + *:CSVNewDelimiter* +3.15 Change the delimiter *NewDelimiter_CSV* +------------------------- +If you want to change the field delimiter of your file you can use the +`:CSVNewDelimiter` or `:NewDelimiter` command: > + + :NewDelimiter char + +This changes the field delimiter of your file to the new delimiter "char". +Note: Will remove trailing delimiters. + + *:CSVDuplicate* +3.16 Check for duplicate records *Duplicate_CSV* +-------------------------------- +If you want to check the file for duplicate records, use the command +`:Duplicate` or `:CSVDuplicate`: > + + :Duplicate columnlist +< + +Columnlist needs to be a numeric comma-separated list of all columns that you +want to check. You can also use a range like '2-5' which means the plugin +should check columns 2,3,4 and 5. + +If the plugin finds a duplicate records, it outputs its line number (but it +only does that at most 10 times). + +3.17 Normal mode commands *csv-mapping* +------------------------- +The csv filetype plugin redefines the following keys as: + + or L or W Move [count] field forwards + + or E or H Move [count] field backwards (but see |csv-mapping-H| + for the movement of H). + + or K Move [count] lines upwards within the same column + + or J Move [count] lines downwards within the same column + + Dynamically fold all lines away, that don't match + the value in the current column. See |csv-filter| + + In |Replace-mode| and |Virtual-Replace-mode| does not + create a new row, but instead moves the cursor to the + beginning of the same column, one more line below. + + Dynamically fold all lines away, that match + the value in the current column. See |csv-filter| + + Remove last item from the dynamic filter. + See |csv-filter| + + *csv-mapping-H* +Note how the mapping of 'H' differs from 'E' + +H step fields backwards but also stops at where the content of the columns +begins. + +If you look into this example (with the cursor being '|') + + aaa, bbbb,|ccc ` + +Pressing 'H' moves to + + aaa, |bbbb,ccc ` + +Pressing 'H' again moves to + + aaa,| bbbb,ccc ` + +Pressing 'H' again moves to + + |aaa, bbbb,ccc ` + +While with 'E', the cursor moves to: + + aaa,| bbbb,ccc ` + +and pressing 'E' again, it would move directly to + + |aaa, bbbb,ccc ` + +Also, the csv plugin defines these text-object: + +if Inner Field (contains everything up to the delimiter) + +af Outer Field (contains everything up to and including + the delimiter) + +Note, that the , , K and J overlap Vim's default mapping for ||, +||, |J| and |K| respectively. Therefore, this functionality has been +mapped to a sane default of J and K. If you haven't +changed the || or || variables, those the +is equival to a single backslash '\', e.g. \K would run the lookup function on +the word under the cursor and \J would join this line with the previous line. + +If you want to prevent the mapping of keys, simply set the global variable +g:csv_nomap_ to 1, e.g. to prevent mapping of in csv files, put > + + let g:csv_nomap_cr = 1 +< +into your |.vimrc|. Note, the keyname must be lower case. + + + *:CSVConvertData* *ConvertData_CSV* +3.18 Converting a CSV File *csv-convert* +-------------------------- +You can convert your CSV file to a different format with the `:ConvertData` +or `:CSVConvertData` command > + + ConvertData + +Use the the ! attribute, to convert your data without the delimiter. + +This command will interactively ask you for the definition of 3 variables. +After which it will convert your csv file into a new format, defined by those +3 variables and open the newly created file in a new window. Those 3 variables +define how the text converted. + +First, You need to define what has to be done, before converting your column +data. That is done with the "pre convert" variable. The content of this +variable will be put in front of the new document. + +Second, you define, what has to be put after the converted content of your +column data. This happens with the "post convert" variable. Basically the +contents of this variable will be put after processing the columns. + +Last, the columns need to be converted into your format. For this you can +specify a printf() format like string, that defines how your data will be +converted. You can use '%s' to specify placeholders, which will later be +replaced by the content of the actual column. + +For example, suppose you want to convert your data into HTML, then you first +call the > + + :ConvertData + +At this point, Vim will ask you for input. First, you need to specify, what +needs to be done before processing the data: + + Pre convert text: ` + +This would specify to put the HTML Header before the actual data can be +processed. If the variable g:csv_pre_convert is already defined, Vim will +already show you its' content as default value. Simply pressing Enter will use +this data. After that, Vim asks, what the end of the converted file needs to +look like: + + Post convert text:
` + +So here you are defining how to finish up the HTML file. If the variable +g:csv_post_convert is already defined, Vim will already show you its' content +as default value which you can confirm by pressing Enter. Last, you define, +how your columns need to be converted. Again, Vim asks you for how to do that: + + Converted text, use %s for column input: ` + %s%s%s + +This time, you can use '%s' expandos. They tell Vim, that they need to be +replaced by the actual content of your file. It does by going from the first +column in your file and replacing it with the corresponding %s in that order. +If there are less '%s' expandos then columns in your file, Vim will skip the +columns, that are not used. Again If the variable g:csv_convert is already +defined, Vim will already show you its' content as default value which you can +confirm by pressing Enter. + +After you hit Enter, Vim will convert your data and put it into a new window. +It may look like this: + + ` + ` + ` +
1,2,3,
2,2,4,
` + +Note, this is only a proof of concept. A better version of converting your +data to HTML is bundled with Vim (|:TOhtml|). + +But may be you want your data converted into SQL-insert statements. That could +be done like this: > + + ConvertData! +< + Pre convert text: ` + +(Leave this empty. It won't be used). + + Post convert text: Commit; ` + +After inserting the data, commit it into the database. + + Converted text, use %s for column input: ` + Insert into table foobar values ('%s', '%s', %s); ` + +Note, that the last argument is not included within single quotation marks, +since in this case the data is assumed to be integer and won't need to be +quoted for the database. + +After hitting Enter, a new Window will be opened, which might look like this: + + Insert into table foobar values('Foobar', '2', 2011); ` + Insert into table foobar values('Bar', '1', 2011); ` + Commit; ` + +Since the command was used with the bang attribute (!), the converted data +doesn't include the column delimiters. + +Now you can copy it into your database, or further manipulate it. + +3.19 Dynamic filters *csv-filter* +-------------------- +If you are on a value and only want to see lines that have the same value in +this column, you can dynamically filter the file and fold away all lines not +matching the value in the current column. To do so, simply press (Enter). +Now Vim will fold away all lines, that don't have the same value in this +particular row. Note, that leading blanks and the delimiter is removed and the +value is used literally when comparing with other values. If you press +on the value, all fields having the same value will be folded away. + +The way this is done is, that the value from the column is extracted and a +regular expression for that field is generated from it. In the end this +regular expression is used for folding the file. + +A subsequent or on another value, will add this value to the +current applied filter (this is like using the logical AND between the +currently active filter and the new value). To remove the last item from the +filter, press (backspace). If all items from the filter are removed, +folding will be disabled. + +If some command messes up the folding, you can use |zX| to have the folding +being reinitialized. + +By default, the first line is assumed to be the header and won't be folded +away. See also |csv-header|. + +If you have set the g:csv_move_folds variable and the file is modifiable, all +folded lines will be moved to the end of the file, so you can view all +non-folded lines as one consecutive area (see also |csv-move-folds|) + + *:CSVFilter* *:Filter* *Filter_CSV* +To see the active filters, you can use the `:Filter` or `:CSVFilter` command. +This will show you a small summary, of what filters are active and looks like +this: + +Nr Match Col Name Value ~ +===================================================== ` +01 - 07 Price 23.10 ` +02 + 08 Qty 10 ` + +This means, there are two filters active. The current active filter is on +column 7 (column name is Price) and all values that match 23.10 will be folded +away AND all values that don't match a value of 10 in the QTY column will also +be folded away. +When removing one item from the filter by pressing , it will always remove +the last item (highest number in NR column) from the active filter values. + +Note, that depending on your csv file and the number of filters you used, +applying the filter might actually slow down vim, because a complex regular +expression is generated that is applied by the fold expression. Look into the +@/ (|quote_/|) register to see its value. + +Use |zX| to apply the current value of your search register as filter. Use > + + :Filters! + +to reapply all values from the current active filter and fold non-matching +items away. + + *:CSVAnalyze* *Analyze_CSV* +3.20 Analyze a Column *csv-analyze* +--------------------- +If you'd like to know, how the values are distributed among a certain column, +you can use the `:CSVAnalyze` or `:Analyze` command. So > + + :Analyze 3 + +outputs the the distribution of the top 5 values in column 3. This looks like +this: + +Nr Count % Value ~ +============================= ` +01 20 50% 10 ` +02 10 25% 2 ` +03 10 25% 5 ` + +This tells you, that the the value '10' in column 3 occurs 50% of the time +(exactly 20 times) and the other 2 values '2' and '5' occur only 10 times, so +25% of the time. + + *:CSVVertFold* *VertFold_CSV* +3.21 Vertical Folding *csv-vertfold* +--------------------- +Sometimes, you want to hide away certain columns to better view only certain +columns without having to horizontally scroll. You can use the `:CSVVertFold` +or `:VertFold` command to hide certain columns: > + + :VertFold [] +< +This will hide all columns from the first until the number entered. It +currently can't hide single columns, because of the way, syntax highlighting +is used. This command uses the conceal-feature |:syn-conceal| to hide away +those columns. If no nr is given, hides all columns from the beginning till +the current column. + +Use > + :VertFold! + +to display all hidden columns again. + + *:CSVTranspose* *Transpose_CSV* +3.22 Transposing a column *csv-transpose* +------------------------- +Transposing means to exchange rows and columns. You can transpose the csv +file, using the `:CSVTranspose` or `:Transpose` : > + + :[range]Transpose +< +command. If [range] is not given, it will transpose the complete file, +otherwise it will only transpose the lines in the range given. Note, comments +will be deleted and transposing does not work with fixed-width columns. + + *:CSVTabularize* +3.23 Transforming into a table *:CSVTable* *csv-tabularize* +------------------------------ +You can also transform your csv data into a visual table, using the +`:CSVTabularize` or `:CSVTable`: > + + :CSVTabularize +< +command. This will make a frame around your csv data and substitute all +delimiters by '|', so that it will look like a table. + +e.g. consider this data: > +> +First,Second,Third ~ +10,5,2 ` +5,2,10 ` +2,10,5 ` +10,5,2 ` + +This will be transformed into: > + + |---------------------| + | First| Second| Third| + |------|-------|------| + | 10| 5| 2| + | 5| 2| 10| + | 2| 10| 5| + | 10| 5| 2| + |---------------------| + +If your Vim uses an unicode 'encoding', the plugin makes a nice table using +special unicode drawing glyphs (but it might be possible, that those chars are +not being displayed correctly, if either your terminal or the gui font doesn't +have characters for those codepoints). If you use the bang form, each row will +be separated by a line. +You can also visual select a range of lines and use :Tabularize to have only +that range converted into a nice ascii table. Else it try to use the current +paragraph and try to transform it. + +If you use the '!' bang argument, between each row, a line will be drawn. + +In csv files, you can also use the :CSVTabularize command, in different +filetypes you can use the :CSVTable command (and is available as plugin so it +will be available for non-CSV filetypes). + +Set the variable g:csv_table_leftalign=1 if you want the columns to be +leftaligned. + +Note: Each row must contain exactly as many fields as columns. + + *:CSVAddColumn* +3.24 Add new empty columns *AddColumn_CSV* +-------------------------- +If you want to add new empty columns to your file you can use the +`:CSVAddColumn` or `:AddColumn` command: > + + :[range]AddColumn [column] [count] + +By default, this works for the whole file, but you can give a different range +to which the AddColumn command applies. If no arguments are given, the new +empty column will be added after the column on which the cursor is. You can +however add as first argument the column number after which the new column +needs to be added. + +Additionally, you can also add a count number to add several columns at once +after the specified column number. You 0 for the column number, if you want to +add several columns after the current column. + + *:CSVSubstitute* +3.25 Substitute in columns *Substitute_CSV* +-------------------------- +If you want to substitute only in specific columns, you can use the +`:CSVSubstitute` or `:Substitute` command: > + + :[range]Substitute [column/]pattern/string[/flags] + +This means in the range and within the given columns replace pattern by +string. This works bascially like the |:s| command, except that you MUST use +forward slashes / to delimit the command. The optional part `[column/]` can +take either the form of an address or if you leave it out, substitution will +only happen in the current column. Additionally, you can use the `1,5/` form +to substitute within the columns 1 till 5 or you can even use `1,$` which +means to substitute in each column (so in fact this simplifies to a simple +`:s` command whithin the given range. For the use of `[/flags]` see |:s_flags| +Here are some examples: > + + :%Substitute 1,4/foobar/baz/gce + +Substitutes in the whole file in columns 1 till 4 the pattern foobar by baz +for every match ('g' flag) and asks for confirmation ('c' flag). + + :%S 3,$/(\d\+)/\1 EUR/g + +Substitutes in each column starting from the third each number and appends the +EURO suffix to it. +============================================================================== +4. CSV Configuration *csv-configuration* + +The CSV plugin tries to automatically detect the field delimiter for your +file, cause although often the file is called CSV (comma separated values), a +semicolon is actually used. The column separator is stored in the buffer-local +variable b:delimiter. This delimiter is heavily used, because you need +it to define a column. Almost all commands use this variable therefore. + +4.1 Delimiter *csv-delimiter* +------------- +To override the automatic detection of the plugin and define the separator +manually, use: > + + :let g:csv_delim=',' + +to let the comma be the delimiter. This sets the buffer local delimiter +variable b:delimiter. + +If your file does not consist of delimited columns, but rather is a fixed +width csv file, see |csv-fixedwidth| for configuring the plugin appropriately. + +If you changed the delimiter, you should reinitiliaze the plugin using +|InitCSV| + +Note: the delimiter will be used to generate a regular expression that matches +a column. Therefore, you need to escape special characters. So instead of '^' +use '\^'. + +4.2 Column *csv-column* +---------- +The definition, of what a column is, is defined as buffer-local variable +b:col. By default this variable is initialized to: > + + let b:col='\%(\%([^' . b:delimiter . ']*"[^"]*"[^' . b:delimiter . ']*' + \. b:delimiter . '\)\|\%([^' . b:delimiter . ']*\%(' . b:delimiter + \. '\|$\)\)\)' + +This should take care of quoted delimiters within a column. Those should +obviously not count as a delimiter. This regular expression is quite +complex and might not always work on some complex cases (e.g. linebreaks +within a field, see RFC4180 for some ugly cases that will probably not work +with this plugin). + +If you changed the b:delimiter variable, you need to redefine the b:col +variable, cause otherwise it will not reflect the change. To change the +variable from the comma to a semicolon, you could call in your CSV-Buffer +this command: > + + :let b:col=substitute(b:col, ',', ';', 'g') + +Check with :echo b:col, if the definition is correct afterwards. + +You can also force the plugin to use your own defined regular expression as +column. That regular expression should include the delimiter for the columns. +To define your own regular expression, set the g:csv_col variable: > + + let g:csv_col='[^,]*,' + +This defines a column as a field delimited by the comma (where no comma can be +contained inside a field), similar to how |csv-strict| works. + +You should reinitialize the plugin afterwards |InitCSV| + +4.3 Highlighting Group *csv-higroup* +---------------------- +By default the csv ftplugin uses the WildMenu highlighting Group to define how +the |HiColumn| command highlights columns. If you would like to define a +different highlighting group, you need to set this via the g:csv_hiGroup +variable. You can e.g. define it in your |.vimrc|: > + + :let g:csv_hiGroup = "IncSearch" + +You need to restart Vim, if you have changed this variable or use |InitCSV| + +The |hl-Title| highlighting is used for the Header line that is created by the +|Header_CSV| command. If you prefer a different highlighting, set the +g:csv_hiHeader variable to the prefered highlighting: > + + let g:csv_hiHeader = 'Pmenu' +< +This would set the header window to the |hl-Pmenu| highlighting, that is used +for the popup menu. To disable the custom highlighting, simply |unlet| the +variable: > + + unlet g:csv_hiHeader + +You should reinitialize the plugin afterwards |InitCSV| + +4.4 Strict Columns *csv-strict* +------------------ +The default regular expression to define a column is quite complex +(|csv-column|). This slows down the processing and makes Vim use more memory +and it could still not fit to your specific use case. + +If you know, that in your data file, the delimiter cannot be contained inside +the fields quoted or escaped, you can speed up processing (this is quite +noticeable when using the |ArrangeColumn_CSV| command) by setting the +g:csv_strict_columns variable: > + + let g:csv_strict_columns = 1 + +This would define a column as this regex: > + + let b:col = '\%([^' . b:delimiter . ']*' . b:delimiter . '\|$\)' + +Much simpler then the default column definition, isn't it? +See also |csv-column| and |csv-delimiter| + +You can disable the effect if you |unlet| the variable: > + + unlet g:csv_strict_columns + +You should reinitialize the plugin afterwards |InitCSV| + +For example when opening a CSV file you get the Error |E363|: pattern uses +more memory than 'maxmempattern'. In this case, either increase the +'maxmempattern' or set the g:csv_strict_columns variable. + + +4.5 Concealing *csv-syntax* *csv-conceal* +-------------- +The CSV plugin comes with a function to syntax highlight csv files. Basically +allt it does is highlight the columns and the header line. + +By default, the delimiter will not be displayed, if Vim supports |conceal| of +syntax items and instead draws a vertical line. If you don't want that, simply +set the g:csv_noconceal variable in your .vimrc > + + let g:csv_no_conceal = 1 + +and to disable it, simply unlet the variable > + + unlet g:csv_no_conceal + +You should reinitialize the plugin afterwards |InitCSV| +Note: You can also set the 'conceallevel' option to control how the concealed +chars will be displayed. + +If you want to customize the syntax colors, you can define your own groups. +The CSV plugin will use already defined highlighting groups, if they are +already defined, otherwise it will define its own defaults which should be +visible with 8, 16, 88 and 256 color terminals. For that it uses the +CSVColumnHeaderOdd and CSVColumnHeaderEven highlight groups for syntax +coloring the first line. All other lines get either the CSVColumnOdd or +CSVColumnEven highlighting. + +In case you want to define your own highlighting groups, you can define your +own syntax highlighting like this in your |.vimrc| > + + hi CSVColumnEven term=bold ctermbg=4 guibg=DarkBlue + hi CSVColumnOdd term=bold ctermbg=5 guibg=DarkMagenta + hi CSVColumnHeaderEven ... + hi CSVColumnHeaderOdd ... + +< +Note, these changes won't take effect, until you restart Vim. + + +4.6 Newlines *csv-newline* +------------ +RFC4180 allows newlines in double quoted strings. By default, the csv-plugin +won't recognize newlines inside fields. It is however possible to make the +plugin aware of newlines within quoted strings. To enable this, set > + + let g:csv_nl = 1 + +and to disable it again, simply unset the variable > + + unlet g:csv_nl + +It is a good idea to reinitialize the plugin afterwards |InitCSV| + +Note, this might not work correctly in all cases. The syntax highlighting +seems to change on cursor movements. This could possibly be a bug in the +syntax highlighting engine of Vim. Also, |WhatColumn_CSV| can't handle +newlines inside fields and will most certainly be wrong. + +4.7 Highlight column automatically *csv-hicol* +---------------------------------- +You can let vim automatically highlight the column on which the cursor is. +This works by defining an |CursorMoved| autocommand to always highlight the +column, when the cursor is moved in normal mode. Note, this does not update +the highlighting, if the Cursor is moved in Insert mode. To enable this, +define the g:csv_highlight_column variable like this > + + let g:csv_highlight_column = 'y' + +and to disable it again, simply unset the variable > + + unlet g:csv_highlight_column + +It is a good idea to reinitialize the plugin afterwards |InitCSV| + +4.8 Fixed width columns *csv-fixedwidth* +----------------------- +Sometimes there are no real columns, but rather the file is fixed width with +no distinct delimiters between each column. The CSV plugin allows you to +handle such virtual columns like csv columns, if you define where each column +starts. + +Note: Except for |ArrangeColumn_CSV| and the |Header_CSV| commands, all +commands work in either mode. Those two commands won't do anything in the case +of fixedwidth columns, since they don't really make sense here. + +4.8.1 Manual setup +------------------ +You can do this, by setting the buffer-local variable +b:csv_fixed_width like this > + + let b:csv_fixed_width="1,5,9,13,17,21" + +This defines that each column starts at multiples of 4. Be sure, to issue +this command in the buffer, that contains your file, otherwise, it won't +have an effect, since this is a buffer-local option (|local-option|) + +After setting this variable, you should reinitialize the plugins using +|InitCSV| + + *CSVFixed* +4.8.2 Setup using a Wizard +-------------------------- +Alternatively, you can setup the fixed width columns using the :CSVFixed +command. This provides a simple wizard to select each column. If you enter +the command: > + :CSVFixed +< +The first column will be highlighted and Vim outputs: +, , , , ... +This means, you can now use those 5 keys to configure the fixed-width columns: + + Use Cursor Left () and Cursor Right () to move the + highlighting bar. + If you press , this column will be fixed and remain + highlighted and there will be another bar, you can move using + the Cursor keys. This means this column will be considered to be + the border between 2 fixed with columns. + Abort + Press the backspace key, to remove the last column you fixed with + the key. + Use Enter to finish the wizard. This will use all fixed columns + to define the fixed width columns of your csv file. The plugin + will be initialized and syntax highlighting should appear. + +Note: This only works, if your Vim has the 'colorcolumn' option available +(This won't work with Vim < 7.3 and also not with a Vim without +syntax +feature). + + +4.9 CSV Header lines *csv-header* +-------------------- +By default, dynamic filtering |csv-filter| will not fold away the first line. +If you don't like that, you can define your header line using the variable +b:csv_fold_headerline, e.g. > + + let b:csv_headerline = 0 + +to disable, that a header line won't be folded away. If your header line +instead is on line 5, simply set this variable to 5. This also applies to the +|Header_CSV| command. + +4.10 Number format *csv-nrformat* +------------------ +When using the |SumCol_CSV| command, you can specify a certain number format +using the /x:y/ argument. You can however also configure the plugin to detect +a different number format than the default number format (which does not +support a thousands separator and uses the '.' as decimal separator). + +To specify a different thousands separator by default, use > + + let b:csv_thousands_sep = ' ' + +to have the space use as thousands separator and > + + let b:csv_decimal_sep = ',' + +to use the comma as decimal separator. + +4.11 Move folded lines *csv-move-folds* +---------------------- +If you use dynamic filters (see |csv-filter|), you can configure the plugin to +move all folded lines to the end of the file. This only happens if you set the +variable > + + let g:csv_move_folds = 1 +< +and the file is modifiable. This let's you see all non-folded records as a +consecutive area without being disrupted by folded lines. + +4.12 Using comments *csv-comments* +------------------- +Strictly speaking, in csv files there can't be any comments. You might however +still wish to comment or annotate certain sections in your file, so the CSV +plugin supports Comments. + +Be default, the CSV plugin will use the 'commentstring' setting to identify +comments. If this option includes the '%s' it will consider the part before +the '%s' as leading comment marker and the part behind it as comment +delimiter. + +You can however define your own comment marker, using the variable +g:csv_comment. Like with the 'commentstring' setting, you can use '%s' +expandos, that will denote where the actual comment text belongs. To define +your own comment string, put this in your |.vimrc| > + + :let g:csv_comment = '#' +< +Which will use the '#' sign as comment leader like in many scripting +languages. + +After setting this variable, you should reinitialize the plugins using +|InitCSV| + + *csv-foldtext* +By default, the csv plugin sets the 'foldtext' option. If you don't want this, +set the variable `g:csv_disable_fdt` in your |.vimrc| > + + :let g:csv_disable_fdt = 1 + +============================================================================== +5. Functions *CSV-Functions* + +The csv plugins also defines some functions, that can be used for scripting +when a csv file is open + +5.1 CSVPat() *CSVPat()* +------------ +CSVPat({column}[, {pattern}]) + +This function returns the pattern for the selected column. If only columns is +given, returns the regular expression used to search for the pattern '.*' in +that column (which means the content of that column). Alternatively, an +optional pattern can be given, so the return string can be directly feeded to +the |/| or |:s| command, e.g. type: > + + :s/=CSVPat(3, 'foobar')/baz + +where the means pressing Control followed by R followed by = +(see |c_CTRL-R_=|). A prompt will apear, with the '=' as the first character +on which you can enter expressions. + +In this case enter CSVPat(3, 'foobar') which returns the pattern to search for +the string 'foobar' in the third column. After you press enter, the returned +pattern will be put after the :s command so you can directly enter / and the +substitute string. + +5.2 CSVField(x,y[, orig]) *CSVField()* +------------------------- +This function returns the field at index (x,y) (starting from 1). If the +parameter orig is given, returns the column "as is" (e.g. including delimiter +and leading and trailing whitespace, otherwise that will be stripped.) + +5.3 CSVCol([name]) *CSVCol()* +------------------ +If the name parameter is given, returns the name of the column, else returns +the index of the current column, starting at 1. + +5.4 CSVSum(col, fmt, startline, endline) *CSVSum()* +---------------------------------------- +Returns the sum for column col. Uses fmt to parse number format (see +|:CSVSumCol|) startline and endline specify the lines to consider, if empty, +will be first and last line. + +============================================================================== +6. CSV Tips and Tricks *csv-tips* + +Here, there you'll find some small tips and tricks that might help when +working with CSV files. + +6.1 Statusline *csv-stl* +-------------- +Suppose you want to include the column, on which the cursor is, into your +statusline. You can do this, by defining in your .vimrc the 'statusline' like +this: > + + function MySTL() + if has("statusline") + hi User1 term=standout ctermfg=0 ctermbg=11 guifg=Black guibg=Yellow + let stl = ... + if exists("*CSV_WCol") + let csv = '%1*%{&ft=~"csv" ? CSV_WCol() : ""}%*' + else + let csv = '' + endif + return stl.csv + endif + endfunc + set stl=%!MySTL() +< + +This will draw in your statusline right aligned the current column and max +column (like 1/10), if you are inside a CSV file. The column info will be +drawn using the User1 highlighting (|hl-User1|), that has been defined in the +second line of the function. In the third line of your function, put your +desired 'statusline' settings as |expression|. Note the section starting with +'if exists(..)' guards against not having loaded the filetype plugin. + +Note: vim-airline (https://github.com/bling/vim-airline) by default supports +the csv plugin and enables a nice little csv statusline which helps for +navigating within a csv file. For details, see the Vim-Airline documentation. + + *CSV_WCol()* +The CSV_WCol() function controls, what will be output. In the simplest case, +when no argument is given, it simply returns on which column the cursor is. +This would look like '1/10' which means the cursor is on the first of 10 +columns. If you rather like to know the name of the column, simply give as +parameter to the function the string "Name". This will return the column name +as it is printed on the first line of that column. This can be adjusted, to +have the column name printed into the statusline (see |csv-stl| above) by +replacing the line > + + let csv = '%1*%{&ft=~"csv" ? CSV_WCol() : ""}%*' +< +by e.g. + + let csv = '%1*%{&ft=~"csv" ? CSV_WCol("Name") . " " . CSV_WCol() : ""}%*' + +which will output "Name 2/10" if the cursor is in the second column +which is named "Name". + +6.2 Slow CSV plugin *csv-slow* +------------------- +Processing a csv file using |ArrangeColumn_CSV| can be quite slow, because Vim +needs to calculate the width for each column and then replace each column by +itself widened by spaces to the optimal length. Unfortunately, csv files tend +to be quite big. Remember, for a file with 10,000 lines and 50 columns Vim +needs to process each cell, which accumulates to 500,000 substitutions. It +might take some time, until Vim is finished. + +You can speed up things a little bit, if you omit the '!' attribute to the +|ArrangeColumn| (but this will only work, if the width has been calculated +before, e.g. by issuing a :1ArrangeColumn command to arrange only the first +line. Additionally you can also configure how this command behaves by setting +some configuration variables. + +Also note, using dynamic filters (|csv-filter|), can slow down Vim +considerably, since they internally work with complex regular expressions, and +if you have a large file, containing many columns, you might hit a performance +penalty (especially, if you want to filter many columns). It's best to avoid +those functions if you are using a large csv file (so using strict columns +|csv-strict| might help a little and also setting 're' to 1 might also +alleviate it a little). + + +6.3 Defining custom aggregate functions *csv-aggregate-functions* +--------------------------------------- +The CSV plugin already defines the |SumCol_CSV| command, to let you calculate +the sum of all values of a certain column within a given range. This will +consider all values within the range, that are not folded away (|csv-filter|), +and also skip comments and the header lines. The delimiter will be deleted +from each field. + +But it may be, that you don't need the sum, but would rather want to have the +average of all values within a certain column. You can define your own +function and let the plugin call it for a column like this: + + 1) You define your own custom function in the after directory of your + vim runtime path |after-directory| (see also #2 below) > + + fun! My_CSV_Average(col) + let sum=0 + for item in a:col + let sum+=item + endfor + return sum/len(a:col) + endfun +< + This function takes a list as argument, and calculates the average for + all items in the list. You could also make use of Vim's |eval()| + function and write your own Product function like this > + + fun! My_CSV_Product(col) + return eval(join(a:col, '*')) + endfun +< + + 2) Now define your own custom command, that calls your custom function for + a certain column > + + command! -buffer -nargs=? -range=% AvgCol + \ :echo csv#EvalColumn(, + \ "My_CSV_Average", ,) +< + This command should best be put into a file called csv.vim and save + it into your ~/.vim/after/ftplugin/ directory. Create directories + that don't exist yet. For Windows, this would be the + $VIMRUNTIME/vimfiles/after/ftplugin directory. + + 3) Make sure, your |.vimrc| includes a filetype plugin setting like this > + + filetype plugin on +< + This should make sure, that all the necessary scripts are loaded by + Vim. + + After restarting Vim, you can now use your custom command definition + :AvgCol. Use a range, for the number of lines you want to evaluate and + optionally use an argument to specify which column you want to be + evaluated > + + :2,$AvgCol 7 +< + This will evaluate the average of column seven (assuming, line 1 is the + header line, which should not be taken into account). + +6.4 Autocommand on opening/closing files *csv-arrange-autocmd* +---------------------------------------- +If you want your CSV files to always be displayed like a table, you can +achieve this using the |ArrangeColumn_CSV| command and some autocommands. +Define these autocommands in your |.vimrc| > + + aug CSV_Editing + au! + au BufRead,BufWritePost *.csv :%ArrangeColumn + au BufWritePre *.csv :%UnArrangeColumn + aug end + +Upon Entering a csv file, Vim will visually arrange all columns and before +writing, those columns will be collapsed again. The BufWritePost autocommand +makes sure, that after the file has been written successfully, the csv file +will again be visually arranged. + +You can also simply set the variable > + + let g:csv_autocmd_arrange = 1 +< +in your vimrc and an autocmd will be installed, that visually arranges your +csv file whenever you open them for editing. Alternatively, you can restrict +this setting to files below a certain size. For example, if you only want to +enable this feature for files smaller than 1 MB, put this into your |.vimrc| > + + let g:csv_autocmd_arrange = 1 + let g:csv_autocmd_arrange_size = 1024*1024 + +Note, this is highly experimental and especially on big files, this might +slow down Vim considerably. + +6.5 Syntax error when opening a CSV file *csv-syntax-error* +---------------------------------------- +This happens usually, when the syntax script is read before the filetype +plugin, so the plugin did not have a chance to setup the column delimiter +correctly. + +The easy way to fix it, is to reverse the order of the :syntax on (|:syn-on|) +and :filetype plugin (|:filetype-plugin-on|) statements in your |.vimrc| + +Alternatively, you can simply call |InitCSV| and ignore the error. + +6.6 Calculate new columns *csv-calculate-column* +------------------------- +Suppose you have a table like this: + +Index;Value1;Value2~ +1;100;3 ` +2;20;4 ` + +And you need one more column, that is the calculated product of column 2 and +3, you can make use of the provided |CSVField()| function using a +|sub-replace-expression| of an |:s| command. In this case, you would do this: > + + :2,3s/$/\=printf("%s%.2f", b:delimiter, + (CSVField(2,line('.'))+0.0)*(CSVField(3,line('.'))+0.0/ + +Note: Enter as single line. The result will be this: > + +Index;Value1;Value2~ +1;100;3;300.00 ` +2;20;4;80.00 ` +============================================================================== +7. CSV Changelog *csv-changelog* + +0.31 Jan 15, 2015 "{{{1 +- fix that H on the very first cell, results in an endless loop + (https://github.com/chrisbra/csv.vim/issues/31, reported by lahvak, thanks!) +- fix that count for |AddColumn| did not work (according to the documentation) + (https://github.com/chrisbra/csv.vim/issues/32, reported by lahvak, thanks!) +- invalid reference to a WarningMsg() function +- WhatColumn! error, if the first line did not contain as many fields + as the line to check. +- Rename |:Table| command to |:CSVTable| ( + https://github.com/chrisbra/csv.vim/issues/33, + reported by Peter Jaros, thanks!) +- Mention to escape special characters when manually specifying the delimiter. + https://github.com/chrisbra/csv.vim/issues/35), also detect '^' as + delimiter. +- Csv fixed with columns better use '\%v' to match columns, otherwise, one + could get problems with multibyte chars +- Sorting should work better with csv fixed with patterns (could generate an + inavlide pattern before) +- Refactor GetSID() (provided by Ingo Karkat + https://github.com/chrisbra/csv.vim/pull/37, thanks!) +- New public function |CSVSum()| +- Restrict |csv-arrange-autocmd| to specific file sizes (suggested by Spencer + Boucher in https://github.com/chrisbra/csv.vim/issues/39, thanks!) +- Make |:CSVSearchInColumn| wrap pattern in '%\(..\)' pairs, so it works + correctly with '\|' atoms +- Small improvements on |:CSVTable| and |:NewDelimiter| command +- and should skip folds (like in normal Vi mode, suggested by + Kamaraju Kusuma, thanks!) + +0.30 Mar 27, 2014 {{{1 +- |:CSVSubstitute| should substitute all matches in a column, when 'g' flag is + given +- Don't override 'fdt' setting (https://github.com/chrisbra/csv.vim/issues/18, + reported by Noah Frederick, thanks!) +- Consistent Commands naming (https://github.com/chrisbra/csv.vim/issues/19, + reported by Noah Frederick, thanks!) +- New Function |CSVField()| and |CSVCol()| +- clean up function did not remove certain buffer local variables, + possible error when calling Menu function to disable CSV menu +- make |:CSVArrangeColumn| do not output the numer of substitutions happened + (suggested by Caylan Larson, thanks!) +- better cleaning up on exit, if Header windows were used +- Let |:CSVVHeader| accept a number, of how many columns to show + (suggested by Caylan Larson, thanks!) +- better error-handling for |CSVFixed| +- selection of inner/outer text objects was wrong, reported by Ingo Karkat, + thanks!) +- errors, when using |:CSVAnalyze| and there were empty attributes +- allow to left-align columns when using |:CSVArrangeColumn| +- |SumCol_CSV| did not detect negative values +- make in (Virtual-) Replace work as documented + +0.29 Aug 14, 2013 {{{1 +- setup |QuitPre| autocommand to quit cleanly in newer vims when using :Header + and :VHeader +- new |AddColumn_CSV| command +- prevent mapping of keys, if g:csv_nomap_ is set + (reported by ping) +- new |Substitute_CSV| command +- better syntax highlighting +- small speedup for |ArrangeColumn_CSV| +- 'E' did not correctly move the the previous column +- support for vim-airline added + +0.28 Dec 14, 2012 {{{1 +- new command :Table to create ascii tables for non-csv files + +0.27 Nov 21, 2012 {{{1 +- Better |CSV-Tabularize| +- Documentation update + +0.26 Jul 25, 2012 {{{1 +- Better handling of setting filetype specific options +- |CSV-Tabularize| +- fix some small errors + +0.25 May 17, 2012 {{{1 +- |SearchInColumn_CSV| should match non-greedily, patch by Matěj Korvas, +- better argument parsing for |SearchInColumn_CSV|, patch by Matěj Korvas, + thanks! +0.24 Apr 12, 2012 {{{1 +- Allow to transpose the file (|csv-transpose|, suggested by Karan Mistry, + thanks!) +- |DeleteColumn_CSV| allows to specify a search pattern and all matching + columns will be deleted (suggested by Karan Mistry, thanks!) + +0.23 Mar 25, 2012 {{{1 +- Don't error out, when creating a new file and syntax highlighting + script can't find the delimiter + (ftplugin will still give a warning, so). +- Don't pollute the search register when loading a file +- Give Warning when number format is wrong +- Don't source ftdetect several times (patch by Zhao Cai, thanks!) +- |NewDelimiter_CSV| to change the delimiter of the file +- |Duplicate_CSV| to check for duplicate records in the file +- Issue https://github.com/chrisbra/csv.vim/issues/13 fixed (missing quote, + reported by y, thanks!) +- |CSVPat()| function +- 'lz' does not work with |:silent| |:s| (patch by Sergey Khorev, thanks!) +- support comments (|csv_comment|, suggested by Peng Yu, thanks!) +0.22 Nov 08, 2011 {{{1 +- Small enhancements to |SumCol_CSV| +- :Filters! reapplys the dynamic filter +- Apply |csv-aggregate-functions| only to those values, that are + not folded away. +- |SumCol_CSV| can use a different number format (suggested by James Cole, + thanks! (also |csv-nrformat| +- Documentation updates (suggested by James Cole and Peng Yu) +- More code cleanup and error handling + https://github.com/chrisbra/csv.vim/issues/9 reported Daniel Carl, thanks! + https://github.com/chrisbra/csv.vim/issues/8 patch by Daniel Carl, thanks! +- New Command |NewRecord_CSV| (suggest by James Cole, thanks!) +- new textobjects InnerField (if) and outerField (af) which contain the field + without or with the delimiter (suggested by James Cole, thanks!) +- |csv-arrange-autocmd| to let Vim automatically visually arrange the columns + using |ArrangeColumn_CSV| +- |csv-move-folds| let Vim move folded lines to the end +- implement a Menu for graphical Vim + +0.21 Oct 06, 2011 {{{1 +- same as 0.20 (erroneously uploaded to vim.org) + +0.20 Oct 06, 2011 {{{1 + +- Implement a wizard for initializing fixed-width columns (|CSVFixed|) +- Vertical folding (|VertFold_CSV|) +- fix plugin indentation (by Daniel Karl, thanks!) +- fixed missing bang parameter for HiColumn function (by Daniel Karl, thanks!) +- fixed broken autodection of delimiter (reported by Peng Yu, thanks!) + +0.19 Sep 26, 2011 {{{1 + +- Make |:ArrangeColumn| more robust +- Link CSVDelimiter to the Conceal highlighting group for Vim's that have + +conceal feature (suggested by John Orr, thanks!) +- allow the possibility to return the Column name in the statusline |csv-stl| + (suggested by John Orr, thanks!) +- documentation updates +- Allow to dynamically add Filters, see |csv-filter| +- Also display what filters are active, see |:Filter| +- Analyze a column for the distribution of a value |csv-analyze| +- Implement UnArrangeColumn command |UnArrangeColumn_CSV| + (suggested by Daniel Karl in https://github.com/chrisbra/csv.vim/issues/7) + +0.18 Aug 30, 2011 {{{1 + +- fix small typos in documentation +- document, that 'K' and 'J' have been remapped and the originial function is + available as \K and \J +- Delimiters should not be highlighted within a column, only when used + as actual delimiters (suggested by Peng Yu, thanks!) +- Performance improvements for |:ArrangeColumn| + +0.17 Aug 16, 2011 {{{1 + +- small cosmetic changes +- small documentation updates +- fold away changelog in help file +- Document, that |DeleteColumn_CSV| deletes the column on which the cursor + is, if no column number has been specified +- Support csv fixed width columns (|csv-fixedwidth|) +- Support to interactively convert your csv file to a different + format (|csv-convert|) + +0.16 Jul 25, 2011 {{{1 + +- Sort on the range, specified (reported by Peng Yu, thanks!) +- |MoveCol_CSV| to move a column behind another column (suggested by Peng Yu, + thanks!) +- Document how to use custom functions with a column + (|csv-aggregate-functions|) +- Use g:csv_highlight_column variable, to have Vim automatically highlight the + column on which the cursor is (|csv-hicol|) +- Header/VHeader command should work better now (|Header_CSV|, |VHeader_CSV|) +- Use setreg() for setting the register for the |Column_CSV| command and make + sure it is blockwise. +- Release 0.14 was not correctly uploaded to vim.org + +0.14 Jul 20, 2011 {{{1 + +- really use g:csv_no_conceal variable (reported by Antonio Ospite, thanks!) +- Force redrawing before displaying error messages in syntax script (reported + by Antonio Ospite, thanks!) +- Make syntax highlighting work better with different terminals (Should work + now with 8, 88 and 256 color terminals, tested with linux konsole, xterm and + rxvt) (https://github.com/chrisbra/csv.vim/issues/4) +- Automatically detect '|' as field separator for csv files + +0.13 Mar 14, 2011 {{{1 + +- documentation update +- https://github.com/chrisbra/csv.vim/issues#issue/2 ('splitbelow' breaks + |Header_CSV|, fix this; thanks lespea!) +- https://github.com/chrisbra/csv.vim/issues#issue/3 ('gdefault' breaks + |ArrangeColumn_CSV|, fix this; thanks lespea!) +- https://github.com/chrisbra/csv.vim/issues#issue/1 (make syntax highlighting + more robust, thanks lespea!) +- fix some small annoying bugs +- WhatColumn! displays column name + +0.12 Feb 24, 2011 {{{1 + +- bugfix release: +- don't use |:noa| when switching between windows +- make sure, colwidth() doesn't throw an error + +0.11 Feb 24, 2011 {{{1 + +- new command |Copy_CSV| +- |Search_CSV| did not find anything in the last column if no delimiter + was given (reported by chroyer) +- |VHeader_CSV| display the first column as Header similar to how + |Header_CSV| works +- |HeaderToggle_CSV| and |VHeaderToggle_CSV| commands that toggle displaying + the header lines/columns + +0.10 Feb 23, 2011 {{{1 + +- Only conceal real delimiters +- document g:csv_no_conceal variable +- document g:csv_nl variable +- document conceal feature and syntax highlighting +- Normal mode command / work like K/J +- More robust regular expression engine, that can also handle newlines inside + quoted strings. +- Slightly adjusted syntax highlighting + +0.9 Feb 19, 2011 {{{1 + +- use conceal char depending on encoding +- Map normal mode keys also for visual/select and operator pending mode + +0.8 Feb 17, 2011 {{{1 + +- Better Error handling +- HiColumn! removes highlighting +- Enable NrColumns, that was deactivated in v.0.7 +- a ColorScheme autocommand makes sure, that the syntax highlighting is + reapplied, after changing the colorscheme. +- SearchInColumn now searches in the current column, if no column has been + specified +- A lot more documentation +- Syntax Highlighting conceales delimiter +- small performance improvements for |ArrangeColumn_CSV| + +0.7 Feb 16, 2011 {{{1 + +- Make the motion commands 'W' and 'E' work more reliable +- Document how to setup filetype plugins +- Make |WhatColumn_CSV| work more reliable (report from + http://vim.wikia.com/Script:3280) +- DeleteColumn deletes current column, if no argument given +- |ArrangeColumn_CSV| handles errors better +- Code cleanup +- Syntax highlighting +- 'H' and 'L' move forward/backwards between csv fields +- 'K' and 'J' move upwards/downwards within the same column +- |Sort_CSV| to sort on a certain column +- |csv-tips| on how to colorize the statusline + +0.6 Feb 15, 2011 {{{1 + +- Make |ArrangeColumn_CSV| work more reliable (had problems with multibyte + chars before) +- Add |Header_CSV| function +- 'W' and 'E' move forward/backwards between csv fields +- provide a file ftdetect/csv.vim to detect csv files + +0.5 Apr 20 2010 {{{1 + +- documentation update +- switched to a public repository: http://github.com/chrisbra/csv.vim +- enabled GLVS (see |GLVS|) + +0.4a Mar 11 2010 {{{1 + +- fixed documentation + +0.4 Mar 11 2010 {{{1 + +- introduce |InitCSV| +- better Error handling +- HiColumn now by default highlights the current column, if no argument is + specified. + +0.3 Oct, 28 2010 {{{1 + +- initial Version + +vim:tw=78:ts=8:ft=help:norl:et:fdm=marker:fdl=0 diff --git a/after/plugin/CSApprox.vim b/after/plugin/CSApprox.vim new file mode 100755 index 0000000..4754efa --- /dev/null +++ b/after/plugin/CSApprox.vim @@ -0,0 +1,29 @@ +" Copyright (c) 2012, Matthew J. Wozniski +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" * Redistributions of source code must retain the above copyright +" notice, this list of conditions and the following disclaimer. +" * Redistributions in binary form must reproduce the above copyright +" notice, this list of conditions and the following disclaimer in the +" documentation and/or other materials provided with the distribution. +" * The names of the contributors may not be used to endorse or promote +" products derived from this software without specific prior written +" permission. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY +" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +" The last thing to do when sourced is to run and actually fix up the colors. +if !has('gui_running') && exists(':CSApprox') + CSApprox +endif diff --git a/autoload/pathogen.vim b/autoload/pathogen.vim new file mode 100755 index 0000000..abafcae --- /dev/null +++ b/autoload/pathogen.vim @@ -0,0 +1,255 @@ +" pathogen.vim - path option manipulation +" Maintainer: Tim Pope +" Version: 2.0 + +" Install in ~/.vim/autoload (or ~\vimfiles\autoload). +" +" For management of individually installed plugins in ~/.vim/bundle (or +" ~\vimfiles\bundle), adding `call pathogen#infect()` to the top of your +" .vimrc is the only other setup necessary. +" +" The API is documented inline below. For maximum ease of reading, +" :set foldmethod=marker + +if exists("g:loaded_pathogen") || &cp + finish +endif +let g:loaded_pathogen = 1 + +" Point of entry for basic default usage. Give a directory name to invoke +" pathogen#runtime_append_all_bundles() (defaults to "bundle"), or a full path +" to invoke pathogen#runtime_prepend_subdirectories(). Afterwards, +" pathogen#cycle_filetype() is invoked. +function! pathogen#infect(...) abort " {{{1 + let source_path = a:0 ? a:1 : 'bundle' + if source_path =~# '[\\/]' + call pathogen#runtime_prepend_subdirectories(source_path) + else + call pathogen#runtime_append_all_bundles(source_path) + endif + call pathogen#cycle_filetype() + return '' +endfunction " }}}1 + +" Split a path into a list. +function! pathogen#split(path) abort " {{{1 + if type(a:path) == type([]) | return a:path | endif + let split = split(a:path,'\\\@"),'!isdirectory(v:val)')) && (!filereadable(dir.sep.'doc'.sep.'tags') || filewritable(dir.sep.'doc'.sep.'tags')) + helptags `=dir.'/doc'` + endif + endfor +endfunction " }}}1 + +command! -bar Helptags :call pathogen#helptags() + +" Like findfile(), but hardcoded to use the runtimepath. +function! pathogen#runtime_findfile(file,count) "{{{1 + let rtp = pathogen#join(1,pathogen#split(&rtp)) + let file = findfile(a:file,rtp,a:count) + if file ==# '' + return '' + else + return fnamemodify(file,':p') + endif +endfunction " }}}1 + +" Backport of fnameescape(). +function! pathogen#fnameescape(string) " {{{1 + if exists('*fnameescape') + return fnameescape(a:string) + elseif a:string ==# '-' + return '\-' + else + return substitute(escape(a:string," \t\n*?[{`$\\%#'\"|!<"),'^[+>]','\\&','') + endif +endfunction " }}}1 + +if exists(':Vedit') + finish +endif + +function! s:find(count,cmd,file,lcd) " {{{1 + let rtp = pathogen#join(1,pathogen#split(&runtimepath)) + let file = pathogen#runtime_findfile(a:file,a:count) + if file ==# '' + return "echoerr 'E345: Can''t find file \"".a:file."\" in runtimepath'" + elseif a:lcd + let path = file[0:-strlen(a:file)-2] + execute 'lcd `=path`' + return a:cmd.' '.pathogen#fnameescape(a:file) + else + return a:cmd.' '.pathogen#fnameescape(file) + endif +endfunction " }}}1 + +function! s:Findcomplete(A,L,P) " {{{1 + let sep = pathogen#separator() + let cheats = { + \'a': 'autoload', + \'d': 'doc', + \'f': 'ftplugin', + \'i': 'indent', + \'p': 'plugin', + \'s': 'syntax'} + if a:A =~# '^\w[\\/]' && has_key(cheats,a:A[0]) + let request = cheats[a:A[0]].a:A[1:-1] + else + let request = a:A + endif + let pattern = substitute(request,'/\|\'.sep,'*'.sep,'g').'*' + let found = {} + for path in pathogen#split(&runtimepath) + let path = expand(path, ':p') + let matches = split(glob(path.sep.pattern),"\n") + call map(matches,'isdirectory(v:val) ? v:val.sep : v:val') + call map(matches,'expand(v:val, ":p")[strlen(path)+1:-1]') + for match in matches + let found[match] = 1 + endfor + endfor + return sort(keys(found)) +endfunction " }}}1 + +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Ve :execute s:find(,'edit',,0) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vedit :execute s:find(,'edit',,0) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vopen :execute s:find(,'edit',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vsplit :execute s:find(,'split',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vvsplit :execute s:find(,'vsplit',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vtabedit :execute s:find(,'tabedit',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vpedit :execute s:find(,'pedit',,1) +command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vread :execute s:find(,'read',,1) + +" vim:set et sw=2: diff --git a/autoload/vim-pathogen b/autoload/vim-pathogen new file mode 160000 index 0000000..06da921 --- /dev/null +++ b/autoload/vim-pathogen @@ -0,0 +1 @@ +Subproject commit 06da921608b971fb47603671bcafdb2843992eb3 diff --git a/bundle/color_sample_pack/plugin/color_sample_pack.vim b/bundle/color_sample_pack/plugin/color_sample_pack.vim new file mode 100755 index 0000000..d2eca2e --- /dev/null +++ b/bundle/color_sample_pack/plugin/color_sample_pack.vim @@ -0,0 +1,207 @@ +" Maintainer: Robert Melton ( robert -at- robertmelton -dot- com) +" Last Change: 2012 Oct 28th + +" default schemes +amenu T&hemes.D&efault.Blue :colo blue +amenu T&hemes.D&efault.DarkBlue :colo darkblue +amenu T&hemes.D&efault.Default :colo default +amenu T&hemes.D&efault.Delek :colo delek +amenu T&hemes.D&efault.Desert :colo desert +amenu T&hemes.D&efault.ElfLord :colo elflord +amenu T&hemes.D&efault.Evening :colo evening +amenu T&hemes.D&efault.Koehler :colo koehler +amenu T&hemes.D&efault.Morning :colo morning +amenu T&hemes.D&efault.Murphy :colo murphy +amenu T&hemes.D&efault.Pablo :colo pablo +amenu T&hemes.D&efault.PeachPuff :colo peachpuff +amenu T&hemes.D&efault.Ron :colo ron +amenu T&hemes.D&efault.Shine :colo shine +amenu T&hemes.D&efault.Torte :colo torte +amenu T&hemes.-s1- : + +" New +amenu T&hemes.&New.&Dark.Wombat256 :colo wombat256 +amenu T&hemes.&New.&Dark.Wombat256mod :colo wombat256mod +amenu T&hemes.&New.&Dark.Zendnb :colo zendnb +amenu T&hemes.&New.&Dark.Vimhut :colo vimhut +amenu T&hemes.&New.&Dark.Sorcerer :colo sorcerer +amenu T&hemes.&New.&Dark.Mizore :colo mizore +amenu T&hemes.&New.&Dark.Midnight :colo midnight +amenu T&hemes.&New.&Dark.Midnight2 :colo midnight2 +amenu T&hemes.&New.&Dark.Manuscript :colo manuscript +amenu T&hemes.&New.&Dark.Luinnar :colo luinnar +amenu T&hemes.&New.&Dark.LiquidCarbon :colo liquidcarbon +amenu T&hemes.&New.&Dark.Gentooish :colo gentooish +amenu T&hemes.&New.&Dark.FU :colo fu +amenu T&hemes.&New.&Dark.Dejavu :colo dejavu +amenu T&hemes.&New.&Dark.Blackbeauty :colo blackbeauty + +amenu T&hemes.&New.&Other.Tesla :colo tesla +amenu T&hemes.&New.&Other.Solarized :colo solarized +amenu T&hemes.&New.&Other.PSClone :colo psclone +amenu T&hemes.&New.&Other.Paradox :colo paradox +amenu T&hemes.&New.&Other.Omen :colo omen +amenu T&hemes.&New.&Other.NightVision :colo nightvision +amenu T&hemes.&New.&Other.Masmed :colo masmed +amenu T&hemes.&New.&Other.Deepblue :colo deepblue +amenu T&hemes.&New.&Other.Darkburn :colo darkburn +amenu T&hemes.&New.&Other.Bigbang :colo bigbang +amenu T&hemes.&New.&Other.Astroboy :colo astroboy +amenu T&hemes.&New.&Other.Anokha :colo anokha + +amenu T&hemes.&New.&Light.Zenesque :colo zenesque +amenu T&hemes.&New.&Light.Scame :colo scame +amenu T&hemes.&New.&Light.Newspaper :colo newspaper +amenu T&hemes.&New.&Light.Montz :colo montz +amenu T&hemes.&New.&Light.MickeySoft :colo mickeysoft +amenu T&hemes.&New.&Light.MayanSmoke :colo mayansmoke +amenu T&hemes.&New.&Light.IntelliJ :colo intellij +amenu T&hemes.&New.&Light.Imperial :colo imperial +amenu T&hemes.&New.&Light.Greyhouse :colo greyhouse +amenu T&hemes.&New.&Light.Github :colo github +amenu T&hemes.&New.&Light.Gaea :colo gaea +amenu T&hemes.&New.&Light.Calmbreeze :colo calmbreeze + +" Updated +amenu T&hemes.&Updated.&Dark.DarkZ :colo darkz +amenu T&hemes.&Updated.&Dark.DesertEx :colo desertEx +amenu T&hemes.&Updated.&Dark.Earendel :colo earendel +amenu T&hemes.&Updated.&Dark.Fruity :colo fruity +amenu T&hemes.&Updated.&Dark.Jellybeans :colo jellybeans +amenu T&hemes.&Updated.&Dark.Leo :colo leo +amenu T&hemes.&Updated.&Dark.Lucius :colo lucius +amenu T&hemes.&Updated.&Dark.Matrix :colo matrix +amenu T&hemes.&Updated.&Dark.Metacosm :colo metacosm +amenu T&hemes.&Updated.&Dark.Moria :colo moria +amenu T&hemes.&Updated.&Dark.Neverness :colo neverness +amenu T&hemes.&Updated.&Dark.Railscasts :colo railscasts +amenu T&hemes.&Updated.&Dark.Synic :colo synic +amenu T&hemes.&Updated.&Dark.Vividchalk :colo vividchalk +amenu T&hemes.&Updated.&Dark.Xoria256 :colo xoria256 +amenu T&hemes.&Updated.&Dark.Zenburn :colo zenburn + +amenu T&hemes.&Updated.&Light.Biogoo :colo biogoo +amenu T&hemes.&Updated.&Light.Print_bw :colo print_bw +amenu T&hemes.&Updated.&Light.Pyte :colo pyte +amenu T&hemes.&Updated.&Light.VYLight :colo vylight + +amenu T&hemes.&Updated.&Other.Moss :colo moss +amenu T&hemes.&Updated.&Other.Peaksea :colo peaksea + +" Themepack Themes +amenu T&hemes.&Dark.Adaryn :colo adaryn +amenu T&hemes.&Dark.Adrian :colo adrian +amenu T&hemes.&Dark.Anotherdark :colo anotherdark +amenu T&hemes.&Dark.Asu1dark :colo asu1dark +amenu T&hemes.&Dark.BlackSea :colo blacksea +amenu T&hemes.&Dark.Brookstream :colo brookstream +amenu T&hemes.&Dark.Calmar256-dark :colo calmar256-dark +amenu T&hemes.&Dark.Camo :colo camo +amenu T&hemes.&Dark.Candy :colo candy +amenu T&hemes.&Dark.Candycode :colo candycode +amenu T&hemes.&Dark.Colorer :colo colorer +amenu T&hemes.&Dark.Dante :colo dante +amenu T&hemes.&Dark.Darkbone :colo darkbone +amenu T&hemes.&Dark.Darkspectrum :colo darkspectrum +amenu T&hemes.&Dark.Desert256 :colo desert256 +amenu T&hemes.&Dark.Dusk :colo dusk +amenu T&hemes.&Dark.DwBlue :colo dw_blue +amenu T&hemes.&Dark.DwCyan :colo dw_cyan +amenu T&hemes.&Dark.DwGreen :colo dw_green +amenu T&hemes.&Dark.DwOrange :colo dw_orange +amenu T&hemes.&Dark.DwPurple :colo dw_purple +amenu T&hemes.&Dark.DwRed :colo dw_red +amenu T&hemes.&Dark.DwYellow :colo dw_yellow +amenu T&hemes.&Dark.Ekvoli :colo ekvoli +amenu T&hemes.&Dark.Fnaqevan :colo fnaqevan +amenu T&hemes.&Dark.Freya :colo freya +amenu T&hemes.&Dark.Golden :colo golden +amenu T&hemes.&Dark.Herald :colo herald +amenu T&hemes.&Dark.Inkpot :colo inkpot +amenu T&hemes.&Dark.Jammy :colo jammy +amenu T&hemes.&Dark.Kellys :colo kellys +amenu T&hemes.&Dark.Lettuce :colo lettuce +amenu T&hemes.&Dark.Manxome :colo manxome +amenu T&hemes.&Dark.Maroloccio :colo maroloccio +amenu T&hemes.&Dark.Molokai :colo molokai +amenu T&hemes.&Dark.Motus :colo motus +amenu T&hemes.&Dark.Mustang :colo mustang +amenu T&hemes.&Dark.Neon :colo neon +amenu T&hemes.&Dark.Northland :colo northland +amenu T&hemes.&Dark.Oceanblack :colo oceanblack +amenu T&hemes.&Dark.Railscasts2 :colo railscasts2 +amenu T&hemes.&Dark.Rdark :colo rdark +amenu T&hemes.&Dark.Relaxedgreen :colo relaxedgreen +amenu T&hemes.&Dark.Rootwater :colo rootwater +amenu T&hemes.&Dark.Tango :colo tango +amenu T&hemes.&Dark.Tango2 :colo tango2 +amenu T&hemes.&Dark.TIRBlack :colo tir_black +amenu T&hemes.&Dark.Twilight :colo twilight +amenu T&hemes.&Dark.Two2Tango :colo two2tango +amenu T&hemes.&Dark.Vibrantink :colo vibrantink +amenu T&hemes.&Dark.Wombat :colo wombat +amenu T&hemes.&Dark.Wuye :colo wuye +amenu T&hemes.&Dark.Zmrok :colo zmrok + + +amenu T&hemes.&Light.Autumn :colo autumn +amenu T&hemes.&Light.Autumn2 :colo autumn2 +amenu T&hemes.&Light.Autumnleaf :colo autumnleaf +amenu T&hemes.&Light.Baycomb :colo baycomb +amenu T&hemes.&Light.BClear :colo bclear +amenu T&hemes.&Light.Buttercream :colo buttercream +amenu T&hemes.&Light.Calmar256-light :colo calmar256-light +amenu T&hemes.&Light.Chela_light :colo chela_light +amenu T&hemes.&Light.Dawn :colo dawn +amenu T&hemes.&Light.Eclipse :colo eclipse +amenu T&hemes.&Light.Fine_blue :colo fine_blue +amenu T&hemes.&Light.Fog :colo fog +amenu T&hemes.&Light.Fruit :colo fruit +amenu T&hemes.&Light.Habilight :colo habilight +amenu T&hemes.&Light.Impact :colo impact +amenu T&hemes.&Light.Ironman :colo ironman +amenu T&hemes.&Light.Martin_krischik :colo martin_krischik +amenu T&hemes.&Light.Nuvola :colo nuvola +amenu T&hemes.&Light.Oceanlight :colo oceanlight +amenu T&hemes.&Light.PapayaWhip :colo PapayaWhip +amenu T&hemes.&Light.Satori :colo satori +amenu T&hemes.&Light.Sienna :colo sienna +amenu T&hemes.&Light.Silent :colo silent +amenu T&hemes.&Light.Simpleandfriendly :colo simpleandfriendly +amenu T&hemes.&Light.SoSo :colo soso +amenu T&hemes.&Light.Spring :colo spring +amenu T&hemes.&Light.SummerFruit256 :colo summerfruit256 +amenu T&hemes.&Light.TAqua :colo taqua +amenu T&hemes.&Light.TCSoft :colo tcsoft +amenu T&hemes.&Light.Tolerable :colo tolerable +amenu T&hemes.&Light.Vc :colo vc +amenu T&hemes.&Light.Winter :colo winter + +amenu T&hemes.&Other.Aiseered :colo aiseered +amenu T&hemes.&Other.Aqua :colo aqua +amenu T&hemes.&Other.Astronaut :colo astronaut +amenu T&hemes.&Other.Bluegreen :colo bluegreen +amenu T&hemes.&Other.Borland :colo borland +amenu T&hemes.&Other.Breeze :colo breeze +amenu T&hemes.&Other.Chocolateliquor :colo chocolateliquor +amenu T&hemes.&Other.Clarity :colo clarity +amenu T&hemes.&Other.CleanPHP :colo cleanphp +amenu T&hemes.&Other.Darkblue2 :colo darkblue2 +amenu T&hemes.&Other.Darkslategray :colo darkslategray +amenu T&hemes.&Other.Denim :colo denim +amenu T&hemes.&Other.Guardian :colo guardian +amenu T&hemes.&Other.Marklar :colo marklar +amenu T&hemes.&Other.Navajo-night :colo navajo-night +amenu T&hemes.&Other.Navajo :colo navajo +amenu T&hemes.&Other.Night :colo night +amenu T&hemes.&Other.Nightshimmer :colo nightshimmer +amenu T&hemes.&Other.NoQuarter :colo no_quarter +amenu T&hemes.&Other.Oceandeep :colo oceandeep +amenu T&hemes.&Other.Olive :colo olive +amenu T&hemes.&Other.RobinHood :colo robinhood +amenu T&hemes.&Other.Sea :colo sea +amenu T&hemes.&Other.Settlemyer :colo settlemyer +amenu T&hemes.&Other.SoftBlue :colo softblue +amenu T&hemes.&Other.Tabula :colo tabula +amenu T&hemes.&Other.Wood :colo wood +amenu T&hemes.&Other.Xemacs :colo xemacs diff --git a/bundle/gundo/README.markdown b/bundle/gundo/README.markdown new file mode 100755 index 0000000..4adeade --- /dev/null +++ b/bundle/gundo/README.markdown @@ -0,0 +1,34 @@ + +Flattr this + +Gundo.vim is Vim plugin to visualize your Vim undo tree. + +Preview +------- + +Screencast: + +### [http://screenr.com/M9l](http://screenr.com/M9l) + +Screenshot: + +gundo + +Requirements +------------ + +* Vim 7.3+ +* Python support for Vim +* Python 2.4+ + +Installation and Usage +---------------------- + +Check out the [project site][] for installation instructions. + +[project site]: http://sjl.bitbucket.org/gundo.vim/ + +License +------- + +GPLv2+, just like Mercurial. diff --git a/bundle/gundo/autoload/gundo.py b/bundle/gundo/autoload/gundo.py new file mode 100755 index 0000000..21d66f0 --- /dev/null +++ b/bundle/gundo/autoload/gundo.py @@ -0,0 +1,577 @@ +# ============================================================================ +# File: gundo.py +# Description: vim global plugin to visualize your undo tree +# Maintainer: Steve Losh +# License: GPLv2+ -- look it up. +# Notes: Much of this code was thiefed from Mercurial, and the rest was +# heavily inspired by scratch.vim and histwin.vim. +# +# ============================================================================ + +import difflib +import itertools +import sys +import time +import vim + + +# Mercurial's graphlog code -------------------------------------------------------- +def asciiedges(seen, rev, parents): + """adds edge info to changelog DAG walk suitable for ascii()""" + if rev not in seen: + seen.append(rev) + nodeidx = seen.index(rev) + + knownparents = [] + newparents = [] + for parent in parents: + if parent in seen: + knownparents.append(parent) + else: + newparents.append(parent) + + ncols = len(seen) + seen[nodeidx:nodeidx + 1] = newparents + edges = [(nodeidx, seen.index(p)) for p in knownparents] + + if len(newparents) > 0: + edges.append((nodeidx, nodeidx)) + if len(newparents) > 1: + edges.append((nodeidx, nodeidx + 1)) + + nmorecols = len(seen) - ncols + return nodeidx, edges, ncols, nmorecols + +def get_nodeline_edges_tail( + node_index, p_node_index, n_columns, n_columns_diff, p_diff, fix_tail): + if fix_tail and n_columns_diff == p_diff and n_columns_diff != 0: + # Still going in the same non-vertical direction. + if n_columns_diff == -1: + start = max(node_index + 1, p_node_index) + tail = ["|", " "] * (start - node_index - 1) + tail.extend(["/", " "] * (n_columns - start)) + return tail + else: + return ["\\", " "] * (n_columns - node_index - 1) + else: + return ["|", " "] * (n_columns - node_index - 1) + +def draw_edges(edges, nodeline, interline): + for (start, end) in edges: + if start == end + 1: + interline[2 * end + 1] = "/" + elif start == end - 1: + interline[2 * start + 1] = "\\" + elif start == end: + interline[2 * start] = "|" + else: + nodeline[2 * end] = "+" + if start > end: + (start, end) = (end, start) + for i in range(2 * start + 1, 2 * end): + if nodeline[i] != "+": + nodeline[i] = "-" + +def fix_long_right_edges(edges): + for (i, (start, end)) in enumerate(edges): + if end > start: + edges[i] = (start, end + 1) + +def ascii(buf, state, type, char, text, coldata): + """prints an ASCII graph of the DAG + + takes the following arguments (one call per node in the graph): + + - Somewhere to keep the needed state in (init to asciistate()) + - Column of the current node in the set of ongoing edges. + - Type indicator of node data == ASCIIDATA. + - Payload: (char, lines): + - Character to use as node's symbol. + - List of lines to display as the node's text. + - Edges; a list of (col, next_col) indicating the edges between + the current node and its parents. + - Number of columns (ongoing edges) in the current revision. + - The difference between the number of columns (ongoing edges) + in the next revision and the number of columns (ongoing edges) + in the current revision. That is: -1 means one column removed; + 0 means no columns added or removed; 1 means one column added. + """ + + idx, edges, ncols, coldiff = coldata + assert -2 < coldiff < 2 + if coldiff == -1: + # Transform + # + # | | | | | | + # o | | into o---+ + # |X / |/ / + # | | | | + fix_long_right_edges(edges) + + # add_padding_line says whether to rewrite + # + # | | | | | | | | + # | o---+ into | o---+ + # | / / | | | # <--- padding line + # o | | | / / + # o | | + add_padding_line = (len(text) > 2 and coldiff == -1 and + [x for (x, y) in edges if x + 1 < y]) + + # fix_nodeline_tail says whether to rewrite + # + # | | o | | | | o | | + # | | |/ / | | |/ / + # | o | | into | o / / # <--- fixed nodeline tail + # | |/ / | |/ / + # o | | o | | + fix_nodeline_tail = len(text) <= 2 and not add_padding_line + + # nodeline is the line containing the node character (typically o) + nodeline = ["|", " "] * idx + nodeline.extend([char, " "]) + + nodeline.extend( + get_nodeline_edges_tail(idx, state[1], ncols, coldiff, + state[0], fix_nodeline_tail)) + + # shift_interline is the line containing the non-vertical + # edges between this entry and the next + shift_interline = ["|", " "] * idx + if coldiff == -1: + n_spaces = 1 + edge_ch = "/" + elif coldiff == 0: + n_spaces = 2 + edge_ch = "|" + else: + n_spaces = 3 + edge_ch = "\\" + shift_interline.extend(n_spaces * [" "]) + shift_interline.extend([edge_ch, " "] * (ncols - idx - 1)) + + # draw edges from the current node to its parents + draw_edges(edges, nodeline, shift_interline) + + # lines is the list of all graph lines to print + lines = [nodeline] + if add_padding_line: + lines.append(get_padding_line(idx, ncols, edges)) + lines.append(shift_interline) + + # make sure that there are as many graph lines as there are + # log strings + while len(text) < len(lines): + text.append("") + if len(lines) < len(text): + extra_interline = ["|", " "] * (ncols + coldiff) + while len(lines) < len(text): + lines.append(extra_interline) + + # print lines + indentation_level = max(ncols, ncols + coldiff) + for (line, logstr) in zip(lines, text): + ln = "%-*s %s" % (2 * indentation_level, "".join(line), logstr) + buf.write(ln.rstrip() + '\n') + + # ... and start over + state[0] = coldiff + state[1] = idx + +def generate(dag, edgefn, current): + seen, state = [], [0, 0] + buf = Buffer() + for node, parents in list(dag): + if node.time: + age_label = age(int(node.time)) + else: + age_label = 'Original' + line = '[%s] %s' % (node.n, age_label) + if node.n == current: + char = '@' + else: + char = 'o' + ascii(buf, state, 'C', char, [line], edgefn(seen, node, parents)) + return buf.b + + +# Mercurial age function ----------------------------------------------------------- +agescales = [("year", 3600 * 24 * 365), + ("month", 3600 * 24 * 30), + ("week", 3600 * 24 * 7), + ("day", 3600 * 24), + ("hour", 3600), + ("minute", 60), + ("second", 1)] + +def age(ts): + '''turn a timestamp into an age string.''' + + def plural(t, c): + if c == 1: + return t + return t + "s" + def fmt(t, c): + return "%d %s" % (c, plural(t, c)) + + now = time.time() + then = ts + if then > now: + return 'in the future' + + delta = max(1, int(now - then)) + if delta > agescales[0][1] * 2: + return time.strftime('%Y-%m-%d', time.gmtime(float(ts))) + + for t, s in agescales: + n = delta // s + if n >= 2 or s == 1: + return '%s ago' % fmt(t, n) + + +# Python Vim utility functions ----------------------------------------------------- +normal = lambda s: vim.command('normal %s' % s) + +MISSING_BUFFER = "Cannot find Gundo's target buffer (%s)" +MISSING_WINDOW = "Cannot find window (%s) for Gundo's target buffer (%s)" + +def _check_sanity(): + '''Check to make sure we're not crazy. + + Does the following things: + + * Make sure the target buffer still exists. + ''' + b = int(vim.eval('g:gundo_target_n')) + + if not vim.eval('bufloaded(%d)' % b): + vim.command('echo "%s"' % (MISSING_BUFFER % b)) + return False + + w = int(vim.eval('bufwinnr(%d)' % b)) + if w == -1: + vim.command('echo "%s"' % (MISSING_WINDOW % (w, b))) + return False + + return True + +def _goto_window_for_buffer(b): + w = int(vim.eval('bufwinnr(%d)' % int(b))) + vim.command('%dwincmd w' % w) + +def _goto_window_for_buffer_name(bn): + b = vim.eval('bufnr("%s")' % bn) + return _goto_window_for_buffer(b) + +def _undo_to(n): + n = int(n) + if n == 0: + vim.command('silent earlier %s' % (int(vim.eval('&undolevels')) + 1)) + else: + vim.command('silent undo %d' % n) + + +INLINE_HELP = '''\ +" Gundo for %s (%d) +" j/k - move between undo states +" p - preview diff of selected and current states +" - revert to selected state + +''' + + +# Python undo tree data structures and functions ----------------------------------- +class Buffer(object): + def __init__(self): + self.b = '' + + def write(self, s): + self.b += s + +class Node(object): + def __init__(self, n, parent, time, curhead): + self.n = int(n) + self.parent = parent + self.children = [] + self.curhead = curhead + self.time = time + +def _make_nodes(alts, nodes, parent=None): + p = parent + + for alt in alts: + curhead = 'curhead' in alt + node = Node(n=alt['seq'], parent=p, time=alt['time'], curhead=curhead) + nodes.append(node) + if alt.get('alt'): + _make_nodes(alt['alt'], nodes, p) + p = node + +def make_nodes(): + ut = vim.eval('undotree()') + entries = ut['entries'] + + root = Node(0, None, False, 0) + nodes = [] + _make_nodes(entries, nodes, root) + nodes.append(root) + nmap = dict((node.n, node) for node in nodes) + return nodes, nmap + +def changenr(nodes): + _curhead_l = list(itertools.dropwhile(lambda n: not n.curhead, nodes)) + if _curhead_l: + current = _curhead_l[0].parent.n + else: + current = int(vim.eval('changenr()')) + return current + + +# Gundo rendering ------------------------------------------------------------------ + +# Rendering utility functions +def _fmt_time(t): + return time.strftime('%Y-%m-%d %I:%M:%S %p', time.localtime(float(t))) + +def _output_preview_text(lines): + _goto_window_for_buffer_name('__Gundo_Preview__') + vim.command('setlocal modifiable') + vim.current.buffer[:] = lines + vim.command('setlocal nomodifiable') + +def _generate_preview_diff(current, node_before, node_after): + _goto_window_for_buffer(vim.eval('g:gundo_target_n')) + + if not node_after.n: # we're at the original file + before_lines = [] + + _undo_to(0) + after_lines = vim.current.buffer[:] + + before_name = 'n/a' + before_time = '' + after_name = 'Original' + after_time = '' + elif not node_before.n: # we're at a pseudo-root state + _undo_to(0) + before_lines = vim.current.buffer[:] + + _undo_to(node_after.n) + after_lines = vim.current.buffer[:] + + before_name = 'Original' + before_time = '' + after_name = node_after.n + after_time = _fmt_time(node_after.time) + else: + _undo_to(node_before.n) + before_lines = vim.current.buffer[:] + + _undo_to(node_after.n) + after_lines = vim.current.buffer[:] + + before_name = node_before.n + before_time = _fmt_time(node_before.time) + after_name = node_after.n + after_time = _fmt_time(node_after.time) + + _undo_to(current) + + return list(difflib.unified_diff(before_lines, after_lines, + before_name, after_name, + before_time, after_time)) + +def _generate_change_preview_diff(current, node_before, node_after): + _goto_window_for_buffer(vim.eval('g:gundo_target_n')) + + _undo_to(node_before.n) + before_lines = vim.current.buffer[:] + + _undo_to(node_after.n) + after_lines = vim.current.buffer[:] + + before_name = node_before.n or 'Original' + before_time = node_before.time and _fmt_time(node_before.time) or '' + after_name = node_after.n or 'Original' + after_time = node_after.time and _fmt_time(node_after.time) or '' + + _undo_to(current) + + return list(difflib.unified_diff(before_lines, after_lines, + before_name, after_name, + before_time, after_time)) + +def GundoRenderGraph(): + if not _check_sanity(): + return + + nodes, nmap = make_nodes() + + for node in nodes: + node.children = [n for n in nodes if n.parent == node] + + def walk_nodes(nodes): + for node in nodes: + if node.parent: + yield (node, [node.parent]) + else: + yield (node, []) + + dag = sorted(nodes, key=lambda n: int(n.n), reverse=True) + current = changenr(nodes) + + result = generate(walk_nodes(dag), asciiedges, current).rstrip().splitlines() + result = [' ' + l for l in result] + + target = (vim.eval('g:gundo_target_f'), int(vim.eval('g:gundo_target_n'))) + + if int(vim.eval('g:gundo_help')): + header = (INLINE_HELP % target).splitlines() + else: + header = [] + + vim.command('call s:GundoOpenGraph()') + vim.command('setlocal modifiable') + vim.current.buffer[:] = (header + result) + vim.command('setlocal nomodifiable') + + i = 1 + for line in result: + try: + line.split('[')[0].index('@') + i += 1 + break + except ValueError: + pass + i += 1 + vim.command('%d' % (i+len(header)-1)) + +def GundoRenderPreview(): + if not _check_sanity(): + return + + target_state = vim.eval('s:GundoGetTargetState()') + + # Check that there's an undo state. There may not be if we're talking about + # a buffer with no changes yet. + if target_state == None: + _goto_window_for_buffer_name('__Gundo__') + return + else: + target_state = int(target_state) + + _goto_window_for_buffer(vim.eval('g:gundo_target_n')) + + nodes, nmap = make_nodes() + current = changenr(nodes) + + node_after = nmap[target_state] + node_before = node_after.parent + + vim.command('call s:GundoOpenPreview()') + _output_preview_text(_generate_preview_diff(current, node_before, node_after)) + + _goto_window_for_buffer_name('__Gundo__') + +def GundoRenderChangePreview(): + if not _check_sanity(): + return + + target_state = vim.eval('s:GundoGetTargetState()') + + # Check that there's an undo state. There may not be if we're talking about + # a buffer with no changes yet. + if target_state == None: + _goto_window_for_buffer_name('__Gundo__') + return + else: + target_state = int(target_state) + + _goto_window_for_buffer(vim.eval('g:gundo_target_n')) + + nodes, nmap = make_nodes() + current = changenr(nodes) + + node_after = nmap[target_state] + node_before = nmap[current] + + vim.command('call s:GundoOpenPreview()') + _output_preview_text(_generate_change_preview_diff(current, node_before, node_after)) + + _goto_window_for_buffer_name('__Gundo__') + + +# Gundo undo/redo +def GundoRevert(): + if not _check_sanity(): + return + + target_n = int(vim.eval('s:GundoGetTargetState()')) + back = vim.eval('g:gundo_target_n') + + _goto_window_for_buffer(back) + _undo_to(target_n) + + vim.command('GundoRenderGraph') + _goto_window_for_buffer(back) + + if int(vim.eval('g:gundo_close_on_revert')): + vim.command('GundoToggle') + +def GundoPlayTo(): + if not _check_sanity(): + return + + target_n = int(vim.eval('s:GundoGetTargetState()')) + back = int(vim.eval('g:gundo_target_n')) + + vim.command('echo "%s"' % back) + + _goto_window_for_buffer(back) + normal('zR') + + nodes, nmap = make_nodes() + + start = nmap[changenr(nodes)] + end = nmap[target_n] + + def _walk_branch(origin, dest): + rev = origin.n < dest.n + + nodes = [] + if origin.n > dest.n: + current, final = origin, dest + else: + current, final = dest, origin + + while current.n >= final.n: + if current.n == final.n: + break + nodes.append(current) + current = current.parent + else: + return None + nodes.append(current) + + if rev: + return reversed(nodes) + else: + return nodes + + branch = _walk_branch(start, end) + + if not branch: + vim.command('unsilent echo "No path to that node from here!"') + return + + for node in branch: + _undo_to(node.n) + vim.command('GundoRenderGraph') + normal('zz') + _goto_window_for_buffer(back) + vim.command('redraw') + vim.command('sleep 60m') + +def initPythonModule(): + if sys.version_info[:2] < (2, 4): + vim.command('let s:has_supported_python = 0') diff --git a/bundle/gundo/autoload/gundo.vim b/bundle/gundo/autoload/gundo.vim new file mode 100755 index 0000000..9a9e5f9 --- /dev/null +++ b/bundle/gundo/autoload/gundo.vim @@ -0,0 +1,469 @@ +" ============================================================================ +" File: gundo.vim +" Description: vim global plugin to visualize your undo tree +" Maintainer: Steve Losh +" License: GPLv2+ -- look it up. +" Notes: Much of this code was thiefed from Mercurial, and the rest was +" heavily inspired by scratch.vim and histwin.vim. +" +" ============================================================================ + + +"{{{ Init + +if v:version < '703'"{{{ + function! s:GundoDidNotLoad() + echohl WarningMsg|echomsg "Gundo unavailable: requires Vim 7.3+"|echohl None + endfunction + command! -nargs=0 GundoToggle call s:GundoDidNotLoad() + finish +endif"}}} + +if !exists('g:gundo_width')"{{{ + let g:gundo_width = 45 +endif"}}} +if !exists('g:gundo_preview_height')"{{{ + let g:gundo_preview_height = 15 +endif"}}} +if !exists('g:gundo_preview_bottom')"{{{ + let g:gundo_preview_bottom = 0 +endif"}}} +if !exists('g:gundo_right')"{{{ + let g:gundo_right = 0 +endif"}}} +if !exists('g:gundo_help')"{{{ + let g:gundo_help = 1 +endif"}}} +if !exists("g:gundo_map_move_older")"{{{ + let g:gundo_map_move_older = 'j' +endif"}}} +if !exists("g:gundo_map_move_newer")"{{{ + let g:gundo_map_move_newer = 'k' +endif"}}} +if !exists("g:gundo_close_on_revert")"{{{ + let g:gundo_close_on_revert = 0 +endif"}}} +if !exists("g:gundo_prefer_python3")"{{{ + let g:gundo_prefer_python3 = 0 +endif"}}} +if !exists("g:gundo_auto_preview")"{{{ + let g:gundo_auto_preview = 1 +endif"}}} + +let s:has_supported_python = 0 +if g:gundo_prefer_python3 && has('python3')"{{{ + let s:has_supported_python = 2 +elseif has('python')" + let s:has_supported_python = 1 +endif + +if !s:has_supported_python + function! s:GundoDidNotLoad() + echohl WarningMsg|echomsg "Gundo requires Vim to be compiled with Python 2.4+"|echohl None + endfunction + command! -nargs=0 GundoToggle call s:GundoDidNotLoad() + finish +endif"}}} + +let s:plugin_path = escape(expand(':p:h'), '\') +"}}} + +"{{{ Gundo utility functions + +function! s:GundoGetTargetState()"{{{ + let target_line = matchstr(getline("."), '\v\[[0-9]+\]') + return matchstr(target_line, '\v[0-9]+') +endfunction"}}} + +function! s:GundoGoToWindowForBufferName(name)"{{{ + if bufwinnr(bufnr(a:name)) != -1 + exe bufwinnr(bufnr(a:name)) . "wincmd w" + return 1 + else + return 0 + endif +endfunction"}}} + +function! s:GundoIsVisible()"{{{ + if bufwinnr(bufnr("__Gundo__")) != -1 || bufwinnr(bufnr("__Gundo_Preview__")) != -1 + return 1 + else + return 0 + endif +endfunction"}}} + +function! s:GundoInlineHelpLength()"{{{ + if g:gundo_help + return 6 + else + return 0 + endif +endfunction"}}} + +"}}} + +"{{{ Gundo buffer settings + +function! s:GundoMapGraph()"{{{ + exec 'nnoremap