xref: /vim-8.2.3635/runtime/syntax/2html.vim (revision 6c391a74)
1071d4279SBram Moolenaar" Vim syntax support file
2349b2fb0SBram Moolenaar" Maintainer: Ben Fritz <[email protected]>
32963456fSBram Moolenaar" Last Change: 2020 Jan 05
4349b2fb0SBram Moolenaar"
5349b2fb0SBram Moolenaar" Additional contributors:
6349b2fb0SBram Moolenaar"
7349b2fb0SBram Moolenaar"             Original by Bram Moolenaar <[email protected]>
8349b2fb0SBram Moolenaar"             Modified by David Ne\v{c}as (Yeti) <[email protected]>
9349b2fb0SBram Moolenaar"             XHTML support by Panagiotis Issaris <[email protected]>
10349b2fb0SBram Moolenaar"             Made w3 compliant by Edd Barrett <[email protected]>
11349b2fb0SBram Moolenaar"             Added html_font. Edd Barrett <[email protected]>
12349b2fb0SBram Moolenaar"             Progress bar based off code from "progressbar widget" plugin by
13349b2fb0SBram Moolenaar"               Andreas Politz, heavily modified:
14349b2fb0SBram Moolenaar"               http://www.vim.org/scripts/script.php?script_id=2006
15349b2fb0SBram Moolenaar"
16349b2fb0SBram Moolenaar"             See Mercurial change logs for more!
17071d4279SBram Moolenaar
18071d4279SBram Moolenaar" Transform a file into HTML, using the current syntax highlighting.
19071d4279SBram Moolenaar
205c73622aSBram Moolenaar" this file uses line continuations
215c73622aSBram Moolenaarlet s:cpo_sav = &cpo
22349b2fb0SBram Moolenaarlet s:ls  = &ls
230c0734d5SBram Moolenaarlet s:ei_sav = &eventignore
246c35beaaSBram Moolenaarset cpo&vim
255c73622aSBram Moolenaar
260c0734d5SBram Moolenaar" HTML filetype can take a while to load/highlight if the destination file
270c0734d5SBram Moolenaar" already exists.
280c0734d5SBram Moolenaarset eventignore+=FileType
290c0734d5SBram Moolenaar
30349b2fb0SBram Moolenaarlet s:end=line('$')
31349b2fb0SBram Moolenaar
32313b7237SBram Moolenaar" Font
33b02cbe34SBram Moolenaarif exists("g:html_font")
3460cce2fbSBram Moolenaar  if type(g:html_font) == type([])
3560cce2fbSBram Moolenaar    let s:htmlfont = "'". join(g:html_font,"','") . "', monospace"
3660cce2fbSBram Moolenaar  else
37076e8b2aSBram Moolenaar    let s:htmlfont = "'". g:html_font . "', monospace"
3860cce2fbSBram Moolenaar  endif
39313b7237SBram Moolenaarelse
40313b7237SBram Moolenaar  let s:htmlfont = "monospace"
41313b7237SBram Moolenaarendif
42313b7237SBram Moolenaar
43076e8b2aSBram Moolenaarlet s:settings = tohtml#GetUserSettings()
445c73622aSBram Moolenaar
450c0734d5SBram Moolenaarif s:settings.use_xhtml
460c0734d5SBram Moolenaar  let s:html5 = 0
470c0734d5SBram Moolenaarelseif s:settings.use_css && !s:settings.no_pre
480c0734d5SBram Moolenaar  let s:html5 = 1
490c0734d5SBram Moolenaarelse
500c0734d5SBram Moolenaar  let s:html5 = 0
510c0734d5SBram Moolenaarendif
520c0734d5SBram Moolenaar
536c35beaaSBram Moolenaarif !exists('s:FOLDED_ID')
546c35beaaSBram Moolenaar  let s:FOLDED_ID  = hlID("Folded")     | lockvar s:FOLDED_ID
556c35beaaSBram Moolenaar  let s:FOLD_C_ID  = hlID("FoldColumn") | lockvar s:FOLD_C_ID
566c35beaaSBram Moolenaar  let s:LINENR_ID  = hlID('LineNr')     | lockvar s:LINENR_ID
576c35beaaSBram Moolenaar  let s:DIFF_D_ID  = hlID("DiffDelete") | lockvar s:DIFF_D_ID
586c35beaaSBram Moolenaar  let s:DIFF_A_ID  = hlID("DiffAdd")    | lockvar s:DIFF_A_ID
596c35beaaSBram Moolenaar  let s:DIFF_C_ID  = hlID("DiffChange") | lockvar s:DIFF_C_ID
606c35beaaSBram Moolenaar  let s:DIFF_T_ID  = hlID("DiffText")   | lockvar s:DIFF_T_ID
616c35beaaSBram Moolenaar  let s:CONCEAL_ID = hlID('Conceal')    | lockvar s:CONCEAL_ID
626c35beaaSBram Moolenaarendif
636c35beaaSBram Moolenaar
648e5af3e5SBram Moolenaar" Whitespace
658e5af3e5SBram Moolenaarif s:settings.pre_wrap
668e5af3e5SBram Moolenaar  let s:whitespace = "white-space: pre-wrap; "
678e5af3e5SBram Moolenaarelse
688e5af3e5SBram Moolenaar  let s:whitespace = ""
698e5af3e5SBram Moolenaarendif
708e5af3e5SBram Moolenaar
716c35beaaSBram Moolenaarif !empty(s:settings.prevent_copy)
726c35beaaSBram Moolenaar  if s:settings.no_invalid
736c35beaaSBram Moolenaar    " User has decided they don't want invalid markup. Still works in
746c35beaaSBram Moolenaar    " OpenOffice, and for text editors, but when pasting into Microsoft Word the
756c35beaaSBram Moolenaar    " input elements get pasted too and they cannot be deleted (at least not
766c35beaaSBram Moolenaar    " easily).
776c35beaaSBram Moolenaar    let s:unselInputType = ""
786c35beaaSBram Moolenaar  else
796c35beaaSBram Moolenaar    " Prevent from copy-pasting the input elements into Microsoft Word where
806c35beaaSBram Moolenaar    " they cannot be deleted easily by deliberately inserting invalid markup.
816c35beaaSBram Moolenaar    let s:unselInputType = " type='invalid_input_type'"
826c35beaaSBram Moolenaar  endif
836c35beaaSBram Moolenaarendif
846c35beaaSBram Moolenaar
850c0734d5SBram Moolenaar" When gui colors are not supported, we can only guess the colors.
860c0734d5SBram Moolenaar" TODO - is this true anymore? Is there a way to ask the terminal what colors
870c0734d5SBram Moolenaar" each number means or read them from some file?
880c0734d5SBram Moolenaarif &termguicolors || has("gui_running")
89071d4279SBram Moolenaar  let s:whatterm = "gui"
90071d4279SBram Moolenaarelse
91071d4279SBram Moolenaar  let s:whatterm = "cterm"
92071d4279SBram Moolenaar  if &t_Co == 8
936c35beaaSBram Moolenaar    let s:cterm_color = {
946c35beaaSBram Moolenaar	    \   0: "#808080", 1: "#ff6060", 2: "#00ff00", 3: "#ffff00",
956c35beaaSBram Moolenaar	    \   4: "#8080ff", 5: "#ff40ff", 6: "#00ffff", 7: "#ffffff"
966c35beaaSBram Moolenaar	    \ }
97071d4279SBram Moolenaar  else
986c35beaaSBram Moolenaar    let s:cterm_color = {
996c35beaaSBram Moolenaar	    \   0: "#000000", 1: "#c00000", 2: "#008000", 3: "#804000",
1006c35beaaSBram Moolenaar	    \   4: "#0000c0", 5: "#c000c0", 6: "#008080", 7: "#c0c0c0",
1016c35beaaSBram Moolenaar	    \   8: "#808080", 9: "#ff6060", 10: "#00ff00", 11: "#ffff00",
1026c35beaaSBram Moolenaar	    \   12: "#8080ff", 13: "#ff40ff", 14: "#00ffff", 15: "#ffffff"
1036c35beaaSBram Moolenaar	    \ }
104313b7237SBram Moolenaar
105313b7237SBram Moolenaar    " Colors for 88 and 256 come from xterm.
106313b7237SBram Moolenaar    if &t_Co == 88
1076c35beaaSBram Moolenaar      call extend(s:cterm_color, {
1086c35beaaSBram Moolenaar	    \   16: "#000000", 17: "#00008b", 18: "#0000cd", 19: "#0000ff",
1096c35beaaSBram Moolenaar	    \   20: "#008b00", 21: "#008b8b", 22: "#008bcd", 23: "#008bff",
1106c35beaaSBram Moolenaar	    \   24: "#00cd00", 25: "#00cd8b", 26: "#00cdcd", 27: "#00cdff",
1116c35beaaSBram Moolenaar	    \   28: "#00ff00", 29: "#00ff8b", 30: "#00ffcd", 31: "#00ffff",
1126c35beaaSBram Moolenaar	    \   32: "#8b0000", 33: "#8b008b", 34: "#8b00cd", 35: "#8b00ff",
1136c35beaaSBram Moolenaar	    \   36: "#8b8b00", 37: "#8b8b8b", 38: "#8b8bcd", 39: "#8b8bff",
1146c35beaaSBram Moolenaar	    \   40: "#8bcd00", 41: "#8bcd8b", 42: "#8bcdcd", 43: "#8bcdff",
1156c35beaaSBram Moolenaar	    \   44: "#8bff00", 45: "#8bff8b", 46: "#8bffcd", 47: "#8bffff",
1166c35beaaSBram Moolenaar	    \   48: "#cd0000", 49: "#cd008b", 50: "#cd00cd", 51: "#cd00ff",
1176c35beaaSBram Moolenaar	    \   52: "#cd8b00", 53: "#cd8b8b", 54: "#cd8bcd", 55: "#cd8bff",
1186c35beaaSBram Moolenaar	    \   56: "#cdcd00", 57: "#cdcd8b", 58: "#cdcdcd", 59: "#cdcdff",
1196c35beaaSBram Moolenaar	    \   60: "#cdff00", 61: "#cdff8b", 62: "#cdffcd", 63: "#cdffff",
1206c35beaaSBram Moolenaar	    \   64: "#ff0000"
1216c35beaaSBram Moolenaar	    \ })
1226c35beaaSBram Moolenaar      call extend(s:cterm_color, {
1236c35beaaSBram Moolenaar	    \   65: "#ff008b", 66: "#ff00cd", 67: "#ff00ff", 68: "#ff8b00",
1246c35beaaSBram Moolenaar	    \   69: "#ff8b8b", 70: "#ff8bcd", 71: "#ff8bff", 72: "#ffcd00",
1256c35beaaSBram Moolenaar	    \   73: "#ffcd8b", 74: "#ffcdcd", 75: "#ffcdff", 76: "#ffff00",
1266c35beaaSBram Moolenaar	    \   77: "#ffff8b", 78: "#ffffcd", 79: "#ffffff", 80: "#2e2e2e",
1276c35beaaSBram Moolenaar	    \   81: "#5c5c5c", 82: "#737373", 83: "#8b8b8b", 84: "#a2a2a2",
1286c35beaaSBram Moolenaar	    \   85: "#b9b9b9", 86: "#d0d0d0", 87: "#e7e7e7"
1296c35beaaSBram Moolenaar	    \ })
130313b7237SBram Moolenaar    elseif &t_Co == 256
1316c35beaaSBram Moolenaar      call extend(s:cterm_color, {
1326c35beaaSBram Moolenaar	    \   16: "#000000", 17: "#00005f", 18: "#000087", 19: "#0000af",
1336c35beaaSBram Moolenaar	    \   20: "#0000d7", 21: "#0000ff", 22: "#005f00", 23: "#005f5f",
1346c35beaaSBram Moolenaar	    \   24: "#005f87", 25: "#005faf", 26: "#005fd7", 27: "#005fff",
1356c35beaaSBram Moolenaar	    \   28: "#008700", 29: "#00875f", 30: "#008787", 31: "#0087af",
1366c35beaaSBram Moolenaar	    \   32: "#0087d7", 33: "#0087ff", 34: "#00af00", 35: "#00af5f",
1376c35beaaSBram Moolenaar	    \   36: "#00af87", 37: "#00afaf", 38: "#00afd7", 39: "#00afff",
1386c35beaaSBram Moolenaar	    \   40: "#00d700", 41: "#00d75f", 42: "#00d787", 43: "#00d7af",
1396c35beaaSBram Moolenaar	    \   44: "#00d7d7", 45: "#00d7ff", 46: "#00ff00", 47: "#00ff5f",
1406c35beaaSBram Moolenaar	    \   48: "#00ff87", 49: "#00ffaf", 50: "#00ffd7", 51: "#00ffff",
1416c35beaaSBram Moolenaar	    \   52: "#5f0000", 53: "#5f005f", 54: "#5f0087", 55: "#5f00af",
1426c35beaaSBram Moolenaar	    \   56: "#5f00d7", 57: "#5f00ff", 58: "#5f5f00", 59: "#5f5f5f",
1436c35beaaSBram Moolenaar	    \   60: "#5f5f87", 61: "#5f5faf", 62: "#5f5fd7", 63: "#5f5fff",
1446c35beaaSBram Moolenaar	    \   64: "#5f8700"
1456c35beaaSBram Moolenaar	    \ })
1466c35beaaSBram Moolenaar      call extend(s:cterm_color, {
1476c35beaaSBram Moolenaar	    \   65: "#5f875f", 66: "#5f8787", 67: "#5f87af", 68: "#5f87d7",
1486c35beaaSBram Moolenaar	    \   69: "#5f87ff", 70: "#5faf00", 71: "#5faf5f", 72: "#5faf87",
1496c35beaaSBram Moolenaar	    \   73: "#5fafaf", 74: "#5fafd7", 75: "#5fafff", 76: "#5fd700",
1506c35beaaSBram Moolenaar	    \   77: "#5fd75f", 78: "#5fd787", 79: "#5fd7af", 80: "#5fd7d7",
1516c35beaaSBram Moolenaar	    \   81: "#5fd7ff", 82: "#5fff00", 83: "#5fff5f", 84: "#5fff87",
1526c35beaaSBram Moolenaar	    \   85: "#5fffaf", 86: "#5fffd7", 87: "#5fffff", 88: "#870000",
1536c35beaaSBram Moolenaar	    \   89: "#87005f", 90: "#870087", 91: "#8700af", 92: "#8700d7",
1546c35beaaSBram Moolenaar	    \   93: "#8700ff", 94: "#875f00", 95: "#875f5f", 96: "#875f87",
1556c35beaaSBram Moolenaar	    \   97: "#875faf", 98: "#875fd7", 99: "#875fff", 100: "#878700",
1566c35beaaSBram Moolenaar	    \   101: "#87875f", 102: "#878787", 103: "#8787af", 104: "#8787d7",
1576c35beaaSBram Moolenaar	    \   105: "#8787ff", 106: "#87af00", 107: "#87af5f", 108: "#87af87",
1586c35beaaSBram Moolenaar	    \   109: "#87afaf", 110: "#87afd7", 111: "#87afff", 112: "#87d700"
1596c35beaaSBram Moolenaar	    \ })
1606c35beaaSBram Moolenaar      call extend(s:cterm_color, {
1616c35beaaSBram Moolenaar	    \   113: "#87d75f", 114: "#87d787", 115: "#87d7af", 116: "#87d7d7",
1626c35beaaSBram Moolenaar	    \   117: "#87d7ff", 118: "#87ff00", 119: "#87ff5f", 120: "#87ff87",
1636c35beaaSBram Moolenaar	    \   121: "#87ffaf", 122: "#87ffd7", 123: "#87ffff", 124: "#af0000",
1646c35beaaSBram Moolenaar	    \   125: "#af005f", 126: "#af0087", 127: "#af00af", 128: "#af00d7",
1656c35beaaSBram Moolenaar	    \   129: "#af00ff", 130: "#af5f00", 131: "#af5f5f", 132: "#af5f87",
1666c35beaaSBram Moolenaar	    \   133: "#af5faf", 134: "#af5fd7", 135: "#af5fff", 136: "#af8700",
1676c35beaaSBram Moolenaar	    \   137: "#af875f", 138: "#af8787", 139: "#af87af", 140: "#af87d7",
1686c35beaaSBram Moolenaar	    \   141: "#af87ff", 142: "#afaf00", 143: "#afaf5f", 144: "#afaf87",
1696c35beaaSBram Moolenaar	    \   145: "#afafaf", 146: "#afafd7", 147: "#afafff", 148: "#afd700",
1706c35beaaSBram Moolenaar	    \   149: "#afd75f", 150: "#afd787", 151: "#afd7af", 152: "#afd7d7",
1716c35beaaSBram Moolenaar	    \   153: "#afd7ff", 154: "#afff00", 155: "#afff5f", 156: "#afff87",
1726c35beaaSBram Moolenaar	    \   157: "#afffaf", 158: "#afffd7"
1736c35beaaSBram Moolenaar	    \ })
1746c35beaaSBram Moolenaar      call extend(s:cterm_color, {
1756c35beaaSBram Moolenaar	    \   159: "#afffff", 160: "#d70000", 161: "#d7005f", 162: "#d70087",
1766c35beaaSBram Moolenaar	    \   163: "#d700af", 164: "#d700d7", 165: "#d700ff", 166: "#d75f00",
1776c35beaaSBram Moolenaar	    \   167: "#d75f5f", 168: "#d75f87", 169: "#d75faf", 170: "#d75fd7",
1786c35beaaSBram Moolenaar	    \   171: "#d75fff", 172: "#d78700", 173: "#d7875f", 174: "#d78787",
1796c35beaaSBram Moolenaar	    \   175: "#d787af", 176: "#d787d7", 177: "#d787ff", 178: "#d7af00",
1806c35beaaSBram Moolenaar	    \   179: "#d7af5f", 180: "#d7af87", 181: "#d7afaf", 182: "#d7afd7",
1816c35beaaSBram Moolenaar	    \   183: "#d7afff", 184: "#d7d700", 185: "#d7d75f", 186: "#d7d787",
1826c35beaaSBram Moolenaar	    \   187: "#d7d7af", 188: "#d7d7d7", 189: "#d7d7ff", 190: "#d7ff00",
1836c35beaaSBram Moolenaar	    \   191: "#d7ff5f", 192: "#d7ff87", 193: "#d7ffaf", 194: "#d7ffd7",
1846c35beaaSBram Moolenaar	    \   195: "#d7ffff", 196: "#ff0000", 197: "#ff005f", 198: "#ff0087",
1856c35beaaSBram Moolenaar	    \   199: "#ff00af", 200: "#ff00d7", 201: "#ff00ff", 202: "#ff5f00",
1866c35beaaSBram Moolenaar	    \   203: "#ff5f5f", 204: "#ff5f87"
1876c35beaaSBram Moolenaar	    \ })
1886c35beaaSBram Moolenaar      call extend(s:cterm_color, {
1896c35beaaSBram Moolenaar	    \   205: "#ff5faf", 206: "#ff5fd7", 207: "#ff5fff", 208: "#ff8700",
1906c35beaaSBram Moolenaar	    \   209: "#ff875f", 210: "#ff8787", 211: "#ff87af", 212: "#ff87d7",
1916c35beaaSBram Moolenaar	    \   213: "#ff87ff", 214: "#ffaf00", 215: "#ffaf5f", 216: "#ffaf87",
1926c35beaaSBram Moolenaar	    \   217: "#ffafaf", 218: "#ffafd7", 219: "#ffafff", 220: "#ffd700",
1936c35beaaSBram Moolenaar	    \   221: "#ffd75f", 222: "#ffd787", 223: "#ffd7af", 224: "#ffd7d7",
1946c35beaaSBram Moolenaar	    \   225: "#ffd7ff", 226: "#ffff00", 227: "#ffff5f", 228: "#ffff87",
1956c35beaaSBram Moolenaar	    \   229: "#ffffaf", 230: "#ffffd7", 231: "#ffffff", 232: "#080808",
1966c35beaaSBram Moolenaar	    \   233: "#121212", 234: "#1c1c1c", 235: "#262626", 236: "#303030",
1976c35beaaSBram Moolenaar	    \   237: "#3a3a3a", 238: "#444444", 239: "#4e4e4e", 240: "#585858",
1986c35beaaSBram Moolenaar	    \   241: "#626262", 242: "#6c6c6c", 243: "#767676", 244: "#808080",
1996c35beaaSBram Moolenaar	    \   245: "#8a8a8a", 246: "#949494", 247: "#9e9e9e", 248: "#a8a8a8",
2006c35beaaSBram Moolenaar	    \   249: "#b2b2b2", 250: "#bcbcbc", 251: "#c6c6c6", 252: "#d0d0d0",
2016c35beaaSBram Moolenaar	    \   253: "#dadada", 254: "#e4e4e4", 255: "#eeeeee"
2026c35beaaSBram Moolenaar	    \ })
203313b7237SBram Moolenaar    endif
204071d4279SBram Moolenaar  endif
205071d4279SBram Moolenaarendif
206071d4279SBram Moolenaar
207071d4279SBram Moolenaar" Return good color specification: in GUI no transformation is done, in
208313b7237SBram Moolenaar" terminal return RGB values of known colors and empty string for unknown
209071d4279SBram Moolenaarif s:whatterm == "gui"
210071d4279SBram Moolenaar  function! s:HtmlColor(color)
211071d4279SBram Moolenaar    return a:color
212071d4279SBram Moolenaar  endfun
213071d4279SBram Moolenaarelse
214071d4279SBram Moolenaar  function! s:HtmlColor(color)
215313b7237SBram Moolenaar    if has_key(s:cterm_color, a:color)
216313b7237SBram Moolenaar      return s:cterm_color[a:color]
217071d4279SBram Moolenaar    else
218071d4279SBram Moolenaar      return ""
219071d4279SBram Moolenaar    endif
220071d4279SBram Moolenaar  endfun
221071d4279SBram Moolenaarendif
222071d4279SBram Moolenaar
2236c35beaaSBram Moolenaar" Find out the background and foreground color for use later
2246c35beaaSBram Moolenaarlet s:fgc = s:HtmlColor(synIDattr(hlID("Normal"), "fg#", s:whatterm))
2256c35beaaSBram Moolenaarlet s:bgc = s:HtmlColor(synIDattr(hlID("Normal"), "bg#", s:whatterm))
2266c35beaaSBram Moolenaarif s:fgc == ""
2276c35beaaSBram Moolenaar  let s:fgc = ( &background == "dark" ? "#ffffff" : "#000000" )
2286c35beaaSBram Moolenaarendif
2296c35beaaSBram Moolenaarif s:bgc == ""
2306c35beaaSBram Moolenaar  let s:bgc = ( &background == "dark" ? "#000000" : "#ffffff" )
2316c35beaaSBram Moolenaarendif
2326c35beaaSBram Moolenaar
233bebca9daSBram Moolenaarif !s:settings.use_css
234071d4279SBram Moolenaar  " Return opening HTML tag for given highlight id
235543b7ef7SBram Moolenaar  function! s:HtmlOpening(id, extra_attrs)
236071d4279SBram Moolenaar    let a = ""
237071d4279SBram Moolenaar    if synIDattr(a:id, "inverse")
238071d4279SBram Moolenaar      " For inverse, we always must set both colors (and exchange them)
239071d4279SBram Moolenaar      let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
240543b7ef7SBram Moolenaar      let a = a . '<span '.a:extra_attrs.'style="background-color: ' . ( x != "" ? x : s:fgc ) . '">'
241071d4279SBram Moolenaar      let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
242071d4279SBram Moolenaar      let a = a . '<font color="' . ( x != "" ? x : s:bgc ) . '">'
243071d4279SBram Moolenaar    else
244071d4279SBram Moolenaar      let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
245543b7ef7SBram Moolenaar      if x != ""
246543b7ef7SBram Moolenaar	let a = a . '<span '.a:extra_attrs.'style="background-color: ' . x . '">'
247543b7ef7SBram Moolenaar      elseif !empty(a:extra_attrs)
248543b7ef7SBram Moolenaar	let a = a . '<span '.a:extra_attrs.'>'
249543b7ef7SBram Moolenaar      endif
250071d4279SBram Moolenaar      let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
251071d4279SBram Moolenaar      if x != "" | let a = a . '<font color="' . x . '">' | endif
252071d4279SBram Moolenaar    endif
253071d4279SBram Moolenaar    if synIDattr(a:id, "bold") | let a = a . "<b>" | endif
254071d4279SBram Moolenaar    if synIDattr(a:id, "italic") | let a = a . "<i>" | endif
255071d4279SBram Moolenaar    if synIDattr(a:id, "underline") | let a = a . "<u>" | endif
256071d4279SBram Moolenaar    return a
257071d4279SBram Moolenaar  endfun
258071d4279SBram Moolenaar
259071d4279SBram Moolenaar  " Return closing HTML tag for given highlight id
260543b7ef7SBram Moolenaar  function! s:HtmlClosing(id, has_extra_attrs)
261071d4279SBram Moolenaar    let a = ""
262071d4279SBram Moolenaar    if synIDattr(a:id, "underline") | let a = a . "</u>" | endif
263071d4279SBram Moolenaar    if synIDattr(a:id, "italic") | let a = a . "</i>" | endif
264071d4279SBram Moolenaar    if synIDattr(a:id, "bold") | let a = a . "</b>" | endif
265071d4279SBram Moolenaar    if synIDattr(a:id, "inverse")
266071d4279SBram Moolenaar      let a = a . '</font></span>'
267071d4279SBram Moolenaar    else
268071d4279SBram Moolenaar      let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
269071d4279SBram Moolenaar      if x != "" | let a = a . '</font>' | endif
270071d4279SBram Moolenaar      let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
271543b7ef7SBram Moolenaar      if x != "" || a:has_extra_attrs | let a = a . '</span>' | endif
272071d4279SBram Moolenaar    endif
273071d4279SBram Moolenaar    return a
274071d4279SBram Moolenaar  endfun
275071d4279SBram Moolenaarendif
276071d4279SBram Moolenaar
2776c35beaaSBram Moolenaar" Use a different function for formatting based on user options. This way we
2786c35beaaSBram Moolenaar" can avoid a lot of logic during the actual execution.
2796c35beaaSBram Moolenaar"
2806c35beaaSBram Moolenaar" Build the function line by line containing only what is needed for the options
2816c35beaaSBram Moolenaar" in use for maximum code sharing with minimal branch logic for greater speed.
2826c35beaaSBram Moolenaar"
2836c35beaaSBram Moolenaar" Note, 'exec' commands do not recognize line continuations, so must concatenate
2846c35beaaSBram Moolenaar" lines rather than continue them.
2856c35beaaSBram Moolenaarif s:settings.use_css
2866c35beaaSBram Moolenaar  " save CSS to a list of rules to add to the output at the end of processing
2876c35beaaSBram Moolenaar
2886c35beaaSBram Moolenaar  " first, get the style names we need
2896c35beaaSBram Moolenaar  let wrapperfunc_lines = [
290543b7ef7SBram Moolenaar	\ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, make_unselectable, unformatted)',
2916c35beaaSBram Moolenaar	\ '',
2926c35beaaSBram Moolenaar	\ '  let l:style_name = synIDattr(a:style_id, "name", s:whatterm)'
2936c35beaaSBram Moolenaar	\ ]
2946c35beaaSBram Moolenaar  if &diff
2956c35beaaSBram Moolenaar    let wrapperfunc_lines += [
2966c35beaaSBram Moolenaar	\ '  let l:diff_style_name = synIDattr(a:diff_style_id, "name", s:whatterm)']
2976c35beaaSBram Moolenaar
2986c35beaaSBram Moolenaar  " Add normal groups and diff groups to separate lists so we can order them to
2996c35beaaSBram Moolenaar  " allow diff highlight to override normal highlight
3006c35beaaSBram Moolenaar
3016c35beaaSBram Moolenaar  " if primary style IS a diff style, grab it from the diff cache instead
3026c35beaaSBram Moolenaar  " (always succeeds because we pre-populate it)
3036c35beaaSBram Moolenaar  let wrapperfunc_lines += [
3046c35beaaSBram Moolenaar	\ '',
3056c35beaaSBram Moolenaar	\ '  if a:style_id == s:DIFF_D_ID || a:style_id == s:DIFF_A_ID ||'.
3066c35beaaSBram Moolenaar	\ '          a:style_id == s:DIFF_C_ID || a:style_id == s:DIFF_T_ID',
3076c35beaaSBram Moolenaar	\ '    let l:saved_style = get(s:diffstylelist,a:style_id)',
3086c35beaaSBram Moolenaar	\ '  else'
3096c35beaaSBram Moolenaar	\ ]
3106c35beaaSBram Moolenaar  endif
3116c35beaaSBram Moolenaar
3126c35beaaSBram Moolenaar  " get primary style info from cache or build it on the fly if not found
3136c35beaaSBram Moolenaar  let wrapperfunc_lines += [
3146c35beaaSBram Moolenaar	\ '    let l:saved_style = get(s:stylelist,a:style_id)',
3156c35beaaSBram Moolenaar	\ '    if type(l:saved_style) == type(0)',
3166c35beaaSBram Moolenaar	\ '      unlet l:saved_style',
3176c35beaaSBram Moolenaar	\ '      let l:saved_style = s:CSS1(a:style_id)',
3186c35beaaSBram Moolenaar	\ '      if l:saved_style != ""',
3196c35beaaSBram Moolenaar	\ '        let l:saved_style = "." . l:style_name . " { " . l:saved_style . "}"',
3206c35beaaSBram Moolenaar	\ '      endif',
3216c35beaaSBram Moolenaar	\ '      let s:stylelist[a:style_id]= l:saved_style',
3226c35beaaSBram Moolenaar	\ '    endif'
3236c35beaaSBram Moolenaar	\ ]
3246c35beaaSBram Moolenaar  if &diff
3256c35beaaSBram Moolenaar    let wrapperfunc_lines += [ '  endif' ]
3266c35beaaSBram Moolenaar  endif
3276c35beaaSBram Moolenaar
3286c35beaaSBram Moolenaar  " Build the wrapper tags around the text. It turns out that caching these
3296c35beaaSBram Moolenaar  " gives pretty much zero performance gain and adds a lot of logic.
3306c35beaaSBram Moolenaar
3316c35beaaSBram Moolenaar  let wrapperfunc_lines += [
3326c35beaaSBram Moolenaar	\ '',
333543b7ef7SBram Moolenaar	\ '  if l:saved_style == "" && empty(a:extra_attrs)'
3346c35beaaSBram Moolenaar	\ ]
3356c35beaaSBram Moolenaar  if &diff
3366c35beaaSBram Moolenaar    let wrapperfunc_lines += [
3376c35beaaSBram Moolenaar	\ '    if a:diff_style_id <= 0'
3386c35beaaSBram Moolenaar	\ ]
3396c35beaaSBram Moolenaar  endif
3406c35beaaSBram Moolenaar  " no surroundings if neither primary nor diff style has any info
3416c35beaaSBram Moolenaar  let wrapperfunc_lines += [
3426c35beaaSBram Moolenaar	\ '       return a:text'
3436c35beaaSBram Moolenaar	\ ]
3446c35beaaSBram Moolenaar  if &diff
3456c35beaaSBram Moolenaar    " no primary style, but diff style
3466c35beaaSBram Moolenaar    let wrapperfunc_lines += [
3476c35beaaSBram Moolenaar	\ '     else',
3486c35beaaSBram Moolenaar	\ '       return "<span class=\"" .l:diff_style_name . "\">".a:text."</span>"',
3496c35beaaSBram Moolenaar	\ '     endif'
3506c35beaaSBram Moolenaar	\ ]
3516c35beaaSBram Moolenaar  endif
3526c35beaaSBram Moolenaar  " open tag for non-empty primary style
3536c35beaaSBram Moolenaar  let wrapperfunc_lines += [
3546c35beaaSBram Moolenaar	\ '  else']
3556c35beaaSBram Moolenaar  " non-empty primary style. handle either empty or non-empty diff style.
3566c35beaaSBram Moolenaar  "
3576c35beaaSBram Moolenaar  " separate the two classes by a space to apply them both if there is a diff
3586c35beaaSBram Moolenaar  " style name, unless the primary style is empty, then just use the diff style
3596c35beaaSBram Moolenaar  " name
3606c35beaaSBram Moolenaar  let diffstyle =
3616c35beaaSBram Moolenaar	  \ (&diff ? '(a:diff_style_id <= 0 ? "" : " ". l:diff_style_name) .'
3626c35beaaSBram Moolenaar	  \        : "")
3636c35beaaSBram Moolenaar  if s:settings.prevent_copy == ""
3646c35beaaSBram Moolenaar    let wrapperfunc_lines += [
365543b7ef7SBram Moolenaar	  \ '    return "<span ".a:extra_attrs."class=\"" . l:style_name .'.diffstyle.'"\">".a:text."</span>"'
3666c35beaaSBram Moolenaar	  \ ]
3676c35beaaSBram Moolenaar  else
3686c35beaaSBram Moolenaar
3690c0734d5SBram Moolenaar    " New method: use generated content in the CSS. The only thing needed here
3700c0734d5SBram Moolenaar    " is a span with no content, with an attribute holding the desired text.
3710c0734d5SBram Moolenaar    "
3720c0734d5SBram Moolenaar    " Old method: use an <input> element when text is unsectable. This is still
3730c0734d5SBram Moolenaar    " used in conditional comments for Internet Explorer, where the new method
3740c0734d5SBram Moolenaar    " doesn't work.
3756c35beaaSBram Moolenaar    "
3766c35beaaSBram Moolenaar    " Wrap the <input> in a <span> to allow fixing the stupid bug in some fonts
3776c35beaaSBram Moolenaar    " which cause browsers to display a 1px gap between lines when these
3786c35beaaSBram Moolenaar    " <input>s have a background color (maybe not really a bug, this isn't
3796c35beaaSBram Moolenaar    " well-defined)
3806c35beaaSBram Moolenaar    "
3816c35beaaSBram Moolenaar    " use strwidth, because we care only about how many character boxes are
3826c35beaaSBram Moolenaar    " needed to size the input, we don't care how many characters (including
3836c35beaaSBram Moolenaar    " separately counted composing chars, from strchars()) or bytes (from
3846c35beaaSBram Moolenaar    " len())the string contains. strdisplaywidth() is not needed because none of
3856c35beaaSBram Moolenaar    " the unselectable groups can contain tab characters (fold column, fold
3866c35beaaSBram Moolenaar    " text, line number).
3876c35beaaSBram Moolenaar    "
3886c35beaaSBram Moolenaar    " Note, if maxlength property needs to be added in the future, it will need
3896c35beaaSBram Moolenaar    " to use strchars(), because HTML specifies that the maxlength parameter
3906c35beaaSBram Moolenaar    " uses the number of unique codepoints for its limit.
3916c35beaaSBram Moolenaar    let wrapperfunc_lines += [
3926c35beaaSBram Moolenaar	  \   '    if a:make_unselectable',
3930c0734d5SBram Moolenaar	  \   '      return "<span ".a:extra_attrs."class=\"" . l:style_name .'.diffstyle.'"\"'
3940c0734d5SBram Moolenaar	  \ ]
3950c0734d5SBram Moolenaar    if s:settings.use_input_for_pc !=# 'all'
3960c0734d5SBram Moolenaar      let wrapperfunc_lines[-1] .= ' " . "data-" . l:style_name . "-content=\"".a:text."\"'
3970c0734d5SBram Moolenaar    endif
3980c0734d5SBram Moolenaar    let wrapperfunc_lines[-1] .= '>'
3990c0734d5SBram Moolenaar    if s:settings.use_input_for_pc !=# 'none'
4000c0734d5SBram Moolenaar      let wrapperfunc_lines[-1] .=
4016c35beaaSBram Moolenaar	    \                '<input'.s:unselInputType.' class=\"" . l:style_name .'.diffstyle.'"\"'.
4026c35beaaSBram Moolenaar	    \                 ' value=\"".substitute(a:unformatted,''\s\+$'',"","")."\"'.
4036c35beaaSBram Moolenaar	    \                 ' onselect=''this.blur(); return false;'''.
4046c35beaaSBram Moolenaar	    \                 ' onmousedown=''this.blur(); return false;'''.
4056c35beaaSBram Moolenaar	    \                 ' onclick=''this.blur(); return false;'''.
4066c35beaaSBram Moolenaar	    \                 ' readonly=''readonly'''.
4076c35beaaSBram Moolenaar	    \                 ' size=\"".strwidth(a:unformatted)."\"'.
4080c0734d5SBram Moolenaar	    \                 (s:settings.use_xhtml ? '/' : '').'>'
4090c0734d5SBram Moolenaar    endif
4100c0734d5SBram Moolenaar    let wrapperfunc_lines[-1] .= '</span>"'
4110c0734d5SBram Moolenaar    let wrapperfunc_lines += [
4126c35beaaSBram Moolenaar	  \ '    else',
413543b7ef7SBram Moolenaar	  \ '      return "<span ".a:extra_attrs."class=\"" . l:style_name .'. diffstyle .'"\">".a:text."</span>"'
4146c35beaaSBram Moolenaar	  \ ]
4156c35beaaSBram Moolenaar  endif
4166c35beaaSBram Moolenaar  let wrapperfunc_lines += [
4176c35beaaSBram Moolenaar	\ '  endif',
4186c35beaaSBram Moolenaar	\ 'endfun'
4196c35beaaSBram Moolenaar	\ ]
4206c35beaaSBram Moolenaarelse
4216c35beaaSBram Moolenaar  " Non-CSS method just needs the wrapper.
4226c35beaaSBram Moolenaar  "
4236c35beaaSBram Moolenaar  " Functions used to get opening/closing automatically return null strings if
4246c35beaaSBram Moolenaar  " no styles exist.
4256c35beaaSBram Moolenaar  if &diff
4266c35beaaSBram Moolenaar    let wrapperfunc_lines = [
427543b7ef7SBram Moolenaar	  \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2)',
428543b7ef7SBram Moolenaar	  \ '  return s:HtmlOpening(a:style_id, a:extra_attrs).(a:diff_style_id <= 0 ? "" :'.
429543b7ef7SBram Moolenaar	  \                                     's:HtmlOpening(a:diff_style_id, "")).a:text.'.
430543b7ef7SBram Moolenaar	  \   '(a:diff_style_id <= 0 ? "" : s:HtmlClosing(a:diff_style_id, 0)).s:HtmlClosing(a:style_id, !empty(a:extra_attrs))',
4316c35beaaSBram Moolenaar	  \ 'endfun'
4326c35beaaSBram Moolenaar	  \ ]
4336c35beaaSBram Moolenaar  else
4346c35beaaSBram Moolenaar    let wrapperfunc_lines = [
435543b7ef7SBram Moolenaar	  \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2)',
436543b7ef7SBram Moolenaar	  \ '  return s:HtmlOpening(a:style_id, a:extra_attrs).a:text.s:HtmlClosing(a:style_id, !empty(a:extra_attrs))',
4376c35beaaSBram Moolenaar	  \ 'endfun'
4386c35beaaSBram Moolenaar	  \ ]
4396c35beaaSBram Moolenaar  endif
4406c35beaaSBram Moolenaarendif
4416c35beaaSBram Moolenaar
4426c35beaaSBram Moolenaar" create the function we built line by line above
4436c35beaaSBram Moolenaarexec join(wrapperfunc_lines, "\n")
4446c35beaaSBram Moolenaar
4456c35beaaSBram Moolenaarlet s:diff_mode = &diff
4466c35beaaSBram Moolenaar
44735a9aaabSBram Moolenaar" Return HTML valid characters enclosed in a span of class style_name with
44835a9aaabSBram Moolenaar" unprintable characters expanded and double spaces replaced as necessary.
4496c35beaaSBram Moolenaar"
4506c35beaaSBram Moolenaar" TODO: eliminate unneeded logic like done for BuildStyleWrapper
451543b7ef7SBram Moolenaarfunction! s:HtmlFormat(text, style_id, diff_style_id, extra_attrs, make_unselectable)
45235a9aaabSBram Moolenaar  " Replace unprintable characters
4536c35beaaSBram Moolenaar  let unformatted = strtrans(a:text)
45435a9aaabSBram Moolenaar
4556c35beaaSBram Moolenaar  let formatted = unformatted
4568ada2ccaSBram Moolenaar
45735a9aaabSBram Moolenaar  " Replace the reserved html characters
4582a8a3ecbSBram Moolenaar  let formatted = substitute(formatted, '&', '\&amp;',  'g')
4592a8a3ecbSBram Moolenaar  let formatted = substitute(formatted, '<', '\&lt;',   'g')
4602a8a3ecbSBram Moolenaar  let formatted = substitute(formatted, '>', '\&gt;',   'g')
4612a8a3ecbSBram Moolenaar  let formatted = substitute(formatted, '"', '\&quot;', 'g')
4626c35beaaSBram Moolenaar  " &apos; is not valid in HTML but it is in XHTML, so just use the numeric
4636c35beaaSBram Moolenaar  " reference for it instead. Needed because it could appear in quotes
4646c35beaaSBram Moolenaar  " especially if unselectable regions is turned on.
4656c35beaaSBram Moolenaar  let formatted = substitute(formatted, '"', '\&#0039;', 'g')
4662a8a3ecbSBram Moolenaar
4672a8a3ecbSBram Moolenaar  " Replace a "form feed" character with HTML to do a page break
4686c35beaaSBram Moolenaar  " TODO: need to prevent this in unselectable areas? Probably it should never
4696c35beaaSBram Moolenaar  " BE in an unselectable area...
4702a8a3ecbSBram Moolenaar  let formatted = substitute(formatted, "\x0c", '<hr class="PAGE-BREAK">', 'g')
4712a8a3ecbSBram Moolenaar
4728df7f888SBram Moolenaar  " Replace double spaces, leading spaces, and trailing spaces if needed
47335a9aaabSBram Moolenaar  if ' ' != s:HtmlSpace
47435a9aaabSBram Moolenaar    let formatted = substitute(formatted, '  ', s:HtmlSpace . s:HtmlSpace, 'g')
4758424a624SBram Moolenaar    let formatted = substitute(formatted, '^ ', s:HtmlSpace, 'g')
4768df7f888SBram Moolenaar    let formatted = substitute(formatted, ' \+$', s:HtmlSpace, 'g')
47735a9aaabSBram Moolenaar  endif
47835a9aaabSBram Moolenaar
4796c35beaaSBram Moolenaar  " Enclose in the correct format
480543b7ef7SBram Moolenaar  return s:BuildStyleWrapper(a:style_id, a:diff_style_id, a:extra_attrs, formatted, a:make_unselectable, unformatted)
48135a9aaabSBram Moolenaarendfun
48235a9aaabSBram Moolenaar
4836c35beaaSBram Moolenaar" set up functions to call HtmlFormat in certain ways based on whether the
4846c35beaaSBram Moolenaar" element is supposed to be unselectable or not
4856c35beaaSBram Moolenaarif s:settings.prevent_copy =~# 'n'
486543b7ef7SBram Moolenaar  if s:settings.number_lines
48731c31679SBram Moolenaar    if s:settings.line_ids
488543b7ef7SBram Moolenaar      function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
489543b7ef7SBram Moolenaar	if a:lnr > 0
49031c31679SBram Moolenaar	  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)
491543b7ef7SBram Moolenaar	else
492543b7ef7SBram Moolenaar	  return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)
493543b7ef7SBram Moolenaar	endif
4946c35beaaSBram Moolenaar      endfun
4956c35beaaSBram Moolenaar    else
49631c31679SBram Moolenaar      function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
49731c31679SBram Moolenaar	return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)
49831c31679SBram Moolenaar      endfun
49931c31679SBram Moolenaar    endif
50031c31679SBram Moolenaar  elseif s:settings.line_ids
501543b7ef7SBram Moolenaar    " if lines are not being numbered the only reason this function gets called
502*6c391a74SBram Moolenaar    " is to put the line IDs on each line; "text" will be empty but lnr will
503543b7ef7SBram Moolenaar    " always be non-zero, however we don't want to use the <input> because that
504543b7ef7SBram Moolenaar    " won't work as nice for empty text
505543b7ef7SBram Moolenaar    function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
50631c31679SBram Moolenaar      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)
507543b7ef7SBram Moolenaar    endfun
508543b7ef7SBram Moolenaar  endif
509543b7ef7SBram Moolenaarelse
51031c31679SBram Moolenaar  if s:settings.line_ids
511543b7ef7SBram Moolenaar    function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
512543b7ef7SBram Moolenaar      if a:lnr > 0
51331c31679SBram Moolenaar	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)
514543b7ef7SBram Moolenaar      else
515543b7ef7SBram Moolenaar	return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)
516543b7ef7SBram Moolenaar      endif
5176c35beaaSBram Moolenaar    endfun
51831c31679SBram Moolenaar  else
51931c31679SBram Moolenaar    function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
52031c31679SBram Moolenaar      return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)
52131c31679SBram Moolenaar    endfun
52231c31679SBram Moolenaar  endif
5236c35beaaSBram Moolenaarendif
5246c35beaaSBram Moolenaarif s:settings.prevent_copy =~# 'd'
5256c35beaaSBram Moolenaar  function! s:HtmlFormat_d(text, style_id, diff_style_id)
526543b7ef7SBram Moolenaar    return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)
5276c35beaaSBram Moolenaar  endfun
5286c35beaaSBram Moolenaarelse
5296c35beaaSBram Moolenaar  function! s:HtmlFormat_d(text, style_id, diff_style_id)
530543b7ef7SBram Moolenaar    return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)
5316c35beaaSBram Moolenaar  endfun
5326c35beaaSBram Moolenaarendif
5336c35beaaSBram Moolenaarif s:settings.prevent_copy =~# 'f'
5340c0734d5SBram Moolenaar  if s:settings.use_input_for_pc ==# 'none'
5350c0734d5SBram Moolenaar    " Simply space-pad to the desired width inside the generated content (note
5360c0734d5SBram Moolenaar    " that the FoldColumn definition includes a whitespace:pre rule)
5370c0734d5SBram Moolenaar    function! s:FoldColumn_build(char, len, numfill, char2, class, click)
5380c0734d5SBram Moolenaar      return "<a href='#' class='".a:class."' onclick='".a:click."' data-FoldColumn-content='".
5390c0734d5SBram Moolenaar	    \ repeat(a:char, a:len).a:char2.repeat(' ', a:numfill).
5400c0734d5SBram Moolenaar	    \ "'></a>"
5410c0734d5SBram Moolenaar    endfun
5420c0734d5SBram Moolenaar    function! s:FoldColumn_fill()
5430c0734d5SBram Moolenaar      return s:HtmlFormat(repeat(' ', s:foldcolumn), s:FOLD_C_ID, 0, "", 1)
5440c0734d5SBram Moolenaar    endfun
5450c0734d5SBram Moolenaar  else
5466c35beaaSBram Moolenaar    " Note the <input> elements for fill spaces will have a single space for
5476c35beaaSBram Moolenaar    " content, to allow active cursor CSS selection to work.
5486c35beaaSBram Moolenaar    "
5496c35beaaSBram Moolenaar    " Wrap the whole thing in a span for the 1px padding workaround for gaps.
5500c0734d5SBram Moolenaar    "
5510c0734d5SBram Moolenaar    " Build the function line by line containing only what is needed for the
5520c0734d5SBram Moolenaar    " options in use for maximum code sharing with minimal branch logic for
5530c0734d5SBram Moolenaar    " greater speed.
5540c0734d5SBram Moolenaar    "
5550c0734d5SBram Moolenaar    " Note, 'exec' commands do not recognize line continuations, so must
5560c0734d5SBram Moolenaar    " concatenate lines rather than continue them.
5570c0734d5SBram Moolenaar    let build_fun_lines = [
5580c0734d5SBram Moolenaar	  \ 'function! s:FoldColumn_build(char, len, numfill, char2, class, click)',
5590c0734d5SBram Moolenaar	  \ '  let l:input_open = "<input readonly=''readonly''".s:unselInputType.'.
5600c0734d5SBram Moolenaar	  \ '          " onselect=''this.blur(); return false;''".'.
5610c0734d5SBram Moolenaar	  \ '          " onmousedown=''this.blur(); ".a:click." return false;''".'.
5620c0734d5SBram Moolenaar	  \ '          " onclick=''return false;'' size=''".'.
5630c0734d5SBram Moolenaar	  \ '          string(a:len + (empty(a:char2) ? 0 : 1) + a:numfill) .'.
5640c0734d5SBram Moolenaar	  \ '          "'' "',
5650c0734d5SBram Moolenaar	  \ '  let l:common_attrs = "class=''FoldColumn'' value=''"',
5660c0734d5SBram Moolenaar	  \ '  let l:input_close = (s:settings.use_xhtml ? "'' />" : "''>")'
5670c0734d5SBram Moolenaar	  \ ]
5680c0734d5SBram Moolenaar    if s:settings.use_input_for_pc ==# 'fallback'
5690c0734d5SBram Moolenaar      let build_fun_lines += [
5700c0734d5SBram Moolenaar	    \ '  let l:gen_content_link ='.
5710c0734d5SBram Moolenaar	    \ '          "<a href=''#'' class=''FoldColumn'' onclick=''".a:click."'' data-FoldColumn-content=''".'.
5720c0734d5SBram Moolenaar	    \ '          repeat(a:char, a:len).a:char2.repeat('' '', a:numfill).'.
5730c0734d5SBram Moolenaar	    \ '          "''></a>"'
5740c0734d5SBram Moolenaar	    \ ]
5750c0734d5SBram Moolenaar    endif
5760c0734d5SBram Moolenaar    let build_fun_lines += [
5770c0734d5SBram Moolenaar	  \ '  return "<span class=''".a:class."''>".'.
5780c0734d5SBram Moolenaar	  \ '          l:input_open.l:common_attrs.repeat(a:char, a:len).(a:char2).'.
5790c0734d5SBram Moolenaar	  \ '          l:input_close.'.
5800c0734d5SBram Moolenaar	  \ (s:settings.use_input_for_pc ==# 'fallback' ? 'l:gen_content_link.' : "").
5810c0734d5SBram Moolenaar	  \ '          "</span>"',
5820c0734d5SBram Moolenaar	  \ 'endfun'
5830c0734d5SBram Moolenaar	  \ ]
5840c0734d5SBram Moolenaar    " create the function we built line by line above
5850c0734d5SBram Moolenaar    exec join(build_fun_lines, "\n")
5860c0734d5SBram Moolenaar
5876c35beaaSBram Moolenaar    function! s:FoldColumn_fill()
5886c35beaaSBram Moolenaar      return s:FoldColumn_build(' ', s:foldcolumn, 0, '', 'FoldColumn', '')
5896c35beaaSBram Moolenaar    endfun
5900c0734d5SBram Moolenaar  endif
5916c35beaaSBram Moolenaarelse
5926c35beaaSBram Moolenaar  " For normal fold columns, simply space-pad to the desired width (note that
5936c35beaaSBram Moolenaar  " the FoldColumn definition includes a whitespace:pre rule)
5946c35beaaSBram Moolenaar  function! s:FoldColumn_build(char, len, numfill, char2, class, click)
5956c35beaaSBram Moolenaar    return "<a href='#' class='".a:class."' onclick='".a:click."'>".
5966c35beaaSBram Moolenaar	  \ repeat(a:char, a:len).a:char2.repeat(' ', a:numfill).
5976c35beaaSBram Moolenaar	  \ "</a>"
5986c35beaaSBram Moolenaar  endfun
5996c35beaaSBram Moolenaar  function! s:FoldColumn_fill()
600543b7ef7SBram Moolenaar    return s:HtmlFormat(repeat(' ', s:foldcolumn), s:FOLD_C_ID, 0, "", 0)
6016c35beaaSBram Moolenaar  endfun
6026c35beaaSBram Moolenaarendif
6036c35beaaSBram Moolenaarif s:settings.prevent_copy =~# 't'
6046c35beaaSBram Moolenaar  " put an extra empty span at the end for dynamic folds, so the linebreak can
6056c35beaaSBram Moolenaar  " be surrounded. Otherwise do it as normal.
6066c35beaaSBram Moolenaar  "
6076c35beaaSBram Moolenaar  " TODO: isn't there a better way to do this, than placing it here and using a
6086c35beaaSBram Moolenaar  " substitute later?
6096c35beaaSBram Moolenaar  if s:settings.dynamic_folds
6106c35beaaSBram Moolenaar    function! s:HtmlFormat_t(text, style_id, diff_style_id)
611543b7ef7SBram Moolenaar      return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1) .
612543b7ef7SBram Moolenaar	    \ s:HtmlFormat("", a:style_id, 0, "", 0)
6136c35beaaSBram Moolenaar    endfun
6146c35beaaSBram Moolenaar  else
6156c35beaaSBram Moolenaar    function! s:HtmlFormat_t(text, style_id, diff_style_id)
616543b7ef7SBram Moolenaar      return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)
6176c35beaaSBram Moolenaar    endfun
6186c35beaaSBram Moolenaar  endif
6196c35beaaSBram Moolenaarelse
6206c35beaaSBram Moolenaar  function! s:HtmlFormat_t(text, style_id, diff_style_id)
621543b7ef7SBram Moolenaar    return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)
6226c35beaaSBram Moolenaar  endfun
6236c35beaaSBram Moolenaarendif
6246c35beaaSBram Moolenaar
625071d4279SBram Moolenaar" Return CSS style describing given highlight id (can be empty)
626071d4279SBram Moolenaarfunction! s:CSS1(id)
627071d4279SBram Moolenaar  let a = ""
628071d4279SBram Moolenaar  if synIDattr(a:id, "inverse")
629071d4279SBram Moolenaar    " For inverse, we always must set both colors (and exchange them)
630071d4279SBram Moolenaar    let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
631071d4279SBram Moolenaar    let a = a . "color: " . ( x != "" ? x : s:bgc ) . "; "
632071d4279SBram Moolenaar    let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
633071d4279SBram Moolenaar    let a = a . "background-color: " . ( x != "" ? x : s:fgc ) . "; "
634071d4279SBram Moolenaar  else
635071d4279SBram Moolenaar    let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
636071d4279SBram Moolenaar    if x != "" | let a = a . "color: " . x . "; " | endif
637071d4279SBram Moolenaar    let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
6386c35beaaSBram Moolenaar    if x != ""
6396c35beaaSBram Moolenaar      let a = a . "background-color: " . x . "; "
6406c35beaaSBram Moolenaar      " stupid hack because almost every browser seems to have at least one font
6416c35beaaSBram Moolenaar      " which shows 1px gaps between lines which have background
6426c35beaaSBram Moolenaar      let a = a . "padding-bottom: 1px; "
6436c35beaaSBram Moolenaar    elseif (a:id == s:FOLDED_ID || a:id == s:LINENR_ID || a:id == s:FOLD_C_ID) && !empty(s:settings.prevent_copy)
6446c35beaaSBram Moolenaar      " input elements default to a different color than the rest of the page
6456c35beaaSBram Moolenaar      let a = a . "background-color: " . s:bgc . "; "
6466c35beaaSBram Moolenaar    endif
647071d4279SBram Moolenaar  endif
648071d4279SBram Moolenaar  if synIDattr(a:id, "bold") | let a = a . "font-weight: bold; " | endif
649071d4279SBram Moolenaar  if synIDattr(a:id, "italic") | let a = a . "font-style: italic; " | endif
650071d4279SBram Moolenaar  if synIDattr(a:id, "underline") | let a = a . "text-decoration: underline; " | endif
651071d4279SBram Moolenaar  return a
652071d4279SBram Moolenaarendfun
653071d4279SBram Moolenaar
654076e8b2aSBram Moolenaarif s:settings.dynamic_folds
6555c73622aSBram Moolenaar  " compares two folds as stored in our list of folds
6565c73622aSBram Moolenaar  " A fold is "less" than another if it starts at an earlier line number,
6575c73622aSBram Moolenaar  " or ends at a later line number, ties broken by fold level
6585c73622aSBram Moolenaar  function! s:FoldCompare(f1, f2)
6595c73622aSBram Moolenaar    if a:f1.firstline != a:f2.firstline
6605c73622aSBram Moolenaar      " put it before if it starts earlier
6615c73622aSBram Moolenaar      return a:f1.firstline - a:f2.firstline
6625c73622aSBram Moolenaar    elseif a:f1.lastline != a:f2.lastline
6635c73622aSBram Moolenaar      " put it before if it ends later
6645c73622aSBram Moolenaar      return a:f2.lastline - a:f1.lastline
6655c73622aSBram Moolenaar    else
6665c73622aSBram Moolenaar      " if folds begin and end on the same lines, put lowest fold level first
6675c73622aSBram Moolenaar      return a:f1.level - a:f2.level
6685c73622aSBram Moolenaar    endif
6695c73622aSBram Moolenaar  endfunction
6705c73622aSBram Moolenaar
6715c73622aSBram Moolenaarendif
6725c73622aSBram Moolenaar
673071d4279SBram Moolenaar
674071d4279SBram Moolenaar" Set some options to make it work faster.
675071d4279SBram Moolenaar" Don't report changes for :substitute, there will be many of them.
6768df7f888SBram Moolenaar" Don't change other windows; turn off scroll bind temporarily
677071d4279SBram Moolenaarlet s:old_title = &title
678071d4279SBram Moolenaarlet s:old_icon = &icon
679071d4279SBram Moolenaarlet s:old_et = &l:et
6808df7f888SBram Moolenaarlet s:old_bind = &l:scrollbind
681071d4279SBram Moolenaarlet s:old_report = &report
682071d4279SBram Moolenaarlet s:old_search = @/
683349b2fb0SBram Moolenaarlet s:old_more = &more
684071d4279SBram Moolenaarset notitle noicon
685071d4279SBram Moolenaarsetlocal et
686349b2fb0SBram Moolenaarset nomore
687071d4279SBram Moolenaarset report=1000000
6888df7f888SBram Moolenaarsetlocal noscrollbind
689071d4279SBram Moolenaar
6907510fe74SBram Moolenaarif exists(':ownsyntax') && exists('w:current_syntax')
6917510fe74SBram Moolenaar  let s:current_syntax = w:current_syntax
6927510fe74SBram Moolenaarelseif exists('b:current_syntax')
6937510fe74SBram Moolenaar  let s:current_syntax = b:current_syntax
6947510fe74SBram Moolenaarelse
6957510fe74SBram Moolenaar  let s:current_syntax = 'none'
6967510fe74SBram Moolenaarendif
6977510fe74SBram Moolenaar
6987510fe74SBram Moolenaarif s:current_syntax == ''
6997510fe74SBram Moolenaar  let s:current_syntax = 'none'
7007510fe74SBram Moolenaarendif
7017510fe74SBram Moolenaar
702f0d58efcSBram Moolenaar" If the user is sourcing this script directly then the plugin version isn't
703f0d58efcSBram Moolenaar" known because the main plugin script didn't load. In the usual case where the
704f0d58efcSBram Moolenaar" user still has the full Vim runtime installed, or has this full plugin
705f0d58efcSBram Moolenaar" installed in a package or something, then we can extract the version from the
706f0d58efcSBram Moolenaar" main plugin file at it's usual spot relative to this file. Otherwise the user
707f0d58efcSBram Moolenaar" is assembling their runtime piecemeal and we have no idea what versions of
708f0d58efcSBram Moolenaar" other files may be present so don't even try to make a guess or assume the
709f0d58efcSBram Moolenaar" presence of other specific files with specific meaning.
710f0d58efcSBram Moolenaar"
711f0d58efcSBram Moolenaar" We don't want to actually source the main plugin file here because the user
712f0d58efcSBram Moolenaar" may have a good reason not to (e.g. they define their own TOhtml command or
713f0d58efcSBram Moolenaar" something).
714f0d58efcSBram Moolenaar"
715f0d58efcSBram Moolenaar" If this seems way too complicated and convoluted, it is. Probably I should
716f0d58efcSBram Moolenaar" have put the version information in the autoload file from the start. But the
717f0d58efcSBram Moolenaar" version has been in the global variable for so long that changing it could
718f0d58efcSBram Moolenaar" break a lot of user scripts.
719f0d58efcSBram Moolenaarif exists("g:loaded_2html_plugin")
720f0d58efcSBram Moolenaar  let s:pluginversion = g:loaded_2html_plugin
721f0d58efcSBram Moolenaarelse
722f0d58efcSBram Moolenaar  if !exists("g:unloaded_tohtml_plugin")
723f0d58efcSBram Moolenaar    let s:main_plugin_path = expand("<sfile>:p:h:h")."/plugin/tohtml.vim"
724f0d58efcSBram Moolenaar    if filereadable(s:main_plugin_path)
725f0d58efcSBram Moolenaar      let s:lines = readfile(s:main_plugin_path, "", 20)
726f0d58efcSBram Moolenaar      call filter(s:lines, 'v:val =~ "loaded_2html_plugin = "')
727f0d58efcSBram Moolenaar      if empty(s:lines)
728f0d58efcSBram Moolenaar	let g:unloaded_tohtml_plugin = "unknown"
729f0d58efcSBram Moolenaar      else
730f0d58efcSBram Moolenaar	let g:unloaded_tohtml_plugin = substitute(s:lines[0], '.*loaded_2html_plugin = \([''"]\)\(\%(\1\@!.\)\+\)\1', '\2', '')
731f0d58efcSBram Moolenaar      endif
732f0d58efcSBram Moolenaar      unlet s:lines
733f0d58efcSBram Moolenaar    else
734f0d58efcSBram Moolenaar      let g:unloaded_tohtml_plugin = "unknown"
735f0d58efcSBram Moolenaar    endif
736f0d58efcSBram Moolenaar    unlet s:main_plugin_path
737f0d58efcSBram Moolenaar  endif
738f0d58efcSBram Moolenaar  let s:pluginversion = g:unloaded_tohtml_plugin
739f0d58efcSBram Moolenaarendif
740f0d58efcSBram Moolenaar
741071d4279SBram Moolenaar" Split window to create a buffer with the HTML file.
742071d4279SBram Moolenaarlet s:orgbufnr = winbufnr(0)
743349b2fb0SBram Moolenaarlet s:origwin_stl = &l:stl
744071d4279SBram Moolenaarif expand("%") == ""
745543b7ef7SBram Moolenaar  if exists('g:html_diff_win_num')
746543b7ef7SBram Moolenaar    exec 'new Untitled_win'.g:html_diff_win_num.'.'.(s:settings.use_xhtml ? 'x' : '').'html'
747543b7ef7SBram Moolenaar  else
748076e8b2aSBram Moolenaar    exec 'new Untitled.'.(s:settings.use_xhtml ? 'x' : '').'html'
749543b7ef7SBram Moolenaar  endif
750071d4279SBram Moolenaarelse
751076e8b2aSBram Moolenaar  exec 'new %.'.(s:settings.use_xhtml ? 'x' : '').'html'
752071d4279SBram Moolenaarendif
753349b2fb0SBram Moolenaar
754349b2fb0SBram Moolenaar" Resize the new window to very small in order to make it draw faster
755349b2fb0SBram Moolenaarlet s:old_winheight = winheight(0)
756349b2fb0SBram Moolenaarlet s:old_winfixheight = &l:winfixheight
757349b2fb0SBram Moolenaarif s:old_winheight > 2
758349b2fb0SBram Moolenaar  resize 1 " leave enough room to view one line at a time
759349b2fb0SBram Moolenaar  norm! G
760349b2fb0SBram Moolenaar  norm! zt
761349b2fb0SBram Moolenaarendif
762349b2fb0SBram Moolenaarsetlocal winfixheight
763349b2fb0SBram Moolenaar
764349b2fb0SBram Moolenaarlet s:newwin_stl = &l:stl
765349b2fb0SBram Moolenaar
766349b2fb0SBram Moolenaar" on the new window, set the least time-consuming fold method
7678df7f888SBram Moolenaarlet s:old_fen = &foldenable
768349b2fb0SBram Moolenaarsetlocal foldmethod=manual
7698df7f888SBram Moolenaarsetlocal nofoldenable
770349b2fb0SBram Moolenaar
771071d4279SBram Moolenaarlet s:newwin = winnr()
772071d4279SBram Moolenaarlet s:orgwin = bufwinnr(s:orgbufnr)
773071d4279SBram Moolenaar
774349b2fb0SBram Moolenaarsetlocal modifiable
775071d4279SBram Moolenaar%d
776071d4279SBram Moolenaarlet s:old_paste = &paste
777071d4279SBram Moolenaarset paste
778071d4279SBram Moolenaarlet s:old_magic = &magic
779071d4279SBram Moolenaarset magic
780071d4279SBram Moolenaar
781166af9bbSBram Moolenaar" set the fileencoding to match the charset we'll be using
782166af9bbSBram Moolenaarlet &l:fileencoding=s:settings.vim_encoding
783166af9bbSBram Moolenaar
784166af9bbSBram Moolenaar" According to http://www.w3.org/TR/html4/charset.html#doc-char-set, the byte
785166af9bbSBram Moolenaar" order mark is highly recommend on the web when using multibyte encodings. But,
786166af9bbSBram Moolenaar" it is not a good idea to include it on UTF-8 files. Otherwise, let Vim
787166af9bbSBram Moolenaar" determine when it is actually inserted.
788166af9bbSBram Moolenaarif s:settings.vim_encoding == 'utf-8'
789166af9bbSBram Moolenaar  setlocal nobomb
790166af9bbSBram Moolenaarelse
791166af9bbSBram Moolenaar  setlocal bomb
792166af9bbSBram Moolenaarendif
793166af9bbSBram Moolenaar
794349b2fb0SBram Moolenaarlet s:lines = []
795349b2fb0SBram Moolenaar
796076e8b2aSBram Moolenaarif s:settings.use_xhtml
797bebca9daSBram Moolenaar  if s:settings.encoding != ""
798bebca9daSBram Moolenaar    call add(s:lines, "<?xml version=\"1.0\" encoding=\"" . s:settings.encoding . "\"?>")
7991cd871b5SBram Moolenaar  else
800349b2fb0SBram Moolenaar    call add(s:lines, "<?xml version=\"1.0\"?>")
8011cd871b5SBram Moolenaar  endif
80235a9aaabSBram Moolenaar  let s:tag_close = ' />'
803071d4279SBram Moolenaarelse
80435a9aaabSBram Moolenaar  let s:tag_close = '>'
80535a9aaabSBram Moolenaarendif
80635a9aaabSBram Moolenaar
80735a9aaabSBram Moolenaarlet s:HtmlSpace = ' '
808c1e37901SBram Moolenaarlet s:LeadingSpace = ' '
80935a9aaabSBram Moolenaarlet s:HtmlEndline = ''
810076e8b2aSBram Moolenaarif s:settings.no_pre
81135a9aaabSBram Moolenaar  let s:HtmlEndline = '<br' . s:tag_close
812543b7ef7SBram Moolenaar  let s:LeadingSpace = s:settings.use_xhtml ? '&#160;' : '&nbsp;'
813c1e37901SBram Moolenaar  let s:HtmlSpace = '\' . s:LeadingSpace
814071d4279SBram Moolenaarendif
815071d4279SBram Moolenaar
816071d4279SBram Moolenaar" HTML header, with the title and generator ;-). Left free space for the CSS,
817071d4279SBram Moolenaar" to be filled at the end.
818349b2fb0SBram Moolenaarcall extend(s:lines, [
819349b2fb0SBram Moolenaar      \ "<html>",
820bebca9daSBram Moolenaar      \ "<head>"])
821bebca9daSBram Moolenaar" include encoding as close to the top as possible, but only if not already
822bebca9daSBram Moolenaar" contained in XML information (to avoid haggling over content type)
823bebca9daSBram Moolenaarif s:settings.encoding != "" && !s:settings.use_xhtml
8240c0734d5SBram Moolenaar  if s:html5
8250c0734d5SBram Moolenaar    call add(s:lines, '<meta charset="' . s:settings.encoding . '"' . s:tag_close)
8260c0734d5SBram Moolenaar  else
827bebca9daSBram Moolenaar    call add(s:lines, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" . s:settings.encoding . '"' . s:tag_close)
828bebca9daSBram Moolenaar  endif
8290c0734d5SBram Moolenaarendif
830bebca9daSBram Moolenaarcall extend(s:lines, [
831349b2fb0SBram Moolenaar      \ ("<title>".expand("%:p:~")."</title>"),
832349b2fb0SBram Moolenaar      \ ("<meta name=\"Generator\" content=\"Vim/".v:version/100.".".v:version%100.'"'.s:tag_close),
833f0d58efcSBram Moolenaar      \ ("<meta name=\"plugin-version\" content=\"".s:pluginversion.'"'.s:tag_close)
834349b2fb0SBram Moolenaar      \ ])
8357510fe74SBram Moolenaarcall add(s:lines, '<meta name="syntax" content="'.s:current_syntax.'"'.s:tag_close)
836076e8b2aSBram Moolenaarcall add(s:lines, '<meta name="settings" content="'.
837076e8b2aSBram Moolenaar      \ join(filter(keys(s:settings),'s:settings[v:val]'),',').
8386c35beaaSBram Moolenaar      \ ',prevent_copy='.s:settings.prevent_copy.
8390c0734d5SBram Moolenaar      \ ',use_input_for_pc='.s:settings.use_input_for_pc.
840076e8b2aSBram Moolenaar      \ '"'.s:tag_close)
8416c35beaaSBram Moolenaarcall add(s:lines, '<meta name="colorscheme" content="'.
8426c35beaaSBram Moolenaar      \ (exists('g:colors_name')
8436c35beaaSBram Moolenaar      \ ? g:colors_name
8446c35beaaSBram Moolenaar      \ : 'none'). '"'.s:tag_close)
845313b7237SBram Moolenaar
846076e8b2aSBram Moolenaarif s:settings.use_css
8470c0734d5SBram Moolenaar  call extend(s:lines, [
8480c0734d5SBram Moolenaar	\ "<style" . (s:html5 ? "" : " type=\"text/css\"") . ">",
8490c0734d5SBram Moolenaar	\ s:settings.use_xhtml ? "" : "<!--"])
8500c0734d5SBram Moolenaar  let s:ieonly = []
851076e8b2aSBram Moolenaar  if s:settings.dynamic_folds
852076e8b2aSBram Moolenaar    if s:settings.hover_unfold
8535c73622aSBram Moolenaar      " if we are doing hover_unfold, use css 2 with css 1 fallback for IE6
854349b2fb0SBram Moolenaar      call extend(s:lines, [
855349b2fb0SBram Moolenaar	    \ ".FoldColumn { text-decoration: none; white-space: pre; }",
856349b2fb0SBram Moolenaar	    \ "",
857349b2fb0SBram Moolenaar	    \ "body * { margin: 0; padding: 0; }", "",
8580c0734d5SBram Moolenaar	    \ ".open-fold   > span.Folded { display: none;  }",
859349b2fb0SBram Moolenaar	    \ ".open-fold   > .fulltext   { display: inline; }",
860349b2fb0SBram Moolenaar	    \ ".closed-fold > .fulltext   { display: none;  }",
8610c0734d5SBram Moolenaar	    \ ".closed-fold > span.Folded { display: inline; }",
862349b2fb0SBram Moolenaar	    \ "",
863349b2fb0SBram Moolenaar	    \ ".open-fold   > .toggle-open   { display: none;   }",
864349b2fb0SBram Moolenaar	    \ ".open-fold   > .toggle-closed { display: inline; }",
865349b2fb0SBram Moolenaar	    \ ".closed-fold > .toggle-open   { display: inline; }",
866349b2fb0SBram Moolenaar	    \ ".closed-fold > .toggle-closed { display: none;   }",
867349b2fb0SBram Moolenaar	    \ "", "",
868349b2fb0SBram Moolenaar	    \ '/* opening a fold while hovering won''t be supported by IE6 and other',
869349b2fb0SBram Moolenaar	    \ "similar browsers, but it should fail gracefully. */",
870349b2fb0SBram Moolenaar	    \ ".closed-fold:hover > .fulltext      { display: inline; }",
871349b2fb0SBram Moolenaar	    \ ".closed-fold:hover > .toggle-filler { display: none; }",
8720c0734d5SBram Moolenaar	    \ ".closed-fold:hover > .Folded        { display: none; }"])
8730c0734d5SBram Moolenaar      " TODO: IE6 is REALLY old and I can't even test it anymore. Maybe we
8740c0734d5SBram Moolenaar      " should remove this? Leave it in for now, it was working at one point,
8750c0734d5SBram Moolenaar      " and doesn't affect any modern browsers. Even newer IE versions should
8760c0734d5SBram Moolenaar      " support the above code and ignore the following.
8770c0734d5SBram Moolenaar      let s:ieonly = [
878349b2fb0SBram Moolenaar	    \ "<!--[if lt IE 7]><style type=\"text/css\">",
879349b2fb0SBram Moolenaar	    \ ".open-fold   .fulltext      { display: inline; }",
8800c0734d5SBram Moolenaar	    \ ".open-fold   span.Folded    { display: none; }",
881349b2fb0SBram Moolenaar	    \ ".open-fold   .toggle-open   { display: none; }",
8820c0734d5SBram Moolenaar	    \ ".open-fold   .toggle-closed { display: inline; }",
883349b2fb0SBram Moolenaar	    \ "",
884349b2fb0SBram Moolenaar	    \ ".closed-fold .fulltext      { display: none; }",
8850c0734d5SBram Moolenaar	    \ ".closed-fold span.Folded    { display: inline; }",
886349b2fb0SBram Moolenaar	    \ ".closed-fold .toggle-open   { display: inline; }",
887349b2fb0SBram Moolenaar	    \ ".closed-fold .toggle-closed { display: none; }",
888349b2fb0SBram Moolenaar	    \ "</style>",
889349b2fb0SBram Moolenaar	    \ "<![endif]-->",
8900c0734d5SBram Moolenaar	    \]
8915c73622aSBram Moolenaar    else
8925c73622aSBram Moolenaar      " if we aren't doing hover_unfold, use CSS 1 only
893349b2fb0SBram Moolenaar      call extend(s:lines, [
894349b2fb0SBram Moolenaar	    \ ".FoldColumn { text-decoration: none; white-space: pre; }",
895349b2fb0SBram Moolenaar	    \ ".open-fold   .fulltext      { display: inline; }",
8960c0734d5SBram Moolenaar	    \ ".open-fold   span.Folded    { display: none; }",
897349b2fb0SBram Moolenaar	    \ ".open-fold   .toggle-open   { display: none; }",
8980c0734d5SBram Moolenaar	    \ ".open-fold   .toggle-closed { display: inline; }",
899349b2fb0SBram Moolenaar	    \ "",
900349b2fb0SBram Moolenaar	    \ ".closed-fold .fulltext      { display: none; }",
9010c0734d5SBram Moolenaar	    \ ".closed-fold span.Folded    { display: inline; }",
902349b2fb0SBram Moolenaar	    \ ".closed-fold .toggle-open   { display: inline; }",
903349b2fb0SBram Moolenaar	    \ ".closed-fold .toggle-closed { display: none; }",
904349b2fb0SBram Moolenaar	    \])
9055c73622aSBram Moolenaar    endif
9060c0734d5SBram Moolenaar  endif
9070c0734d5SBram Moolenaar  " else we aren't doing any dynamic folding, no need for any special rules
9080c0734d5SBram Moolenaar
909349b2fb0SBram Moolenaar  call extend(s:lines, [
910bebca9daSBram Moolenaar	  \ s:settings.use_xhtml ? "" : '-->',
911349b2fb0SBram Moolenaar	  \ "</style>",
912349b2fb0SBram Moolenaar	  \])
9130c0734d5SBram Moolenaar  call extend(s:lines, s:ieonly)
9140c0734d5SBram Moolenaar  unlet s:ieonly
9155c73622aSBram Moolenaarendif
9165c73622aSBram Moolenaar
9170c0734d5SBram Moolenaarlet s:uses_script = s:settings.dynamic_folds || s:settings.line_ids
918f0d58efcSBram Moolenaar
919f0d58efcSBram Moolenaar" insert script tag if needed
920f0d58efcSBram Moolenaarif s:uses_script
9216c35beaaSBram Moolenaar  call extend(s:lines, [
9226c35beaaSBram Moolenaar        \ "",
9230c0734d5SBram Moolenaar        \ "<script" . (s:html5 ? "" : " type='text/javascript'") . ">",
9246c35beaaSBram Moolenaar        \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])
925f0d58efcSBram Moolenaarendif
9266c35beaaSBram Moolenaar
9275c73622aSBram Moolenaar" insert javascript to toggle folds open and closed
928076e8b2aSBram Moolenaarif s:settings.dynamic_folds
929349b2fb0SBram Moolenaar  call extend(s:lines, [
930349b2fb0SBram Moolenaar	\ "",
931349b2fb0SBram Moolenaar	\ "function toggleFold(objID)",
932349b2fb0SBram Moolenaar	\ "{",
933349b2fb0SBram Moolenaar	\ "  var fold;",
934349b2fb0SBram Moolenaar	\ "  fold = document.getElementById(objID);",
935349b2fb0SBram Moolenaar	\ "  if (fold.className == 'closed-fold')",
936349b2fb0SBram Moolenaar	\ "  {",
937349b2fb0SBram Moolenaar	\ "    fold.className = 'open-fold';",
938349b2fb0SBram Moolenaar	\ "  }",
939349b2fb0SBram Moolenaar	\ "  else if (fold.className == 'open-fold')",
940349b2fb0SBram Moolenaar	\ "  {",
941349b2fb0SBram Moolenaar	\ "    fold.className = 'closed-fold';",
942349b2fb0SBram Moolenaar	\ "  }",
9436c35beaaSBram Moolenaar	\ "}"
9446c35beaaSBram Moolenaar	\ ])
9456c35beaaSBram Moolenaarendif
9466c35beaaSBram Moolenaar
94731c31679SBram Moolenaarif s:settings.line_ids
948543b7ef7SBram Moolenaar  " insert javascript to get IDs from line numbers, and to open a fold before
949543b7ef7SBram Moolenaar  " jumping to any lines contained therein
950543b7ef7SBram Moolenaar  call extend(s:lines, [
951543b7ef7SBram Moolenaar	\ "",
952543b7ef7SBram Moolenaar	\ "/* function to open any folds containing a jumped-to line before jumping to it */",
953543b7ef7SBram Moolenaar	\ "function JumpToLine()",
954543b7ef7SBram Moolenaar	\ "{",
955543b7ef7SBram Moolenaar	\ "  var lineNum;",
956543b7ef7SBram Moolenaar	\ "  lineNum = window.location.hash;",
957543b7ef7SBram Moolenaar	\ "  lineNum = lineNum.substr(1); /* strip off '#' */",
958543b7ef7SBram Moolenaar	\ "",
959543b7ef7SBram Moolenaar	\ "  if (lineNum.indexOf('L') == -1) {",
960543b7ef7SBram Moolenaar	\ "    lineNum = 'L'+lineNum;",
961543b7ef7SBram Moolenaar	\ "  }",
962f0d58efcSBram Moolenaar	\ "  var lineElem = document.getElementById(lineNum);"
963543b7ef7SBram Moolenaar	\ ])
964f0d58efcSBram Moolenaar
965543b7ef7SBram Moolenaar  if s:settings.dynamic_folds
966543b7ef7SBram Moolenaar    call extend(s:lines, [
967543b7ef7SBram Moolenaar	  \ "",
968543b7ef7SBram Moolenaar	  \ "  /* navigate upwards in the DOM tree to open all folds containing the line */",
969543b7ef7SBram Moolenaar	  \ "  var node = lineElem;",
97031c31679SBram Moolenaar	  \ "  while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')",
971543b7ef7SBram Moolenaar	  \ "  {",
972543b7ef7SBram Moolenaar	  \ "    if (node.className == 'closed-fold')",
973543b7ef7SBram Moolenaar	  \ "    {",
974543b7ef7SBram Moolenaar	  \ "      node.className = 'open-fold';",
975543b7ef7SBram Moolenaar	  \ "    }",
976543b7ef7SBram Moolenaar	  \ "    node = node.parentNode;",
977543b7ef7SBram Moolenaar	  \ "  }",
978543b7ef7SBram Moolenaar	  \ ])
979543b7ef7SBram Moolenaar  endif
980543b7ef7SBram Moolenaar  call extend(s:lines, [
981543b7ef7SBram Moolenaar	\ "  /* Always jump to new location even if the line was hidden inside a fold, or",
982543b7ef7SBram Moolenaar	\ "   * we corrected the raw number to a line ID.",
983543b7ef7SBram Moolenaar	\ "   */",
984543b7ef7SBram Moolenaar	\ "  if (lineElem) {",
985543b7ef7SBram Moolenaar	\ "    lineElem.scrollIntoView(true);",
986543b7ef7SBram Moolenaar	\ "  }",
987543b7ef7SBram Moolenaar	\ "  return true;",
988543b7ef7SBram Moolenaar	\ "}",
989543b7ef7SBram Moolenaar	\ "if ('onhashchange' in window) {",
990543b7ef7SBram Moolenaar	\ "  window.onhashchange = JumpToLine;",
991543b7ef7SBram Moolenaar	\ "}"
992543b7ef7SBram Moolenaar	\ ])
99331c31679SBram Moolenaarendif
994543b7ef7SBram Moolenaar
995f0d58efcSBram Moolenaar" insert script closing tag if needed
996f0d58efcSBram Moolenaarif s:uses_script
9976c35beaaSBram Moolenaar  call extend(s:lines, [
9986c35beaaSBram Moolenaar        \ '',
999bebca9daSBram Moolenaar        \ s:settings.use_xhtml ? '//]]>' : '-->',
1000349b2fb0SBram Moolenaar        \ "</script>"
1001349b2fb0SBram Moolenaar        \ ])
1002f0d58efcSBram Moolenaarendif
10035c73622aSBram Moolenaar
10040c0734d5SBram Moolenaarcall extend(s:lines, ["</head>",
10050c0734d5SBram Moolenaar      \ "<body".(s:settings.line_ids ? " onload='JumpToLine();'" : "").">"])
10060c0734d5SBram Moolenaar
10076c35beaaSBram Moolenaarif s:settings.no_pre
10086c35beaaSBram Moolenaar  " if we're not using CSS we use a font tag which can't have a div inside
10096c35beaaSBram Moolenaar  if s:settings.use_css
101031c31679SBram Moolenaar    call extend(s:lines, ["<div id='vimCodeElement".s:settings.id_suffix."'>"])
10116c35beaaSBram Moolenaar  endif
10126c35beaaSBram Moolenaarelse
101331c31679SBram Moolenaar  call extend(s:lines, ["<pre id='vimCodeElement".s:settings.id_suffix."'>"])
1014071d4279SBram Moolenaarendif
1015071d4279SBram Moolenaar
1016071d4279SBram Moolenaarexe s:orgwin . "wincmd w"
1017071d4279SBram Moolenaar
10186c35beaaSBram Moolenaar" caches of style data
10196c35beaaSBram Moolenaar" initialize to include line numbers if using them
10206c35beaaSBram Moolenaarif s:settings.number_lines
10216c35beaaSBram Moolenaar  let s:stylelist = { s:LINENR_ID : ".LineNr { " . s:CSS1( s:LINENR_ID ) . "}" }
10226c35beaaSBram Moolenaarelse
10236c35beaaSBram Moolenaar  let s:stylelist = {}
10246c35beaaSBram Moolenaarendif
10256c35beaaSBram Moolenaarlet s:diffstylelist = {
10266c35beaaSBram Moolenaar      \   s:DIFF_A_ID : ".DiffAdd { " . s:CSS1( s:DIFF_A_ID ) . "}",
10276c35beaaSBram Moolenaar      \   s:DIFF_C_ID : ".DiffChange { " . s:CSS1( s:DIFF_C_ID ) . "}",
10286c35beaaSBram Moolenaar      \   s:DIFF_D_ID : ".DiffDelete { " . s:CSS1( s:DIFF_D_ID ) . "}",
10296c35beaaSBram Moolenaar      \   s:DIFF_T_ID : ".DiffText { " . s:CSS1( s:DIFF_T_ID ) . "}"
10306c35beaaSBram Moolenaar      \ }
1031071d4279SBram Moolenaar
1032349b2fb0SBram Moolenaar" set up progress bar in the status line
1033076e8b2aSBram Moolenaarif !s:settings.no_progress
1034349b2fb0SBram Moolenaar  " ProgressBar Indicator
1035349b2fb0SBram Moolenaar  let s:progressbar={}
1036349b2fb0SBram Moolenaar
1037*6c391a74SBram Moolenaar  " Progressbar specific functions
10380c0734d5SBram Moolenaar
10390c0734d5SBram Moolenaar  func! s:SetProgbarColor()
10400c0734d5SBram Moolenaar    if hlID("TOhtmlProgress") != 0
10410c0734d5SBram Moolenaar      hi! link TOhtmlProgress_auto TOhtmlProgress
10420c0734d5SBram Moolenaar    elseif hlID("TOhtmlProgress_auto")==0 ||
10430c0734d5SBram Moolenaar       \ !exists("s:last_colors_name") || !exists("g:colors_name") ||
10440c0734d5SBram Moolenaar       \ g:colors_name != s:last_colors_name
10450c0734d5SBram Moolenaar      let s:last_colors_name = exists("g:colors_name") ? g:colors_name : "none"
10460c0734d5SBram Moolenaar
10470c0734d5SBram Moolenaar      let l:diffatr = synIDattr(hlID("DiffDelete"), "reverse", s:whatterm) ? "fg#" : "bg#"
10480c0734d5SBram Moolenaar      let l:stlatr = synIDattr(hlID("StatusLine"), "reverse", s:whatterm) ? "fg#" : "bg#"
10490c0734d5SBram Moolenaar
10500c0734d5SBram Moolenaar      let l:progbar_color = synIDattr(hlID("DiffDelete"), l:diffatr, s:whatterm)
10510c0734d5SBram Moolenaar      let l:stl_color = synIDattr(hlID("StatusLine"), l:stlatr, s:whatterm)
10520c0734d5SBram Moolenaar
10530c0734d5SBram Moolenaar      if "" == l:progbar_color
10540c0734d5SBram Moolenaar	let l:progbar_color = synIDattr(hlID("DiffDelete"), "reverse", s:whatterm) ? s:fgc : s:bgc
10550c0734d5SBram Moolenaar      endif
10560c0734d5SBram Moolenaar      if "" == l:stl_color
10570c0734d5SBram Moolenaar	let l:stl_color = synIDattr(hlID("StatusLine"), "reverse", s:whatterm) ? s:fgc : s:bgc
10580c0734d5SBram Moolenaar      endif
10590c0734d5SBram Moolenaar
10600c0734d5SBram Moolenaar      if l:progbar_color == l:stl_color
10610c0734d5SBram Moolenaar	if s:whatterm == 'cterm'
10620c0734d5SBram Moolenaar	  if l:progbar_color >= (&t_Co/2)
10630c0734d5SBram Moolenaar	    let l:progbar_color-=1
10640c0734d5SBram Moolenaar	  else
10650c0734d5SBram Moolenaar	    let l:progbar_color+=1
10660c0734d5SBram Moolenaar	  endif
10670c0734d5SBram Moolenaar	else
10680c0734d5SBram Moolenaar	  let l:rgb = map(matchlist(l:progbar_color, '#\zs\x\x\ze\(\x\x\)\(\x\x\)')[:2], 'str2nr(v:val, 16)')
10690c0734d5SBram Moolenaar	  let l:avg = (l:rgb[0] + l:rgb[1] + l:rgb[2])/3
10700c0734d5SBram Moolenaar	  if l:avg >= 128
10710c0734d5SBram Moolenaar	    let l:avg_new = l:avg
10720c0734d5SBram Moolenaar	    while l:avg - l:avg_new < 0x15
10730c0734d5SBram Moolenaar	      let l:rgb = map(l:rgb, 'v:val * 3 / 4')
10740c0734d5SBram Moolenaar	      let l:avg_new = (l:rgb[0] + l:rgb[1] + l:rgb[2])/3
10750c0734d5SBram Moolenaar	    endwhile
10760c0734d5SBram Moolenaar	  else
10770c0734d5SBram Moolenaar	    let l:avg_new = l:avg
10780c0734d5SBram Moolenaar	    while l:avg_new - l:avg < 0x15
10790c0734d5SBram Moolenaar	      let l:rgb = map(l:rgb, 'min([max([v:val, 4]) * 5 / 4, 255])')
10800c0734d5SBram Moolenaar	      let l:avg_new = (l:rgb[0] + l:rgb[1] + l:rgb[2])/3
10810c0734d5SBram Moolenaar	    endwhile
10820c0734d5SBram Moolenaar	  endif
10830c0734d5SBram Moolenaar	  let l:progbar_color = printf("#%02x%02x%02x", l:rgb[0], l:rgb[1], l:rgb[2])
10840c0734d5SBram Moolenaar	endif
10850c0734d5SBram Moolenaar	echomsg "diff detected progbar color set to" l:progbar_color
10860c0734d5SBram Moolenaar      endif
10870c0734d5SBram Moolenaar      exe "hi TOhtmlProgress_auto" s:whatterm."bg=".l:progbar_color
10880c0734d5SBram Moolenaar    endif
10890c0734d5SBram Moolenaar  endfun
10900c0734d5SBram Moolenaar
1091349b2fb0SBram Moolenaar  func! s:ProgressBar(title, max_value, winnr)
1092349b2fb0SBram Moolenaar    let pgb=copy(s:progressbar)
1093349b2fb0SBram Moolenaar    let pgb.title = a:title.' '
1094349b2fb0SBram Moolenaar    let pgb.max_value = a:max_value
1095349b2fb0SBram Moolenaar    let pgb.winnr = a:winnr
1096349b2fb0SBram Moolenaar    let pgb.cur_value = 0
10970c0734d5SBram Moolenaar
1098349b2fb0SBram Moolenaar    let pgb.items = { 'title'   : { 'color' : 'Statusline' },
10990c0734d5SBram Moolenaar	  \'bar'     : { 'color' : 'Statusline' , 'fillcolor' : 'TOhtmlProgress_auto' , 'bg' : 'Statusline' } ,
1100349b2fb0SBram Moolenaar	  \'counter' : { 'color' : 'Statusline' } }
1101349b2fb0SBram Moolenaar    let pgb.last_value = 0
1102349b2fb0SBram Moolenaar    let pgb.needs_redraw = 0
1103349b2fb0SBram Moolenaar    " Note that you must use len(split) instead of len() if you want to use
1104349b2fb0SBram Moolenaar    " unicode in title.
1105349b2fb0SBram Moolenaar    "
1106349b2fb0SBram Moolenaar    " Subtract 3 for spacing around the title.
1107349b2fb0SBram Moolenaar    " Subtract 4 for the percentage display.
1108349b2fb0SBram Moolenaar    " Subtract 2 for spacing before this.
1109349b2fb0SBram Moolenaar    " Subtract 2 more for the '|' on either side of the progress bar
1110349b2fb0SBram Moolenaar    let pgb.subtractedlen=len(split(pgb.title, '\zs'))+3+4+2+2
1111349b2fb0SBram Moolenaar    let pgb.max_len = 0
1112349b2fb0SBram Moolenaar    set laststatus=2
1113349b2fb0SBram Moolenaar    return pgb
1114349b2fb0SBram Moolenaar  endfun
1115349b2fb0SBram Moolenaar
1116349b2fb0SBram Moolenaar  " Function: progressbar.calculate_ticks() {{{1
1117349b2fb0SBram Moolenaar  func! s:progressbar.calculate_ticks(pb_len)
1118349b2fb0SBram Moolenaar    if a:pb_len<=0
1119349b2fb0SBram Moolenaar      let pb_len = 100
1120349b2fb0SBram Moolenaar    else
1121349b2fb0SBram Moolenaar      let pb_len = a:pb_len
1122349b2fb0SBram Moolenaar    endif
1123349b2fb0SBram Moolenaar    let self.progress_ticks = map(range(pb_len+1), "v:val * self.max_value / pb_len")
1124349b2fb0SBram Moolenaar  endfun
1125349b2fb0SBram Moolenaar
1126349b2fb0SBram Moolenaar  "Function: progressbar.paint()
1127349b2fb0SBram Moolenaar  func! s:progressbar.paint()
1128349b2fb0SBram Moolenaar    " Recalculate widths.
1129349b2fb0SBram Moolenaar    let max_len = winwidth(self.winnr)
1130349b2fb0SBram Moolenaar    let pb_len = 0
1131349b2fb0SBram Moolenaar    " always true on first call because of initial value of self.max_len
1132349b2fb0SBram Moolenaar    if max_len != self.max_len
1133349b2fb0SBram Moolenaar      let self.max_len = max_len
1134349b2fb0SBram Moolenaar
1135349b2fb0SBram Moolenaar      " Progressbar length
1136349b2fb0SBram Moolenaar      let pb_len = max_len - self.subtractedlen
1137349b2fb0SBram Moolenaar
1138349b2fb0SBram Moolenaar      call self.calculate_ticks(pb_len)
1139349b2fb0SBram Moolenaar
1140349b2fb0SBram Moolenaar      let self.needs_redraw = 1
1141349b2fb0SBram Moolenaar      let cur_value = 0
1142349b2fb0SBram Moolenaar      let self.pb_len = pb_len
1143349b2fb0SBram Moolenaar    else
1144349b2fb0SBram Moolenaar      " start searching at the last found index to make the search for the
1145349b2fb0SBram Moolenaar      " appropriate tick value normally take 0 or 1 comparisons
1146349b2fb0SBram Moolenaar      let cur_value = self.last_value
1147349b2fb0SBram Moolenaar      let pb_len = self.pb_len
1148349b2fb0SBram Moolenaar    endif
1149349b2fb0SBram Moolenaar
1150349b2fb0SBram Moolenaar    let cur_val_max = pb_len > 0 ? pb_len : 100
1151349b2fb0SBram Moolenaar
1152349b2fb0SBram Moolenaar    " find the current progress bar position based on precalculated thresholds
1153349b2fb0SBram Moolenaar    while cur_value < cur_val_max && self.cur_value > self.progress_ticks[cur_value]
1154349b2fb0SBram Moolenaar      let cur_value += 1
1155349b2fb0SBram Moolenaar    endwhile
1156349b2fb0SBram Moolenaar
1157349b2fb0SBram Moolenaar    " update progress bar
1158349b2fb0SBram Moolenaar    if self.last_value != cur_value || self.needs_redraw || self.cur_value == self.max_value
1159349b2fb0SBram Moolenaar      let self.needs_redraw = 1
1160349b2fb0SBram Moolenaar      let self.last_value = cur_value
1161349b2fb0SBram Moolenaar
1162349b2fb0SBram Moolenaar      let t_color  = self.items.title.color
1163349b2fb0SBram Moolenaar      let b_fcolor = self.items.bar.fillcolor
1164349b2fb0SBram Moolenaar      let b_color  = self.items.bar.color
1165349b2fb0SBram Moolenaar      let c_color  = self.items.counter.color
1166349b2fb0SBram Moolenaar
1167349b2fb0SBram Moolenaar      let stl =  "%#".t_color."#%-( ".self.title." %)".
1168349b2fb0SBram Moolenaar	    \"%#".b_color."#".
1169349b2fb0SBram Moolenaar	    \(pb_len>0 ?
1170349b2fb0SBram Moolenaar	    \	('|%#'.b_fcolor."#%-(".repeat(" ",cur_value)."%)".
1171349b2fb0SBram Moolenaar	    \	 '%#'.b_color."#".repeat(" ",pb_len-cur_value)."|"):
1172349b2fb0SBram Moolenaar	    \	('')).
1173349b2fb0SBram Moolenaar	    \"%=%#".c_color."#%( ".printf("%3.d ",100*self.cur_value/self.max_value)."%% %)"
1174349b2fb0SBram Moolenaar      call setwinvar(self.winnr, '&stl', stl)
1175349b2fb0SBram Moolenaar    endif
1176349b2fb0SBram Moolenaar  endfun
1177349b2fb0SBram Moolenaar
1178349b2fb0SBram Moolenaar  func! s:progressbar.incr( ... )
1179349b2fb0SBram Moolenaar    let self.cur_value += (a:0 ? a:1 : 1)
1180349b2fb0SBram Moolenaar    " if we were making a general-purpose progress bar, we'd need to limit to a
1181349b2fb0SBram Moolenaar    " lower limit as well, but since we always increment with a positive value
1182349b2fb0SBram Moolenaar    " in this script, we only need limit the upper value
1183349b2fb0SBram Moolenaar    let self.cur_value = (self.cur_value > self.max_value ? self.max_value : self.cur_value)
1184349b2fb0SBram Moolenaar    call self.paint()
1185349b2fb0SBram Moolenaar  endfun
1186349b2fb0SBram Moolenaar  " }}}
1187076e8b2aSBram Moolenaar  if s:settings.dynamic_folds
1188349b2fb0SBram Moolenaar    " to process folds we make two passes through each line
1189349b2fb0SBram Moolenaar    let s:pgb = s:ProgressBar("Processing folds:", line('$')*2, s:orgwin)
1190349b2fb0SBram Moolenaar  endif
11910c0734d5SBram Moolenaar
11920c0734d5SBram Moolenaar  call s:SetProgbarColor()
1193349b2fb0SBram Moolenaarendif
1194349b2fb0SBram Moolenaar
11955c73622aSBram Moolenaar" First do some preprocessing for dynamic folding. Do this for the entire file
11965c73622aSBram Moolenaar" so we don't accidentally start within a closed fold or something.
11975c73622aSBram Moolenaarlet s:allfolds = []
11985c73622aSBram Moolenaar
1199076e8b2aSBram Moolenaarif s:settings.dynamic_folds
12005c73622aSBram Moolenaar  let s:lnum = 1
12015c73622aSBram Moolenaar  let s:end = line('$')
12025c73622aSBram Moolenaar  " save the fold text and set it to the default so we can find fold levels
12035c73622aSBram Moolenaar  let s:foldtext_save = &foldtext
1204349b2fb0SBram Moolenaar  setlocal foldtext&
12055c73622aSBram Moolenaar
12065c73622aSBram Moolenaar  " we will set the foldcolumn in the html to the greater of the maximum fold
12075c73622aSBram Moolenaar  " level and the current foldcolumn setting
12085c73622aSBram Moolenaar  let s:foldcolumn = &foldcolumn
12095c73622aSBram Moolenaar
12105c73622aSBram Moolenaar  " get all info needed to describe currently closed folds
1211349b2fb0SBram Moolenaar  while s:lnum <= s:end
12125c73622aSBram Moolenaar    if foldclosed(s:lnum) == s:lnum
12135c73622aSBram Moolenaar      " default fold text has '+-' and then a number of dashes equal to fold
12145c73622aSBram Moolenaar      " level, so subtract 2 from index of first non-dash after the dashes
12155c73622aSBram Moolenaar      " in order to get the fold level of the current fold
12165c73622aSBram Moolenaar      let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2
12175c73622aSBram Moolenaar      " store fold info for later use
12185c73622aSBram Moolenaar      let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"}
12195c73622aSBram Moolenaar      call add(s:allfolds, s:newfold)
12205c73622aSBram Moolenaar      " open the fold so we can find any contained folds
12215c73622aSBram Moolenaar      execute s:lnum."foldopen"
12225c73622aSBram Moolenaar    else
1223076e8b2aSBram Moolenaar      if !s:settings.no_progress
1224349b2fb0SBram Moolenaar	call s:pgb.incr()
1225349b2fb0SBram Moolenaar	if s:pgb.needs_redraw
1226349b2fb0SBram Moolenaar	  redrawstatus
1227349b2fb0SBram Moolenaar	  let s:pgb.needs_redraw = 0
1228349b2fb0SBram Moolenaar	endif
1229349b2fb0SBram Moolenaar      endif
12305c73622aSBram Moolenaar      let s:lnum = s:lnum + 1
12315c73622aSBram Moolenaar    endif
12325c73622aSBram Moolenaar  endwhile
12335c73622aSBram Moolenaar
12345c73622aSBram Moolenaar  " close all folds to get info for originally open folds
12355c73622aSBram Moolenaar  silent! %foldclose!
12365c73622aSBram Moolenaar  let s:lnum = 1
12375c73622aSBram Moolenaar
12385c73622aSBram Moolenaar  " the originally open folds will be all folds we encounter that aren't
12395c73622aSBram Moolenaar  " already in the list of closed folds
1240349b2fb0SBram Moolenaar  while s:lnum <= s:end
12415c73622aSBram Moolenaar    if foldclosed(s:lnum) == s:lnum
12425c73622aSBram Moolenaar      " default fold text has '+-' and then a number of dashes equal to fold
12435c73622aSBram Moolenaar      " level, so subtract 2 from index of first non-dash after the dashes
12445c73622aSBram Moolenaar      " in order to get the fold level of the current fold
12455c73622aSBram Moolenaar      let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2
12465c73622aSBram Moolenaar      let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"}
12475c73622aSBram Moolenaar      " only add the fold if we don't already have it
12485c73622aSBram Moolenaar      if empty(s:allfolds) || index(s:allfolds, s:newfold) == -1
12495c73622aSBram Moolenaar	let s:newfold.type = "open-fold"
12505c73622aSBram Moolenaar	call add(s:allfolds, s:newfold)
12515c73622aSBram Moolenaar      endif
12525c73622aSBram Moolenaar      " open the fold so we can find any contained folds
12535c73622aSBram Moolenaar      execute s:lnum."foldopen"
12545c73622aSBram Moolenaar    else
1255076e8b2aSBram Moolenaar      if !s:settings.no_progress
1256349b2fb0SBram Moolenaar	call s:pgb.incr()
1257349b2fb0SBram Moolenaar	if s:pgb.needs_redraw
1258349b2fb0SBram Moolenaar	  redrawstatus
1259349b2fb0SBram Moolenaar	  let s:pgb.needs_redraw = 0
1260349b2fb0SBram Moolenaar	endif
1261349b2fb0SBram Moolenaar      endif
12625c73622aSBram Moolenaar      let s:lnum = s:lnum + 1
12635c73622aSBram Moolenaar    endif
12645c73622aSBram Moolenaar  endwhile
12655c73622aSBram Moolenaar
12665c73622aSBram Moolenaar  " sort the folds so that we only ever need to look at the first item in the
12675c73622aSBram Moolenaar  " list of folds
12685c73622aSBram Moolenaar  call sort(s:allfolds, "s:FoldCompare")
12695c73622aSBram Moolenaar
1270349b2fb0SBram Moolenaar  let &l:foldtext = s:foldtext_save
12715c73622aSBram Moolenaar  unlet s:foldtext_save
12725c73622aSBram Moolenaar
12735c73622aSBram Moolenaar  " close all folds again so we can get the fold text as we go
12745c73622aSBram Moolenaar  silent! %foldclose!
12752a8a3ecbSBram Moolenaar
1276251e1912SBram Moolenaar  " Go through and remove folds we don't need to (or cannot) process in the
1277251e1912SBram Moolenaar  " current conversion range
1278251e1912SBram Moolenaar  "
1279251e1912SBram Moolenaar  " If a fold is removed which contains other folds, which are included, we need
1280251e1912SBram Moolenaar  " to adjust the level of the included folds as used by the conversion logic
1281251e1912SBram Moolenaar  " (avoiding special cases is good)
1282251e1912SBram Moolenaar  "
1283251e1912SBram Moolenaar  " Note any time we remove a fold, either all of the included folds are in it,
1284251e1912SBram Moolenaar  " or none of them, because we only remove a fold if neither its start nor its
1285251e1912SBram Moolenaar  " end are within the conversion range.
1286251e1912SBram Moolenaar  let leveladjust = 0
12872a8a3ecbSBram Moolenaar  for afold in s:allfolds
12882a8a3ecbSBram Moolenaar    let removed = 0
12892a8a3ecbSBram Moolenaar    if exists("g:html_start_line") && exists("g:html_end_line")
12902a8a3ecbSBram Moolenaar      if afold.firstline < g:html_start_line
1291251e1912SBram Moolenaar	if afold.lastline <= g:html_end_line && afold.lastline >= g:html_start_line
12922a8a3ecbSBram Moolenaar	  " if a fold starts before the range to convert but stops within the
12932a8a3ecbSBram Moolenaar	  " range, we need to include it. Make it start on the first converted
12942a8a3ecbSBram Moolenaar	  " line.
12952a8a3ecbSBram Moolenaar	  let afold.firstline = g:html_start_line
12962a8a3ecbSBram Moolenaar	else
12972a8a3ecbSBram Moolenaar	  " if the fold lies outside the range or the start and stop enclose
12982a8a3ecbSBram Moolenaar	  " the entire range, don't bother parsing it
12992a8a3ecbSBram Moolenaar	  call remove(s:allfolds, index(s:allfolds, afold))
13002a8a3ecbSBram Moolenaar	  let removed = 1
1301251e1912SBram Moolenaar	  if afold.lastline > g:html_end_line
1302251e1912SBram Moolenaar	    let leveladjust += 1
1303251e1912SBram Moolenaar	  endif
13042a8a3ecbSBram Moolenaar	endif
13052a8a3ecbSBram Moolenaar      elseif afold.firstline > g:html_end_line
13062a8a3ecbSBram Moolenaar	" If the entire fold lies outside the range we need to remove it.
13072a8a3ecbSBram Moolenaar	call remove(s:allfolds, index(s:allfolds, afold))
13082a8a3ecbSBram Moolenaar	let removed = 1
13092a8a3ecbSBram Moolenaar      endif
13102a8a3ecbSBram Moolenaar    elseif exists("g:html_start_line")
13112a8a3ecbSBram Moolenaar      if afold.firstline < g:html_start_line
13122a8a3ecbSBram Moolenaar	" if there is no last line, but there is a first line, the end of the
13132a8a3ecbSBram Moolenaar	" fold will always lie within the region of interest, so keep it
13142a8a3ecbSBram Moolenaar	let afold.firstline = g:html_start_line
13152a8a3ecbSBram Moolenaar      endif
13162a8a3ecbSBram Moolenaar    elseif exists("g:html_end_line")
13172a8a3ecbSBram Moolenaar      " if there is no first line we default to the first line in the buffer so
13182a8a3ecbSBram Moolenaar      " the fold start will always be included if the fold itself is included.
13192a8a3ecbSBram Moolenaar      " If however the entire fold lies outside the range we need to remove it.
13202a8a3ecbSBram Moolenaar      if afold.firstline > g:html_end_line
13212a8a3ecbSBram Moolenaar	call remove(s:allfolds, index(s:allfolds, afold))
13222a8a3ecbSBram Moolenaar	let removed = 1
13232a8a3ecbSBram Moolenaar      endif
13242a8a3ecbSBram Moolenaar    endif
13252a8a3ecbSBram Moolenaar    if !removed
1326251e1912SBram Moolenaar      let afold.level -= leveladjust
13272a8a3ecbSBram Moolenaar      if afold.level+1 > s:foldcolumn
13282a8a3ecbSBram Moolenaar	let s:foldcolumn = afold.level+1
13292a8a3ecbSBram Moolenaar      endif
13302a8a3ecbSBram Moolenaar    endif
13312a8a3ecbSBram Moolenaar  endfor
1332251e1912SBram Moolenaar
1333251e1912SBram Moolenaar  " if we've removed folds containing the conversion range from processing,
1334251e1912SBram Moolenaar  " getting foldtext as we go won't know to open the removed folds, so the
1335251e1912SBram Moolenaar  " foldtext would be wrong; open them now.
1336251e1912SBram Moolenaar  "
1337251e1912SBram Moolenaar  " Note that only when a start and an end line is specified will a fold
1338251e1912SBram Moolenaar  " containing the current range ever be removed.
1339251e1912SBram Moolenaar  while leveladjust > 0
1340251e1912SBram Moolenaar    exe g:html_start_line."foldopen"
1341251e1912SBram Moolenaar    let leveladjust -= 1
1342251e1912SBram Moolenaar  endwhile
13435c73622aSBram Moolenaarendif
13445c73622aSBram Moolenaar
13455c73622aSBram Moolenaar" Now loop over all lines in the original text to convert to html.
1346071d4279SBram Moolenaar" Use html_start_line and html_end_line if they are set.
1347b02cbe34SBram Moolenaarif exists("g:html_start_line")
1348071d4279SBram Moolenaar  let s:lnum = html_start_line
1349071d4279SBram Moolenaar  if s:lnum < 1 || s:lnum > line("$")
1350071d4279SBram Moolenaar    let s:lnum = 1
1351071d4279SBram Moolenaar  endif
1352071d4279SBram Moolenaarelse
1353071d4279SBram Moolenaar  let s:lnum = 1
1354071d4279SBram Moolenaarendif
1355b02cbe34SBram Moolenaarif exists("g:html_end_line")
1356071d4279SBram Moolenaar  let s:end = html_end_line
1357071d4279SBram Moolenaar  if s:end < s:lnum || s:end > line("$")
1358071d4279SBram Moolenaar    let s:end = line("$")
1359071d4279SBram Moolenaar  endif
1360071d4279SBram Moolenaarelse
1361071d4279SBram Moolenaar  let s:end = line("$")
1362071d4279SBram Moolenaarendif
1363071d4279SBram Moolenaar
13645c73622aSBram Moolenaar" stack to keep track of all the folds containing the current line
13655c73622aSBram Moolenaarlet s:foldstack = []
13665c73622aSBram Moolenaar
1367076e8b2aSBram Moolenaarif !s:settings.no_progress
1368349b2fb0SBram Moolenaar  let s:pgb = s:ProgressBar("Processing lines:", s:end - s:lnum + 1, s:orgwin)
1369349b2fb0SBram Moolenaarendif
1370349b2fb0SBram Moolenaar
1371076e8b2aSBram Moolenaarif s:settings.number_lines
13725c73622aSBram Moolenaar  let s:margin = strlen(s:end) + 1
13735c73622aSBram Moolenaarelse
13745c73622aSBram Moolenaar  let s:margin = 0
13755c73622aSBram Moolenaarendif
13765c73622aSBram Moolenaar
1377076e8b2aSBram Moolenaarif has('folding') && !s:settings.ignore_folding
137835a9aaabSBram Moolenaar  let s:foldfillchar = &fillchars[matchend(&fillchars, 'fold:')]
137935a9aaabSBram Moolenaar  if s:foldfillchar == ''
138035a9aaabSBram Moolenaar    let s:foldfillchar = '-'
13817b0294cbSBram Moolenaar  endif
138235a9aaabSBram Moolenaarendif
138335a9aaabSBram Moolenaarlet s:difffillchar = &fillchars[matchend(&fillchars, 'diff:')]
138435a9aaabSBram Moolenaarif s:difffillchar == ''
138535a9aaabSBram Moolenaar  let s:difffillchar = '-'
13867b0294cbSBram Moolenaarendif
13877b0294cbSBram Moolenaar
13885c73622aSBram Moolenaarlet s:foldId = 0
13897b0294cbSBram Moolenaar
13902a8a3ecbSBram Moolenaarif !s:settings.expand_tabs
13912a8a3ecbSBram Moolenaar  " If keeping tabs, add them to printable characters so we keep them when
13922a8a3ecbSBram Moolenaar  " formatting text (strtrans() doesn't replace printable chars)
13932a8a3ecbSBram Moolenaar  let s:old_isprint = &isprint
13942a8a3ecbSBram Moolenaar  setlocal isprint+=9
13952a8a3ecbSBram Moolenaarendif
13962a8a3ecbSBram Moolenaar
1397071d4279SBram Moolenaarwhile s:lnum <= s:end
1398071d4279SBram Moolenaar
139947136d70SBram Moolenaar  " If there are filler lines for diff mode, show these above the line.
140047136d70SBram Moolenaar  let s:filler = diff_filler(s:lnum)
140147136d70SBram Moolenaar  if s:filler > 0
140247136d70SBram Moolenaar    let s:n = s:filler
140347136d70SBram Moolenaar    while s:n > 0
140435a9aaabSBram Moolenaar      let s:new = repeat(s:difffillchar, 3)
140547136d70SBram Moolenaar
1406076e8b2aSBram Moolenaar      if s:n > 2 && s:n < s:filler && !s:settings.whole_filler
140735a9aaabSBram Moolenaar	let s:new = s:new . " " . s:filler . " inserted lines "
140835a9aaabSBram Moolenaar	let s:n = 2
140935a9aaabSBram Moolenaar      endif
141035a9aaabSBram Moolenaar
1411076e8b2aSBram Moolenaar      if !s:settings.no_pre
141235a9aaabSBram Moolenaar	" HTML line wrapping is off--go ahead and fill to the margin
14136c35beaaSBram Moolenaar	" TODO: what about when CSS wrapping is turned on?
14145c73622aSBram Moolenaar	let s:new = s:new . repeat(s:difffillchar, &columns - strlen(s:new) - s:margin)
14155c73622aSBram Moolenaar      else
14165c73622aSBram Moolenaar	let s:new = s:new . repeat(s:difffillchar, 3)
141735a9aaabSBram Moolenaar      endif
141835a9aaabSBram Moolenaar
14196c35beaaSBram Moolenaar      let s:new = s:HtmlFormat_d(s:new, s:DIFF_D_ID, 0)
1420076e8b2aSBram Moolenaar      if s:settings.number_lines
14216c35beaaSBram Moolenaar	" Indent if line numbering is on. Indent gets style of line number
14226c35beaaSBram Moolenaar	" column.
1423543b7ef7SBram Moolenaar	let s:new = s:HtmlFormat_n(repeat(' ', s:margin), s:LINENR_ID, 0, 0) . s:new
14246c35beaaSBram Moolenaar      endif
14256c35beaaSBram Moolenaar      if s:settings.dynamic_folds && !s:settings.no_foldcolumn && s:foldcolumn > 0
14266c35beaaSBram Moolenaar	" Indent for foldcolumn if there is one. Assume it's empty, there should
14276c35beaaSBram Moolenaar	" not be a fold for deleted lines in diff mode.
14286c35beaaSBram Moolenaar	let s:new = s:FoldColumn_fill() . s:new
14295c73622aSBram Moolenaar      endif
1430349b2fb0SBram Moolenaar      call add(s:lines, s:new.s:HtmlEndline)
143135a9aaabSBram Moolenaar
143247136d70SBram Moolenaar      let s:n = s:n - 1
143347136d70SBram Moolenaar    endwhile
143447136d70SBram Moolenaar    unlet s:n
143547136d70SBram Moolenaar  endif
143647136d70SBram Moolenaar  unlet s:filler
143747136d70SBram Moolenaar
143847136d70SBram Moolenaar  " Start the line with the line number.
1439076e8b2aSBram Moolenaar  if s:settings.number_lines
14405c73622aSBram Moolenaar    let s:numcol = repeat(' ', s:margin - 1 - strlen(s:lnum)) . s:lnum . ' '
144147136d70SBram Moolenaar  endif
144247136d70SBram Moolenaar
14435c73622aSBram Moolenaar  let s:new = ""
14445c73622aSBram Moolenaar
1445076e8b2aSBram Moolenaar  if has('folding') && !s:settings.ignore_folding && foldclosed(s:lnum) > -1 && !s:settings.dynamic_folds
14467b0294cbSBram Moolenaar    "
14475c73622aSBram Moolenaar    " This is the beginning of a folded block (with no dynamic folding)
14486c35beaaSBram Moolenaar    let s:new = foldtextresult(s:lnum)
1449076e8b2aSBram Moolenaar    if !s:settings.no_pre
145035a9aaabSBram Moolenaar      " HTML line wrapping is off--go ahead and fill to the margin
145135a9aaabSBram Moolenaar      let s:new = s:new . repeat(s:foldfillchar, &columns - strlen(s:new))
14527b0294cbSBram Moolenaar    endif
14537b0294cbSBram Moolenaar
14546c35beaaSBram Moolenaar    " put numcol in a separate group for sake of unselectable text
1455543b7ef7SBram Moolenaar    let s:new = (s:settings.number_lines ? s:HtmlFormat_n(s:numcol, s:FOLDED_ID, 0, s:lnum): "") . s:HtmlFormat_t(s:new, s:FOLDED_ID, 0)
14567b0294cbSBram Moolenaar
14577b0294cbSBram Moolenaar    " Skip to the end of the fold
1458349b2fb0SBram Moolenaar    let s:new_lnum = foldclosedend(s:lnum)
1459349b2fb0SBram Moolenaar
1460076e8b2aSBram Moolenaar    if !s:settings.no_progress
1461349b2fb0SBram Moolenaar      call s:pgb.incr(s:new_lnum - s:lnum)
1462349b2fb0SBram Moolenaar    endif
1463349b2fb0SBram Moolenaar
1464349b2fb0SBram Moolenaar    let s:lnum = s:new_lnum
14657b0294cbSBram Moolenaar
14667b0294cbSBram Moolenaar  else
14677b0294cbSBram Moolenaar    "
14685c73622aSBram Moolenaar    " A line that is not folded, or doing dynamic folding.
14697b0294cbSBram Moolenaar    "
147035a9aaabSBram Moolenaar    let s:line = getline(s:lnum)
14717b0294cbSBram Moolenaar    let s:len = strlen(s:line)
14727b0294cbSBram Moolenaar
1473076e8b2aSBram Moolenaar    if s:settings.dynamic_folds
14745c73622aSBram Moolenaar      " First insert a closing for any open folds that end on this line
14755c73622aSBram Moolenaar      while !empty(s:foldstack) && get(s:foldstack,0).lastline == s:lnum-1
14765c73622aSBram Moolenaar	let s:new = s:new."</span></span>"
14775c73622aSBram Moolenaar	call remove(s:foldstack, 0)
14785c73622aSBram Moolenaar      endwhile
14795c73622aSBram Moolenaar
14802a8a3ecbSBram Moolenaar      " Now insert an opening for any new folds that start on this line
14815c73622aSBram Moolenaar      let s:firstfold = 1
14825c73622aSBram Moolenaar      while !empty(s:allfolds) && get(s:allfolds,0).firstline == s:lnum
14835c73622aSBram Moolenaar	let s:foldId = s:foldId + 1
1484349b2fb0SBram Moolenaar	let s:new .= "<span id='"
1485349b2fb0SBram Moolenaar	let s:new .= (exists('g:html_diff_win_num') ? "win".g:html_diff_win_num : "")
148631c31679SBram Moolenaar	let s:new .= "fold".s:foldId.s:settings.id_suffix."' class='".s:allfolds[0].type."'>"
1487349b2fb0SBram Moolenaar
14885c73622aSBram Moolenaar
14895c73622aSBram Moolenaar	" Unless disabled, add a fold column for the opening line of a fold.
14905c73622aSBram Moolenaar	"
14915c73622aSBram Moolenaar	" Note that dynamic folds require using css so we just use css to take
14925c73622aSBram Moolenaar	" care of the leading spaces rather than using &nbsp; in the case of
14935c73622aSBram Moolenaar	" html_no_pre to make it easier
1494076e8b2aSBram Moolenaar	if !s:settings.no_foldcolumn
14955c73622aSBram Moolenaar	  " add fold column that can open the new fold
14965c73622aSBram Moolenaar	  if s:allfolds[0].level > 1 && s:firstfold
14976c35beaaSBram Moolenaar	    let s:new = s:new . s:FoldColumn_build('|', s:allfolds[0].level - 1, 0, "",
149831c31679SBram Moolenaar		  \ 'toggle-open FoldColumn','javascript:toggleFold("fold'.s:foldstack[0].id.s:settings.id_suffix.'");')
14995c73622aSBram Moolenaar	  endif
15006c35beaaSBram Moolenaar	  " add the filler spaces separately from the '+' char so that it can be
15016c35beaaSBram Moolenaar	  " shown/hidden separately during a hover unfold
15026c35beaaSBram Moolenaar	  let s:new = s:new . s:FoldColumn_build("+", 1, 0, "",
150331c31679SBram Moolenaar		\ 'toggle-open FoldColumn', 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
15045c73622aSBram Moolenaar	  " If this is not the last fold we're opening on this line, we need
15055c73622aSBram Moolenaar	  " to keep the filler spaces hidden if the fold is opened by mouse
15065c73622aSBram Moolenaar	  " hover. If it is the last fold to open in the line, we shouldn't hide
15075c73622aSBram Moolenaar	  " them, so don't apply the toggle-filler class.
15086c35beaaSBram Moolenaar	  let s:new = s:new . s:FoldColumn_build(" ", 1, s:foldcolumn - s:allfolds[0].level - 1, "",
15096c35beaaSBram Moolenaar		\ 'toggle-open FoldColumn'. (get(s:allfolds, 1, {'firstline': 0}).firstline == s:lnum ?" toggle-filler" :""),
151031c31679SBram Moolenaar		\ 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
15115c73622aSBram Moolenaar
15125c73622aSBram Moolenaar	  " add fold column that can close the new fold
15136c35beaaSBram Moolenaar	  " only add extra blank space if we aren't opening another fold on the
15146c35beaaSBram Moolenaar	  " same line
15155c73622aSBram Moolenaar	  if get(s:allfolds, 1, {'firstline': 0}).firstline != s:lnum
15166c35beaaSBram Moolenaar	    let s:extra_space = s:foldcolumn - s:allfolds[0].level
15176c35beaaSBram Moolenaar	  else
15186c35beaaSBram Moolenaar	    let s:extra_space = 0
15195c73622aSBram Moolenaar	  endif
15206c35beaaSBram Moolenaar	  if s:firstfold
15216c35beaaSBram Moolenaar	    " the first fold in a line has '|' characters from folds opened in
15226c35beaaSBram Moolenaar	    " previous lines, before the '-' for this fold
15236c35beaaSBram Moolenaar	    let s:new .= s:FoldColumn_build('|', s:allfolds[0].level - 1, s:extra_space, '-',
152431c31679SBram Moolenaar		  \ 'toggle-closed FoldColumn', 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
15256c35beaaSBram Moolenaar	  else
15266c35beaaSBram Moolenaar	    " any subsequent folds in the line only add a single '-'
15276c35beaaSBram Moolenaar	    let s:new = s:new . s:FoldColumn_build("-", 1, s:extra_space, "",
152831c31679SBram Moolenaar		  \ 'toggle-closed FoldColumn', 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
15296c35beaaSBram Moolenaar	  endif
15305c73622aSBram Moolenaar	  let s:firstfold = 0
15315c73622aSBram Moolenaar	endif
15325c73622aSBram Moolenaar
15336c35beaaSBram Moolenaar	" Add fold text, moving the span ending to the next line so collapsing
15346c35beaaSBram Moolenaar	" of folds works correctly.
15356c35beaaSBram Moolenaar	" Put numcol in a separate group for sake of unselectable text.
1536543b7ef7SBram Moolenaar	let s:new = s:new . (s:settings.number_lines ? s:HtmlFormat_n(s:numcol, s:FOLDED_ID, 0, 0) : "") . substitute(s:HtmlFormat_t(foldtextresult(s:lnum), s:FOLDED_ID, 0), '</span>', s:HtmlEndline.'\n\0', '')
15375c73622aSBram Moolenaar	let s:new = s:new . "<span class='fulltext'>"
15385c73622aSBram Moolenaar
15395c73622aSBram Moolenaar	" open the fold now that we have the fold text to allow retrieval of
15405c73622aSBram Moolenaar	" fold text for subsequent folds
15415c73622aSBram Moolenaar	execute s:lnum."foldopen"
15425c73622aSBram Moolenaar	call insert(s:foldstack, remove(s:allfolds,0))
15435c73622aSBram Moolenaar	let s:foldstack[0].id = s:foldId
15445c73622aSBram Moolenaar      endwhile
15455c73622aSBram Moolenaar
15465c73622aSBram Moolenaar      " Unless disabled, add a fold column for other lines.
15475c73622aSBram Moolenaar      "
15485c73622aSBram Moolenaar      " Note that dynamic folds require using css so we just use css to take
15495c73622aSBram Moolenaar      " care of the leading spaces rather than using &nbsp; in the case of
15505c73622aSBram Moolenaar      " html_no_pre to make it easier
1551076e8b2aSBram Moolenaar      if !s:settings.no_foldcolumn
15525c73622aSBram Moolenaar	if empty(s:foldstack)
15537510fe74SBram Moolenaar	  " add the empty foldcolumn for unfolded lines if there is a fold
15547510fe74SBram Moolenaar	  " column at all
15557510fe74SBram Moolenaar	  if s:foldcolumn > 0
15566c35beaaSBram Moolenaar	    let s:new = s:new . s:FoldColumn_fill()
15577510fe74SBram Moolenaar	  endif
15585c73622aSBram Moolenaar	else
15595c73622aSBram Moolenaar	  " add the fold column for folds not on the opening line
15605c73622aSBram Moolenaar	  if get(s:foldstack, 0).firstline < s:lnum
15616c35beaaSBram Moolenaar	    let s:new = s:new . s:FoldColumn_build('|', s:foldstack[0].level, s:foldcolumn - s:foldstack[0].level, "",
156231c31679SBram Moolenaar		  \ 'FoldColumn', 'javascript:toggleFold("fold'.s:foldstack[0].id.s:settings.id_suffix.'");')
15635c73622aSBram Moolenaar	  endif
15645c73622aSBram Moolenaar	endif
15655c73622aSBram Moolenaar      endif
15665c73622aSBram Moolenaar    endif
15675c73622aSBram Moolenaar
15685c73622aSBram Moolenaar    " Now continue with the unfolded line text
1569076e8b2aSBram Moolenaar    if s:settings.number_lines
1570543b7ef7SBram Moolenaar      let s:new = s:new . s:HtmlFormat_n(s:numcol, s:LINENR_ID, 0, s:lnum)
157131c31679SBram Moolenaar    elseif s:settings.line_ids
1572543b7ef7SBram Moolenaar      let s:new = s:new . s:HtmlFormat_n("", s:LINENR_ID, 0, s:lnum)
1573071d4279SBram Moolenaar    endif
1574071d4279SBram Moolenaar
157547136d70SBram Moolenaar    " Get the diff attribute, if any.
157647136d70SBram Moolenaar    let s:diffattr = diff_hlID(s:lnum, 1)
157747136d70SBram Moolenaar
15787510fe74SBram Moolenaar    " initialize conceal info to act like not concealed, just in case
15797510fe74SBram Moolenaar    let s:concealinfo = [0, '']
15807510fe74SBram Moolenaar
1581071d4279SBram Moolenaar    " Loop over each character in the line
1582071d4279SBram Moolenaar    let s:col = 1
15838ada2ccaSBram Moolenaar
15848ada2ccaSBram Moolenaar    " most of the time we won't use the diff_id, initialize to zero
15858ada2ccaSBram Moolenaar    let s:diff_id = 0
15868ada2ccaSBram Moolenaar
158735a9aaabSBram Moolenaar    while s:col <= s:len || (s:col == 1 && s:diffattr)
1588071d4279SBram Moolenaar      let s:startcol = s:col " The start column for processing text
1589076e8b2aSBram Moolenaar      if !s:settings.ignore_conceal && has('conceal')
15907510fe74SBram Moolenaar	let s:concealinfo = synconcealed(s:lnum, s:col)
15917510fe74SBram Moolenaar      endif
1592076e8b2aSBram Moolenaar      if !s:settings.ignore_conceal && s:concealinfo[0]
15937510fe74SBram Moolenaar	let s:col = s:col + 1
15947510fe74SBram Moolenaar	" Speed loop (it's small - that's the trick)
15957510fe74SBram Moolenaar	" Go along till we find a change in the match sequence number (ending
15967510fe74SBram Moolenaar	" the specific concealed region) or until there are no more concealed
15977510fe74SBram Moolenaar	" characters.
15987510fe74SBram Moolenaar	while s:col <= s:len && s:concealinfo == synconcealed(s:lnum, s:col) | let s:col = s:col + 1 | endwhile
15997510fe74SBram Moolenaar      elseif s:diffattr
16008ada2ccaSBram Moolenaar	let s:diff_id = diff_hlID(s:lnum, s:col)
16018ada2ccaSBram Moolenaar	let s:id = synID(s:lnum, s:col, 1)
160247136d70SBram Moolenaar	let s:col = s:col + 1
160347136d70SBram Moolenaar	" Speed loop (it's small - that's the trick)
160447136d70SBram Moolenaar	" Go along till we find a change in hlID
16058ada2ccaSBram Moolenaar	while s:col <= s:len && s:id == synID(s:lnum, s:col, 1)
16068ada2ccaSBram Moolenaar	      \   && s:diff_id == diff_hlID(s:lnum, s:col) |
16078ada2ccaSBram Moolenaar	      \     let s:col = s:col + 1 |
16088ada2ccaSBram Moolenaar	      \ endwhile
1609076e8b2aSBram Moolenaar	if s:len < &columns && !s:settings.no_pre
16108ada2ccaSBram Moolenaar	  " Add spaces at the end of the raw text line to extend the changed
16118ada2ccaSBram Moolenaar	  " line to the full width.
16125c73622aSBram Moolenaar	  let s:line = s:line . repeat(' ', &columns - virtcol([s:lnum, s:len]) - s:margin)
161335a9aaabSBram Moolenaar	  let s:len = &columns
161435a9aaabSBram Moolenaar	endif
161547136d70SBram Moolenaar      else
1616071d4279SBram Moolenaar	let s:id = synID(s:lnum, s:col, 1)
1617071d4279SBram Moolenaar	let s:col = s:col + 1
1618071d4279SBram Moolenaar	" Speed loop (it's small - that's the trick)
1619071d4279SBram Moolenaar	" Go along till we find a change in synID
1620071d4279SBram Moolenaar	while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) | let s:col = s:col + 1 | endwhile
162147136d70SBram Moolenaar      endif
1622071d4279SBram Moolenaar
1623076e8b2aSBram Moolenaar      if s:settings.ignore_conceal || !s:concealinfo[0]
16242a8a3ecbSBram Moolenaar	" Expand tabs if needed
162535a9aaabSBram Moolenaar	let s:expandedtab = strpart(s:line, s:startcol - 1, s:col - s:startcol)
16262a8a3ecbSBram Moolenaar	if s:settings.expand_tabs
16275c73622aSBram Moolenaar	  let s:offset = 0
16285c73622aSBram Moolenaar	  let s:idx = stridx(s:expandedtab, "\t")
1629f0d58efcSBram Moolenaar	  let s:tablist = split(&vts,',')
1630f0d58efcSBram Moolenaar	  if empty(s:tablist)
1631f0d58efcSBram Moolenaar	    let s:tablist = [ &ts ]
1632f0d58efcSBram Moolenaar	  endif
1633f0d58efcSBram Moolenaar	  let s:tabidx = 0
1634f0d58efcSBram Moolenaar	  let s:tabwidth = 0
16355c73622aSBram Moolenaar	  while s:idx >= 0
16360c0734d5SBram Moolenaar	    if s:startcol + s:idx == 1
16370c0734d5SBram Moolenaar	      let s:i = s:tablist[0]
16380c0734d5SBram Moolenaar	    else
16390c0734d5SBram Moolenaar	      " Get the character, which could be multiple bytes, which falls
16400c0734d5SBram Moolenaar	      " immediately before the found tab. Extract it by matching a
16410c0734d5SBram Moolenaar	      " character just prior to the column where the tab matches.
16420c0734d5SBram Moolenaar	      " We'll use this to get the byte index of the character
16430c0734d5SBram Moolenaar	      " immediately preceding the tab, so we can then look up the
16440c0734d5SBram Moolenaar	      " virtual column that character appears in, to determine how
16450c0734d5SBram Moolenaar	      " much of the current tabstop has been used up.
16460c0734d5SBram Moolenaar	      if s:idx == 0
16470c0734d5SBram Moolenaar		" if the found tab is the first character in the text being
16480c0734d5SBram Moolenaar		" processed, we need to get the character prior to the text,
16490c0734d5SBram Moolenaar		" given by startcol.
16500c0734d5SBram Moolenaar		let s:prevc = matchstr(s:line, '.\%' . (s:startcol + s:offset) . 'c')
16510c0734d5SBram Moolenaar	      else
16520c0734d5SBram Moolenaar		" Otherwise, the byte index of the tab into s:expandedtab is
16530c0734d5SBram Moolenaar		" given by s:idx.
16540c0734d5SBram Moolenaar		let s:prevc = matchstr(s:expandedtab, '.\%' . (s:idx + 1) . 'c')
16550c0734d5SBram Moolenaar	      endif
16560c0734d5SBram Moolenaar	      let s:vcol = virtcol([s:lnum, s:startcol + s:idx + s:offset - len(s:prevc)])
16570c0734d5SBram Moolenaar
16580c0734d5SBram Moolenaar	      " find the tabstop interval to use for the tab we just found. Keep
16590c0734d5SBram Moolenaar	      " adding tabstops (which could be variable) until we would exceed
16600c0734d5SBram Moolenaar	      " the virtual screen position of the start of the found tab.
16610c0734d5SBram Moolenaar	      while s:vcol >= s:tabwidth + s:tablist[s:tabidx]
1662f0d58efcSBram Moolenaar		let s:tabwidth += s:tablist[s:tabidx]
1663f0d58efcSBram Moolenaar		if s:tabidx < len(s:tablist)-1
1664f0d58efcSBram Moolenaar		  let s:tabidx = s:tabidx+1
1665f0d58efcSBram Moolenaar		endif
1666f0d58efcSBram Moolenaar	      endwhile
1667f0d58efcSBram Moolenaar	      let s:i = s:tablist[s:tabidx] - (s:vcol - s:tabwidth)
16685c73622aSBram Moolenaar	    endif
16690c0734d5SBram Moolenaar	    " update offset to keep the index within the line corresponding to
16700c0734d5SBram Moolenaar	    " actual tab characters instead of replaced spaces; s:idx reflects
16710c0734d5SBram Moolenaar	    " replaced spaces in s:expandedtab, s:offset cancels out all but
16720c0734d5SBram Moolenaar	    " the tab character itself.
16735c73622aSBram Moolenaar	    let s:offset -= s:i - 1
16745c73622aSBram Moolenaar	    let s:expandedtab = substitute(s:expandedtab, '\t', repeat(' ', s:i), '')
16755c73622aSBram Moolenaar	    let s:idx = stridx(s:expandedtab, "\t")
167635a9aaabSBram Moolenaar	  endwhile
16772a8a3ecbSBram Moolenaar	end
167835a9aaabSBram Moolenaar
16797510fe74SBram Moolenaar	" get the highlight group name to use
1680071d4279SBram Moolenaar	let s:id = synIDtrans(s:id)
16817510fe74SBram Moolenaar      else
16827510fe74SBram Moolenaar	" use Conceal highlighting for concealed text
16836c35beaaSBram Moolenaar	let s:id = s:CONCEAL_ID
16847510fe74SBram Moolenaar	let s:expandedtab = s:concealinfo[1]
16857510fe74SBram Moolenaar      endif
16867510fe74SBram Moolenaar
16876c35beaaSBram Moolenaar      " Output the text with the same synID, with class set to the highlight ID
16886c35beaaSBram Moolenaar      " name, unless it has been concealed completely.
16897510fe74SBram Moolenaar      if strlen(s:expandedtab) > 0
1690543b7ef7SBram Moolenaar	let s:new = s:new . s:HtmlFormat(s:expandedtab,  s:id, s:diff_id, "", 0)
16917510fe74SBram Moolenaar      endif
1692071d4279SBram Moolenaar    endwhile
16937b0294cbSBram Moolenaar  endif
1694071d4279SBram Moolenaar
16957510fe74SBram Moolenaar  call extend(s:lines, split(s:new.s:HtmlEndline, '\n', 1))
1696076e8b2aSBram Moolenaar  if !s:settings.no_progress && s:pgb.needs_redraw
1697349b2fb0SBram Moolenaar    redrawstatus
1698349b2fb0SBram Moolenaar    let s:pgb.needs_redraw = 0
1699349b2fb0SBram Moolenaar  endif
1700071d4279SBram Moolenaar  let s:lnum = s:lnum + 1
1701313b7237SBram Moolenaar
1702076e8b2aSBram Moolenaar  if !s:settings.no_progress
1703349b2fb0SBram Moolenaar    call s:pgb.incr()
1704349b2fb0SBram Moolenaar  endif
1705349b2fb0SBram Moolenaarendwhile
1706349b2fb0SBram Moolenaar
1707076e8b2aSBram Moolenaarif s:settings.dynamic_folds
17085c73622aSBram Moolenaar  " finish off any open folds
17095c73622aSBram Moolenaar  while !empty(s:foldstack)
1710349b2fb0SBram Moolenaar    let s:lines[-1].="</span></span>"
17115c73622aSBram Moolenaar    call remove(s:foldstack, 0)
17125c73622aSBram Moolenaar  endwhile
17135c73622aSBram Moolenaar
17145c73622aSBram Moolenaar  " add fold column to the style list if not already there
17156c35beaaSBram Moolenaar  let s:id = s:FOLD_C_ID
17166c35beaaSBram Moolenaar  if !has_key(s:stylelist, s:id)
17176c35beaaSBram Moolenaar    let s:stylelist[s:id] = '.FoldColumn { ' . s:CSS1(s:id) . '}'
17185c73622aSBram Moolenaar  endif
17195c73622aSBram Moolenaarendif
17205c73622aSBram Moolenaar
1721076e8b2aSBram Moolenaarif s:settings.no_pre
1722076e8b2aSBram Moolenaar  if !s:settings.use_css
17238ada2ccaSBram Moolenaar    " Close off the font tag that encapsulates the whole <body>
1724bebca9daSBram Moolenaar    call extend(s:lines, ["</font>", "</body>", "</html>"])
17258ada2ccaSBram Moolenaar  else
17266c35beaaSBram Moolenaar    call extend(s:lines, ["</div>", "</body>", "</html>"])
17278ada2ccaSBram Moolenaar  endif
1728071d4279SBram Moolenaarelse
1729349b2fb0SBram Moolenaar  call extend(s:lines, ["</pre>", "</body>", "</html>"])
1730071d4279SBram Moolenaarendif
1731071d4279SBram Moolenaar
1732349b2fb0SBram Moolenaarexe s:newwin . "wincmd w"
1733349b2fb0SBram Moolenaarcall setline(1, s:lines)
1734349b2fb0SBram Moolenaarunlet s:lines
1735071d4279SBram Moolenaar
17366c35beaaSBram Moolenaar" Mangle modelines so Vim doesn't try to use HTML text as a modeline if editing
17376c35beaaSBram Moolenaar" this file in the future; need to do this after generating all the text in case
17386c35beaaSBram Moolenaar" the modeline text has different highlight groups which all turn out to be
17396c35beaaSBram Moolenaar" stripped from the final output.
1740dd007ed5SBram Moolenaar%s!\v(%(^|\s+)%([Vv]i%(m%([<=>]?\d+)?)?|ex)):!\1\&#0058;!ge
17416c35beaaSBram Moolenaar
1742543b7ef7SBram Moolenaar" The generated HTML is admittedly ugly and takes a LONG time to fold.
1743543b7ef7SBram Moolenaar" Make sure the user doesn't do syntax folding when loading a generated file,
1744543b7ef7SBram Moolenaar" using a modeline.
1745543b7ef7SBram Moolenaarcall append(line('$'), "<!-- vim: set foldmethod=manual : -->")
1746543b7ef7SBram Moolenaar
1747071d4279SBram Moolenaar" Now, when we finally know which, we define the colors and styles
1748076e8b2aSBram Moolenaarif s:settings.use_css
17490c0734d5SBram Moolenaar  1;/<style\>/+1
1750071d4279SBram Moolenaarendif
1751071d4279SBram Moolenaar
1752071d4279SBram Moolenaar" Normal/global attributes
1753076e8b2aSBram Moolenaarif s:settings.use_css
1754076e8b2aSBram Moolenaar  if s:settings.no_pre
17556c35beaaSBram Moolenaar    call append('.', "body { color: " . s:fgc . "; background-color: " . s:bgc . "; font-family: ". s:htmlfont ."; }")
17566c35beaaSBram Moolenaar    +
1757071d4279SBram Moolenaar  else
17586c35beaaSBram Moolenaar    call append('.', "pre { " . s:whitespace . "font-family: ". s:htmlfont ."; color: " . s:fgc . "; background-color: " . s:bgc . "; }")
17596c35beaaSBram Moolenaar    +
1760071d4279SBram Moolenaar    yank
1761071d4279SBram Moolenaar    put
1762071d4279SBram Moolenaar    execute "normal! ^cwbody\e"
17638e5af3e5SBram Moolenaar    " body should not have the wrap formatting, only the pre section
17648e5af3e5SBram Moolenaar    if s:whitespace != ''
17658e5af3e5SBram Moolenaar      exec 's#'.s:whitespace
17668e5af3e5SBram Moolenaar    endif
1767071d4279SBram Moolenaar  endif
17686c35beaaSBram Moolenaar  " fix browser inconsistencies (sometimes within the same browser) of different
17696c35beaaSBram Moolenaar  " default font size for different elements
17706c35beaaSBram Moolenaar  call append('.', '* { font-size: 1em; }')
17716c35beaaSBram Moolenaar  +
17726c35beaaSBram Moolenaar  " if we use any input elements for unselectable content, make sure they look
17736c35beaaSBram Moolenaar  " like normal text
17746c35beaaSBram Moolenaar  if !empty(s:settings.prevent_copy)
17750c0734d5SBram Moolenaar    if s:settings.use_input_for_pc !=# "none"
17766c35beaaSBram Moolenaar      call append('.', 'input { border: none; margin: 0; padding: 0; font-family: '.s:htmlfont.'; }')
17776c35beaaSBram Moolenaar      +
17786c35beaaSBram Moolenaar      " ch units for browsers which support them, em units for a somewhat
17790c0734d5SBram Moolenaar      " reasonable fallback.
17800c0734d5SBram Moolenaar      for w in range(1, 20, 1)
17816c35beaaSBram Moolenaar	call append('.', [
17820c0734d5SBram Moolenaar	      \ "input[size='".w."'] { width: ".w."em; width: ".w."ch; }"
17836c35beaaSBram Moolenaar	      \ ])
17846c35beaaSBram Moolenaar	+
17856c35beaaSBram Moolenaar      endfor
17860c0734d5SBram Moolenaar    endif
17870c0734d5SBram Moolenaar
17880c0734d5SBram Moolenaar    if s:settings.use_input_for_pc !=# 'all'
17890c0734d5SBram Moolenaar      let s:unselectable_styles = []
17900c0734d5SBram Moolenaar      if s:settings.prevent_copy =~# 'f'
17910c0734d5SBram Moolenaar	call add(s:unselectable_styles, 'FoldColumn')
17920c0734d5SBram Moolenaar      endif
17930c0734d5SBram Moolenaar      if s:settings.prevent_copy =~# 'n'
17940c0734d5SBram Moolenaar	call add(s:unselectable_styles, 'LineNr')
17950c0734d5SBram Moolenaar      endif
17960c0734d5SBram Moolenaar      if s:settings.prevent_copy =~# 't' && !s:settings.ignore_folding
17970c0734d5SBram Moolenaar	call add(s:unselectable_styles, 'Folded')
17980c0734d5SBram Moolenaar      endif
17990c0734d5SBram Moolenaar      if s:settings.prevent_copy =~# 'd'
18000c0734d5SBram Moolenaar	call add(s:unselectable_styles, 'DiffDelete')
18010c0734d5SBram Moolenaar      endif
18020c0734d5SBram Moolenaar      if s:settings.use_input_for_pc !=# 'none'
18030c0734d5SBram Moolenaar	call append('.', [
18040c0734d5SBram Moolenaar	      \ '/* Note: IE does not support @supports conditionals, but also does not fully support',
18050c0734d5SBram Moolenaar	      \ '   "content:" with custom content, so we *want* the check to fail */',
18060c0734d5SBram Moolenaar	      \ '@supports ( content: attr(data-custom-content) ) {'
18070c0734d5SBram Moolenaar	      \ ])
18080c0734d5SBram Moolenaar	+3
18090c0734d5SBram Moolenaar      endif
18100c0734d5SBram Moolenaar      " The line number column inside the foldtext is styled just like the fold
18110c0734d5SBram Moolenaar      " text in Vim, but it should use the prevent_copy settings of line number
18120c0734d5SBram Moolenaar      " rather than fold text. Apply the prevent_copy styles to foldtext
18130c0734d5SBram Moolenaar      " specifically for line numbers, which always come after the fold column,
18140c0734d5SBram Moolenaar      " or at the beginning of the line.
18150c0734d5SBram Moolenaar      if s:settings.prevent_copy =~# 'n' && !s:settings.ignore_folding
18160c0734d5SBram Moolenaar	call append('.', [
18170c0734d5SBram Moolenaar	      \ '  .FoldColumn + .Folded, .Folded:first-child { user-select: none; }',
18180c0734d5SBram Moolenaar	      \ '  .FoldColumn + [data-Folded-content]::before, [data-Folded-content]:first-child::before { content: attr(data-Folded-content); }',
18190c0734d5SBram Moolenaar	      \ '  .FoldColumn + [data-Folded-content]::before, [data-Folded-content]:first-child::before { padding-bottom: 1px; display: inline-block; /* match the 1-px padding of standard items with background */ }',
18200c0734d5SBram Moolenaar	      \ '  .FoldColumn + span[data-Folded-content]::before, [data-Folded-content]:first-child::before { cursor: default; }',
18210c0734d5SBram Moolenaar	      \ ])
18220c0734d5SBram Moolenaar	+4
18230c0734d5SBram Moolenaar      endif
18240c0734d5SBram Moolenaar      for s:style_name in s:unselectable_styles
18250c0734d5SBram Moolenaar	call append('.', [
18260c0734d5SBram Moolenaar	      \ '  .'.s:style_name.' { user-select: none; }',
18270c0734d5SBram Moolenaar	      \ '  [data-'.s:style_name.'-content]::before { content: attr(data-'.s:style_name.'-content); }',
18280c0734d5SBram Moolenaar	      \ '  [data-'.s:style_name.'-content]::before { padding-bottom: 1px; display: inline-block; /* match the 1-px padding of standard items with background */ }',
18290c0734d5SBram Moolenaar	      \ '  span[data-'.s:style_name.'-content]::before { cursor: default; }',
18300c0734d5SBram Moolenaar	      \ ])
18310c0734d5SBram Moolenaar	+4
18320c0734d5SBram Moolenaar      endfor
18330c0734d5SBram Moolenaar      if s:settings.use_input_for_pc !=# 'none'
18340c0734d5SBram Moolenaar	call append('.', [
18350c0734d5SBram Moolenaar	      \ '  input { display: none; }',
18360c0734d5SBram Moolenaar	      \ '}'
18370c0734d5SBram Moolenaar	      \ ])
18380c0734d5SBram Moolenaar	+2
18390c0734d5SBram Moolenaar      endif
18400c0734d5SBram Moolenaar      unlet s:unselectable_styles
18410c0734d5SBram Moolenaar    endif
18420c0734d5SBram Moolenaar
18430c0734d5SBram Moolenaar    " Fix mouse cursor shape for the fallback <input> method of uncopyable text
18440c0734d5SBram Moolenaar    if s:settings.use_input_for_pc !=# 'none'
18456c35beaaSBram Moolenaar      if s:settings.prevent_copy =~# 'f'
18466c35beaaSBram Moolenaar	" Make the cursor show active fold columns as active areas, and empty fold
18476c35beaaSBram Moolenaar	" columns as not interactive.
18486c35beaaSBram Moolenaar	call append('.', ['input.FoldColumn { cursor: pointer; }',
18490c0734d5SBram Moolenaar	      \ 'input.FoldColumn[value="'.repeat(' ', s:foldcolumn).'"] { cursor: default; }'
18506c35beaaSBram Moolenaar	      \ ])
18516c35beaaSBram Moolenaar	+2
18520c0734d5SBram Moolenaar	if s:settings.use_input_for_pc !=# 'all'
18530c0734d5SBram Moolenaar	  call append('.', [
18540c0734d5SBram Moolenaar		\ 'a[data-FoldColumn-content="'.repeat(' ', s:foldcolumn).'"] { cursor: default; }'
18550c0734d5SBram Moolenaar		\ ])
18560c0734d5SBram Moolenaar	  +1
18570c0734d5SBram Moolenaar	end
18586c35beaaSBram Moolenaar      endif
18596c35beaaSBram Moolenaar      " make line number column show as non-interactive if not selectable
18606c35beaaSBram Moolenaar      if s:settings.prevent_copy =~# 'n'
18616c35beaaSBram Moolenaar	call append('.', 'input.LineNr { cursor: default; }')
18626c35beaaSBram Moolenaar	+
18636c35beaaSBram Moolenaar      endif
18646c35beaaSBram Moolenaar      " make fold text and line number column within fold text show as
18656c35beaaSBram Moolenaar      " non-interactive if not selectable
18666c35beaaSBram Moolenaar      if (s:settings.prevent_copy =~# 'n' || s:settings.prevent_copy =~# 't') && !s:settings.ignore_folding
18676c35beaaSBram Moolenaar	call append('.', 'input.Folded { cursor: default; }')
18686c35beaaSBram Moolenaar	+
18696c35beaaSBram Moolenaar      endif
18700c0734d5SBram Moolenaar      " make diff filler show as non-interactive if not selectable
18710c0734d5SBram Moolenaar      if s:settings.prevent_copy =~# 'd'
18720c0734d5SBram Moolenaar	call append('.', 'input.DiffDelete { cursor: default; }')
18730c0734d5SBram Moolenaar	+
18740c0734d5SBram Moolenaar      endif
18750c0734d5SBram Moolenaar    endif
18766c35beaaSBram Moolenaar  endif
1877071d4279SBram Moolenaarelse
18780c0734d5SBram Moolenaar  " For Netscape 4, set <body> attributes too, though, strictly speaking, it's
18790c0734d5SBram Moolenaar  " incorrect.
1880543b7ef7SBram Moolenaar  execute '%s:<body\([^>]*\):<body bgcolor="' . s:bgc . '" text="' . s:fgc . '"\1>\r<font face="'. s:htmlfont .'"'
1881071d4279SBram Moolenaarendif
1882071d4279SBram Moolenaar
18836c35beaaSBram Moolenaar" Gather attributes for all other classes. Do diff first so that normal
18846c35beaaSBram Moolenaar" highlight groups are inserted before it.
1885076e8b2aSBram Moolenaarif s:settings.use_css
18866c35beaaSBram Moolenaar  if s:diff_mode
18876c35beaaSBram Moolenaar    call append('.', filter(map(keys(s:diffstylelist), "s:diffstylelist[v:val]"), 'v:val != ""'))
18886c35beaaSBram Moolenaar  endif
18896c35beaaSBram Moolenaar  if !empty(s:stylelist)
18906c35beaaSBram Moolenaar    call append('.', filter(map(keys(s:stylelist), "s:stylelist[v:val]"), 'v:val != ""'))
1891071d4279SBram Moolenaar  endif
1892071d4279SBram Moolenaarendif
1893071d4279SBram Moolenaar
1894071d4279SBram Moolenaar" Add hyperlinks
18956c35beaaSBram Moolenaar" TODO: add option to not do this? Maybe just make the color the same as the
18966c35beaaSBram Moolenaar" text highlight group normally is?
18971cd871b5SBram Moolenaar%s+\(https\=://\S\{-}\)\(\([.,;:}]\=\(\s\|$\)\)\|[\\"'<>]\|&gt;\|&lt;\|&quot;\)+<a href="\1">\1</a>\2+ge
1898071d4279SBram Moolenaar
1899071d4279SBram Moolenaar" The DTD
1900076e8b2aSBram Moolenaarif s:settings.use_xhtml
1901076e8b2aSBram Moolenaar  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\">"
19020c0734d5SBram Moolenaarelseif s:html5
19030c0734d5SBram Moolenaar  exe "normal! gg0i<!DOCTYPE html>\n"
19041cd871b5SBram Moolenaarelse
1905076e8b2aSBram Moolenaar  exe "normal! gg0i<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
19061cd871b5SBram Moolenaarendif
19071cd871b5SBram Moolenaar
1908076e8b2aSBram Moolenaarif s:settings.use_xhtml
19091cd871b5SBram Moolenaar  exe "normal! gg/<html/e\na xmlns=\"http://www.w3.org/1999/xhtml\"\e"
19101cd871b5SBram Moolenaarendif
1911071d4279SBram Moolenaar
1912071d4279SBram Moolenaar" Cleanup
1913071d4279SBram Moolenaar%s:\s\+$::e
1914071d4279SBram Moolenaar
19152a8a3ecbSBram Moolenaar" Restore old settings (new window first)
1916543b7ef7SBram Moolenaar"
1917543b7ef7SBram Moolenaar" Don't bother restoring foldmethod in case it was syntax because the markup is
1918543b7ef7SBram Moolenaar" so weirdly formatted it can take a LONG time.
19198df7f888SBram Moolenaarlet &l:foldenable = s:old_fen
1920071d4279SBram Moolenaarlet &report = s:old_report
1921071d4279SBram Moolenaarlet &title = s:old_title
1922071d4279SBram Moolenaarlet &icon = s:old_icon
1923071d4279SBram Moolenaarlet &paste = s:old_paste
1924071d4279SBram Moolenaarlet &magic = s:old_magic
1925071d4279SBram Moolenaarlet @/ = s:old_search
1926349b2fb0SBram Moolenaarlet &more = s:old_more
19272a8a3ecbSBram Moolenaar
19282a8a3ecbSBram Moolenaar" switch to original window to restore those settings
1929071d4279SBram Moolenaarexe s:orgwin . "wincmd w"
19302a8a3ecbSBram Moolenaar
19312a8a3ecbSBram Moolenaarif !s:settings.expand_tabs
19322a8a3ecbSBram Moolenaar  let &l:isprint = s:old_isprint
19332a8a3ecbSBram Moolenaarendif
1934166af9bbSBram Moolenaarlet &l:stl = s:origwin_stl
1935071d4279SBram Moolenaarlet &l:et = s:old_et
19368df7f888SBram Moolenaarlet &l:scrollbind = s:old_bind
19372a8a3ecbSBram Moolenaar
19382a8a3ecbSBram Moolenaar" and back to the new window again to end there
1939071d4279SBram Moolenaarexe s:newwin . "wincmd w"
19402a8a3ecbSBram Moolenaar
1941166af9bbSBram Moolenaarlet &l:stl = s:newwin_stl
1942349b2fb0SBram Moolenaarexec 'resize' s:old_winheight
1943349b2fb0SBram Moolenaarlet &l:winfixheight = s:old_winfixheight
1944071d4279SBram Moolenaar
1945349b2fb0SBram Moolenaarlet &ls=s:ls
19460c0734d5SBram Moolenaarlet &eventignore=s:ei_sav
1947349b2fb0SBram Moolenaar
1948071d4279SBram Moolenaar" Save a little bit of memory (worth doing?)
19498e5af3e5SBram Moolenaarunlet s:htmlfont s:whitespace
19508df7f888SBram Moolenaarunlet s:old_et s:old_paste s:old_icon s:old_report s:old_title s:old_search
1951543b7ef7SBram Moolenaarunlet s:old_magic s:old_more s:old_fen s:old_winheight
19522a8a3ecbSBram Moolenaarunlet! s:old_isprint
19536c35beaaSBram Moolenaarunlet s:whatterm s:stylelist s:diffstylelist s:lnum s:end s:margin s:fgc s:bgc s:old_winfixheight
19546c35beaaSBram Moolenaarunlet! s:col s:id s:attr s:len s:line s:new s:expandedtab s:concealinfo s:diff_mode
19550c0734d5SBram Moolenaarunlet! s:orgwin s:newwin s:orgbufnr s:idx s:i s:offset s:ls s:ei_sav s:origwin_stl
19568df7f888SBram Moolenaarunlet! s:newwin_stl s:current_syntax
195705159a0cSBram Moolenaarif !v:profiling
1958071d4279SBram Moolenaar  delfunc s:HtmlColor
195935a9aaabSBram Moolenaar  delfunc s:HtmlFormat
1960071d4279SBram Moolenaar  delfunc s:CSS1
19616c35beaaSBram Moolenaar  delfunc s:BuildStyleWrapper
1962076e8b2aSBram Moolenaar  if !s:settings.use_css
1963071d4279SBram Moolenaar    delfunc s:HtmlOpening
1964071d4279SBram Moolenaar    delfunc s:HtmlClosing
1965071d4279SBram Moolenaar  endif
1966076e8b2aSBram Moolenaar  if s:settings.dynamic_folds
19675c73622aSBram Moolenaar    delfunc s:FoldCompare
19685c73622aSBram Moolenaar  endif
19695c73622aSBram Moolenaar
1970076e8b2aSBram Moolenaar  if !s:settings.no_progress
1971349b2fb0SBram Moolenaar    delfunc s:ProgressBar
1972349b2fb0SBram Moolenaar    delfunc s:progressbar.paint
1973349b2fb0SBram Moolenaar    delfunc s:progressbar.incr
1974349b2fb0SBram Moolenaar    unlet s:pgb s:progressbar
1975349b2fb0SBram Moolenaar  endif
1976349b2fb0SBram Moolenaarendif
1977349b2fb0SBram Moolenaar
19788df7f888SBram Moolenaarunlet! s:new_lnum s:diffattr s:difffillchar s:foldfillchar s:HtmlSpace
19796c35beaaSBram Moolenaarunlet! s:LeadingSpace s:HtmlEndline s:firstfold s:numcol s:foldcolumn
19806c35beaaSBram Moolenaarunlet s:foldstack s:allfolds s:foldId s:settings
19815c73622aSBram Moolenaar
19825c73622aSBram Moolenaarlet &cpo = s:cpo_sav
1983349b2fb0SBram Moolenaarunlet! s:cpo_sav
19845c73622aSBram Moolenaar
1985349b2fb0SBram Moolenaar" Make sure any patches will probably use consistent indent
19867c86f4ccSBram Moolenaar"   vim: ts=8 sw=2 sts=2 noet
1987