blob: 69780cffef5511811686bc3fe111d476ee5a878f [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 Moolenaarbe4e0162023-02-02 13:59:48 +00003" Last Change: 2023 Jan 01
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 Moolenaar6ebe4f92022-10-28 20:47:54 +0100818if !s:settings.no_doc
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100819 call extend(s:lines, [
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +0100820 \ "<html>",
821 \ "<head>"])
822 " include encoding as close to the top as possible, but only if not already
823 " contained in XML information (to avoid haggling over content type)
824 if s:settings.encoding != "" && !s:settings.use_xhtml
825 if s:html5
826 call add(s:lines, '<meta charset="' . s:settings.encoding . '"' . s:tag_close)
Bram Moolenaar5c736222010-01-06 20:54:52 +0100827 else
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +0100828 call add(s:lines, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" . s:settings.encoding . '"' . s:tag_close)
Bram Moolenaar5c736222010-01-06 20:54:52 +0100829 endif
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100830 endif
Bram Moolenaar0c0734d2019-11-26 21:44:46 +0100831 call extend(s:lines, [
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +0100832 \ ("<title>".expand("%:p:~")."</title>"),
833 \ ("<meta name=\"Generator\" content=\"Vim/".v:version/100.".".v:version%100.'"'.s:tag_close),
834 \ ("<meta name=\"plugin-version\" content=\"".s:pluginversion.'"'.s:tag_close)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200835 \ ])
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +0100836 call add(s:lines, '<meta name="syntax" content="'.s:current_syntax.'"'.s:tag_close)
837 call add(s:lines, '<meta name="settings" content="'.
838 \ join(filter(keys(s:settings),'s:settings[v:val]'),',').
839 \ ',prevent_copy='.s:settings.prevent_copy.
840 \ ',use_input_for_pc='.s:settings.use_input_for_pc.
841 \ '"'.s:tag_close)
842 call add(s:lines, '<meta name="colorscheme" content="'.
843 \ (exists('g:colors_name')
844 \ ? g:colors_name
845 \ : 'none'). '"'.s:tag_close)
Bram Moolenaar5c736222010-01-06 20:54:52 +0100846
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +0100847 if s:settings.use_css
848 call extend(s:lines, [
849 \ "<style" . (s:html5 ? "" : " type=\"text/css\"") . ">",
850 \ s:settings.use_xhtml ? "" : "<!--"])
851 let s:ieonly = []
852 if s:settings.dynamic_folds
853 if s:settings.hover_unfold
854 " if we are doing hover_unfold, use css 2 with css 1 fallback for IE6
855 call extend(s:lines, [
856 \ ".FoldColumn { text-decoration: none; white-space: pre; }",
857 \ "",
858 \ "body * { margin: 0; padding: 0; }", "",
859 \ ".open-fold > span.Folded { display: none; }",
860 \ ".open-fold > .fulltext { display: inline; }",
861 \ ".closed-fold > .fulltext { display: none; }",
862 \ ".closed-fold > span.Folded { display: inline; }",
863 \ "",
864 \ ".open-fold > .toggle-open { display: none; }",
865 \ ".open-fold > .toggle-closed { display: inline; }",
866 \ ".closed-fold > .toggle-open { display: inline; }",
867 \ ".closed-fold > .toggle-closed { display: none; }",
868 \ "", "",
869 \ '/* opening a fold while hovering won''t be supported by IE6 and other',
870 \ "similar browsers, but it should fail gracefully. */",
871 \ ".closed-fold:hover > .fulltext { display: inline; }",
872 \ ".closed-fold:hover > .toggle-filler { display: none; }",
873 \ ".closed-fold:hover > .Folded { display: none; }"])
874 " TODO: IE6 is REALLY old and I can't even test it anymore. Maybe we
875 " should remove this? Leave it in for now, it was working at one point,
876 " and doesn't affect any modern browsers. Even newer IE versions should
877 " support the above code and ignore the following.
878 let s:ieonly = [
879 \ "<!--[if lt IE 7]><style type=\"text/css\">",
880 \ ".open-fold .fulltext { display: inline; }",
881 \ ".open-fold span.Folded { display: none; }",
882 \ ".open-fold .toggle-open { display: none; }",
883 \ ".open-fold .toggle-closed { display: inline; }",
884 \ "",
885 \ ".closed-fold .fulltext { display: none; }",
886 \ ".closed-fold span.Folded { display: inline; }",
887 \ ".closed-fold .toggle-open { display: inline; }",
888 \ ".closed-fold .toggle-closed { display: none; }",
889 \ "</style>",
890 \ "<![endif]-->",
891 \]
892 else
893 " if we aren't doing hover_unfold, use CSS 1 only
894 call extend(s:lines, [
895 \ ".FoldColumn { text-decoration: none; white-space: pre; }",
896 \ ".open-fold .fulltext { display: inline; }",
897 \ ".open-fold span.Folded { display: none; }",
898 \ ".open-fold .toggle-open { display: none; }",
899 \ ".open-fold .toggle-closed { display: inline; }",
900 \ "",
901 \ ".closed-fold .fulltext { display: none; }",
902 \ ".closed-fold span.Folded { display: inline; }",
903 \ ".closed-fold .toggle-open { display: inline; }",
904 \ ".closed-fold .toggle-closed { display: none; }",
905 \])
906 endif
907 endif
908 " else we aren't doing any dynamic folding, no need for any special rules
Bram Moolenaarf0d58ef2018-11-16 16:13:44 +0100909
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +0100910 call extend(s:lines, [
911 \ s:settings.use_xhtml ? "" : '-->',
912 \ "</style>",
913 \])
914 call extend(s:lines, s:ieonly)
915 unlet s:ieonly
916 endif
917
918 let s:uses_script = s:settings.dynamic_folds || s:settings.line_ids
919
920 " insert script tag if needed
921 if s:uses_script
922 call extend(s:lines, [
923 \ "",
924 \ "<script" . (s:html5 ? "" : " type='text/javascript'") . ">",
925 \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])
926 endif
927
928 " insert javascript to toggle folds open and closed
Bram Moolenaar31c31672013-06-26 13:28:14 +0200929 if s:settings.dynamic_folds
930 call extend(s:lines, [
931 \ "",
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +0100932 \ "function toggleFold(objID)",
933 \ "{",
934 \ " var fold;",
935 \ " fold = document.getElementById(objID);",
936 \ " if (fold.className == 'closed-fold')",
Bram Moolenaar31c31672013-06-26 13:28:14 +0200937 \ " {",
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +0100938 \ " fold.className = 'open-fold';",
Bram Moolenaar31c31672013-06-26 13:28:14 +0200939 \ " }",
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +0100940 \ " else if (fold.className == 'open-fold')",
941 \ " {",
942 \ " fold.className = 'closed-fold';",
943 \ " }",
944 \ "}"
Bram Moolenaar31c31672013-06-26 13:28:14 +0200945 \ ])
946 endif
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200947
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +0100948 if s:settings.line_ids
949 " insert javascript to get IDs from line numbers, and to open a fold before
950 " jumping to any lines contained therein
951 call extend(s:lines, [
952 \ "",
953 \ "/* function to open any folds containing a jumped-to line before jumping to it */",
954 \ "function JumpToLine()",
955 \ "{",
956 \ " var lineNum;",
957 \ " lineNum = window.location.hash;",
958 \ " lineNum = lineNum.substr(1); /* strip off '#' */",
959 \ "",
960 \ " if (lineNum.indexOf('L') == -1) {",
961 \ " lineNum = 'L'+lineNum;",
962 \ " }",
963 \ " var lineElem = document.getElementById(lineNum);"
964 \ ])
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200965
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +0100966 if s:settings.dynamic_folds
967 call extend(s:lines, [
968 \ "",
969 \ " /* navigate upwards in the DOM tree to open all folds containing the line */",
970 \ " var node = lineElem;",
971 \ " while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')",
972 \ " {",
973 \ " if (node.className == 'closed-fold')",
974 \ " {",
975 \ " node.className = 'open-fold';",
976 \ " }",
977 \ " node = node.parentNode;",
978 \ " }",
979 \ ])
980 endif
981 call extend(s:lines, [
982 \ " /* Always jump to new location even if the line was hidden inside a fold, or",
983 \ " * we corrected the raw number to a line ID.",
984 \ " */",
985 \ " if (lineElem) {",
986 \ " lineElem.scrollIntoView(true);",
987 \ " }",
988 \ " return true;",
989 \ "}",
990 \ "if ('onhashchange' in window) {",
991 \ " window.onhashchange = JumpToLine;",
992 \ "}"
993 \ ])
994 endif
995
996 " insert script closing tag if needed
997 if s:uses_script
998 call extend(s:lines, [
999 \ '',
1000 \ s:settings.use_xhtml ? '//]]>' : '-->',
1001 \ "</script>"
1002 \ ])
1003 endif
1004
1005 call extend(s:lines, ["</head>",
1006 \ "<body".(s:settings.line_ids ? " onload='JumpToLine();'" : "").">"])
1007endif
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001008
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001009if s:settings.no_pre
1010 " if we're not using CSS we use a font tag which can't have a div inside
1011 if s:settings.use_css
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +01001012 call extend(s:lines, ["<div id='vimCodeElement" .. s:settings.id_suffix .. "'>"])
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001013 endif
1014else
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +01001015 call extend(s:lines, ["<pre id='vimCodeElement" .. s:settings.id_suffix .. "'>"])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001016endif
1017
1018exe s:orgwin . "wincmd w"
1019
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001020" caches of style data
1021" initialize to include line numbers if using them
1022if s:settings.number_lines
1023 let s:stylelist = { s:LINENR_ID : ".LineNr { " . s:CSS1( s:LINENR_ID ) . "}" }
1024else
1025 let s:stylelist = {}
1026endif
1027let s:diffstylelist = {
1028 \ s:DIFF_A_ID : ".DiffAdd { " . s:CSS1( s:DIFF_A_ID ) . "}",
1029 \ s:DIFF_C_ID : ".DiffChange { " . s:CSS1( s:DIFF_C_ID ) . "}",
1030 \ s:DIFF_D_ID : ".DiffDelete { " . s:CSS1( s:DIFF_D_ID ) . "}",
1031 \ s:DIFF_T_ID : ".DiffText { " . s:CSS1( s:DIFF_T_ID ) . "}"
1032 \ }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001033
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001034" set up progress bar in the status line
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001035if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001036 " ProgressBar Indicator
1037 let s:progressbar={}
1038
Bram Moolenaar6c391a72021-09-09 21:55:11 +02001039 " Progressbar specific functions
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001040
1041 func! s:SetProgbarColor()
1042 if hlID("TOhtmlProgress") != 0
1043 hi! link TOhtmlProgress_auto TOhtmlProgress
1044 elseif hlID("TOhtmlProgress_auto")==0 ||
1045 \ !exists("s:last_colors_name") || !exists("g:colors_name") ||
1046 \ g:colors_name != s:last_colors_name
1047 let s:last_colors_name = exists("g:colors_name") ? g:colors_name : "none"
1048
1049 let l:diffatr = synIDattr(hlID("DiffDelete"), "reverse", s:whatterm) ? "fg#" : "bg#"
1050 let l:stlatr = synIDattr(hlID("StatusLine"), "reverse", s:whatterm) ? "fg#" : "bg#"
1051
1052 let l:progbar_color = synIDattr(hlID("DiffDelete"), l:diffatr, s:whatterm)
1053 let l:stl_color = synIDattr(hlID("StatusLine"), l:stlatr, s:whatterm)
1054
1055 if "" == l:progbar_color
1056 let l:progbar_color = synIDattr(hlID("DiffDelete"), "reverse", s:whatterm) ? s:fgc : s:bgc
1057 endif
1058 if "" == l:stl_color
1059 let l:stl_color = synIDattr(hlID("StatusLine"), "reverse", s:whatterm) ? s:fgc : s:bgc
1060 endif
1061
1062 if l:progbar_color == l:stl_color
1063 if s:whatterm == 'cterm'
1064 if l:progbar_color >= (&t_Co/2)
1065 let l:progbar_color-=1
1066 else
1067 let l:progbar_color+=1
1068 endif
1069 else
1070 let l:rgb = map(matchlist(l:progbar_color, '#\zs\x\x\ze\(\x\x\)\(\x\x\)')[:2], 'str2nr(v:val, 16)')
1071 let l:avg = (l:rgb[0] + l:rgb[1] + l:rgb[2])/3
1072 if l:avg >= 128
1073 let l:avg_new = l:avg
1074 while l:avg - l:avg_new < 0x15
1075 let l:rgb = map(l:rgb, 'v:val * 3 / 4')
1076 let l:avg_new = (l:rgb[0] + l:rgb[1] + l:rgb[2])/3
1077 endwhile
1078 else
1079 let l:avg_new = l:avg
1080 while l:avg_new - l:avg < 0x15
1081 let l:rgb = map(l:rgb, 'min([max([v:val, 4]) * 5 / 4, 255])')
1082 let l:avg_new = (l:rgb[0] + l:rgb[1] + l:rgb[2])/3
1083 endwhile
1084 endif
1085 let l:progbar_color = printf("#%02x%02x%02x", l:rgb[0], l:rgb[1], l:rgb[2])
1086 endif
1087 echomsg "diff detected progbar color set to" l:progbar_color
1088 endif
1089 exe "hi TOhtmlProgress_auto" s:whatterm."bg=".l:progbar_color
1090 endif
1091 endfun
1092
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001093 func! s:ProgressBar(title, max_value, winnr)
1094 let pgb=copy(s:progressbar)
1095 let pgb.title = a:title.' '
1096 let pgb.max_value = a:max_value
1097 let pgb.winnr = a:winnr
1098 let pgb.cur_value = 0
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001099
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001100 let pgb.items = { 'title' : { 'color' : 'Statusline' },
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001101 \'bar' : { 'color' : 'Statusline' , 'fillcolor' : 'TOhtmlProgress_auto' , 'bg' : 'Statusline' } ,
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001102 \'counter' : { 'color' : 'Statusline' } }
1103 let pgb.last_value = 0
1104 let pgb.needs_redraw = 0
1105 " Note that you must use len(split) instead of len() if you want to use
1106 " unicode in title.
1107 "
1108 " Subtract 3 for spacing around the title.
1109 " Subtract 4 for the percentage display.
1110 " Subtract 2 for spacing before this.
1111 " Subtract 2 more for the '|' on either side of the progress bar
1112 let pgb.subtractedlen=len(split(pgb.title, '\zs'))+3+4+2+2
1113 let pgb.max_len = 0
1114 set laststatus=2
1115 return pgb
1116 endfun
1117
1118 " Function: progressbar.calculate_ticks() {{{1
1119 func! s:progressbar.calculate_ticks(pb_len)
1120 if a:pb_len<=0
1121 let pb_len = 100
1122 else
1123 let pb_len = a:pb_len
1124 endif
1125 let self.progress_ticks = map(range(pb_len+1), "v:val * self.max_value / pb_len")
1126 endfun
1127
1128 "Function: progressbar.paint()
1129 func! s:progressbar.paint()
1130 " Recalculate widths.
1131 let max_len = winwidth(self.winnr)
1132 let pb_len = 0
1133 " always true on first call because of initial value of self.max_len
1134 if max_len != self.max_len
1135 let self.max_len = max_len
1136
1137 " Progressbar length
1138 let pb_len = max_len - self.subtractedlen
1139
1140 call self.calculate_ticks(pb_len)
1141
1142 let self.needs_redraw = 1
1143 let cur_value = 0
1144 let self.pb_len = pb_len
1145 else
1146 " start searching at the last found index to make the search for the
1147 " appropriate tick value normally take 0 or 1 comparisons
1148 let cur_value = self.last_value
1149 let pb_len = self.pb_len
1150 endif
1151
1152 let cur_val_max = pb_len > 0 ? pb_len : 100
1153
1154 " find the current progress bar position based on precalculated thresholds
1155 while cur_value < cur_val_max && self.cur_value > self.progress_ticks[cur_value]
1156 let cur_value += 1
1157 endwhile
1158
1159 " update progress bar
1160 if self.last_value != cur_value || self.needs_redraw || self.cur_value == self.max_value
1161 let self.needs_redraw = 1
1162 let self.last_value = cur_value
1163
1164 let t_color = self.items.title.color
1165 let b_fcolor = self.items.bar.fillcolor
1166 let b_color = self.items.bar.color
1167 let c_color = self.items.counter.color
1168
1169 let stl = "%#".t_color."#%-( ".self.title." %)".
1170 \"%#".b_color."#".
1171 \(pb_len>0 ?
1172 \ ('|%#'.b_fcolor."#%-(".repeat(" ",cur_value)."%)".
1173 \ '%#'.b_color."#".repeat(" ",pb_len-cur_value)."|"):
1174 \ ('')).
1175 \"%=%#".c_color."#%( ".printf("%3.d ",100*self.cur_value/self.max_value)."%% %)"
1176 call setwinvar(self.winnr, '&stl', stl)
1177 endif
1178 endfun
1179
1180 func! s:progressbar.incr( ... )
1181 let self.cur_value += (a:0 ? a:1 : 1)
1182 " if we were making a general-purpose progress bar, we'd need to limit to a
1183 " lower limit as well, but since we always increment with a positive value
1184 " in this script, we only need limit the upper value
1185 let self.cur_value = (self.cur_value > self.max_value ? self.max_value : self.cur_value)
1186 call self.paint()
1187 endfun
1188 " }}}
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001189 if s:settings.dynamic_folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001190 " to process folds we make two passes through each line
1191 let s:pgb = s:ProgressBar("Processing folds:", line('$')*2, s:orgwin)
1192 endif
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001193
1194 call s:SetProgbarColor()
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001195endif
1196
Bram Moolenaar5c736222010-01-06 20:54:52 +01001197" First do some preprocessing for dynamic folding. Do this for the entire file
1198" so we don't accidentally start within a closed fold or something.
1199let s:allfolds = []
1200
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001201if s:settings.dynamic_folds
Bram Moolenaar5c736222010-01-06 20:54:52 +01001202 let s:lnum = 1
1203 let s:end = line('$')
1204 " save the fold text and set it to the default so we can find fold levels
1205 let s:foldtext_save = &foldtext
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001206 setlocal foldtext&
Bram Moolenaar5c736222010-01-06 20:54:52 +01001207
1208 " we will set the foldcolumn in the html to the greater of the maximum fold
1209 " level and the current foldcolumn setting
1210 let s:foldcolumn = &foldcolumn
1211
1212 " get all info needed to describe currently closed folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001213 while s:lnum <= s:end
Bram Moolenaar5c736222010-01-06 20:54:52 +01001214 if foldclosed(s:lnum) == s:lnum
1215 " default fold text has '+-' and then a number of dashes equal to fold
1216 " level, so subtract 2 from index of first non-dash after the dashes
1217 " in order to get the fold level of the current fold
1218 let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2
Bram Moolenaar5c736222010-01-06 20:54:52 +01001219 " store fold info for later use
1220 let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"}
1221 call add(s:allfolds, s:newfold)
1222 " open the fold so we can find any contained folds
1223 execute s:lnum."foldopen"
1224 else
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001225 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001226 call s:pgb.incr()
1227 if s:pgb.needs_redraw
1228 redrawstatus
1229 let s:pgb.needs_redraw = 0
1230 endif
1231 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +01001232 let s:lnum = s:lnum + 1
1233 endif
1234 endwhile
1235
1236 " close all folds to get info for originally open folds
1237 silent! %foldclose!
1238 let s:lnum = 1
1239
1240 " the originally open folds will be all folds we encounter that aren't
1241 " already in the list of closed folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001242 while s:lnum <= s:end
Bram Moolenaar5c736222010-01-06 20:54:52 +01001243 if foldclosed(s:lnum) == s:lnum
1244 " default fold text has '+-' and then a number of dashes equal to fold
1245 " level, so subtract 2 from index of first non-dash after the dashes
1246 " in order to get the fold level of the current fold
1247 let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2
Bram Moolenaar5c736222010-01-06 20:54:52 +01001248 let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"}
1249 " only add the fold if we don't already have it
1250 if empty(s:allfolds) || index(s:allfolds, s:newfold) == -1
1251 let s:newfold.type = "open-fold"
1252 call add(s:allfolds, s:newfold)
1253 endif
1254 " open the fold so we can find any contained folds
1255 execute s:lnum."foldopen"
1256 else
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001257 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001258 call s:pgb.incr()
1259 if s:pgb.needs_redraw
1260 redrawstatus
1261 let s:pgb.needs_redraw = 0
1262 endif
1263 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +01001264 let s:lnum = s:lnum + 1
1265 endif
1266 endwhile
1267
1268 " sort the folds so that we only ever need to look at the first item in the
1269 " list of folds
1270 call sort(s:allfolds, "s:FoldCompare")
1271
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001272 let &l:foldtext = s:foldtext_save
Bram Moolenaar5c736222010-01-06 20:54:52 +01001273 unlet s:foldtext_save
1274
1275 " close all folds again so we can get the fold text as we go
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001276 silent! %foldclose!
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001277
Bram Moolenaar251e1912011-06-19 05:09:16 +02001278 " Go through and remove folds we don't need to (or cannot) process in the
1279 " current conversion range
1280 "
1281 " If a fold is removed which contains other folds, which are included, we need
1282 " to adjust the level of the included folds as used by the conversion logic
1283 " (avoiding special cases is good)
1284 "
1285 " Note any time we remove a fold, either all of the included folds are in it,
1286 " or none of them, because we only remove a fold if neither its start nor its
1287 " end are within the conversion range.
1288 let leveladjust = 0
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001289 for afold in s:allfolds
1290 let removed = 0
1291 if exists("g:html_start_line") && exists("g:html_end_line")
1292 if afold.firstline < g:html_start_line
Bram Moolenaar251e1912011-06-19 05:09:16 +02001293 if afold.lastline <= g:html_end_line && afold.lastline >= g:html_start_line
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001294 " if a fold starts before the range to convert but stops within the
1295 " range, we need to include it. Make it start on the first converted
1296 " line.
1297 let afold.firstline = g:html_start_line
1298 else
1299 " if the fold lies outside the range or the start and stop enclose
1300 " the entire range, don't bother parsing it
1301 call remove(s:allfolds, index(s:allfolds, afold))
1302 let removed = 1
Bram Moolenaar251e1912011-06-19 05:09:16 +02001303 if afold.lastline > g:html_end_line
1304 let leveladjust += 1
1305 endif
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001306 endif
1307 elseif afold.firstline > g:html_end_line
1308 " If the entire fold lies outside the range we need to remove it.
1309 call remove(s:allfolds, index(s:allfolds, afold))
1310 let removed = 1
1311 endif
1312 elseif exists("g:html_start_line")
1313 if afold.firstline < g:html_start_line
1314 " if there is no last line, but there is a first line, the end of the
1315 " fold will always lie within the region of interest, so keep it
1316 let afold.firstline = g:html_start_line
1317 endif
1318 elseif exists("g:html_end_line")
1319 " if there is no first line we default to the first line in the buffer so
1320 " the fold start will always be included if the fold itself is included.
1321 " If however the entire fold lies outside the range we need to remove it.
1322 if afold.firstline > g:html_end_line
1323 call remove(s:allfolds, index(s:allfolds, afold))
1324 let removed = 1
1325 endif
1326 endif
1327 if !removed
Bram Moolenaar251e1912011-06-19 05:09:16 +02001328 let afold.level -= leveladjust
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001329 if afold.level+1 > s:foldcolumn
1330 let s:foldcolumn = afold.level+1
1331 endif
1332 endif
1333 endfor
Bram Moolenaar251e1912011-06-19 05:09:16 +02001334
1335 " if we've removed folds containing the conversion range from processing,
1336 " getting foldtext as we go won't know to open the removed folds, so the
1337 " foldtext would be wrong; open them now.
1338 "
1339 " Note that only when a start and an end line is specified will a fold
1340 " containing the current range ever be removed.
1341 while leveladjust > 0
1342 exe g:html_start_line."foldopen"
1343 let leveladjust -= 1
1344 endwhile
Bram Moolenaar5c736222010-01-06 20:54:52 +01001345endif
1346
1347" Now loop over all lines in the original text to convert to html.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001348" Use html_start_line and html_end_line if they are set.
Bram Moolenaarb02cbe32010-07-11 22:38:52 +02001349if exists("g:html_start_line")
Bram Moolenaar071d4272004-06-13 20:20:40 +00001350 let s:lnum = html_start_line
1351 if s:lnum < 1 || s:lnum > line("$")
1352 let s:lnum = 1
1353 endif
1354else
1355 let s:lnum = 1
1356endif
Bram Moolenaarb02cbe32010-07-11 22:38:52 +02001357if exists("g:html_end_line")
Bram Moolenaar071d4272004-06-13 20:20:40 +00001358 let s:end = html_end_line
1359 if s:end < s:lnum || s:end > line("$")
1360 let s:end = line("$")
1361 endif
1362else
1363 let s:end = line("$")
1364endif
1365
Bram Moolenaar5c736222010-01-06 20:54:52 +01001366" stack to keep track of all the folds containing the current line
1367let s:foldstack = []
1368
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001369if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001370 let s:pgb = s:ProgressBar("Processing lines:", s:end - s:lnum + 1, s:orgwin)
1371endif
1372
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001373if s:settings.number_lines
Bram Moolenaar5c736222010-01-06 20:54:52 +01001374 let s:margin = strlen(s:end) + 1
1375else
1376 let s:margin = 0
1377endif
1378
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001379if has('folding') && !s:settings.ignore_folding
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001380 let s:foldfillchar = &fillchars[matchend(&fillchars, 'fold:')]
1381 if s:foldfillchar == ''
1382 let s:foldfillchar = '-'
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001383 endif
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001384endif
1385let s:difffillchar = &fillchars[matchend(&fillchars, 'diff:')]
1386if s:difffillchar == ''
1387 let s:difffillchar = '-'
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001388endif
1389
Bram Moolenaar5c736222010-01-06 20:54:52 +01001390let s:foldId = 0
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001391
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001392if !s:settings.expand_tabs
1393 " If keeping tabs, add them to printable characters so we keep them when
1394 " formatting text (strtrans() doesn't replace printable chars)
1395 let s:old_isprint = &isprint
1396 setlocal isprint+=9
1397endif
1398
Bram Moolenaar071d4272004-06-13 20:20:40 +00001399while s:lnum <= s:end
1400
Bram Moolenaar47136d72004-10-12 20:02:24 +00001401 " If there are filler lines for diff mode, show these above the line.
1402 let s:filler = diff_filler(s:lnum)
1403 if s:filler > 0
1404 let s:n = s:filler
1405 while s:n > 0
Bram Moolenaar5c736222010-01-06 20:54:52 +01001406 let s:new = repeat(s:difffillchar, 3)
Bram Moolenaar47136d72004-10-12 20:02:24 +00001407
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001408 if s:n > 2 && s:n < s:filler && !s:settings.whole_filler
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001409 let s:new = s:new . " " . s:filler . " inserted lines "
1410 let s:n = 2
1411 endif
1412
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001413 if !s:settings.no_pre
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001414 " HTML line wrapping is off--go ahead and fill to the margin
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001415 " TODO: what about when CSS wrapping is turned on?
Bram Moolenaar5c736222010-01-06 20:54:52 +01001416 let s:new = s:new . repeat(s:difffillchar, &columns - strlen(s:new) - s:margin)
1417 else
1418 let s:new = s:new . repeat(s:difffillchar, 3)
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001419 endif
1420
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001421 let s:new = s:HtmlFormat_d(s:new, s:DIFF_D_ID, 0)
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001422 if s:settings.number_lines
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001423 " Indent if line numbering is on. Indent gets style of line number
1424 " column.
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001425 let s:new = s:HtmlFormat_n(repeat(' ', s:margin), s:LINENR_ID, 0, 0) . s:new
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001426 endif
1427 if s:settings.dynamic_folds && !s:settings.no_foldcolumn && s:foldcolumn > 0
1428 " Indent for foldcolumn if there is one. Assume it's empty, there should
1429 " not be a fold for deleted lines in diff mode.
1430 let s:new = s:FoldColumn_fill() . s:new
Bram Moolenaar5c736222010-01-06 20:54:52 +01001431 endif
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001432 call add(s:lines, s:new.s:HtmlEndline)
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001433
Bram Moolenaar47136d72004-10-12 20:02:24 +00001434 let s:n = s:n - 1
1435 endwhile
1436 unlet s:n
1437 endif
1438 unlet s:filler
1439
1440 " Start the line with the line number.
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001441 if s:settings.number_lines
Bram Moolenaar5c736222010-01-06 20:54:52 +01001442 let s:numcol = repeat(' ', s:margin - 1 - strlen(s:lnum)) . s:lnum . ' '
Bram Moolenaar47136d72004-10-12 20:02:24 +00001443 endif
1444
Bram Moolenaar5c736222010-01-06 20:54:52 +01001445 let s:new = ""
1446
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001447 if has('folding') && !s:settings.ignore_folding && foldclosed(s:lnum) > -1 && !s:settings.dynamic_folds
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001448 "
Bram Moolenaar5c736222010-01-06 20:54:52 +01001449 " This is the beginning of a folded block (with no dynamic folding)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001450 let s:new = foldtextresult(s:lnum)
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001451 if !s:settings.no_pre
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001452 " HTML line wrapping is off--go ahead and fill to the margin
1453 let s:new = s:new . repeat(s:foldfillchar, &columns - strlen(s:new))
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001454 endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001455
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001456 " put numcol in a separate group for sake of unselectable text
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001457 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 +00001458
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001459 " Skip to the end of the fold
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001460 let s:new_lnum = foldclosedend(s:lnum)
1461
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001462 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001463 call s:pgb.incr(s:new_lnum - s:lnum)
1464 endif
1465
1466 let s:lnum = s:new_lnum
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001467
1468 else
1469 "
Bram Moolenaar5c736222010-01-06 20:54:52 +01001470 " A line that is not folded, or doing dynamic folding.
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001471 "
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001472 let s:line = getline(s:lnum)
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001473 let s:len = strlen(s:line)
1474
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001475 if s:settings.dynamic_folds
Bram Moolenaar5c736222010-01-06 20:54:52 +01001476 " First insert a closing for any open folds that end on this line
1477 while !empty(s:foldstack) && get(s:foldstack,0).lastline == s:lnum-1
1478 let s:new = s:new."</span></span>"
1479 call remove(s:foldstack, 0)
1480 endwhile
1481
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001482 " Now insert an opening for any new folds that start on this line
Bram Moolenaar5c736222010-01-06 20:54:52 +01001483 let s:firstfold = 1
1484 while !empty(s:allfolds) && get(s:allfolds,0).firstline == s:lnum
1485 let s:foldId = s:foldId + 1
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001486 let s:new .= "<span id='"
1487 let s:new .= (exists('g:html_diff_win_num') ? "win".g:html_diff_win_num : "")
Bram Moolenaar31c31672013-06-26 13:28:14 +02001488 let s:new .= "fold".s:foldId.s:settings.id_suffix."' class='".s:allfolds[0].type."'>"
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001489
Bram Moolenaar5c736222010-01-06 20:54:52 +01001490
1491 " Unless disabled, add a fold column for the opening line of a fold.
1492 "
1493 " Note that dynamic folds require using css so we just use css to take
1494 " care of the leading spaces rather than using &nbsp; in the case of
1495 " html_no_pre to make it easier
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001496 if !s:settings.no_foldcolumn
Bram Moolenaar5c736222010-01-06 20:54:52 +01001497 " add fold column that can open the new fold
1498 if s:allfolds[0].level > 1 && s:firstfold
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001499 let s:new = s:new . s:FoldColumn_build('|', s:allfolds[0].level - 1, 0, "",
Bram Moolenaar31c31672013-06-26 13:28:14 +02001500 \ 'toggle-open FoldColumn','javascript:toggleFold("fold'.s:foldstack[0].id.s:settings.id_suffix.'");')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001501 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001502 " add the filler spaces separately from the '+' char so that it can be
1503 " shown/hidden separately during a hover unfold
1504 let s:new = s:new . s:FoldColumn_build("+", 1, 0, "",
Bram Moolenaar31c31672013-06-26 13:28:14 +02001505 \ 'toggle-open FoldColumn', 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001506 " If this is not the last fold we're opening on this line, we need
1507 " to keep the filler spaces hidden if the fold is opened by mouse
1508 " hover. If it is the last fold to open in the line, we shouldn't hide
1509 " them, so don't apply the toggle-filler class.
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001510 let s:new = s:new . s:FoldColumn_build(" ", 1, s:foldcolumn - s:allfolds[0].level - 1, "",
1511 \ 'toggle-open FoldColumn'. (get(s:allfolds, 1, {'firstline': 0}).firstline == s:lnum ?" toggle-filler" :""),
Bram Moolenaar31c31672013-06-26 13:28:14 +02001512 \ 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001513
1514 " add fold column that can close the new fold
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001515 " only add extra blank space if we aren't opening another fold on the
1516 " same line
Bram Moolenaar5c736222010-01-06 20:54:52 +01001517 if get(s:allfolds, 1, {'firstline': 0}).firstline != s:lnum
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001518 let s:extra_space = s:foldcolumn - s:allfolds[0].level
1519 else
1520 let s:extra_space = 0
Bram Moolenaar5c736222010-01-06 20:54:52 +01001521 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001522 if s:firstfold
1523 " the first fold in a line has '|' characters from folds opened in
1524 " previous lines, before the '-' for this fold
1525 let s:new .= s:FoldColumn_build('|', s:allfolds[0].level - 1, s:extra_space, '-',
Bram Moolenaar31c31672013-06-26 13:28:14 +02001526 \ 'toggle-closed FoldColumn', 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001527 else
1528 " any subsequent folds in the line only add a single '-'
1529 let s:new = s:new . s:FoldColumn_build("-", 1, s:extra_space, "",
Bram Moolenaar31c31672013-06-26 13:28:14 +02001530 \ 'toggle-closed FoldColumn', 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001531 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +01001532 let s:firstfold = 0
1533 endif
1534
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001535 " Add fold text, moving the span ending to the next line so collapsing
1536 " of folds works correctly.
1537 " Put numcol in a separate group for sake of unselectable text.
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001538 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 +01001539 let s:new = s:new . "<span class='fulltext'>"
1540
1541 " open the fold now that we have the fold text to allow retrieval of
1542 " fold text for subsequent folds
1543 execute s:lnum."foldopen"
1544 call insert(s:foldstack, remove(s:allfolds,0))
1545 let s:foldstack[0].id = s:foldId
1546 endwhile
1547
1548 " Unless disabled, add a fold column for other lines.
1549 "
1550 " Note that dynamic folds require using css so we just use css to take
1551 " care of the leading spaces rather than using &nbsp; in the case of
1552 " html_no_pre to make it easier
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001553 if !s:settings.no_foldcolumn
Bram Moolenaar5c736222010-01-06 20:54:52 +01001554 if empty(s:foldstack)
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001555 " add the empty foldcolumn for unfolded lines if there is a fold
1556 " column at all
1557 if s:foldcolumn > 0
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001558 let s:new = s:new . s:FoldColumn_fill()
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001559 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +01001560 else
1561 " add the fold column for folds not on the opening line
1562 if get(s:foldstack, 0).firstline < s:lnum
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001563 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 +02001564 \ 'FoldColumn', 'javascript:toggleFold("fold'.s:foldstack[0].id.s:settings.id_suffix.'");')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001565 endif
1566 endif
1567 endif
1568 endif
1569
1570 " Now continue with the unfolded line text
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001571 if s:settings.number_lines
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001572 let s:new = s:new . s:HtmlFormat_n(s:numcol, s:LINENR_ID, 0, s:lnum)
Bram Moolenaar31c31672013-06-26 13:28:14 +02001573 elseif s:settings.line_ids
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001574 let s:new = s:new . s:HtmlFormat_n("", s:LINENR_ID, 0, s:lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001575 endif
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001576
Bram Moolenaar47136d72004-10-12 20:02:24 +00001577 " Get the diff attribute, if any.
1578 let s:diffattr = diff_hlID(s:lnum, 1)
1579
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001580 " initialize conceal info to act like not concealed, just in case
1581 let s:concealinfo = [0, '']
1582
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001583 " Loop over each character in the line
1584 let s:col = 1
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001585
1586 " most of the time we won't use the diff_id, initialize to zero
1587 let s:diff_id = 0
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001588
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001589 while s:col <= s:len || (s:col == 1 && s:diffattr)
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001590 let s:startcol = s:col " The start column for processing text
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001591 if !s:settings.ignore_conceal && has('conceal')
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001592 let s:concealinfo = synconcealed(s:lnum, s:col)
1593 endif
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001594 if !s:settings.ignore_conceal && s:concealinfo[0]
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001595 let s:col = s:col + 1
1596 " Speed loop (it's small - that's the trick)
1597 " Go along till we find a change in the match sequence number (ending
1598 " the specific concealed region) or until there are no more concealed
1599 " characters.
1600 while s:col <= s:len && s:concealinfo == synconcealed(s:lnum, s:col) | let s:col = s:col + 1 | endwhile
1601 elseif s:diffattr
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001602 let s:diff_id = diff_hlID(s:lnum, s:col)
1603 let s:id = synID(s:lnum, s:col, 1)
Bram Moolenaar47136d72004-10-12 20:02:24 +00001604 let s:col = s:col + 1
1605 " Speed loop (it's small - that's the trick)
1606 " Go along till we find a change in hlID
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001607 while s:col <= s:len && s:id == synID(s:lnum, s:col, 1)
1608 \ && s:diff_id == diff_hlID(s:lnum, s:col) |
1609 \ let s:col = s:col + 1 |
1610 \ endwhile
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001611 if s:len < &columns && !s:settings.no_pre
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001612 " Add spaces at the end of the raw text line to extend the changed
1613 " line to the full width.
Bram Moolenaar5c736222010-01-06 20:54:52 +01001614 let s:line = s:line . repeat(' ', &columns - virtcol([s:lnum, s:len]) - s:margin)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001615 let s:len = &columns
1616 endif
Bram Moolenaar47136d72004-10-12 20:02:24 +00001617 else
1618 let s:id = synID(s:lnum, s:col, 1)
1619 let s:col = s:col + 1
1620 " Speed loop (it's small - that's the trick)
1621 " Go along till we find a change in synID
1622 while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) | let s:col = s:col + 1 | endwhile
1623 endif
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001624
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001625 if s:settings.ignore_conceal || !s:concealinfo[0]
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001626 " Expand tabs if needed
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001627 let s:expandedtab = strpart(s:line, s:startcol - 1, s:col - s:startcol)
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001628 if s:settings.expand_tabs
1629 let s:offset = 0
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001630 let s:idx = stridx(s:expandedtab, "\t")
Bram Moolenaarf0d58ef2018-11-16 16:13:44 +01001631 let s:tablist = split(&vts,',')
1632 if empty(s:tablist)
1633 let s:tablist = [ &ts ]
1634 endif
1635 let s:tabidx = 0
1636 let s:tabwidth = 0
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001637 while s:idx >= 0
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001638 if s:startcol + s:idx == 1
1639 let s:i = s:tablist[0]
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001640 else
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001641 " Get the character, which could be multiple bytes, which falls
1642 " immediately before the found tab. Extract it by matching a
1643 " character just prior to the column where the tab matches.
1644 " We'll use this to get the byte index of the character
1645 " immediately preceding the tab, so we can then look up the
1646 " virtual column that character appears in, to determine how
1647 " much of the current tabstop has been used up.
1648 if s:idx == 0
1649 " if the found tab is the first character in the text being
1650 " processed, we need to get the character prior to the text,
1651 " given by startcol.
1652 let s:prevc = matchstr(s:line, '.\%' . (s:startcol + s:offset) . 'c')
1653 else
1654 " Otherwise, the byte index of the tab into s:expandedtab is
1655 " given by s:idx.
1656 let s:prevc = matchstr(s:expandedtab, '.\%' . (s:idx + 1) . 'c')
1657 endif
1658 let s:vcol = virtcol([s:lnum, s:startcol + s:idx + s:offset - len(s:prevc)])
1659
1660 " find the tabstop interval to use for the tab we just found. Keep
1661 " adding tabstops (which could be variable) until we would exceed
1662 " the virtual screen position of the start of the found tab.
1663 while s:vcol >= s:tabwidth + s:tablist[s:tabidx]
1664 let s:tabwidth += s:tablist[s:tabidx]
1665 if s:tabidx < len(s:tablist)-1
1666 let s:tabidx = s:tabidx+1
1667 endif
1668 endwhile
1669 let s:i = s:tablist[s:tabidx] - (s:vcol - s:tabwidth)
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001670 endif
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001671 " update offset to keep the index within the line corresponding to
1672 " actual tab characters instead of replaced spaces; s:idx reflects
1673 " replaced spaces in s:expandedtab, s:offset cancels out all but
1674 " the tab character itself.
1675 let s:offset -= s:i - 1
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001676 let s:expandedtab = substitute(s:expandedtab, '\t', repeat(' ', s:i), '')
1677 let s:idx = stridx(s:expandedtab, "\t")
1678 endwhile
1679 end
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001680
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001681 " get the highlight group name to use
1682 let s:id = synIDtrans(s:id)
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001683 else
1684 " use Conceal highlighting for concealed text
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001685 let s:id = s:CONCEAL_ID
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001686 let s:expandedtab = s:concealinfo[1]
1687 endif
1688
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001689 " Output the text with the same synID, with class set to the highlight ID
1690 " name, unless it has been concealed completely.
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001691 if strlen(s:expandedtab) > 0
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001692 let s:new = s:new . s:HtmlFormat(s:expandedtab, s:id, s:diff_id, "", 0)
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001693 endif
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001694 endwhile
1695 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001697 call extend(s:lines, split(s:new.s:HtmlEndline, '\n', 1))
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001698 if !s:settings.no_progress && s:pgb.needs_redraw
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001699 redrawstatus
1700 let s:pgb.needs_redraw = 0
1701 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001702 let s:lnum = s:lnum + 1
Bram Moolenaar313b7232007-05-05 17:56:55 +00001703
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001704 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001705 call s:pgb.incr()
1706 endif
1707endwhile
1708
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001709if s:settings.dynamic_folds
Bram Moolenaar5c736222010-01-06 20:54:52 +01001710 " finish off any open folds
1711 while !empty(s:foldstack)
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001712 let s:lines[-1].="</span></span>"
Bram Moolenaar5c736222010-01-06 20:54:52 +01001713 call remove(s:foldstack, 0)
1714 endwhile
1715
1716 " add fold column to the style list if not already there
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001717 let s:id = s:FOLD_C_ID
1718 if !has_key(s:stylelist, s:id)
1719 let s:stylelist[s:id] = '.FoldColumn { ' . s:CSS1(s:id) . '}'
Bram Moolenaar5c736222010-01-06 20:54:52 +01001720 endif
1721endif
1722
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001723if s:settings.no_pre
1724 if !s:settings.use_css
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001725 " Close off the font tag that encapsulates the whole <body>
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +01001726 call extend(s:lines, ["</font>"])
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001727 else
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +01001728 call extend(s:lines, ["</div>"])
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001729 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001730else
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +01001731 call extend(s:lines, ["</pre>"])
1732endif
1733if !s:settings.no_doc
1734 call extend(s:lines, ["</body>", "</html>"])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001735endif
1736
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001737exe s:newwin . "wincmd w"
1738call setline(1, s:lines)
1739unlet s:lines
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001741" Mangle modelines so Vim doesn't try to use HTML text as a modeline if editing
1742" this file in the future; need to do this after generating all the text in case
1743" the modeline text has different highlight groups which all turn out to be
1744" stripped from the final output.
Bram Moolenaardd007ed2013-07-09 15:44:17 +02001745%s!\v(%(^|\s+)%([Vv]i%(m%([<=>]?\d+)?)?|ex)):!\1\&#0058;!ge
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001746
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001747" The generated HTML is admittedly ugly and takes a LONG time to fold.
1748" Make sure the user doesn't do syntax folding when loading a generated file,
1749" using a modeline.
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +01001750if !s:settings.no_modeline
1751 call append(line('$'), "<!-- vim: set foldmethod=manual : -->")
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752endif
1753
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +01001754" Now, when we finally know which, we define the colors and styles
1755if s:settings.use_css && !s:settings.no_doc
1756 1;/<style\>/+1
1757
1758 " Normal/global attributes
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001759 if s:settings.no_pre
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001760 call append('.', "body { color: " . s:fgc . "; background-color: " . s:bgc . "; font-family: ". s:htmlfont ."; }")
1761 +
Bram Moolenaar071d4272004-06-13 20:20:40 +00001762 else
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001763 call append('.', "pre { " . s:whitespace . "font-family: ". s:htmlfont ."; color: " . s:fgc . "; background-color: " . s:bgc . "; }")
1764 +
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765 yank
1766 put
1767 execute "normal! ^cwbody\e"
Bram Moolenaar8e5af3e2011-04-28 19:02:44 +02001768 " body should not have the wrap formatting, only the pre section
1769 if s:whitespace != ''
1770 exec 's#'.s:whitespace
1771 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001773 " fix browser inconsistencies (sometimes within the same browser) of different
1774 " default font size for different elements
1775 call append('.', '* { font-size: 1em; }')
1776 +
1777 " if we use any input elements for unselectable content, make sure they look
1778 " like normal text
1779 if !empty(s:settings.prevent_copy)
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001780 if s:settings.use_input_for_pc !=# "none"
1781 call append('.', 'input { border: none; margin: 0; padding: 0; font-family: '.s:htmlfont.'; }')
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001782 +
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001783 " ch units for browsers which support them, em units for a somewhat
1784 " reasonable fallback.
1785 for w in range(1, 20, 1)
1786 call append('.', [
1787 \ "input[size='".w."'] { width: ".w."em; width: ".w."ch; }"
1788 \ ])
1789 +
1790 endfor
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001791 endif
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001792
1793 if s:settings.use_input_for_pc !=# 'all'
1794 let s:unselectable_styles = []
1795 if s:settings.prevent_copy =~# 'f'
1796 call add(s:unselectable_styles, 'FoldColumn')
1797 endif
1798 if s:settings.prevent_copy =~# 'n'
1799 call add(s:unselectable_styles, 'LineNr')
1800 endif
1801 if s:settings.prevent_copy =~# 't' && !s:settings.ignore_folding
1802 call add(s:unselectable_styles, 'Folded')
1803 endif
1804 if s:settings.prevent_copy =~# 'd'
1805 call add(s:unselectable_styles, 'DiffDelete')
1806 endif
1807 if s:settings.use_input_for_pc !=# 'none'
1808 call append('.', [
1809 \ '/* Note: IE does not support @supports conditionals, but also does not fully support',
1810 \ ' "content:" with custom content, so we *want* the check to fail */',
1811 \ '@supports ( content: attr(data-custom-content) ) {'
1812 \ ])
1813 +3
1814 endif
1815 " The line number column inside the foldtext is styled just like the fold
1816 " text in Vim, but it should use the prevent_copy settings of line number
1817 " rather than fold text. Apply the prevent_copy styles to foldtext
1818 " specifically for line numbers, which always come after the fold column,
1819 " or at the beginning of the line.
1820 if s:settings.prevent_copy =~# 'n' && !s:settings.ignore_folding
1821 call append('.', [
1822 \ ' .FoldColumn + .Folded, .Folded:first-child { user-select: none; }',
1823 \ ' .FoldColumn + [data-Folded-content]::before, [data-Folded-content]:first-child::before { content: attr(data-Folded-content); }',
1824 \ ' .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 */ }',
1825 \ ' .FoldColumn + span[data-Folded-content]::before, [data-Folded-content]:first-child::before { cursor: default; }',
1826 \ ])
1827 +4
1828 endif
1829 for s:style_name in s:unselectable_styles
1830 call append('.', [
1831 \ ' .'.s:style_name.' { user-select: none; }',
1832 \ ' [data-'.s:style_name.'-content]::before { content: attr(data-'.s:style_name.'-content); }',
1833 \ ' [data-'.s:style_name.'-content]::before { padding-bottom: 1px; display: inline-block; /* match the 1-px padding of standard items with background */ }',
1834 \ ' span[data-'.s:style_name.'-content]::before { cursor: default; }',
1835 \ ])
1836 +4
1837 endfor
1838 if s:settings.use_input_for_pc !=# 'none'
1839 call append('.', [
1840 \ ' input { display: none; }',
1841 \ '}'
1842 \ ])
1843 +2
1844 endif
1845 unlet s:unselectable_styles
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001846 endif
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001847
1848 " Fix mouse cursor shape for the fallback <input> method of uncopyable text
1849 if s:settings.use_input_for_pc !=# 'none'
1850 if s:settings.prevent_copy =~# 'f'
1851 " Make the cursor show active fold columns as active areas, and empty fold
1852 " columns as not interactive.
1853 call append('.', ['input.FoldColumn { cursor: pointer; }',
1854 \ 'input.FoldColumn[value="'.repeat(' ', s:foldcolumn).'"] { cursor: default; }'
1855 \ ])
1856 +2
1857 if s:settings.use_input_for_pc !=# 'all'
1858 call append('.', [
1859 \ 'a[data-FoldColumn-content="'.repeat(' ', s:foldcolumn).'"] { cursor: default; }'
1860 \ ])
1861 +1
1862 end
1863 endif
1864 " make line number column show as non-interactive if not selectable
1865 if s:settings.prevent_copy =~# 'n'
1866 call append('.', 'input.LineNr { cursor: default; }')
1867 +
1868 endif
1869 " make fold text and line number column within fold text show as
1870 " non-interactive if not selectable
1871 if (s:settings.prevent_copy =~# 'n' || s:settings.prevent_copy =~# 't') && !s:settings.ignore_folding
1872 call append('.', 'input.Folded { cursor: default; }')
1873 +
1874 endif
1875 " make diff filler show as non-interactive if not selectable
1876 if s:settings.prevent_copy =~# 'd'
1877 call append('.', 'input.DiffDelete { cursor: default; }')
1878 +
1879 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001880 endif
1881 endif
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +01001882endif
1883
Bram Moolenaarf1dcd142022-12-31 15:30:45 +00001884if !s:settings.use_css && !s:settings.no_doc
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001885 " For Netscape 4, set <body> attributes too, though, strictly speaking, it's
1886 " incorrect.
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001887 execute '%s:<body\([^>]*\):<body bgcolor="' . s:bgc . '" text="' . s:fgc . '"\1>\r<font face="'. s:htmlfont .'"'
Bram Moolenaar071d4272004-06-13 20:20:40 +00001888endif
1889
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001890" Gather attributes for all other classes. Do diff first so that normal
1891" highlight groups are inserted before it.
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +01001892if s:settings.use_css && !s:settings.no_doc
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001893 if s:diff_mode
1894 call append('.', filter(map(keys(s:diffstylelist), "s:diffstylelist[v:val]"), 'v:val != ""'))
1895 endif
1896 if !empty(s:stylelist)
1897 call append('.', filter(map(keys(s:stylelist), "s:stylelist[v:val]"), 'v:val != ""'))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898 endif
1899endif
1900
Bram Moolenaar071d4272004-06-13 20:20:40 +00001901" Add hyperlinks
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +01001902if !s:settings.no_links
1903 %s+\(https\=://\S\{-}\)\(\([.,;:}]\=\(\s\|$\)\)\|[\\"'<>]\|&gt;\|&lt;\|&quot;\)+<a href="\1">\1</a>\2+ge
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001904endif
1905
Bram Moolenaar6ebe4f92022-10-28 20:47:54 +01001906" The DTD
1907if !s:settings.no_doc
1908 if s:settings.use_xhtml
1909 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\">"
1910 elseif s:html5
1911 exe "normal! gg0i<!DOCTYPE html>\n"
1912 else
1913 exe "normal! gg0i<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
1914 endif
1915endif
1916
1917if s:settings.use_xhtml && !s:settings.no_doc
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001918 exe "normal! gg/<html/e\na xmlns=\"http://www.w3.org/1999/xhtml\"\e"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001919endif
1920
1921" Cleanup
1922%s:\s\+$::e
1923
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001924" Restore old settings (new window first)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001925"
1926" Don't bother restoring foldmethod in case it was syntax because the markup is
1927" so weirdly formatted it can take a LONG time.
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001928let &l:foldenable = s:old_fen
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929let &report = s:old_report
1930let &title = s:old_title
1931let &icon = s:old_icon
1932let &paste = s:old_paste
1933let &magic = s:old_magic
1934let @/ = s:old_search
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001935let &more = s:old_more
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001936
1937" switch to original window to restore those settings
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938exe s:orgwin . "wincmd w"
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001939
1940if !s:settings.expand_tabs
1941 let &l:isprint = s:old_isprint
1942endif
Bram Moolenaar166af9b2010-11-16 20:34:40 +01001943let &l:stl = s:origwin_stl
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944let &l:et = s:old_et
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001945let &l:scrollbind = s:old_bind
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001946
1947" and back to the new window again to end there
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948exe s:newwin . "wincmd w"
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001949
Bram Moolenaar166af9b2010-11-16 20:34:40 +01001950let &l:stl = s:newwin_stl
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001951exec 'resize' s:old_winheight
1952let &l:winfixheight = s:old_winfixheight
Bram Moolenaar071d4272004-06-13 20:20:40 +00001953
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001954let &ls=s:ls
Bram Moolenaar0c0734d2019-11-26 21:44:46 +01001955let &eventignore=s:ei_sav
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001956
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957" Save a little bit of memory (worth doing?)
Bram Moolenaar8e5af3e2011-04-28 19:02:44 +02001958unlet s:htmlfont s:whitespace
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001959unlet 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 +02001960unlet s:old_magic s:old_more s:old_fen s:old_winheight
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001961unlet! s:old_isprint
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001962unlet s:whatterm s:stylelist s:diffstylelist s:lnum s:end s:margin s:fgc s:bgc s:old_winfixheight
1963unlet! 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 +01001964unlet! 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 +02001965unlet! s:newwin_stl s:current_syntax
Bram Moolenaar05159a02005-02-26 23:04:13 +00001966if !v:profiling
1967 delfunc s:HtmlColor
1968 delfunc s:HtmlFormat
1969 delfunc s:CSS1
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001970 delfunc s:BuildStyleWrapper
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001971 if !s:settings.use_css
Bram Moolenaar05159a02005-02-26 23:04:13 +00001972 delfunc s:HtmlOpening
1973 delfunc s:HtmlClosing
1974 endif
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001975 if s:settings.dynamic_folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001976 delfunc s:FoldCompare
1977 endif
1978
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001979 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001980 delfunc s:ProgressBar
1981 delfunc s:progressbar.paint
1982 delfunc s:progressbar.incr
1983 unlet s:pgb s:progressbar
1984 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001985endif
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001986
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001987unlet! s:new_lnum s:diffattr s:difffillchar s:foldfillchar s:HtmlSpace
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001988unlet! s:LeadingSpace s:HtmlEndline s:firstfold s:numcol s:foldcolumn
1989unlet s:foldstack s:allfolds s:foldId s:settings
Bram Moolenaar5c736222010-01-06 20:54:52 +01001990
1991let &cpo = s:cpo_sav
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001992unlet! s:cpo_sav
Bram Moolenaar5c736222010-01-06 20:54:52 +01001993
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001994" Make sure any patches will probably use consistent indent
Bram Moolenaar7c86f4c2010-07-18 14:07:22 +02001995" vim: ts=8 sw=2 sts=2 noet