1" Vim syntax support file 2" Maintainer: Ben Fritz <[email protected]> 3" Last Change: 2012 Jun 30 4" 5" Additional contributors: 6" 7" Original by Bram Moolenaar <[email protected]> 8" Modified by David Ne\v{c}as (Yeti) <[email protected]> 9" XHTML support by Panagiotis Issaris <[email protected]> 10" Made w3 compliant by Edd Barrett <[email protected]> 11" Added html_font. Edd Barrett <[email protected]> 12" Progress bar based off code from "progressbar widget" plugin by 13" Andreas Politz, heavily modified: 14" http://www.vim.org/scripts/script.php?script_id=2006 15" 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 continuations 21let s:cpo_sav = &cpo 22let s:ls = &ls 23set cpo&vim 24 25let s:end=line('$') 26 27" Font 28if exists("g:html_font") 29 let s:htmlfont = "'". g:html_font . "', monospace" 30else 31 let s:htmlfont = "monospace" 32endif 33 34let s:settings = tohtml#GetUserSettings() 35 36if !exists('s:FOLDED_ID') 37 let s:FOLDED_ID = hlID("Folded") | lockvar s:FOLDED_ID 38 let s:FOLD_C_ID = hlID("FoldColumn") | lockvar s:FOLD_C_ID 39 let s:LINENR_ID = hlID('LineNr') | lockvar s:LINENR_ID 40 let s:DIFF_D_ID = hlID("DiffDelete") | lockvar s:DIFF_D_ID 41 let s:DIFF_A_ID = hlID("DiffAdd") | lockvar s:DIFF_A_ID 42 let s:DIFF_C_ID = hlID("DiffChange") | lockvar s:DIFF_C_ID 43 let s:DIFF_T_ID = hlID("DiffText") | lockvar s:DIFF_T_ID 44 let s:CONCEAL_ID = hlID('Conceal') | lockvar s:CONCEAL_ID 45endif 46 47" Whitespace 48if s:settings.pre_wrap 49 let s:whitespace = "white-space: pre-wrap; " 50else 51 let s:whitespace = "" 52endif 53 54if !empty(s:settings.prevent_copy) 55 if s:settings.no_invalid 56 " User has decided they don't want invalid markup. Still works in 57 " OpenOffice, and for text editors, but when pasting into Microsoft Word the 58 " input elements get pasted too and they cannot be deleted (at least not 59 " easily). 60 let s:unselInputType = "" 61 else 62 " Prevent from copy-pasting the input elements into Microsoft Word where 63 " they cannot be deleted easily by deliberately inserting invalid markup. 64 let s:unselInputType = " type='invalid_input_type'" 65 endif 66endif 67 68" When not in gui we can only guess the colors. 69" TODO - is this true anymore? 70if has("gui_running") 71 let s:whatterm = "gui" 72else 73 let s:whatterm = "cterm" 74 if &t_Co == 8 75 let s:cterm_color = { 76 \ 0: "#808080", 1: "#ff6060", 2: "#00ff00", 3: "#ffff00", 77 \ 4: "#8080ff", 5: "#ff40ff", 6: "#00ffff", 7: "#ffffff" 78 \ } 79 else 80 let s:cterm_color = { 81 \ 0: "#000000", 1: "#c00000", 2: "#008000", 3: "#804000", 82 \ 4: "#0000c0", 5: "#c000c0", 6: "#008080", 7: "#c0c0c0", 83 \ 8: "#808080", 9: "#ff6060", 10: "#00ff00", 11: "#ffff00", 84 \ 12: "#8080ff", 13: "#ff40ff", 14: "#00ffff", 15: "#ffffff" 85 \ } 86 87 " Colors for 88 and 256 come from xterm. 88 if &t_Co == 88 89 call extend(s:cterm_color, { 90 \ 16: "#000000", 17: "#00008b", 18: "#0000cd", 19: "#0000ff", 91 \ 20: "#008b00", 21: "#008b8b", 22: "#008bcd", 23: "#008bff", 92 \ 24: "#00cd00", 25: "#00cd8b", 26: "#00cdcd", 27: "#00cdff", 93 \ 28: "#00ff00", 29: "#00ff8b", 30: "#00ffcd", 31: "#00ffff", 94 \ 32: "#8b0000", 33: "#8b008b", 34: "#8b00cd", 35: "#8b00ff", 95 \ 36: "#8b8b00", 37: "#8b8b8b", 38: "#8b8bcd", 39: "#8b8bff", 96 \ 40: "#8bcd00", 41: "#8bcd8b", 42: "#8bcdcd", 43: "#8bcdff", 97 \ 44: "#8bff00", 45: "#8bff8b", 46: "#8bffcd", 47: "#8bffff", 98 \ 48: "#cd0000", 49: "#cd008b", 50: "#cd00cd", 51: "#cd00ff", 99 \ 52: "#cd8b00", 53: "#cd8b8b", 54: "#cd8bcd", 55: "#cd8bff", 100 \ 56: "#cdcd00", 57: "#cdcd8b", 58: "#cdcdcd", 59: "#cdcdff", 101 \ 60: "#cdff00", 61: "#cdff8b", 62: "#cdffcd", 63: "#cdffff", 102 \ 64: "#ff0000" 103 \ }) 104 call extend(s:cterm_color, { 105 \ 65: "#ff008b", 66: "#ff00cd", 67: "#ff00ff", 68: "#ff8b00", 106 \ 69: "#ff8b8b", 70: "#ff8bcd", 71: "#ff8bff", 72: "#ffcd00", 107 \ 73: "#ffcd8b", 74: "#ffcdcd", 75: "#ffcdff", 76: "#ffff00", 108 \ 77: "#ffff8b", 78: "#ffffcd", 79: "#ffffff", 80: "#2e2e2e", 109 \ 81: "#5c5c5c", 82: "#737373", 83: "#8b8b8b", 84: "#a2a2a2", 110 \ 85: "#b9b9b9", 86: "#d0d0d0", 87: "#e7e7e7" 111 \ }) 112 elseif &t_Co == 256 113 call extend(s:cterm_color, { 114 \ 16: "#000000", 17: "#00005f", 18: "#000087", 19: "#0000af", 115 \ 20: "#0000d7", 21: "#0000ff", 22: "#005f00", 23: "#005f5f", 116 \ 24: "#005f87", 25: "#005faf", 26: "#005fd7", 27: "#005fff", 117 \ 28: "#008700", 29: "#00875f", 30: "#008787", 31: "#0087af", 118 \ 32: "#0087d7", 33: "#0087ff", 34: "#00af00", 35: "#00af5f", 119 \ 36: "#00af87", 37: "#00afaf", 38: "#00afd7", 39: "#00afff", 120 \ 40: "#00d700", 41: "#00d75f", 42: "#00d787", 43: "#00d7af", 121 \ 44: "#00d7d7", 45: "#00d7ff", 46: "#00ff00", 47: "#00ff5f", 122 \ 48: "#00ff87", 49: "#00ffaf", 50: "#00ffd7", 51: "#00ffff", 123 \ 52: "#5f0000", 53: "#5f005f", 54: "#5f0087", 55: "#5f00af", 124 \ 56: "#5f00d7", 57: "#5f00ff", 58: "#5f5f00", 59: "#5f5f5f", 125 \ 60: "#5f5f87", 61: "#5f5faf", 62: "#5f5fd7", 63: "#5f5fff", 126 \ 64: "#5f8700" 127 \ }) 128 call extend(s:cterm_color, { 129 \ 65: "#5f875f", 66: "#5f8787", 67: "#5f87af", 68: "#5f87d7", 130 \ 69: "#5f87ff", 70: "#5faf00", 71: "#5faf5f", 72: "#5faf87", 131 \ 73: "#5fafaf", 74: "#5fafd7", 75: "#5fafff", 76: "#5fd700", 132 \ 77: "#5fd75f", 78: "#5fd787", 79: "#5fd7af", 80: "#5fd7d7", 133 \ 81: "#5fd7ff", 82: "#5fff00", 83: "#5fff5f", 84: "#5fff87", 134 \ 85: "#5fffaf", 86: "#5fffd7", 87: "#5fffff", 88: "#870000", 135 \ 89: "#87005f", 90: "#870087", 91: "#8700af", 92: "#8700d7", 136 \ 93: "#8700ff", 94: "#875f00", 95: "#875f5f", 96: "#875f87", 137 \ 97: "#875faf", 98: "#875fd7", 99: "#875fff", 100: "#878700", 138 \ 101: "#87875f", 102: "#878787", 103: "#8787af", 104: "#8787d7", 139 \ 105: "#8787ff", 106: "#87af00", 107: "#87af5f", 108: "#87af87", 140 \ 109: "#87afaf", 110: "#87afd7", 111: "#87afff", 112: "#87d700" 141 \ }) 142 call extend(s:cterm_color, { 143 \ 113: "#87d75f", 114: "#87d787", 115: "#87d7af", 116: "#87d7d7", 144 \ 117: "#87d7ff", 118: "#87ff00", 119: "#87ff5f", 120: "#87ff87", 145 \ 121: "#87ffaf", 122: "#87ffd7", 123: "#87ffff", 124: "#af0000", 146 \ 125: "#af005f", 126: "#af0087", 127: "#af00af", 128: "#af00d7", 147 \ 129: "#af00ff", 130: "#af5f00", 131: "#af5f5f", 132: "#af5f87", 148 \ 133: "#af5faf", 134: "#af5fd7", 135: "#af5fff", 136: "#af8700", 149 \ 137: "#af875f", 138: "#af8787", 139: "#af87af", 140: "#af87d7", 150 \ 141: "#af87ff", 142: "#afaf00", 143: "#afaf5f", 144: "#afaf87", 151 \ 145: "#afafaf", 146: "#afafd7", 147: "#afafff", 148: "#afd700", 152 \ 149: "#afd75f", 150: "#afd787", 151: "#afd7af", 152: "#afd7d7", 153 \ 153: "#afd7ff", 154: "#afff00", 155: "#afff5f", 156: "#afff87", 154 \ 157: "#afffaf", 158: "#afffd7" 155 \ }) 156 call extend(s:cterm_color, { 157 \ 159: "#afffff", 160: "#d70000", 161: "#d7005f", 162: "#d70087", 158 \ 163: "#d700af", 164: "#d700d7", 165: "#d700ff", 166: "#d75f00", 159 \ 167: "#d75f5f", 168: "#d75f87", 169: "#d75faf", 170: "#d75fd7", 160 \ 171: "#d75fff", 172: "#d78700", 173: "#d7875f", 174: "#d78787", 161 \ 175: "#d787af", 176: "#d787d7", 177: "#d787ff", 178: "#d7af00", 162 \ 179: "#d7af5f", 180: "#d7af87", 181: "#d7afaf", 182: "#d7afd7", 163 \ 183: "#d7afff", 184: "#d7d700", 185: "#d7d75f", 186: "#d7d787", 164 \ 187: "#d7d7af", 188: "#d7d7d7", 189: "#d7d7ff", 190: "#d7ff00", 165 \ 191: "#d7ff5f", 192: "#d7ff87", 193: "#d7ffaf", 194: "#d7ffd7", 166 \ 195: "#d7ffff", 196: "#ff0000", 197: "#ff005f", 198: "#ff0087", 167 \ 199: "#ff00af", 200: "#ff00d7", 201: "#ff00ff", 202: "#ff5f00", 168 \ 203: "#ff5f5f", 204: "#ff5f87" 169 \ }) 170 call extend(s:cterm_color, { 171 \ 205: "#ff5faf", 206: "#ff5fd7", 207: "#ff5fff", 208: "#ff8700", 172 \ 209: "#ff875f", 210: "#ff8787", 211: "#ff87af", 212: "#ff87d7", 173 \ 213: "#ff87ff", 214: "#ffaf00", 215: "#ffaf5f", 216: "#ffaf87", 174 \ 217: "#ffafaf", 218: "#ffafd7", 219: "#ffafff", 220: "#ffd700", 175 \ 221: "#ffd75f", 222: "#ffd787", 223: "#ffd7af", 224: "#ffd7d7", 176 \ 225: "#ffd7ff", 226: "#ffff00", 227: "#ffff5f", 228: "#ffff87", 177 \ 229: "#ffffaf", 230: "#ffffd7", 231: "#ffffff", 232: "#080808", 178 \ 233: "#121212", 234: "#1c1c1c", 235: "#262626", 236: "#303030", 179 \ 237: "#3a3a3a", 238: "#444444", 239: "#4e4e4e", 240: "#585858", 180 \ 241: "#626262", 242: "#6c6c6c", 243: "#767676", 244: "#808080", 181 \ 245: "#8a8a8a", 246: "#949494", 247: "#9e9e9e", 248: "#a8a8a8", 182 \ 249: "#b2b2b2", 250: "#bcbcbc", 251: "#c6c6c6", 252: "#d0d0d0", 183 \ 253: "#dadada", 254: "#e4e4e4", 255: "#eeeeee" 184 \ }) 185 endif 186 endif 187endif 188 189" Return good color specification: in GUI no transformation is done, in 190" terminal return RGB values of known colors and empty string for unknown 191if s:whatterm == "gui" 192 function! s:HtmlColor(color) 193 return a:color 194 endfun 195else 196 function! s:HtmlColor(color) 197 if has_key(s:cterm_color, a:color) 198 return s:cterm_color[a:color] 199 else 200 return "" 201 endif 202 endfun 203endif 204 205" Find out the background and foreground color for use later 206let s:fgc = s:HtmlColor(synIDattr(hlID("Normal"), "fg#", s:whatterm)) 207let s:bgc = s:HtmlColor(synIDattr(hlID("Normal"), "bg#", s:whatterm)) 208if s:fgc == "" 209 let s:fgc = ( &background == "dark" ? "#ffffff" : "#000000" ) 210endif 211if s:bgc == "" 212 let s:bgc = ( &background == "dark" ? "#000000" : "#ffffff" ) 213endif 214 215if !s:settings.use_css 216 " Return opening HTML tag for given highlight id 217 function! s:HtmlOpening(id) 218 let a = "" 219 if synIDattr(a:id, "inverse") 220 " For inverse, we always must set both colors (and exchange them) 221 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) 222 let a = a . '<span style="background-color: ' . ( x != "" ? x : s:fgc ) . '">' 223 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) 224 let a = a . '<font color="' . ( x != "" ? x : s:bgc ) . '">' 225 else 226 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) 227 if x != "" | let a = a . '<span style="background-color: ' . x . '">' | endif 228 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) 229 if x != "" | let a = a . '<font color="' . x . '">' | endif 230 endif 231 if synIDattr(a:id, "bold") | let a = a . "<b>" | endif 232 if synIDattr(a:id, "italic") | let a = a . "<i>" | endif 233 if synIDattr(a:id, "underline") | let a = a . "<u>" | endif 234 return a 235 endfun 236 237 " Return closing HTML tag for given highlight id 238 function! s:HtmlClosing(id) 239 let a = "" 240 if synIDattr(a:id, "underline") | let a = a . "</u>" | endif 241 if synIDattr(a:id, "italic") | let a = a . "</i>" | endif 242 if synIDattr(a:id, "bold") | let a = a . "</b>" | endif 243 if synIDattr(a:id, "inverse") 244 let a = a . '</font></span>' 245 else 246 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) 247 if x != "" | let a = a . '</font>' | endif 248 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) 249 if x != "" | let a = a . '</span>' | endif 250 endif 251 return a 252 endfun 253endif 254 255" Use a different function for formatting based on user options. This way we 256" can avoid a lot of logic during the actual execution. 257" 258" Build the function line by line containing only what is needed for the options 259" in use for maximum code sharing with minimal branch logic for greater speed. 260" 261" Note, 'exec' commands do not recognize line continuations, so must concatenate 262" lines rather than continue them. 263if s:settings.use_css 264 " save CSS to a list of rules to add to the output at the end of processing 265 266 " first, get the style names we need 267 let wrapperfunc_lines = [ 268 \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, text, make_unselectable, unformatted)', 269 \ '', 270 \ ' let l:style_name = synIDattr(a:style_id, "name", s:whatterm)' 271 \ ] 272 if &diff 273 let wrapperfunc_lines += [ 274 \ ' let l:diff_style_name = synIDattr(a:diff_style_id, "name", s:whatterm)'] 275 276 " Add normal groups and diff groups to separate lists so we can order them to 277 " allow diff highlight to override normal highlight 278 279 " if primary style IS a diff style, grab it from the diff cache instead 280 " (always succeeds because we pre-populate it) 281 let wrapperfunc_lines += [ 282 \ '', 283 \ ' if a:style_id == s:DIFF_D_ID || a:style_id == s:DIFF_A_ID ||'. 284 \ ' a:style_id == s:DIFF_C_ID || a:style_id == s:DIFF_T_ID', 285 \ ' let l:saved_style = get(s:diffstylelist,a:style_id)', 286 \ ' else' 287 \ ] 288 endif 289 290 " get primary style info from cache or build it on the fly if not found 291 let wrapperfunc_lines += [ 292 \ ' let l:saved_style = get(s:stylelist,a:style_id)', 293 \ ' if type(l:saved_style) == type(0)', 294 \ ' unlet l:saved_style', 295 \ ' let l:saved_style = s:CSS1(a:style_id)', 296 \ ' if l:saved_style != ""', 297 \ ' let l:saved_style = "." . l:style_name . " { " . l:saved_style . "}"', 298 \ ' endif', 299 \ ' let s:stylelist[a:style_id]= l:saved_style', 300 \ ' endif' 301 \ ] 302 if &diff 303 let wrapperfunc_lines += [ ' endif' ] 304 endif 305 306 " Build the wrapper tags around the text. It turns out that caching these 307 " gives pretty much zero performance gain and adds a lot of logic. 308 309 let wrapperfunc_lines += [ 310 \ '', 311 \ ' if l:saved_style == ""' 312 \ ] 313 if &diff 314 let wrapperfunc_lines += [ 315 \ ' if a:diff_style_id <= 0' 316 \ ] 317 endif 318 " no surroundings if neither primary nor diff style has any info 319 let wrapperfunc_lines += [ 320 \ ' return a:text' 321 \ ] 322 if &diff 323 " no primary style, but diff style 324 let wrapperfunc_lines += [ 325 \ ' else', 326 \ ' return "<span class=\"" .l:diff_style_name . "\">".a:text."</span>"', 327 \ ' endif' 328 \ ] 329 endif 330 " open tag for non-empty primary style 331 let wrapperfunc_lines += [ 332 \ ' else'] 333 " non-empty primary style. handle either empty or non-empty diff style. 334 " 335 " separate the two classes by a space to apply them both if there is a diff 336 " style name, unless the primary style is empty, then just use the diff style 337 " name 338 let diffstyle = 339 \ (&diff ? '(a:diff_style_id <= 0 ? "" : " ". l:diff_style_name) .' 340 \ : "") 341 if s:settings.prevent_copy == "" 342 let wrapperfunc_lines += [ 343 \ ' return "<span class=\"" . l:style_name .'.diffstyle.'"\">".a:text."</span>"' 344 \ ] 345 else 346 347 " 348 " Wrap the <input> in a <span> to allow fixing the stupid bug in some fonts 349 " which cause browsers to display a 1px gap between lines when these 350 " <input>s have a background color (maybe not really a bug, this isn't 351 " well-defined) 352 " 353 " use strwidth, because we care only about how many character boxes are 354 " needed to size the input, we don't care how many characters (including 355 " separately counted composing chars, from strchars()) or bytes (from 356 " len())the string contains. strdisplaywidth() is not needed because none of 357 " the unselectable groups can contain tab characters (fold column, fold 358 " text, line number). 359 " 360 " Note, if maxlength property needs to be added in the future, it will need 361 " to use strchars(), because HTML specifies that the maxlength parameter 362 " uses the number of unique codepoints for its limit. 363 let wrapperfunc_lines += [ 364 \ ' if a:make_unselectable', 365 \ ' return "<span class=\"" . l:style_name .'.diffstyle.'"\">'. 366 \ '<input'.s:unselInputType.' class=\"" . l:style_name .'.diffstyle.'"\"'. 367 \ ' value=\"".substitute(a:unformatted,''\s\+$'',"","")."\"'. 368 \ ' onselect=''this.blur(); return false;'''. 369 \ ' onmousedown=''this.blur(); return false;'''. 370 \ ' onclick=''this.blur(); return false;'''. 371 \ ' readonly=''readonly'''. 372 \ ' size=\"".strwidth(a:unformatted)."\"'. 373 \ (s:settings.use_xhtml ? '/' : '').'></span>"', 374 \ ' else', 375 \ ' return "<span class=\"" . l:style_name .'. diffstyle .'"\">".a:text."</span>"' 376 \ ] 377 endif 378 " close off tag for non-empty primary style 379 if s:settings.prevent_copy == "" 380 let wrapperfunc_lines[-1] .= 381 \ ' "\">".a:text."</span>"' 382 else 383 let wrapperfunc_lines[-1] .= 384 \ ' "\">".a:text."</span>"' 385 endif 386 let wrapperfunc_lines += [ 387 \ ' endif', 388 \ 'endfun' 389 \ ] 390else 391 " Non-CSS method just needs the wrapper. 392 " 393 " Functions used to get opening/closing automatically return null strings if 394 " no styles exist. 395 if &diff 396 let wrapperfunc_lines = [ 397 \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, text, unusedarg, unusedarg2)', 398 \ ' return s:HtmlOpening(a:style_id).(a:diff_style_id <= 0 ? "" :'. 399 \ 's:HtmlOpening(a:diff_style_id)).a:text.'. 400 \ '(a:diff_style_id <= 0 ? "" : s:HtmlClosing(a:diff_style_id)).s:HtmlClosing(a:style_id)', 401 \ 'endfun' 402 \ ] 403 else 404 let wrapperfunc_lines = [ 405 \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, text, unusedarg, unusedarg2)', 406 \ ' return s:HtmlOpening(a:style_id).a:text.s:HtmlClosing(a:style_id)', 407 \ 'endfun' 408 \ ] 409 endif 410endif 411 412" create the function we built line by line above 413exec join(wrapperfunc_lines, "\n") 414 415let s:diff_mode = &diff 416 417" Return HTML valid characters enclosed in a span of class style_name with 418" unprintable characters expanded and double spaces replaced as necessary. 419" 420" TODO: eliminate unneeded logic like done for BuildStyleWrapper 421function! s:HtmlFormat(text, style_id, diff_style_id, make_unselectable) 422 " Replace unprintable characters 423 let unformatted = strtrans(a:text) 424 425 let formatted = unformatted 426 427 " Replace the reserved html characters 428 let formatted = substitute(formatted, '&', '\&', 'g') 429 let formatted = substitute(formatted, '<', '\<', 'g') 430 let formatted = substitute(formatted, '>', '\>', 'g') 431 let formatted = substitute(formatted, '"', '\"', 'g') 432 " ' is not valid in HTML but it is in XHTML, so just use the numeric 433 " reference for it instead. Needed because it could appear in quotes 434 " especially if unselectable regions is turned on. 435 let formatted = substitute(formatted, '"', '\'', 'g') 436 437 " Replace a "form feed" character with HTML to do a page break 438 " TODO: need to prevent this in unselectable areas? Probably it should never 439 " BE in an unselectable area... 440 let formatted = substitute(formatted, "\x0c", '<hr class="PAGE-BREAK">', 'g') 441 442 " Replace double spaces, leading spaces, and trailing spaces if needed 443 if ' ' != s:HtmlSpace 444 let formatted = substitute(formatted, ' ', s:HtmlSpace . s:HtmlSpace, 'g') 445 let formatted = substitute(formatted, '^ ', s:HtmlSpace, 'g') 446 let formatted = substitute(formatted, ' \+$', s:HtmlSpace, 'g') 447 endif 448 449 " Enclose in the correct format 450 return s:BuildStyleWrapper(a:style_id, a:diff_style_id, formatted, a:make_unselectable, unformatted) 451endfun 452 453" set up functions to call HtmlFormat in certain ways based on whether the 454" element is supposed to be unselectable or not 455if s:settings.prevent_copy =~# 'n' 456 function! s:HtmlFormat_n(text, style_id, diff_style_id) 457 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 1) 458 endfun 459else 460 function! s:HtmlFormat_n(text, style_id, diff_style_id) 461 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 0) 462 endfun 463endif 464if s:settings.prevent_copy =~# 'd' 465 function! s:HtmlFormat_d(text, style_id, diff_style_id) 466 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 1) 467 endfun 468else 469 function! s:HtmlFormat_d(text, style_id, diff_style_id) 470 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 0) 471 endfun 472endif 473if s:settings.prevent_copy =~# 'f' 474 " Note the <input> elements for fill spaces will have a single space for 475 " content, to allow active cursor CSS selection to work. 476 " 477 " Wrap the whole thing in a span for the 1px padding workaround for gaps. 478 function! s:FoldColumn_build(char, len, numfill, char2, class, click) 479 let l:input_open = "<input readonly='readonly'".s:unselInputType. 480 \ " onselect='this.blur(); return false;'". 481 \ " onmousedown='this.blur(); ".a:click." return false;'". 482 \ " onclick='return false;' size='". 483 \ string(a:len + (empty(a:char2) ? 0 : 1) + a:numfill) . 484 \ "' " 485 let l:common_attrs = "class='FoldColumn' value='" 486 let l:input_close = (s:settings.use_xhtml ? "' />" : "'>") 487 return "<span class='".a:class."'>". 488 \ l:input_open.l:common_attrs.repeat(a:char, a:len). 489 \ (!empty(a:char2) ? a:char2 : ""). 490 \ l:input_close . "</span>" 491 endfun 492 function! s:FoldColumn_fill() 493 return s:FoldColumn_build('', s:foldcolumn, 0, '', 'FoldColumn', '') 494 endfun 495else 496 " For normal fold columns, simply space-pad to the desired width (note that 497 " the FoldColumn definition includes a whitespace:pre rule) 498 function! s:FoldColumn_build(char, len, numfill, char2, class, click) 499 return "<a href='#' class='".a:class."' onclick='".a:click."'>". 500 \ repeat(a:char, a:len).a:char2.repeat(' ', a:numfill). 501 \ "</a>" 502 endfun 503 function! s:FoldColumn_fill() 504 return s:HtmlFormat(repeat(' ', s:foldcolumn), s:FOLD_C_ID, 0, 0) 505 endfun 506endif 507if s:settings.prevent_copy =~# 't' 508 " put an extra empty span at the end for dynamic folds, so the linebreak can 509 " be surrounded. Otherwise do it as normal. 510 " 511 " TODO: isn't there a better way to do this, than placing it here and using a 512 " substitute later? 513 if s:settings.dynamic_folds 514 function! s:HtmlFormat_t(text, style_id, diff_style_id) 515 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 1) . 516 \ s:HtmlFormat("", a:style_id, 0, 0) 517 endfun 518 else 519 function! s:HtmlFormat_t(text, style_id, diff_style_id) 520 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 1) 521 endfun 522 endif 523else 524 function! s:HtmlFormat_t(text, style_id, diff_style_id) 525 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 0) 526 endfun 527endif 528 529" Return CSS style describing given highlight id (can be empty) 530function! s:CSS1(id) 531 let a = "" 532 if synIDattr(a:id, "inverse") 533 " For inverse, we always must set both colors (and exchange them) 534 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) 535 let a = a . "color: " . ( x != "" ? x : s:bgc ) . "; " 536 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) 537 let a = a . "background-color: " . ( x != "" ? x : s:fgc ) . "; " 538 else 539 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) 540 if x != "" | let a = a . "color: " . x . "; " | endif 541 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) 542 if x != "" 543 let a = a . "background-color: " . x . "; " 544 " stupid hack because almost every browser seems to have at least one font 545 " which shows 1px gaps between lines which have background 546 let a = a . "padding-bottom: 1px; " 547 elseif (a:id == s:FOLDED_ID || a:id == s:LINENR_ID || a:id == s:FOLD_C_ID) && !empty(s:settings.prevent_copy) 548 " input elements default to a different color than the rest of the page 549 let a = a . "background-color: " . s:bgc . "; " 550 endif 551 endif 552 if synIDattr(a:id, "bold") | let a = a . "font-weight: bold; " | endif 553 if synIDattr(a:id, "italic") | let a = a . "font-style: italic; " | endif 554 if synIDattr(a:id, "underline") | let a = a . "text-decoration: underline; " | endif 555 return a 556endfun 557 558if s:settings.dynamic_folds 559 " compares two folds as stored in our list of folds 560 " A fold is "less" than another if it starts at an earlier line number, 561 " or ends at a later line number, ties broken by fold level 562 function! s:FoldCompare(f1, f2) 563 if a:f1.firstline != a:f2.firstline 564 " put it before if it starts earlier 565 return a:f1.firstline - a:f2.firstline 566 elseif a:f1.lastline != a:f2.lastline 567 " put it before if it ends later 568 return a:f2.lastline - a:f1.lastline 569 else 570 " if folds begin and end on the same lines, put lowest fold level first 571 return a:f1.level - a:f2.level 572 endif 573 endfunction 574 575endif 576 577 578" Set some options to make it work faster. 579" Don't report changes for :substitute, there will be many of them. 580" Don't change other windows; turn off scroll bind temporarily 581let s:old_title = &title 582let s:old_icon = &icon 583let s:old_et = &l:et 584let s:old_bind = &l:scrollbind 585let s:old_report = &report 586let s:old_search = @/ 587let s:old_more = &more 588set notitle noicon 589setlocal et 590set nomore 591set report=1000000 592setlocal noscrollbind 593 594if exists(':ownsyntax') && exists('w:current_syntax') 595 let s:current_syntax = w:current_syntax 596elseif exists('b:current_syntax') 597 let s:current_syntax = b:current_syntax 598else 599 let s:current_syntax = 'none' 600endif 601 602if s:current_syntax == '' 603 let s:current_syntax = 'none' 604endif 605 606" Split window to create a buffer with the HTML file. 607let s:orgbufnr = winbufnr(0) 608let s:origwin_stl = &l:stl 609if expand("%") == "" 610 exec 'new Untitled.'.(s:settings.use_xhtml ? 'x' : '').'html' 611else 612 exec 'new %.'.(s:settings.use_xhtml ? 'x' : '').'html' 613endif 614 615" Resize the new window to very small in order to make it draw faster 616let s:old_winheight = winheight(0) 617let s:old_winfixheight = &l:winfixheight 618if s:old_winheight > 2 619 resize 1 " leave enough room to view one line at a time 620 norm! G 621 norm! zt 622endif 623setlocal winfixheight 624 625let s:newwin_stl = &l:stl 626 627" on the new window, set the least time-consuming fold method 628let s:old_fdm = &foldmethod 629let s:old_fen = &foldenable 630setlocal foldmethod=manual 631setlocal nofoldenable 632 633let s:newwin = winnr() 634let s:orgwin = bufwinnr(s:orgbufnr) 635 636setlocal modifiable 637%d 638let s:old_paste = &paste 639set paste 640let s:old_magic = &magic 641set magic 642 643" set the fileencoding to match the charset we'll be using 644let &l:fileencoding=s:settings.vim_encoding 645 646" According to http://www.w3.org/TR/html4/charset.html#doc-char-set, the byte 647" order mark is highly recommend on the web when using multibyte encodings. But, 648" it is not a good idea to include it on UTF-8 files. Otherwise, let Vim 649" determine when it is actually inserted. 650if s:settings.vim_encoding == 'utf-8' 651 setlocal nobomb 652else 653 setlocal bomb 654endif 655 656let s:lines = [] 657 658if s:settings.use_xhtml 659 if s:settings.encoding != "" 660 call add(s:lines, "<?xml version=\"1.0\" encoding=\"" . s:settings.encoding . "\"?>") 661 else 662 call add(s:lines, "<?xml version=\"1.0\"?>") 663 endif 664 let s:tag_close = ' />' 665else 666 let s:tag_close = '>' 667endif 668 669let s:HtmlSpace = ' ' 670let s:LeadingSpace = ' ' 671let s:HtmlEndline = '' 672if s:settings.no_pre 673 let s:HtmlEndline = '<br' . s:tag_close 674 let s:LeadingSpace = ' ' 675 let s:HtmlSpace = '\' . s:LeadingSpace 676endif 677 678" HTML header, with the title and generator ;-). Left free space for the CSS, 679" to be filled at the end. 680call extend(s:lines, [ 681 \ "<html>", 682 \ "<head>"]) 683" include encoding as close to the top as possible, but only if not already 684" contained in XML information (to avoid haggling over content type) 685if s:settings.encoding != "" && !s:settings.use_xhtml 686 call add(s:lines, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" . s:settings.encoding . '"' . s:tag_close) 687endif 688call extend(s:lines, [ 689 \ ("<title>".expand("%:p:~")."</title>"), 690 \ ("<meta name=\"Generator\" content=\"Vim/".v:version/100.".".v:version%100.'"'.s:tag_close), 691 \ ("<meta name=\"plugin-version\" content=\"".g:loaded_2html_plugin.'"'.s:tag_close) 692 \ ]) 693call add(s:lines, '<meta name="syntax" content="'.s:current_syntax.'"'.s:tag_close) 694call add(s:lines, '<meta name="settings" content="'. 695 \ join(filter(keys(s:settings),'s:settings[v:val]'),','). 696 \ ',prevent_copy='.s:settings.prevent_copy. 697 \ '"'.s:tag_close) 698call add(s:lines, '<meta name="colorscheme" content="'. 699 \ (exists('g:colors_name') 700 \ ? g:colors_name 701 \ : 'none'). '"'.s:tag_close) 702 703if s:settings.use_css 704 if s:settings.dynamic_folds 705 if s:settings.hover_unfold 706 " if we are doing hover_unfold, use css 2 with css 1 fallback for IE6 707 call extend(s:lines, [ 708 \ "<style type=\"text/css\">", 709 \ s:settings.use_xhtml ? "" : "<!--", 710 \ ".FoldColumn { text-decoration: none; white-space: pre; }", 711 \ "", 712 \ "body * { margin: 0; padding: 0; }", "", 713 \ ".open-fold > .Folded { display: none; }", 714 \ ".open-fold > .fulltext { display: inline; }", 715 \ ".closed-fold > .fulltext { display: none; }", 716 \ ".closed-fold > .Folded { display: inline; }", 717 \ "", 718 \ ".open-fold > .toggle-open { display: none; }", 719 \ ".open-fold > .toggle-closed { display: inline; }", 720 \ ".closed-fold > .toggle-open { display: inline; }", 721 \ ".closed-fold > .toggle-closed { display: none; }", 722 \ "", "", 723 \ '/* opening a fold while hovering won''t be supported by IE6 and other', 724 \ "similar browsers, but it should fail gracefully. */", 725 \ ".closed-fold:hover > .fulltext { display: inline; }", 726 \ ".closed-fold:hover > .toggle-filler { display: none; }", 727 \ ".closed-fold:hover > .Folded { display: none; }", 728 \ s:settings.use_xhtml ? "" : '-->', 729 \ '</style>']) 730 " TODO: IE7 doesn't *actually* support XHTML, maybe we should remove this. 731 " But if it's served up as tag soup, maybe the following will work, so 732 " leave it in for now. 733 call extend(s:lines, [ 734 \ "<!--[if lt IE 7]><style type=\"text/css\">", 735 \ ".open-fold .Folded { display: none; }", 736 \ ".open-fold .fulltext { display: inline; }", 737 \ ".open-fold .toggle-open { display: none; }", 738 \ ".closed-fold .toggle-closed { display: inline; }", 739 \ "", 740 \ ".closed-fold .fulltext { display: none; }", 741 \ ".closed-fold .Folded { display: inline; }", 742 \ ".closed-fold .toggle-open { display: inline; }", 743 \ ".closed-fold .toggle-closed { display: none; }", 744 \ "</style>", 745 \ "<![endif]-->", 746 \]) 747 else 748 " if we aren't doing hover_unfold, use CSS 1 only 749 call extend(s:lines, [ 750 \ "<style type=\"text/css\">", 751 \ s:settings.use_xhtml ? "" :"<!--", 752 \ ".FoldColumn { text-decoration: none; white-space: pre; }", 753 \ ".open-fold .Folded { display: none; }", 754 \ ".open-fold .fulltext { display: inline; }", 755 \ ".open-fold .toggle-open { display: none; }", 756 \ ".closed-fold .toggle-closed { display: inline; }", 757 \ "", 758 \ ".closed-fold .fulltext { display: none; }", 759 \ ".closed-fold .Folded { display: inline; }", 760 \ ".closed-fold .toggle-open { display: inline; }", 761 \ ".closed-fold .toggle-closed { display: none; }", 762 \ s:settings.use_xhtml ? "" : '-->', 763 \ '</style>' 764 \]) 765 endif 766 else 767 " if we aren't doing any dynamic folding, no need for any special rules 768 call extend(s:lines, [ 769 \ "<style type=\"text/css\">", 770 \ s:settings.use_xhtml ? "" : "<!--", 771 \ s:settings.use_xhtml ? "" : '-->', 772 \ "</style>", 773 \]) 774 endif 775endif 776 777" insert script tag if any javascript is needed 778if s:settings.dynamic_folds || s:settings.prevent_copy != "" 779 call extend(s:lines, [ 780 \ "", 781 \ "<script type='text/javascript'>", 782 \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"]) 783endif 784 785" insert javascript to toggle folds open and closed 786if s:settings.dynamic_folds 787 call extend(s:lines, [ 788 \ "", 789 \ "function toggleFold(objID)", 790 \ "{", 791 \ " var fold;", 792 \ " fold = document.getElementById(objID);", 793 \ " if(fold.className == 'closed-fold')", 794 \ " {", 795 \ " fold.className = 'open-fold';", 796 \ " }", 797 \ " else if (fold.className == 'open-fold')", 798 \ " {", 799 \ " fold.className = 'closed-fold';", 800 \ " }", 801 \ "}" 802 \]) 803endif 804 805" Small text columns like the foldcolumn and line number column need a weird 806" hack to work around Webkit's and (in versions prior to 9) IE's lack of support 807" for the 'ch' unit without messing up Opera, which also doesn't support it but 808" works anyway. 809" 810" The problem is that without the 'ch' unit, it is not possible to specify a 811" size of an <input> in terms of character widths. Only Opera seems to do the 812" "sensible" thing and make the <input> sized to fit exactly as many characters 813" as specified by its "size" attribute, but the spec actually says "at least 814" wide enough to fit 'size' characters", so the other browsers are technically 815" correct as well. 816" 817" Anyway, this leads to two diffculties: 818" 1. The foldcolumn is made up of multiple elements side-by-side with 819" different sizes, each of which has their own extra padding added. Thus, a 820" column made up of one item of size 1 and another of size 2 would not 821" necessarily be equal in size to another line's foldcolumn with a single 822" item of size 3. 823" 2. The extra padding added to the <input> elements adds up to make the 824" foldcolumn and line number column too wide, especially in Webkit 825" browsers. 826" 827" So, the full workaround is: 828" 1. Define a default size in em, equal to the number of characters in the 829" input element, in case javascript is disabled and the browser does not 830" support the 'ch' unit. Unfortunately this makes Opera no longer work 831" properly without javascript. 1em per character is much too wide but it 832" looks better in webkit browsers than unaligned columns. 833" 2. Insert the following javascript to run at page load, which checks for the 834" width of a single character (in an extraneous page element inserted 835" before the page title, and set to hidden) and compares it to the width of 836" another extra <input> element with only one character. If the width 837" matches, the script does nothing more, but if not, it will figure out the 838" fraction of an em unit which would correspond with a ch unit if there 839" were one, and set the containing element (<pre> or <div>) to a class with 840" pre-defined rules which is closest to that fraction of an em. Rules are 841" defined from 0.05 em to 1em per ch. 842if !empty(s:settings.prevent_copy) 843 call extend(s:lines, [ 844 \ '', 845 \ '/* simulate a "ch" unit by asking the browser how big a zero character is */', 846 \ 'function FixCharWidth() {', 847 \ ' /* get the hidden element which gives the width of a single character */', 848 \ ' var goodWidth = document.getElementById("oneCharWidth").clientWidth;', 849 \ ' /* get all input elements, we''ll filter on class later */', 850 \ ' var inputTags = document.getElementsByTagName("input");', 851 \ ' var ratio = 5;', 852 \ ' var inputWidth = document.getElementById("oneInputWidth").clientWidth;', 853 \ ' var emWidth = document.getElementById("oneEmWidth").clientWidth;', 854 \ ' if (inputWidth > goodWidth) {', 855 \ ' while (ratio < 100*goodWidth/emWidth && ratio < 100) {', 856 \ ' ratio += 5;', 857 \ ' }', 858 \ ' document.getElementById("vimCodeElement").className = "em"+ratio;', 859 \ ' }', 860 \ '}' 861 \ ]) 862endif 863 864" insert script closing tag if any javascript is needed 865if s:settings.dynamic_folds || s:settings.prevent_copy != "" 866 call extend(s:lines, [ 867 \ '', 868 \ s:settings.use_xhtml ? '//]]>' : '-->', 869 \ "</script>" 870 \ ]) 871endif 872 873call extend(s:lines, ["</head>"]) 874if !empty(s:settings.prevent_copy) 875 call extend(s:lines, 876 \ ["<body onload='FixCharWidth();'>", 877 \ "<!-- hidden divs used by javascript to get the width of a char -->", 878 \ "<div id='oneCharWidth'>0</div>", 879 \ "<div id='oneInputWidth'><input size='1' value='0'".s:tag_close."</div>", 880 \ "<div id='oneEmWidth' style='width: 1em;'></div>" 881 \ ]) 882else 883 call extend(s:lines, ["<body>"]) 884endif 885if s:settings.no_pre 886 " if we're not using CSS we use a font tag which can't have a div inside 887 if s:settings.use_css 888 call extend(s:lines, ["<div id='vimCodeElement'>"]) 889 endif 890else 891 call extend(s:lines, ["<pre id='vimCodeElement'>"]) 892endif 893 894exe s:orgwin . "wincmd w" 895 896" caches of style data 897" initialize to include line numbers if using them 898if s:settings.number_lines 899 let s:stylelist = { s:LINENR_ID : ".LineNr { " . s:CSS1( s:LINENR_ID ) . "}" } 900else 901 let s:stylelist = {} 902endif 903let s:diffstylelist = { 904 \ s:DIFF_A_ID : ".DiffAdd { " . s:CSS1( s:DIFF_A_ID ) . "}", 905 \ s:DIFF_C_ID : ".DiffChange { " . s:CSS1( s:DIFF_C_ID ) . "}", 906 \ s:DIFF_D_ID : ".DiffDelete { " . s:CSS1( s:DIFF_D_ID ) . "}", 907 \ s:DIFF_T_ID : ".DiffText { " . s:CSS1( s:DIFF_T_ID ) . "}" 908 \ } 909 910" set up progress bar in the status line 911if !s:settings.no_progress 912 " ProgressBar Indicator 913 let s:progressbar={} 914 915 " Progessbar specific functions 916 func! s:ProgressBar(title, max_value, winnr) 917 let pgb=copy(s:progressbar) 918 let pgb.title = a:title.' ' 919 let pgb.max_value = a:max_value 920 let pgb.winnr = a:winnr 921 let pgb.cur_value = 0 922 let pgb.items = { 'title' : { 'color' : 'Statusline' }, 923 \'bar' : { 'color' : 'Statusline' , 'fillcolor' : 'DiffDelete' , 'bg' : 'Statusline' } , 924 \'counter' : { 'color' : 'Statusline' } } 925 let pgb.last_value = 0 926 let pgb.needs_redraw = 0 927 " Note that you must use len(split) instead of len() if you want to use 928 " unicode in title. 929 " 930 " Subtract 3 for spacing around the title. 931 " Subtract 4 for the percentage display. 932 " Subtract 2 for spacing before this. 933 " Subtract 2 more for the '|' on either side of the progress bar 934 let pgb.subtractedlen=len(split(pgb.title, '\zs'))+3+4+2+2 935 let pgb.max_len = 0 936 set laststatus=2 937 return pgb 938 endfun 939 940 " Function: progressbar.calculate_ticks() {{{1 941 func! s:progressbar.calculate_ticks(pb_len) 942 if a:pb_len<=0 943 let pb_len = 100 944 else 945 let pb_len = a:pb_len 946 endif 947 let self.progress_ticks = map(range(pb_len+1), "v:val * self.max_value / pb_len") 948 endfun 949 950 "Function: progressbar.paint() 951 func! s:progressbar.paint() 952 " Recalculate widths. 953 let max_len = winwidth(self.winnr) 954 let pb_len = 0 955 " always true on first call because of initial value of self.max_len 956 if max_len != self.max_len 957 let self.max_len = max_len 958 959 " Progressbar length 960 let pb_len = max_len - self.subtractedlen 961 962 call self.calculate_ticks(pb_len) 963 964 let self.needs_redraw = 1 965 let cur_value = 0 966 let self.pb_len = pb_len 967 else 968 " start searching at the last found index to make the search for the 969 " appropriate tick value normally take 0 or 1 comparisons 970 let cur_value = self.last_value 971 let pb_len = self.pb_len 972 endif 973 974 let cur_val_max = pb_len > 0 ? pb_len : 100 975 976 " find the current progress bar position based on precalculated thresholds 977 while cur_value < cur_val_max && self.cur_value > self.progress_ticks[cur_value] 978 let cur_value += 1 979 endwhile 980 981 " update progress bar 982 if self.last_value != cur_value || self.needs_redraw || self.cur_value == self.max_value 983 let self.needs_redraw = 1 984 let self.last_value = cur_value 985 986 let t_color = self.items.title.color 987 let b_fcolor = self.items.bar.fillcolor 988 let b_color = self.items.bar.color 989 let c_color = self.items.counter.color 990 991 let stl = "%#".t_color."#%-( ".self.title." %)". 992 \"%#".b_color."#". 993 \(pb_len>0 ? 994 \ ('|%#'.b_fcolor."#%-(".repeat(" ",cur_value)."%)". 995 \ '%#'.b_color."#".repeat(" ",pb_len-cur_value)."|"): 996 \ ('')). 997 \"%=%#".c_color."#%( ".printf("%3.d ",100*self.cur_value/self.max_value)."%% %)" 998 call setwinvar(self.winnr, '&stl', stl) 999 endif 1000 endfun 1001 1002 func! s:progressbar.incr( ... ) 1003 let self.cur_value += (a:0 ? a:1 : 1) 1004 " if we were making a general-purpose progress bar, we'd need to limit to a 1005 " lower limit as well, but since we always increment with a positive value 1006 " in this script, we only need limit the upper value 1007 let self.cur_value = (self.cur_value > self.max_value ? self.max_value : self.cur_value) 1008 call self.paint() 1009 endfun 1010 " }}} 1011 if s:settings.dynamic_folds 1012 " to process folds we make two passes through each line 1013 let s:pgb = s:ProgressBar("Processing folds:", line('$')*2, s:orgwin) 1014 endif 1015endif 1016 1017" First do some preprocessing for dynamic folding. Do this for the entire file 1018" so we don't accidentally start within a closed fold or something. 1019let s:allfolds = [] 1020 1021if s:settings.dynamic_folds 1022 let s:lnum = 1 1023 let s:end = line('$') 1024 " save the fold text and set it to the default so we can find fold levels 1025 let s:foldtext_save = &foldtext 1026 setlocal foldtext& 1027 1028 " we will set the foldcolumn in the html to the greater of the maximum fold 1029 " level and the current foldcolumn setting 1030 let s:foldcolumn = &foldcolumn 1031 1032 " get all info needed to describe currently closed folds 1033 while s:lnum <= s:end 1034 if foldclosed(s:lnum) == s:lnum 1035 " default fold text has '+-' and then a number of dashes equal to fold 1036 " level, so subtract 2 from index of first non-dash after the dashes 1037 " in order to get the fold level of the current fold 1038 let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2 1039 " store fold info for later use 1040 let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"} 1041 call add(s:allfolds, s:newfold) 1042 " open the fold so we can find any contained folds 1043 execute s:lnum."foldopen" 1044 else 1045 if !s:settings.no_progress 1046 call s:pgb.incr() 1047 if s:pgb.needs_redraw 1048 redrawstatus 1049 let s:pgb.needs_redraw = 0 1050 endif 1051 endif 1052 let s:lnum = s:lnum + 1 1053 endif 1054 endwhile 1055 1056 " close all folds to get info for originally open folds 1057 silent! %foldclose! 1058 let s:lnum = 1 1059 1060 " the originally open folds will be all folds we encounter that aren't 1061 " already in the list of closed folds 1062 while s:lnum <= s:end 1063 if foldclosed(s:lnum) == s:lnum 1064 " default fold text has '+-' and then a number of dashes equal to fold 1065 " level, so subtract 2 from index of first non-dash after the dashes 1066 " in order to get the fold level of the current fold 1067 let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2 1068 let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"} 1069 " only add the fold if we don't already have it 1070 if empty(s:allfolds) || index(s:allfolds, s:newfold) == -1 1071 let s:newfold.type = "open-fold" 1072 call add(s:allfolds, s:newfold) 1073 endif 1074 " open the fold so we can find any contained folds 1075 execute s:lnum."foldopen" 1076 else 1077 if !s:settings.no_progress 1078 call s:pgb.incr() 1079 if s:pgb.needs_redraw 1080 redrawstatus 1081 let s:pgb.needs_redraw = 0 1082 endif 1083 endif 1084 let s:lnum = s:lnum + 1 1085 endif 1086 endwhile 1087 1088 " sort the folds so that we only ever need to look at the first item in the 1089 " list of folds 1090 call sort(s:allfolds, "s:FoldCompare") 1091 1092 let &l:foldtext = s:foldtext_save 1093 unlet s:foldtext_save 1094 1095 " close all folds again so we can get the fold text as we go 1096 silent! %foldclose! 1097 1098 " Go through and remove folds we don't need to (or cannot) process in the 1099 " current conversion range 1100 " 1101 " If a fold is removed which contains other folds, which are included, we need 1102 " to adjust the level of the included folds as used by the conversion logic 1103 " (avoiding special cases is good) 1104 " 1105 " Note any time we remove a fold, either all of the included folds are in it, 1106 " or none of them, because we only remove a fold if neither its start nor its 1107 " end are within the conversion range. 1108 let leveladjust = 0 1109 for afold in s:allfolds 1110 let removed = 0 1111 if exists("g:html_start_line") && exists("g:html_end_line") 1112 if afold.firstline < g:html_start_line 1113 if afold.lastline <= g:html_end_line && afold.lastline >= g:html_start_line 1114 " if a fold starts before the range to convert but stops within the 1115 " range, we need to include it. Make it start on the first converted 1116 " line. 1117 let afold.firstline = g:html_start_line 1118 else 1119 " if the fold lies outside the range or the start and stop enclose 1120 " the entire range, don't bother parsing it 1121 call remove(s:allfolds, index(s:allfolds, afold)) 1122 let removed = 1 1123 if afold.lastline > g:html_end_line 1124 let leveladjust += 1 1125 endif 1126 endif 1127 elseif afold.firstline > g:html_end_line 1128 " If the entire fold lies outside the range we need to remove it. 1129 call remove(s:allfolds, index(s:allfolds, afold)) 1130 let removed = 1 1131 endif 1132 elseif exists("g:html_start_line") 1133 if afold.firstline < g:html_start_line 1134 " if there is no last line, but there is a first line, the end of the 1135 " fold will always lie within the region of interest, so keep it 1136 let afold.firstline = g:html_start_line 1137 endif 1138 elseif exists("g:html_end_line") 1139 " if there is no first line we default to the first line in the buffer so 1140 " the fold start will always be included if the fold itself is included. 1141 " If however the entire fold lies outside the range we need to remove it. 1142 if afold.firstline > g:html_end_line 1143 call remove(s:allfolds, index(s:allfolds, afold)) 1144 let removed = 1 1145 endif 1146 endif 1147 if !removed 1148 let afold.level -= leveladjust 1149 if afold.level+1 > s:foldcolumn 1150 let s:foldcolumn = afold.level+1 1151 endif 1152 endif 1153 endfor 1154 1155 " if we've removed folds containing the conversion range from processing, 1156 " getting foldtext as we go won't know to open the removed folds, so the 1157 " foldtext would be wrong; open them now. 1158 " 1159 " Note that only when a start and an end line is specified will a fold 1160 " containing the current range ever be removed. 1161 while leveladjust > 0 1162 exe g:html_start_line."foldopen" 1163 let leveladjust -= 1 1164 endwhile 1165endif 1166 1167" Now loop over all lines in the original text to convert to html. 1168" Use html_start_line and html_end_line if they are set. 1169if exists("g:html_start_line") 1170 let s:lnum = html_start_line 1171 if s:lnum < 1 || s:lnum > line("$") 1172 let s:lnum = 1 1173 endif 1174else 1175 let s:lnum = 1 1176endif 1177if exists("g:html_end_line") 1178 let s:end = html_end_line 1179 if s:end < s:lnum || s:end > line("$") 1180 let s:end = line("$") 1181 endif 1182else 1183 let s:end = line("$") 1184endif 1185 1186" stack to keep track of all the folds containing the current line 1187let s:foldstack = [] 1188 1189if !s:settings.no_progress 1190 let s:pgb = s:ProgressBar("Processing lines:", s:end - s:lnum + 1, s:orgwin) 1191endif 1192 1193if s:settings.number_lines 1194 let s:margin = strlen(s:end) + 1 1195else 1196 let s:margin = 0 1197endif 1198 1199if has('folding') && !s:settings.ignore_folding 1200 let s:foldfillchar = &fillchars[matchend(&fillchars, 'fold:')] 1201 if s:foldfillchar == '' 1202 let s:foldfillchar = '-' 1203 endif 1204endif 1205let s:difffillchar = &fillchars[matchend(&fillchars, 'diff:')] 1206if s:difffillchar == '' 1207 let s:difffillchar = '-' 1208endif 1209 1210let s:foldId = 0 1211 1212if !s:settings.expand_tabs 1213 " If keeping tabs, add them to printable characters so we keep them when 1214 " formatting text (strtrans() doesn't replace printable chars) 1215 let s:old_isprint = &isprint 1216 setlocal isprint+=9 1217endif 1218 1219while s:lnum <= s:end 1220 1221 " If there are filler lines for diff mode, show these above the line. 1222 let s:filler = diff_filler(s:lnum) 1223 if s:filler > 0 1224 let s:n = s:filler 1225 while s:n > 0 1226 let s:new = repeat(s:difffillchar, 3) 1227 1228 if s:n > 2 && s:n < s:filler && !s:settings.whole_filler 1229 let s:new = s:new . " " . s:filler . " inserted lines " 1230 let s:n = 2 1231 endif 1232 1233 if !s:settings.no_pre 1234 " HTML line wrapping is off--go ahead and fill to the margin 1235 " TODO: what about when CSS wrapping is turned on? 1236 let s:new = s:new . repeat(s:difffillchar, &columns - strlen(s:new) - s:margin) 1237 else 1238 let s:new = s:new . repeat(s:difffillchar, 3) 1239 endif 1240 1241 let s:new = s:HtmlFormat_d(s:new, s:DIFF_D_ID, 0) 1242 if s:settings.number_lines 1243 " Indent if line numbering is on. Indent gets style of line number 1244 " column. 1245 let s:new = s:HtmlFormat_n(repeat(' ', s:margin), s:LINENR_ID, 0) . s:new 1246 endif 1247 if s:settings.dynamic_folds && !s:settings.no_foldcolumn && s:foldcolumn > 0 1248 " Indent for foldcolumn if there is one. Assume it's empty, there should 1249 " not be a fold for deleted lines in diff mode. 1250 let s:new = s:FoldColumn_fill() . s:new 1251 endif 1252 call add(s:lines, s:new.s:HtmlEndline) 1253 1254 let s:n = s:n - 1 1255 endwhile 1256 unlet s:n 1257 endif 1258 unlet s:filler 1259 1260 " Start the line with the line number. 1261 if s:settings.number_lines 1262 let s:numcol = repeat(' ', s:margin - 1 - strlen(s:lnum)) . s:lnum . ' ' 1263 endif 1264 1265 let s:new = "" 1266 1267 if has('folding') && !s:settings.ignore_folding && foldclosed(s:lnum) > -1 && !s:settings.dynamic_folds 1268 " 1269 " This is the beginning of a folded block (with no dynamic folding) 1270 let s:new = foldtextresult(s:lnum) 1271 if !s:settings.no_pre 1272 " HTML line wrapping is off--go ahead and fill to the margin 1273 let s:new = s:new . repeat(s:foldfillchar, &columns - strlen(s:new)) 1274 endif 1275 1276 " put numcol in a separate group for sake of unselectable text 1277 let s:new = (s:settings.number_lines ? s:HtmlFormat_n(s:numcol, s:FOLDED_ID, 0): "") . s:HtmlFormat_t(s:new, s:FOLDED_ID, 0) 1278 1279 " Skip to the end of the fold 1280 let s:new_lnum = foldclosedend(s:lnum) 1281 1282 if !s:settings.no_progress 1283 call s:pgb.incr(s:new_lnum - s:lnum) 1284 endif 1285 1286 let s:lnum = s:new_lnum 1287 1288 else 1289 " 1290 " A line that is not folded, or doing dynamic folding. 1291 " 1292 let s:line = getline(s:lnum) 1293 let s:len = strlen(s:line) 1294 1295 if s:settings.dynamic_folds 1296 " First insert a closing for any open folds that end on this line 1297 while !empty(s:foldstack) && get(s:foldstack,0).lastline == s:lnum-1 1298 let s:new = s:new."</span></span>" 1299 call remove(s:foldstack, 0) 1300 endwhile 1301 1302 " Now insert an opening for any new folds that start on this line 1303 let s:firstfold = 1 1304 while !empty(s:allfolds) && get(s:allfolds,0).firstline == s:lnum 1305 let s:foldId = s:foldId + 1 1306 let s:new .= "<span id='" 1307 let s:new .= (exists('g:html_diff_win_num') ? "win".g:html_diff_win_num : "") 1308 let s:new .= "fold".s:foldId."' class='".s:allfolds[0].type."'>" 1309 1310 1311 " Unless disabled, add a fold column for the opening line of a fold. 1312 " 1313 " Note that dynamic folds require using css so we just use css to take 1314 " care of the leading spaces rather than using in the case of 1315 " html_no_pre to make it easier 1316 if !s:settings.no_foldcolumn 1317 " add fold column that can open the new fold 1318 if s:allfolds[0].level > 1 && s:firstfold 1319 let s:new = s:new . s:FoldColumn_build('|', s:allfolds[0].level - 1, 0, "", 1320 \ 'toggle-open FoldColumn','javascript:toggleFold("fold'.s:foldstack[0].id.'");') 1321 endif 1322 " add the filler spaces separately from the '+' char so that it can be 1323 " shown/hidden separately during a hover unfold 1324 let s:new = s:new . s:FoldColumn_build("+", 1, 0, "", 1325 \ 'toggle-open FoldColumn', 'javascript:toggleFold("fold'.s:foldId.'");') 1326 " If this is not the last fold we're opening on this line, we need 1327 " to keep the filler spaces hidden if the fold is opened by mouse 1328 " hover. If it is the last fold to open in the line, we shouldn't hide 1329 " them, so don't apply the toggle-filler class. 1330 let s:new = s:new . s:FoldColumn_build(" ", 1, s:foldcolumn - s:allfolds[0].level - 1, "", 1331 \ 'toggle-open FoldColumn'. (get(s:allfolds, 1, {'firstline': 0}).firstline == s:lnum ?" toggle-filler" :""), 1332 \ 'javascript:toggleFold("fold'.s:foldId.'");') 1333 1334 " add fold column that can close the new fold 1335 " only add extra blank space if we aren't opening another fold on the 1336 " same line 1337 if get(s:allfolds, 1, {'firstline': 0}).firstline != s:lnum 1338 let s:extra_space = s:foldcolumn - s:allfolds[0].level 1339 else 1340 let s:extra_space = 0 1341 endif 1342 if s:firstfold 1343 " the first fold in a line has '|' characters from folds opened in 1344 " previous lines, before the '-' for this fold 1345 let s:new .= s:FoldColumn_build('|', s:allfolds[0].level - 1, s:extra_space, '-', 1346 \ 'toggle-closed FoldColumn', 'javascript:toggleFold("fold'.s:foldId.'");') 1347 else 1348 " any subsequent folds in the line only add a single '-' 1349 let s:new = s:new . s:FoldColumn_build("-", 1, s:extra_space, "", 1350 \ 'toggle-closed FoldColumn', 'javascript:toggleFold("fold'.s:foldId.'");') 1351 endif 1352 let s:firstfold = 0 1353 endif 1354 1355 " Add fold text, moving the span ending to the next line so collapsing 1356 " of folds works correctly. 1357 " Put numcol in a separate group for sake of unselectable text. 1358 let s:new = s:new . (s:settings.number_lines ? s:HtmlFormat_n(s:numcol, s:FOLDED_ID, 0) : "") . substitute(s:HtmlFormat_t(foldtextresult(s:lnum), s:FOLDED_ID, 0), '</span>', s:HtmlEndline.'\n\0', '') 1359 let s:new = s:new . "<span class='fulltext'>" 1360 1361 " open the fold now that we have the fold text to allow retrieval of 1362 " fold text for subsequent folds 1363 execute s:lnum."foldopen" 1364 call insert(s:foldstack, remove(s:allfolds,0)) 1365 let s:foldstack[0].id = s:foldId 1366 endwhile 1367 1368 " Unless disabled, add a fold column for other lines. 1369 " 1370 " Note that dynamic folds require using css so we just use css to take 1371 " care of the leading spaces rather than using in the case of 1372 " html_no_pre to make it easier 1373 if !s:settings.no_foldcolumn 1374 if empty(s:foldstack) 1375 " add the empty foldcolumn for unfolded lines if there is a fold 1376 " column at all 1377 if s:foldcolumn > 0 1378 let s:new = s:new . s:FoldColumn_fill() 1379 endif 1380 else 1381 " add the fold column for folds not on the opening line 1382 if get(s:foldstack, 0).firstline < s:lnum 1383 let s:new = s:new . s:FoldColumn_build('|', s:foldstack[0].level, s:foldcolumn - s:foldstack[0].level, "", 1384 \ 'FoldColumn', 'javascript:toggleFold("fold'.s:foldstack[0].id.'");') 1385 endif 1386 endif 1387 endif 1388 endif 1389 1390 " Now continue with the unfolded line text 1391 if s:settings.number_lines 1392 let s:new = s:new . s:HtmlFormat_n(s:numcol, s:LINENR_ID, 0) 1393 endif 1394 1395 " Get the diff attribute, if any. 1396 let s:diffattr = diff_hlID(s:lnum, 1) 1397 1398 " initialize conceal info to act like not concealed, just in case 1399 let s:concealinfo = [0, ''] 1400 1401 " Loop over each character in the line 1402 let s:col = 1 1403 1404 " most of the time we won't use the diff_id, initialize to zero 1405 let s:diff_id = 0 1406 1407 while s:col <= s:len || (s:col == 1 && s:diffattr) 1408 let s:startcol = s:col " The start column for processing text 1409 if !s:settings.ignore_conceal && has('conceal') 1410 let s:concealinfo = synconcealed(s:lnum, s:col) 1411 endif 1412 if !s:settings.ignore_conceal && s:concealinfo[0] 1413 let s:col = s:col + 1 1414 " Speed loop (it's small - that's the trick) 1415 " Go along till we find a change in the match sequence number (ending 1416 " the specific concealed region) or until there are no more concealed 1417 " characters. 1418 while s:col <= s:len && s:concealinfo == synconcealed(s:lnum, s:col) | let s:col = s:col + 1 | endwhile 1419 elseif s:diffattr 1420 let s:diff_id = diff_hlID(s:lnum, s:col) 1421 let s:id = synID(s:lnum, s:col, 1) 1422 let s:col = s:col + 1 1423 " Speed loop (it's small - that's the trick) 1424 " Go along till we find a change in hlID 1425 while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) 1426 \ && s:diff_id == diff_hlID(s:lnum, s:col) | 1427 \ let s:col = s:col + 1 | 1428 \ endwhile 1429 if s:len < &columns && !s:settings.no_pre 1430 " Add spaces at the end of the raw text line to extend the changed 1431 " line to the full width. 1432 let s:line = s:line . repeat(' ', &columns - virtcol([s:lnum, s:len]) - s:margin) 1433 let s:len = &columns 1434 endif 1435 else 1436 let s:id = synID(s:lnum, s:col, 1) 1437 let s:col = s:col + 1 1438 " Speed loop (it's small - that's the trick) 1439 " Go along till we find a change in synID 1440 while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) | let s:col = s:col + 1 | endwhile 1441 endif 1442 1443 if s:settings.ignore_conceal || !s:concealinfo[0] 1444 " Expand tabs if needed 1445 let s:expandedtab = strpart(s:line, s:startcol - 1, s:col - s:startcol) 1446 if s:settings.expand_tabs 1447 let s:offset = 0 1448 let s:idx = stridx(s:expandedtab, "\t") 1449 while s:idx >= 0 1450 if has("multi_byte_encoding") 1451 if s:startcol + s:idx == 1 1452 let s:i = &ts 1453 else 1454 if s:idx == 0 1455 let s:prevc = matchstr(s:line, '.\%' . (s:startcol + s:idx + s:offset) . 'c') 1456 else 1457 let s:prevc = matchstr(s:expandedtab, '.\%' . (s:idx + 1) . 'c') 1458 endif 1459 let s:vcol = virtcol([s:lnum, s:startcol + s:idx + s:offset - len(s:prevc)]) 1460 let s:i = &ts - (s:vcol % &ts) 1461 endif 1462 let s:offset -= s:i - 1 1463 else 1464 let s:i = &ts - ((s:idx + s:startcol - 1) % &ts) 1465 endif 1466 let s:expandedtab = substitute(s:expandedtab, '\t', repeat(' ', s:i), '') 1467 let s:idx = stridx(s:expandedtab, "\t") 1468 endwhile 1469 end 1470 1471 " get the highlight group name to use 1472 let s:id = synIDtrans(s:id) 1473 else 1474 " use Conceal highlighting for concealed text 1475 let s:id = s:CONCEAL_ID 1476 let s:expandedtab = s:concealinfo[1] 1477 endif 1478 1479 " Output the text with the same synID, with class set to the highlight ID 1480 " name, unless it has been concealed completely. 1481 if strlen(s:expandedtab) > 0 1482 let s:new = s:new . s:HtmlFormat(s:expandedtab, s:id, s:diff_id, 0) 1483 endif 1484 endwhile 1485 endif 1486 1487 call extend(s:lines, split(s:new.s:HtmlEndline, '\n', 1)) 1488 if !s:settings.no_progress && s:pgb.needs_redraw 1489 redrawstatus 1490 let s:pgb.needs_redraw = 0 1491 endif 1492 let s:lnum = s:lnum + 1 1493 1494 if !s:settings.no_progress 1495 call s:pgb.incr() 1496 endif 1497endwhile 1498 1499if s:settings.dynamic_folds 1500 " finish off any open folds 1501 while !empty(s:foldstack) 1502 let s:lines[-1].="</span></span>" 1503 call remove(s:foldstack, 0) 1504 endwhile 1505 1506 " add fold column to the style list if not already there 1507 let s:id = s:FOLD_C_ID 1508 if !has_key(s:stylelist, s:id) 1509 let s:stylelist[s:id] = '.FoldColumn { ' . s:CSS1(s:id) . '}' 1510 endif 1511endif 1512 1513if s:settings.no_pre 1514 if !s:settings.use_css 1515 " Close off the font tag that encapsulates the whole <body> 1516 call extend(s:lines, ["</font>", "</body>", "</html>"]) 1517 else 1518 call extend(s:lines, ["</div>", "</body>", "</html>"]) 1519 endif 1520else 1521 call extend(s:lines, ["</pre>", "</body>", "</html>"]) 1522endif 1523 1524exe s:newwin . "wincmd w" 1525call setline(1, s:lines) 1526unlet s:lines 1527 1528" Mangle modelines so Vim doesn't try to use HTML text as a modeline if editing 1529" this file in the future; need to do this after generating all the text in case 1530" the modeline text has different highlight groups which all turn out to be 1531" stripped from the final output. 1532%s!\v(%(^|\s+)%(vim?|ex)):!\1\:!ge 1533 1534" Now, when we finally know which, we define the colors and styles 1535if s:settings.use_css 1536 1;/<style type="text/+1 1537endif 1538 1539" Normal/global attributes 1540" For Netscape 4, set <body> attributes too, though, strictly speaking, it's 1541" incorrect. 1542if s:settings.use_css 1543 if s:settings.no_pre 1544 call append('.', "body { color: " . s:fgc . "; background-color: " . s:bgc . "; font-family: ". s:htmlfont ."; }") 1545 + 1546 else 1547 call append('.', "pre { " . s:whitespace . "font-family: ". s:htmlfont ."; color: " . s:fgc . "; background-color: " . s:bgc . "; }") 1548 + 1549 yank 1550 put 1551 execute "normal! ^cwbody\e" 1552 " body should not have the wrap formatting, only the pre section 1553 if s:whitespace != '' 1554 exec 's#'.s:whitespace 1555 endif 1556 endif 1557 " fix browser inconsistencies (sometimes within the same browser) of different 1558 " default font size for different elements 1559 call append('.', '* { font-size: 1em; }') 1560 + 1561 " if we use any input elements for unselectable content, make sure they look 1562 " like normal text 1563 if !empty(s:settings.prevent_copy) 1564 call append('.', 'input { border: none; margin: 0; padding: 0; font-family: '.s:htmlfont.'; }') 1565 + 1566 " ch units for browsers which support them, em units for a somewhat 1567 " reasonable fallback. Also make sure the special elements for size 1568 " calculations aren't seen. 1569 call append('.', [ 1570 \ "input[size='1'] { width: 1em; width: 1ch; }", 1571 \ "input[size='2'] { width: 2em; width: 2ch; }", 1572 \ "input[size='3'] { width: 3em; width: 3ch; }", 1573 \ "input[size='4'] { width: 4em; width: 4ch; }", 1574 \ "input[size='5'] { width: 5em; width: 5ch; }", 1575 \ "input[size='6'] { width: 6em; width: 6ch; }", 1576 \ "input[size='7'] { width: 7em; width: 7ch; }", 1577 \ "input[size='8'] { width: 8em; width: 8ch; }", 1578 \ "input[size='9'] { width: 9em; width: 9ch; }", 1579 \ "input[size='10'] { width: 10em; width: 10ch; }", 1580 \ "input[size='11'] { width: 11em; width: 11ch; }", 1581 \ "input[size='12'] { width: 12em; width: 12ch; }", 1582 \ "input[size='13'] { width: 13em; width: 13ch; }", 1583 \ "input[size='14'] { width: 14em; width: 14ch; }", 1584 \ "input[size='15'] { width: 15em; width: 15ch; }", 1585 \ "input[size='16'] { width: 16em; width: 16ch; }", 1586 \ "input[size='17'] { width: 17em; width: 17ch; }", 1587 \ "input[size='18'] { width: 18em; width: 18ch; }", 1588 \ "input[size='19'] { width: 19em; width: 19ch; }", 1589 \ "input[size='20'] { width: 20em; width: 20ch; }", 1590 \ "#oneCharWidth, #oneEmWidth, #oneInputWidth { padding: 0; margin: 0; position: absolute; left: -999999px; visibility: hidden; }" 1591 \ ]) 1592 +21 1593 for w in range(5, 100, 5) 1594 let base = 0.01 * w 1595 call append('.', join(map(range(1,20), "'.em'.w.' input[size='''.v:val.'''] { width: '.string(v:val*base).'em; }'"))) 1596 + 1597 endfor 1598 if s:settings.prevent_copy =~# 'f' 1599 " Make the cursor show active fold columns as active areas, and empty fold 1600 " columns as not interactive. 1601 call append('.', ['input.FoldColumn { cursor: pointer; }', 1602 \ 'input.FoldColumn[value=""] { cursor: default; }' 1603 \ ]) 1604 +2 1605 endif 1606 " make line number column show as non-interactive if not selectable 1607 if s:settings.prevent_copy =~# 'n' 1608 call append('.', 'input.LineNr { cursor: default; }') 1609 + 1610 endif 1611 " make fold text and line number column within fold text show as 1612 " non-interactive if not selectable 1613 if (s:settings.prevent_copy =~# 'n' || s:settings.prevent_copy =~# 't') && !s:settings.ignore_folding 1614 call append('.', 'input.Folded { cursor: default; }') 1615 + 1616 endif 1617 endif 1618else 1619 execute '%s:<body>:<body bgcolor="' . s:bgc . '" text="' . s:fgc . '">\r<font face="'. s:htmlfont .'">' 1620endif 1621 1622" Gather attributes for all other classes. Do diff first so that normal 1623" highlight groups are inserted before it. 1624if s:settings.use_css 1625 if s:diff_mode 1626 call append('.', filter(map(keys(s:diffstylelist), "s:diffstylelist[v:val]"), 'v:val != ""')) 1627 endif 1628 if !empty(s:stylelist) 1629 call append('.', filter(map(keys(s:stylelist), "s:stylelist[v:val]"), 'v:val != ""')) 1630 endif 1631endif 1632 1633" Add hyperlinks 1634" TODO: add option to not do this? Maybe just make the color the same as the 1635" text highlight group normally is? 1636%s+\(https\=://\S\{-}\)\(\([.,;:}]\=\(\s\|$\)\)\|[\\"'<>]\|>\|<\|"\)+<a href="\1">\1</a>\2+ge 1637 1638" The DTD 1639if s:settings.use_xhtml 1640 exe "normal! gg$a\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" 1641elseif s:settings.use_css && !s:settings.no_pre 1642 exe "normal! gg0i<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n" 1643else 1644 exe "normal! gg0i<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n" 1645endif 1646 1647if s:settings.use_xhtml 1648 exe "normal! gg/<html/e\na xmlns=\"http://www.w3.org/1999/xhtml\"\e" 1649endif 1650 1651" Cleanup 1652%s:\s\+$::e 1653 1654" Restore old settings (new window first) 1655let &l:foldenable = s:old_fen 1656let &l:foldmethod = s:old_fdm 1657let &report = s:old_report 1658let &title = s:old_title 1659let &icon = s:old_icon 1660let &paste = s:old_paste 1661let &magic = s:old_magic 1662let @/ = s:old_search 1663let &more = s:old_more 1664 1665" switch to original window to restore those settings 1666exe s:orgwin . "wincmd w" 1667 1668if !s:settings.expand_tabs 1669 let &l:isprint = s:old_isprint 1670endif 1671let &l:stl = s:origwin_stl 1672let &l:et = s:old_et 1673let &l:scrollbind = s:old_bind 1674 1675" and back to the new window again to end there 1676exe s:newwin . "wincmd w" 1677 1678let &l:stl = s:newwin_stl 1679exec 'resize' s:old_winheight 1680let &l:winfixheight = s:old_winfixheight 1681 1682let &ls=s:ls 1683 1684" Save a little bit of memory (worth doing?) 1685unlet s:htmlfont s:whitespace 1686unlet s:old_et s:old_paste s:old_icon s:old_report s:old_title s:old_search 1687unlet s:old_magic s:old_more s:old_fdm s:old_fen s:old_winheight 1688unlet! s:old_isprint 1689unlet s:whatterm s:stylelist s:diffstylelist s:lnum s:end s:margin s:fgc s:bgc s:old_winfixheight 1690unlet! s:col s:id s:attr s:len s:line s:new s:expandedtab s:concealinfo s:diff_mode 1691unlet! s:orgwin s:newwin s:orgbufnr s:idx s:i s:offset s:ls s:origwin_stl 1692unlet! s:newwin_stl s:current_syntax 1693if !v:profiling 1694 delfunc s:HtmlColor 1695 delfunc s:HtmlFormat 1696 delfunc s:CSS1 1697 delfunc s:BuildStyleWrapper 1698 if !s:settings.use_css 1699 delfunc s:HtmlOpening 1700 delfunc s:HtmlClosing 1701 endif 1702 if s:settings.dynamic_folds 1703 delfunc s:FoldCompare 1704 endif 1705 1706 if !s:settings.no_progress 1707 delfunc s:ProgressBar 1708 delfunc s:progressbar.paint 1709 delfunc s:progressbar.incr 1710 unlet s:pgb s:progressbar 1711 endif 1712endif 1713 1714unlet! s:new_lnum s:diffattr s:difffillchar s:foldfillchar s:HtmlSpace 1715unlet! s:LeadingSpace s:HtmlEndline s:firstfold s:numcol s:foldcolumn 1716unlet s:foldstack s:allfolds s:foldId s:settings 1717 1718let &cpo = s:cpo_sav 1719unlet! s:cpo_sav 1720 1721" Make sure any patches will probably use consistent indent 1722" vim: ts=8 sw=2 sts=2 noet 1723