1" Vim autoload file for the tohtml plugin. 2" Maintainer: Ben Fritz <[email protected]> 3" Last Change: 2018 Nov 11 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 if s:settings.use_xhtml 368 call add(html, xml_line) 369 endif 370 if s:settings.use_xhtml 371 call add(html, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">") 372 call add(html, '<html xmlns="http://www.w3.org/1999/xhtml">') 373 elseif s:settings.use_css && !s:settings.no_pre 374 call add(html, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">") 375 call add(html, '<html>') 376 else 377 call add(html, '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"') 378 call add(html, ' "http://www.w3.org/TR/html4/loose.dtd">') 379 call add(html, '<html>') 380 endif 381 call add(html, '<head>') 382 383 " include encoding as close to the top as possible, but only if not already 384 " contained in XML information 385 if s:settings.encoding != "" && !s:settings.use_xhtml 386 call add(html, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" . s:settings.encoding . '"' . tag_close) 387 endif 388 389 call add(html, '<title>diff</title>') 390 call add(html, '<meta name="Generator" content="Vim/'.v:version/100.'.'.v:version%100.'"'.tag_close) 391 call add(html, '<meta name="plugin-version" content="'.g:loaded_2html_plugin.'"'.tag_close) 392 call add(html, '<meta name="settings" content="'. 393 \ join(filter(keys(s:settings),'s:settings[v:val]'),','). 394 \ ',prevent_copy='.s:settings.prevent_copy. 395 \ '"'.tag_close) 396 call add(html, '<meta name="colorscheme" content="'. 397 \ (exists('g:colors_name') 398 \ ? g:colors_name 399 \ : 'none'). '"'.tag_close) 400 401 call add(html, '</head>') 402 let body_line_num = len(html) 403 if !empty(s:settings.prevent_copy) 404 call add(html, "<body onload='FixCharWidth();".(s:settings.line_ids ? " JumpToLine();" : "")."'>") 405 call add(html, "<!-- hidden divs used by javascript to get the width of a char -->") 406 call add(html, "<div id='oneCharWidth'>0</div>") 407 call add(html, "<div id='oneInputWidth'><input size='1' value='0'".tag_close."</div>") 408 call add(html, "<div id='oneEmWidth' style='width: 1em;'></div>") 409 else 410 call add(html, '<body'.(s:settings.line_ids ? ' onload="JumpToLine();"' : '').'>') 411 endif 412 call add(html, "<table border='1' width='100%' id='vimCodeElement".s:settings.id_suffix."'>") 413 414 call add(html, '<tr>') 415 for buf in a:win_list 416 call add(html, '<th>'.bufname(buf).'</th>') 417 endfor 418 call add(html, '</tr><tr>') 419 420 let diff_style_start = 0 421 let insert_index = 0 422 423 for buf in a:buf_list 424 let temp = [] 425 exe bufwinnr(buf) . 'wincmd w' 426 427 " If text is folded because of user foldmethod settings, etc. we don't want 428 " to act on everything in a fold by mistake. 429 setlocal nofoldenable 430 431 " When not using CSS or when using xhtml, the <body> line can be important. 432 " Assume it will be the same for all buffers and grab it from the first 433 " buffer. Similarly, need to grab the body end line as well. 434 if body_line == '' 435 1 436 call search('<body') 437 let body_line = getline('.') 438 $ 439 call search('</body>', 'b') 440 let s:body_end_line = getline('.') 441 endif 442 443 " Grab the style information. Some of this will be duplicated so only insert 444 " it if it's not already there. {{{ 445 1 446 let style_start = search('^<style type="text/css">') 447 1 448 let style_end = search('^</style>') 449 if style_start > 0 && style_end > 0 450 let buf_styles = getline(style_start + 1, style_end - 1) 451 for a_style in buf_styles 452 if index(style, a_style) == -1 453 if diff_style_start == 0 454 if a_style =~ '\<Diff\(Change\|Text\|Add\|Delete\)' 455 let diff_style_start = len(style)-1 456 endif 457 endif 458 call insert(style, a_style, insert_index) 459 let insert_index += 1 460 endif 461 endfor 462 endif " }}} 463 464 " everything new will get added before the diff styles so diff highlight 465 " properly overrides normal highlight 466 if diff_style_start != 0 467 let insert_index = diff_style_start 468 endif 469 470 " Delete those parts that are not needed so we can include the rest into the 471 " resulting table. 472 1,/^<body.*\%(\n<!--.*-->\_s\+.*id='oneCharWidth'.*\_s\+.*id='oneInputWidth'.*\_s\+.*id='oneEmWidth'\)\?\zs/d_ 473 $ 474 ?</body>?,$d_ 475 let temp = getline(1,'$') 476 " clean out id on the main content container because we already set it on 477 " the table 478 let temp[0] = substitute(temp[0], " id='vimCodeElement[^']*'", "", "") 479 " undo deletion of start and end part 480 " so we can later save the file as valid html 481 " TODO: restore using grabbed lines if undolevel is 1? 482 normal! 2u 483 if s:settings.use_css 484 call add(html, '<td valign="top"><div>') 485 elseif s:settings.use_xhtml 486 call add(html, '<td nowrap="nowrap" valign="top"><div>') 487 else 488 call add(html, '<td nowrap valign="top"><div>') 489 endif 490 let html += temp 491 call add(html, '</div></td>') 492 493 " Close this buffer 494 " TODO: the comment above says we're going to allow saving the file 495 " later...but here we discard it? 496 quit! 497 endfor 498 499 let html[body_line_num] = body_line 500 501 call add(html, '</tr>') 502 call add(html, '</table>') 503 call add(html, s:body_end_line) 504 call add(html, '</html>') 505 506 " The generated HTML is admittedly ugly and takes a LONG time to fold. 507 " Make sure the user doesn't do syntax folding when loading a generated file, 508 " using a modeline. 509 call add(html, '<!-- vim: set foldmethod=manual : -->') 510 511 let i = 1 512 let name = "Diff" . (s:settings.use_xhtml ? ".xhtml" : ".html") 513 " Find an unused file name if current file name is already in use 514 while filereadable(name) 515 let name = substitute(name, '\d*\.x\?html$', '', '') . i . '.' . fnamemodify(copy(name), ":t:e") 516 let i += 1 517 endwhile 518 exe "topleft new " . name 519 setlocal modifiable 520 521 " just in case some user autocmd creates content in the new buffer, make sure 522 " it is empty before proceeding 523 %d 524 525 " set the fileencoding to match the charset we'll be using 526 let &l:fileencoding=s:settings.vim_encoding 527 528 " According to http://www.w3.org/TR/html4/charset.html#doc-char-set, the byte 529 " order mark is highly recommend on the web when using multibyte encodings. But, 530 " it is not a good idea to include it on UTF-8 files. Otherwise, let Vim 531 " determine when it is actually inserted. 532 if s:settings.vim_encoding == 'utf-8' 533 setlocal nobomb 534 else 535 setlocal bomb 536 endif 537 538 call append(0, html) 539 540 if len(style) > 0 541 1 542 let style_start = search('^</head>')-1 543 544 " add required javascript in reverse order so we can just call append again 545 " and again without adjusting {{{ 546 547 let s:uses_script = s:settings.dynamic_folds || s:settings.line_ids || !empty(s:settings.prevent_copy) 548 549 " insert script closing tag if needed 550 if s:uses_script 551 call append(style_start, [ 552 \ '', 553 \ s:settings.use_xhtml ? '//]]>' : '-->', 554 \ "</script>" 555 \ ]) 556 endif 557 558 " insert script which corrects the size of small input elements in 559 " prevent_copy mode. See 2html.vim for details on why this is needed and how 560 " it works. 561 if !empty(s:settings.prevent_copy) 562 call append(style_start, [ 563 \ '', 564 \ '/* simulate a "ch" unit by asking the browser how big a zero character is */', 565 \ 'function FixCharWidth() {', 566 \ ' /* get the hidden element which gives the width of a single character */', 567 \ ' var goodWidth = document.getElementById("oneCharWidth").clientWidth;', 568 \ ' /* get all input elements, we''ll filter on class later */', 569 \ ' var inputTags = document.getElementsByTagName("input");', 570 \ ' var ratio = 5;', 571 \ ' var inputWidth = document.getElementById("oneInputWidth").clientWidth;', 572 \ ' var emWidth = document.getElementById("oneEmWidth").clientWidth;', 573 \ ' if (inputWidth > goodWidth) {', 574 \ ' while (ratio < 100*goodWidth/emWidth && ratio < 100) {', 575 \ ' ratio += 5;', 576 \ ' }', 577 \ ' document.getElementById("vimCodeElement'.s:settings.id_suffix.'").className = "em"+ratio;', 578 \ ' }', 579 \ '}' 580 \ ]) 581 endif 582 583 " insert javascript to get IDs from line numbers, and to open a fold before 584 " jumping to any lines contained therein 585 if s:settings.line_ids 586 call append(style_start, [ 587 \ " /* Always jump to new location even if the line was hidden inside a fold, or", 588 \ " * we corrected the raw number to a line ID.", 589 \ " */", 590 \ " if (lineElem) {", 591 \ " lineElem.scrollIntoView(true);", 592 \ " }", 593 \ " return true;", 594 \ "}", 595 \ "if ('onhashchange' in window) {", 596 \ " window.onhashchange = JumpToLine;", 597 \ "}" 598 \ ]) 599 600 if s:settings.dynamic_folds 601 call append(style_start, [ 602 \ "", 603 \ " /* navigate upwards in the DOM tree to open all folds containing the line */", 604 \ " var node = lineElem;", 605 \ " while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')", 606 \ " {", 607 \ " if (node.className == 'closed-fold')", 608 \ " {", 609 \ " /* toggle open the fold ID (remove window ID) */", 610 \ " toggleFold(node.id.substr(4));", 611 \ " }", 612 \ " node = node.parentNode;", 613 \ " }", 614 \ ]) 615 endif 616 endif 617 618 if s:settings.line_ids 619 call append(style_start, [ 620 \ "", 621 \ "/* function to open any folds containing a jumped-to line before jumping to it */", 622 \ "function JumpToLine()", 623 \ "{", 624 \ " var lineNum;", 625 \ " lineNum = window.location.hash;", 626 \ " lineNum = lineNum.substr(1); /* strip off '#' */", 627 \ "", 628 \ " if (lineNum.indexOf('L') == -1) {", 629 \ " lineNum = 'L'+lineNum;", 630 \ " }", 631 \ " if (lineNum.indexOf('W') == -1) {", 632 \ " lineNum = 'W1'+lineNum;", 633 \ " }", 634 \ " var lineElem = document.getElementById(lineNum);" 635 \ ]) 636 endif 637 638 " Insert javascript to toggle matching folds open and closed in all windows, 639 " if dynamic folding is active. 640 if s:settings.dynamic_folds 641 call append(style_start, [ 642 \ " function toggleFold(objID)", 643 \ " {", 644 \ " for (win_num = 1; win_num <= ".len(a:buf_list)."; win_num++)", 645 \ " {", 646 \ " var fold;", 647 \ ' fold = document.getElementById("win"+win_num+objID);', 648 \ " if(fold.className == 'closed-fold')", 649 \ " {", 650 \ " fold.className = 'open-fold';", 651 \ " }", 652 \ " else if (fold.className == 'open-fold')", 653 \ " {", 654 \ " fold.className = 'closed-fold';", 655 \ " }", 656 \ " }", 657 \ " }", 658 \ ]) 659 endif 660 661 if s:uses_script 662 " insert script tag; javascript is always needed for the line number 663 " normalization for URL hashes 664 call append(style_start, [ 665 \ "<script type='text/javascript'>", 666 \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"]) 667 endif 668 669 " Insert styles from all the generated html documents and additional styles 670 " for the table-based layout of the side-by-side diff. The diff should take 671 " up the full browser window (but not more), and be static in size, 672 " horizontally scrollable when the lines are too long. Otherwise, the diff 673 " is pretty useless for really long lines. {{{ 674 if s:settings.use_css 675 call append(style_start, 676 \ ['<style type="text/css">']+ 677 \ style+ 678 \ [ s:settings.use_xhtml ? '' : '<!--', 679 \ 'table { table-layout: fixed; }', 680 \ 'html, body, table, tbody { width: 100%; margin: 0; padding: 0; }', 681 \ 'th, td { width: '.printf("%.1f",100.0/len(a:win_list)).'%; }', 682 \ 'td div { overflow: auto; }', 683 \ s:settings.use_xhtml ? '' : '-->', 684 \ '</style>' 685 \]) 686 endif "}}} 687 endif 688 689 let &paste = s:old_paste 690 let &magic = s:old_magic 691endfunc "}}} 692 693" Gets a single user option and sets it in the passed-in Dict, or gives it the 694" default value if the option doesn't actually exist. 695func! tohtml#GetOption(settings, option, default) "{{{ 696 if exists('g:html_'.a:option) 697 let a:settings[a:option] = g:html_{a:option} 698 else 699 let a:settings[a:option] = a:default 700 endif 701endfunc "}}} 702 703" returns a Dict containing the values of all user options for 2html, including 704" default values for those not given an explicit value by the user. Discards the 705" html_ prefix of the option for nicer looking code. 706func! tohtml#GetUserSettings() "{{{ 707 if exists('s:settings') 708 " just restore the known options if we've already retrieved them 709 return s:settings 710 else 711 " otherwise figure out which options are set 712 let user_settings = {} 713 714 " Define the correct option if the old option name exists and we haven't 715 " already defined the correct one. Maybe I'll put out a warnig message about 716 " this sometime and remove the old option entirely at some even later time, 717 " but for now just silently accept the old option. 718 if exists('g:use_xhtml') && !exists("g:html_use_xhtml") 719 let g:html_use_xhtml = g:use_xhtml 720 endif 721 722 " get current option settings with appropriate defaults {{{ 723 call tohtml#GetOption(user_settings, 'no_progress', !has("statusline") ) 724 call tohtml#GetOption(user_settings, 'diff_one_file', 0 ) 725 call tohtml#GetOption(user_settings, 'number_lines', &number ) 726 call tohtml#GetOption(user_settings, 'pre_wrap', &wrap ) 727 call tohtml#GetOption(user_settings, 'use_css', 1 ) 728 call tohtml#GetOption(user_settings, 'ignore_conceal', 0 ) 729 call tohtml#GetOption(user_settings, 'ignore_folding', 0 ) 730 call tohtml#GetOption(user_settings, 'dynamic_folds', 0 ) 731 call tohtml#GetOption(user_settings, 'no_foldcolumn', user_settings.ignore_folding) 732 call tohtml#GetOption(user_settings, 'hover_unfold', 0 ) 733 call tohtml#GetOption(user_settings, 'no_pre', 0 ) 734 call tohtml#GetOption(user_settings, 'no_invalid', 0 ) 735 call tohtml#GetOption(user_settings, 'whole_filler', 0 ) 736 call tohtml#GetOption(user_settings, 'use_xhtml', 0 ) 737 call tohtml#GetOption(user_settings, 'line_ids', user_settings.number_lines ) 738 " }}} 739 740 " override those settings that need it {{{ 741 742 " hover opening implies dynamic folding 743 if user_settings.hover_unfold 744 let user_settings.dynamic_folds = 1 745 endif 746 747 " ignore folding overrides dynamic folding 748 if user_settings.ignore_folding && user_settings.dynamic_folds 749 let user_settings.dynamic_folds = 0 750 let user_settings.hover_unfold = 0 751 endif 752 753 " dynamic folding with no foldcolumn implies hover opens 754 if user_settings.dynamic_folds && user_settings.no_foldcolumn 755 let user_settings.hover_unfold = 1 756 endif 757 758 " dynamic folding implies css 759 if user_settings.dynamic_folds 760 let user_settings.use_css = 1 761 else 762 let user_settings.no_foldcolumn = 1 " won't do anything but for consistency and for the test suite 763 endif 764 765 " if we're not using CSS we cannot use a pre section because <font> tags 766 " aren't allowed inside a <pre> block 767 if !user_settings.use_css 768 let user_settings.no_pre = 1 769 endif 770 771 " pre_wrap doesn't do anything if not using pre or not using CSS 772 if user_settings.no_pre || !user_settings.use_css 773 let user_settings.pre_wrap=0 774 endif 775 "}}} 776 777 " set up expand_tabs option after all the overrides so we know the 778 " appropriate defaults {{{ 779 if user_settings.no_pre == 0 780 call tohtml#GetOption(user_settings, 781 \ 'expand_tabs', 782 \ &expandtab || &ts != 8 || &vts != '' || user_settings.number_lines || 783 \ (user_settings.dynamic_folds && !user_settings.no_foldcolumn)) 784 else 785 let user_settings.expand_tabs = 1 786 endif 787 " }}} 788 789 " textual options 790 if exists("g:html_use_encoding") "{{{ 791 " user specified the desired MIME charset, figure out proper 792 " 'fileencoding' from it or warn the user if we cannot 793 let user_settings.encoding = g:html_use_encoding 794 let user_settings.vim_encoding = tohtml#EncodingFromCharset(g:html_use_encoding) 795 if user_settings.vim_encoding == '' 796 echohl WarningMsg 797 echomsg "TOhtml: file encoding for" 798 \ g:html_use_encoding 799 \ "unknown, please set 'fileencoding'" 800 echohl None 801 endif 802 else 803 " Figure out proper MIME charset from 'fileencoding' if possible 804 if &l:fileencoding != '' 805 " If the buffer is not a "normal" type, the 'fileencoding' value may not 806 " be trusted; since the buffer should not be written the fileencoding is 807 " not intended to be used. 808 if &l:buftype=='' || &l:buftype==?'help' 809 let user_settings.vim_encoding = &l:fileencoding 810 call tohtml#CharsetFromEncoding(user_settings) 811 else 812 let user_settings.encoding = '' " trigger detection using &encoding 813 endif 814 endif 815 816 " else from 'encoding' if possible 817 if &l:fileencoding == '' || user_settings.encoding == '' 818 let user_settings.vim_encoding = &encoding 819 call tohtml#CharsetFromEncoding(user_settings) 820 endif 821 822 " else default to UTF-8 and warn user 823 if user_settings.encoding == '' 824 let user_settings.vim_encoding = 'utf-8' 825 let user_settings.encoding = 'UTF-8' 826 echohl WarningMsg 827 echomsg "TOhtml: couldn't determine MIME charset, using UTF-8" 828 echohl None 829 endif 830 endif "}}} 831 832 " Default to making nothing uncopyable, because we default to 833 " not-standards way of doing things, and also because Microsoft Word and 834 " others paste the <input> elements anyway. 835 " 836 " html_prevent_copy only has an effect when using CSS. 837 " 838 " All options: 839 " f - fold column 840 " n - line numbers (also within fold text) 841 " t - fold text 842 " d - diff filler 843 " c - concealed text (reserved future) 844 " l - listchars (reserved possible future) 845 " s - signs (reserved possible future) 846 " 847 " Normal text is always selectable. 848 let user_settings.prevent_copy = "" 849 if user_settings.use_css 850 if exists("g:html_prevent_copy") 851 if user_settings.dynamic_folds && !user_settings.no_foldcolumn && g:html_prevent_copy =~# 'f' 852 let user_settings.prevent_copy .= 'f' 853 endif 854 if user_settings.number_lines && g:html_prevent_copy =~# 'n' 855 let user_settings.prevent_copy .= 'n' 856 endif 857 if &diff && g:html_prevent_copy =~# 'd' 858 let user_settings.prevent_copy .= 'd' 859 endif 860 if !user_settings.ignore_folding && g:html_prevent_copy =~# 't' 861 let user_settings.prevent_copy .= 't' 862 endif 863 else 864 let user_settings.prevent_copy = "" 865 endif 866 endif 867 if empty(user_settings.prevent_copy) 868 let user_settings.no_invalid = 0 869 endif 870 871 if exists('g:html_id_expr') 872 let user_settings.id_suffix = eval(g:html_id_expr) 873 if user_settings.id_suffix !~ '^[-_:.A-Za-z0-9]*$' 874 echohl WarningMsg 875 echomsg '2html: g:html_id_expr evaluated to invalid string for HTML id attributes' 876 echomsg '2html: Omitting user-specified suffix' 877 echohl None 878 sleep 3 879 let user_settings.id_suffix="" 880 endif 881 else 882 let user_settings.id_suffix="" 883 endif 884 885 " TODO: font 886 887 return user_settings 888 endif 889endfunc "}}} 890 891" get the proper HTML charset name from a Vim encoding option. 892function! tohtml#CharsetFromEncoding(settings) "{{{ 893 let l:vim_encoding = a:settings.vim_encoding 894 if exists('g:html_charset_override') && has_key(g:html_charset_override, l:vim_encoding) 895 let a:settings.encoding = g:html_charset_override[l:vim_encoding] 896 else 897 if l:vim_encoding =~ '^8bit\|^2byte' 898 " 8bit- and 2byte- prefixes are to indicate encodings available on the 899 " system that Vim will convert with iconv(), look up just the encoding name, 900 " not Vim's prefix. 901 let l:vim_encoding = substitute(l:vim_encoding, '^8bit-\|^2byte-', '', '') 902 endif 903 if has_key(g:tohtml#encoding_to_charset, l:vim_encoding) 904 let a:settings.encoding = g:tohtml#encoding_to_charset[l:vim_encoding] 905 else 906 let a:settings.encoding = "" 907 endif 908 endif 909 if a:settings.encoding != "" 910 let l:vim_encoding = tohtml#EncodingFromCharset(a:settings.encoding) 911 if l:vim_encoding != "" 912 " if the Vim encoding to HTML encoding conversion is set up (by default or 913 " by the user) to convert to a different encoding, we need to also change 914 " the Vim encoding of the new buffer 915 let a:settings.vim_encoding = l:vim_encoding 916 endif 917 endif 918endfun "}}} 919 920" Get the proper Vim encoding option setting from an HTML charset name. 921function! tohtml#EncodingFromCharset(encoding) "{{{ 922 if exists('g:html_encoding_override') && has_key(g:html_encoding_override, a:encoding) 923 return g:html_encoding_override[a:encoding] 924 elseif has_key(g:tohtml#charset_to_encoding, tolower(a:encoding)) 925 return g:tohtml#charset_to_encoding[tolower(a:encoding)] 926 else 927 return "" 928 endif 929endfun "}}} 930 931let &cpo = s:cpo_sav 932unlet s:cpo_sav 933 934" Make sure any patches will probably use consistent indent 935" vim: ts=8 sw=2 sts=2 noet fdm=marker 936