blob: 461b47fab444b953390a7b5c96fbaf7d5e279323 [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 Moolenaar543b7ef2013-06-01 14:50:56 +02003" Last Change: 2013 May 31
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 Moolenaar6c35bea2012-07-25 17:49:10 +020023set cpo&vim
Bram Moolenaar5c736222010-01-06 20:54:52 +010024
Bram Moolenaar349b2fb2010-07-16 20:35:36 +020025let s:end=line('$')
Bram Moolenaar349b2fb2010-07-16 20:35:36 +020026
Bram Moolenaar313b7232007-05-05 17:56:55 +000027" Font
Bram Moolenaarb02cbe32010-07-11 22:38:52 +020028if exists("g:html_font")
Bram Moolenaar076e8b22010-08-05 21:54:00 +020029 let s:htmlfont = "'". g:html_font . "', monospace"
Bram Moolenaar313b7232007-05-05 17:56:55 +000030else
31 let s:htmlfont = "monospace"
32endif
33
Bram Moolenaar076e8b22010-08-05 21:54:00 +020034let s:settings = tohtml#GetUserSettings()
Bram Moolenaar5c736222010-01-06 20:54:52 +010035
Bram Moolenaar6c35bea2012-07-25 17:49:10 +020036if !exists('s:FOLDED_ID')
37 let s:FOLDED_ID = hlID("Folded") | lockvar s:FOLDED_ID
38 let s:FOLD_C_ID = hlID("FoldColumn") | lockvar s:FOLD_C_ID
39 let s:LINENR_ID = hlID('LineNr') | lockvar s:LINENR_ID
40 let s:DIFF_D_ID = hlID("DiffDelete") | lockvar s:DIFF_D_ID
41 let s:DIFF_A_ID = hlID("DiffAdd") | lockvar s:DIFF_A_ID
42 let s:DIFF_C_ID = hlID("DiffChange") | lockvar s:DIFF_C_ID
43 let s:DIFF_T_ID = hlID("DiffText") | lockvar s:DIFF_T_ID
44 let s:CONCEAL_ID = hlID('Conceal') | lockvar s:CONCEAL_ID
45endif
46
Bram Moolenaar8e5af3e2011-04-28 19:02:44 +020047" Whitespace
48if s:settings.pre_wrap
49 let s:whitespace = "white-space: pre-wrap; "
50else
51 let s:whitespace = ""
52endif
53
Bram Moolenaar6c35bea2012-07-25 17:49:10 +020054if !empty(s:settings.prevent_copy)
55 if s:settings.no_invalid
56 " User has decided they don't want invalid markup. Still works in
57 " OpenOffice, and for text editors, but when pasting into Microsoft Word the
58 " input elements get pasted too and they cannot be deleted (at least not
59 " easily).
60 let s:unselInputType = ""
61 else
62 " Prevent from copy-pasting the input elements into Microsoft Word where
63 " they cannot be deleted easily by deliberately inserting invalid markup.
64 let s:unselInputType = " type='invalid_input_type'"
65 endif
66endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068" When not in gui we can only guess the colors.
Bram Moolenaar6c35bea2012-07-25 17:49:10 +020069" TODO - is this true anymore?
Bram Moolenaar071d4272004-06-13 20:20:40 +000070if has("gui_running")
71 let s:whatterm = "gui"
72else
73 let s:whatterm = "cterm"
74 if &t_Co == 8
Bram Moolenaar6c35bea2012-07-25 17:49:10 +020075 let s:cterm_color = {
76 \ 0: "#808080", 1: "#ff6060", 2: "#00ff00", 3: "#ffff00",
77 \ 4: "#8080ff", 5: "#ff40ff", 6: "#00ffff", 7: "#ffffff"
78 \ }
Bram Moolenaar071d4272004-06-13 20:20:40 +000079 else
Bram Moolenaar6c35bea2012-07-25 17:49:10 +020080 let s:cterm_color = {
81 \ 0: "#000000", 1: "#c00000", 2: "#008000", 3: "#804000",
82 \ 4: "#0000c0", 5: "#c000c0", 6: "#008080", 7: "#c0c0c0",
83 \ 8: "#808080", 9: "#ff6060", 10: "#00ff00", 11: "#ffff00",
84 \ 12: "#8080ff", 13: "#ff40ff", 14: "#00ffff", 15: "#ffffff"
85 \ }
Bram Moolenaar313b7232007-05-05 17:56:55 +000086
87 " Colors for 88 and 256 come from xterm.
88 if &t_Co == 88
Bram Moolenaar6c35bea2012-07-25 17:49:10 +020089 call extend(s:cterm_color, {
90 \ 16: "#000000", 17: "#00008b", 18: "#0000cd", 19: "#0000ff",
91 \ 20: "#008b00", 21: "#008b8b", 22: "#008bcd", 23: "#008bff",
92 \ 24: "#00cd00", 25: "#00cd8b", 26: "#00cdcd", 27: "#00cdff",
93 \ 28: "#00ff00", 29: "#00ff8b", 30: "#00ffcd", 31: "#00ffff",
94 \ 32: "#8b0000", 33: "#8b008b", 34: "#8b00cd", 35: "#8b00ff",
95 \ 36: "#8b8b00", 37: "#8b8b8b", 38: "#8b8bcd", 39: "#8b8bff",
96 \ 40: "#8bcd00", 41: "#8bcd8b", 42: "#8bcdcd", 43: "#8bcdff",
97 \ 44: "#8bff00", 45: "#8bff8b", 46: "#8bffcd", 47: "#8bffff",
98 \ 48: "#cd0000", 49: "#cd008b", 50: "#cd00cd", 51: "#cd00ff",
99 \ 52: "#cd8b00", 53: "#cd8b8b", 54: "#cd8bcd", 55: "#cd8bff",
100 \ 56: "#cdcd00", 57: "#cdcd8b", 58: "#cdcdcd", 59: "#cdcdff",
101 \ 60: "#cdff00", 61: "#cdff8b", 62: "#cdffcd", 63: "#cdffff",
102 \ 64: "#ff0000"
103 \ })
104 call extend(s:cterm_color, {
105 \ 65: "#ff008b", 66: "#ff00cd", 67: "#ff00ff", 68: "#ff8b00",
106 \ 69: "#ff8b8b", 70: "#ff8bcd", 71: "#ff8bff", 72: "#ffcd00",
107 \ 73: "#ffcd8b", 74: "#ffcdcd", 75: "#ffcdff", 76: "#ffff00",
108 \ 77: "#ffff8b", 78: "#ffffcd", 79: "#ffffff", 80: "#2e2e2e",
109 \ 81: "#5c5c5c", 82: "#737373", 83: "#8b8b8b", 84: "#a2a2a2",
110 \ 85: "#b9b9b9", 86: "#d0d0d0", 87: "#e7e7e7"
111 \ })
Bram Moolenaar313b7232007-05-05 17:56:55 +0000112 elseif &t_Co == 256
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200113 call extend(s:cterm_color, {
114 \ 16: "#000000", 17: "#00005f", 18: "#000087", 19: "#0000af",
115 \ 20: "#0000d7", 21: "#0000ff", 22: "#005f00", 23: "#005f5f",
116 \ 24: "#005f87", 25: "#005faf", 26: "#005fd7", 27: "#005fff",
117 \ 28: "#008700", 29: "#00875f", 30: "#008787", 31: "#0087af",
118 \ 32: "#0087d7", 33: "#0087ff", 34: "#00af00", 35: "#00af5f",
119 \ 36: "#00af87", 37: "#00afaf", 38: "#00afd7", 39: "#00afff",
120 \ 40: "#00d700", 41: "#00d75f", 42: "#00d787", 43: "#00d7af",
121 \ 44: "#00d7d7", 45: "#00d7ff", 46: "#00ff00", 47: "#00ff5f",
122 \ 48: "#00ff87", 49: "#00ffaf", 50: "#00ffd7", 51: "#00ffff",
123 \ 52: "#5f0000", 53: "#5f005f", 54: "#5f0087", 55: "#5f00af",
124 \ 56: "#5f00d7", 57: "#5f00ff", 58: "#5f5f00", 59: "#5f5f5f",
125 \ 60: "#5f5f87", 61: "#5f5faf", 62: "#5f5fd7", 63: "#5f5fff",
126 \ 64: "#5f8700"
127 \ })
128 call extend(s:cterm_color, {
129 \ 65: "#5f875f", 66: "#5f8787", 67: "#5f87af", 68: "#5f87d7",
130 \ 69: "#5f87ff", 70: "#5faf00", 71: "#5faf5f", 72: "#5faf87",
131 \ 73: "#5fafaf", 74: "#5fafd7", 75: "#5fafff", 76: "#5fd700",
132 \ 77: "#5fd75f", 78: "#5fd787", 79: "#5fd7af", 80: "#5fd7d7",
133 \ 81: "#5fd7ff", 82: "#5fff00", 83: "#5fff5f", 84: "#5fff87",
134 \ 85: "#5fffaf", 86: "#5fffd7", 87: "#5fffff", 88: "#870000",
135 \ 89: "#87005f", 90: "#870087", 91: "#8700af", 92: "#8700d7",
136 \ 93: "#8700ff", 94: "#875f00", 95: "#875f5f", 96: "#875f87",
137 \ 97: "#875faf", 98: "#875fd7", 99: "#875fff", 100: "#878700",
138 \ 101: "#87875f", 102: "#878787", 103: "#8787af", 104: "#8787d7",
139 \ 105: "#8787ff", 106: "#87af00", 107: "#87af5f", 108: "#87af87",
140 \ 109: "#87afaf", 110: "#87afd7", 111: "#87afff", 112: "#87d700"
141 \ })
142 call extend(s:cterm_color, {
143 \ 113: "#87d75f", 114: "#87d787", 115: "#87d7af", 116: "#87d7d7",
144 \ 117: "#87d7ff", 118: "#87ff00", 119: "#87ff5f", 120: "#87ff87",
145 \ 121: "#87ffaf", 122: "#87ffd7", 123: "#87ffff", 124: "#af0000",
146 \ 125: "#af005f", 126: "#af0087", 127: "#af00af", 128: "#af00d7",
147 \ 129: "#af00ff", 130: "#af5f00", 131: "#af5f5f", 132: "#af5f87",
148 \ 133: "#af5faf", 134: "#af5fd7", 135: "#af5fff", 136: "#af8700",
149 \ 137: "#af875f", 138: "#af8787", 139: "#af87af", 140: "#af87d7",
150 \ 141: "#af87ff", 142: "#afaf00", 143: "#afaf5f", 144: "#afaf87",
151 \ 145: "#afafaf", 146: "#afafd7", 147: "#afafff", 148: "#afd700",
152 \ 149: "#afd75f", 150: "#afd787", 151: "#afd7af", 152: "#afd7d7",
153 \ 153: "#afd7ff", 154: "#afff00", 155: "#afff5f", 156: "#afff87",
154 \ 157: "#afffaf", 158: "#afffd7"
155 \ })
156 call extend(s:cterm_color, {
157 \ 159: "#afffff", 160: "#d70000", 161: "#d7005f", 162: "#d70087",
158 \ 163: "#d700af", 164: "#d700d7", 165: "#d700ff", 166: "#d75f00",
159 \ 167: "#d75f5f", 168: "#d75f87", 169: "#d75faf", 170: "#d75fd7",
160 \ 171: "#d75fff", 172: "#d78700", 173: "#d7875f", 174: "#d78787",
161 \ 175: "#d787af", 176: "#d787d7", 177: "#d787ff", 178: "#d7af00",
162 \ 179: "#d7af5f", 180: "#d7af87", 181: "#d7afaf", 182: "#d7afd7",
163 \ 183: "#d7afff", 184: "#d7d700", 185: "#d7d75f", 186: "#d7d787",
164 \ 187: "#d7d7af", 188: "#d7d7d7", 189: "#d7d7ff", 190: "#d7ff00",
165 \ 191: "#d7ff5f", 192: "#d7ff87", 193: "#d7ffaf", 194: "#d7ffd7",
166 \ 195: "#d7ffff", 196: "#ff0000", 197: "#ff005f", 198: "#ff0087",
167 \ 199: "#ff00af", 200: "#ff00d7", 201: "#ff00ff", 202: "#ff5f00",
168 \ 203: "#ff5f5f", 204: "#ff5f87"
169 \ })
170 call extend(s:cterm_color, {
171 \ 205: "#ff5faf", 206: "#ff5fd7", 207: "#ff5fff", 208: "#ff8700",
172 \ 209: "#ff875f", 210: "#ff8787", 211: "#ff87af", 212: "#ff87d7",
173 \ 213: "#ff87ff", 214: "#ffaf00", 215: "#ffaf5f", 216: "#ffaf87",
174 \ 217: "#ffafaf", 218: "#ffafd7", 219: "#ffafff", 220: "#ffd700",
175 \ 221: "#ffd75f", 222: "#ffd787", 223: "#ffd7af", 224: "#ffd7d7",
176 \ 225: "#ffd7ff", 226: "#ffff00", 227: "#ffff5f", 228: "#ffff87",
177 \ 229: "#ffffaf", 230: "#ffffd7", 231: "#ffffff", 232: "#080808",
178 \ 233: "#121212", 234: "#1c1c1c", 235: "#262626", 236: "#303030",
179 \ 237: "#3a3a3a", 238: "#444444", 239: "#4e4e4e", 240: "#585858",
180 \ 241: "#626262", 242: "#6c6c6c", 243: "#767676", 244: "#808080",
181 \ 245: "#8a8a8a", 246: "#949494", 247: "#9e9e9e", 248: "#a8a8a8",
182 \ 249: "#b2b2b2", 250: "#bcbcbc", 251: "#c6c6c6", 252: "#d0d0d0",
183 \ 253: "#dadada", 254: "#e4e4e4", 255: "#eeeeee"
184 \ })
Bram Moolenaar313b7232007-05-05 17:56:55 +0000185 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000186 endif
187endif
188
189" Return good color specification: in GUI no transformation is done, in
Bram Moolenaar313b7232007-05-05 17:56:55 +0000190" terminal return RGB values of known colors and empty string for unknown
Bram Moolenaar071d4272004-06-13 20:20:40 +0000191if s:whatterm == "gui"
192 function! s:HtmlColor(color)
193 return a:color
194 endfun
195else
196 function! s:HtmlColor(color)
Bram Moolenaar313b7232007-05-05 17:56:55 +0000197 if has_key(s:cterm_color, a:color)
198 return s:cterm_color[a:color]
Bram Moolenaar071d4272004-06-13 20:20:40 +0000199 else
200 return ""
201 endif
202 endfun
203endif
204
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200205" Find out the background and foreground color for use later
206let s:fgc = s:HtmlColor(synIDattr(hlID("Normal"), "fg#", s:whatterm))
207let s:bgc = s:HtmlColor(synIDattr(hlID("Normal"), "bg#", s:whatterm))
208if s:fgc == ""
209 let s:fgc = ( &background == "dark" ? "#ffffff" : "#000000" )
210endif
211if s:bgc == ""
212 let s:bgc = ( &background == "dark" ? "#000000" : "#ffffff" )
213endif
214
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200215if !s:settings.use_css
Bram Moolenaar071d4272004-06-13 20:20:40 +0000216 " Return opening HTML tag for given highlight id
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200217 function! s:HtmlOpening(id, extra_attrs)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000218 let a = ""
219 if synIDattr(a:id, "inverse")
220 " For inverse, we always must set both colors (and exchange them)
221 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200222 let a = a . '<span '.a:extra_attrs.'style="background-color: ' . ( x != "" ? x : s:fgc ) . '">'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000223 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
224 let a = a . '<font color="' . ( x != "" ? x : s:bgc ) . '">'
225 else
226 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200227 if x != ""
228 let a = a . '<span '.a:extra_attrs.'style="background-color: ' . x . '">'
229 elseif !empty(a:extra_attrs)
230 let a = a . '<span '.a:extra_attrs.'>'
231 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
233 if x != "" | let a = a . '<font color="' . x . '">' | endif
234 endif
235 if synIDattr(a:id, "bold") | let a = a . "<b>" | endif
236 if synIDattr(a:id, "italic") | let a = a . "<i>" | endif
237 if synIDattr(a:id, "underline") | let a = a . "<u>" | endif
238 return a
239 endfun
240
241 " Return closing HTML tag for given highlight id
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200242 function! s:HtmlClosing(id, has_extra_attrs)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000243 let a = ""
244 if synIDattr(a:id, "underline") | let a = a . "</u>" | endif
245 if synIDattr(a:id, "italic") | let a = a . "</i>" | endif
246 if synIDattr(a:id, "bold") | let a = a . "</b>" | endif
247 if synIDattr(a:id, "inverse")
248 let a = a . '</font></span>'
249 else
250 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
251 if x != "" | let a = a . '</font>' | endif
252 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200253 if x != "" || a:has_extra_attrs | let a = a . '</span>' | endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000254 endif
255 return a
256 endfun
257endif
258
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200259" Use a different function for formatting based on user options. This way we
260" can avoid a lot of logic during the actual execution.
261"
262" Build the function line by line containing only what is needed for the options
263" in use for maximum code sharing with minimal branch logic for greater speed.
264"
265" Note, 'exec' commands do not recognize line continuations, so must concatenate
266" lines rather than continue them.
267if s:settings.use_css
268 " save CSS to a list of rules to add to the output at the end of processing
269
270 " first, get the style names we need
271 let wrapperfunc_lines = [
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200272 \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, make_unselectable, unformatted)',
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200273 \ '',
274 \ ' let l:style_name = synIDattr(a:style_id, "name", s:whatterm)'
275 \ ]
276 if &diff
277 let wrapperfunc_lines += [
278 \ ' let l:diff_style_name = synIDattr(a:diff_style_id, "name", s:whatterm)']
279
280 " Add normal groups and diff groups to separate lists so we can order them to
281 " allow diff highlight to override normal highlight
282
283 " if primary style IS a diff style, grab it from the diff cache instead
284 " (always succeeds because we pre-populate it)
285 let wrapperfunc_lines += [
286 \ '',
287 \ ' if a:style_id == s:DIFF_D_ID || a:style_id == s:DIFF_A_ID ||'.
288 \ ' a:style_id == s:DIFF_C_ID || a:style_id == s:DIFF_T_ID',
289 \ ' let l:saved_style = get(s:diffstylelist,a:style_id)',
290 \ ' else'
291 \ ]
292 endif
293
294 " get primary style info from cache or build it on the fly if not found
295 let wrapperfunc_lines += [
296 \ ' let l:saved_style = get(s:stylelist,a:style_id)',
297 \ ' if type(l:saved_style) == type(0)',
298 \ ' unlet l:saved_style',
299 \ ' let l:saved_style = s:CSS1(a:style_id)',
300 \ ' if l:saved_style != ""',
301 \ ' let l:saved_style = "." . l:style_name . " { " . l:saved_style . "}"',
302 \ ' endif',
303 \ ' let s:stylelist[a:style_id]= l:saved_style',
304 \ ' endif'
305 \ ]
306 if &diff
307 let wrapperfunc_lines += [ ' endif' ]
308 endif
309
310 " Build the wrapper tags around the text. It turns out that caching these
311 " gives pretty much zero performance gain and adds a lot of logic.
312
313 let wrapperfunc_lines += [
314 \ '',
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200315 \ ' if l:saved_style == "" && empty(a:extra_attrs)'
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200316 \ ]
317 if &diff
318 let wrapperfunc_lines += [
319 \ ' if a:diff_style_id <= 0'
320 \ ]
321 endif
322 " no surroundings if neither primary nor diff style has any info
323 let wrapperfunc_lines += [
324 \ ' return a:text'
325 \ ]
326 if &diff
327 " no primary style, but diff style
328 let wrapperfunc_lines += [
329 \ ' else',
330 \ ' return "<span class=\"" .l:diff_style_name . "\">".a:text."</span>"',
331 \ ' endif'
332 \ ]
333 endif
334 " open tag for non-empty primary style
335 let wrapperfunc_lines += [
336 \ ' else']
337 " non-empty primary style. handle either empty or non-empty diff style.
338 "
339 " separate the two classes by a space to apply them both if there is a diff
340 " style name, unless the primary style is empty, then just use the diff style
341 " name
342 let diffstyle =
343 \ (&diff ? '(a:diff_style_id <= 0 ? "" : " ". l:diff_style_name) .'
344 \ : "")
345 if s:settings.prevent_copy == ""
346 let wrapperfunc_lines += [
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200347 \ ' return "<span ".a:extra_attrs."class=\"" . l:style_name .'.diffstyle.'"\">".a:text."</span>"'
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200348 \ ]
349 else
350
351 "
352 " Wrap the <input> in a <span> to allow fixing the stupid bug in some fonts
353 " which cause browsers to display a 1px gap between lines when these
354 " <input>s have a background color (maybe not really a bug, this isn't
355 " well-defined)
356 "
357 " use strwidth, because we care only about how many character boxes are
358 " needed to size the input, we don't care how many characters (including
359 " separately counted composing chars, from strchars()) or bytes (from
360 " len())the string contains. strdisplaywidth() is not needed because none of
361 " the unselectable groups can contain tab characters (fold column, fold
362 " text, line number).
363 "
364 " Note, if maxlength property needs to be added in the future, it will need
365 " to use strchars(), because HTML specifies that the maxlength parameter
366 " uses the number of unique codepoints for its limit.
367 let wrapperfunc_lines += [
368 \ ' if a:make_unselectable',
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200369 \ ' return "<span ".a:extra_attrs."class=\"" . l:style_name .'.diffstyle.'"\">'.
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200370 \ '<input'.s:unselInputType.' class=\"" . l:style_name .'.diffstyle.'"\"'.
371 \ ' value=\"".substitute(a:unformatted,''\s\+$'',"","")."\"'.
372 \ ' onselect=''this.blur(); return false;'''.
373 \ ' onmousedown=''this.blur(); return false;'''.
374 \ ' onclick=''this.blur(); return false;'''.
375 \ ' readonly=''readonly'''.
376 \ ' size=\"".strwidth(a:unformatted)."\"'.
377 \ (s:settings.use_xhtml ? '/' : '').'></span>"',
378 \ ' else',
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200379 \ ' return "<span ".a:extra_attrs."class=\"" . l:style_name .'. diffstyle .'"\">".a:text."</span>"'
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200380 \ ]
381 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200382 let wrapperfunc_lines += [
383 \ ' endif',
384 \ 'endfun'
385 \ ]
386else
387 " Non-CSS method just needs the wrapper.
388 "
389 " Functions used to get opening/closing automatically return null strings if
390 " no styles exist.
391 if &diff
392 let wrapperfunc_lines = [
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200393 \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2)',
394 \ ' return s:HtmlOpening(a:style_id, a:extra_attrs).(a:diff_style_id <= 0 ? "" :'.
395 \ 's:HtmlOpening(a:diff_style_id, "")).a:text.'.
396 \ '(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 +0200397 \ 'endfun'
398 \ ]
399 else
400 let wrapperfunc_lines = [
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200401 \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2)',
402 \ ' 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 +0200403 \ 'endfun'
404 \ ]
405 endif
406endif
407
408" create the function we built line by line above
409exec join(wrapperfunc_lines, "\n")
410
411let s:diff_mode = &diff
412
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000413" Return HTML valid characters enclosed in a span of class style_name with
414" unprintable characters expanded and double spaces replaced as necessary.
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200415"
416" TODO: eliminate unneeded logic like done for BuildStyleWrapper
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200417function! s:HtmlFormat(text, style_id, diff_style_id, extra_attrs, make_unselectable)
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000418 " Replace unprintable characters
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200419 let unformatted = strtrans(a:text)
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000420
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200421 let formatted = unformatted
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +0200422
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000423 " Replace the reserved html characters
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +0100424 let formatted = substitute(formatted, '&', '\&amp;', 'g')
425 let formatted = substitute(formatted, '<', '\&lt;', 'g')
426 let formatted = substitute(formatted, '>', '\&gt;', 'g')
427 let formatted = substitute(formatted, '"', '\&quot;', 'g')
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200428 " &apos; is not valid in HTML but it is in XHTML, so just use the numeric
429 " reference for it instead. Needed because it could appear in quotes
430 " especially if unselectable regions is turned on.
431 let formatted = substitute(formatted, '"', '\&#0039;', 'g')
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +0100432
433 " Replace a "form feed" character with HTML to do a page break
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200434 " TODO: need to prevent this in unselectable areas? Probably it should never
435 " BE in an unselectable area...
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +0100436 let formatted = substitute(formatted, "\x0c", '<hr class="PAGE-BREAK">', 'g')
437
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200438 " Replace double spaces, leading spaces, and trailing spaces if needed
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000439 if ' ' != s:HtmlSpace
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000440 let formatted = substitute(formatted, ' ', s:HtmlSpace . s:HtmlSpace, 'g')
Bram Moolenaar8424a622006-04-19 21:23:36 +0000441 let formatted = substitute(formatted, '^ ', s:HtmlSpace, 'g')
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200442 let formatted = substitute(formatted, ' \+$', s:HtmlSpace, 'g')
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000443 endif
444
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200445 " Enclose in the correct format
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200446 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 +0000447endfun
448
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200449" set up functions to call HtmlFormat in certain ways based on whether the
450" element is supposed to be unselectable or not
451if s:settings.prevent_copy =~# 'n'
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200452 if s:settings.number_lines
453 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
454 if a:lnr > 0
455 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.'" ', 1)
456 else
457 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)
458 endif
459 endfun
460 else
461 " if lines are not being numbered the only reason this function gets called
462 " is to put the line IDs on each line; "text" will be emtpy but lnr will
463 " always be non-zero, however we don't want to use the <input> because that
464 " won't work as nice for empty text
465 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
466 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.'" ', 0)
467 endfun
468 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200469else
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200470 function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
471 if a:lnr > 0
472 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.'" ', 0)
473 else
474 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)
475 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200476 endfun
477endif
478if s:settings.prevent_copy =~# 'd'
479 function! s:HtmlFormat_d(text, style_id, diff_style_id)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200480 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200481 endfun
482else
483 function! s:HtmlFormat_d(text, style_id, diff_style_id)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200484 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200485 endfun
486endif
487if s:settings.prevent_copy =~# 'f'
488 " Note the <input> elements for fill spaces will have a single space for
489 " content, to allow active cursor CSS selection to work.
490 "
491 " Wrap the whole thing in a span for the 1px padding workaround for gaps.
492 function! s:FoldColumn_build(char, len, numfill, char2, class, click)
493 let l:input_open = "<input readonly='readonly'".s:unselInputType.
494 \ " onselect='this.blur(); return false;'".
495 \ " onmousedown='this.blur(); ".a:click." return false;'".
496 \ " onclick='return false;' size='".
497 \ string(a:len + (empty(a:char2) ? 0 : 1) + a:numfill) .
498 \ "' "
499 let l:common_attrs = "class='FoldColumn' value='"
500 let l:input_close = (s:settings.use_xhtml ? "' />" : "'>")
501 return "<span class='".a:class."'>".
502 \ l:input_open.l:common_attrs.repeat(a:char, a:len).
503 \ (!empty(a:char2) ? a:char2 : "").
504 \ l:input_close . "</span>"
505 endfun
506 function! s:FoldColumn_fill()
507 return s:FoldColumn_build('', s:foldcolumn, 0, '', 'FoldColumn', '')
508 endfun
509else
510 " For normal fold columns, simply space-pad to the desired width (note that
511 " the FoldColumn definition includes a whitespace:pre rule)
512 function! s:FoldColumn_build(char, len, numfill, char2, class, click)
513 return "<a href='#' class='".a:class."' onclick='".a:click."'>".
514 \ repeat(a:char, a:len).a:char2.repeat(' ', a:numfill).
515 \ "</a>"
516 endfun
517 function! s:FoldColumn_fill()
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200518 return s:HtmlFormat(repeat(' ', s:foldcolumn), s:FOLD_C_ID, 0, "", 0)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200519 endfun
520endif
521if s:settings.prevent_copy =~# 't'
522 " put an extra empty span at the end for dynamic folds, so the linebreak can
523 " be surrounded. Otherwise do it as normal.
524 "
525 " TODO: isn't there a better way to do this, than placing it here and using a
526 " substitute later?
527 if s:settings.dynamic_folds
528 function! s:HtmlFormat_t(text, style_id, diff_style_id)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200529 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1) .
530 \ s:HtmlFormat("", a:style_id, 0, "", 0)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200531 endfun
532 else
533 function! s:HtmlFormat_t(text, style_id, diff_style_id)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200534 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200535 endfun
536 endif
537else
538 function! s:HtmlFormat_t(text, style_id, diff_style_id)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200539 return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200540 endfun
541endif
542
Bram Moolenaar071d4272004-06-13 20:20:40 +0000543" Return CSS style describing given highlight id (can be empty)
544function! s:CSS1(id)
545 let a = ""
546 if synIDattr(a:id, "inverse")
547 " For inverse, we always must set both colors (and exchange them)
548 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
549 let a = a . "color: " . ( x != "" ? x : s:bgc ) . "; "
550 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
551 let a = a . "background-color: " . ( x != "" ? x : s:fgc ) . "; "
552 else
553 let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm))
554 if x != "" | let a = a . "color: " . x . "; " | endif
555 let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm))
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200556 if x != ""
557 let a = a . "background-color: " . x . "; "
558 " stupid hack because almost every browser seems to have at least one font
559 " which shows 1px gaps between lines which have background
560 let a = a . "padding-bottom: 1px; "
561 elseif (a:id == s:FOLDED_ID || a:id == s:LINENR_ID || a:id == s:FOLD_C_ID) && !empty(s:settings.prevent_copy)
562 " input elements default to a different color than the rest of the page
563 let a = a . "background-color: " . s:bgc . "; "
564 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565 endif
566 if synIDattr(a:id, "bold") | let a = a . "font-weight: bold; " | endif
567 if synIDattr(a:id, "italic") | let a = a . "font-style: italic; " | endif
568 if synIDattr(a:id, "underline") | let a = a . "text-decoration: underline; " | endif
569 return a
570endfun
571
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200572if s:settings.dynamic_folds
Bram Moolenaar5c736222010-01-06 20:54:52 +0100573 " compares two folds as stored in our list of folds
574 " A fold is "less" than another if it starts at an earlier line number,
575 " or ends at a later line number, ties broken by fold level
576 function! s:FoldCompare(f1, f2)
577 if a:f1.firstline != a:f2.firstline
578 " put it before if it starts earlier
579 return a:f1.firstline - a:f2.firstline
580 elseif a:f1.lastline != a:f2.lastline
581 " put it before if it ends later
582 return a:f2.lastline - a:f1.lastline
583 else
584 " if folds begin and end on the same lines, put lowest fold level first
585 return a:f1.level - a:f2.level
586 endif
587 endfunction
588
589endif
590
Bram Moolenaar071d4272004-06-13 20:20:40 +0000591
592" Set some options to make it work faster.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000593" Don't report changes for :substitute, there will be many of them.
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200594" Don't change other windows; turn off scroll bind temporarily
Bram Moolenaar071d4272004-06-13 20:20:40 +0000595let s:old_title = &title
596let s:old_icon = &icon
597let s:old_et = &l:et
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200598let s:old_bind = &l:scrollbind
Bram Moolenaar071d4272004-06-13 20:20:40 +0000599let s:old_report = &report
600let s:old_search = @/
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200601let s:old_more = &more
Bram Moolenaar071d4272004-06-13 20:20:40 +0000602set notitle noicon
603setlocal et
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200604set nomore
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605set report=1000000
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200606setlocal noscrollbind
Bram Moolenaar071d4272004-06-13 20:20:40 +0000607
Bram Moolenaar7510fe72010-07-25 12:46:44 +0200608if exists(':ownsyntax') && exists('w:current_syntax')
609 let s:current_syntax = w:current_syntax
610elseif exists('b:current_syntax')
611 let s:current_syntax = b:current_syntax
612else
613 let s:current_syntax = 'none'
614endif
615
616if s:current_syntax == ''
617 let s:current_syntax = 'none'
618endif
619
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620" Split window to create a buffer with the HTML file.
621let s:orgbufnr = winbufnr(0)
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200622let s:origwin_stl = &l:stl
Bram Moolenaar071d4272004-06-13 20:20:40 +0000623if expand("%") == ""
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200624 if exists('g:html_diff_win_num')
625 exec 'new Untitled_win'.g:html_diff_win_num.'.'.(s:settings.use_xhtml ? 'x' : '').'html'
626 else
627 exec 'new Untitled.'.(s:settings.use_xhtml ? 'x' : '').'html'
628 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629else
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200630 exec 'new %.'.(s:settings.use_xhtml ? 'x' : '').'html'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631endif
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200632
633" Resize the new window to very small in order to make it draw faster
634let s:old_winheight = winheight(0)
635let s:old_winfixheight = &l:winfixheight
636if s:old_winheight > 2
637 resize 1 " leave enough room to view one line at a time
638 norm! G
639 norm! zt
640endif
641setlocal winfixheight
642
643let s:newwin_stl = &l:stl
644
645" on the new window, set the least time-consuming fold method
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200646let s:old_fen = &foldenable
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200647setlocal foldmethod=manual
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200648setlocal nofoldenable
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200649
Bram Moolenaar071d4272004-06-13 20:20:40 +0000650let s:newwin = winnr()
651let s:orgwin = bufwinnr(s:orgbufnr)
652
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200653setlocal modifiable
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654%d
655let s:old_paste = &paste
656set paste
657let s:old_magic = &magic
658set magic
659
Bram Moolenaar166af9b2010-11-16 20:34:40 +0100660" set the fileencoding to match the charset we'll be using
661let &l:fileencoding=s:settings.vim_encoding
662
663" According to http://www.w3.org/TR/html4/charset.html#doc-char-set, the byte
664" order mark is highly recommend on the web when using multibyte encodings. But,
665" it is not a good idea to include it on UTF-8 files. Otherwise, let Vim
666" determine when it is actually inserted.
667if s:settings.vim_encoding == 'utf-8'
668 setlocal nobomb
669else
670 setlocal bomb
671endif
672
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200673let s:lines = []
674
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200675if s:settings.use_xhtml
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200676 if s:settings.encoding != ""
677 call add(s:lines, "<?xml version=\"1.0\" encoding=\"" . s:settings.encoding . "\"?>")
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000678 else
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200679 call add(s:lines, "<?xml version=\"1.0\"?>")
Bram Moolenaar1cd871b2004-12-19 22:46:22 +0000680 endif
Bram Moolenaar313b7232007-05-05 17:56:55 +0000681 let s:tag_close = ' />'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000682else
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000683 let s:tag_close = '>'
684endif
685
686let s:HtmlSpace = ' '
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000687let s:LeadingSpace = ' '
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000688let s:HtmlEndline = ''
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200689if s:settings.no_pre
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +0000690 let s:HtmlEndline = '<br' . s:tag_close
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200691 let s:LeadingSpace = s:settings.use_xhtml ? '&#160;' : '&nbsp;'
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000692 let s:HtmlSpace = '\' . s:LeadingSpace
Bram Moolenaar071d4272004-06-13 20:20:40 +0000693endif
694
695" HTML header, with the title and generator ;-). Left free space for the CSS,
696" to be filled at the end.
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200697call extend(s:lines, [
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200698 \ "<html>",
699 \ "<head>"])
700" include encoding as close to the top as possible, but only if not already
701" contained in XML information (to avoid haggling over content type)
702if s:settings.encoding != "" && !s:settings.use_xhtml
703 call add(s:lines, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" . s:settings.encoding . '"' . s:tag_close)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704endif
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200705call extend(s:lines, [
706 \ ("<title>".expand("%:p:~")."</title>"),
707 \ ("<meta name=\"Generator\" content=\"Vim/".v:version/100.".".v:version%100.'"'.s:tag_close),
708 \ ("<meta name=\"plugin-version\" content=\"".g:loaded_2html_plugin.'"'.s:tag_close)
709 \ ])
Bram Moolenaar7510fe72010-07-25 12:46:44 +0200710call add(s:lines, '<meta name="syntax" content="'.s:current_syntax.'"'.s:tag_close)
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200711call add(s:lines, '<meta name="settings" content="'.
712 \ join(filter(keys(s:settings),'s:settings[v:val]'),',').
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200713 \ ',prevent_copy='.s:settings.prevent_copy.
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200714 \ '"'.s:tag_close)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200715call add(s:lines, '<meta name="colorscheme" content="'.
716 \ (exists('g:colors_name')
717 \ ? g:colors_name
718 \ : 'none'). '"'.s:tag_close)
Bram Moolenaar313b7232007-05-05 17:56:55 +0000719
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200720if s:settings.use_css
721 if s:settings.dynamic_folds
722 if s:settings.hover_unfold
Bram Moolenaar5c736222010-01-06 20:54:52 +0100723 " if we are doing hover_unfold, use css 2 with css 1 fallback for IE6
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200724 call extend(s:lines, [
725 \ "<style type=\"text/css\">",
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200726 \ s:settings.use_xhtml ? "" : "<!--",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200727 \ ".FoldColumn { text-decoration: none; white-space: pre; }",
728 \ "",
729 \ "body * { margin: 0; padding: 0; }", "",
730 \ ".open-fold > .Folded { display: none; }",
731 \ ".open-fold > .fulltext { display: inline; }",
732 \ ".closed-fold > .fulltext { display: none; }",
733 \ ".closed-fold > .Folded { display: inline; }",
734 \ "",
735 \ ".open-fold > .toggle-open { display: none; }",
736 \ ".open-fold > .toggle-closed { display: inline; }",
737 \ ".closed-fold > .toggle-open { display: inline; }",
738 \ ".closed-fold > .toggle-closed { display: none; }",
739 \ "", "",
740 \ '/* opening a fold while hovering won''t be supported by IE6 and other',
741 \ "similar browsers, but it should fail gracefully. */",
742 \ ".closed-fold:hover > .fulltext { display: inline; }",
743 \ ".closed-fold:hover > .toggle-filler { display: none; }",
744 \ ".closed-fold:hover > .Folded { display: none; }",
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200745 \ s:settings.use_xhtml ? "" : '-->',
Bram Moolenaar8df7f882010-08-13 11:30:02 +0200746 \ '</style>'])
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200747 " TODO: IE7 doesn't *actually* support XHTML, maybe we should remove this.
748 " But if it's served up as tag soup, maybe the following will work, so
749 " leave it in for now.
750 call extend(s:lines, [
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200751 \ "<!--[if lt IE 7]><style type=\"text/css\">",
752 \ ".open-fold .Folded { display: none; }",
753 \ ".open-fold .fulltext { display: inline; }",
754 \ ".open-fold .toggle-open { display: none; }",
755 \ ".closed-fold .toggle-closed { display: inline; }",
756 \ "",
757 \ ".closed-fold .fulltext { display: none; }",
758 \ ".closed-fold .Folded { display: inline; }",
759 \ ".closed-fold .toggle-open { display: inline; }",
760 \ ".closed-fold .toggle-closed { display: none; }",
761 \ "</style>",
762 \ "<![endif]-->",
763 \])
Bram Moolenaar5c736222010-01-06 20:54:52 +0100764 else
765 " if we aren't doing hover_unfold, use CSS 1 only
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200766 call extend(s:lines, [
767 \ "<style type=\"text/css\">",
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200768 \ s:settings.use_xhtml ? "" :"<!--",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200769 \ ".FoldColumn { text-decoration: none; white-space: pre; }",
770 \ ".open-fold .Folded { display: none; }",
771 \ ".open-fold .fulltext { display: inline; }",
772 \ ".open-fold .toggle-open { display: none; }",
773 \ ".closed-fold .toggle-closed { display: inline; }",
774 \ "",
775 \ ".closed-fold .fulltext { display: none; }",
776 \ ".closed-fold .Folded { display: inline; }",
777 \ ".closed-fold .toggle-open { display: inline; }",
778 \ ".closed-fold .toggle-closed { display: none; }",
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200779 \ s:settings.use_xhtml ? "" : '-->',
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200780 \ '</style>'
781 \])
Bram Moolenaar5c736222010-01-06 20:54:52 +0100782 endif
783 else
784 " if we aren't doing any dynamic folding, no need for any special rules
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200785 call extend(s:lines, [
786 \ "<style type=\"text/css\">",
Bram Moolenaarbebca9d2010-08-07 15:47:30 +0200787 \ s:settings.use_xhtml ? "" : "<!--",
788 \ s:settings.use_xhtml ? "" : '-->',
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200789 \ "</style>",
790 \])
Bram Moolenaar5c736222010-01-06 20:54:52 +0100791 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792endif
Bram Moolenaar5c736222010-01-06 20:54:52 +0100793
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200794" insert script tag; javascript is always needed for the line number
795" normalization for URL hashes
796call extend(s:lines, [
797 \ "",
798 \ "<script type='text/javascript'>",
799 \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200800
Bram Moolenaar5c736222010-01-06 20:54:52 +0100801" insert javascript to toggle folds open and closed
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200802if s:settings.dynamic_folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200803 call extend(s:lines, [
804 \ "",
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200805 \ "function toggleFold(objID)",
806 \ "{",
807 \ " var fold;",
808 \ " fold = document.getElementById(objID);",
809 \ " if(fold.className == 'closed-fold')",
810 \ " {",
811 \ " fold.className = 'open-fold';",
812 \ " }",
813 \ " else if (fold.className == 'open-fold')",
814 \ " {",
815 \ " fold.className = 'closed-fold';",
816 \ " }",
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200817 \ "}"
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200818 \ ])
Bram Moolenaar5c736222010-01-06 20:54:52 +0100819endif
820
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200821" insert javascript to get IDs from line numbers, and to open a fold before
822" jumping to any lines contained therein
823call extend(s:lines, [
824 \ "",
825 \ "/* function to open any folds containing a jumped-to line before jumping to it */",
826 \ "function JumpToLine()",
827 \ "{",
828 \ " var lineNum;",
829 \ " lineNum = window.location.hash;",
830 \ " lineNum = lineNum.substr(1); /* strip off '#' */",
831 \ "",
832 \ " if (lineNum.indexOf('L') == -1) {",
833 \ " lineNum = 'L'+lineNum;",
834 \ " }",
835 \ " lineElem = document.getElementById(lineNum);"
836 \ ])
837if s:settings.dynamic_folds
838 call extend(s:lines, [
839 \ "",
840 \ " /* navigate upwards in the DOM tree to open all folds containing the line */",
841 \ " var node = lineElem;",
842 \ " while (node && node.id != 'vimCodeElement')",
843 \ " {",
844 \ " if (node.className == 'closed-fold')",
845 \ " {",
846 \ " node.className = 'open-fold';",
847 \ " }",
848 \ " node = node.parentNode;",
849 \ " }",
850 \ ])
851endif
852call extend(s:lines, [
853 \ " /* Always jump to new location even if the line was hidden inside a fold, or",
854 \ " * we corrected the raw number to a line ID.",
855 \ " */",
856 \ " if (lineElem) {",
857 \ " lineElem.scrollIntoView(true);",
858 \ " }",
859 \ " return true;",
860 \ "}",
861 \ "if ('onhashchange' in window) {",
862 \ " window.onhashchange = JumpToLine;",
863 \ "}"
864 \ ])
865
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200866" Small text columns like the foldcolumn and line number column need a weird
867" hack to work around Webkit's and (in versions prior to 9) IE's lack of support
868" for the 'ch' unit without messing up Opera, which also doesn't support it but
869" works anyway.
870"
871" The problem is that without the 'ch' unit, it is not possible to specify a
872" size of an <input> in terms of character widths. Only Opera seems to do the
873" "sensible" thing and make the <input> sized to fit exactly as many characters
874" as specified by its "size" attribute, but the spec actually says "at least
875" wide enough to fit 'size' characters", so the other browsers are technically
876" correct as well.
877"
878" Anyway, this leads to two diffculties:
879" 1. The foldcolumn is made up of multiple elements side-by-side with
880" different sizes, each of which has their own extra padding added. Thus, a
881" column made up of one item of size 1 and another of size 2 would not
882" necessarily be equal in size to another line's foldcolumn with a single
883" item of size 3.
884" 2. The extra padding added to the <input> elements adds up to make the
885" foldcolumn and line number column too wide, especially in Webkit
886" browsers.
887"
888" So, the full workaround is:
889" 1. Define a default size in em, equal to the number of characters in the
890" input element, in case javascript is disabled and the browser does not
891" support the 'ch' unit. Unfortunately this makes Opera no longer work
892" properly without javascript. 1em per character is much too wide but it
893" looks better in webkit browsers than unaligned columns.
894" 2. Insert the following javascript to run at page load, which checks for the
895" width of a single character (in an extraneous page element inserted
896" before the page title, and set to hidden) and compares it to the width of
897" another extra <input> element with only one character. If the width
898" matches, the script does nothing more, but if not, it will figure out the
899" fraction of an em unit which would correspond with a ch unit if there
900" were one, and set the containing element (<pre> or <div>) to a class with
901" pre-defined rules which is closest to that fraction of an em. Rules are
902" defined from 0.05 em to 1em per ch.
903if !empty(s:settings.prevent_copy)
904 call extend(s:lines, [
905 \ '',
906 \ '/* simulate a "ch" unit by asking the browser how big a zero character is */',
907 \ 'function FixCharWidth() {',
908 \ ' /* get the hidden element which gives the width of a single character */',
909 \ ' var goodWidth = document.getElementById("oneCharWidth").clientWidth;',
910 \ ' /* get all input elements, we''ll filter on class later */',
911 \ ' var inputTags = document.getElementsByTagName("input");',
912 \ ' var ratio = 5;',
913 \ ' var inputWidth = document.getElementById("oneInputWidth").clientWidth;',
914 \ ' var emWidth = document.getElementById("oneEmWidth").clientWidth;',
915 \ ' if (inputWidth > goodWidth) {',
916 \ ' while (ratio < 100*goodWidth/emWidth && ratio < 100) {',
917 \ ' ratio += 5;',
918 \ ' }',
919 \ ' document.getElementById("vimCodeElement").className = "em"+ratio;',
920 \ ' }',
921 \ '}'
922 \ ])
923endif
924
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200925" insert script closing tag
926call extend(s:lines, [
927 \ '',
928 \ s:settings.use_xhtml ? '//]]>' : '-->',
929 \ "</script>"
930 \ ])
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200931
932call extend(s:lines, ["</head>"])
933if !empty(s:settings.prevent_copy)
934 call extend(s:lines,
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200935 \ ["<body onload='FixCharWidth(); JumpToLine();'>",
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200936 \ "<!-- hidden divs used by javascript to get the width of a char -->",
937 \ "<div id='oneCharWidth'>0</div>",
938 \ "<div id='oneInputWidth'><input size='1' value='0'".s:tag_close."</div>",
939 \ "<div id='oneEmWidth' style='width: 1em;'></div>"
940 \ ])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000941else
Bram Moolenaar543b7ef2013-06-01 14:50:56 +0200942 call extend(s:lines, ["<body onload='JumpToLine();'>"])
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200943endif
944if s:settings.no_pre
945 " if we're not using CSS we use a font tag which can't have a div inside
946 if s:settings.use_css
947 call extend(s:lines, ["<div id='vimCodeElement'>"])
948 endif
949else
950 call extend(s:lines, ["<pre id='vimCodeElement'>"])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000951endif
952
953exe s:orgwin . "wincmd w"
954
Bram Moolenaar6c35bea2012-07-25 17:49:10 +0200955" caches of style data
956" initialize to include line numbers if using them
957if s:settings.number_lines
958 let s:stylelist = { s:LINENR_ID : ".LineNr { " . s:CSS1( s:LINENR_ID ) . "}" }
959else
960 let s:stylelist = {}
961endif
962let s:diffstylelist = {
963 \ s:DIFF_A_ID : ".DiffAdd { " . s:CSS1( s:DIFF_A_ID ) . "}",
964 \ s:DIFF_C_ID : ".DiffChange { " . s:CSS1( s:DIFF_C_ID ) . "}",
965 \ s:DIFF_D_ID : ".DiffDelete { " . s:CSS1( s:DIFF_D_ID ) . "}",
966 \ s:DIFF_T_ID : ".DiffText { " . s:CSS1( s:DIFF_T_ID ) . "}"
967 \ }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000968
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200969" set up progress bar in the status line
Bram Moolenaar076e8b22010-08-05 21:54:00 +0200970if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +0200971 " ProgressBar Indicator
972 let s:progressbar={}
973
974 " Progessbar specific functions
975 func! s:ProgressBar(title, max_value, winnr)
976 let pgb=copy(s:progressbar)
977 let pgb.title = a:title.' '
978 let pgb.max_value = a:max_value
979 let pgb.winnr = a:winnr
980 let pgb.cur_value = 0
981 let pgb.items = { 'title' : { 'color' : 'Statusline' },
982 \'bar' : { 'color' : 'Statusline' , 'fillcolor' : 'DiffDelete' , 'bg' : 'Statusline' } ,
983 \'counter' : { 'color' : 'Statusline' } }
984 let pgb.last_value = 0
985 let pgb.needs_redraw = 0
986 " Note that you must use len(split) instead of len() if you want to use
987 " unicode in title.
988 "
989 " Subtract 3 for spacing around the title.
990 " Subtract 4 for the percentage display.
991 " Subtract 2 for spacing before this.
992 " Subtract 2 more for the '|' on either side of the progress bar
993 let pgb.subtractedlen=len(split(pgb.title, '\zs'))+3+4+2+2
994 let pgb.max_len = 0
995 set laststatus=2
996 return pgb
997 endfun
998
999 " Function: progressbar.calculate_ticks() {{{1
1000 func! s:progressbar.calculate_ticks(pb_len)
1001 if a:pb_len<=0
1002 let pb_len = 100
1003 else
1004 let pb_len = a:pb_len
1005 endif
1006 let self.progress_ticks = map(range(pb_len+1), "v:val * self.max_value / pb_len")
1007 endfun
1008
1009 "Function: progressbar.paint()
1010 func! s:progressbar.paint()
1011 " Recalculate widths.
1012 let max_len = winwidth(self.winnr)
1013 let pb_len = 0
1014 " always true on first call because of initial value of self.max_len
1015 if max_len != self.max_len
1016 let self.max_len = max_len
1017
1018 " Progressbar length
1019 let pb_len = max_len - self.subtractedlen
1020
1021 call self.calculate_ticks(pb_len)
1022
1023 let self.needs_redraw = 1
1024 let cur_value = 0
1025 let self.pb_len = pb_len
1026 else
1027 " start searching at the last found index to make the search for the
1028 " appropriate tick value normally take 0 or 1 comparisons
1029 let cur_value = self.last_value
1030 let pb_len = self.pb_len
1031 endif
1032
1033 let cur_val_max = pb_len > 0 ? pb_len : 100
1034
1035 " find the current progress bar position based on precalculated thresholds
1036 while cur_value < cur_val_max && self.cur_value > self.progress_ticks[cur_value]
1037 let cur_value += 1
1038 endwhile
1039
1040 " update progress bar
1041 if self.last_value != cur_value || self.needs_redraw || self.cur_value == self.max_value
1042 let self.needs_redraw = 1
1043 let self.last_value = cur_value
1044
1045 let t_color = self.items.title.color
1046 let b_fcolor = self.items.bar.fillcolor
1047 let b_color = self.items.bar.color
1048 let c_color = self.items.counter.color
1049
1050 let stl = "%#".t_color."#%-( ".self.title." %)".
1051 \"%#".b_color."#".
1052 \(pb_len>0 ?
1053 \ ('|%#'.b_fcolor."#%-(".repeat(" ",cur_value)."%)".
1054 \ '%#'.b_color."#".repeat(" ",pb_len-cur_value)."|"):
1055 \ ('')).
1056 \"%=%#".c_color."#%( ".printf("%3.d ",100*self.cur_value/self.max_value)."%% %)"
1057 call setwinvar(self.winnr, '&stl', stl)
1058 endif
1059 endfun
1060
1061 func! s:progressbar.incr( ... )
1062 let self.cur_value += (a:0 ? a:1 : 1)
1063 " if we were making a general-purpose progress bar, we'd need to limit to a
1064 " lower limit as well, but since we always increment with a positive value
1065 " in this script, we only need limit the upper value
1066 let self.cur_value = (self.cur_value > self.max_value ? self.max_value : self.cur_value)
1067 call self.paint()
1068 endfun
1069 " }}}
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001070 if s:settings.dynamic_folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001071 " to process folds we make two passes through each line
1072 let s:pgb = s:ProgressBar("Processing folds:", line('$')*2, s:orgwin)
1073 endif
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001074endif
1075
Bram Moolenaar5c736222010-01-06 20:54:52 +01001076" First do some preprocessing for dynamic folding. Do this for the entire file
1077" so we don't accidentally start within a closed fold or something.
1078let s:allfolds = []
1079
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001080if s:settings.dynamic_folds
Bram Moolenaar5c736222010-01-06 20:54:52 +01001081 let s:lnum = 1
1082 let s:end = line('$')
1083 " save the fold text and set it to the default so we can find fold levels
1084 let s:foldtext_save = &foldtext
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001085 setlocal foldtext&
Bram Moolenaar5c736222010-01-06 20:54:52 +01001086
1087 " we will set the foldcolumn in the html to the greater of the maximum fold
1088 " level and the current foldcolumn setting
1089 let s:foldcolumn = &foldcolumn
1090
1091 " get all info needed to describe currently closed folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001092 while s:lnum <= s:end
Bram Moolenaar5c736222010-01-06 20:54:52 +01001093 if foldclosed(s:lnum) == s:lnum
1094 " default fold text has '+-' and then a number of dashes equal to fold
1095 " level, so subtract 2 from index of first non-dash after the dashes
1096 " in order to get the fold level of the current fold
1097 let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2
Bram Moolenaar5c736222010-01-06 20:54:52 +01001098 " store fold info for later use
1099 let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"}
1100 call add(s:allfolds, s:newfold)
1101 " open the fold so we can find any contained folds
1102 execute s:lnum."foldopen"
1103 else
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001104 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001105 call s:pgb.incr()
1106 if s:pgb.needs_redraw
1107 redrawstatus
1108 let s:pgb.needs_redraw = 0
1109 endif
1110 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +01001111 let s:lnum = s:lnum + 1
1112 endif
1113 endwhile
1114
1115 " close all folds to get info for originally open folds
1116 silent! %foldclose!
1117 let s:lnum = 1
1118
1119 " the originally open folds will be all folds we encounter that aren't
1120 " already in the list of closed folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001121 while s:lnum <= s:end
Bram Moolenaar5c736222010-01-06 20:54:52 +01001122 if foldclosed(s:lnum) == s:lnum
1123 " default fold text has '+-' and then a number of dashes equal to fold
1124 " level, so subtract 2 from index of first non-dash after the dashes
1125 " in order to get the fold level of the current fold
1126 let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2
Bram Moolenaar5c736222010-01-06 20:54:52 +01001127 let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"}
1128 " only add the fold if we don't already have it
1129 if empty(s:allfolds) || index(s:allfolds, s:newfold) == -1
1130 let s:newfold.type = "open-fold"
1131 call add(s:allfolds, s:newfold)
1132 endif
1133 " open the fold so we can find any contained folds
1134 execute s:lnum."foldopen"
1135 else
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001136 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001137 call s:pgb.incr()
1138 if s:pgb.needs_redraw
1139 redrawstatus
1140 let s:pgb.needs_redraw = 0
1141 endif
1142 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +01001143 let s:lnum = s:lnum + 1
1144 endif
1145 endwhile
1146
1147 " sort the folds so that we only ever need to look at the first item in the
1148 " list of folds
1149 call sort(s:allfolds, "s:FoldCompare")
1150
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001151 let &l:foldtext = s:foldtext_save
Bram Moolenaar5c736222010-01-06 20:54:52 +01001152 unlet s:foldtext_save
1153
1154 " close all folds again so we can get the fold text as we go
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001155 silent! %foldclose!
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001156
Bram Moolenaar251e1912011-06-19 05:09:16 +02001157 " Go through and remove folds we don't need to (or cannot) process in the
1158 " current conversion range
1159 "
1160 " If a fold is removed which contains other folds, which are included, we need
1161 " to adjust the level of the included folds as used by the conversion logic
1162 " (avoiding special cases is good)
1163 "
1164 " Note any time we remove a fold, either all of the included folds are in it,
1165 " or none of them, because we only remove a fold if neither its start nor its
1166 " end are within the conversion range.
1167 let leveladjust = 0
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001168 for afold in s:allfolds
1169 let removed = 0
1170 if exists("g:html_start_line") && exists("g:html_end_line")
1171 if afold.firstline < g:html_start_line
Bram Moolenaar251e1912011-06-19 05:09:16 +02001172 if afold.lastline <= g:html_end_line && afold.lastline >= g:html_start_line
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001173 " if a fold starts before the range to convert but stops within the
1174 " range, we need to include it. Make it start on the first converted
1175 " line.
1176 let afold.firstline = g:html_start_line
1177 else
1178 " if the fold lies outside the range or the start and stop enclose
1179 " the entire range, don't bother parsing it
1180 call remove(s:allfolds, index(s:allfolds, afold))
1181 let removed = 1
Bram Moolenaar251e1912011-06-19 05:09:16 +02001182 if afold.lastline > g:html_end_line
1183 let leveladjust += 1
1184 endif
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001185 endif
1186 elseif afold.firstline > g:html_end_line
1187 " If the entire fold lies outside the range we need to remove it.
1188 call remove(s:allfolds, index(s:allfolds, afold))
1189 let removed = 1
1190 endif
1191 elseif exists("g:html_start_line")
1192 if afold.firstline < g:html_start_line
1193 " if there is no last line, but there is a first line, the end of the
1194 " fold will always lie within the region of interest, so keep it
1195 let afold.firstline = g:html_start_line
1196 endif
1197 elseif exists("g:html_end_line")
1198 " if there is no first line we default to the first line in the buffer so
1199 " the fold start will always be included if the fold itself is included.
1200 " If however the entire fold lies outside the range we need to remove it.
1201 if afold.firstline > g:html_end_line
1202 call remove(s:allfolds, index(s:allfolds, afold))
1203 let removed = 1
1204 endif
1205 endif
1206 if !removed
Bram Moolenaar251e1912011-06-19 05:09:16 +02001207 let afold.level -= leveladjust
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001208 if afold.level+1 > s:foldcolumn
1209 let s:foldcolumn = afold.level+1
1210 endif
1211 endif
1212 endfor
Bram Moolenaar251e1912011-06-19 05:09:16 +02001213
1214 " if we've removed folds containing the conversion range from processing,
1215 " getting foldtext as we go won't know to open the removed folds, so the
1216 " foldtext would be wrong; open them now.
1217 "
1218 " Note that only when a start and an end line is specified will a fold
1219 " containing the current range ever be removed.
1220 while leveladjust > 0
1221 exe g:html_start_line."foldopen"
1222 let leveladjust -= 1
1223 endwhile
Bram Moolenaar5c736222010-01-06 20:54:52 +01001224endif
1225
1226" Now loop over all lines in the original text to convert to html.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227" Use html_start_line and html_end_line if they are set.
Bram Moolenaarb02cbe32010-07-11 22:38:52 +02001228if exists("g:html_start_line")
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229 let s:lnum = html_start_line
1230 if s:lnum < 1 || s:lnum > line("$")
1231 let s:lnum = 1
1232 endif
1233else
1234 let s:lnum = 1
1235endif
Bram Moolenaarb02cbe32010-07-11 22:38:52 +02001236if exists("g:html_end_line")
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237 let s:end = html_end_line
1238 if s:end < s:lnum || s:end > line("$")
1239 let s:end = line("$")
1240 endif
1241else
1242 let s:end = line("$")
1243endif
1244
Bram Moolenaar5c736222010-01-06 20:54:52 +01001245" stack to keep track of all the folds containing the current line
1246let s:foldstack = []
1247
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001248if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001249 let s:pgb = s:ProgressBar("Processing lines:", s:end - s:lnum + 1, s:orgwin)
1250endif
1251
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001252if s:settings.number_lines
Bram Moolenaar5c736222010-01-06 20:54:52 +01001253 let s:margin = strlen(s:end) + 1
1254else
1255 let s:margin = 0
1256endif
1257
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001258if has('folding') && !s:settings.ignore_folding
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001259 let s:foldfillchar = &fillchars[matchend(&fillchars, 'fold:')]
1260 if s:foldfillchar == ''
1261 let s:foldfillchar = '-'
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001262 endif
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001263endif
1264let s:difffillchar = &fillchars[matchend(&fillchars, 'diff:')]
1265if s:difffillchar == ''
1266 let s:difffillchar = '-'
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001267endif
1268
Bram Moolenaar5c736222010-01-06 20:54:52 +01001269let s:foldId = 0
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001270
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001271if !s:settings.expand_tabs
1272 " If keeping tabs, add them to printable characters so we keep them when
1273 " formatting text (strtrans() doesn't replace printable chars)
1274 let s:old_isprint = &isprint
1275 setlocal isprint+=9
1276endif
1277
Bram Moolenaar071d4272004-06-13 20:20:40 +00001278while s:lnum <= s:end
1279
Bram Moolenaar47136d72004-10-12 20:02:24 +00001280 " If there are filler lines for diff mode, show these above the line.
1281 let s:filler = diff_filler(s:lnum)
1282 if s:filler > 0
1283 let s:n = s:filler
1284 while s:n > 0
Bram Moolenaar5c736222010-01-06 20:54:52 +01001285 let s:new = repeat(s:difffillchar, 3)
Bram Moolenaar47136d72004-10-12 20:02:24 +00001286
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001287 if s:n > 2 && s:n < s:filler && !s:settings.whole_filler
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001288 let s:new = s:new . " " . s:filler . " inserted lines "
1289 let s:n = 2
1290 endif
1291
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001292 if !s:settings.no_pre
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001293 " HTML line wrapping is off--go ahead and fill to the margin
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001294 " TODO: what about when CSS wrapping is turned on?
Bram Moolenaar5c736222010-01-06 20:54:52 +01001295 let s:new = s:new . repeat(s:difffillchar, &columns - strlen(s:new) - s:margin)
1296 else
1297 let s:new = s:new . repeat(s:difffillchar, 3)
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001298 endif
1299
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001300 let s:new = s:HtmlFormat_d(s:new, s:DIFF_D_ID, 0)
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001301 if s:settings.number_lines
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001302 " Indent if line numbering is on. Indent gets style of line number
1303 " column.
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001304 let s:new = s:HtmlFormat_n(repeat(' ', s:margin), s:LINENR_ID, 0, 0) . s:new
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001305 endif
1306 if s:settings.dynamic_folds && !s:settings.no_foldcolumn && s:foldcolumn > 0
1307 " Indent for foldcolumn if there is one. Assume it's empty, there should
1308 " not be a fold for deleted lines in diff mode.
1309 let s:new = s:FoldColumn_fill() . s:new
Bram Moolenaar5c736222010-01-06 20:54:52 +01001310 endif
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001311 call add(s:lines, s:new.s:HtmlEndline)
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001312
Bram Moolenaar47136d72004-10-12 20:02:24 +00001313 let s:n = s:n - 1
1314 endwhile
1315 unlet s:n
1316 endif
1317 unlet s:filler
1318
1319 " Start the line with the line number.
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001320 if s:settings.number_lines
Bram Moolenaar5c736222010-01-06 20:54:52 +01001321 let s:numcol = repeat(' ', s:margin - 1 - strlen(s:lnum)) . s:lnum . ' '
Bram Moolenaar47136d72004-10-12 20:02:24 +00001322 endif
1323
Bram Moolenaar5c736222010-01-06 20:54:52 +01001324 let s:new = ""
1325
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001326 if has('folding') && !s:settings.ignore_folding && foldclosed(s:lnum) > -1 && !s:settings.dynamic_folds
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001327 "
Bram Moolenaar5c736222010-01-06 20:54:52 +01001328 " This is the beginning of a folded block (with no dynamic folding)
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001329 let s:new = foldtextresult(s:lnum)
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001330 if !s:settings.no_pre
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001331 " HTML line wrapping is off--go ahead and fill to the margin
1332 let s:new = s:new . repeat(s:foldfillchar, &columns - strlen(s:new))
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001333 endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001334
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001335 " put numcol in a separate group for sake of unselectable text
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001336 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 +00001337
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001338 " Skip to the end of the fold
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001339 let s:new_lnum = foldclosedend(s:lnum)
1340
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001341 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001342 call s:pgb.incr(s:new_lnum - s:lnum)
1343 endif
1344
1345 let s:lnum = s:new_lnum
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001346
1347 else
1348 "
Bram Moolenaar5c736222010-01-06 20:54:52 +01001349 " A line that is not folded, or doing dynamic folding.
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001350 "
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001351 let s:line = getline(s:lnum)
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001352 let s:len = strlen(s:line)
1353
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001354 if s:settings.dynamic_folds
Bram Moolenaar5c736222010-01-06 20:54:52 +01001355 " First insert a closing for any open folds that end on this line
1356 while !empty(s:foldstack) && get(s:foldstack,0).lastline == s:lnum-1
1357 let s:new = s:new."</span></span>"
1358 call remove(s:foldstack, 0)
1359 endwhile
1360
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001361 " Now insert an opening for any new folds that start on this line
Bram Moolenaar5c736222010-01-06 20:54:52 +01001362 let s:firstfold = 1
1363 while !empty(s:allfolds) && get(s:allfolds,0).firstline == s:lnum
1364 let s:foldId = s:foldId + 1
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001365 let s:new .= "<span id='"
1366 let s:new .= (exists('g:html_diff_win_num') ? "win".g:html_diff_win_num : "")
1367 let s:new .= "fold".s:foldId."' class='".s:allfolds[0].type."'>"
1368
Bram Moolenaar5c736222010-01-06 20:54:52 +01001369
1370 " Unless disabled, add a fold column for the opening line of a fold.
1371 "
1372 " Note that dynamic folds require using css so we just use css to take
1373 " care of the leading spaces rather than using &nbsp; in the case of
1374 " html_no_pre to make it easier
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001375 if !s:settings.no_foldcolumn
Bram Moolenaar5c736222010-01-06 20:54:52 +01001376 " add fold column that can open the new fold
1377 if s:allfolds[0].level > 1 && s:firstfold
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001378 let s:new = s:new . s:FoldColumn_build('|', s:allfolds[0].level - 1, 0, "",
1379 \ 'toggle-open FoldColumn','javascript:toggleFold("fold'.s:foldstack[0].id.'");')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001380 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001381 " add the filler spaces separately from the '+' char so that it can be
1382 " shown/hidden separately during a hover unfold
1383 let s:new = s:new . s:FoldColumn_build("+", 1, 0, "",
1384 \ 'toggle-open FoldColumn', 'javascript:toggleFold("fold'.s:foldId.'");')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001385 " If this is not the last fold we're opening on this line, we need
1386 " to keep the filler spaces hidden if the fold is opened by mouse
1387 " hover. If it is the last fold to open in the line, we shouldn't hide
1388 " them, so don't apply the toggle-filler class.
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001389 let s:new = s:new . s:FoldColumn_build(" ", 1, s:foldcolumn - s:allfolds[0].level - 1, "",
1390 \ 'toggle-open FoldColumn'. (get(s:allfolds, 1, {'firstline': 0}).firstline == s:lnum ?" toggle-filler" :""),
1391 \ 'javascript:toggleFold("fold'.s:foldId.'");')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001392
1393 " add fold column that can close the new fold
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001394 " only add extra blank space if we aren't opening another fold on the
1395 " same line
Bram Moolenaar5c736222010-01-06 20:54:52 +01001396 if get(s:allfolds, 1, {'firstline': 0}).firstline != s:lnum
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001397 let s:extra_space = s:foldcolumn - s:allfolds[0].level
1398 else
1399 let s:extra_space = 0
Bram Moolenaar5c736222010-01-06 20:54:52 +01001400 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001401 if s:firstfold
1402 " the first fold in a line has '|' characters from folds opened in
1403 " previous lines, before the '-' for this fold
1404 let s:new .= s:FoldColumn_build('|', s:allfolds[0].level - 1, s:extra_space, '-',
1405 \ 'toggle-closed FoldColumn', 'javascript:toggleFold("fold'.s:foldId.'");')
1406 else
1407 " any subsequent folds in the line only add a single '-'
1408 let s:new = s:new . s:FoldColumn_build("-", 1, s:extra_space, "",
1409 \ 'toggle-closed FoldColumn', 'javascript:toggleFold("fold'.s:foldId.'");')
1410 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +01001411 let s:firstfold = 0
1412 endif
1413
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001414 " Add fold text, moving the span ending to the next line so collapsing
1415 " of folds works correctly.
1416 " Put numcol in a separate group for sake of unselectable text.
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001417 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 +01001418 let s:new = s:new . "<span class='fulltext'>"
1419
1420 " open the fold now that we have the fold text to allow retrieval of
1421 " fold text for subsequent folds
1422 execute s:lnum."foldopen"
1423 call insert(s:foldstack, remove(s:allfolds,0))
1424 let s:foldstack[0].id = s:foldId
1425 endwhile
1426
1427 " Unless disabled, add a fold column for other lines.
1428 "
1429 " Note that dynamic folds require using css so we just use css to take
1430 " care of the leading spaces rather than using &nbsp; in the case of
1431 " html_no_pre to make it easier
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001432 if !s:settings.no_foldcolumn
Bram Moolenaar5c736222010-01-06 20:54:52 +01001433 if empty(s:foldstack)
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001434 " add the empty foldcolumn for unfolded lines if there is a fold
1435 " column at all
1436 if s:foldcolumn > 0
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001437 let s:new = s:new . s:FoldColumn_fill()
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001438 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +01001439 else
1440 " add the fold column for folds not on the opening line
1441 if get(s:foldstack, 0).firstline < s:lnum
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001442 let s:new = s:new . s:FoldColumn_build('|', s:foldstack[0].level, s:foldcolumn - s:foldstack[0].level, "",
1443 \ 'FoldColumn', 'javascript:toggleFold("fold'.s:foldstack[0].id.'");')
Bram Moolenaar5c736222010-01-06 20:54:52 +01001444 endif
1445 endif
1446 endif
1447 endif
1448
1449 " Now continue with the unfolded line text
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001450 if s:settings.number_lines
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001451 let s:new = s:new . s:HtmlFormat_n(s:numcol, s:LINENR_ID, 0, s:lnum)
1452 else
1453 let s:new = s:new . s:HtmlFormat_n("", s:LINENR_ID, 0, s:lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001454 endif
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001455
Bram Moolenaar47136d72004-10-12 20:02:24 +00001456 " Get the diff attribute, if any.
1457 let s:diffattr = diff_hlID(s:lnum, 1)
1458
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001459 " initialize conceal info to act like not concealed, just in case
1460 let s:concealinfo = [0, '']
1461
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001462 " Loop over each character in the line
1463 let s:col = 1
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001464
1465 " most of the time we won't use the diff_id, initialize to zero
1466 let s:diff_id = 0
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001467
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001468 while s:col <= s:len || (s:col == 1 && s:diffattr)
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001469 let s:startcol = s:col " The start column for processing text
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001470 if !s:settings.ignore_conceal && has('conceal')
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001471 let s:concealinfo = synconcealed(s:lnum, s:col)
1472 endif
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001473 if !s:settings.ignore_conceal && s:concealinfo[0]
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001474 let s:col = s:col + 1
1475 " Speed loop (it's small - that's the trick)
1476 " Go along till we find a change in the match sequence number (ending
1477 " the specific concealed region) or until there are no more concealed
1478 " characters.
1479 while s:col <= s:len && s:concealinfo == synconcealed(s:lnum, s:col) | let s:col = s:col + 1 | endwhile
1480 elseif s:diffattr
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001481 let s:diff_id = diff_hlID(s:lnum, s:col)
1482 let s:id = synID(s:lnum, s:col, 1)
Bram Moolenaar47136d72004-10-12 20:02:24 +00001483 let s:col = s:col + 1
1484 " Speed loop (it's small - that's the trick)
1485 " Go along till we find a change in hlID
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001486 while s:col <= s:len && s:id == synID(s:lnum, s:col, 1)
1487 \ && s:diff_id == diff_hlID(s:lnum, s:col) |
1488 \ let s:col = s:col + 1 |
1489 \ endwhile
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001490 if s:len < &columns && !s:settings.no_pre
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001491 " Add spaces at the end of the raw text line to extend the changed
1492 " line to the full width.
Bram Moolenaar5c736222010-01-06 20:54:52 +01001493 let s:line = s:line . repeat(' ', &columns - virtcol([s:lnum, s:len]) - s:margin)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001494 let s:len = &columns
1495 endif
Bram Moolenaar47136d72004-10-12 20:02:24 +00001496 else
1497 let s:id = synID(s:lnum, s:col, 1)
1498 let s:col = s:col + 1
1499 " Speed loop (it's small - that's the trick)
1500 " Go along till we find a change in synID
1501 while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) | let s:col = s:col + 1 | endwhile
1502 endif
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001503
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001504 if s:settings.ignore_conceal || !s:concealinfo[0]
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001505 " Expand tabs if needed
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001506 let s:expandedtab = strpart(s:line, s:startcol - 1, s:col - s:startcol)
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001507 if s:settings.expand_tabs
1508 let s:offset = 0
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001509 let s:idx = stridx(s:expandedtab, "\t")
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001510 while s:idx >= 0
1511 if has("multi_byte_encoding")
1512 if s:startcol + s:idx == 1
1513 let s:i = &ts
1514 else
1515 if s:idx == 0
1516 let s:prevc = matchstr(s:line, '.\%' . (s:startcol + s:idx + s:offset) . 'c')
1517 else
1518 let s:prevc = matchstr(s:expandedtab, '.\%' . (s:idx + 1) . 'c')
1519 endif
1520 let s:vcol = virtcol([s:lnum, s:startcol + s:idx + s:offset - len(s:prevc)])
1521 let s:i = &ts - (s:vcol % &ts)
1522 endif
1523 let s:offset -= s:i - 1
1524 else
1525 let s:i = &ts - ((s:idx + s:startcol - 1) % &ts)
1526 endif
1527 let s:expandedtab = substitute(s:expandedtab, '\t', repeat(' ', s:i), '')
1528 let s:idx = stridx(s:expandedtab, "\t")
1529 endwhile
1530 end
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00001531
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001532 " get the highlight group name to use
1533 let s:id = synIDtrans(s:id)
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001534 else
1535 " use Conceal highlighting for concealed text
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001536 let s:id = s:CONCEAL_ID
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001537 let s:expandedtab = s:concealinfo[1]
1538 endif
1539
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001540 " Output the text with the same synID, with class set to the highlight ID
1541 " name, unless it has been concealed completely.
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001542 if strlen(s:expandedtab) > 0
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001543 let s:new = s:new . s:HtmlFormat(s:expandedtab, s:id, s:diff_id, "", 0)
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001544 endif
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001545 endwhile
1546 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001547
Bram Moolenaar7510fe72010-07-25 12:46:44 +02001548 call extend(s:lines, split(s:new.s:HtmlEndline, '\n', 1))
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001549 if !s:settings.no_progress && s:pgb.needs_redraw
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001550 redrawstatus
1551 let s:pgb.needs_redraw = 0
1552 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001553 let s:lnum = s:lnum + 1
Bram Moolenaar313b7232007-05-05 17:56:55 +00001554
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001555 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001556 call s:pgb.incr()
1557 endif
1558endwhile
1559
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001560if s:settings.dynamic_folds
Bram Moolenaar5c736222010-01-06 20:54:52 +01001561 " finish off any open folds
1562 while !empty(s:foldstack)
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001563 let s:lines[-1].="</span></span>"
Bram Moolenaar5c736222010-01-06 20:54:52 +01001564 call remove(s:foldstack, 0)
1565 endwhile
1566
1567 " add fold column to the style list if not already there
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001568 let s:id = s:FOLD_C_ID
1569 if !has_key(s:stylelist, s:id)
1570 let s:stylelist[s:id] = '.FoldColumn { ' . s:CSS1(s:id) . '}'
Bram Moolenaar5c736222010-01-06 20:54:52 +01001571 endif
1572endif
1573
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001574if s:settings.no_pre
1575 if !s:settings.use_css
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001576 " Close off the font tag that encapsulates the whole <body>
Bram Moolenaarbebca9d2010-08-07 15:47:30 +02001577 call extend(s:lines, ["</font>", "</body>", "</html>"])
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001578 else
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001579 call extend(s:lines, ["</div>", "</body>", "</html>"])
Bram Moolenaar8ada2cc2010-07-29 20:43:36 +02001580 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001581else
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001582 call extend(s:lines, ["</pre>", "</body>", "</html>"])
Bram Moolenaar071d4272004-06-13 20:20:40 +00001583endif
1584
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001585exe s:newwin . "wincmd w"
1586call setline(1, s:lines)
1587unlet s:lines
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001589" Mangle modelines so Vim doesn't try to use HTML text as a modeline if editing
1590" this file in the future; need to do this after generating all the text in case
1591" the modeline text has different highlight groups which all turn out to be
1592" stripped from the final output.
1593%s!\v(%(^|\s+)%(vim?|ex)):!\1\&#0058;!ge
1594
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001595" The generated HTML is admittedly ugly and takes a LONG time to fold.
1596" Make sure the user doesn't do syntax folding when loading a generated file,
1597" using a modeline.
1598call append(line('$'), "<!-- vim: set foldmethod=manual : -->")
1599
Bram Moolenaar071d4272004-06-13 20:20:40 +00001600" Now, when we finally know which, we define the colors and styles
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001601if s:settings.use_css
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 1;/<style type="text/+1
1603endif
1604
Bram Moolenaar071d4272004-06-13 20:20:40 +00001605" Normal/global attributes
1606" For Netscape 4, set <body> attributes too, though, strictly speaking, it's
1607" incorrect.
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001608if s:settings.use_css
1609 if s:settings.no_pre
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001610 call append('.', "body { color: " . s:fgc . "; background-color: " . s:bgc . "; font-family: ". s:htmlfont ."; }")
1611 +
Bram Moolenaar071d4272004-06-13 20:20:40 +00001612 else
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001613 call append('.', "pre { " . s:whitespace . "font-family: ". s:htmlfont ."; color: " . s:fgc . "; background-color: " . s:bgc . "; }")
1614 +
Bram Moolenaar071d4272004-06-13 20:20:40 +00001615 yank
1616 put
1617 execute "normal! ^cwbody\e"
Bram Moolenaar8e5af3e2011-04-28 19:02:44 +02001618 " body should not have the wrap formatting, only the pre section
1619 if s:whitespace != ''
1620 exec 's#'.s:whitespace
1621 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001622 endif
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001623 " fix browser inconsistencies (sometimes within the same browser) of different
1624 " default font size for different elements
1625 call append('.', '* { font-size: 1em; }')
1626 +
1627 " if we use any input elements for unselectable content, make sure they look
1628 " like normal text
1629 if !empty(s:settings.prevent_copy)
1630 call append('.', 'input { border: none; margin: 0; padding: 0; font-family: '.s:htmlfont.'; }')
1631 +
1632 " ch units for browsers which support them, em units for a somewhat
1633 " reasonable fallback. Also make sure the special elements for size
1634 " calculations aren't seen.
1635 call append('.', [
1636 \ "input[size='1'] { width: 1em; width: 1ch; }",
1637 \ "input[size='2'] { width: 2em; width: 2ch; }",
1638 \ "input[size='3'] { width: 3em; width: 3ch; }",
1639 \ "input[size='4'] { width: 4em; width: 4ch; }",
1640 \ "input[size='5'] { width: 5em; width: 5ch; }",
1641 \ "input[size='6'] { width: 6em; width: 6ch; }",
1642 \ "input[size='7'] { width: 7em; width: 7ch; }",
1643 \ "input[size='8'] { width: 8em; width: 8ch; }",
1644 \ "input[size='9'] { width: 9em; width: 9ch; }",
1645 \ "input[size='10'] { width: 10em; width: 10ch; }",
1646 \ "input[size='11'] { width: 11em; width: 11ch; }",
1647 \ "input[size='12'] { width: 12em; width: 12ch; }",
1648 \ "input[size='13'] { width: 13em; width: 13ch; }",
1649 \ "input[size='14'] { width: 14em; width: 14ch; }",
1650 \ "input[size='15'] { width: 15em; width: 15ch; }",
1651 \ "input[size='16'] { width: 16em; width: 16ch; }",
1652 \ "input[size='17'] { width: 17em; width: 17ch; }",
1653 \ "input[size='18'] { width: 18em; width: 18ch; }",
1654 \ "input[size='19'] { width: 19em; width: 19ch; }",
1655 \ "input[size='20'] { width: 20em; width: 20ch; }",
1656 \ "#oneCharWidth, #oneEmWidth, #oneInputWidth { padding: 0; margin: 0; position: absolute; left: -999999px; visibility: hidden; }"
1657 \ ])
1658 +21
1659 for w in range(5, 100, 5)
1660 let base = 0.01 * w
1661 call append('.', join(map(range(1,20), "'.em'.w.' input[size='''.v:val.'''] { width: '.string(v:val*base).'em; }'")))
1662 +
1663 endfor
1664 if s:settings.prevent_copy =~# 'f'
1665 " Make the cursor show active fold columns as active areas, and empty fold
1666 " columns as not interactive.
1667 call append('.', ['input.FoldColumn { cursor: pointer; }',
1668 \ 'input.FoldColumn[value=""] { cursor: default; }'
1669 \ ])
1670 +2
1671 endif
1672 " make line number column show as non-interactive if not selectable
1673 if s:settings.prevent_copy =~# 'n'
1674 call append('.', 'input.LineNr { cursor: default; }')
1675 +
1676 endif
1677 " make fold text and line number column within fold text show as
1678 " non-interactive if not selectable
1679 if (s:settings.prevent_copy =~# 'n' || s:settings.prevent_copy =~# 't') && !s:settings.ignore_folding
1680 call append('.', 'input.Folded { cursor: default; }')
1681 +
1682 endif
1683 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684else
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001685 execute '%s:<body\([^>]*\):<body bgcolor="' . s:bgc . '" text="' . s:fgc . '"\1>\r<font face="'. s:htmlfont .'"'
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686endif
1687
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001688" Gather attributes for all other classes. Do diff first so that normal
1689" highlight groups are inserted before it.
1690if s:settings.use_css
1691 if s:diff_mode
1692 call append('.', filter(map(keys(s:diffstylelist), "s:diffstylelist[v:val]"), 'v:val != ""'))
1693 endif
1694 if !empty(s:stylelist)
1695 call append('.', filter(map(keys(s:stylelist), "s:stylelist[v:val]"), 'v:val != ""'))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696 endif
1697endif
1698
Bram Moolenaar071d4272004-06-13 20:20:40 +00001699" Add hyperlinks
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001700" TODO: add option to not do this? Maybe just make the color the same as the
1701" text highlight group normally is?
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001702%s+\(https\=://\S\{-}\)\(\([.,;:}]\=\(\s\|$\)\)\|[\\"'<>]\|&gt;\|&lt;\|&quot;\)+<a href="\1">\1</a>\2+ge
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703
1704" The DTD
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001705if s:settings.use_xhtml
1706 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\">"
1707elseif s:settings.use_css && !s:settings.no_pre
1708 exe "normal! gg0i<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n"
Bram Moolenaar313b7232007-05-05 17:56:55 +00001709else
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001710 exe "normal! gg0i<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001711endif
1712
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001713if s:settings.use_xhtml
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001714 exe "normal! gg/<html/e\na xmlns=\"http://www.w3.org/1999/xhtml\"\e"
Bram Moolenaar071d4272004-06-13 20:20:40 +00001715endif
1716
1717" Cleanup
1718%s:\s\+$::e
1719
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001720" Restore old settings (new window first)
Bram Moolenaar543b7ef2013-06-01 14:50:56 +02001721"
1722" Don't bother restoring foldmethod in case it was syntax because the markup is
1723" so weirdly formatted it can take a LONG time.
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001724let &l:foldenable = s:old_fen
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725let &report = s:old_report
1726let &title = s:old_title
1727let &icon = s:old_icon
1728let &paste = s:old_paste
1729let &magic = s:old_magic
1730let @/ = s:old_search
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001731let &more = s:old_more
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001732
1733" switch to original window to restore those settings
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734exe s:orgwin . "wincmd w"
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001735
1736if !s:settings.expand_tabs
1737 let &l:isprint = s:old_isprint
1738endif
Bram Moolenaar166af9b2010-11-16 20:34:40 +01001739let &l:stl = s:origwin_stl
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740let &l:et = s:old_et
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001741let &l:scrollbind = s:old_bind
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001742
1743" and back to the new window again to end there
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744exe s:newwin . "wincmd w"
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001745
Bram Moolenaar166af9b2010-11-16 20:34:40 +01001746let &l:stl = s:newwin_stl
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001747exec 'resize' s:old_winheight
1748let &l:winfixheight = s:old_winfixheight
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001750let &ls=s:ls
1751
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752" Save a little bit of memory (worth doing?)
Bram Moolenaar8e5af3e2011-04-28 19:02:44 +02001753unlet s:htmlfont s:whitespace
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001754unlet 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 +02001755unlet s:old_magic s:old_more s:old_fen s:old_winheight
Bram Moolenaar2a8a3ec2011-01-08 16:06:37 +01001756unlet! s:old_isprint
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001757unlet s:whatterm s:stylelist s:diffstylelist s:lnum s:end s:margin s:fgc s:bgc s:old_winfixheight
1758unlet! s:col s:id s:attr s:len s:line s:new s:expandedtab s:concealinfo s:diff_mode
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001759unlet! s:orgwin s:newwin s:orgbufnr s:idx s:i s:offset s:ls s:origwin_stl
1760unlet! s:newwin_stl s:current_syntax
Bram Moolenaar05159a02005-02-26 23:04:13 +00001761if !v:profiling
1762 delfunc s:HtmlColor
1763 delfunc s:HtmlFormat
1764 delfunc s:CSS1
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001765 delfunc s:BuildStyleWrapper
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001766 if !s:settings.use_css
Bram Moolenaar05159a02005-02-26 23:04:13 +00001767 delfunc s:HtmlOpening
1768 delfunc s:HtmlClosing
1769 endif
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001770 if s:settings.dynamic_folds
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001771 delfunc s:FoldCompare
1772 endif
1773
Bram Moolenaar076e8b22010-08-05 21:54:00 +02001774 if !s:settings.no_progress
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001775 delfunc s:ProgressBar
1776 delfunc s:progressbar.paint
1777 delfunc s:progressbar.incr
1778 unlet s:pgb s:progressbar
1779 endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780endif
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001781
Bram Moolenaar8df7f882010-08-13 11:30:02 +02001782unlet! s:new_lnum s:diffattr s:difffillchar s:foldfillchar s:HtmlSpace
Bram Moolenaar6c35bea2012-07-25 17:49:10 +02001783unlet! s:LeadingSpace s:HtmlEndline s:firstfold s:numcol s:foldcolumn
1784unlet s:foldstack s:allfolds s:foldId s:settings
Bram Moolenaar5c736222010-01-06 20:54:52 +01001785
1786let &cpo = s:cpo_sav
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001787unlet! s:cpo_sav
Bram Moolenaar5c736222010-01-06 20:54:52 +01001788
Bram Moolenaar349b2fb2010-07-16 20:35:36 +02001789" Make sure any patches will probably use consistent indent
Bram Moolenaar7c86f4c2010-07-18 14:07:22 +02001790" vim: ts=8 sw=2 sts=2 noet