diff options
-rw-r--r-- | runtime/autoload/tohtml.vim | 71 | ||||
-rw-r--r-- | runtime/doc/syntax.txt | 2 | ||||
-rw-r--r-- | runtime/plugin/tohtml.vim | 27 | ||||
-rw-r--r-- | runtime/syntax/2html.vim | 663 |
4 files changed, 428 insertions, 335 deletions
diff --git a/runtime/autoload/tohtml.vim b/runtime/autoload/tohtml.vim index 1086347473..d2722a4021 100644 --- a/runtime/autoload/tohtml.vim +++ b/runtime/autoload/tohtml.vim @@ -1,6 +1,6 @@ " Vim autoload file for the tohtml plugin. " Maintainer: Ben Fritz <fritzophrenic@gmail.com> -" Last Change: 2023 Jan 01 +" Last Change: 2023 Sep 03 " " Additional contributors: " @@ -307,7 +307,7 @@ func! tohtml#Convert2HTML(line1, line2) "{{{ let g:html_diff_win_num = 0 for window in win_list " switch to the next buffer to convert - exe ":" . bufwinnr(window) . "wincmd w" + exe ":" .. bufwinnr(window) .. "wincmd w" " figure out whether current charset and encoding will work, if not " default to UTF-8 @@ -355,7 +355,7 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ if !s:settings.no_doc if s:settings.use_xhtml if s:settings.encoding != "" - let xml_line = "<?xml version=\"1.0\" encoding=\"" . s:settings.encoding . "\"?>" + let xml_line = "<?xml version=\"1.0\" encoding=\"" .. s:settings.encoding .. "\"?>" else let xml_line = "<?xml version=\"1.0\"?>" endif @@ -387,34 +387,34 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ " contained in XML information if s:settings.encoding != "" && !s:settings.use_xhtml if s:html5 - call add(html, '<meta charset="' . s:settings.encoding . '"' . tag_close) + call add(html, '<meta charset="' .. s:settings.encoding .. '"' .. tag_close) else - call add(html, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" . s:settings.encoding . '"' . tag_close) + call add(html, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" .. s:settings.encoding .. '"' .. tag_close) endif endif call add(html, '<title>diff</title>') - call add(html, '<meta name="Generator" content="Vim/'.v:version/100.'.'.v:version%100.'"'.tag_close) - call add(html, '<meta name="plugin-version" content="'.g:loaded_2html_plugin.'"'.tag_close) + call add(html, '<meta name="Generator" content="Vim/'..v:version/100..'.'..v:version%100..'"'..tag_close) + call add(html, '<meta name="plugin-version" content="'..g:loaded_2html_plugin..'"'..tag_close) call add(html, '<meta name="settings" content="'. \ join(filter(keys(s:settings),'s:settings[v:val]'),','). - \ ',prevent_copy='.s:settings.prevent_copy. - \ ',use_input_for_pc='.s:settings.use_input_for_pc. - \ '"'.tag_close) + \ ',prevent_copy='..s:settings.prevent_copy. + \ ',use_input_for_pc='..s:settings.use_input_for_pc. + \ '"'..tag_close) call add(html, '<meta name="colorscheme" content="'. \ (exists('g:colors_name') \ ? g:colors_name - \ : 'none'). '"'.tag_close) + \ : 'none').. '"'..tag_close) call add(html, '</head>') let body_line_num = len(html) - call add(html, '<body'.(s:settings.line_ids ? ' onload="JumpToLine();"' : '').'>') + call add(html, '<body'..(s:settings.line_ids ? ' onload="JumpToLine();"' : '')..'>') endif - call add(html, "<table ".(s:settings.use_css? "" : "border='1' width='100%' ")."id='vimCodeElement".s:settings.id_suffix."'>") + call add(html, "<table "..(s:settings.use_css? "" : "border='1' width='100%' ").."id='vimCodeElement"..s:settings.id_suffix.."'>") call add(html, '<tr>') for buf in a:win_list - call add(html, '<th>'.bufname(buf).'</th>') + call add(html, '<th>'..bufname(buf)..'</th>') endfor call add(html, '</tr><tr>') @@ -423,7 +423,7 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ for buf in a:buf_list let temp = [] - exe bufwinnr(buf) . 'wincmd w' + exe bufwinnr(buf) .. 'wincmd w' " If text is folded because of user foldmethod settings, etc. we don't want " to act on everything in a fold by mistake. @@ -526,16 +526,16 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ endif let i = 1 - let name = "Diff" . (s:settings.use_xhtml ? ".xhtml" : ".html") + let name = "Diff" .. (s:settings.use_xhtml ? ".xhtml" : ".html") " Find an unused file name if current file name is already in use while filereadable(name) - let name = substitute(name, '\d*\.x\?html$', '', '') . i . '.' . fnamemodify(copy(name), ":t:e") + let name = substitute(name, '\d*\.x\?html$', '', '') .. i .. '.' .. fnamemodify(copy(name), ":t:e") let i += 1 endwhile let s:ei_sav = &eventignore set eventignore+=FileType - exe "topleft new " . name + exe "topleft new " .. name let &eventignore=s:ei_sav unlet s:ei_sav @@ -601,7 +601,7 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ \ "", \ " /* navigate upwards in the DOM tree to open all folds containing the line */", \ " var node = lineElem;", - \ " while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')", + \ " while (node && node.id != 'vimCodeElement"..s:settings.id_suffix.."')", \ " {", \ " if (node.className == 'closed-fold')", \ " {", @@ -640,7 +640,7 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ call append(style_start, [ \ " function toggleFold(objID)", \ " {", - \ " for (win_num = 1; win_num <= ".len(a:buf_list)."; win_num++)", + \ " for (win_num = 1; win_num <= "..len(a:buf_list).."; win_num++)", \ " {", \ " var fold;", \ ' fold = document.getElementById("win"+win_num+objID);', @@ -660,7 +660,7 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ if s:uses_script " insert script tag if needed call append(style_start, [ - \ "<script" . (s:html5 ? "" : " type='text/javascript'") . ">", + \ "<script" .. (s:html5 ? "" : " type='text/javascript'") .. ">", \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"]) endif @@ -671,14 +671,14 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{ " is pretty useless for really long lines. {{{ if s:settings.use_css call append(style_start, - \ ['<style' . (s:html5 ? '' : 'type="text/css"') . '>']+ + \ ['<style' .. (s:html5 ? '' : 'type="text/css"') .. '>']+ \ style+ \ [ s:settings.use_xhtml ? '' : '<!--', \ 'table { table-layout: fixed; }', \ 'html, body, table, tbody { width: 100%; margin: 0; padding: 0; }', \ 'table, td, th { border: 1px solid; }', \ 'td { vertical-align: top; }', - \ 'th, td { width: '.printf("%.1f",100.0/len(a:win_list)).'%; }', + \ 'th, td { width: '..printf("%.1f",100.0/len(a:win_list))..'%; }', \ 'td div { overflow: auto; }', \ s:settings.use_xhtml ? '' : '-->', \ '</style>' @@ -694,7 +694,7 @@ endfunc "}}} " Gets a single user option and sets it in the passed-in Dict, or gives it the " default value if the option doesn't actually exist. func! tohtml#GetOption(settings, option, default) "{{{ - if exists('g:html_'.a:option) + if exists('g:html_'..a:option) let a:settings[a:option] = g:html_{a:option} else let a:settings[a:option] = a:default @@ -713,10 +713,11 @@ func! tohtml#GetUserSettings() "{{{ let user_settings = {} " Define the correct option if the old option name exists and we haven't - " already defined the correct one. Maybe I'll put out a warning message about - " this sometime and remove the old option entirely at some even later time, - " but for now just silently accept the old option. + " already defined the correct one. if exists('g:use_xhtml') && !exists("g:html_use_xhtml") + echohl WarningMsg + echomsg "Warning: g:use_xhtml is deprecated, use g:html_use_xhtml" + echohl None let g:html_use_xhtml = g:use_xhtml endif @@ -739,7 +740,7 @@ func! tohtml#GetUserSettings() "{{{ call tohtml#GetOption(user_settings, 'whole_filler', 0 ) call tohtml#GetOption(user_settings, 'use_xhtml', 0 ) call tohtml#GetOption(user_settings, 'line_ids', user_settings.number_lines ) - call tohtml#GetOption(user_settings, 'use_input_for_pc', 'fallback') + call tohtml#GetOption(user_settings, 'use_input_for_pc', 'none') " }}} " override those settings that need it {{{ @@ -854,16 +855,16 @@ func! tohtml#GetUserSettings() "{{{ if user_settings.use_css if exists("g:html_prevent_copy") if user_settings.dynamic_folds && !user_settings.no_foldcolumn && g:html_prevent_copy =~# 'f' - let user_settings.prevent_copy .= 'f' + let user_settings.prevent_copy ..= 'f' endif if user_settings.number_lines && g:html_prevent_copy =~# 'n' - let user_settings.prevent_copy .= 'n' + let user_settings.prevent_copy ..= 'n' endif if &diff && g:html_prevent_copy =~# 'd' - let user_settings.prevent_copy .= 'd' + let user_settings.prevent_copy ..= 'd' endif if !user_settings.ignore_folding && g:html_prevent_copy =~# 't' - let user_settings.prevent_copy .= 't' + let user_settings.prevent_copy ..= 't' endif else let user_settings.prevent_copy = "" @@ -875,10 +876,10 @@ func! tohtml#GetUserSettings() "{{{ " enforce valid values for use_input_for_pc if user_settings.use_input_for_pc !~# 'fallback\|none\|all' - let user_settings.use_input_for_pc = 'fallback' + let user_settings.use_input_for_pc = 'none' echohl WarningMsg - echomsg '2html: "' . g:html_use_input_for_pc . '" is not valid for g:html_use_input_for_pc' - echomsg '2html: defaulting to "' . user_settings.use_input_for_pc . '"' + echomsg '2html: "' .. g:html_use_input_for_pc .. '" is not valid for g:html_use_input_for_pc' + echomsg '2html: defaulting to "' .. user_settings.use_input_for_pc .. '"' echohl None sleep 3 endif diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 29a12396d4..6a20734a60 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -596,7 +596,7 @@ The method used to prevent copying in the generated page depends on the value of |g:html_use_input_for_pc|. *g:html_use_input_for_pc* -Default: "fallback" +Default: "none" If |g:html_prevent_copy| is non-empty, then: When "all", read-only <input> elements are used in place of normal text for diff --git a/runtime/plugin/tohtml.vim b/runtime/plugin/tohtml.vim index 0369313f08..56eb2c15bf 100644 --- a/runtime/plugin/tohtml.vim +++ b/runtime/plugin/tohtml.vim @@ -1,6 +1,6 @@ " Vim plugin for converting a syntax highlighted file to HTML. " Maintainer: Ben Fritz <fritzophrenic@gmail.com> -" Last Change: 2023 Jan 01 +" Last Change: 2023 Sep 07 " " The core of the code is in $VIMRUNTIME/autoload/tohtml.vim and " $VIMRUNTIME/syntax/2html.vim @@ -8,11 +8,29 @@ if exists('g:loaded_2html_plugin') finish endif -let g:loaded_2html_plugin = 'vim9.0_v1' +let g:loaded_2html_plugin = 'vim9.0_v2' " " Changelog: {{{ -" 9.0_v1 (this version): - Implement g:html_no_doc and g:html_no_modeline +" 9.0_v2 (this version): - Warn if using deprecated g:use_xhtml option +" - Change default g:html_use_input_for_pc to "none" +" instead of "fallback". All modern browsers support +" the "user-select: none" and "content:" CSS +" properties so the older method relying on extra +" markup and unspecified browser/app clipboard +" handling is only needed in rare special cases. +" - Fix SourceForge issue #33: generate diff filler +" correctly when new lines have been added to or +" removed from end of buffer. +" - Fix SourceForge issue #32/Vim Github issue #8547: +" use translated highlight ID for styling the +" special-use group names (e.g. LineNr) used +" directly by name in the 2html processing. +" - Fix SourceForge issue #26, refactoring to use +" :let-heredoc style string assignment and +" additional fixes for ".." vs. "." style string +" concatenation. Requires Vim v8.1.1354 or higher. +" 9.0_v1 (Vim 9.0.1275): - Implement g:html_no_doc and g:html_no_modeline " for diff mode. Add tests. " (Vim 9.0.1122): NOTE: no version string update for this version! " - Bugfix for variable name in g:html_no_doc @@ -21,7 +39,8 @@ let g:loaded_2html_plugin = 'vim9.0_v1' " and g:html_no_modeline (partially included in Vim " runtime prior to version string update). " - Updates for new Vim9 string append style (i.e. use -" ".." instead of ".") +" ".." instead of "."). Requires Vim version +" 8.1.1114 or higher. " " 8.1 updates: {{{ " 8.1_v2 (Vim 8.1.2312): - Fix SourceForge issue #19: fix calculation of tab diff --git a/runtime/syntax/2html.vim b/runtime/syntax/2html.vim index 69780cffef..f3ce8bed8d 100644 --- a/runtime/syntax/2html.vim +++ b/runtime/syntax/2html.vim @@ -1,6 +1,6 @@ " Vim syntax support file " Maintainer: Ben Fritz <fritzophrenic@gmail.com> -" Last Change: 2023 Jan 01 +" Last Change: 2023 Sep 05 " " Additional contributors: " @@ -32,9 +32,9 @@ let s:end=line('$') " Font if exists("g:html_font") if type(g:html_font) == type([]) - let s:htmlfont = "'". join(g:html_font,"','") . "', monospace" + let s:htmlfont = "'".. join(g:html_font,"','") .. "', monospace" else - let s:htmlfont = "'". g:html_font . "', monospace" + let s:htmlfont = "'".. g:html_font .. "', monospace" endif else let s:htmlfont = "monospace" @@ -221,8 +221,8 @@ else endif " Find out the background and foreground color for use later -let s:fgc = s:HtmlColor(synIDattr(hlID("Normal"), "fg#", s:whatterm)) -let s:bgc = s:HtmlColor(synIDattr(hlID("Normal"), "bg#", s:whatterm)) +let s:fgc = s:HtmlColor(synIDattr(hlID("Normal")->synIDtrans(), "fg#", s:whatterm)) +let s:bgc = s:HtmlColor(synIDattr(hlID("Normal")->synIDtrans(), "bg#", s:whatterm)) if s:fgc == "" let s:fgc = ( &background == "dark" ? "#ffffff" : "#000000" ) endif @@ -234,41 +234,43 @@ if !s:settings.use_css " Return opening HTML tag for given highlight id function! s:HtmlOpening(id, extra_attrs) let a = "" - if synIDattr(a:id, "inverse") + let translated_ID = synIDtrans(a:id) + if synIDattr(translated_ID, "inverse") " For inverse, we always must set both colors (and exchange them) - let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) - let a = a . '<span '.a:extra_attrs.'style="background-color: ' . ( x != "" ? x : s:fgc ) . '">' - let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) - let a = a . '<font color="' . ( x != "" ? x : s:bgc ) . '">' + let x = s:HtmlColor(synIDattr(translated_ID, "fg#", s:whatterm)) + let a = a .. '<span '..a:extra_attrs..'style="background-color: ' .. ( x != "" ? x : s:fgc ) .. '">' + let x = s:HtmlColor(synIDattr(translated_ID, "bg#", s:whatterm)) + let a = a .. '<font color="' .. ( x != "" ? x : s:bgc ) .. '">' else - let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) + let x = s:HtmlColor(synIDattr(translated_ID, "bg#", s:whatterm)) if x != "" - let a = a . '<span '.a:extra_attrs.'style="background-color: ' . x . '">' + let a = a .. '<span '..a:extra_attrs..'style="background-color: ' .. x .. '">' elseif !empty(a:extra_attrs) - let a = a . '<span '.a:extra_attrs.'>' + let a = a .. '<span '..a:extra_attrs..'>' endif - let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) - if x != "" | let a = a . '<font color="' . x . '">' | endif + let x = s:HtmlColor(synIDattr(translated_ID, "fg#", s:whatterm)) + if x != "" | let a = a .. '<font color="' .. x .. '">' | endif endif - if synIDattr(a:id, "bold") | let a = a . "<b>" | endif - if synIDattr(a:id, "italic") | let a = a . "<i>" | endif - if synIDattr(a:id, "underline") | let a = a . "<u>" | endif + if synIDattr(translated_ID, "bold") | let a = a .. "<b>" | endif + if synIDattr(translated_ID, "italic") | let a = a .. "<i>" | endif + if synIDattr(translated_ID, "underline") | let a = a .. "<u>" | endif return a endfun " Return closing HTML tag for given highlight id function! s:HtmlClosing(id, has_extra_attrs) let a = "" - if synIDattr(a:id, "underline") | let a = a . "</u>" | endif - if synIDattr(a:id, "italic") | let a = a . "</i>" | endif - if synIDattr(a:id, "bold") | let a = a . "</b>" | endif - if synIDattr(a:id, "inverse") - let a = a . '</font></span>' + let translated_ID = synIDtrans(a:id) + if synIDattr(translated_ID, "underline") | let a = a .. "</u>" | endif + if synIDattr(translated_ID, "italic") | let a = a .. "</i>" | endif + if synIDattr(translated_ID, "bold") | let a = a .. "</b>" | endif + if synIDattr(translated_ID, "inverse") + let a = a .. '</font></span>' else - let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) - if x != "" | let a = a . '</font>' | endif - let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) - if x != "" || a:has_extra_attrs | let a = a . '</span>' | endif + let x = s:HtmlColor(synIDattr(translated_ID, "fg#", s:whatterm)) + if x != "" | let a = a .. '</font>' | endif + let x = s:HtmlColor(synIDattr(translated_ID, "bg#", s:whatterm)) + if x != "" || a:has_extra_attrs | let a = a .. '</span>' | endif endif return a endfun @@ -286,84 +288,102 @@ if s:settings.use_css " save CSS to a list of rules to add to the output at the end of processing " first, get the style names we need - let wrapperfunc_lines = [ - \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, make_unselectable, unformatted)', - \ '', - \ ' let l:style_name = synIDattr(a:style_id, "name", s:whatterm)' - \ ] + let s:wrapperfunc_lines = [] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, make_unselectable, unformatted) + + let l:style_name = synIDattr(a:style_id, "name", s:whatterm) + ENDLET if &diff - let wrapperfunc_lines += [ - \ ' let l:diff_style_name = synIDattr(a:diff_style_id, "name", s:whatterm)'] - - " Add normal groups and diff groups to separate lists so we can order them to - " allow diff highlight to override normal highlight - - " if primary style IS a diff style, grab it from the diff cache instead - " (always succeeds because we pre-populate it) - let wrapperfunc_lines += [ - \ '', - \ ' if a:style_id == s:DIFF_D_ID || a:style_id == s:DIFF_A_ID ||'. - \ ' a:style_id == s:DIFF_C_ID || a:style_id == s:DIFF_T_ID', - \ ' let l:saved_style = get(s:diffstylelist,a:style_id)', - \ ' else' - \ ] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + let l:diff_style_name = synIDattr(a:diff_style_id, "name", s:whatterm) + ENDLET + + " Add normal groups and diff groups to separate lists so we can order them to + " allow diff highlight to override normal highlight + + " if primary style IS a diff style, grab it from the diff cache instead + " (always succeeds because we pre-populate it) + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + + if a:style_id == s:DIFF_D_ID || a:style_id == s:DIFF_A_ID || a:style_id == s:DIFF_C_ID || a:style_id == s:DIFF_T_ID + let l:saved_style = get(s:diffstylelist,a:style_id) + else + ENDLET endif " get primary style info from cache or build it on the fly if not found - let wrapperfunc_lines += [ - \ ' let l:saved_style = get(s:stylelist,a:style_id)', - \ ' if type(l:saved_style) == type(0)', - \ ' unlet l:saved_style', - \ ' let l:saved_style = s:CSS1(a:style_id)', - \ ' if l:saved_style != ""', - \ ' let l:saved_style = "." . l:style_name . " { " . l:saved_style . "}"', - \ ' endif', - \ ' let s:stylelist[a:style_id]= l:saved_style', - \ ' endif' - \ ] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + let l:saved_style = get(s:stylelist,a:style_id) + if type(l:saved_style) == type(0) + unlet l:saved_style + let l:saved_style = s:CSS1(a:style_id) + if l:saved_style != "" + let l:saved_style = "." .. l:style_name .. " { " .. l:saved_style .. "}" + endif + let s:stylelist[a:style_id] = l:saved_style + endif + ENDLET if &diff - let wrapperfunc_lines += [ ' endif' ] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + endif + ENDLET endif +" Ignore this comment, just bypassing a highlighting issue: if " Build the wrapper tags around the text. It turns out that caching these " gives pretty much zero performance gain and adds a lot of logic. - let wrapperfunc_lines += [ - \ '', - \ ' if l:saved_style == "" && empty(a:extra_attrs)' - \ ] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + + if l:saved_style == "" && empty(a:extra_attrs) + ENDLET if &diff - let wrapperfunc_lines += [ - \ ' if a:diff_style_id <= 0' - \ ] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + if a:diff_style_id <= 0 + ENDLET endif " no surroundings if neither primary nor diff style has any info - let wrapperfunc_lines += [ - \ ' return a:text' - \ ] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + return a:text + ENDLET if &diff " no primary style, but diff style - let wrapperfunc_lines += [ - \ ' else', - \ ' return "<span class=\"" .l:diff_style_name . "\">".a:text."</span>"', - \ ' endif' - \ ] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + else + return '<span class="' ..l:diff_style_name .. '">'..a:text.."</span>" + endif + ENDLET endif + " Ignore this comment, just bypassing a highlighting issue: if + " open tag for non-empty primary style - let wrapperfunc_lines += [ - \ ' else'] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + else + ENDLET " non-empty primary style. handle either empty or non-empty diff style. " " separate the two classes by a space to apply them both if there is a diff " style name, unless the primary style is empty, then just use the diff style " name - let diffstyle = - \ (&diff ? '(a:diff_style_id <= 0 ? "" : " ". l:diff_style_name) .' - \ : "") + let s:diffstyle = + \ (&diff ? '(a:diff_style_id <= 0 ? "" : " " .. l:diff_style_name)..' + \ : '') if s:settings.prevent_copy == "" - let wrapperfunc_lines += [ - \ ' return "<span ".a:extra_attrs."class=\"" . l:style_name .'.diffstyle.'"\">".a:text."</span>"' - \ ] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim eval ENDLET + return "<span "..a:extra_attrs..'class="' .. l:style_name ..{s:diffstyle}'">'..a:text.."</span>" + ENDLET else " New method: use generated content in the CSS. The only thing needed here @@ -388,59 +408,76 @@ if s:settings.use_css " Note, if maxlength property needs to be added in the future, it will need " to use strchars(), because HTML specifies that the maxlength parameter " uses the number of unique codepoints for its limit. - let wrapperfunc_lines += [ - \ ' if a:make_unselectable', - \ ' return "<span ".a:extra_attrs."class=\"" . l:style_name .'.diffstyle.'"\"' - \ ] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim eval ENDLET + if a:make_unselectable + let return_span = "<span "..a:extra_attrs..'class="' .. l:style_name ..{s:diffstyle}'"' + ENDLET if s:settings.use_input_for_pc !=# 'all' - let wrapperfunc_lines[-1] .= ' " . "data-" . l:style_name . "-content=\"".a:text."\"' + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + let return_span ..= " data-" .. l:style_name .. '-content="'..a:text..'"' + ENDLET endif - let wrapperfunc_lines[-1] .= '>' + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + let return_span ..= '>' + ENDLET if s:settings.use_input_for_pc !=# 'none' - let wrapperfunc_lines[-1] .= - \ '<input'.s:unselInputType.' class=\"" . l:style_name .'.diffstyle.'"\"'. - \ ' value=\"".substitute(a:unformatted,''\s\+$'',"","")."\"'. - \ ' onselect=''this.blur(); return false;'''. - \ ' onmousedown=''this.blur(); return false;'''. - \ ' onclick=''this.blur(); return false;'''. - \ ' readonly=''readonly'''. - \ ' size=\"".strwidth(a:unformatted)."\"'. - \ (s:settings.use_xhtml ? '/' : '').'>' + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim eval ENDLET + let return_span ..= '<input'..s:unselInputType..' class="' .. l:style_name ..{s:diffstyle}'"' + let return_span ..= ' value="'..substitute(a:unformatted,'\s\+$',"","")..'"' + let return_span ..= " onselect='this.blur(); return false;'" + let return_span ..= " onmousedown='this.blur(); return false;'" + let return_span ..= " onclick='this.blur(); return false;'" + let return_span ..= " readonly='readonly'" + let return_span ..= ' size="'..strwidth(a:unformatted)..'"' + let return_span ..= (s:settings.use_xhtml ? '/>' : '>') + ENDLET endif - let wrapperfunc_lines[-1] .= '</span>"' - let wrapperfunc_lines += [ - \ ' else', - \ ' return "<span ".a:extra_attrs."class=\"" . l:style_name .'. diffstyle .'"\">".a:text."</span>"' - \ ] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim eval ENDLET + return return_span..'</span>' + else + return "<span "..a:extra_attrs..'class="' .. l:style_name .. {s:diffstyle}'">'..a:text.."</span>" + endif + ENDLET endif - let wrapperfunc_lines += [ - \ ' endif', - \ 'endfun' - \ ] + call add(s:wrapperfunc_lines, []) + let s:wrapperfunc_lines[-1] =<< trim ENDLET + endif + endfun + ENDLET else " Non-CSS method just needs the wrapper. " " Functions used to get opening/closing automatically return null strings if " no styles exist. if &diff - let wrapperfunc_lines = [ - \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2)', - \ ' return s:HtmlOpening(a:style_id, a:extra_attrs).(a:diff_style_id <= 0 ? "" :'. - \ 's:HtmlOpening(a:diff_style_id, "")).a:text.'. - \ '(a:diff_style_id <= 0 ? "" : s:HtmlClosing(a:diff_style_id, 0)).s:HtmlClosing(a:style_id, !empty(a:extra_attrs))', - \ 'endfun' - \ ] + let s:wrapperfunc_lines =<< trim ENDLET + function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2) + if a:diff_style_id <= 0 + let l:diff_opening = s:HtmlOpening(a:diff_style_id, "") + let l:diff_closing = s:HtmlClosing(a:diff_style_id, 0) + else + let l:diff_opening = "" + let l:diff_closing = "" + endif + return s:HtmlOpening(a:style_id, a:extra_attrs)..l:diff_opening..a:text..l:diff_closing..s:HtmlClosing(a:style_id, !empty(a:extra_attrs)) + endfun + ENDLET else - let wrapperfunc_lines = [ - \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2)', - \ ' return s:HtmlOpening(a:style_id, a:extra_attrs).a:text.s:HtmlClosing(a:style_id, !empty(a:extra_attrs))', - \ 'endfun' - \ ] + let s:wrapperfunc_lines =<< trim ENDLET + function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2) + return s:HtmlOpening(a:style_id, a:extra_attrs)..a:text..s:HtmlClosing(a:style_id, !empty(a:extra_attrs)) + endfun + ENDLET endif endif " create the function we built line by line above -exec join(wrapperfunc_lines, "\n") +exec join(flatten(s:wrapperfunc_lines), "\n") let s:diff_mode = &diff @@ -471,7 +508,7 @@ function! s:HtmlFormat(text, style_id, diff_style_id, extra_attrs, make_unselect " Replace double spaces, leading spaces, and trailing spaces if needed if ' ' != s:HtmlSpace - let formatted = substitute(formatted, ' ', s:HtmlSpace . s:HtmlSpace, 'g') + let formatted = substitute(formatted, ' ', s:HtmlSpace .. s:HtmlSpace, 'g') let formatted = substitute(formatted, '^ ', s:HtmlSpace, 'g') let formatted = substitute(formatted, ' \+$', s:HtmlSpace, 'g') endif @@ -487,7 +524,7 @@ if s:settings.prevent_copy =~# 'n' if s:settings.line_ids function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr) if a:lnr > 0 - return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 'id="'.(exists('g:html_diff_win_num') ? 'W'.g:html_diff_win_num : "").'L'.a:lnr.s:settings.id_suffix.'" ', 1) + return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 'id="'..(exists('g:html_diff_win_num') ? 'W'..g:html_diff_win_num : "")..'L'..a:lnr..s:settings.id_suffix..'" ', 1) else return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1) endif @@ -503,14 +540,14 @@ if s:settings.prevent_copy =~# 'n' " always be non-zero, however we don't want to use the <input> because that " won't work as nice for empty text function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr) - return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 'id="'.(exists('g:html_diff_win_num') ? 'W'.g:html_diff_win_num : "").'L'.a:lnr.s:settings.id_suffix.'" ', 0) + return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 'id="'..(exists('g:html_diff_win_num') ? 'W'..g:html_diff_win_num : "")..'L'..a:lnr..s:settings.id_suffix..'" ', 0) endfun endif else if s:settings.line_ids function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr) if a:lnr > 0 - return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 'id="'.(exists('g:html_diff_win_num') ? 'W'.g:html_diff_win_num : "").'L'.a:lnr.s:settings.id_suffix.'" ', 0) + return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 'id="'..(exists('g:html_diff_win_num') ? 'W'..g:html_diff_win_num : "")..'L'..a:lnr..s:settings.id_suffix..'" ', 0) else return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0) endif @@ -535,8 +572,8 @@ if s:settings.prevent_copy =~# 'f' " Simply space-pad to the desired width inside the generated content (note " that the FoldColumn definition includes a whitespace:pre rule) function! s:FoldColumn_build(char, len, numfill, char2, class, click) - return "<a href='#' class='".a:class."' onclick='".a:click."' data-FoldColumn-content='". - \ repeat(a:char, a:len).a:char2.repeat(' ', a:numfill). + return "<a href='#' class='"..a:class.."' onclick='"..a:click.."' data-FoldColumn-content='". + \ repeat(a:char, a:len)..a:char2..repeat(' ', a:numfill). \ "'></a>" endfun function! s:FoldColumn_fill() @@ -554,35 +591,38 @@ if s:settings.prevent_copy =~# 'f' " " Note, 'exec' commands do not recognize line continuations, so must " concatenate lines rather than continue them. - let build_fun_lines = [ - \ 'function! s:FoldColumn_build(char, len, numfill, char2, class, click)', - \ ' let l:input_open = "<input readonly=''readonly''".s:unselInputType.'. - \ ' " onselect=''this.blur(); return false;''".'. - \ ' " onmousedown=''this.blur(); ".a:click." return false;''".'. - \ ' " onclick=''return false;'' size=''".'. - \ ' string(a:len + (empty(a:char2) ? 0 : 1) + a:numfill) .'. - \ ' "'' "', - \ ' let l:common_attrs = "class=''FoldColumn'' value=''"', - \ ' let l:input_close = (s:settings.use_xhtml ? "'' />" : "''>")' - \ ] + let s:build_fun_lines = [] + call add(s:build_fun_lines, []) + let s:build_fun_lines[-1] =<< trim ENDLET + function! s:FoldColumn_build(char, len, numfill, char2, class, click) + let l:input_open = "<input readonly='readonly'"..s:unselInputType + let l:input_open ..= " onselect='this.blur(); return false;'" + let l:input_open ..= " onmousedown='this.blur(); "..a:click.." return false;'" + let l:input_open ..= " onclick='return false;' size='" + let l:input_open ..= string(a:len + (empty(a:char2) ? 0 : 1) + a:numfill) .. "' " + let l:common_attrs = "class='FoldColumn' value='" + let l:input_close = (s:settings.use_xhtml ? "' />" : "'>") + let l:return_span = "<span class='"..a:class.."'>" + let l:return_span ..= l:input_open..l:common_attrs..repeat(a:char, a:len)..(a:char2) + let l:return_span ..= l:input_close + ENDLET if s:settings.use_input_for_pc ==# 'fallback' - let build_fun_lines += [ - \ ' let l:gen_content_link ='. - \ ' "<a href=''#'' class=''FoldColumn'' onclick=''".a:click."'' data-FoldColumn-content=''".'. - \ ' repeat(a:char, a:len).a:char2.repeat('' '', a:numfill).'. - \ ' "''></a>"' - \ ] + call add(s:build_fun_lines, []) + let s:build_fun_lines[-1] =<< trim ENDLET + let l:return_span ..= "<a href='#' class='FoldColumn' onclick='"..a:click.."'" + let l:return_span ..= " data-FoldColumn-content='" + let l:return_span ..= repeat(a:char, a:len)..a:char2..repeat(' ', a:numfill) + let l:return_span ..= "'></a>" + ENDLET endif - let build_fun_lines += [ - \ ' return "<span class=''".a:class."''>".'. - \ ' l:input_open.l:common_attrs.repeat(a:char, a:len).(a:char2).'. - \ ' l:input_close.'. - \ (s:settings.use_input_for_pc ==# 'fallback' ? 'l:gen_content_link.' : ""). - \ ' "</span>"', - \ 'endfun' - \ ] + call add(s:build_fun_lines, []) + let s:build_fun_lines[-1] =<< trim ENDLET + let l:return_span ..= "</span>" + return l:return_span + endfun + ENDLET " create the function we built line by line above - exec join(build_fun_lines, "\n") + exec join(flatten(s:build_fun_lines), "\n") function! s:FoldColumn_fill() return s:FoldColumn_build(' ', s:foldcolumn, 0, '', 'FoldColumn', '') @@ -592,8 +632,8 @@ else " For normal fold columns, simply space-pad to the desired width (note that " the FoldColumn definition includes a whitespace:pre rule) function! s:FoldColumn_build(char, len, numfill, char2, class, click) - return "<a href='#' class='".a:class."' onclick='".a:click."'>". - \ repeat(a:char, a:len).a:char2.repeat(' ', a:numfill). + return "<a href='#' class='"..a:class.."' onclick='"..a:click.."'>". + \ repeat(a:char, a:len)..a:char2..repeat(' ', a:numfill). \ "</a>" endfun function! s:FoldColumn_fill() @@ -625,29 +665,30 @@ endif " Return CSS style describing given highlight id (can be empty) function! s:CSS1(id) let a = "" - if synIDattr(a:id, "inverse") + let translated_ID = synIDtrans(a:id) + if synIDattr(translated_ID, "inverse") " For inverse, we always must set both colors (and exchange them) - let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) - let a = a . "color: " . ( x != "" ? x : s:bgc ) . "; " - let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) - let a = a . "background-color: " . ( x != "" ? x : s:fgc ) . "; " + let x = s:HtmlColor(synIDattr(translated_ID, "bg#", s:whatterm)) + let a = a .. "color: " .. ( x != "" ? x : s:bgc ) .. "; " + let x = s:HtmlColor(synIDattr(translated_ID, "fg#", s:whatterm)) + let a = a .. "background-color: " .. ( x != "" ? x : s:fgc ) .. "; " else - let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) - if x != "" | let a = a . "color: " . x . "; " | endif - let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) + let x = s:HtmlColor(synIDattr(translated_ID, "fg#", s:whatterm)) + if x != "" | let a = a .. "color: " .. x .. "; " | endif + let x = s:HtmlColor(synIDattr(translated_ID, "bg#", s:whatterm)) if x != "" - let a = a . "background-color: " . x . "; " + let a = a .. "background-color: " .. x .. "; " " stupid hack because almost every browser seems to have at least one font " which shows 1px gaps between lines which have background - let a = a . "padding-bottom: 1px; " - elseif (a:id == s:FOLDED_ID || a:id == s:LINENR_ID || a:id == s:FOLD_C_ID) && !empty(s:settings.prevent_copy) + let a = a .. "padding-bottom: 1px; " + elseif (translated_ID == s:FOLDED_ID || translated_ID == s:LINENR_ID || translated_ID == s:FOLD_C_ID) && !empty(s:settings.prevent_copy) " input elements default to a different color than the rest of the page - let a = a . "background-color: " . s:bgc . "; " + let a = a .. "background-color: " .. s:bgc .. "; " endif endif - if synIDattr(a:id, "bold") | let a = a . "font-weight: bold; " | endif - if synIDattr(a:id, "italic") | let a = a . "font-style: italic; " | endif - if synIDattr(a:id, "underline") | let a = a . "text-decoration: underline; " | endif + if synIDattr(translated_ID, "bold") | let a = a .. "font-weight: bold; " | endif + if synIDattr(translated_ID, "italic") | let a = a .. "font-style: italic; " | endif + if synIDattr(translated_ID, "underline") | let a = a .. "text-decoration: underline; " | endif return a endfun @@ -720,7 +761,7 @@ if exists("g:loaded_2html_plugin") let s:pluginversion = g:loaded_2html_plugin else if !exists("g:unloaded_tohtml_plugin") - let s:main_plugin_path = expand("<sfile>:p:h:h")."/plugin/tohtml.vim" + let s:main_plugin_path = expand("<sfile>:p:h:h").."/plugin/tohtml.vim" if filereadable(s:main_plugin_path) let s:lines = readfile(s:main_plugin_path, "", 20) call filter(s:lines, 'v:val =~ "loaded_2html_plugin = "') @@ -743,12 +784,12 @@ let s:orgbufnr = winbufnr(0) let s:origwin_stl = &l:stl if expand("%") == "" if exists('g:html_diff_win_num') - exec 'new Untitled_win'.g:html_diff_win_num.'.'.(s:settings.use_xhtml ? 'x' : '').'html' + exec 'new Untitled_win'..g:html_diff_win_num..'.'.(s:settings.use_xhtml ? 'xhtml' : 'html') else - exec 'new Untitled.'.(s:settings.use_xhtml ? 'x' : '').'html' + exec 'new Untitled.'..(s:settings.use_xhtml ? 'xhtml' : 'html') endif else - exec 'new %.'.(s:settings.use_xhtml ? 'x' : '').'html' + exec 'new %.'..(s:settings.use_xhtml ? 'xhtml' : 'html') endif " Resize the new window to very small in order to make it draw faster @@ -795,7 +836,7 @@ le |