blob: ea9db154ba2d73313eb682992548e49ed5584b6c [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001" Vim syntax support file
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02002" Maintainer: Ben Fritz <fritzophrenic@gmail.com>
Bram Moolenaar29634562020-01-09 21:46:04 +01003" Last Change: 2020 Jan 05
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02004"
5" Additional contributors:
6"
Bram Moolenaar7510fe72010-07-25 12:46:44 +02007" Original by Bram Moolenaar <Bram@vim.org>
8" Modified by David Ne\v{c}as (Yeti) <yeti@physics.muni.cz>
9" XHTML support by Panagiotis Issaris <takis@lumumba.luc.ac.be>
10" Made w3 compliant by Edd Barrett <vext01@gmail.com>
11" Added html_font. Edd Barrett <vext01@gmail.com>
12" Progress bar based off code from "progressbar widget" plugin by
13" Andreas Politz, heavily modified:
14" http://www.vim.org/scripts/script.php?script_id=2006
Bram Moolenaar349b2fb2010-07-16 20:35:36 +020015"
Bram Moolenaar7510fe72010-07-25 12:46:44 +020016" See Mercurial change logs for more!
Bram Moolenaar071d4272004-06-13 20:20:40 +000017
18" Transform a file into HTML, using the current syntax highlighting.
19
Bram Moolenaar5c736222010-01-06 20:54:52 +010020" this file uses line continuations
21let s:cpo_sav = &cpo
Bram Moolenaar349b2fb2010-07-16 20:35:36 +020022let s:ls = &ls
Bram Moolenaar0c0734d2019-11-26 21:44:46 +010023let s:ei_sav = &eventignore
Bram Moolenaar6c35bea2012-07-25 17:49:10 +020024set cpo&vim
Bram Moolenaar5c736222010-01-06 20:54:52 +010025
Bram Moolenaar0c0734d2019-11-26 21:44:46 +010026" HTML filetype can take a while to load/highlight if the destination file
27" already exists.
28set eventignore+=FileType
29
Bram Moolenaar349b2fb2010-07-16 20:35:36 +020030let s:end=line('$')
Bram Moolenaar349b2fb2010-07-16 20:35:36 +020031
Bram Moolenaar313b7232007-05-05 17:56:55 +000032" Font
Bram Moolenaarb02cbe32010-07-11 22:38:52 +020033if exists("g:html_font")
Bram Moolenaar60cce2f2015-10-13 23:21:27 +020034 if type(g:html_font) == type([])
35 let s:htmlfont = "'". join(g:html_font,"','") . "', monospace"
36 else
37 let s:htmlfont = "'". g:html_font . "', monospace"
38 endif
Bram Moolenaar313b7232007-05-05 17:56:55 +000039else
40 let s:htmlfont = "monospace"
41endif
42
Bram Moolenaar076e8b22010-08-05 21:54:00 +020043let s:settings = tohtml#GetUserSettings()
Bram Moolenaar5c736222010-01-06 20:54:52 +010044
Bram Moolenaar0c0734d2019-11-26 21:44:46 +010045if s:settings.use_xhtml
46 let s:html5 = 0
47elseif s:settings.use_css && !s:settings.no_pre
48 let s:html5 = 1
49else
50 let s:html5 = 0
51endif
52
Bram Moolenaar6c35bea2012-07-25 17:49:10 +020053if !exists('s:FOLDED_ID')
54 let s:FOLDED_ID = hlID("Folded") | lockvar s:FOLDED_ID
55 let s:FOLD_C_ID = hlID("FoldColumn") | lockvar s:FOLD_C_ID
56 let s:LINENR_ID = hlID('LineNr') | lockvar s:LINENR_ID
57 let s:DIFF_D_ID = hlID("DiffDelete") | lockvar s:DIFF_D_ID
58 let s:DIFF_A_ID = hlID("DiffAdd") | lockvar s:DIFF_A_ID
59 let s:DIFF_C_ID = hlID("DiffChange") | lockvar s:DIFF_C_ID
60 let s:DIFF_T_ID = hlID("DiffText") | lockvar s:DIFF_T_ID
61 let s:CONCEAL_ID = hlID('Conceal') | lockvar s:CONCEAL_ID
62endif
63
Bram Moolenaar8e5af3e2011-04-28 19:02:44 +020064" Whitespace
65if s:settings.pre_wrap
66 let s:whitespace = "white-space: pre-wrap; "
67else
68 let s:whitespace = ""
69endif
70
Bram Moolenaar6c35bea2012-07-25 17:49:10 +020071if !empty(s:settings.prevent_copy)
72 if s:settings.no_invalid
73 " User has decided they don't want invalid markup. Still works in
74 " OpenOffice, and for text editors, but when pasting into Microsoft Word the
75 " input elements get pasted too and they cannot be deleted (at least not
76 " easily).
77 let s:unselInputType = ""
78 else
79 " Prevent from copy-pasting the input elements into Microsoft Word where
80 " they cannot be deleted easily by deliberately inserting invalid markup.
81 let s:unselInputType = " type='invalid_input_type'"
82 endif
83endif
84
Bram Moolenaar0c0734d2019-11-26 21:44:46 +010085" When gui colors are not supported, we can only guess the colors.
86" TODO - is this true anymore? Is there a way to ask the terminal what colors
87" each number means or read them from some file?
88if &termguicolors || has("gui_running")
Bram Moolenaar071d4272004-06-13 20:20:40 +000089 let s:whatterm = "gui"
90else
91 let s:whatterm = "cterm"
92 if &t_Co == 8
Bram Moolenaar6c35bea2012-07-25 17:49:10 +020093 let s:cterm_color = {
94 \ 0: "#808080", 1: "#ff6060", 2: "#00ff00", 3: "#ffff00",
95 \ 4: "#8080ff", 5: "#ff40ff", 6: "#00ffff", 7: "#ffffff"
96 \ }
Bram Moolenaar071d4272004-06-13 20:20:40 +000097 else
Bram Moolenaar6c35bea2012-07-25 17:49:10 +020098 let s:cterm_color = {
99 \ 0: "#000000", 1: "#c00000", 2: "#008000", 3: "#804000",
100 \ 4: "#0000c0", 5: "#c000c0", 6: "#008080", 7: "#c0c0c0",
101 \ 8: "#808080", 9: "#ff6060", 10: "#00ff00", 11: "#ffff00",
102 \ 12: "#8080ff", 13: "#ff40ff", 14: "#00ffff", 15: "#ffffff"
103 \ }
Bram Moolenaar313b7232007-05-05 17:56:55 +0000104
105 " Colors for 88 and 256 come from xterm.
106 if &t_Co == 88
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200107 call extend(s:cterm_color, {
108 \ 16: "#000000", 17: "#00008b", 18: "#0000cd", 19: "#0000ff",
109 \ 20: "#008b00", 21: "#008b8b", 22: "#008bcd", 23: "#008bff",
110 \ 24: "#00cd00", 25: "#00cd8b", 26: "#00cdcd", 27: "#00cdff",
111 \ 28: "#00ff00", 29: "#00ff8b", 30: "#00ffcd", 31: "#00ffff",
112 \ 32: "#8b0000", 33: "#8b008b", 34: "#8b00cd", 35: "#8b00ff",
113 \ 36: "#8b8b00", 37: "#8b8b8b", 38: "#8b8bcd", 39: "#8b8bff",
114 \ 40: "#8bcd00", 41: "#8bcd8b", 42: "#8bcdcd", 43: "#8bcdff",
115 \ 44: "#8bff00", 45: "#8bff8b", 46: "#8bffcd", 47: "#8bffff",
116 \ 48: "#cd0000", 49: "#cd008b", 50: "#cd00cd", 51: "#cd00ff",
117 \ 52: "#cd8b00", 53: "#cd8b8b", 54: "#cd8bcd", 55: "#cd8bff",
118 \ 56: "#cdcd00", 57: "#cdcd8b", 58: "#cdcdcd", 59: "#cdcdff",
119 \ 60: "#cdff00", 61: "#cdff8b", 62: "#cdffcd", 63: "#cdffff",
120 \ 64: "#ff0000"
121 \ })
122 call extend(s:cterm_color, {
123 \ 65: "#ff008b", 66: "#ff00cd", 67: "#ff00ff", 68: "#ff8b00",
124 \ 69: "#ff8b8b", 70: "#ff8bcd", 71: "#ff8bff", 72: "#ffcd00",
125 \ 73: "#ffcd8b", 74: "#ffcdcd", 75: "#ffcdff", 76: "#ffff00",
126 \ 77: "#ffff8b", 78: "#ffffcd", 79: "#ffffff", 80: "#2e2e2e",
127 \ 81: "#5c5c5c", 82: "#737373", 83: "#8b8b8b", 84: "#a2a2a2",
128 \ 85: "#b9b9b9", 86: "#d0d0d0", 87: "#e7e7e7"
129 \ })
Bram Moolenaar313b7232007-05-05 17:56:55 +0000130 elseif &t_Co == 256
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200131 call extend(s:cterm_color, {
132 \ 16: "#000000", 17: "#00005f", 18: "#000087", 19: "#0000af",
133 \ 20: "#0000d7", 21: "#0000ff", 22: "#005f00", 23: "#005f5f",
134 \ 24: "#005f87", 25: "#005faf", 26: "#005fd7", 27: "#005fff",
135 \ 28: "#008700", 29: "#00875f", 30: "#008787", 31: "#0087af",
136 \ 32: "#0087d7", 33: "#0087ff", 34: "#00af00", 35: "#00af5f",
137 \ 36: "#00af87", 37: "#00afaf", 38: "#00afd7", 39: "#00afff",
138 \ 40: "#00d700", 41: "#00d75f", 42: "#00d787", 43: "#00d7af",
139 \ 44: "#00d7d7", 45: "#00d7ff", 46: "#00ff00", 47: "#00ff5f",
140 \ 48: "#00ff87", 49: "#00ffaf", 50: "#00ffd7", 51: "#00ffff",
141 \ 52: "#5f0000", 53: "#5f005f", 54: "#5f0087", 55: "#5f00af",
142 \ 56: "#5f00d7", 57: "#5f00ff", 58: "#5f5f00", 59: "#5f5f5f",
143 \ 60: "#5f5f87", 61: "#5f5faf", 62: "#5f5fd7", 63: "#5f5fff",
144 \ 64: "#5f8700"
145 \ })
146 call extend(s:cterm_color, {
147 \ 65: "#5f875f", 66: "#5f8787", 67: "#5f87af", 68: "#5f87d7",
148 \ 69: "#5f87ff", 70: "#5faf00", 71: "#5faf5f", 72: "#5faf87",
149 \ 73: "#5fafaf", 74: "#5fafd7", 75: "#5fafff", 76: "#5fd700",
150 \ 77: "#5fd75f", 78: "#5fd787", 79: "#5fd7af", 80: "#5fd7d7",
151 \ 81: "#5fd7ff", 82: "#5fff00", 83: "#5fff5f", 84: "#5fff87",
152 \ 85: "#5fffaf", 86: "#5fffd7", 87: "#5fffff", 88: "#870000",
153 \ 89: "#87005f", 90: "#870087", 91: "#8700af", 92: "#8700d7",
154 \ 93: "#8700ff", 94: "#875f00", 95: "#875f5f", 96: "#875f87",
155 \ 97: "#875faf", 98: "#875fd7", 99: "#875fff", 100: "#878700",
156 \ 101: "#87875f", 102: "#878787", 103: "#8787af", 104: "#8787d7",
157 \ 105: "#8787ff", 106: "#87af00", 107: "#87af5f", 108: "#87af87",
158 \ 109: "#87afaf", 110: "#87afd7", 111: "#87afff", 112: "#87d700"
159 \ })
160 call extend(s:cterm_color, {
161 \ 113: "#87d75f", 114: "#87d787", 115: "#87d7af", 116: "#87d7d7",
162 \ 117: "#87d7ff", 118: "#87ff00", 119: "#87ff5f", 120: "#87ff87",
163 \ 121: "#87ffaf", 122: "#87ffd7", 123: "#87ffff", 124: "#af0000",
164 \ 125: "#af005f", 126: "#af0087", 127: "#af00af", 128: "#af00d7",
165 \ 129: "#af00ff", 130: "#af5f00", 131: "#af5f5f", 132: "#af5f87",
166 \ 133: "#af5faf", 134: "#af5fd7", 135: "#af5fff", 136: "#af8700",
167 \ 137: "#af875f", 138: "#af8787", 139: "#af87af", 140: "#af87d7",
168 \ 141: "#af87ff", 142: "#afaf00", 143: "#afaf5f", 144: "#afaf87",
169 \ 145: "#afafaf", 146: "#afafd7", 147: "#afafff", 148: "#afd700",
170 \ 149: "#afd75f", 150: "#afd787", 151: "#afd7af", 152: "#afd7d7",
171 \ 153: "#afd7ff", 154: "#afff00", 155: "#afff5f", 156: "#afff87",
172 \ 157: "#afffaf", 158: "#afffd7"
173 \ })
174 call extend(s:cterm_color, {
175 \ 159: "#afffff", 160: "#d70000", 161: "#d7005f", 162: "#d70087",
176 \ 163: "#d700af", 164: "#d700d7", 165: "#d700ff", 166: "#d75f00",
177 \ 167: "#d75f5f", 168: "#d75f87", 169: "#d75faf", 170: "#d75fd7",
178 \ 171: "#d75fff", 172: "#d78700", 173: "#d7875f", 174: "#d78787",
179 \ 175: "#d787af", 176: "#d787d7", 177: "#d787ff", 178: "#d7af00",
180 \ 179: "#d7af5f", 180: "#d7af87", 181: "#d7afaf", 182: "#d7afd7",
181 \ 183: "#d7afff", 184: "#d7d700", 185: "#d7d75f", 186: "#d7d787",
182 \ 187: "#d7d7af", 188: "#d7d7d7", 189: "#d7d7ff", 190: "#d7ff00",
183 \ 191: "#d7ff5f", 192: "#d7ff87", 193: "#d7ffaf", 194: "#d7ffd7",
184 \ 195: "#d7ffff", 196: "#ff0000", 197: "#ff005f", 198: "#ff0087",
185 \ 199: "#ff00af", 200: "#ff00d7", 201: "#ff00ff", 202: "#ff5f00",
186 \ 203: "#ff5f5f", 204: "#ff5f87"
187 \ })
188 call extend(s:cterm_color, {
189 \ 205: "#ff5faf", 206: "#ff5fd7", 207: "#ff5fff", 208: "#ff8700",
190 \ 209: "#ff875f", 210: "#ff8787", 211: "#ff87af", 212: "#ff87d7",
191 \ 213: "#ff87ff", 214: "#ffaf00", 215: "#ffaf5f", 216: "#ffaf87",
192 \ 217: "#ffafaf", 218: "#ffafd7", 219: "#ffafff", 220: "#ffd700",
193 \ 221: "#ffd75f", 222: "#ffd787", 223: "#ffd7af", 224: "#ffd7d7",
194 \ 225: "#ffd7ff", 226: "#ffff00", 227: "#ffff5f", 228: "#ffff87",
195 \ 229: "#ffffaf", 230: "#ffffd7", 231: "#ffffff", 232: "#080808",
196 \ 233: "#121212", 234: "#1c1c1c", 235: "#262626", 236: "#303030",
197 \ 237: "#3a3a3a", 238: "#444444", 239: "#4e4e4e", 240: "#585858",
198 \ 241: "#626262", 242: "#6c6c6c", 243: "#767676", 244: "#808080",
199 \ 245: "#8a8a8a", 246: "#949494", 247: "#9e9e9e", 248: "#a8a8a8",
200 \ 249: "#b2b2b2", 250: "#bcbcbc", 251: "#c6c6c6", 252: "#d0d0d0",
201 \ 253: "#dadada", 254: "#e4e4e4", 255: "#eeeeee"
202 \ })
Bram Moolenaar313b7232007-05-05 17:56:55 +0000203 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000204 endif
205endif
206
207" Return good color specification: in GUI no transformation is done, in
Bram Moolenaar313b7232007-05-05 17:56:55 +0000208" terminal return RGB values of known colors and empty string for unknown
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209if s:whatterm == "gui"
210 function! s:HtmlColor(color)
211 return a:color
212 endfun
213else
214 function! s:HtmlColor(color)
Bram Moolenaar313b7232007-05-05 17:56:55 +0000215 if has_key(s:cterm_color, a:color)
216 return s:cterm_color[a:color]
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217 else
218 return ""
219 endif
220 endfun
221endif
222
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200223" Find out the background and foreground color for use later
224let s:fgc = s:HtmlColor(synIDattr(hlID("Normal"), "fg#", s:whatterm))
225let s:bgc = s:HtmlColor(synIDattr(hlID("Normal"), "bg#", s:whatterm))
226if s:fgc == ""
227 let s:fgc = ( &background == "dark" ? "#ffffff" : "#000000" )
228endif
229if s:bgc == ""
230 let s:bgc = ( &background == "dark" ? "#000000" : "#ffffff" )
231endif
232
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200233if !s:settings.use_css
Bram Moolenaar071d4272004-06-13 20:20:40 +0000234 " Return opening HTML tag for given highlight id
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200235 function! s:HtmlOpening(id, extra_attrs)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236 let a = ""
237 if synIDattr(a:id, "inverse")
238 " For inverse, we always must set both colors (and exchange them)
239 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200240 let a = a . '<span '.a:extra_attrs.'style="background-color: ' . ( x != "" ? x : s:fgc ) . '">'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
242 let a = a . '<font color="' . ( x != "" ? x : s:bgc ) . '">'
243 else
244 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200245 if x != ""
246 let a = a . '<span '.a:extra_attrs.'style="background-color: ' . x . '">'
247 elseif !empty(a:extra_attrs)
248 let a = a . '<span '.a:extra_attrs.'>'
249 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000250 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
251 if x != "" | let a = a . '<font color="' . x . '">' | endif
252 endif
253 if synIDattr(a:id, "bold") | let a = a . "<b>" | endif
254 if synIDattr(a:id, "italic") | let a = a . "<i>" | endif
255 if synIDattr(a:id, "underline") | let a = a . "<u>" | endif
256 return a
257 endfun
258
259 " Return closing HTML tag for given highlight id
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200260 function! s:HtmlClosing(id, has_extra_attrs)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000261 let a = ""
262 if synIDattr(a:id, "underline") | let a = a . "</u>" | endif
263 if synIDattr(a:id, "italic") | let a = a . "</i>" | endif
264 if synIDattr(a:id, "bold") | let a = a . "</b>" | endif
265 if synIDattr(a:id, "inverse")
266 let a = a . '</font></span>'
267 else
268 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
269 if x != "" | let a = a . '</font>' | endif
270 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200271 if x != "" || a:has_extra_attrs | let a = a . '</span>' | endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000272 endif
273 return a
274 endfun
275endif
276
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200277" Use a different function for formatting based on user options. This way we
278" can avoid a lot of logic during the actual execution.
279"
280" Build the function line by line containing only what is needed for the options
281" in use for maximum code sharing with minimal branch logic for greater speed.
282"
283" Note, 'exec' commands do not recognize line continuations, so must concatenate
284" lines rather than continue them.
285if s:settings.use_css
286 " save CSS to a list of rules to add to the output at the end of processing
287
288 " first, get the style names we need
289 let wrapperfunc_lines = [
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200290 \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, make_unselectable, unformatted)',
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200291 \ '',
292 \ ' let l:style_name = synIDattr(a:style_id, "name", s:whatterm)'
293 \ ]
294 if &diff
295 let wrapperfunc_lines += [
296 \ ' let l:diff_style_name = synIDattr(a:diff_style_id, "name", s:whatterm)']
297
298 " Add normal groups and diff groups to separate lists so we can order them to
299 " allow diff highlight to override normal highlight
300
301 " if primary style IS a diff style, grab it from the diff cache instead
302 " (always succeeds because we pre-populate it)
303 let wrapperfunc_lines += [
304 \ '',
305 \ ' if a:style_id == s:DIFF_D_ID || a:style_id == s:DIFF_A_ID ||'.
306 \ ' a:style_id == s:DIFF_C_ID || a:style_id == s:DIFF_T_ID',
307 \ ' let l:saved_style = get(s:diffstylelist,a:style_id)',
308 \ ' else'
309 \ ]
310 endif
311
312 " get primary style info from cache or build it on the fly if not found
313 let wrapperfunc_lines += [
314 \ ' let l:saved_style = get(s:stylelist,a:style_id)',
315 \ ' if type(l:saved_style) == type(0)',
316 \ ' unlet l:saved_style',
317 \ ' let l:saved_style = s:CSS1(a:style_id)',
318 \ ' if l:saved_style != ""',
319 \ ' let l:saved_style = "." . l:style_name . " { " . l:saved_style . "}"',
320 \ ' endif',
321 \ ' let s:stylelist[a:style_id]= l:saved_style',
322 \ ' endif'
323 \ ]
324 if &diff
325 let wrapperfunc_lines += [ ' endif' ]
326 endif
327
328 " Build the wrapper tags around the text. It turns out that caching these
329 " gives pretty much zero performance gain and adds a lot of logic.
330
331 let wrapperfunc_lines += [
332 \ '',
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200333 \ ' if l:saved_style == "" && empty(a:extra_attrs)'
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200334 \ ]
335 if &diff
336 let wrapperfunc_lines += [
337 \ ' if a:diff_style_id <= 0'
338 \ ]
339 endif
340 " no surroundings if neither primary nor diff style has any info
341 let wrapperfunc_lines += [
342 \ ' return a:text'
343 \ ]
344 if &diff
345 " no primary style, but diff style
346 let wrapperfunc_lines += [
347 \ ' else',
348 \ ' return "<span class=\"" .l:diff_style_name . "\">".a:text."</span>"',
349 \ ' endif'
350 \ ]
351 endif
352 " open tag for non-empty primary style
353 let wrapperfunc_lines += [
354 \ ' else']
355 " non-empty primary style. handle either empty or non-empty diff style.
356 "
357 " separate the two classes by a space to apply them both if there is a diff
358 " style name, unless the primary style is empty, then just use the diff style
359 " name
360 let diffstyle =
361 \ (&diff ? '(a:diff_style_id <= 0 ? "" : " ". l:diff_style_name) .'
362 \ : "")
363 if s:settings.prevent_copy == ""
364 let wrapperfunc_lines += [
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200365 \ ' return "<span ".a:extra_attrs."class=\"" . l:style_name .'.diffstyle.'"\">".a:text."</span>"'
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200366 \ ]
367 else
368
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100369 " New method: use generated content in the CSS. The only thing needed here
370 " is a span with no content, with an attribute holding the desired text.
371 "
372 " Old method: use an <input> element when text is unsectable. This is still
373 " used in conditional comments for Internet Explorer, where the new method
374 " doesn't work.
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200375 "
376 " Wrap the <input> in a <span> to allow fixing the stupid bug in some fonts
377 " which cause browsers to display a 1px gap between lines when these
378 " <input>s have a background color (maybe not really a bug, this isn't
379 " well-defined)
380 "
381 " use strwidth, because we care only about how many character boxes are
382 " needed to size the input, we don't care how many characters (including
383 " separately counted composing chars, from strchars()) or bytes (from
384 " len())the string contains. strdisplaywidth() is not needed because none of
385 " the unselectable groups can contain tab characters (fold column, fold
386 " text, line number).
387 "
388 " Note, if maxlength property needs to be added in the future, it will need
389 " to use strchars(), because HTML specifies that the maxlength parameter
390 " uses the number of unique codepoints for its limit.
391 let wrapperfunc_lines += [
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100392 \ ' if a:make_unselectable',
393 \ ' return "<span ".a:extra_attrs."class=\"" . l:style_name .'.diffstyle.'"\"'
394 \ ]
395 if s:settings.use_input_for_pc !=# 'all'
396 let wrapperfunc_lines[-1] .= ' " . "data-" . l:style_name . "-content=\"".a:text."\"'
397 endif
398 let wrapperfunc_lines[-1] .= '>'
399 if s:settings.use_input_for_pc !=# 'none'
400 let wrapperfunc_lines[-1] .=
401 \ '<input'.s:unselInputType.' class=\"" . l:style_name .'.diffstyle.'"\"'.
402 \ ' value=\"".substitute(a:unformatted,''\s\+$'',"","")."\"'.
403 \ ' onselect=''this.blur(); return false;'''.
404 \ ' onmousedown=''this.blur(); return false;'''.
405 \ ' onclick=''this.blur(); return false;'''.
406 \ ' readonly=''readonly'''.
407 \ ' size=\"".strwidth(a:unformatted)."\"'.
408 \ (s:settings.use_xhtml ? '/' : '').'>'
409 endif
410 let wrapperfunc_lines[-1] .= '</span>"'
411 let wrapperfunc_lines += [
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200412 \ ' else',
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200413 \ ' return "<span ".a:extra_attrs."class=\"" . l:style_name .'. diffstyle .'"\">".a:text."</span>"'
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200414 \ ]
415 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200416 let wrapperfunc_lines += [
417 \ ' endif',
418 \ 'endfun'
419 \ ]
420else
421 " Non-CSS method just needs the wrapper.
422 "
423 " Functions used to get opening/closing automatically return null strings if
424 " no styles exist.
425 if &diff
426 let wrapperfunc_lines = [
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200427 \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2)',
428 \ ' return s:HtmlOpening(a:style_id, a:extra_attrs).(a:diff_style_id <= 0 ? "" :'.
429 \ 's:HtmlOpening(a:diff_style_id, "")).a:text.'.
430 \ '(a:diff_style_id <= 0 ? "" : s:HtmlClosing(a:diff_style_id, 0)).s:HtmlClosing(a:style_id, !empty(a:extra_attrs))',
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200431 \ 'endfun'
432 \ ]
433 else
434 let wrapperfunc_lines = [
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200435 \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2)',
436 \ ' return s:HtmlOpening(a:style_id, a:extra_attrs).a:text.s:HtmlClosing(a:style_id, !empty(a:extra_attrs))',
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200437 \ 'endfun'
438 \ ]
439 endif
440endif
441
442" create the function we built line by line above
443exec join(wrapperfunc_lines, "\n")
444
445let s:diff_mode = &diff
446
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000447" Return HTML valid characters enclosed in a span of class style_name with
448" unprintable characters expanded and double spaces replaced as necessary.
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200449"
450" TODO: eliminate unneeded logic like done for BuildStyleWrapper
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200451function! s:HtmlFormat(text, style_id, diff_style_id, extra_attrs, make_unselectable)
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000452 " Replace unprintable characters
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200453 let unformatted = strtrans(a:text)
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000454
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200455 let formatted = unformatted
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +0200456
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000457 " Replace the reserved html characters
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +0100458 let formatted = substitute(formatted, '&', '\&amp;', 'g')
459 let formatted = substitute(formatted, '<', '\&lt;', 'g')
460 let formatted = substitute(formatted, '>', '\&gt;', 'g')
461 let formatted = substitute(formatted, '"', '\&quot;', 'g')
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200462 " &apos; is not valid in HTML but it is in XHTML, so just use the numeric
463 " reference for it instead. Needed because it could appear in quotes
464 " especially if unselectable regions is turned on.
465 let formatted = substitute(formatted, '"', '\&#0039;', 'g')
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +0100466
467 " Replace a "form feed" character with HTML to do a page break
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200468 " TODO: need to prevent this in unselectable areas? Probably it should never
469 " BE in an unselectable area...
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +0100470 let formatted = substitute(formatted, "\x0c", '<hr class="PAGE-BREAK">', 'g')
471
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200472 " Replace double spaces, leading spaces, and trailing spaces if needed
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000473 if ' ' != s:HtmlSpace
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000474 let formatted = substitute(formatted, ' ', s:HtmlSpace . s:HtmlSpace, 'g')
Bram Moolenaar8424a622006-04-19 21:23:36 +0000475 let formatted = substitute(formatted, '^ ', s:HtmlSpace, 'g')
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200476 let formatted = substitute(formatted, ' \+$', s:HtmlSpace, 'g')
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000477 endif
478
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200479 " Enclose in the correct format
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200480 return s:BuildStyleWrapper(a:style_id, a:diff_style_id, a:extra_attrs, formatted, a:make_unselectable, unformatted)
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000481endfun
482
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200483" set up functions to call HtmlFormat in certain ways based on whether the
484" element is supposed to be unselectable or not
485if s:settings.prevent_copy =~# 'n'
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200486 if s:settings.number_lines
Bram Moolenaar31c31672013-06-26 13:28:14 +0200487 if s:settings.line_ids
488 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
489 if a:lnr > 0
490 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)
491 else
492 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)
493 endif
494 endfun
495 else
496 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200497 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)
Bram Moolenaar31c31672013-06-26 13:28:14 +0200498 endfun
499 endif
500 elseif s:settings.line_ids
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200501 " if lines are not being numbered the only reason this function gets called
Bram Moolenaar6c391a72021-09-09 21:55:11 +0200502 " is to put the line IDs on each line; "text" will be empty but lnr will
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200503 " always be non-zero, however we don't want to use the <input> because that
504 " won't work as nice for empty text
505 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
Bram Moolenaar31c31672013-06-26 13:28:14 +0200506 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)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200507 endfun
508 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200509else
Bram Moolenaar31c31672013-06-26 13:28:14 +0200510 if s:settings.line_ids
511 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
512 if a:lnr > 0
513 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)
514 else
515 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)
516 endif
517 endfun
518 else
519 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200520 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)
Bram Moolenaar31c31672013-06-26 13:28:14 +0200521 endfun
522 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200523endif
524if s:settings.prevent_copy =~# 'd'
525 function! s:HtmlFormat_d(text, style_id, diff_style_id)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200526 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200527 endfun
528else
529 function! s:HtmlFormat_d(text, style_id, diff_style_id)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200530 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200531 endfun
532endif
533if s:settings.prevent_copy =~# 'f'
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100534 if s:settings.use_input_for_pc ==# 'none'
535 " Simply space-pad to the desired width inside the generated content (note
536 " that the FoldColumn definition includes a whitespace:pre rule)
537 function! s:FoldColumn_build(char, len, numfill, char2, class, click)
538 return "<a href='#' class='".a:class."' onclick='".a:click."' data-FoldColumn-content='".
539 \ repeat(a:char, a:len).a:char2.repeat(' ', a:numfill).
540 \ "'></a>"
541 endfun
542 function! s:FoldColumn_fill()
543 return s:HtmlFormat(repeat(' ', s:foldcolumn), s:FOLD_C_ID, 0, "", 1)
544 endfun
545 else
546 " Note the <input> elements for fill spaces will have a single space for
547 " content, to allow active cursor CSS selection to work.
548 "
549 " Wrap the whole thing in a span for the 1px padding workaround for gaps.
550 "
551 " Build the function line by line containing only what is needed for the
552 " options in use for maximum code sharing with minimal branch logic for
553 " greater speed.
554 "
555 " Note, 'exec' commands do not recognize line continuations, so must
556 " concatenate lines rather than continue them.
557 let build_fun_lines = [
558 \ 'function! s:FoldColumn_build(char, len, numfill, char2, class, click)',
559 \ ' let l:input_open = "<input readonly=''readonly''".s:unselInputType.'.
560 \ ' " onselect=''this.blur(); return false;''".'.
561 \ ' " onmousedown=''this.blur(); ".a:click." return false;''".'.
562 \ ' " onclick=''return false;'' size=''".'.
563 \ ' string(a:len + (empty(a:char2) ? 0 : 1) + a:numfill) .'.
564 \ ' "'' "',
565 \ ' let l:common_attrs = "class=''FoldColumn'' value=''"',
566 \ ' let l:input_close = (s:settings.use_xhtml ? "'' />" : "''>")'
567 \ ]
568 if s:settings.use_input_for_pc ==# 'fallback'
569 let build_fun_lines += [
570 \ ' let l:gen_content_link ='.
571 \ ' "<a href=''#'' class=''FoldColumn'' onclick=''".a:click."'' data-FoldColumn-content=''".'.
572 \ ' repeat(a:char, a:len).a:char2.repeat('' '', a:numfill).'.
573 \ ' "''></a>"'
574 \ ]
575 endif
576 let build_fun_lines += [
577 \ ' return "<span class=''".a:class."''>".'.
578 \ ' l:input_open.l:common_attrs.repeat(a:char, a:len).(a:char2).'.
579 \ ' l:input_close.'.
580 \ (s:settings.use_input_for_pc ==# 'fallback' ? 'l:gen_content_link.' : "").
581 \ ' "</span>"',
582 \ 'endfun'
583 \ ]
584 " create the function we built line by line above
585 exec join(build_fun_lines, "\n")
586
587 function! s:FoldColumn_fill()
588 return s:FoldColumn_build(' ', s:foldcolumn, 0, '', 'FoldColumn', '')
589 endfun
590 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200591else
592 " For normal fold columns, simply space-pad to the desired width (note that
593 " the FoldColumn definition includes a whitespace:pre rule)
594 function! s:FoldColumn_build(char, len, numfill, char2, class, click)
595 return "<a href='#' class='".a:class."' onclick='".a:click."'>".
596 \ repeat(a:char, a:len).a:char2.repeat(' ', a:numfill).
597 \ "</a>"
598 endfun
599 function! s:FoldColumn_fill()
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200600 return s:HtmlFormat(repeat(' ', s:foldcolumn), s:FOLD_C_ID, 0, "", 0)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200601 endfun
602endif
603if s:settings.prevent_copy =~# 't'
604 " put an extra empty span at the end for dynamic folds, so the linebreak can
605 " be surrounded. Otherwise do it as normal.
606 "
607 " TODO: isn't there a better way to do this, than placing it here and using a
608 " substitute later?
609 if s:settings.dynamic_folds
610 function! s:HtmlFormat_t(text, style_id, diff_style_id)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200611 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1) .
612 \ s:HtmlFormat("", a:style_id, 0, "", 0)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200613 endfun
614 else
615 function! s:HtmlFormat_t(text, style_id, diff_style_id)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200616 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200617 endfun
618 endif
619else
620 function! s:HtmlFormat_t(text, style_id, diff_style_id)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200621 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200622 endfun
623endif
624
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625" Return CSS style describing given highlight id (can be empty)
626function! s:CSS1(id)
627 let a = ""
628 if synIDattr(a:id, "inverse")
629 " For inverse, we always must set both colors (and exchange them)
630 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
631 let a = a . "color: " . ( x != "" ? x : s:bgc ) . "; "
632 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
633 let a = a . "background-color: " . ( x != "" ? x : s:fgc ) . "; "
634 else
635 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
636 if x != "" | let a = a . "color: " . x . "; " | endif
637 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200638 if x != ""
639 let a = a . "background-color: " . x . "; "
640 " stupid hack because almost every browser seems to have at least one font
641 " which shows 1px gaps between lines which have background
642 let a = a . "padding-bottom: 1px; "
643 elseif (a:id == s:FOLDED_ID || a:id == s:LINENR_ID || a:id == s:FOLD_C_ID) && !empty(s:settings.prevent_copy)
644 " input elements default to a different color than the rest of the page
645 let a = a . "background-color: " . s:bgc . "; "
646 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647 endif
648 if synIDattr(a:id, "bold") | let a = a . "font-weight: bold; " | endif
649 if synIDattr(a:id, "italic") | let a = a . "font-style: italic; " | endif
650 if synIDattr(a:id, "underline") | let a = a . "text-decoration: underline; " | endif
651 return a
652endfun
653
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200654if s:settings.dynamic_folds
Bram Moolenaar5c736222010-01-06 20:54:52 +0100655 " compares two folds as stored in our list of folds
656 " A fold is "less" than another if it starts at an earlier line number,
657 " or ends at a later line number, ties broken by fold level
658 function! s:FoldCompare(f1, f2)
659 if a:f1.firstline != a:f2.firstline
660 " put it before if it starts earlier
661 return a:f1.firstline - a:f2.firstline
662 elseif a:f1.lastline != a:f2.lastline
663 " put it before if it ends later
664 return a:f2.lastline - a:f1.lastline
665 else
666 " if folds begin and end on the same lines, put lowest fold level first
667 return a:f1.level - a:f2.level
668 endif
669 endfunction
670
671endif
672
Bram Moolenaar071d4272004-06-13 20:20:40 +0000673
674" Set some options to make it work faster.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675" Don't report changes for :substitute, there will be many of them.
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200676" Don't change other windows; turn off scroll bind temporarily
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677let s:old_title = &title
678let s:old_icon = &icon
679let s:old_et = &l:et
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200680let s:old_bind = &l:scrollbind
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681let s:old_report = &report
682let s:old_search = @/
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200683let s:old_more = &more
Bram Moolenaar071d4272004-06-13 20:20:40 +0000684set notitle noicon
685setlocal et
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200686set nomore
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687set report=1000000
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200688setlocal noscrollbind
Bram Moolenaar071d4272004-06-13 20:20:40 +0000689
Bram Moolenaar7510fe72010-07-25 12:46:44 +0200690if exists(':ownsyntax') && exists('w:current_syntax')
691 let s:current_syntax = w:current_syntax
692elseif exists('b:current_syntax')
693 let s:current_syntax = b:current_syntax
694else
695 let s:current_syntax = 'none'
696endif
697
698if s:current_syntax == ''
699 let s:current_syntax = 'none'
700endif
701
Bram Moolenaarf0d58ef2018-11-16 16:13:44 +0100702" If the user is sourcing this script directly then the plugin version isn't
703" known because the main plugin script didn't load. In the usual case where the
704" user still has the full Vim runtime installed, or has this full plugin
705" installed in a package or something, then we can extract the version from the
706" main plugin file at it's usual spot relative to this file. Otherwise the user
707" is assembling their runtime piecemeal and we have no idea what versions of
708" other files may be present so don't even try to make a guess or assume the
709" presence of other specific files with specific meaning.
710"
711" We don't want to actually source the main plugin file here because the user
712" may have a good reason not to (e.g. they define their own TOhtml command or
713" something).
714"
715" If this seems way too complicated and convoluted, it is. Probably I should
716" have put the version information in the autoload file from the start. But the
717" version has been in the global variable for so long that changing it could
718" break a lot of user scripts.
719if exists("g:loaded_2html_plugin")
720 let s:pluginversion = g:loaded_2html_plugin
721else
722 if !exists("g:unloaded_tohtml_plugin")
723 let s:main_plugin_path = expand("<sfile>:p:h:h")."/plugin/tohtml.vim"
724 if filereadable(s:main_plugin_path)
725 let s:lines = readfile(s:main_plugin_path, "", 20)
726 call filter(s:lines, 'v:val =~ "loaded_2html_plugin = "')
727 if empty(s:lines)
728 let g:unloaded_tohtml_plugin = "unknown"
729 else
730 let g:unloaded_tohtml_plugin = substitute(s:lines[0], '.*loaded_2html_plugin = \([''"]\)\(\%(\1\@!.\)\+\)\1', '\2', '')
731 endif
732 unlet s:lines
733 else
734 let g:unloaded_tohtml_plugin = "unknown"
735 endif
736 unlet s:main_plugin_path
737 endif
738 let s:pluginversion = g:unloaded_tohtml_plugin
739endif
740
Bram Moolenaar071d4272004-06-13 20:20:40 +0000741" Split window to create a buffer with the HTML file.
742let s:orgbufnr = winbufnr(0)
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200743let s:origwin_stl = &l:stl
Bram Moolenaar071d4272004-06-13 20:20:40 +0000744if expand("%") == ""
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200745 if exists('g:html_diff_win_num')
746 exec 'new Untitled_win'.g:html_diff_win_num.'.'.(s:settings.use_xhtml ? 'x' : '').'html'
747 else
748 exec 'new Untitled.'.(s:settings.use_xhtml ? 'x' : '').'html'
749 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000750else
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200751 exec 'new %.'.(s:settings.use_xhtml ? 'x' : '').'html'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000752endif
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200753
754" Resize the new window to very small in order to make it draw faster
755let s:old_winheight = winheight(0)
756let s:old_winfixheight = &l:winfixheight
757if s:old_winheight > 2
758 resize 1 " leave enough room to view one line at a time
759 norm! G
760 norm! zt
761endif
762setlocal winfixheight
763
764let s:newwin_stl = &l:stl
765
766" on the new window, set the least time-consuming fold method
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200767let s:old_fen = &foldenable
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200768setlocal foldmethod=manual
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200769setlocal nofoldenable
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200770
Bram Moolenaar071d4272004-06-13 20:20:40 +0000771let s:newwin = winnr()
772let s:orgwin = bufwinnr(s:orgbufnr)
773
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200774setlocal modifiable
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775%d
776let s:old_paste = &paste
777set paste
778let s:old_magic = &magic
779set magic
780
Bram Moolenaar166af9b2010-11-16 20:34:40 +0100781" set the fileencoding to match the charset we'll be using
782let &l:fileencoding=s:settings.vim_encoding
783
784" According to http://www.w3.org/TR/html4/charset.html#doc-char-set, the byte
785" order mark is highly recommend on the web when using multibyte encodings. But,
786" it is not a good idea to include it on UTF-8 files. Otherwise, let Vim
787" determine when it is actually inserted.
788if s:settings.vim_encoding == 'utf-8'
789 setlocal nobomb
790else
791 setlocal bomb
792endif
793
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200794let s:lines = []
795
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200796if s:settings.use_xhtml
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200797 if s:settings.encoding != ""
798 call add(s:lines, "<?xml version=\"1.0\" encoding=\"" . s:settings.encoding . "\"?>")
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000799 else
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200800 call add(s:lines, "<?xml version=\"1.0\"?>")
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000801 endif
Bram Moolenaar313b7232007-05-05 17:56:55 +0000802 let s:tag_close = ' />'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803else
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000804 let s:tag_close = '>'
805endif
806
807let s:HtmlSpace = ' '
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000808let s:LeadingSpace = ' '
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000809let s:HtmlEndline = ''
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200810if s:settings.no_pre
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000811 let s:HtmlEndline = '<br' . s:tag_close
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200812 let s:LeadingSpace = s:settings.use_xhtml ? '&#160;' : '&nbsp;'
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000813 let s:HtmlSpace = '\' . s:LeadingSpace
Bram Moolenaar071d4272004-06-13 20:20:40 +0000814endif
815
816" HTML header, with the title and generator ;-). Left free space for the CSS,
817" to be filled at the end.
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200818call extend(s:lines, [
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200819 \ "<html>",
820 \ "<head>"])
821" include encoding as close to the top as possible, but only if not already
822" contained in XML information (to avoid haggling over content type)
823if s:settings.encoding != "" && !s:settings.use_xhtml
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100824 if s:html5
825 call add(s:lines, '<meta charset="' . s:settings.encoding . '"' . s:tag_close)
826 else
827 call add(s:lines, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" . s:settings.encoding . '"' . s:tag_close)
828 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000829endif
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200830call extend(s:lines, [
831 \ ("<title>".expand("%:p:~")."</title>"),
832 \ ("<meta name=\"Generator\" content=\"Vim/".v:version/100.".".v:version%100.'"'.s:tag_close),
Bram Moolenaarf0d58ef2018-11-16 16:13:44 +0100833 \ ("<meta name=\"plugin-version\" content=\"".s:pluginversion.'"'.s:tag_close)
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200834 \ ])
Bram Moolenaar7510fe72010-07-25 12:46:44 +0200835call add(s:lines, '<meta name="syntax" content="'.s:current_syntax.'"'.s:tag_close)
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200836call add(s:lines, '<meta name="settings" content="'.
837 \ join(filter(keys(s:settings),'s:settings[v:val]'),',').
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200838 \ ',prevent_copy='.s:settings.prevent_copy.
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100839 \ ',use_input_for_pc='.s:settings.use_input_for_pc.
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200840 \ '"'.s:tag_close)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200841call add(s:lines, '<meta name="colorscheme" content="'.
842 \ (exists('g:colors_name')
843 \ ? g:colors_name
844 \ : 'none'). '"'.s:tag_close)
Bram Moolenaar313b7232007-05-05 17:56:55 +0000845
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200846if s:settings.use_css
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100847 call extend(s:lines, [
848 \ "<style" . (s:html5 ? "" : " type=\"text/css\"") . ">",
849 \ s:settings.use_xhtml ? "" : "<!--"])
850 let s:ieonly = []
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200851 if s:settings.dynamic_folds
852 if s:settings.hover_unfold
Bram Moolenaar5c736222010-01-06 20:54:52 +0100853 " if we are doing hover_unfold, use css 2 with css 1 fallback for IE6
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200854 call extend(s:lines, [
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200855 \ ".FoldColumn { text-decoration: none; white-space: pre; }",
856 \ "",
857 \ "body * { margin: 0; padding: 0; }", "",
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100858 \ ".open-fold > span.Folded { display: none; }",
859 \ ".open-fold > .fulltext { display: inline; }",
860 \ ".closed-fold > .fulltext { display: none; }",
861 \ ".closed-fold > span.Folded { display: inline; }",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200862 \ "",
863 \ ".open-fold > .toggle-open { display: none; }",
864 \ ".open-fold > .toggle-closed { display: inline; }",
865 \ ".closed-fold > .toggle-open { display: inline; }",
866 \ ".closed-fold > .toggle-closed { display: none; }",
867 \ "", "",
868 \ '/* opening a fold while hovering won''t be supported by IE6 and other',
869 \ "similar browsers, but it should fail gracefully. */",
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100870 \ ".closed-fold:hover > .fulltext { display: inline; }",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200871 \ ".closed-fold:hover > .toggle-filler { display: none; }",
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100872 \ ".closed-fold:hover > .Folded { display: none; }"])
873 " TODO: IE6 is REALLY old and I can't even test it anymore. Maybe we
874 " should remove this? Leave it in for now, it was working at one point,
875 " and doesn't affect any modern browsers. Even newer IE versions should
876 " support the above code and ignore the following.
877 let s:ieonly = [
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200878 \ "<!--[if lt IE 7]><style type=\"text/css\">",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200879 \ ".open-fold .fulltext { display: inline; }",
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100880 \ ".open-fold span.Folded { display: none; }",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200881 \ ".open-fold .toggle-open { display: none; }",
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100882 \ ".open-fold .toggle-closed { display: inline; }",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200883 \ "",
884 \ ".closed-fold .fulltext { display: none; }",
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100885 \ ".closed-fold span.Folded { display: inline; }",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200886 \ ".closed-fold .toggle-open { display: inline; }",
887 \ ".closed-fold .toggle-closed { display: none; }",
888 \ "</style>",
889 \ "<![endif]-->",
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100890 \]
Bram Moolenaar5c736222010-01-06 20:54:52 +0100891 else
892 " if we aren't doing hover_unfold, use CSS 1 only
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200893 call extend(s:lines, [
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200894 \ ".FoldColumn { text-decoration: none; white-space: pre; }",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200895 \ ".open-fold .fulltext { display: inline; }",
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100896 \ ".open-fold span.Folded { display: none; }",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200897 \ ".open-fold .toggle-open { display: none; }",
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100898 \ ".open-fold .toggle-closed { display: inline; }",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200899 \ "",
900 \ ".closed-fold .fulltext { display: none; }",
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100901 \ ".closed-fold span.Folded { display: inline; }",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200902 \ ".closed-fold .toggle-open { display: inline; }",
903 \ ".closed-fold .toggle-closed { display: none; }",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200904 \])
Bram Moolenaar5c736222010-01-06 20:54:52 +0100905 endif
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100906 endif
907 " else we aren't doing any dynamic folding, no need for any special rules
908
909 call extend(s:lines, [
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200910 \ s:settings.use_xhtml ? "" : '-->',
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200911 \ "</style>",
912 \])
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100913 call extend(s:lines, s:ieonly)
914 unlet s:ieonly
Bram Moolenaar071d4272004-06-13 20:20:40 +0000915endif
Bram Moolenaar5c736222010-01-06 20:54:52 +0100916
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100917let s:uses_script = s:settings.dynamic_folds || s:settings.line_ids
Bram Moolenaarf0d58ef2018-11-16 16:13:44 +0100918
919" insert script tag if needed
920if s:uses_script
921 call extend(s:lines, [
922 \ "",
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100923 \ "<script" . (s:html5 ? "" : " type='text/javascript'") . ">",
Bram Moolenaarf0d58ef2018-11-16 16:13:44 +0100924 \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])
925endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200926
Bram Moolenaar5c736222010-01-06 20:54:52 +0100927" insert javascript to toggle folds open and closed
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200928if s:settings.dynamic_folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200929 call extend(s:lines, [
930 \ "",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200931 \ "function toggleFold(objID)",
932 \ "{",
933 \ " var fold;",
934 \ " fold = document.getElementById(objID);",
Bram Moolenaar29634562020-01-09 21:46:04 +0100935 \ " if (fold.className == 'closed-fold')",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200936 \ " {",
937 \ " fold.className = 'open-fold';",
938 \ " }",
939 \ " else if (fold.className == 'open-fold')",
940 \ " {",
941 \ " fold.className = 'closed-fold';",
942 \ " }",
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200943 \ "}"
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200944 \ ])
Bram Moolenaar5c736222010-01-06 20:54:52 +0100945endif
946
Bram Moolenaar31c31672013-06-26 13:28:14 +0200947if s:settings.line_ids
948 " insert javascript to get IDs from line numbers, and to open a fold before
949 " jumping to any lines contained therein
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200950 call extend(s:lines, [
951 \ "",
Bram Moolenaar31c31672013-06-26 13:28:14 +0200952 \ "/* function to open any folds containing a jumped-to line before jumping to it */",
953 \ "function JumpToLine()",
954 \ "{",
955 \ " var lineNum;",
956 \ " lineNum = window.location.hash;",
957 \ " lineNum = lineNum.substr(1); /* strip off '#' */",
958 \ "",
959 \ " if (lineNum.indexOf('L') == -1) {",
960 \ " lineNum = 'L'+lineNum;",
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200961 \ " }",
Bram Moolenaarf0d58ef2018-11-16 16:13:44 +0100962 \ " var lineElem = document.getElementById(lineNum);"
Bram Moolenaar31c31672013-06-26 13:28:14 +0200963 \ ])
Bram Moolenaarf0d58ef2018-11-16 16:13:44 +0100964
Bram Moolenaar31c31672013-06-26 13:28:14 +0200965 if s:settings.dynamic_folds
966 call extend(s:lines, [
967 \ "",
968 \ " /* navigate upwards in the DOM tree to open all folds containing the line */",
969 \ " var node = lineElem;",
970 \ " while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')",
971 \ " {",
972 \ " if (node.className == 'closed-fold')",
973 \ " {",
974 \ " node.className = 'open-fold';",
975 \ " }",
976 \ " node = node.parentNode;",
977 \ " }",
978 \ ])
979 endif
980 call extend(s:lines, [
981 \ " /* Always jump to new location even if the line was hidden inside a fold, or",
982 \ " * we corrected the raw number to a line ID.",
983 \ " */",
984 \ " if (lineElem) {",
985 \ " lineElem.scrollIntoView(true);",
986 \ " }",
987 \ " return true;",
988 \ "}",
989 \ "if ('onhashchange' in window) {",
990 \ " window.onhashchange = JumpToLine;",
991 \ "}"
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200992 \ ])
993endif
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200994
Bram Moolenaarf0d58ef2018-11-16 16:13:44 +0100995" insert script closing tag if needed
996if s:uses_script
997 call extend(s:lines, [
998 \ '',
999 \ s:settings.use_xhtml ? '//]]>' : '-->',
1000 \ "</script>"
1001 \ ])
1002endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001003
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001004call extend(s:lines, ["</head>",
1005 \ "<body".(s:settings.line_ids ? " onload='JumpToLine();'" : "").">"])
1006
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001007if s:settings.no_pre
1008 " if we're not using CSS we use a font tag which can't have a div inside
1009 if s:settings.use_css
Bram Moolenaar31c31672013-06-26 13:28:14 +02001010 call extend(s:lines, ["<div id='vimCodeElement".s:settings.id_suffix."'>"])
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001011 endif
1012else
Bram Moolenaar31c31672013-06-26 13:28:14 +02001013 call extend(s:lines, ["<pre id='vimCodeElement".s:settings.id_suffix."'>"])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001014endif
1015
1016exe s:orgwin . "wincmd w"
1017
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001018" caches of style data
1019" initialize to include line numbers if using them
1020if s:settings.number_lines
1021 let s:stylelist = { s:LINENR_ID : ".LineNr { " . s:CSS1( s:LINENR_ID ) . "}" }
1022else
1023 let s:stylelist = {}
1024endif
1025let s:diffstylelist = {
1026 \ s:DIFF_A_ID : ".DiffAdd { " . s:CSS1( s:DIFF_A_ID ) . "}",
1027 \ s:DIFF_C_ID : ".DiffChange { " . s:CSS1( s:DIFF_C_ID ) . "}",
1028 \ s:DIFF_D_ID : ".DiffDelete { " . s:CSS1( s:DIFF_D_ID ) . "}",
1029 \ s:DIFF_T_ID : ".DiffText { " . s:CSS1( s:DIFF_T_ID ) . "}"
1030 \ }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001031
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001032" set up progress bar in the status line
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001033if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001034 " ProgressBar Indicator
1035 let s:progressbar={}
1036
Bram Moolenaar6c391a72021-09-09 21:55:11 +02001037 " Progressbar specific functions
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001038
1039 func! s:SetProgbarColor()
1040 if hlID("TOhtmlProgress") != 0
1041 hi! link TOhtmlProgress_auto TOhtmlProgress
1042 elseif hlID("TOhtmlProgress_auto")==0 ||
1043 \ !exists("s:last_colors_name") || !exists("g:colors_name") ||
1044 \ g:colors_name != s:last_colors_name
1045 let s:last_colors_name = exists("g:colors_name") ? g:colors_name : "none"
1046
1047 let l:diffatr = synIDattr(hlID("DiffDelete"), "reverse", s:whatterm) ? "fg#" : "bg#"
1048 let l:stlatr = synIDattr(hlID("StatusLine"), "reverse", s:whatterm) ? "fg#" : "bg#"
1049
1050 let l:progbar_color = synIDattr(hlID("DiffDelete"), l:diffatr, s:whatterm)
1051 let l:stl_color = synIDattr(hlID("StatusLine"), l:stlatr, s:whatterm)
1052
1053 if "" == l:progbar_color
1054 let l:progbar_color = synIDattr(hlID("DiffDelete"), "reverse", s:whatterm) ? s:fgc : s:bgc
1055 endif
1056 if "" == l:stl_color
1057 let l:stl_color = synIDattr(hlID("StatusLine"), "reverse", s:whatterm) ? s:fgc : s:bgc
1058 endif
1059
1060 if l:progbar_color == l:stl_color
1061 if s:whatterm == 'cterm'
1062 if l:progbar_color >= (&t_Co/2)
1063 let l:progbar_color-=1
1064 else
1065 let l:progbar_color+=1
1066 endif
1067 else
1068 let l:rgb = map(matchlist(l:progbar_color, '#\zs\x\x\ze\(\x\x\)\(\x\x\)')[:2], 'str2nr(v:val, 16)')
1069 let l:avg = (l:rgb[0] + l:rgb[1] + l:rgb[2])/3
1070 if l:avg >= 128
1071 let l:avg_new = l:avg
1072 while l:avg - l:avg_new < 0x15
1073 let l:rgb = map(l:rgb, 'v:val * 3 / 4')
1074 let l:avg_new = (l:rgb[0] + l:rgb[1] + l:rgb[2])/3
1075 endwhile
1076 else
1077 let l:avg_new = l:avg
1078 while l:avg_new - l:avg < 0x15
1079 let l:rgb = map(l:rgb, 'min([max([v:val, 4]) * 5 / 4, 255])')
1080 let l:avg_new = (l:rgb[0] + l:rgb[1] + l:rgb[2])/3
1081 endwhile
1082 endif
1083 let l:progbar_color = printf("#%02x%02x%02x", l:rgb[0], l:rgb[1], l:rgb[2])
1084 endif
1085 echomsg "diff detected progbar color set to" l:progbar_color
1086 endif
1087 exe "hi TOhtmlProgress_auto" s:whatterm."bg=".l:progbar_color
1088 endif
1089 endfun
1090
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001091 func! s:ProgressBar(title, max_value, winnr)
1092 let pgb=copy(s:progressbar)
1093 let pgb.title = a:title.' '
1094 let pgb.max_value = a:max_value
1095 let pgb.winnr = a:winnr
1096 let pgb.cur_value = 0
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001097
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001098 let pgb.items = { 'title' : { 'color' : 'Statusline' },
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001099 \'bar' : { 'color' : 'Statusline' , 'fillcolor' : 'TOhtmlProgress_auto' , 'bg' : 'Statusline' } ,
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001100 \'counter' : { 'color' : 'Statusline' } }
1101 let pgb.last_value = 0
1102 let pgb.needs_redraw = 0
1103 " Note that you must use len(split) instead of len() if you want to use
1104 " unicode in title.
1105 "
1106 " Subtract 3 for spacing around the title.
1107 " Subtract 4 for the percentage display.
1108 " Subtract 2 for spacing before this.
1109 " Subtract 2 more for the '|' on either side of the progress bar
1110 let pgb.subtractedlen=len(split(pgb.title, '\zs'))+3+4+2+2
1111 let pgb.max_len = 0
1112 set laststatus=2
1113 return pgb
1114 endfun
1115
1116 " Function: progressbar.calculate_ticks() {{{1
1117 func! s:progressbar.calculate_ticks(pb_len)
1118 if a:pb_len<=0
1119 let pb_len = 100
1120 else
1121 let pb_len = a:pb_len
1122 endif
1123 let self.progress_ticks = map(range(pb_len+1), "v:val * self.max_value / pb_len")
1124 endfun
1125
1126 "Function: progressbar.paint()
1127 func! s:progressbar.paint()
1128 " Recalculate widths.
1129 let max_len = winwidth(self.winnr)
1130 let pb_len = 0
1131 " always true on first call because of initial value of self.max_len
1132 if max_len != self.max_len
1133 let self.max_len = max_len
1134
1135 " Progressbar length
1136 let pb_len = max_len - self.subtractedlen
1137
1138 call self.calculate_ticks(pb_len)
1139
1140 let self.needs_redraw = 1
1141 let cur_value = 0
1142 let self.pb_len = pb_len
1143 else
1144 " start searching at the last found index to make the search for the
1145 " appropriate tick value normally take 0 or 1 comparisons
1146 let cur_value = self.last_value
1147 let pb_len = self.pb_len
1148 endif
1149
1150 let cur_val_max = pb_len > 0 ? pb_len : 100
1151
1152 " find the current progress bar position based on precalculated thresholds
1153 while cur_value < cur_val_max && self.cur_value > self.progress_ticks[cur_value]
1154 let cur_value += 1
1155 endwhile
1156
1157 " update progress bar
1158 if self.last_value != cur_value || self.needs_redraw || self.cur_value == self.max_value
1159 let self.needs_redraw = 1
1160 let self.last_value = cur_value
1161
1162 let t_color = self.items.title.color
1163 let b_fcolor = self.items.bar.fillcolor
1164 let b_color = self.items.bar.color
1165 let c_color = self.items.counter.color
1166
1167 let stl = "%#".t_color."#%-( ".self.title." %)".
1168 \"%#".b_color."#".
1169 \(pb_len>0 ?
1170 \ ('|%#'.b_fcolor."#%-(".repeat(" ",cur_value)."%)".
1171 \ '%#'.b_color."#".repeat(" ",pb_len-cur_value)."|"):
1172 \ ('')).
1173 \"%=%#".c_color."#%( ".printf("%3.d ",100*self.cur_value/self.max_value)."%% %)"
1174 call setwinvar(self.winnr, '&stl', stl)
1175 endif
1176 endfun
1177
1178 func! s:progressbar.incr( ... )
1179 let self.cur_value += (a:0 ? a:1 : 1)
1180 " if we were making a general-purpose progress bar, we'd need to limit to a
1181 " lower limit as well, but since we always increment with a positive value
1182 " in this script, we only need limit the upper value
1183 let self.cur_value = (self.cur_value > self.max_value ? self.max_value : self.cur_value)
1184 call self.paint()
1185 endfun
1186 " }}}
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001187 if s:settings.dynamic_folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001188 " to process folds we make two passes through each line
1189 let s:pgb = s:ProgressBar("Processing folds:", line('$')*2, s:orgwin)
1190 endif
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001191
1192 call s:SetProgbarColor()
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001193endif
1194
Bram Moolenaar5c736222010-01-06 20:54:52 +01001195" First do some preprocessing for dynamic folding. Do this for the entire file
1196" so we don't accidentally start within a closed fold or something.
1197let s:allfolds = []
1198
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001199if s:settings.dynamic_folds
Bram Moolenaar5c736222010-01-06 20:54:52 +01001200 let s:lnum = 1
1201 let s:end = line('$')
1202 " save the fold text and set it to the default so we can find fold levels
1203 let s:foldtext_save = &foldtext
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001204 setlocal foldtext&
Bram Moolenaar5c736222010-01-06 20:54:52 +01001205
1206 " we will set the foldcolumn in the html to the greater of the maximum fold
1207 " level and the current foldcolumn setting
1208 let s:foldcolumn = &foldcolumn
1209
1210 " get all info needed to describe currently closed folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001211 while s:lnum <= s:end
Bram Moolenaar5c736222010-01-06 20:54:52 +01001212 if foldclosed(s:lnum) == s:lnum
1213 " default fold text has '+-' and then a number of dashes equal to fold
1214 " level, so subtract 2 from index of first non-dash after the dashes
1215 " in order to get the fold level of the current fold
1216 let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2
Bram Moolenaar5c736222010-01-06 20:54:52 +01001217 " store fold info for later use
1218 let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"}
1219 call add(s:allfolds, s:newfold)
1220 " open the fold so we can find any contained folds
1221 execute s:lnum."foldopen"
1222 else
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001223 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001224 call s:pgb.incr()
1225 if s:pgb.needs_redraw
1226 redrawstatus
1227 let s:pgb.needs_redraw = 0
1228 endif
1229 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +01001230 let s:lnum = s:lnum + 1
1231 endif
1232 endwhile
1233
1234 " close all folds to get info for originally open folds
1235 silent! %foldclose!
1236 let s:lnum = 1
1237
1238 " the originally open folds will be all folds we encounter that aren't
1239 " already in the list of closed folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001240 while s:lnum <= s:end
Bram Moolenaar5c736222010-01-06 20:54:52 +01001241 if foldclosed(s:lnum) == s:lnum
1242 " default fold text has '+-' and then a number of dashes equal to fold
1243 " level, so subtract 2 from index of first non-dash after the dashes
1244 " in order to get the fold level of the current fold
1245 let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2
Bram Moolenaar5c736222010-01-06 20:54:52 +01001246 let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"}
1247 " only add the fold if we don't already have it
1248 if empty(s:allfolds) || index(s:allfolds, s:newfold) == -1
1249 let s:newfold.type = "open-fold"
1250 call add(s:allfolds, s:newfold)
1251 endif
1252 " open the fold so we can find any contained folds
1253 execute s:lnum."foldopen"
1254 else
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001255 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001256 call s:pgb.incr()
1257 if s:pgb.needs_redraw
1258 redrawstatus
1259 let s:pgb.needs_redraw = 0
1260 endif
1261 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +01001262 let s:lnum = s:lnum + 1
1263 endif
1264 endwhile
1265
1266 " sort the folds so that we only ever need to look at the first item in the
1267 " list of folds
1268 call sort(s:allfolds, "s:FoldCompare")
1269
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001270 let &l:foldtext = s:foldtext_save
Bram Moolenaar5c736222010-01-06 20:54:52 +01001271 unlet s:foldtext_save
1272
1273 " close all folds again so we can get the fold text as we go
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001274 silent! %foldclose!
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001275
Bram Moolenaar251e1912011-06-19 05:09:16 +02001276 " Go through and remove folds we don't need to (or cannot) process in the
1277 " current conversion range
1278 "
1279 " If a fold is removed which contains other folds, which are included, we need
1280 " to adjust the level of the included folds as used by the conversion logic
1281 " (avoiding special cases is good)
1282 "
1283 " Note any time we remove a fold, either all of the included folds are in it,
1284 " or none of them, because we only remove a fold if neither its start nor its
1285 " end are within the conversion range.
1286 let leveladjust = 0
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001287 for afold in s:allfolds
1288 let removed = 0
1289 if exists("g:html_start_line") && exists("g:html_end_line")
1290 if afold.firstline < g:html_start_line
Bram Moolenaar251e1912011-06-19 05:09:16 +02001291 if afold.lastline <= g:html_end_line && afold.lastline >= g:html_start_line
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001292 " if a fold starts before the range to convert but stops within the
1293 " range, we need to include it. Make it start on the first converted
1294 " line.
1295 let afold.firstline = g:html_start_line
1296 else
1297 " if the fold lies outside the range or the start and stop enclose
1298 " the entire range, don't bother parsing it
1299 call remove(s:allfolds, index(s:allfolds, afold))
1300 let removed = 1
Bram Moolenaar251e1912011-06-19 05:09:16 +02001301 if afold.lastline > g:html_end_line
1302 let leveladjust += 1
1303 endif
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001304 endif
1305 elseif afold.firstline > g:html_end_line
1306 " If the entire fold lies outside the range we need to remove it.
1307 call remove(s:allfolds, index(s:allfolds, afold))
1308 let removed = 1
1309 endif
1310 elseif exists("g:html_start_line")
1311 if afold.firstline < g:html_start_line
1312 " if there is no last line, but there is a first line, the end of the
1313 " fold will always lie within the region of interest, so keep it
1314 let afold.firstline = g:html_start_line
1315 endif
1316 elseif exists("g:html_end_line")
1317 " if there is no first line we default to the first line in the buffer so
1318 " the fold start will always be included if the fold itself is included.
1319 " If however the entire fold lies outside the range we need to remove it.
1320 if afold.firstline > g:html_end_line
1321 call remove(s:allfolds, index(s:allfolds, afold))
1322 let removed = 1
1323 endif
1324 endif
1325 if !removed
Bram Moolenaar251e1912011-06-19 05:09:16 +02001326 let afold.level -= leveladjust
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001327 if afold.level+1 > s:foldcolumn
1328 let s:foldcolumn = afold.level+1
1329 endif
1330 endif
1331 endfor
Bram Moolenaar251e1912011-06-19 05:09:16 +02001332
1333 " if we've removed folds containing the conversion range from processing,
1334 " getting foldtext as we go won't know to open the removed folds, so the
1335 " foldtext would be wrong; open them now.
1336 "
1337 " Note that only when a start and an end line is specified will a fold
1338 " containing the current range ever be removed.
1339 while leveladjust > 0
1340 exe g:html_start_line."foldopen"
1341 let leveladjust -= 1
1342 endwhile
Bram Moolenaar5c736222010-01-06 20:54:52 +01001343endif
1344
1345" Now loop over all lines in the original text to convert to html.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001346" Use html_start_line and html_end_line if they are set.
Bram Moolenaarb02cbe32010-07-11 22:38:52 +02001347if exists("g:html_start_line")
Bram Moolenaar071d4272004-06-13 20:20:40 +00001348 let s:lnum = html_start_line
1349 if s:lnum < 1 || s:lnum > line("$")
1350 let s:lnum = 1
1351 endif
1352else
1353 let s:lnum = 1
1354endif
Bram Moolenaarb02cbe32010-07-11 22:38:52 +02001355if exists("g:html_end_line")
Bram Moolenaar071d4272004-06-13 20:20:40 +00001356 let s:end = html_end_line
1357 if s:end < s:lnum || s:end > line("$")
1358 let s:end = line("$")
1359 endif
1360else
1361 let s:end = line("$")
1362endif
1363
Bram Moolenaar5c736222010-01-06 20:54:52 +01001364" stack to keep track of all the folds containing the current line
1365let s:foldstack = []
1366
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001367if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001368 let s:pgb = s:ProgressBar("Processing lines:", s:end - s:lnum + 1, s:orgwin)
1369endif
1370
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001371if s:settings.number_lines
Bram Moolenaar5c736222010-01-06 20:54:52 +01001372 let s:margin = strlen(s:end) + 1
1373else
1374 let s:margin = 0
1375endif
1376
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001377if has('folding') && !s:settings.ignore_folding
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001378 let s:foldfillchar = &fillchars[matchend(&fillchars, 'fold:')]
1379 if s:foldfillchar == ''
1380 let s:foldfillchar = '-'
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001381 endif
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001382endif
1383let s:difffillchar = &fillchars[matchend(&fillchars, 'diff:')]
1384if s:difffillchar == ''
1385 let s:difffillchar = '-'
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001386endif
1387
Bram Moolenaar5c736222010-01-06 20:54:52 +01001388let s:foldId = 0
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001389
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001390if !s:settings.expand_tabs
1391 " If keeping tabs, add them to printable characters so we keep them when
1392 " formatting text (strtrans() doesn't replace printable chars)
1393 let s:old_isprint = &isprint
1394 setlocal isprint+=9
1395endif
1396
Bram Moolenaar071d4272004-06-13 20:20:40 +00001397while s:lnum <= s:end
1398
Bram Moolenaar47136d72004-10-12 20:02:24 +00001399 " If there are filler lines for diff mode, show these above the line.
1400 let s:filler = diff_filler(s:lnum)
1401 if s:filler > 0
1402 let s:n = s:filler
1403 while s:n > 0
Bram Moolenaar5c736222010-01-06 20:54:52 +01001404 let s:new = repeat(s:difffillchar, 3)
Bram Moolenaar47136d72004-10-12 20:02:24 +00001405
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001406 if s:n > 2 && s:n < s:filler && !s:settings.whole_filler
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001407 let s:new = s:new . " " . s:filler . " inserted lines "
1408 let s:n = 2
1409 endif
1410
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001411 if !s:settings.no_pre
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001412 " HTML line wrapping is off--go ahead and fill to the margin
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001413 " TODO: what about when CSS wrapping is turned on?
Bram Moolenaar5c736222010-01-06 20:54:52 +01001414 let s:new = s:new . repeat(s:difffillchar, &columns - strlen(s:new) - s:margin)
1415 else
1416 let s:new = s:new . repeat(s:difffillchar, 3)
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001417 endif
1418
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001419 let s:new = s:HtmlFormat_d(s:new, s:DIFF_D_ID, 0)
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001420 if s:settings.number_lines
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001421 " Indent if line numbering is on. Indent gets style of line number
1422 " column.
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001423 let s:new = s:HtmlFormat_n(repeat(' ', s:margin), s:LINENR_ID, 0, 0) . s:new
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001424 endif
1425 if s:settings.dynamic_folds && !s:settings.no_foldcolumn && s:foldcolumn > 0
1426 " Indent for foldcolumn if there is one. Assume it's empty, there should
1427 " not be a fold for deleted lines in diff mode.
1428 let s:new = s:FoldColumn_fill() . s:new
Bram Moolenaar5c736222010-01-06 20:54:52 +01001429 endif
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001430 call add(s:lines, s:new.s:HtmlEndline)
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001431
Bram Moolenaar47136d72004-10-12 20:02:24 +00001432 let s:n = s:n - 1
1433 endwhile
1434 unlet s:n
1435 endif
1436 unlet s:filler
1437
1438 " Start the line with the line number.
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001439 if s:settings.number_lines
Bram Moolenaar5c736222010-01-06 20:54:52 +01001440 let s:numcol = repeat(' ', s:margin - 1 - strlen(s:lnum)) . s:lnum . ' '
Bram Moolenaar47136d72004-10-12 20:02:24 +00001441 endif
1442
Bram Moolenaar5c736222010-01-06 20:54:52 +01001443 let s:new = ""
1444
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001445 if has('folding') && !s:settings.ignore_folding && foldclosed(s:lnum) > -1 && !s:settings.dynamic_folds
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001446 "
Bram Moolenaar5c736222010-01-06 20:54:52 +01001447 " This is the beginning of a folded block (with no dynamic folding)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001448 let s:new = foldtextresult(s:lnum)
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001449 if !s:settings.no_pre
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001450 " HTML line wrapping is off--go ahead and fill to the margin
1451 let s:new = s:new . repeat(s:foldfillchar, &columns - strlen(s:new))
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001452 endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001453
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001454 " put numcol in a separate group for sake of unselectable text
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001455 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)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001456
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001457 " Skip to the end of the fold
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001458 let s:new_lnum = foldclosedend(s:lnum)
1459
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001460 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001461 call s:pgb.incr(s:new_lnum - s:lnum)
1462 endif
1463
1464 let s:lnum = s:new_lnum
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001465
1466 else
1467 "
Bram Moolenaar5c736222010-01-06 20:54:52 +01001468 " A line that is not folded, or doing dynamic folding.
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001469 "
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001470 let s:line = getline(s:lnum)
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001471 let s:len = strlen(s:line)
1472
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001473 if s:settings.dynamic_folds
Bram Moolenaar5c736222010-01-06 20:54:52 +01001474 " First insert a closing for any open folds that end on this line
1475 while !empty(s:foldstack) && get(s:foldstack,0).lastline == s:lnum-1
1476 let s:new = s:new."</span></span>"
1477 call remove(s:foldstack, 0)
1478 endwhile
1479
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001480 " Now insert an opening for any new folds that start on this line
Bram Moolenaar5c736222010-01-06 20:54:52 +01001481 let s:firstfold = 1
1482 while !empty(s:allfolds) && get(s:allfolds,0).firstline == s:lnum
1483 let s:foldId = s:foldId + 1
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001484 let s:new .= "<span id='"
1485 let s:new .= (exists('g:html_diff_win_num') ? "win".g:html_diff_win_num : "")
Bram Moolenaar31c31672013-06-26 13:28:14 +02001486 let s:new .= "fold".s:foldId.s:settings.id_suffix."' class='".s:allfolds[0].type."'>"
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001487
Bram Moolenaar5c736222010-01-06 20:54:52 +01001488
1489 " Unless disabled, add a fold column for the opening line of a fold.
1490 "
1491 " Note that dynamic folds require using css so we just use css to take
1492 " care of the leading spaces rather than using &nbsp; in the case of
1493 " html_no_pre to make it easier
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001494 if !s:settings.no_foldcolumn
Bram Moolenaar5c736222010-01-06 20:54:52 +01001495 " add fold column that can open the new fold
1496 if s:allfolds[0].level > 1 && s:firstfold
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001497 let s:new = s:new . s:FoldColumn_build('|', s:allfolds[0].level - 1, 0, "",
Bram Moolenaar31c31672013-06-26 13:28:14 +02001498 \ 'toggle-open FoldColumn','javascript:toggleFold("fold'.s:foldstack[0].id.s:settings.id_suffix.'");')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001499 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001500 " add the filler spaces separately from the '+' char so that it can be
1501 " shown/hidden separately during a hover unfold
1502 let s:new = s:new . s:FoldColumn_build("+", 1, 0, "",
Bram Moolenaar31c31672013-06-26 13:28:14 +02001503 \ 'toggle-open FoldColumn', 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001504 " If this is not the last fold we're opening on this line, we need
1505 " to keep the filler spaces hidden if the fold is opened by mouse
1506 " hover. If it is the last fold to open in the line, we shouldn't hide
1507 " them, so don't apply the toggle-filler class.
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001508 let s:new = s:new . s:FoldColumn_build(" ", 1, s:foldcolumn - s:allfolds[0].level - 1, "",
1509 \ 'toggle-open FoldColumn'. (get(s:allfolds, 1, {'firstline': 0}).firstline == s:lnum ?" toggle-filler" :""),
Bram Moolenaar31c31672013-06-26 13:28:14 +02001510 \ 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001511
1512 " add fold column that can close the new fold
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001513 " only add extra blank space if we aren't opening another fold on the
1514 " same line
Bram Moolenaar5c736222010-01-06 20:54:52 +01001515 if get(s:allfolds, 1, {'firstline': 0}).firstline != s:lnum
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001516 let s:extra_space = s:foldcolumn - s:allfolds[0].level
1517 else
1518 let s:extra_space = 0
Bram Moolenaar5c736222010-01-06 20:54:52 +01001519 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001520 if s:firstfold
1521 " the first fold in a line has '|' characters from folds opened in
1522 " previous lines, before the '-' for this fold
1523 let s:new .= s:FoldColumn_build('|', s:allfolds[0].level - 1, s:extra_space, '-',
Bram Moolenaar31c31672013-06-26 13:28:14 +02001524 \ 'toggle-closed FoldColumn', 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001525 else
1526 " any subsequent folds in the line only add a single '-'
1527 let s:new = s:new . s:FoldColumn_build("-", 1, s:extra_space, "",
Bram Moolenaar31c31672013-06-26 13:28:14 +02001528 \ 'toggle-closed FoldColumn', 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001529 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +01001530 let s:firstfold = 0
1531 endif
1532
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001533 " Add fold text, moving the span ending to the next line so collapsing
1534 " of folds works correctly.
1535 " Put numcol in a separate group for sake of unselectable text.
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001536 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', '')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001537 let s:new = s:new . "<span class='fulltext'>"
1538
1539 " open the fold now that we have the fold text to allow retrieval of
1540 " fold text for subsequent folds
1541 execute s:lnum."foldopen"
1542 call insert(s:foldstack, remove(s:allfolds,0))
1543 let s:foldstack[0].id = s:foldId
1544 endwhile
1545
1546 " Unless disabled, add a fold column for other lines.
1547 "
1548 " Note that dynamic folds require using css so we just use css to take
1549 " care of the leading spaces rather than using &nbsp; in the case of
1550 " html_no_pre to make it easier
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001551 if !s:settings.no_foldcolumn
Bram Moolenaar5c736222010-01-06 20:54:52 +01001552 if empty(s:foldstack)
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001553 " add the empty foldcolumn for unfolded lines if there is a fold
1554 " column at all
1555 if s:foldcolumn > 0
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001556 let s:new = s:new . s:FoldColumn_fill()
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001557 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +01001558 else
1559 " add the fold column for folds not on the opening line
1560 if get(s:foldstack, 0).firstline < s:lnum
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001561 let s:new = s:new . s:FoldColumn_build('|', s:foldstack[0].level, s:foldcolumn - s:foldstack[0].level, "",
Bram Moolenaar31c31672013-06-26 13:28:14 +02001562 \ 'FoldColumn', 'javascript:toggleFold("fold'.s:foldstack[0].id.s:settings.id_suffix.'");')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001563 endif
1564 endif
1565 endif
1566 endif
1567
1568 " Now continue with the unfolded line text
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001569 if s:settings.number_lines
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001570 let s:new = s:new . s:HtmlFormat_n(s:numcol, s:LINENR_ID, 0, s:lnum)
Bram Moolenaar31c31672013-06-26 13:28:14 +02001571 elseif s:settings.line_ids
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001572 let s:new = s:new . s:HtmlFormat_n("", s:LINENR_ID, 0, s:lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001573 endif
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001574
Bram Moolenaar47136d72004-10-12 20:02:24 +00001575 " Get the diff attribute, if any.
1576 let s:diffattr = diff_hlID(s:lnum, 1)
1577
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001578 " initialize conceal info to act like not concealed, just in case
1579 let s:concealinfo = [0, '']
1580
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001581 " Loop over each character in the line
1582 let s:col = 1
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001583
1584 " most of the time we won't use the diff_id, initialize to zero
1585 let s:diff_id = 0
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001586
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001587 while s:col <= s:len || (s:col == 1 && s:diffattr)
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001588 let s:startcol = s:col " The start column for processing text
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001589 if !s:settings.ignore_conceal && has('conceal')
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001590 let s:concealinfo = synconcealed(s:lnum, s:col)
1591 endif
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001592 if !s:settings.ignore_conceal && s:concealinfo[0]
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001593 let s:col = s:col + 1
1594 " Speed loop (it's small - that's the trick)
1595 " Go along till we find a change in the match sequence number (ending
1596 " the specific concealed region) or until there are no more concealed
1597 " characters.
1598 while s:col <= s:len && s:concealinfo == synconcealed(s:lnum, s:col) | let s:col = s:col + 1 | endwhile
1599 elseif s:diffattr
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001600 let s:diff_id = diff_hlID(s:lnum, s:col)
1601 let s:id = synID(s:lnum, s:col, 1)
Bram Moolenaar47136d72004-10-12 20:02:24 +00001602 let s:col = s:col + 1
1603 " Speed loop (it's small - that's the trick)
1604 " Go along till we find a change in hlID
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001605 while s:col <= s:len && s:id == synID(s:lnum, s:col, 1)
1606 \ && s:diff_id == diff_hlID(s:lnum, s:col) |
1607 \ let s:col = s:col + 1 |
1608 \ endwhile
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001609 if s:len < &columns && !s:settings.no_pre
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001610 " Add spaces at the end of the raw text line to extend the changed
1611 " line to the full width.
Bram Moolenaar5c736222010-01-06 20:54:52 +01001612 let s:line = s:line . repeat(' ', &columns - virtcol([s:lnum, s:len]) - s:margin)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001613 let s:len = &columns
1614 endif
Bram Moolenaar47136d72004-10-12 20:02:24 +00001615 else
1616 let s:id = synID(s:lnum, s:col, 1)
1617 let s:col = s:col + 1
1618 " Speed loop (it's small - that's the trick)
1619 " Go along till we find a change in synID
1620 while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) | let s:col = s:col + 1 | endwhile
1621 endif
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001622
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001623 if s:settings.ignore_conceal || !s:concealinfo[0]
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001624 " Expand tabs if needed
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001625 let s:expandedtab = strpart(s:line, s:startcol - 1, s:col - s:startcol)
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001626 if s:settings.expand_tabs
1627 let s:offset = 0
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001628 let s:idx = stridx(s:expandedtab, "\t")
Bram Moolenaarf0d58ef2018-11-16 16:13:44 +01001629 let s:tablist = split(&vts,',')
1630 if empty(s:tablist)
1631 let s:tablist = [ &ts ]
1632 endif
1633 let s:tabidx = 0
1634 let s:tabwidth = 0
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001635 while s:idx >= 0
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001636 if s:startcol + s:idx == 1
1637 let s:i = s:tablist[0]
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001638 else
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001639 " Get the character, which could be multiple bytes, which falls
1640 " immediately before the found tab. Extract it by matching a
1641 " character just prior to the column where the tab matches.
1642 " We'll use this to get the byte index of the character
1643 " immediately preceding the tab, so we can then look up the
1644 " virtual column that character appears in, to determine how
1645 " much of the current tabstop has been used up.
1646 if s:idx == 0
1647 " if the found tab is the first character in the text being
1648 " processed, we need to get the character prior to the text,
1649 " given by startcol.
1650 let s:prevc = matchstr(s:line, '.\%' . (s:startcol + s:offset) . 'c')
1651 else
1652 " Otherwise, the byte index of the tab into s:expandedtab is
1653 " given by s:idx.
1654 let s:prevc = matchstr(s:expandedtab, '.\%' . (s:idx + 1) . 'c')
1655 endif
1656 let s:vcol = virtcol([s:lnum, s:startcol + s:idx + s:offset - len(s:prevc)])
1657
1658 " find the tabstop interval to use for the tab we just found. Keep
1659 " adding tabstops (which could be variable) until we would exceed
1660 " the virtual screen position of the start of the found tab.
1661 while s:vcol >= s:tabwidth + s:tablist[s:tabidx]
1662 let s:tabwidth += s:tablist[s:tabidx]
1663 if s:tabidx < len(s:tablist)-1
1664 let s:tabidx = s:tabidx+1
1665 endif
1666 endwhile
1667 let s:i = s:tablist[s:tabidx] - (s:vcol - s:tabwidth)
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001668 endif
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001669 " update offset to keep the index within the line corresponding to
1670 " actual tab characters instead of replaced spaces; s:idx reflects
1671 " replaced spaces in s:expandedtab, s:offset cancels out all but
1672 " the tab character itself.
1673 let s:offset -= s:i - 1
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001674 let s:expandedtab = substitute(s:expandedtab, '\t', repeat(' ', s:i), '')
1675 let s:idx = stridx(s:expandedtab, "\t")
1676 endwhile
1677 end
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001678
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001679 " get the highlight group name to use
1680 let s:id = synIDtrans(s:id)
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001681 else
1682 " use Conceal highlighting for concealed text
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001683 let s:id = s:CONCEAL_ID
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001684 let s:expandedtab = s:concealinfo[1]
1685 endif
1686
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001687 " Output the text with the same synID, with class set to the highlight ID
1688 " name, unless it has been concealed completely.
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001689 if strlen(s:expandedtab) > 0
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001690 let s:new = s:new . s:HtmlFormat(s:expandedtab, s:id, s:diff_id, "", 0)
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001691 endif
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001692 endwhile
1693 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001694
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001695 call extend(s:lines, split(s:new.s:HtmlEndline, '\n', 1))
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001696 if !s:settings.no_progress && s:pgb.needs_redraw
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001697 redrawstatus
1698 let s:pgb.needs_redraw = 0
1699 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001700 let s:lnum = s:lnum + 1
Bram Moolenaar313b7232007-05-05 17:56:55 +00001701
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001702 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001703 call s:pgb.incr()
1704 endif
1705endwhile
1706
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001707if s:settings.dynamic_folds
Bram Moolenaar5c736222010-01-06 20:54:52 +01001708 " finish off any open folds
1709 while !empty(s:foldstack)
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001710 let s:lines[-1].="</span></span>"
Bram Moolenaar5c736222010-01-06 20:54:52 +01001711 call remove(s:foldstack, 0)
1712 endwhile
1713
1714 " add fold column to the style list if not already there
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001715 let s:id = s:FOLD_C_ID
1716 if !has_key(s:stylelist, s:id)
1717 let s:stylelist[s:id] = '.FoldColumn { ' . s:CSS1(s:id) . '}'
Bram Moolenaar5c736222010-01-06 20:54:52 +01001718 endif
1719endif
1720
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001721if s:settings.no_pre
1722 if !s:settings.use_css
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001723 " Close off the font tag that encapsulates the whole <body>
Bram Moolenaarbebca9d2010-08-07 15:47:30 +02001724 call extend(s:lines, ["</font>", "</body>", "</html>"])
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001725 else
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001726 call extend(s:lines, ["</div>", "</body>", "</html>"])
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001727 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728else
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001729 call extend(s:lines, ["</pre>", "</body>", "</html>"])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001730endif
1731
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001732exe s:newwin . "wincmd w"
1733call setline(1, s:lines)
1734unlet s:lines
Bram Moolenaar071d4272004-06-13 20:20:40 +00001735
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001736" Mangle modelines so Vim doesn't try to use HTML text as a modeline if editing
1737" this file in the future; need to do this after generating all the text in case
1738" the modeline text has different highlight groups which all turn out to be
1739" stripped from the final output.
Bram Moolenaardd007ed2013-07-09 15:44:17 +02001740%s!\v(%(^|\s+)%([Vv]i%(m%([<=>]?\d+)?)?|ex)):!\1\&#0058;!ge
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001741
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001742" The generated HTML is admittedly ugly and takes a LONG time to fold.
1743" Make sure the user doesn't do syntax folding when loading a generated file,
1744" using a modeline.
1745call append(line('$'), "<!-- vim: set foldmethod=manual : -->")
1746
Bram Moolenaar071d4272004-06-13 20:20:40 +00001747" Now, when we finally know which, we define the colors and styles
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001748if s:settings.use_css
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001749 1;/<style\>/+1
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750endif
1751
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752" Normal/global attributes
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001753if s:settings.use_css
1754 if s:settings.no_pre
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001755 call append('.', "body { color: " . s:fgc . "; background-color: " . s:bgc . "; font-family: ". s:htmlfont ."; }")
1756 +
Bram Moolenaar071d4272004-06-13 20:20:40 +00001757 else
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001758 call append('.', "pre { " . s:whitespace . "font-family: ". s:htmlfont ."; color: " . s:fgc . "; background-color: " . s:bgc . "; }")
1759 +
Bram Moolenaar071d4272004-06-13 20:20:40 +00001760 yank
1761 put
1762 execute "normal! ^cwbody\e"
Bram Moolenaar8e5af3e2011-04-28 19:02:44 +02001763 " body should not have the wrap formatting, only the pre section
1764 if s:whitespace != ''
1765 exec 's#'.s:whitespace
1766 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001768 " fix browser inconsistencies (sometimes within the same browser) of different
1769 " default font size for different elements
1770 call append('.', '* { font-size: 1em; }')
1771 +
1772 " if we use any input elements for unselectable content, make sure they look
1773 " like normal text
1774 if !empty(s:settings.prevent_copy)
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001775 if s:settings.use_input_for_pc !=# "none"
1776 call append('.', 'input { border: none; margin: 0; padding: 0; font-family: '.s:htmlfont.'; }')
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001777 +
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001778 " ch units for browsers which support them, em units for a somewhat
1779 " reasonable fallback.
1780 for w in range(1, 20, 1)
1781 call append('.', [
1782 \ "input[size='".w."'] { width: ".w."em; width: ".w."ch; }"
1783 \ ])
1784 +
1785 endfor
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001786 endif
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001787
1788 if s:settings.use_input_for_pc !=# 'all'
1789 let s:unselectable_styles = []
1790 if s:settings.prevent_copy =~# 'f'
1791 call add(s:unselectable_styles, 'FoldColumn')
1792 endif
1793 if s:settings.prevent_copy =~# 'n'
1794 call add(s:unselectable_styles, 'LineNr')
1795 endif
1796 if s:settings.prevent_copy =~# 't' && !s:settings.ignore_folding
1797 call add(s:unselectable_styles, 'Folded')
1798 endif
1799 if s:settings.prevent_copy =~# 'd'
1800 call add(s:unselectable_styles, 'DiffDelete')
1801 endif
1802 if s:settings.use_input_for_pc !=# 'none'
1803 call append('.', [
1804 \ '/* Note: IE does not support @supports conditionals, but also does not fully support',
1805 \ ' "content:" with custom content, so we *want* the check to fail */',
1806 \ '@supports ( content: attr(data-custom-content) ) {'
1807 \ ])
1808 +3
1809 endif
1810 " The line number column inside the foldtext is styled just like the fold
1811 " text in Vim, but it should use the prevent_copy settings of line number
1812 " rather than fold text. Apply the prevent_copy styles to foldtext
1813 " specifically for line numbers, which always come after the fold column,
1814 " or at the beginning of the line.
1815 if s:settings.prevent_copy =~# 'n' && !s:settings.ignore_folding
1816 call append('.', [
1817 \ ' .FoldColumn + .Folded, .Folded:first-child { user-select: none; }',
1818 \ ' .FoldColumn + [data-Folded-content]::before, [data-Folded-content]:first-child::before { content: attr(data-Folded-content); }',
1819 \ ' .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 */ }',
1820 \ ' .FoldColumn + span[data-Folded-content]::before, [data-Folded-content]:first-child::before { cursor: default; }',
1821 \ ])
1822 +4
1823 endif
1824 for s:style_name in s:unselectable_styles
1825 call append('.', [
1826 \ ' .'.s:style_name.' { user-select: none; }',
1827 \ ' [data-'.s:style_name.'-content]::before { content: attr(data-'.s:style_name.'-content); }',
1828 \ ' [data-'.s:style_name.'-content]::before { padding-bottom: 1px; display: inline-block; /* match the 1-px padding of standard items with background */ }',
1829 \ ' span[data-'.s:style_name.'-content]::before { cursor: default; }',
1830 \ ])
1831 +4
1832 endfor
1833 if s:settings.use_input_for_pc !=# 'none'
1834 call append('.', [
1835 \ ' input { display: none; }',
1836 \ '}'
1837 \ ])
1838 +2
1839 endif
1840 unlet s:unselectable_styles
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001841 endif
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001842
1843 " Fix mouse cursor shape for the fallback <input> method of uncopyable text
1844 if s:settings.use_input_for_pc !=# 'none'
1845 if s:settings.prevent_copy =~# 'f'
1846 " Make the cursor show active fold columns as active areas, and empty fold
1847 " columns as not interactive.
1848 call append('.', ['input.FoldColumn { cursor: pointer; }',
1849 \ 'input.FoldColumn[value="'.repeat(' ', s:foldcolumn).'"] { cursor: default; }'
1850 \ ])
1851 +2
1852 if s:settings.use_input_for_pc !=# 'all'
1853 call append('.', [
1854 \ 'a[data-FoldColumn-content="'.repeat(' ', s:foldcolumn).'"] { cursor: default; }'
1855 \ ])
1856 +1
1857 end
1858 endif
1859 " make line number column show as non-interactive if not selectable
1860 if s:settings.prevent_copy =~# 'n'
1861 call append('.', 'input.LineNr { cursor: default; }')
1862 +
1863 endif
1864 " make fold text and line number column within fold text show as
1865 " non-interactive if not selectable
1866 if (s:settings.prevent_copy =~# 'n' || s:settings.prevent_copy =~# 't') && !s:settings.ignore_folding
1867 call append('.', 'input.Folded { cursor: default; }')
1868 +
1869 endif
1870 " make diff filler show as non-interactive if not selectable
1871 if s:settings.prevent_copy =~# 'd'
1872 call append('.', 'input.DiffDelete { cursor: default; }')
1873 +
1874 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001875 endif
1876 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877else
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001878 " For Netscape 4, set <body> attributes too, though, strictly speaking, it's
1879 " incorrect.
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001880 execute '%s:<body\([^>]*\):<body bgcolor="' . s:bgc . '" text="' . s:fgc . '"\1>\r<font face="'. s:htmlfont .'"'
Bram Moolenaar071d4272004-06-13 20:20:40 +00001881endif
1882
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001883" Gather attributes for all other classes. Do diff first so that normal
1884" highlight groups are inserted before it.
1885if s:settings.use_css
1886 if s:diff_mode
1887 call append('.', filter(map(keys(s:diffstylelist), "s:diffstylelist[v:val]"), 'v:val != ""'))
1888 endif
1889 if !empty(s:stylelist)
1890 call append('.', filter(map(keys(s:stylelist), "s:stylelist[v:val]"), 'v:val != ""'))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891 endif
1892endif
1893
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894" Add hyperlinks
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001895" TODO: add option to not do this? Maybe just make the color the same as the
1896" text highlight group normally is?
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001897%s+\(https\=://\S\{-}\)\(\([.,;:}]\=\(\s\|$\)\)\|[\\"'<>]\|&gt;\|&lt;\|&quot;\)+<a href="\1">\1</a>\2+ge
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898
1899" The DTD
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001900if s:settings.use_xhtml
1901 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\">"
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001902elseif s:html5
1903 exe "normal! gg0i<!DOCTYPE html>\n"
Bram Moolenaar313b7232007-05-05 17:56:55 +00001904else
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001905 exe "normal! gg0i<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001906endif
1907
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001908if s:settings.use_xhtml
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001909 exe "normal! gg/<html/e\na xmlns=\"http://www.w3.org/1999/xhtml\"\e"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910endif
1911
1912" Cleanup
1913%s:\s\+$::e
1914
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001915" Restore old settings (new window first)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001916"
1917" Don't bother restoring foldmethod in case it was syntax because the markup is
1918" so weirdly formatted it can take a LONG time.
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001919let &l:foldenable = s:old_fen
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920let &report = s:old_report
1921let &title = s:old_title
1922let &icon = s:old_icon
1923let &paste = s:old_paste
1924let &magic = s:old_magic
1925let @/ = s:old_search
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001926let &more = s:old_more
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001927
1928" switch to original window to restore those settings
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929exe s:orgwin . "wincmd w"
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001930
1931if !s:settings.expand_tabs
1932 let &l:isprint = s:old_isprint
1933endif
Bram Moolenaar166af9b2010-11-16 20:34:40 +01001934let &l:stl = s:origwin_stl
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935let &l:et = s:old_et
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001936let &l:scrollbind = s:old_bind
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001937
1938" and back to the new window again to end there
Bram Moolenaar071d4272004-06-13 20:20:40 +00001939exe s:newwin . "wincmd w"
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001940
Bram Moolenaar166af9b2010-11-16 20:34:40 +01001941let &l:stl = s:newwin_stl
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001942exec 'resize' s:old_winheight
1943let &l:winfixheight = s:old_winfixheight
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001945let &ls=s:ls
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001946let &eventignore=s:ei_sav
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001947
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948" Save a little bit of memory (worth doing?)
Bram Moolenaar8e5af3e2011-04-28 19:02:44 +02001949unlet s:htmlfont s:whitespace
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001950unlet s:old_et s:old_paste s:old_icon s:old_report s:old_title s:old_search
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001951unlet s:old_magic s:old_more s:old_fen s:old_winheight
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001952unlet! s:old_isprint
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001953unlet s:whatterm s:stylelist s:diffstylelist s:lnum s:end s:margin s:fgc s:bgc s:old_winfixheight
1954unlet! s:col s:id s:attr s:len s:line s:new s:expandedtab s:concealinfo s:diff_mode
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001955unlet! s:orgwin s:newwin s:orgbufnr s:idx s:i s:offset s:ls s:ei_sav s:origwin_stl
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001956unlet! s:newwin_stl s:current_syntax
Bram Moolenaar05159a02005-02-26 23:04:13 +00001957if !v:profiling
1958 delfunc s:HtmlColor
1959 delfunc s:HtmlFormat
1960 delfunc s:CSS1
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001961 delfunc s:BuildStyleWrapper
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001962 if !s:settings.use_css
Bram Moolenaar05159a02005-02-26 23:04:13 +00001963 delfunc s:HtmlOpening
1964 delfunc s:HtmlClosing
1965 endif
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001966 if s:settings.dynamic_folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001967 delfunc s:FoldCompare
1968 endif
1969
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001970 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001971 delfunc s:ProgressBar
1972 delfunc s:progressbar.paint
1973 delfunc s:progressbar.incr
1974 unlet s:pgb s:progressbar
1975 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001976endif
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001977
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001978unlet! s:new_lnum s:diffattr s:difffillchar s:foldfillchar s:HtmlSpace
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001979unlet! s:LeadingSpace s:HtmlEndline s:firstfold s:numcol s:foldcolumn
1980unlet s:foldstack s:allfolds s:foldId s:settings
Bram Moolenaar5c736222010-01-06 20:54:52 +01001981
1982let &cpo = s:cpo_sav
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001983unlet! s:cpo_sav
Bram Moolenaar5c736222010-01-06 20:54:52 +01001984
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001985" Make sure any patches will probably use consistent indent
Bram Moolenaar7c86f4c2010-07-18 14:07:22 +02001986" vim: ts=8 sw=2 sts=2 noet