codekingpro/portable-devtools
115k
1" Vim syntax support file2" Maintainer: Ben Fritz <fritzophrenic@gmail.com>3" Last Change: 2024 Nov 024"5" Additional contributors:6"7" Original by Bram Moolenaar <Bram@vim.org>8" Modified by David Ne\v{c}as (Yeti) <yeti@physics.muni.cz>9" XHTML support by Panagiotis Issaris <takis@lumumba.luc.ac.be>10" Made w3 compliant by Edd Barrett <vext01@gmail.com>11" Added html_font. Edd Barrett <vext01@gmail.com>12" Progress bar based off code from "progressbar widget" plugin by13" Andreas Politz, heavily modified:14" http://www.vim.org/scripts/script.php?script_id=200615"16" See Mercurial change logs for more!17 18" Transform a file into HTML, using the current syntax highlighting.19 20" this file uses line continuations21let s:cpo_sav = &cpo22let s:ls = &ls23let s:ei_sav = &eventignore24set cpo&vim25 26" HTML filetype can take a while to load/highlight if the destination file27" already exists.28set eventignore+=FileType29 30let s:end=line('$')31 32" Font33if exists("g:html_font")34 if type(g:html_font) == type([])35 let s:htmlfont = "'".. join(g:html_font,"','") .. "', monospace"36 else37 let s:htmlfont = "'".. g:html_font .. "', monospace"38 endif39else40 let s:htmlfont = "monospace"41endif42 43let s:settings = tohtml#GetUserSettings()44 45if s:settings.use_xhtml46 let s:html5 = 047elseif s:settings.use_css && !s:settings.no_pre48 let s:html5 = 149else50 let s:html5 = 051endif52 53if !exists('s:FOLDED_ID')54 let s:FOLDED_ID = hlID("Folded") | lockvar s:FOLDED_ID55 let s:FOLD_C_ID = hlID("FoldColumn") | lockvar s:FOLD_C_ID56 let s:LINENR_ID = hlID('LineNr') | lockvar s:LINENR_ID57 let s:DIFF_D_ID = hlID("DiffDelete") | lockvar s:DIFF_D_ID58 let s:DIFF_A_ID = hlID("DiffAdd") | lockvar s:DIFF_A_ID59 let s:DIFF_C_ID = hlID("DiffChange") | lockvar s:DIFF_C_ID60 let s:DIFF_T_ID = hlID("DiffText") | lockvar s:DIFF_T_ID61 let s:CONCEAL_ID = hlID('Conceal') | lockvar s:CONCEAL_ID62endif63 64" Whitespace65if s:settings.pre_wrap66 let s:whitespace = "white-space: pre-wrap; "67else68 let s:whitespace = ""69endif70 71if !empty(s:settings.prevent_copy)72 if s:settings.no_invalid73 " User has decided they don't want invalid markup. Still works in74 " OpenOffice, and for text editors, but when pasting into Microsoft Word the75 " input elements get pasted too and they cannot be deleted (at least not76 " easily).77 let s:unselInputType = ""78 else79 " Prevent from copy-pasting the input elements into Microsoft Word where80 " they cannot be deleted easily by deliberately inserting invalid markup.81 let s:unselInputType = " type='invalid_input_type'"82 endif83endif84 85" When gui colors are not supported, we can only guess the colors.86" TODO - is this true anymore? Is there a way to ask the terminal what colors87" each number means or read them from some file?88if &termguicolors || has("gui_running")89 let s:whatterm = "gui"90else91 let s:whatterm = "cterm"92 if &t_Co == 893 let s:cterm_color = {94 \ 0: "#808080", 1: "#ff6060", 2: "#00ff00", 3: "#ffff00",95 \ 4: "#8080ff", 5: "#ff40ff", 6: "#00ffff", 7: "#ffffff"96 \ }97 else98 let s:cterm_color = {99 \ 0: "#000000", 1: "#c00000", 2: "#008000", 3: "#804000", 100 \ 4: "#0000c0", 5: "#c000c0", 6: "#008080", 7: "#c0c0c0", 101 \ 8: "#808080", 9: "#ff6060", 10: "#00ff00", 11: "#ffff00",102 \ 12: "#8080ff", 13: "#ff40ff", 14: "#00ffff", 15: "#ffffff"103 \ }104 105 " Colors for 88 and 256 come from xterm.106 if &t_Co == 88107 call extend(s:cterm_color, {108 \ 16: "#000000", 17: "#00008b", 18: "#0000cd", 19: "#0000ff",109 \ 20: "#008b00", 21: "#008b8b", 22: "#008bcd", 23: "#008bff",110 \ 24: "#00cd00", 25: "#00cd8b", 26: "#00cdcd", 27: "#00cdff",111 \ 28: "#00ff00", 29: "#00ff8b", 30: "#00ffcd", 31: "#00ffff",112 \ 32: "#8b0000", 33: "#8b008b", 34: "#8b00cd", 35: "#8b00ff",113 \ 36: "#8b8b00", 37: "#8b8b8b", 38: "#8b8bcd", 39: "#8b8bff",114 \ 40: "#8bcd00", 41: "#8bcd8b", 42: "#8bcdcd", 43: "#8bcdff",115 \ 44: "#8bff00", 45: "#8bff8b", 46: "#8bffcd", 47: "#8bffff",116 \ 48: "#cd0000", 49: "#cd008b", 50: "#cd00cd", 51: "#cd00ff",117 \ 52: "#cd8b00", 53: "#cd8b8b", 54: "#cd8bcd", 55: "#cd8bff",118 \ 56: "#cdcd00", 57: "#cdcd8b", 58: "#cdcdcd", 59: "#cdcdff",119 \ 60: "#cdff00", 61: "#cdff8b", 62: "#cdffcd", 63: "#cdffff",120 \ 64: "#ff0000"121 \ })122 call extend(s:cterm_color, {123 \ 65: "#ff008b", 66: "#ff00cd", 67: "#ff00ff", 68: "#ff8b00",124 \ 69: "#ff8b8b", 70: "#ff8bcd", 71: "#ff8bff", 72: "#ffcd00",125 \ 73: "#ffcd8b", 74: "#ffcdcd", 75: "#ffcdff", 76: "#ffff00",126 \ 77: "#ffff8b", 78: "#ffffcd", 79: "#ffffff", 80: "#2e2e2e",127 \ 81: "#5c5c5c", 82: "#737373", 83: "#8b8b8b", 84: "#a2a2a2",128 \ 85: "#b9b9b9", 86: "#d0d0d0", 87: "#e7e7e7"129 \ })130 elseif &t_Co == 256131 call extend(s:cterm_color, {132 \ 16: "#000000", 17: "#00005f", 18: "#000087", 19: "#0000af",133 \ 20: "#0000d7", 21: "#0000ff", 22: "#005f00", 23: "#005f5f",134 \ 24: "#005f87", 25: "#005faf", 26: "#005fd7", 27: "#005fff",135 \ 28: "#008700", 29: "#00875f", 30: "#008787", 31: "#0087af",136 \ 32: "#0087d7", 33: "#0087ff", 34: "#00af00", 35: "#00af5f",137 \ 36: "#00af87", 37: "#00afaf", 38: "#00afd7", 39: "#00afff",138 \ 40: "#00d700", 41: "#00d75f", 42: "#00d787", 43: "#00d7af",139 \ 44: "#00d7d7", 45: "#00d7ff", 46: "#00ff00", 47: "#00ff5f",140 \ 48: "#00ff87", 49: "#00ffaf", 50: "#00ffd7", 51: "#00ffff",141 \ 52: "#5f0000", 53: "#5f005f", 54: "#5f0087", 55: "#5f00af",142 \ 56: "#5f00d7", 57: "#5f00ff", 58: "#5f5f00", 59: "#5f5f5f",143 \ 60: "#5f5f87", 61: "#5f5faf", 62: "#5f5fd7", 63: "#5f5fff",144 \ 64: "#5f8700"145 \ })146 call extend(s:cterm_color, {147 \ 65: "#5f875f", 66: "#5f8787", 67: "#5f87af", 68: "#5f87d7",148 \ 69: "#5f87ff", 70: "#5faf00", 71: "#5faf5f", 72: "#5faf87",149 \ 73: "#5fafaf", 74: "#5fafd7", 75: "#5fafff", 76: "#5fd700",150 \ 77: "#5fd75f", 78: "#5fd787", 79: "#5fd7af", 80: "#5fd7d7",151 \ 81: "#5fd7ff", 82: "#5fff00", 83: "#5fff5f", 84: "#5fff87",152 \ 85: "#5fffaf", 86: "#5fffd7", 87: "#5fffff", 88: "#870000",153 \ 89: "#87005f", 90: "#870087", 91: "#8700af", 92: "#8700d7",154 \ 93: "#8700ff", 94: "#875f00", 95: "#875f5f", 96: "#875f87",155 \ 97: "#875faf", 98: "#875fd7", 99: "#875fff", 100: "#878700",156 \ 101: "#87875f", 102: "#878787", 103: "#8787af", 104: "#8787d7",157 \ 105: "#8787ff", 106: "#87af00", 107: "#87af5f", 108: "#87af87",158 \ 109: "#87afaf", 110: "#87afd7", 111: "#87afff", 112: "#87d700"159 \ })160 call extend(s:cterm_color, {161 \ 113: "#87d75f", 114: "#87d787", 115: "#87d7af", 116: "#87d7d7",162 \ 117: "#87d7ff", 118: "#87ff00", 119: "#87ff5f", 120: "#87ff87",163 \ 121: "#87ffaf", 122: "#87ffd7", 123: "#87ffff", 124: "#af0000",164 \ 125: "#af005f", 126: "#af0087", 127: "#af00af", 128: "#af00d7",165 \ 129: "#af00ff", 130: "#af5f00", 131: "#af5f5f", 132: "#af5f87",166 \ 133: "#af5faf", 134: "#af5fd7", 135: "#af5fff", 136: "#af8700",167 \ 137: "#af875f", 138: "#af8787", 139: "#af87af", 140: "#af87d7",168 \ 141: "#af87ff", 142: "#afaf00", 143: "#afaf5f", 144: "#afaf87",169 \ 145: "#afafaf", 146: "#afafd7", 147: "#afafff", 148: "#afd700",170 \ 149: "#afd75f", 150: "#afd787", 151: "#afd7af", 152: "#afd7d7",171 \ 153: "#afd7ff", 154: "#afff00", 155: "#afff5f", 156: "#afff87",172 \ 157: "#afffaf", 158: "#afffd7"173 \ })174 call extend(s:cterm_color, {175 \ 159: "#afffff", 160: "#d70000", 161: "#d7005f", 162: "#d70087",176 \ 163: "#d700af", 164: "#d700d7", 165: "#d700ff", 166: "#d75f00",177 \ 167: "#d75f5f", 168: "#d75f87", 169: "#d75faf", 170: "#d75fd7",178 \ 171: "#d75fff", 172: "#d78700", 173: "#d7875f", 174: "#d78787",179 \ 175: "#d787af", 176: "#d787d7", 177: "#d787ff", 178: "#d7af00",180 \ 179: "#d7af5f", 180: "#d7af87", 181: "#d7afaf", 182: "#d7afd7",181 \ 183: "#d7afff", 184: "#d7d700", 185: "#d7d75f", 186: "#d7d787",182 \ 187: "#d7d7af", 188: "#d7d7d7", 189: "#d7d7ff", 190: "#d7ff00",183 \ 191: "#d7ff5f", 192: "#d7ff87", 193: "#d7ffaf", 194: "#d7ffd7",184 \ 195: "#d7ffff", 196: "#ff0000", 197: "#ff005f", 198: "#ff0087",185 \ 199: "#ff00af", 200: "#ff00d7", 201: "#ff00ff", 202: "#ff5f00",186 \ 203: "#ff5f5f", 204: "#ff5f87"187 \ })188 call extend(s:cterm_color, {189 \ 205: "#ff5faf", 206: "#ff5fd7", 207: "#ff5fff", 208: "#ff8700",190 \ 209: "#ff875f", 210: "#ff8787", 211: "#ff87af", 212: "#ff87d7",191 \ 213: "#ff87ff", 214: "#ffaf00", 215: "#ffaf5f", 216: "#ffaf87",192 \ 217: "#ffafaf", 218: "#ffafd7", 219: "#ffafff", 220: "#ffd700",193 \ 221: "#ffd75f", 222: "#ffd787", 223: "#ffd7af", 224: "#ffd7d7",194 \ 225: "#ffd7ff", 226: "#ffff00", 227: "#ffff5f", 228: "#ffff87",195 \ 229: "#ffffaf", 230: "#ffffd7", 231: "#ffffff", 232: "#080808",196 \ 233: "#121212", 234: "#1c1c1c", 235: "#262626", 236: "#303030",197 \ 237: "#3a3a3a", 238: "#444444", 239: "#4e4e4e", 240: "#585858",198 \ 241: "#626262", 242: "#6c6c6c", 243: "#767676", 244: "#808080",199 \ 245: "#8a8a8a", 246: "#949494", 247: "#9e9e9e", 248: "#a8a8a8",200 \ 249: "#b2b2b2", 250: "#bcbcbc", 251: "#c6c6c6", 252: "#d0d0d0",201 \ 253: "#dadada", 254: "#e4e4e4", 255: "#eeeeee"202 \ })203 endif204 endif205endif206 207" Return good color specification: in GUI no transformation is done, in208" terminal return RGB values of known colors and empty string for unknown209if s:whatterm == "gui"210 function! s:HtmlColor(color)211 return a:color212 endfun213else214 function! s:HtmlColor(color)215 if has_key(s:cterm_color, a:color)216 return s:cterm_color[a:color]217 else218 return ""219 endif220 endfun221endif222 223" Find out the background and foreground color for use later224let s:fgc = s:HtmlColor(synIDattr(hlID("Normal")->synIDtrans(), "fg#", s:whatterm))225let s:bgc = s:HtmlColor(synIDattr(hlID("Normal")->synIDtrans(), "bg#", s:whatterm))226if s:fgc == ""227 let s:fgc = ( &background == "dark" ? "#ffffff" : "#000000" )228endif229if s:bgc == ""230 let s:bgc = ( &background == "dark" ? "#000000" : "#ffffff" )231endif232 233if !s:settings.use_css234 " Return opening HTML tag for given highlight id235 function! s:HtmlOpening(id, extra_attrs)236 let a = ""237 let translated_ID = synIDtrans(a:id)238 if synIDattr(translated_ID, "inverse")239 " For inverse, we always must set both colors (and exchange them)240 let x = s:HtmlColor(synIDattr(translated_ID, "fg#", s:whatterm))241 let a = a .. '<span '..a:extra_attrs..'style="background-color: ' .. ( x != "" ? x : s:fgc ) .. '">'242 let x = s:HtmlColor(synIDattr(translated_ID, "bg#", s:whatterm))243 let a = a .. '<font color="' .. ( x != "" ? x : s:bgc ) .. '">'244 else245 let x = s:HtmlColor(synIDattr(translated_ID, "bg#", s:whatterm))246 if x != ""247 let a = a .. '<span '..a:extra_attrs..'style="background-color: ' .. x .. '">'248 elseif !empty(a:extra_attrs)249 let a = a .. '<span '..a:extra_attrs..'>'250 endif251 let x = s:HtmlColor(synIDattr(translated_ID, "fg#", s:whatterm))252 if x != "" | let a = a .. '<font color="' .. x .. '">' | endif253 endif254 if synIDattr(translated_ID, "bold") | let a = a .. "<b>" | endif255 if synIDattr(translated_ID, "italic") | let a = a .. "<i>" | endif256 if synIDattr(translated_ID, "underline") | let a = a .. "<u>" | endif257 return a258 endfun259 260 " Return closing HTML tag for given highlight id261 function! s:HtmlClosing(id, has_extra_attrs)262 let a = ""263 let translated_ID = synIDtrans(a:id)264 if synIDattr(translated_ID, "underline") | let a = a .. "</u>" | endif265 if synIDattr(translated_ID, "italic") | let a = a .. "</i>" | endif266 if synIDattr(translated_ID, "bold") | let a = a .. "</b>" | endif267 if synIDattr(translated_ID, "inverse")268 let a = a .. '</font></span>'269 else270 let x = s:HtmlColor(synIDattr(translated_ID, "fg#", s:whatterm))271 if x != "" | let a = a .. '</font>' | endif272 let x = s:HtmlColor(synIDattr(translated_ID, "bg#", s:whatterm))273 if x != "" || a:has_extra_attrs | let a = a .. '</span>' | endif274 endif275 return a276 endfun277endif278 279" Use a different function for formatting based on user options. This way we280" can avoid a lot of logic during the actual execution.281"282" Build the function line by line containing only what is needed for the options283" in use for maximum code sharing with minimal branch logic for greater speed.284"285" Note, 'exec' commands do not recognize line continuations, so must concatenate286" lines rather than continue them.287if s:settings.use_css288 " save CSS to a list of rules to add to the output at the end of processing289 290 " first, get the style names we need291 let s:wrapperfunc_lines = []292 call add(s:wrapperfunc_lines, [])293 let s:wrapperfunc_lines[-1] =<< trim ENDLET294 function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, make_unselectable, unformatted)295 296 let l:style_name = synIDattr(a:style_id, "name", s:whatterm)297 ENDLET298 if &diff299 call add(s:wrapperfunc_lines, [])300 let s:wrapperfunc_lines[-1] =<< trim ENDLET301 let l:diff_style_name = synIDattr(a:diff_style_id, "name", s:whatterm)302 ENDLET303 304 " Add normal groups and diff groups to separate lists so we can order them to305 " allow diff highlight to override normal highlight306 307 " if primary style IS a diff style, grab it from the diff cache instead308 " (always succeeds because we pre-populate it)309 call add(s:wrapperfunc_lines, [])310 let s:wrapperfunc_lines[-1] =<< trim ENDLET311 312 if a:style_id == s:DIFF_D_ID || a:style_id == s:DIFF_A_ID || a:style_id == s:DIFF_C_ID || a:style_id == s:DIFF_T_ID313 let l:saved_style = get(s:diffstylelist,a:style_id)314 else315 ENDLET316 endif317 318 " get primary style info from cache or build it on the fly if not found319 call add(s:wrapperfunc_lines, [])320 let s:wrapperfunc_lines[-1] =<< trim ENDLET321 let l:saved_style = get(s:stylelist,a:style_id)322 if type(l:saved_style) == type(0)323 unlet l:saved_style324 let l:saved_style = s:CSS1(a:style_id)325 if l:saved_style != ""326 let l:saved_style = "." .. l:style_name .. " { " .. l:saved_style .. "}"327 endif328 let s:stylelist[a:style_id] = l:saved_style329 endif330 ENDLET331 if &diff332 call add(s:wrapperfunc_lines, [])333 let s:wrapperfunc_lines[-1] =<< trim ENDLET334 endif335 ENDLET336 endif337" Ignore this comment, just bypassing a highlighting issue: if338 339 " Build the wrapper tags around the text. It turns out that caching these340 " gives pretty much zero performance gain and adds a lot of logic.341 342 call add(s:wrapperfunc_lines, [])343 let s:wrapperfunc_lines[-1] =<< trim ENDLET344 345 if l:saved_style == "" && empty(a:extra_attrs)346 ENDLET347 if &diff348 call add(s:wrapperfunc_lines, [])349 let s:wrapperfunc_lines[-1] =<< trim ENDLET350 if a:diff_style_id <= 0351 ENDLET352 endif353 " no surroundings if neither primary nor diff style has any info354 call add(s:wrapperfunc_lines, [])355 let s:wrapperfunc_lines[-1] =<< trim ENDLET356 return a:text357 ENDLET358 if &diff359 " no primary style, but diff style360 call add(s:wrapperfunc_lines, [])361 let s:wrapperfunc_lines[-1] =<< trim ENDLET362 else363 return '<span class="' ..l:diff_style_name .. '">'..a:text.."</span>"364 endif365 ENDLET366 endif367 " Ignore this comment, just bypassing a highlighting issue: if368 369 " open tag for non-empty primary style370 call add(s:wrapperfunc_lines, [])371 let s:wrapperfunc_lines[-1] =<< trim ENDLET372 else373 ENDLET374 " non-empty primary style. handle either empty or non-empty diff style.375 "376 " separate the two classes by a space to apply them both if there is a diff377 " style name, unless the primary style is empty, then just use the diff style378 " name379 let s:diffstyle =380 \ (&diff ? '(a:diff_style_id <= 0 ? "" : " " .. l:diff_style_name)..'381 \ : '')382 if s:settings.prevent_copy == ""383 call add(s:wrapperfunc_lines, [])384 let s:wrapperfunc_lines[-1] =<< trim eval ENDLET385 return "<span "..a:extra_attrs..'class="' .. l:style_name ..{s:diffstyle}'">'..a:text.."</span>"386 ENDLET387 else388 389 " New method: use generated content in the CSS. The only thing needed here390 " is a span with no content, with an attribute holding the desired text.391 "392 " Old method: use an <input> element when text is unsectable. This is still393 " used in conditional comments for Internet Explorer, where the new method394 " doesn't work.395 "396 " Wrap the <input> in a <span> to allow fixing the stupid bug in some fonts397 " which cause browsers to display a 1px gap between lines when these398 " <input>s have a background color (maybe not really a bug, this isn't399 " well-defined)400 "401 " use strwidth, because we care only about how many character boxes are402 " needed to size the input, we don't care how many characters (including403 " separately counted composing chars, from strchars()) or bytes (from404 " len())the string contains. strdisplaywidth() is not needed because none of405 " the unselectable groups can contain tab characters (fold column, fold406 " text, line number).407 "408 " Note, if maxlength property needs to be added in the future, it will need409 " to use strchars(), because HTML specifies that the maxlength parameter410 " uses the number of unique codepoints for its limit.411 call add(s:wrapperfunc_lines, [])412 let s:wrapperfunc_lines[-1] =<< trim eval ENDLET413 if a:make_unselectable414 let return_span = "<span "..a:extra_attrs..'class="' .. l:style_name ..{s:diffstyle}'"'415 ENDLET416 if s:settings.use_input_for_pc !=# 'all'417 call add(s:wrapperfunc_lines, [])418 let s:wrapperfunc_lines[-1] =<< trim ENDLET419 let return_span ..= " data-" .. l:style_name .. '-content="'..a:text..'"'420 ENDLET421 endif422 call add(s:wrapperfunc_lines, [])423 let s:wrapperfunc_lines[-1] =<< trim ENDLET424 let return_span ..= '>'425 ENDLET426 if s:settings.use_input_for_pc !=# 'none'427 call add(s:wrapperfunc_lines, [])428 let s:wrapperfunc_lines[-1] =<< trim eval ENDLET429 let return_span ..= '<input'..s:unselInputType..' class="' .. l:style_name ..{s:diffstyle}'"'430 let return_span ..= ' value="'..substitute(a:unformatted,'\s\+$',"","")..'"'431 let return_span ..= " onselect='this.blur(); return false;'"432 let return_span ..= " onmousedown='this.blur(); return false;'"433 let return_span ..= " onclick='this.blur(); return false;'"434 let return_span ..= " readonly='readonly'"435 let return_span ..= ' size="'..strwidth(a:unformatted)..'"'436 let return_span ..= (s:settings.use_xhtml ? '/>' : '>')437 ENDLET438 endif439 call add(s:wrapperfunc_lines, [])440 let s:wrapperfunc_lines[-1] =<< trim eval ENDLET441 return return_span..'</span>'442 else443 return "<span "..a:extra_attrs..'class="' .. l:style_name .. {s:diffstyle}'">'..a:text.."</span>"444 endif445 ENDLET446 endif447 call add(s:wrapperfunc_lines, [])448 let s:wrapperfunc_lines[-1] =<< trim ENDLET449 endif450 endfun451 ENDLET452else453 " Non-CSS method just needs the wrapper.454 "455 " Functions used to get opening/closing automatically return null strings if456 " no styles exist.457 if &diff458 let s:wrapperfunc_lines =<< trim ENDLET459 function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2)460 if a:diff_style_id <= 0461 let l:diff_opening = s:HtmlOpening(a:diff_style_id, "")462 let l:diff_closing = s:HtmlClosing(a:diff_style_id, 0)463 else464 let l:diff_opening = ""465 let l:diff_closing = ""466 endif467 return s:HtmlOpening(a:style_id, a:extra_attrs)..l:diff_opening..a:text..l:diff_closing..s:HtmlClosing(a:style_id, !empty(a:extra_attrs))468 endfun469 ENDLET470 else471 let s:wrapperfunc_lines =<< trim ENDLET472 function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2)473 return s:HtmlOpening(a:style_id, a:extra_attrs)..a:text..s:HtmlClosing(a:style_id, !empty(a:extra_attrs))474 endfun475 ENDLET476 endif477endif478 479" create the function we built line by line above480exec join(flatten(s:wrapperfunc_lines), "\n")481 482let s:diff_mode = &diff483 484" Return HTML valid characters enclosed in a span of class style_name with485" unprintable characters expanded and double spaces replaced as necessary.486"487" TODO: eliminate unneeded logic like done for BuildStyleWrapper488function! s:HtmlFormat(text, style_id, diff_style_id, extra_attrs, make_unselectable)489 " Replace unprintable characters490 let unformatted = strtrans(a:text)491 492 let formatted = unformatted493 494 " Replace the reserved html characters495 let formatted = substitute(formatted, '&', '\&', 'g')496 let formatted = substitute(formatted, '<', '\<', 'g')497 let formatted = substitute(formatted, '>', '\>', 'g')498 let formatted = substitute(formatted, '"', '\"', 'g')499 " ' is not valid in HTML but it is in XHTML, so just use the numeric500 " reference for it instead. Needed because it could appear in quotes501 " especially if unselectable regions is turned on.502 let formatted = substitute(formatted, '"', '\'', 'g')503 504 " Replace a "form feed" character with HTML to do a page break505 " TODO: need to prevent this in unselectable areas? Probably it should never506 " BE in an unselectable area...507 let formatted = substitute(formatted, "\x0c", '<hr class="PAGE-BREAK">', 'g')508 509 " Replace double spaces, leading spaces, and trailing spaces if needed510 if ' ' != s:HtmlSpace511 let formatted = substitute(formatted, ' ', s:HtmlSpace .. s:HtmlSpace, 'g')512 let formatted = substitute(formatted, '^ ', s:HtmlSpace, 'g')513 let formatted = substitute(formatted, ' \+$', s:HtmlSpace, 'g')514 endif515 516 " Enclose in the correct format517 return s:BuildStyleWrapper(a:style_id, a:diff_style_id, a:extra_attrs, formatted, a:make_unselectable, unformatted)518endfun519 520" set up functions to call HtmlFormat in certain ways based on whether the521" element is supposed to be unselectable or not522if s:settings.prevent_copy =~# 'n'523 if s:settings.number_lines524 if s:settings.line_ids525 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)526 if a:lnr > 0527 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 'id="'..(exists('g:html_diff_win_num') ? 'W'..g:html_diff_win_num : "")..'L'..a:lnr..s:settings.id_suffix..'" ', 1)528 else529 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)530 endif531 endfun532 else533 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)534 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)535 endfun536 endif537 elseif s:settings.line_ids538 " if lines are not being numbered the only reason this function gets called539 " is to put the line IDs on each line; "text" will be empty but lnr will540 " always be non-zero, however we don't want to use the <input> because that541 " won't work as nice for empty text542 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)543 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 'id="'..(exists('g:html_diff_win_num') ? 'W'..g:html_diff_win_num : "")..'L'..a:lnr..s:settings.id_suffix..'" ', 0)544 endfun545 endif546else547 if s:settings.line_ids548 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)549 if a:lnr > 0550 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 'id="'..(exists('g:html_diff_win_num') ? 'W'..g:html_diff_win_num : "")..'L'..a:lnr..s:settings.id_suffix..'" ', 0)551 else552 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)553 endif554 endfun555 else556 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)557 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)558 endfun559 endif560endif561if s:settings.prevent_copy =~# 'd'562 function! s:HtmlFormat_d(text, style_id, diff_style_id)563 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)564 endfun565else566 function! s:HtmlFormat_d(text, style_id, diff_style_id)567 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)568 endfun569endif570if s:settings.prevent_copy =~# 'f'571 if s:settings.use_input_for_pc ==# 'none'572 " Simply space-pad to the desired width inside the generated content (note573 " that the FoldColumn definition includes a whitespace:pre rule)574 function! s:FoldColumn_build(char, len, numfill, char2, class, click)575 return "<a href='#' class='"..a:class.."' onclick='"..a:click.."' data-FoldColumn-content='".576 \ repeat(a:char, a:len)..a:char2..repeat(' ', a:numfill).577 \ "'></a>"578 endfun579 function! s:FoldColumn_fill()580 return s:HtmlFormat(repeat(' ', s:foldcolumn), s:FOLD_C_ID, 0, "", 1)581 endfun582 else583 " Note the <input> elements for fill spaces will have a single space for584 " content, to allow active cursor CSS selection to work.585 "586 " Wrap the whole thing in a span for the 1px padding workaround for gaps.587 "588 " Build the function line by line containing only what is needed for the589 " options in use for maximum code sharing with minimal branch logic for590 " greater speed.591 "592 " Note, 'exec' commands do not recognize line continuations, so must593 " concatenate lines rather than continue them.594 let s:build_fun_lines = []595 call add(s:build_fun_lines, [])596 let s:build_fun_lines[-1] =<< trim ENDLET597 function! s:FoldColumn_build(char, len, numfill, char2, class, click)598 let l:input_open = "<input readonly='readonly'"..s:unselInputType599 let l:input_open ..= " onselect='this.blur(); return false;'"600 let l:input_open ..= " onmousedown='this.blur(); "..a:click.." return false;'"601 let l:input_open ..= " onclick='return false;' size='"602 let l:input_open ..= string(a:len + (empty(a:char2) ? 0 : 1) + a:numfill) .. "' "603 let l:common_attrs = "class='FoldColumn' value='"604 let l:input_close = (s:settings.use_xhtml ? "' />" : "'>")605 let l:return_span = "<span class='"..a:class.."'>"606 let l:return_span ..= l:input_open..l:common_attrs..repeat(a:char, a:len)..(a:char2)607 let l:return_span ..= l:input_close608 ENDLET609 if s:settings.use_input_for_pc ==# 'fallback'610 call add(s:build_fun_lines, [])611 let s:build_fun_lines[-1] =<< trim ENDLET612 let l:return_span ..= "<a href='#' class='FoldColumn' onclick='"..a:click.."'"613 let l:return_span ..= " data-FoldColumn-content='"614 let l:return_span ..= repeat(a:char, a:len)..a:char2..repeat(' ', a:numfill)615 let l:return_span ..= "'></a>"616 ENDLET617 endif618 call add(s:build_fun_lines, [])619 let s:build_fun_lines[-1] =<< trim ENDLET620 let l:return_span ..= "</span>"621 return l:return_span622 endfun623 ENDLET624 " create the function we built line by line above625 exec join(flatten(s:build_fun_lines), "\n")626 627 function! s:FoldColumn_fill()628 return s:FoldColumn_build(' ', s:foldcolumn, 0, '', 'FoldColumn', '')629 endfun630 endif631else632 " For normal fold columns, simply space-pad to the desired width (note that633 " the FoldColumn definition includes a whitespace:pre rule)634 function! s:FoldColumn_build(char, len, numfill, char2, class, click)635 return "<a href='#' class='"..a:class.."' onclick='"..a:click.."'>".636 \ repeat(a:char, a:len)..a:char2..repeat(' ', a:numfill).637 \ "</a>"638 endfun639 function! s:FoldColumn_fill()640 return s:HtmlFormat(repeat(' ', s:foldcolumn), s:FOLD_C_ID, 0, "", 0)641 endfun642endif643if s:settings.prevent_copy =~# 't'644 " put an extra empty span at the end for dynamic folds, so the linebreak can645 " be surrounded. Otherwise do it as normal.646 "647 " TODO: isn't there a better way to do this, than placing it here and using a648 " substitute later?649 if s:settings.dynamic_folds650 function! s:HtmlFormat_t(text, style_id, diff_style_id)651 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1) .652 \ s:HtmlFormat("", a:style_id, 0, "", 0)653 endfun654 else655 function! s:HtmlFormat_t(text, style_id, diff_style_id)656 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)657 endfun658 endif659else660 function! s:HtmlFormat_t(text, style_id, diff_style_id)661 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)662 endfun663endif664 665" Return CSS style describing given highlight id (can be empty)666function! s:CSS1(id)667 let a = ""668 let translated_ID = synIDtrans(a:id)669 if synIDattr(translated_ID, "inverse")670 " For inverse, we always must set both colors (and exchange them)671 let x = s:HtmlColor(synIDattr(translated_ID, "bg#", s:whatterm))672 let a = a .. "color: " .. ( x != "" ? x : s:bgc ) .. "; "673 let x = s:HtmlColor(synIDattr(translated_ID, "fg#", s:whatterm))674 let a = a .. "background-color: " .. ( x != "" ? x : s:fgc ) .. "; "675 else676 let x = s:HtmlColor(synIDattr(translated_ID, "fg#", s:whatterm))677 if x != "" | let a = a .. "color: " .. x .. "; " | endif678 let x = s:HtmlColor(synIDattr(translated_ID, "bg#", s:whatterm))679 if x != ""680 let a = a .. "background-color: " .. x .. "; "681 " stupid hack because almost every browser seems to have at least one font682 " which shows 1px gaps between lines which have background683 let a = a .. "padding-bottom: 1px; "684 elseif (translated_ID == s:FOLDED_ID || translated_ID == s:LINENR_ID || translated_ID == s:FOLD_C_ID) && !empty(s:settings.prevent_copy)685 " input elements default to a different color than the rest of the page686 let a = a .. "background-color: " .. s:bgc .. "; "687 endif688 endif689 if synIDattr(translated_ID, "bold") | let a = a .. "font-weight: bold; " | endif690 if synIDattr(translated_ID, "italic") | let a = a .. "font-style: italic; " | endif691 if synIDattr(translated_ID, "underline") | let a = a .. "text-decoration: underline; " | endif692 return a693endfun694 695if s:settings.dynamic_folds696 " compares two folds as stored in our list of folds697 " A fold is "less" than another if it starts at an earlier line number,698 " or ends at a later line number, ties broken by fold level699 function! s:FoldCompare(f1, f2)700 if a:f1.firstline != a:f2.firstline701 " put it before if it starts earlier702 return a:f1.firstline - a:f2.firstline703 elseif a:f1.lastline != a:f2.lastline704 " put it before if it ends later705 return a:f2.lastline - a:f1.lastline706 else707 " if folds begin and end on the same lines, put lowest fold level first708 return a:f1.level - a:f2.level709 endif710 endfunction711 712endif713 714 715" Set some options to make it work faster.716" Don't report changes for :substitute, there will be many of them.717" Don't change other windows; turn off scroll bind temporarily718let s:old_title = &title719let s:old_icon = &icon720let s:old_et = &l:et721let s:old_bind = &l:scrollbind722let s:old_report = &report723let s:old_search = @/724let s:old_more = &more725set notitle noicon726setlocal et727set nomore728set report=1000000729setlocal noscrollbind730 731if exists(':ownsyntax') && exists('w:current_syntax')732 let s:current_syntax = w:current_syntax733elseif exists('b:current_syntax')734 let s:current_syntax = b:current_syntax735else736 let s:current_syntax = 'none'737endif738 739if s:current_syntax == ''740 let s:current_syntax = 'none'741endif742 743" If the user is sourcing this script directly then the plugin version isn't744" known because the main plugin script didn't load. In the usual case where the745" user still has the full Vim runtime installed, or has this full plugin746" installed in a package or something, then we can extract the version from the747" main plugin file at it's usual spot relative to this file. Otherwise the user748" is assembling their runtime piecemeal and we have no idea what versions of749" other files may be present so don't even try to make a guess or assume the750" presence of other specific files with specific meaning.751"752" We don't want to actually source the main plugin file here because the user753" may have a good reason not to (e.g. they define their own TOhtml command or754" something).755"756" If this seems way too complicated and convoluted, it is. Probably I should757" have put the version information in the autoload file from the start. But the758" version has been in the global variable for so long that changing it could759" break a lot of user scripts.760if exists("g:loaded_2html_plugin")761 let s:pluginversion = g:loaded_2html_plugin762else763 if !exists("g:unloaded_tohtml_plugin")764 let s:main_plugin_path = expand("<sfile>:p:h:h").."/plugin/tohtml.vim"765 if filereadable(s:main_plugin_path)766 let s:lines = readfile(s:main_plugin_path, "", 20)767 call filter(s:lines, 'v:val =~ "loaded_2html_plugin = "')768 if empty(s:lines)769 let g:unloaded_tohtml_plugin = "unknown"770 else771 let g:unloaded_tohtml_plugin = substitute(s:lines[0], '.*loaded_2html_plugin = \([''"]\)\(\%(\1\@!.\)\+\)\1', '\2', '')772 endif773 unlet s:lines774 else775 let g:unloaded_tohtml_plugin = "unknown"776 endif777 unlet s:main_plugin_path778 endif779 let s:pluginversion = g:unloaded_tohtml_plugin780endif781 782" Split window to create a buffer with the HTML file.783let s:orgbufnr = winbufnr(0)784let s:origwin_stl = &l:stl785if expand("%") == ""786 if exists('g:html_diff_win_num')787 exec 'new Untitled_win'..g:html_diff_win_num..'.'.(s:settings.use_xhtml ? 'xhtml' : 'html')788 else789 exec 'new Untitled.'..(s:settings.use_xhtml ? 'xhtml' : 'html')790 endif791else792 exec 'new %.'..(s:settings.use_xhtml ? 'xhtml' : 'html')793endif794 795" Resize the new window to very small in order to make it draw faster796let s:old_winheight = winheight(0)797let s:old_winfixheight = &l:winfixheight798if s:old_winheight > 2799 resize 1 " leave enough room to view one line at a time800 norm! G801 norm! zt802endif803setlocal winfixheight804 805let s:newwin_stl = &l:stl806 807" on the new window, set the least time-consuming fold method808let s:old_fen = &foldenable809setlocal foldmethod=manual810setlocal nofoldenable811 812let s:newwin = winnr()813let s:orgwin = bufwinnr(s:orgbufnr)814 815setlocal modifiable816%d817let s:old_paste = &paste818set paste819let s:old_magic = &magic820set magic821 822" set the fileencoding to match the charset we'll be using823let &l:fileencoding=s:settings.vim_encoding824 825" According to http://www.w3.org/TR/html4/charset.html#doc-char-set, the byte826" order mark is highly recommend on the web when using multibyte encodings. But,827" it is not a good idea to include it on UTF-8 files. Otherwise, let Vim828" determine when it is actually inserted.829if s:settings.vim_encoding == 'utf-8'830 setlocal nobomb831else832 setlocal bomb833endif834 835let s:lines = []836 837if s:settings.use_xhtml838 if s:settings.encoding != ""839 call add(s:lines, "<?xml version=\"1.0\" encoding=\"" .. s:settings.encoding .. "\"?>")840 else841 call add(s:lines, "<?xml version=\"1.0\"?>")842 endif843 let s:tag_close = ' />'844else845 let s:tag_close = '>'846endif847 848let s:HtmlSpace = ' '849let s:LeadingSpace = ' '850let s:HtmlEndline = ''851if s:settings.no_pre852 let s:HtmlEndline = '<br' .. s:tag_close853 let s:LeadingSpace = s:settings.use_xhtml ? ' ' : ' '854 let s:HtmlSpace = '\' .. s:LeadingSpace855endif856 857" HTML header, with the title and generator ;-). Left free space for the CSS,858" to be filled at the end.859if !s:settings.no_doc860 call extend(s:lines, [861 \ "<html>",862 \ "<head>"])863 " include encoding as close to the top as possible, but only if not already864 " contained in XML information (to avoid haggling over content type)865 if s:settings.encoding != "" && !s:settings.use_xhtml866 if s:html5867 call add(s:lines, '<meta charset="' .. s:settings.encoding .. '"' .. s:tag_close)868 else869 call add(s:lines, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" .. s:settings.encoding .. '"' .. s:tag_close)870 endif871 endif872 call extend(s:lines, [873 \ ("<title>"..expand("%:p:~").."</title>"),874 \ ("<meta name=\"Generator\" content=\"Vim/"..v:version/100.."."..v:version%100..'"'..s:tag_close),875 \ ("<meta name=\"plugin-version\" content=\""..s:pluginversion..'"'..s:tag_close)876 \ ])877 call add(s:lines, '<meta name="syntax" content="'..s:current_syntax..'"'..s:tag_close)878 call add(s:lines, '<meta name="settings" content="'..879 \ join(filter(keys(s:settings),'s:settings[v:val]'),',')..880 \ ',prevent_copy='..s:settings.prevent_copy..881 \ ',use_input_for_pc='..s:settings.use_input_for_pc..882 \ '"'..s:tag_close)883 call add(s:lines, '<meta name="colorscheme" content="'..884 \ (exists('g:colors_name')885 \ ? g:colors_name886 \ : 'none').. '"'..s:tag_close)887 888 if s:settings.use_css889 call extend(s:lines, [890 \ "<style" .. (s:html5 ? "" : " type=\"text/css\"") .. ">",891 \ s:settings.use_xhtml ? "" : "<!--"])892 let s:ieonly = []893 if s:settings.dynamic_folds894 if s:settings.hover_unfold895 " if we are doing hover_unfold, use css 2 with css 1 fallback for IE6896 call extend(s:lines, [897 \ ".FoldColumn { text-decoration: none; white-space: pre; }",898 \ "",899 \ "body * { margin: 0; padding: 0; }", "",900 \ ".open-fold > span.Folded { display: none; }",901 \ ".open-fold > .fulltext { display: inline; }",902 \ ".closed-fold > .fulltext { display: none; }",903 \ ".closed-fold > span.Folded { display: inline; }",904 \ "",905 \ ".open-fold > .toggle-open { display: none; }",906 \ ".open-fold > .toggle-closed { display: inline; }",907 \ ".closed-fold > .toggle-open { display: inline; }",908 \ ".closed-fold > .toggle-closed { display: none; }",909 \ "", "",910 \ '/* opening a fold while hovering won''t be supported by IE6 and other',911 \ "similar browsers, but it should fail gracefully. */",912 \ ".closed-fold:hover > .fulltext { display: inline; }",913 \ ".closed-fold:hover > .toggle-filler { display: none; }",914 \ ".closed-fold:hover > .Folded { display: none; }"])915 " TODO: IE6 is REALLY old and I can't even test it anymore. Maybe we916 " should remove this? Leave it in for now, it was working at one point,917 " and doesn't affect any modern browsers. Even newer IE versions should918 " support the above code and ignore the following.919 let s:ieonly = [920 \ "<!--[if lt IE 7]><style type=\"text/css\">",921 \ ".open-fold .fulltext { display: inline; }",922 \ ".open-fold span.Folded { display: none; }",923 \ ".open-fold .toggle-open { display: none; }",924 \ ".open-fold .toggle-closed { display: inline; }",925 \ "",926 \ ".closed-fold .fulltext { display: none; }",927 \ ".closed-fold span.Folded { display: inline; }",928 \ ".closed-fold .toggle-open { display: inline; }",929 \ ".closed-fold .toggle-closed { display: none; }",930 \ "</style>",931 \ "<![endif]-->",932 \]933 else934 " if we aren't doing hover_unfold, use CSS 1 only935 call extend(s:lines, [936 \ ".FoldColumn { text-decoration: none; white-space: pre; }",937 \ ".open-fold .fulltext { display: inline; }",938 \ ".open-fold span.Folded { display: none; }",939 \ ".open-fold .toggle-open { display: none; }",940 \ ".open-fold .toggle-closed { display: inline; }",941 \ "",942 \ ".closed-fold .fulltext { display: none; }",943 \ ".closed-fold span.Folded { display: inline; }",944 \ ".closed-fold .toggle-open { display: inline; }",945 \ ".closed-fold .toggle-closed { display: none; }",946 \])947 endif948 endif949 " else we aren't doing any dynamic folding, no need for any special rules950 951 call extend(s:lines, [952 \ s:settings.use_xhtml ? "" : '-->',953 \ "</style>",954 \])955 call extend(s:lines, s:ieonly)956 unlet s:ieonly957 endif958 959 let s:uses_script = s:settings.dynamic_folds || s:settings.line_ids960 961 " insert script tag if needed962 if s:uses_script963 call extend(s:lines, [964 \ "",965 \ "<script" .. (s:html5 ? "" : " type='text/javascript'") .. ">",966 \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])967 endif968 969 " insert javascript to toggle folds open and closed970 if s:settings.dynamic_folds971 call extend(s:lines, [972 \ "",973 \ "function toggleFold(objID)",974 \ "{",975 \ " var fold;",976 \ " fold = document.getElementById(objID);",977 \ " if (fold.className == 'closed-fold')",978 \ " {",979 \ " fold.className = 'open-fold';",980 \ " }",981 \ " else if (fold.className == 'open-fold')",982 \ " {",983 \ " fold.className = 'closed-fold';",984 \ " }",985 \ "}"986 \ ])987 endif988 989 if s:settings.line_ids990 " insert javascript to get IDs from line numbers, and to open a fold before991 " jumping to any lines contained therein992 call extend(s:lines, [993 \ "",994 \ "/* function to open any folds containing a jumped-to line before jumping to it */",995 \ "function JumpToLine()",996 \ "{",997 \ " var lineNum;",998 \ " lineNum = window.location.hash;",999 \ " lineNum = lineNum.substr(1); /* strip off '#' */",1000 \ "",1001 \ " if (lineNum.indexOf('L') == -1) {",1002 \ " lineNum = 'L'+lineNum;",1003 \ " }",1004 \ " var lineElem = document.getElementById(lineNum);"1005 \ ])1006 1007 if s:settings.dynamic_folds1008 call extend(s:lines, [1009 \ "",1010 \ " /* navigate upwards in the DOM tree to open all folds containing the line */",1011 \ " var node = lineElem;",1012 \ " while (node && node.id != 'vimCodeElement"..s:settings.id_suffix.."')",1013 \ " {",1014 \ " if (node.className == 'closed-fold')",1015 \ " {",1016 \ " node.className = 'open-fold';",1017 \ " }",1018 \ " node = node.parentNode;",1019 \ " }",1020 \ ])1021 endif1022 call extend(s:lines, [1023 \ " /* Always jump to new location even if the line was hidden inside a fold, or",1024 \ " * we corrected the raw number to a line ID.",1025 \ " */",1026 \ " if (lineElem) {",1027 \ " lineElem.scrollIntoView(true);",1028 \ " }",1029 \ " return true;",1030 \ "}",1031 \ "if ('onhashchange' in window) {",1032 \ " window.onhashchange = JumpToLine;",1033 \ "}"1034 \ ])1035 endif1036 1037 " insert script closing tag if needed1038 if s:uses_script1039 call extend(s:lines, [1040 \ '',1041 \ s:settings.use_xhtml ? '//]]>' : '-->',1042 \ "</script>"1043 \ ])1044 endif1045 1046 call extend(s:lines, ["</head>",1047 \ "<body"..(s:settings.line_ids ? " onload='JumpToLine();'" : "")..">"])1048endif1049 1050if s:settings.no_pre1051 " if we're not using CSS we use a font tag which can't have a div inside1052 if s:settings.use_css1053 call extend(s:lines, ["<div id='vimCodeElement" .. s:settings.id_suffix .. "'>"])1054 endif1055else1056 call extend(s:lines, ["<pre id='vimCodeElement" .. s:settings.id_suffix .. "'>"])1057endif1058 1059exe s:orgwin .. "wincmd w"1060 1061" caches of style data1062" initialize to include line numbers if using them1063if s:settings.number_lines1064 let s:stylelist = { s:LINENR_ID : ".LineNr { " .. s:CSS1( s:LINENR_ID ) .. "}" }1065else1066 let s:stylelist = {}1067endif1068let s:diffstylelist = {1069 \ s:DIFF_A_ID : ".DiffAdd { " .. s:CSS1( s:DIFF_A_ID ) .. "}",1070 \ s:DIFF_C_ID : ".DiffChange { " .. s:CSS1( s:DIFF_C_ID ) .. "}",1071 \ s:DIFF_D_ID : ".DiffDelete { " .. s:CSS1( s:DIFF_D_ID ) .. "}",1072 \ s:DIFF_T_ID : ".DiffText { " .. s:CSS1( s:DIFF_T_ID ) .. "}"1073 \ }1074 1075" set up progress bar in the status line1076if !s:settings.no_progress1077 " ProgressBar Indicator1078 let s:progressbar={}1079 1080 " Progressbar specific functions1081 1082 func! s:SetProgbarColor()1083 if hlID("TOhtmlProgress") != 01084 hi! link TOhtmlProgress_auto TOhtmlProgress1085 elseif hlID("TOhtmlProgress_auto")==0 ||1086 \ !exists("s:last_colors_name") || !exists("g:colors_name") ||1087 \ g:colors_name != s:last_colors_name1088 let s:last_colors_name = exists("g:colors_name") ? g:colors_name : "none"1089 1090 let l:diffatr = synIDattr(hlID("DiffDelete")->synIDtrans(), "reverse", s:whatterm) ? "fg#" : "bg#"1091 let l:stlatr = synIDattr(hlID("StatusLine")->synIDtrans(), "reverse", s:whatterm) ? "fg#" : "bg#"1092 1093 let l:progbar_color = synIDattr(hlID("DiffDelete")->synIDtrans(), l:diffatr, s:whatterm)1094 let l:stl_color = synIDattr(hlID("StatusLine")->synIDtrans(), l:stlatr, s:whatterm)1095 1096 if "" == l:progbar_color1097 let l:progbar_color = synIDattr(hlID("DiffDelete")->synIDtrans(), "reverse", s:whatterm) ? s:fgc : s:bgc1098 endif1099 if "" == l:stl_color1100 let l:stl_color = synIDattr(hlID("StatusLine")->synIDtrans(), "reverse", s:whatterm) ? s:fgc : s:bgc1101 endif1102 1103 if l:progbar_color == l:stl_color1104 if s:whatterm == 'cterm'1105 if l:progbar_color >= (&t_Co/2)1106 let l:progbar_color-=11107 else1108 let l:progbar_color+=11109 endif1110 else1111 let l:rgb = map(matchlist(l:progbar_color, '#\zs\x\x\ze\(\x\x\)\(\x\x\)')[:2], 'str2nr(v:val, 16)')1112 let l:avg = (l:rgb[0] + l:rgb[1] + l:rgb[2])/31113 if l:avg >= 1281114 let l:avg_new = l:avg1115 while l:avg - l:avg_new < 0x151116 let l:rgb = map(l:rgb, 'v:val * 3 / 4')1117 let l:avg_new = (l:rgb[0] + l:rgb[1] + l:rgb[2])/31118 endwhile1119 else1120 let l:avg_new = l:avg1121 while l:avg_new - l:avg < 0x151122 let l:rgb = map(l:rgb, 'min([max([v:val, 4]) * 5 / 4, 255])')1123 let l:avg_new = (l:rgb[0] + l:rgb[1] + l:rgb[2])/31124 endwhile1125 endif1126 let l:progbar_color = printf("#%02x%02x%02x", l:rgb[0], l:rgb[1], l:rgb[2])1127 endif1128 echomsg "diff detected progbar color set to" l:progbar_color1129 endif1130 exe "hi TOhtmlProgress_auto" s:whatterm.."bg="..l:progbar_color1131 endif1132 endfun1133 1134 func! s:ProgressBar(title, max_value, winnr)1135 let pgb=copy(s:progressbar)1136 let pgb.title = a:title..' '1137 let pgb.max_value = a:max_value1138 let pgb.winnr = a:winnr1139 let pgb.cur_value = 01140 1141 let pgb.items = { 'title' : { 'color' : 'Statusline' },1142 \'bar' : { 'color' : 'Statusline' , 'fillcolor' : 'TOhtmlProgress_auto' , 'bg' : 'Statusline' } ,1143 \'counter' : { 'color' : 'Statusline' } }1144 let pgb.last_value = 01145 let pgb.needs_redraw = 01146 " Note that you must use len(split) instead of len() if you want to use 1147 " unicode in title.1148 "1149 " Subtract 3 for spacing around the title.1150 " Subtract 4 for the percentage display.1151 " Subtract 2 for spacing before this.1152 " Subtract 2 more for the '|' on either side of the progress bar1153 let pgb.subtractedlen=len(split(pgb.title, '\zs'))+3+4+2+21154 let pgb.max_len = 01155 set laststatus=21156 return pgb1157 endfun1158 1159 " Function: progressbar.calculate_ticks() {{{11160 func! s:progressbar.calculate_ticks(pb_len)1161 if a:pb_len<=01162 let pb_len = 1001163 else1164 let pb_len = a:pb_len1165 endif1166 let self.progress_ticks = map(range(pb_len+1), "v:val * self.max_value / pb_len")1167 endfun1168 1169 "Function: progressbar.paint()1170 func! s:progressbar.paint()1171 " Recalculate widths.1172 let max_len = winwidth(self.winnr)1173 let pb_len = 01174 " always true on first call because of initial value of self.max_len1175 if max_len != self.max_len1176 let self.max_len = max_len1177 1178 " Progressbar length1179 let pb_len = max_len - self.subtractedlen1180 1181 call self.calculate_ticks(pb_len)1182 1183 let self.needs_redraw = 11184 let cur_value = 01185 let self.pb_len = pb_len1186 else1187 " start searching at the last found index to make the search for the1188 " appropriate tick value normally take 0 or 1 comparisons1189 let cur_value = self.last_value1190 let pb_len = self.pb_len1191 endif1192 1193 let cur_val_max = pb_len > 0 ? pb_len : 1001194 1195 " find the current progress bar position based on precalculated thresholds1196 while cur_value < cur_val_max && self.cur_value > self.progress_ticks[cur_value]1197 let cur_value += 11198 endwhile1199 1200 " update progress bar