xref: /vim-8.2.3635/runtime/autoload/tohtml.vim (revision 6c391a74)
1" Vim autoload file for the tohtml plugin.
2" Maintainer: Ben Fritz <[email protected]>
3" Last Change: 2019 Aug 16
4"
5" Additional contributors:
6"
7"	      Original by Bram Moolenaar <[email protected]>
8"	      Diff2HTML() added by Christian Brabandt <[email protected]>
9"
10"	      See Mercurial change logs for more!
11
12" this file uses line continuations
13let s:cpo_sav = &cpo
14set cpo&vim
15
16" Automatically find charsets from all encodings supported natively by Vim. With
17" the 8bit- and 2byte- prefixes, Vim can actually support more encodings than
18" this. Let the user specify these however since they won't be supported on
19" every system.
20"
21" Note, not all of Vim's supported encodings have a charset to use.
22"
23" Names in this list are from:
24"   http://www.iana.org/assignments/character-sets
25" g:tohtml#encoding_to_charset: {{{
26let g:tohtml#encoding_to_charset = {
27      \ 'latin1' : 'ISO-8859-1',
28      \ 'iso-8859-2' : 'ISO-8859-2',
29      \ 'iso-8859-3' : 'ISO-8859-3',
30      \ 'iso-8859-4' : 'ISO-8859-4',
31      \ 'iso-8859-5' : 'ISO-8859-5',
32      \ 'iso-8859-6' : 'ISO-8859-6',
33      \ 'iso-8859-7' : 'ISO-8859-7',
34      \ 'iso-8859-8' : 'ISO-8859-8',
35      \ 'iso-8859-9' : 'ISO-8859-9',
36      \ 'iso-8859-10' : '',
37      \ 'iso-8859-13' : 'ISO-8859-13',
38      \ 'iso-8859-14' : '',
39      \ 'iso-8859-15' : 'ISO-8859-15',
40      \ 'koi8-r' : 'KOI8-R',
41      \ 'koi8-u' : 'KOI8-U',
42      \ 'macroman' : 'macintosh',
43      \ 'cp437' : '',
44      \ 'cp775' : '',
45      \ 'cp850' : '',
46      \ 'cp852' : '',
47      \ 'cp855' : '',
48      \ 'cp857' : '',
49      \ 'cp860' : '',
50      \ 'cp861' : '',
51      \ 'cp862' : '',
52      \ 'cp863' : '',
53      \ 'cp865' : '',
54      \ 'cp866' : 'IBM866',
55      \ 'cp869' : '',
56      \ 'cp874' : '',
57      \ 'cp1250' : 'windows-1250',
58      \ 'cp1251' : 'windows-1251',
59      \ 'cp1253' : 'windows-1253',
60      \ 'cp1254' : 'windows-1254',
61      \ 'cp1255' : 'windows-1255',
62      \ 'cp1256' : 'windows-1256',
63      \ 'cp1257' : 'windows-1257',
64      \ 'cp1258' : 'windows-1258',
65      \ 'euc-jp' : 'EUC-JP',
66      \ 'sjis' : 'Shift_JIS',
67      \ 'cp932' : 'Shift_JIS',
68      \ 'cp949' : '',
69      \ 'euc-kr' : 'EUC-KR',
70      \ 'cp936' : 'GBK',
71      \ 'euc-cn' : 'GB2312',
72      \ 'big5' : 'Big5',
73      \ 'cp950' : 'Big5',
74      \ 'utf-8' : 'UTF-8',
75      \ 'ucs-2' : 'UTF-8',
76      \ 'ucs-2le' : 'UTF-8',
77      \ 'utf-16' : 'UTF-8',
78      \ 'utf-16le' : 'UTF-8',
79      \ 'ucs-4' : 'UTF-8',
80      \ 'ucs-4le' : 'UTF-8',
81      \ }
82lockvar g:tohtml#encoding_to_charset
83" Notes:
84"   1. All UCS/UTF are converted to UTF-8 because it is much better supported
85"   2. Any blank spaces are there because Vim supports it but at least one major
86"      web browser does not according to http://wiki.whatwg.org/wiki/Web_Encodings.
87" }}}
88
89" Only automatically find encodings supported natively by Vim, let the user
90" specify the encoding if it's not natively supported. This function is only
91" used when the user specifies the charset, they better know what they are
92" doing!
93"
94" Names in this list are from:
95"   http://www.iana.org/assignments/character-sets
96" g:tohtml#charset_to_encoding: {{{
97let g:tohtml#charset_to_encoding = {
98      \ 'iso_8859-1:1987' : 'latin1',
99      \ 'iso-ir-100' : 'latin1',
100      \ 'iso_8859-1' : 'latin1',
101      \ 'iso-8859-1' : 'latin1',
102      \ 'latin1' : 'latin1',
103      \ 'l1' : 'latin1',
104      \ 'ibm819' : 'latin1',
105      \ 'cp819' : 'latin1',
106      \ 'csisolatin1' : 'latin1',
107      \ 'iso_8859-2:1987' : 'iso-8859-2',
108      \ 'iso-ir-101' : 'iso-8859-2',
109      \ 'iso_8859-2' : 'iso-8859-2',
110      \ 'iso-8859-2' : 'iso-8859-2',
111      \ 'latin2' : 'iso-8859-2',
112      \ 'l2' : 'iso-8859-2',
113      \ 'csisolatin2' : 'iso-8859-2',
114      \ 'iso_8859-3:1988' : 'iso-8859-3',
115      \ 'iso-ir-109' : 'iso-8859-3',
116      \ 'iso_8859-3' : 'iso-8859-3',
117      \ 'iso-8859-3' : 'iso-8859-3',
118      \ 'latin3' : 'iso-8859-3',
119      \ 'l3' : 'iso-8859-3',
120      \ 'csisolatin3' : 'iso-8859-3',
121      \ 'iso_8859-4:1988' : 'iso-8859-4',
122      \ 'iso-ir-110' : 'iso-8859-4',
123      \ 'iso_8859-4' : 'iso-8859-4',
124      \ 'iso-8859-4' : 'iso-8859-4',
125      \ 'latin4' : 'iso-8859-4',
126      \ 'l4' : 'iso-8859-4',
127      \ 'csisolatin4' : 'iso-8859-4',
128      \ 'iso_8859-5:1988' : 'iso-8859-5',
129      \ 'iso-ir-144' : 'iso-8859-5',
130      \ 'iso_8859-5' : 'iso-8859-5',
131      \ 'iso-8859-5' : 'iso-8859-5',
132      \ 'cyrillic' : 'iso-8859-5',
133      \ 'csisolatincyrillic' : 'iso-8859-5',
134      \ 'iso_8859-6:1987' : 'iso-8859-6',
135      \ 'iso-ir-127' : 'iso-8859-6',
136      \ 'iso_8859-6' : 'iso-8859-6',
137      \ 'iso-8859-6' : 'iso-8859-6',
138      \ 'ecma-114' : 'iso-8859-6',
139      \ 'asmo-708' : 'iso-8859-6',
140      \ 'arabic' : 'iso-8859-6',
141      \ 'csisolatinarabic' : 'iso-8859-6',
142      \ 'iso_8859-7:1987' : 'iso-8859-7',
143      \ 'iso-ir-126' : 'iso-8859-7',
144      \ 'iso_8859-7' : 'iso-8859-7',
145      \ 'iso-8859-7' : 'iso-8859-7',
146      \ 'elot_928' : 'iso-8859-7',
147      \ 'ecma-118' : 'iso-8859-7',
148      \ 'greek' : 'iso-8859-7',
149      \ 'greek8' : 'iso-8859-7',
150      \ 'csisolatingreek' : 'iso-8859-7',
151      \ 'iso_8859-8:1988' : 'iso-8859-8',
152      \ 'iso-ir-138' : 'iso-8859-8',
153      \ 'iso_8859-8' : 'iso-8859-8',
154      \ 'iso-8859-8' : 'iso-8859-8',
155      \ 'hebrew' : 'iso-8859-8',
156      \ 'csisolatinhebrew' : 'iso-8859-8',
157      \ 'iso_8859-9:1989' : 'iso-8859-9',
158      \ 'iso-ir-148' : 'iso-8859-9',
159      \ 'iso_8859-9' : 'iso-8859-9',
160      \ 'iso-8859-9' : 'iso-8859-9',
161      \ 'latin5' : 'iso-8859-9',
162      \ 'l5' : 'iso-8859-9',
163      \ 'csisolatin5' : 'iso-8859-9',
164      \ 'iso-8859-10' : 'iso-8859-10',
165      \ 'iso-ir-157' : 'iso-8859-10',
166      \ 'l6' : 'iso-8859-10',
167      \ 'iso_8859-10:1992' : 'iso-8859-10',
168      \ 'csisolatin6' : 'iso-8859-10',
169      \ 'latin6' : 'iso-8859-10',
170      \ 'iso-8859-13' : 'iso-8859-13',
171      \ 'iso-8859-14' : 'iso-8859-14',
172      \ 'iso-ir-199' : 'iso-8859-14',
173      \ 'iso_8859-14:1998' : 'iso-8859-14',
174      \ 'iso_8859-14' : 'iso-8859-14',
175      \ 'latin8' : 'iso-8859-14',
176      \ 'iso-celtic' : 'iso-8859-14',
177      \ 'l8' : 'iso-8859-14',
178      \ 'iso-8859-15' : 'iso-8859-15',
179      \ 'iso_8859-15' : 'iso-8859-15',
180      \ 'latin-9' : 'iso-8859-15',
181      \ 'koi8-r' : 'koi8-r',
182      \ 'cskoi8r' : 'koi8-r',
183      \ 'koi8-u' : 'koi8-u',
184      \ 'macintosh' : 'macroman',
185      \ 'mac' : 'macroman',
186      \ 'csmacintosh' : 'macroman',
187      \ 'ibm437' : 'cp437',
188      \ 'cp437' : 'cp437',
189      \ '437' : 'cp437',
190      \ 'cspc8codepage437' : 'cp437',
191      \ 'ibm775' : 'cp775',
192      \ 'cp775' : 'cp775',
193      \ 'cspc775baltic' : 'cp775',
194      \ 'ibm850' : 'cp850',
195      \ 'cp850' : 'cp850',
196      \ '850' : 'cp850',
197      \ 'cspc850multilingual' : 'cp850',
198      \ 'ibm852' : 'cp852',
199      \ 'cp852' : 'cp852',
200      \ '852' : 'cp852',
201      \ 'cspcp852' : 'cp852',
202      \ 'ibm855' : 'cp855',
203      \ 'cp855' : 'cp855',
204      \ '855' : 'cp855',
205      \ 'csibm855' : 'cp855',
206      \ 'ibm857' : 'cp857',
207      \ 'cp857' : 'cp857',
208      \ '857' : 'cp857',
209      \ 'csibm857' : 'cp857',
210      \ 'ibm860' : 'cp860',
211      \ 'cp860' : 'cp860',
212      \ '860' : 'cp860',
213      \ 'csibm860' : 'cp860',
214      \ 'ibm861' : 'cp861',
215      \ 'cp861' : 'cp861',
216      \ '861' : 'cp861',
217      \ 'cp-is' : 'cp861',
218      \ 'csibm861' : 'cp861',
219      \ 'ibm862' : 'cp862',
220      \ 'cp862' : 'cp862',
221      \ '862' : 'cp862',
222      \ 'cspc862latinhebrew' : 'cp862',
223      \ 'ibm863' : 'cp863',
224      \ 'cp863' : 'cp863',
225      \ '863' : 'cp863',
226      \ 'csibm863' : 'cp863',
227      \ 'ibm865' : 'cp865',
228      \ 'cp865' : 'cp865',
229      \ '865' : 'cp865',
230      \ 'csibm865' : 'cp865',
231      \ 'ibm866' : 'cp866',
232      \ 'cp866' : 'cp866',
233      \ '866' : 'cp866',
234      \ 'csibm866' : 'cp866',
235      \ 'ibm869' : 'cp869',
236      \ 'cp869' : 'cp869',
237      \ '869' : 'cp869',
238      \ 'cp-gr' : 'cp869',
239      \ 'csibm869' : 'cp869',
240      \ 'windows-1250' : 'cp1250',
241      \ 'windows-1251' : 'cp1251',
242      \ 'windows-1253' : 'cp1253',
243      \ 'windows-1254' : 'cp1254',
244      \ 'windows-1255' : 'cp1255',
245      \ 'windows-1256' : 'cp1256',
246      \ 'windows-1257' : 'cp1257',
247      \ 'windows-1258' : 'cp1258',
248      \ 'extended_unix_code_packed_format_for_japanese' : 'euc-jp',
249      \ 'cseucpkdfmtjapanese' : 'euc-jp',
250      \ 'euc-jp' : 'euc-jp',
251      \ 'shift_jis' : 'sjis',
252      \ 'ms_kanji' : 'sjis',
253      \ 'sjis' : 'sjis',
254      \ 'csshiftjis' : 'sjis',
255      \ 'ibm-thai' : 'cp874',
256      \ 'csibmthai' : 'cp874',
257      \ 'ks_c_5601-1987' : 'cp949',
258      \ 'iso-ir-149' : 'cp949',
259      \ 'ks_c_5601-1989' : 'cp949',
260      \ 'ksc_5601' : 'cp949',
261      \ 'korean' : 'cp949',
262      \ 'csksc56011987' : 'cp949',
263      \ 'euc-kr' : 'euc-kr',
264      \ 'cseuckr' : 'euc-kr',
265      \ 'gbk' : 'cp936',
266      \ 'cp936' : 'cp936',
267      \ 'ms936' : 'cp936',
268      \ 'windows-936' : 'cp936',
269      \ 'gb_2312-80' : 'euc-cn',
270      \ 'iso-ir-58' : 'euc-cn',
271      \ 'chinese' : 'euc-cn',
272      \ 'csiso58gb231280' : 'euc-cn',
273      \ 'big5' : 'big5',
274      \ 'csbig5' : 'big5',
275      \ 'utf-8' : 'utf-8',
276      \ 'iso-10646-ucs-2' : 'ucs-2',
277      \ 'csunicode' : 'ucs-2',
278      \ 'utf-16' : 'utf-16',
279      \ 'utf-16be' : 'utf-16',
280      \ 'utf-16le' : 'utf-16le',
281      \ 'utf-32' : 'ucs-4',
282      \ 'utf-32be' : 'ucs-4',
283      \ 'utf-32le' : 'ucs-4le',
284      \ 'iso-10646-ucs-4' : 'ucs-4',
285      \ 'csucs4' : 'ucs-4'
286      \ }
287lockvar g:tohtml#charset_to_encoding
288"}}}
289
290func! tohtml#Convert2HTML(line1, line2) "{{{
291  let s:settings = tohtml#GetUserSettings()
292
293  if !&diff || s:settings.diff_one_file "{{{
294    if a:line2 >= a:line1
295      let g:html_start_line = a:line1
296      let g:html_end_line = a:line2
297    else
298      let g:html_start_line = a:line2
299      let g:html_end_line = a:line1
300    endif
301    runtime syntax/2html.vim "}}}
302  else "{{{
303    let win_list = []
304    let buf_list = []
305    windo if &diff | call add(win_list, winbufnr(0)) | endif
306    let s:settings.whole_filler = 1
307    let g:html_diff_win_num = 0
308    for window in win_list
309      " switch to the next buffer to convert
310      exe ":" . bufwinnr(window) . "wincmd w"
311
312      " figure out whether current charset and encoding will work, if not
313      " default to UTF-8
314      if !exists('g:html_use_encoding') &&
315	    \ (((&l:fileencoding=='' || (&l:buftype!='' && &l:buftype!=?'help'))
316	    \      && &encoding!=?s:settings.vim_encoding)
317	    \ || &l:fileencoding!='' && &l:fileencoding!=?s:settings.vim_encoding)
318	echohl WarningMsg
319	echomsg "TOhtml: mismatched file encodings in Diff buffers, using UTF-8"
320	echohl None
321	let s:settings.vim_encoding = 'utf-8'
322	let s:settings.encoding = 'UTF-8'
323      endif
324
325      " set up for diff-mode conversion
326      let g:html_start_line = 1
327      let g:html_end_line = line('$')
328      let g:html_diff_win_num += 1
329
330      " convert this file
331      runtime syntax/2html.vim
332
333      " remember the HTML buffer for later combination
334      call add(buf_list, bufnr('%'))
335    endfor
336    unlet g:html_diff_win_num
337    call tohtml#Diff2HTML(win_list, buf_list)
338  endif "}}}
339
340  unlet g:html_start_line
341  unlet g:html_end_line
342  unlet s:settings
343endfunc "}}}
344
345func! tohtml#Diff2HTML(win_list, buf_list) "{{{
346  let xml_line = ""
347  let tag_close = '>'
348
349  let s:old_paste = &paste
350  set paste
351  let s:old_magic = &magic
352  set magic
353
354  if s:settings.use_xhtml
355    if s:settings.encoding != ""
356      let xml_line = "<?xml version=\"1.0\" encoding=\"" . s:settings.encoding . "\"?>"
357    else
358      let xml_line = "<?xml version=\"1.0\"?>"
359    endif
360    let tag_close = ' />'
361  endif
362
363  let style = [s:settings.use_xhtml ? "" : '-->']
364  let body_line = ''
365
366  let html = []
367  let s:html5 = 0
368  if s:settings.use_xhtml
369    call add(html, xml_line)
370  endif
371  if s:settings.use_xhtml
372    call add(html, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">")
373    call add(html, '<html xmlns="http://www.w3.org/1999/xhtml">')
374  elseif s:settings.use_css && !s:settings.no_pre
375    call add(html, "<!DOCTYPE html>")
376    call add(html, '<html>')
377    let s:html5 = 1
378  else
379    call add(html, '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"')
380    call add(html, '  "http://www.w3.org/TR/html4/loose.dtd">')
381    call add(html, '<html>')
382  endif
383  call add(html, '<head>')
384
385  " include encoding as close to the top as possible, but only if not already
386  " contained in XML information
387  if s:settings.encoding != "" && !s:settings.use_xhtml
388    if s:html5
389      call add(html, '<meta charset="' . s:settings.encoding . '"' . tag_close)
390    else
391      call add(html, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" . s:settings.encoding . '"' . tag_close)
392    endif
393  endif
394
395  call add(html, '<title>diff</title>')
396  call add(html, '<meta name="Generator" content="Vim/'.v:version/100.'.'.v:version%100.'"'.tag_close)
397  call add(html, '<meta name="plugin-version" content="'.g:loaded_2html_plugin.'"'.tag_close)
398  call add(html, '<meta name="settings" content="'.
399	\ join(filter(keys(s:settings),'s:settings[v:val]'),',').
400	\ ',prevent_copy='.s:settings.prevent_copy.
401	\ ',use_input_for_pc='.s:settings.use_input_for_pc.
402	\ '"'.tag_close)
403  call add(html, '<meta name="colorscheme" content="'.
404	\ (exists('g:colors_name')
405	\ ? g:colors_name
406	\ : 'none'). '"'.tag_close)
407
408  call add(html, '</head>')
409  let body_line_num = len(html)
410  call add(html, '<body'.(s:settings.line_ids ? ' onload="JumpToLine();"' : '').'>')
411  call add(html, "<table ".(s:settings.use_css? "" : "border='1' width='100%' ")."id='vimCodeElement".s:settings.id_suffix."'>")
412
413  call add(html, '<tr>')
414  for buf in a:win_list
415    call add(html, '<th>'.bufname(buf).'</th>')
416  endfor
417  call add(html, '</tr><tr>')
418
419  let diff_style_start = 0
420  let insert_index = 0
421
422  for buf in a:buf_list
423    let temp = []
424    exe bufwinnr(buf) . 'wincmd w'
425
426    " If text is folded because of user foldmethod settings, etc. we don't want
427    " to act on everything in a fold by mistake.
428    setlocal nofoldenable
429
430    " When not using CSS or when using xhtml, the <body> line can be important.
431    " Assume it will be the same for all buffers and grab it from the first
432    " buffer. Similarly, need to grab the body end line as well.
433    if body_line == ''
434      1
435      call search('<body')
436      let body_line = getline('.')
437      $
438      call search('</body>', 'b')
439      let s:body_end_line = getline('.')
440    endif
441
442    " Grab the style information. Some of this will be duplicated so only insert
443    " it if it's not already there. {{{
444    1
445    let style_start = search('^<style\( type="text/css"\)\?>')
446    1
447    let style_end = search('^</style>')
448    if style_start > 0 && style_end > 0
449      let buf_styles = getline(style_start + 1, style_end - 1)
450      for a_style in buf_styles
451	if index(style, a_style) == -1
452	  if diff_style_start == 0
453	    if a_style =~ '\<Diff\(Change\|Text\|Add\|Delete\)'
454	      let diff_style_start = len(style)-1
455	    endif
456	  endif
457	  call insert(style, a_style, insert_index)
458	  let insert_index += 1
459	endif
460      endfor
461    endif " }}}
462
463    " everything new will get added before the diff styles so diff highlight
464    " properly overrides normal highlight
465    if diff_style_start != 0
466      let insert_index = diff_style_start
467    endif
468
469    " Delete those parts that are not needed so we can include the rest into the
470    " resulting table.
471    1,/^<body.*\%(\n<!--.*-->\_s\+.*id='oneCharWidth'.*\_s\+.*id='oneInputWidth'.*\_s\+.*id='oneEmWidth'\)\?\zs/d_
472    $
473    ?</body>?,$d_
474    let temp = getline(1,'$')
475    " clean out id on the main content container because we already set it on
476    " the table
477    let temp[0] = substitute(temp[0], " id='vimCodeElement[^']*'", "", "")
478    " undo deletion of start and end part
479    " so we can later save the file as valid html
480    " TODO: restore using grabbed lines if undolevel is 1?
481    normal! 2u
482    if s:settings.use_css
483      call add(html, '<td><div>')
484    elseif s:settings.use_xhtml
485      call add(html, '<td nowrap="nowrap" valign="top"><div>')
486    else
487      call add(html, '<td nowrap valign="top"><div>')
488    endif
489    let html += temp
490    call add(html, '</div></td>')
491
492    " Close this buffer
493    " TODO: the comment above says we're going to allow saving the file
494    " later...but here we discard it?
495    quit!
496  endfor
497
498  let html[body_line_num] = body_line
499
500  call add(html, '</tr>')
501  call add(html, '</table>')
502  call add(html, s:body_end_line)
503  call add(html, '</html>')
504
505  " The generated HTML is admittedly ugly and takes a LONG time to fold.
506  " Make sure the user doesn't do syntax folding when loading a generated file,
507  " using a modeline.
508  call add(html, '<!-- vim: set foldmethod=manual : -->')
509
510  let i = 1
511  let name = "Diff" . (s:settings.use_xhtml ? ".xhtml" : ".html")
512  " Find an unused file name if current file name is already in use
513  while filereadable(name)
514    let name = substitute(name, '\d*\.x\?html$', '', '') . i . '.' . fnamemodify(copy(name), ":t:e")
515    let i += 1
516  endwhile
517
518  let s:ei_sav = &eventignore
519  set eventignore+=FileType
520  exe "topleft new " . name
521  let &eventignore=s:ei_sav
522  unlet s:ei_sav
523
524  setlocal modifiable
525
526  " just in case some user autocmd creates content in the new buffer, make sure
527  " it is empty before proceeding
528  %d
529
530  " set the fileencoding to match the charset we'll be using
531  let &l:fileencoding=s:settings.vim_encoding
532
533  " According to http://www.w3.org/TR/html4/charset.html#doc-char-set, the byte
534  " order mark is highly recommend on the web when using multibyte encodings. But,
535  " it is not a good idea to include it on UTF-8 files. Otherwise, let Vim
536  " determine when it is actually inserted.
537  if s:settings.vim_encoding == 'utf-8'
538    setlocal nobomb
539  else
540    setlocal bomb
541  endif
542
543  call append(0, html)
544
545  if len(style) > 0
546    1
547    let style_start = search('^</head>')-1
548
549    " add required javascript in reverse order so we can just call append again
550    " and again without adjusting {{{
551
552    let s:uses_script = s:settings.dynamic_folds || s:settings.line_ids
553
554    " insert script closing tag if needed
555    if s:uses_script
556      call append(style_start, [
557	    \ '',
558	    \ s:settings.use_xhtml ? '//]]>' : '-->',
559	    \ "</script>"
560	    \ ])
561    endif
562
563    " insert javascript to get IDs from line numbers, and to open a fold before
564    " jumping to any lines contained therein
565    if s:settings.line_ids
566      call append(style_start, [
567	    \ "  /* Always jump to new location even if the line was hidden inside a fold, or",
568	    \ "   * we corrected the raw number to a line ID.",
569	    \ "   */",
570	    \ "  if (lineElem) {",
571	    \ "    lineElem.scrollIntoView(true);",
572	    \ "  }",
573	    \ "  return true;",
574	    \ "}",
575	    \ "if ('onhashchange' in window) {",
576	    \ "  window.onhashchange = JumpToLine;",
577	    \ "}"
578	    \ ])
579
580      if s:settings.dynamic_folds
581	call append(style_start, [
582	      \ "",
583	      \ "  /* navigate upwards in the DOM tree to open all folds containing the line */",
584	      \ "  var node = lineElem;",
585	      \ "  while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')",
586	      \ "  {",
587	      \ "    if (node.className == 'closed-fold')",
588	      \ "    {",
589	      \ "      /* toggle open the fold ID (remove window ID) */",
590	      \ "      toggleFold(node.id.substr(4));",
591	      \ "    }",
592	      \ "    node = node.parentNode;",
593	      \ "  }",
594	      \ ])
595      endif
596    endif
597
598    if s:settings.line_ids
599      call append(style_start, [
600	    \ "",
601	    \ "/* function to open any folds containing a jumped-to line before jumping to it */",
602	    \ "function JumpToLine()",
603	    \ "{",
604	    \ "  var lineNum;",
605	    \ "  lineNum = window.location.hash;",
606	    \ "  lineNum = lineNum.substr(1); /* strip off '#' */",
607	    \ "",
608	    \ "  if (lineNum.indexOf('L') == -1) {",
609	    \ "    lineNum = 'L'+lineNum;",
610	    \ "  }",
611	    \ "  if (lineNum.indexOf('W') == -1) {",
612	    \ "    lineNum = 'W1'+lineNum;",
613	    \ "  }",
614	    \ "  var lineElem = document.getElementById(lineNum);"
615	    \ ])
616    endif
617
618    " Insert javascript to toggle matching folds open and closed in all windows,
619    " if dynamic folding is active.
620    if s:settings.dynamic_folds
621      call append(style_start, [
622	    \  "  function toggleFold(objID)",
623	    \  "  {",
624	    \  "    for (win_num = 1; win_num <= ".len(a:buf_list)."; win_num++)",
625	    \  "    {",
626	    \  "      var fold;",
627	    \  '      fold = document.getElementById("win"+win_num+objID);',
628	    \  "      if(fold.className == 'closed-fold')",
629	    \  "      {",
630	    \  "        fold.className = 'open-fold';",
631	    \  "      }",
632	    \  "      else if (fold.className == 'open-fold')",
633	    \  "      {",
634	    \  "        fold.className = 'closed-fold';",
635	    \  "      }",
636	    \  "    }",
637	    \  "  }",
638	    \ ])
639    endif
640
641    if s:uses_script
642      " insert script tag if needed
643      call append(style_start, [
644	    \ "<script" . (s:html5 ? "" : " type='text/javascript'") . ">",
645	    \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])
646    endif
647
648    " Insert styles from all the generated html documents and additional styles
649    " for the table-based layout of the side-by-side diff. The diff should take
650    " up the full browser window (but not more), and be static in size,
651    " horizontally scrollable when the lines are too long. Otherwise, the diff
652    " is pretty useless for really long lines. {{{
653    if s:settings.use_css
654      call append(style_start,
655	    \ ['<style' . (s:html5 ? '' : 'type="text/css"') . '>']+
656	    \ style+
657	    \ [ s:settings.use_xhtml ? '' : '<!--',
658	    \   'table { table-layout: fixed; }',
659	    \   'html, body, table, tbody { width: 100%; margin: 0; padding: 0; }',
660	    \   'table, td, th { border: 1px solid; }',
661	    \   'td { vertical-align: top; }',
662	    \   'th, td { width: '.printf("%.1f",100.0/len(a:win_list)).'%; }',
663	    \   'td div { overflow: auto; }',
664	    \   s:settings.use_xhtml ? '' : '-->',
665	    \   '</style>'
666	    \])
667    endif "}}}
668  endif
669
670  let &paste = s:old_paste
671  let &magic = s:old_magic
672endfunc "}}}
673
674" Gets a single user option and sets it in the passed-in Dict, or gives it the
675" default value if the option doesn't actually exist.
676func! tohtml#GetOption(settings, option, default) "{{{
677  if exists('g:html_'.a:option)
678    let a:settings[a:option] = g:html_{a:option}
679  else
680    let a:settings[a:option] = a:default
681  endif
682endfunc "}}}
683
684" returns a Dict containing the values of all user options for 2html, including
685" default values for those not given an explicit value by the user. Discards the
686" html_ prefix of the option for nicer looking code.
687func! tohtml#GetUserSettings() "{{{
688  if exists('s:settings')
689    " just restore the known options if we've already retrieved them
690    return s:settings
691  else
692    " otherwise figure out which options are set
693    let user_settings = {}
694
695    " Define the correct option if the old option name exists and we haven't
696    " already defined the correct one. Maybe I'll put out a warning message about
697    " this sometime and remove the old option entirely at some even later time,
698    " but for now just silently accept the old option.
699    if exists('g:use_xhtml') && !exists("g:html_use_xhtml")
700      let g:html_use_xhtml = g:use_xhtml
701    endif
702
703    " get current option settings with appropriate defaults {{{
704    call tohtml#GetOption(user_settings,       'no_progress', !has("statusline") )
705    call tohtml#GetOption(user_settings,     'diff_one_file', 0 )
706    call tohtml#GetOption(user_settings,      'number_lines', &number )
707    call tohtml#GetOption(user_settings,          'pre_wrap', &wrap )
708    call tohtml#GetOption(user_settings,           'use_css', 1 )
709    call tohtml#GetOption(user_settings,    'ignore_conceal', 0 )
710    call tohtml#GetOption(user_settings,    'ignore_folding', 0 )
711    call tohtml#GetOption(user_settings,     'dynamic_folds', 0 )
712    call tohtml#GetOption(user_settings,     'no_foldcolumn', user_settings.ignore_folding)
713    call tohtml#GetOption(user_settings,      'hover_unfold', 0 )
714    call tohtml#GetOption(user_settings,            'no_pre', 0 )
715    call tohtml#GetOption(user_settings,        'no_invalid', 0 )
716    call tohtml#GetOption(user_settings,      'whole_filler', 0 )
717    call tohtml#GetOption(user_settings,         'use_xhtml', 0 )
718    call tohtml#GetOption(user_settings,          'line_ids', user_settings.number_lines )
719    call tohtml#GetOption(user_settings, 'use_input_for_pc', 'fallback')
720    " }}}
721
722    " override those settings that need it {{{
723
724    " hover opening implies dynamic folding
725    if user_settings.hover_unfold
726      let user_settings.dynamic_folds = 1
727    endif
728
729    " ignore folding overrides dynamic folding
730    if user_settings.ignore_folding && user_settings.dynamic_folds
731      let user_settings.dynamic_folds = 0
732      let user_settings.hover_unfold = 0
733    endif
734
735    " dynamic folding with no foldcolumn implies hover opens
736    if user_settings.dynamic_folds && user_settings.no_foldcolumn
737      let user_settings.hover_unfold = 1
738    endif
739
740    " dynamic folding implies css
741    if user_settings.dynamic_folds
742      let user_settings.use_css = 1
743    else
744      let user_settings.no_foldcolumn = 1 " won't do anything but for consistency and for the test suite
745    endif
746
747    " if we're not using CSS we cannot use a pre section because <font> tags
748    " aren't allowed inside a <pre> block
749    if !user_settings.use_css
750      let user_settings.no_pre = 1
751    endif
752
753    " pre_wrap doesn't do anything if not using pre or not using CSS
754    if user_settings.no_pre || !user_settings.use_css
755      let user_settings.pre_wrap=0
756    endif
757    "}}}
758
759    " set up expand_tabs option after all the overrides so we know the
760    " appropriate defaults {{{
761    if user_settings.no_pre == 0
762      call tohtml#GetOption(user_settings,
763	    \ 'expand_tabs',
764	    \ &expandtab || &ts != 8 || &vts != '' || user_settings.number_lines ||
765	    \   (user_settings.dynamic_folds && !user_settings.no_foldcolumn))
766    else
767      let user_settings.expand_tabs = 1
768    endif
769    " }}}
770
771    " textual options
772    if exists("g:html_use_encoding") "{{{
773      " user specified the desired MIME charset, figure out proper
774      " 'fileencoding' from it or warn the user if we cannot
775      let user_settings.encoding = g:html_use_encoding
776      let user_settings.vim_encoding = tohtml#EncodingFromCharset(g:html_use_encoding)
777      if user_settings.vim_encoding == ''
778	echohl WarningMsg
779	echomsg "TOhtml: file encoding for"
780	      \ g:html_use_encoding
781	      \ "unknown, please set 'fileencoding'"
782	echohl None
783      endif
784    else
785      " Figure out proper MIME charset from 'fileencoding' if possible
786      if &l:fileencoding != ''
787	" If the buffer is not a "normal" type, the 'fileencoding' value may not
788	" be trusted; since the buffer should not be written the fileencoding is
789	" not intended to be used.
790	if &l:buftype=='' || &l:buftype==?'help'
791	  let user_settings.vim_encoding = &l:fileencoding
792	  call tohtml#CharsetFromEncoding(user_settings)
793	else
794	  let user_settings.encoding = '' " trigger detection using &encoding
795	endif
796      endif
797
798      " else from 'encoding' if possible
799      if &l:fileencoding == '' || user_settings.encoding == ''
800	let user_settings.vim_encoding = &encoding
801	call tohtml#CharsetFromEncoding(user_settings)
802      endif
803
804      " else default to UTF-8 and warn user
805      if user_settings.encoding == ''
806	let user_settings.vim_encoding = 'utf-8'
807	let user_settings.encoding = 'UTF-8'
808	echohl WarningMsg
809	echomsg "TOhtml: couldn't determine MIME charset, using UTF-8"
810	echohl None
811      endif
812    endif "}}}
813
814    " Default to making nothing uncopyable, because we default to
815    " not-standards way of doing things, and also because Microsoft Word and
816    " others paste the <input> elements anyway.
817    "
818    " html_prevent_copy only has an effect when using CSS.
819    "
820    " All options:
821    "	  f - fold column
822    "	  n - line numbers (also within fold text)
823    "	  t - fold text
824    "	  d - diff filler
825    "	  c - concealed text (reserved future)
826    "	  l - listchars (reserved possible future)
827    "	  s - signs (reserved possible future)
828    "
829    " Normal text is always selectable.
830    let user_settings.prevent_copy = ""
831    if user_settings.use_css
832      if exists("g:html_prevent_copy")
833	if user_settings.dynamic_folds && !user_settings.no_foldcolumn && g:html_prevent_copy =~# 'f'
834	  let user_settings.prevent_copy .= 'f'
835	endif
836	if user_settings.number_lines && g:html_prevent_copy =~# 'n'
837	  let user_settings.prevent_copy .= 'n'
838	endif
839	if &diff && g:html_prevent_copy =~# 'd'
840	  let user_settings.prevent_copy .= 'd'
841	endif
842	if !user_settings.ignore_folding && g:html_prevent_copy =~# 't'
843	  let user_settings.prevent_copy .= 't'
844	endif
845      else
846	let user_settings.prevent_copy = ""
847      endif
848    endif
849    if empty(user_settings.prevent_copy)
850      let user_settings.no_invalid = 0
851    endif
852
853    " enforce valid values for use_input_for_pc
854    if user_settings.use_input_for_pc !~# 'fallback\|none\|all'
855      let user_settings.use_input_for_pc = 'fallback'
856      echohl WarningMsg
857      echomsg '2html: "' . g:html_use_input_for_pc . '" is not valid for g:html_use_input_for_pc'
858      echomsg '2html: defaulting to "' . user_settings.use_input_for_pc . '"'
859      echohl None
860      sleep 3
861    endif
862
863    if exists('g:html_id_expr')
864      let user_settings.id_suffix = eval(g:html_id_expr)
865      if user_settings.id_suffix !~ '^[-_:.A-Za-z0-9]*$'
866	echohl WarningMsg
867	echomsg '2html: g:html_id_expr evaluated to invalid string for HTML id attributes'
868	echomsg '2html: Omitting user-specified suffix'
869	echohl None
870	sleep 3
871	let user_settings.id_suffix=""
872      endif
873    else
874      let user_settings.id_suffix=""
875    endif
876
877    " TODO: font
878
879    return user_settings
880  endif
881endfunc "}}}
882
883" get the proper HTML charset name from a Vim encoding option.
884function! tohtml#CharsetFromEncoding(settings) "{{{
885  let l:vim_encoding = a:settings.vim_encoding
886  if exists('g:html_charset_override') && has_key(g:html_charset_override, l:vim_encoding)
887    let a:settings.encoding = g:html_charset_override[l:vim_encoding]
888  else
889    if l:vim_encoding =~ '^8bit\|^2byte'
890      " 8bit- and 2byte- prefixes are to indicate encodings available on the
891      " system that Vim will convert with iconv(), look up just the encoding name,
892      " not Vim's prefix.
893      let l:vim_encoding = substitute(l:vim_encoding, '^8bit-\|^2byte-', '', '')
894    endif
895    if has_key(g:tohtml#encoding_to_charset, l:vim_encoding)
896      let a:settings.encoding = g:tohtml#encoding_to_charset[l:vim_encoding]
897    else
898      let a:settings.encoding = ""
899    endif
900  endif
901  if a:settings.encoding != ""
902    let l:vim_encoding = tohtml#EncodingFromCharset(a:settings.encoding)
903    if l:vim_encoding != ""
904      " if the Vim encoding to HTML encoding conversion is set up (by default or
905      " by the user) to convert to a different encoding, we need to also change
906      " the Vim encoding of the new buffer
907      let a:settings.vim_encoding = l:vim_encoding
908    endif
909  endif
910endfun "}}}
911
912" Get the proper Vim encoding option setting from an HTML charset name.
913function! tohtml#EncodingFromCharset(encoding) "{{{
914  if exists('g:html_encoding_override') && has_key(g:html_encoding_override, a:encoding)
915    return g:html_encoding_override[a:encoding]
916  elseif has_key(g:tohtml#charset_to_encoding, tolower(a:encoding))
917    return g:tohtml#charset_to_encoding[tolower(a:encoding)]
918  else
919    return ""
920  endif
921endfun "}}}
922
923let &cpo = s:cpo_sav
924unlet s:cpo_sav
925
926" Make sure any patches will probably use consistent indent
927"   vim: ts=8 sw=2 sts=2 noet fdm=marker
928