runtime(tohtml): Update TOhtml to version 9.0v2 (#13050)

Commit: 
https://github.com/vim/vim/commit/86cfb39030eb557e1a1c7804f9c147556ca5dbf1
Author: fritzophrenic <fritzophre...@gmail.com>
Date:   Fri Sep 8 12:20:01 2023 -0500

    runtime(tohtml): Update TOhtml to version 9.0v2 
(https://github.com/vim/vim/issues/13050)
    
    Modified behavior:
      - Change default value of g:html_use_input_for_pc from "fallback" to
        "none". This means with default settings, only the standards-based
        method to make special text unselectable is used. The old method
        relying on unspecified browser behavior for <input> tags is now only
        used if a user specifically enables it.
      - Officially deprecate g:use_xhtml option (in favor of
        g:html_use_xhtml) by issuing a warning message when used.
    
    Bugfixes:
      - Fix issue #8547: LineNr and other special highlight groups did not
        get proper style rules defined when using "hi link".
      - Fix that diff filler was not properly added for deleted lines at the
        end of a buffer.
    
    Other:
      - Refactored function definitions from long lists of strings to use
        :let-heredoc variable assignment instead.
      - Corrected deprecated "." string concatenation operator to ".."
        operator in more places.
    
    
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/runtime/autoload/tohtml.vim b/runtime/autoload/tohtml.vim
index 108634747..d2722a402 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 <fritzophre...@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 29a12396d..6a20734a6 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 0369313f0..56eb2c15b 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 <fritzophre...@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 69780cffe..f3ce8bed8 100644
--- a/runtime/syntax/2html.vim
+++ b/runtime/syntax/2html.vim
@@ -1,6 +1,6 @@
 " Vim syntax support file
 " Maintainer: Ben Fritz <fritzophre...@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, "
")
+exec join(flatten(s:wrapperfunc_lines), "
")
 
 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, "
")
+    exec join(flatten(s:build_fun_lines), "
")
 
     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 @@ let s:lines = []
 
 if s:settings.use_xhtml
   if s:settings.encoding != ""
-    call add(s:lines, "<?xml version=\"1.0\" encoding=\"" . 
s:settings.encoding . "\"?>")
+    call add(s:lines, "<?xml version=\"1.0\" encoding=\"" .. 
s:settings.encoding .. "\"?>")
   else
     call add(s:lines, "<?xml version=\"1.0\"?>")
   endif
@@ -808,9 +849,9 @@ let s:HtmlSpace = ' '
 let s:LeadingSpace = ' '
 let s:HtmlEndline = ''
 if s:settings.no_pre
-  let s:HtmlEndline = '<br' . s:tag_close
+  let s:HtmlEndline = '<br' .. s:tag_close
   let s:LeadingSpace = s:settings.use_xhtml ? '&#160;' : '&nbsp;'
-  let s:HtmlSpace = '\' . s:LeadingSpace
+  let s:HtmlSpace = '\' .. s:LeadingSpace
 endif
 
 " HTML header, with the title and generator ;-). Left free space for the CSS,
@@ -823,30 +864,30 @@ if !s:settings.no_doc
   " contained in XML information (to avoid haggling over content type)
   if s:settings.encoding != "" && !s:settings.use_xhtml
     if s:html5
-      call add(s:lines, '<meta charset="' . s:settings.encoding . '"' . 
s:tag_close)
+      call add(s:lines, '<meta charset="' .. s:settings.encoding .. '"' .. 
s:tag_close)
     else
-      call add(s:lines, "<meta http-equiv=\"content-type\" 
content=\"text/html; charset=" . s:settings.encoding . '"' . s:tag_close)
+      call add(s:lines, "<meta http-equiv=\"content-type\" 
content=\"text/html; charset=" .. s:settings.encoding .. '"' .. s:tag_close)
     endif
   endif
   call extend(s:lines, [
-       \ ("<title>".expand("%:p:~")."</title>"),
-       \ ("<meta name=\"Generator\" 
content=\"Vim/".v:version/100.".".v:version%100.'"'.s:tag_close),
-       \ ("<meta name=\"plugin-version\" 
content=\"".s:pluginversion.'"'.s:tag_close)
+       \ ("<title>"..expand("%:p:~").."</title>"),
+       \ ("<meta name=\"Generator\" 
content=\"Vim/"..v:version/100.."."..v:version%100..'"'..s:tag_close),
+       \ ("<meta name=\"plugin-version\" 
content=\""..s:pluginversion..'"'..s:tag_close)
        \ ])
-  call add(s:lines, '<meta name="syntax" 
content="'.s:current_syntax.'"'.s:tag_close)
-  call add(s:lines, '<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.
-       \ '"'.s:tag_close)
-  call add(s:lines, '<meta name="colorscheme" content="'.
+  call add(s:lines, '<meta name="syntax" 
content="'..s:current_syntax..'"'..s:tag_close)
+  call add(s:lines, '<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..
+       \ '"'..s:tag_close)
+  call add(s:lines, '<meta name="colorscheme" content="'..
        \ (exists('g:colors_name')
        \ ? g:colors_name
-       \ : 'none'). '"'.s:tag_close)
+       \ : 'none').. '"'..s:tag_close)
 
   if s:settings.use_css
     call extend(s:lines, [
-         \ "<style" . (s:html5 ? "" : " type=\"text/css\"") . ">",
+         \ "<style" .. (s:html5 ? "" : " type=\"text/css\"") .. ">",
          \ s:settings.use_xhtml ? "" : "<!--"])
     let s:ieonly = []
     if s:settings.dynamic_folds
@@ -921,7 +962,7 @@ if !s:settings.no_doc
   if s:uses_script
     call extend(s:lines, [
          \ "",
-         \ "<script" . (s:html5 ? "" : " type='text/javascript'") . ">",
+         \ "<script" .. (s:html5 ? "" : " type='text/javascript'") .. ">",
          \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])
   endif
 
@@ -968,7 +1009,7 @@ if !s:settings.no_doc
            \ "",
            \ "  /* 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')",
            \ "    {",
@@ -1003,7 +1044,7 @@ if !s:settings.no_doc
   endif
 
   call extend(s:lines, ["</head>",
-       \ "<body".(s:settings.line_ids ? " onload='JumpToLine();'" : "").">"])
+       \ "<body"..(s:settings.line_ids ? " onload='JumpToLine();'" : "")..">"])
 endif
 
 if s:settings.no_pre
@@ -1015,20 +1056,20 @@ else
   call extend(s:lines, ["<pre id='vimCodeElement" .. s:settings.id_suffix .. 
"'>"])
 endif
 
-exe s:orgwin . "wincmd w"
+exe s:orgwin .. "wincmd w"
 
 " caches of style data
 " initialize to include line numbers if using them
 if s:settings.number_lines
-  let s:stylelist = { s:LINENR_ID : ".LineNr { " . s:CSS1( s:LINENR_ID ) . "}" 
}
+  let s:stylelist = { s:LINENR_ID : ".LineNr { " .. s:CSS1( s:LINENR_ID ) .. 
"}" }
 else
   let s:stylelist = {}
 endif
 let s:diffstylelist = {
-      \   s:DIFF_A_ID : ".DiffAdd { " . s:CSS1( s:DIFF_A_ID ) . "}",
-      \   s:DIFF_C_ID : ".DiffChange { " . s:CSS1( s:DIFF_C_ID ) . "}",
-      \   s:DIFF_D_ID : ".DiffDelete { " . s:CSS1( s:DIFF_D_ID ) . "}",
-      \   s:DIFF_T_ID : ".DiffText { " . s:CSS1( s:DIFF_T_ID ) . "}"
+      \   s:DIFF_A_ID : ".DiffAdd { " .. s:CSS1( s:DIFF_A_ID ) .. "}",
+      \   s:DIFF_C_ID : ".DiffChange { " .. s:CSS1( s:DIFF_C_ID ) .. "}",
+      \   s:DIFF_D_ID : ".DiffDelete { " .. s:CSS1( s:DIFF_D_ID ) .. "}",
+      \   s:DIFF_T_ID : ".DiffText { " .. s:CSS1( s:DIFF_T_ID ) .. "}"
       \ }
 
 " set up progress bar in the status line
@@ -1046,17 +1087,17 @@ if !s:settings.no_progress
        \ g:colors_name != s:last_colors_name
       let s:last_colors_name = exists("g:colors_name") ? g:colors_name : "none"
 
-      let l:diffatr = synIDattr(hlID("DiffDelete"), "reverse", s:whatterm) ? 
"fg#" : "bg#"
-      let l:stlatr = synIDattr(hlID("StatusLine"), "reverse", s:whatterm) ? 
"fg#" : "bg#"
+      let l:diffatr = synIDattr(hlID("DiffDelete")->synIDtrans(), "reverse", 
s:whatterm) ? "fg#" : "bg#"
+      let l:stlatr = synIDattr(hlID("StatusLine")->synIDtrans(), "reverse", 
s:whatterm) ? "fg#" : "bg#"
 
-      let l:progbar_color = synIDattr(hlID("DiffDelete"), l:diffatr, 
s:whatterm)
-      let l:stl_color = synIDattr(hlID("StatusLine"), l:stlatr, s:whatterm)
+      let l:progbar_color = synIDattr(hlID("DiffDelete")->synIDtrans(), 
l:diffatr, s:whatterm)
+      let l:stl_color = synIDattr(hlID("StatusLine")->synIDtrans(), l:stlatr, 
s:whatterm)
 
       if "" == l:progbar_color
-       let l:progbar_color = synIDattr(hlID("DiffDelete"), "reverse", 
s:whatterm) ? s:fgc : s:bgc
+       let l:progbar_color = synIDattr(hlID("DiffDelete")->synIDtrans(), 
"reverse", s:whatterm) ? s:fgc : s:bgc
       endif
       if "" == l:stl_color
-       let l:stl_color = synIDattr(hlID("StatusLine"), "reverse", s:whatterm) 
? s:fgc : s:bgc
+       let l:stl_color = synIDattr(hlID("StatusLine")->synIDtrans(), 
"reverse", s:whatterm) ? s:fgc : s:bgc
       endif
 
       if l:progbar_color == l:stl_color
@@ -1086,13 +1127,13 @@ if !s:settings.no_progress
        endif
        echomsg "diff detected progbar color set to" l:progbar_color
       endif
-      exe "hi TOhtmlProgress_auto" s:whatterm."bg=".l:progbar_color
+      exe "hi TOhtmlProgress_auto" s:whatterm.."bg="..l:progbar_color
     endif
   endfun
 
   func! s:ProgressBar(title, max_value, winnr)
     let pgb=copy(s:progressbar)
-    let pgb.title = a:title.' '
+    let pgb.title = a:title..' '
     let pgb.max_value = a:max_value
     let pgb.winnr = a:winnr
     let pgb.cur_value = 0
@@ -1194,6 +1235,66 @@ if !s:settings.no_progress
   call s:SetProgbarColor()
 endif
 
+let s:build_fun_lines = []
+call add(s:build_fun_lines, [])
+let s:build_fun_lines[-1] =<< trim ENDLET
+    func! s:Add_diff_fill(lnum)
+      let l:filler = diff_filler(a:lnum)
+      if l:filler > 0
+       let l:to_insert = l:filler
+       while l:to_insert > 0
+         let l:new = repeat(s:difffillchar, 3)
+
+         if l:to_insert > 2 && l:to_insert < l:filler && 
!s:settings.whole_filler
+           let l:new = l:new .. " " .. l:filler .. " inserted lines "
+           let l:to_insert = 2
+         endif
+ENDLET
+call add(s:build_fun_lines, [])
+if !s:settings.no_pre
+  let s:build_fun_lines[-1] =<< trim ENDLET
+         " HTML line wrapping is off--go ahead and fill to the margin
+         " TODO: what about when CSS wrapping is turned on?
+         let l:new = l:new .. repeat(s:difffillchar, &columns - strlen(l:new) 
- s:margin)
+  ENDLET
+else
+  let s:build_fun_lines[-1] =<< trim ENDLET
+         let l:new = l:new .. repeat(s:difffillchar, 3)
+  ENDLET
+endif
+call add(s:build_fun_lines, [])
+let s:build_fun_lines[-1] =<< trim ENDLET
+       let l:new = s:HtmlFormat_d(l:new, s:DIFF_D_ID, 0)
+ENDLET
+if s:settings.number_lines
+  call add(s:build_fun_lines, [])
+  let s:build_fun_lines[-1] =<< trim ENDLET
+         " Indent if line numbering is on. Indent gets style of line number
+         " column.
+         let l:new = s:HtmlFormat_n(repeat(' ', s:margin), s:LINENR_ID, 0, 0) 
.. l:new
+  ENDLET
+endif
+if s:settings.dynamic_folds && !s:settings.no_foldcolumn 
+  call add(s:build_fun_lines, [])
+  let s:build_fun_lines[-1] =<< trim ENDLET
+         if s:foldcolumn > 0
+           " Indent for foldcolumn if there is one. Assume it's empty, there 
should
+           " not be a fold for deleted lines in diff mode.
+           let l:new = s:FoldColumn_fill() .. l:new
+         endif
+  ENDLET
+endif
+" Ignore this comment, just bypassing a highlighting issue: if
+call add(s:build_fun_lines, [])
+let s:build_fun_lines[-1] =<< trim ENDLET
+       call add(s:lines, l:new..s:HtmlEndline)
+       let l:to_insert = l:to_insert - 1
+      endwhile
+    endif
+  endfun
+ENDLET
+exec join(flatten(s:build_fun_lines), "
")
+
 " First do some preprocessing for dynamic folding. Do this for the entire file
 " so we don't accidentally start within a closed fold or something.
 let s:allfolds = []
@@ -1220,7 +1321,7 @@ if s:settings.dynamic_folds
       let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 
'level': s:level,'type': "closed-fold"}
       call add(s:allfolds, s:newfold)
       " open the fold so we can find any contained folds
-      execute s:lnum."foldopen"
+      execute s:lnum.."foldopen"
     else
       if !s:settings.no_progress
        call s:pgb.incr()
@@ -1252,7 +1353,7 @@ if s:settings.dynamic_folds
        call add(s:allfolds, s:newfold)
       endif
       " open the fold so we can find any contained folds
-      execute s:lnum."foldopen"
+      execute s:lnum.."foldopen"
     else
       if !s:settings.no_progress
        call s:pgb.incr()
@@ -1339,7 +1440,7 @@ if s:settings.dynamic_folds
   " Note that only when a start and an end line is specified will a fold
   " containing the current range ever be removed.
   while leveladjust > 0
-    exe g:html_start_line."foldopen"
+    exe g:html_start_line.."foldopen"
     let leveladjust -= 1
   endwhile
 endif
@@ -1399,47 +1500,11 @@ endif
 while s:lnum <= s:end
 
   " If there are filler lines for diff mode, show these above the line.
-  let s:filler = diff_filler(s:lnum)
-  if s:filler > 0
-    let s:n = s:filler
-    while s:n > 0
-      let s:new = repeat(s:difffillchar, 3)
-
-      if s:n > 2 && s:n < s:filler && !s:settings.whole_filler
-       let s:new = s:new . " " . s:filler . " inserted lines "
-       let s:n = 2
-      endif
-
-      if !s:settings.no_pre
-       " HTML line wrapping is off--go ahead and fill to the margin
-       " TODO: what about when CSS wrapping is turned on?
-       let s:new = s:new . repeat(s:difffillchar, &columns - strlen(s:new) - 
s:margin)
-      else
-       let s:new = s:new . repeat(s:difffillchar, 3)
-      endif
-
-      let s:new = s:HtmlFormat_d(s:new, s:DIFF_D_ID, 0)
-      if s:settings.number_lines
-       " Indent if line numbering is on. Indent gets style of line number
-       " column.
-       let s:new = s:HtmlFormat_n(repeat(' ', s:margin), s:LINENR_ID, 0, 0) . 
s:new
-      endif
-      if s:settings.dynamic_folds && !s:settings.no_foldcolumn && s:foldcolumn 
> 0
-       " Indent for foldcolumn if there is one. Assume it's empty, there should
-       " not be a fold for deleted lines in diff mode.
-       let s:new = s:FoldColumn_fill() . s:new
-      endif
-      call add(s:lines, s:new.s:HtmlEndline)
-
-      let s:n = s:n - 1
-    endwhile
-    unlet s:n
-  endif
-  unlet s:filler
+  call s:Add_diff_fill(s:lnum)
 
   " Start the line with the line number.
   if s:settings.number_lines
-    let s:numcol = repeat(' ', s:margin - 1 - strlen(s:lnum)) . s:lnum . ' '
+    let s:numcol = repeat(' ', s:margin - 1 - strlen(s:lnum)) .. s:lnum .. ' '
   endif
 
   let s:new = ""
@@ -1450,11 +1515,11 @@ while s:lnum <= s:end
     let s:new = foldtextresult(s:lnum)
     if !s:settings.no_pre
       " HTML line wrapping is off--go ahead and fill to the margin
-      let s:new = s:new . repeat(s:foldfillchar, &columns - strlen(s:new))
+      let s:new = s:new .. repeat(s:foldfillchar, &columns - strlen(s:new))
     endif
 
     " put numcol in a separate group for sake of unselectable text
-    let s:new = (s:settings.number_lines ? s:HtmlFormat_n(s:numcol, 
s:FOLDED_ID, 0, s:lnum): "") . s:HtmlFormat_t(s:new, s:FOLDED_ID, 0)
+    let s:new = (s:settings.number_lines ? s:HtmlFormat_n(s:numcol, 
s:FOLDED_ID, 0, s:lnum): "") .. s:HtmlFormat_t(s:new, s:FOLDED_ID, 0)
 
     " Skip to the end of the fold
     let s:new_lnum = foldclosedend(s:lnum)
@@ -1475,7 +1540,7 @@ while s:lnum <= s:end
     if s:settings.dynamic_folds
       " First insert a closing for any open folds that end on this line
       while !empty(s:foldstack) && get(s:foldstack,0).lastline == s:lnum-1
-       let s:new = s:new."</span></span>"
+       let s:new = s:new.."</span></span>"
        call remove(s:foldstack, 0)
       endwhile
 
@@ -1483,9 +1548,9 @@ while s:lnum <= s:end
       let s:firstfold = 1
       while !empty(s:allfolds) && get(s:allfolds,0).firstline == s:lnum
        let s:foldId = s:foldId + 1
-       let s:new .= "<span id='"
-       let s:new .= (exists('g:html_diff_win_num') ? "win".g:html_diff_win_num 
: "")
-       let s:new .= "fold".s:foldId.s:settings.id_suffix."' 
class='".s:allfolds[0].type."'>"
+       let s:new ..= "<span id='"
+       let s:new ..= (exists('g:html_diff_win_num') ? 
"win"..g:html_diff_win_num : "")
+       let s:new ..= "fold"..s:foldId..s:settings.id_suffix.."' 
class='"..s:allfolds[0].type.."'>"
 
 
        " Unless disabled, add a fold column for the opening line of a fold.
@@ -1496,20 +1561,20 @@ while s:lnum <= s:end
        if !s:settings.no_foldcolumn
          " add fold column that can open the new fold
          if s:allfolds[0].level > 1 && s:firstfold
-           let s:new = s:new . s:FoldColumn_build('|', s:allfolds[0].level - 
1, 0, "",
-                 \ 'toggle-open 
FoldColumn','javascript:toggleFold("fold'.s:foldstack[0].id.s:settings.id_suffix.'");')
+           let s:new = s:new .. s:FoldColumn_build('|', s:allfolds[0].level - 
1, 0, "",
+                 \ 'toggle-open 
FoldColumn','javascript:toggleFold("fold'..s:foldstack[0].id..s:settings.id_suffix..'");')
          endif
          " add the filler spaces separately from the '+' char so that it can be
          " shown/hidden separately during a hover unfold
-         let s:new = s:new . s:FoldColumn_build("+", 1, 0, "",
-               \ 'toggle-open FoldColumn', 
'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
+         let s:new = s:new .. s:FoldColumn_build("+", 1, 0, "",
+               \ 'toggle-open FoldColumn', 
'javascript:toggleFold("fold'..s:foldId..s:settings.id_suffix..'");')
          " If this is not the last fold we're opening on this line, we need
          " to keep the filler spaces hidden if the fold is opened by mouse
          " hover. If it is the last fold to open in the line, we shouldn't hide
          " them, so don't apply the toggle-filler class.
-         let s:new = s:new . s:FoldColumn_build(" ", 1, s:foldcolumn - 
s:allfolds[0].level - 1, "",
-               \ 'toggle-open FoldColumn'. (get(s:allfolds, 1, {'firstline': 
0}).firstline == s:lnum ?" toggle-filler" :""),
-               \ 
'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
+         let s:new = s:new .. s:FoldColumn_build(" ", 1, s:foldcolumn - 
s:allfolds[0].level - 1, "",
+               \ 'toggle-open FoldColumn'.. (get(s:allfolds, 1, {'firstline': 
0}).firstline == s:lnum ?" toggle-filler" :""),
+               \ 
'javascript:toggleFold("fold'..s:foldId..s:settings.id_suffix..'");')
 
          " add fold column that can close the new fold
          " only add extra blank space if we aren't opening another fold on the
@@ -1522,12 +1587,12 @@ while s:lnum <= s:end
          if s:firstfold
            " the first fold in a line has '|' characters from folds opened in
            " previous lines, before the '-' for this fold
-           let s:new .= s:FoldColumn_build('|', s:allfolds[0].level - 1, 
s:extra_space, '-',
-                 \ 'toggle-closed FoldColumn', 
'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
+           let s:new ..= s:FoldColumn_build('|', s:allfolds[0].level - 1, 
s:extra_space, '-',
+                 \ 'toggle-closed FoldColumn', 
'javascript:toggleFold("fold'..s:foldId..s:settings.id_suffix..'");')
          else
            " any subsequent folds in the line only add a single '-'
-           let s:new = s:new . s:FoldColumn_build("-", 1, s:extra_space, "",
-                 \ 'toggle-closed FoldColumn', 
'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");')
+           let s:new = s:new .. s:FoldColumn_build("-", 1, s:extra_space, "",
+                 \ 'toggle-closed FoldColumn', 
'javascript:toggleFold("fold'..s:foldId..s:settings.id_suffix..'");')
          endif
          let s:firstfold = 0
        endif
@@ -1535,12 +1600,12 @@ while s:lnum <= s:end
        " Add fold text, moving the span ending to the next line so collapsing
        " of folds works correctly.
        " Put numcol in a separate group for sake of unselectable text.
-       let s:new = s:new . (s:settings.number_lines ? s:HtmlFormat_n(s:numcol, 
s:FOLDED_ID, 0, 0) : "") . substitute(s:HtmlFormat_t(foldtextresult(s:lnum), 
s:FOLDED_ID, 0), '</span>', s:HtmlEndline.'

-       let s:new = s:new . "<span class='fulltext'>"
+       let s:new = s:new .. (s:settings.number_lines ? 
s:HtmlFormat_n(s:numcol, s:FOLDED_ID, 0, 0) : "") .. 
substitute(s:HtmlFormat_t(foldtextresult(s:lnum), s:FOLDED_ID, 0), '</span>', 
s:HtmlEndline..'

+       let s:new = s:new .. "<span class='fulltext'>"
 
        " open the fold now that we have the fold text to allow retrieval of
        " fold text for subsequent folds
-       execute s:lnum."foldopen"
+       execute s:lnum.."foldopen"
        call insert(s:foldstack, remove(s:allfolds,0))
        let s:foldstack[0].id = s:foldId
       endwhile
@@ -1555,13 +1620,13 @@ while s:lnum <= s:end
          " add the empty foldcolumn for unfolded lines if there is a fold
          " column at all
          if s:foldcolumn > 0
-           let s:new = s:new . s:FoldColumn_fill()
+           let s:new = s:new .. s:FoldColumn_fill()
          endif
        else
          " add the fold column for folds not on the opening line
          if get(s:foldstack, 0).firstline < s:lnum
-           let s:new = s:new . s:FoldColumn_build('|', s:foldstack[0].level, 
s:foldcolumn - s:foldstack[0].level, "",
-                 \ 'FoldColumn', 
'javascript:toggleFold("fold'.s:foldstack[0].id.s:settings.id_suffix.'");')
+           let s:new = s:new .. s:FoldColumn_build('|', s:foldstack[0].level, 
s:foldcolumn - s:foldstack[0].level, "",
+                 \ 'FoldColumn', 
'javascript:toggleFold("fold'..s:foldstack[0].id..s:settings.id_suffix..'");')
          endif
        endif
       endif
@@ -1569,9 +1634,9 @@ while s:lnum <= s:end
 
     " Now continue with the unfolded line text
     if s:settings.number_lines
-      let s:new = s:new . s:HtmlFormat_n(s:numcol, s:LINENR_ID, 0, s:lnum)
+      let s:new = s:new .. s:HtmlFormat_n(s:numcol, s:LINENR_ID, 0, s:lnum)
     elseif s:settings.line_ids
-      let s:new = s:new . s:HtmlFormat_n("", s:LINENR_ID, 0, s:lnum)
+      let s:new = s:new .. s:HtmlFormat_n("", s:LINENR_ID, 0, s:lnum)
     endif
 
     " Get the diff attribute, if any.
@@ -1611,7 +1676,7 @@ while s:lnum <= s:end
        if s:len < &columns && !s:settings.no_pre
          " Add spaces at the end of the raw text line to extend the changed
          " line to the full width.
-         let s:line = s:line . repeat(' ', &columns - virtcol([s:lnum, s:len]) 
- s:margin)
+         let s:line = s:line .. repeat(' ', &columns - virtcol([s:lnum, 
s:len]) - s:margin)
          let s:len = &columns
        endif
       else
@@ -1649,11 +1714,11 @@ while s:lnum <= s:end
                " if the found tab is the first character in the text being
                " processed, we need to get the character prior to the text,
                " given by startcol.
-               let s:prevc = matchstr(s:line, '.\%' . (s:startcol + s:offset) 
. 'c')
+               let s:prevc = matchstr(s:line, '.\%' .. (s:startcol + s:offset) 
.. 'c')
              else
                " Otherwise, the byte index of the tab into s:expandedtab is
                " given by s:idx.
-               let s:prevc = matchstr(s:expandedtab, '.\%' . (s:idx + 1) . 'c')
+               let s:prevc = matchstr(s:expandedtab, '.\%' .. (s:idx + 1) .. 
'c')
              endif
              let s:vcol = virtcol([s:lnum, s:startcol + s:idx + s:offset - 
len(s:prevc)])
 
@@ -1689,12 +1754,12 @@ while s:lnum <= s:end
       " Output the text with the same synID, with class set to the highlight ID
       " name, unless it has been concealed completely.
       if strlen(s:expandedtab) > 0
-       let s:new = s:new . s:HtmlFormat(s:expandedtab,  s:id, s:diff_id, "", 0)
+       let s:new = s:new .. s:HtmlFormat(s:expandedtab,  s:id, s:diff_id, "", 
0)
       endif
     endwhile
   endif
 
-  call extend(s:lines, split(s:new.s:HtmlEndline, '
', 1))
+  call extend(s:lines, split(s:new..s:HtmlEndline, '
', 1))
   if !s:settings.no_progress && s:pgb.needs_redraw
     redrawstatus
     let s:pgb.needs_redraw = 0
@@ -1706,17 +1771,21 @@ while s:lnum <= s:end
   endif
 endwhile
 
+" Diff filler is returned based on what needs inserting *before* the given 
line.
+" So to get diff filler at the end of the buffer, we need to use last line + 1
+call s:Add_diff_fill(s:end+1)
+
 if s:settings.dynamic_folds
   " finish off any open folds
   while !empty(s:foldstack)
-    let s:lines[-1].="</span></span>"
+    let s:lines[-1]..="</span></span>"
     call remove(s:foldstack, 0)
   endwhile
 
   " add fold column to the style list if not already there
   let s:id = s:FOLD_C_ID
   if !has_key(s:stylelist, s:id)
-    let s:stylelist[s:id] = '.FoldColumn { ' . s:CSS1(s:id) . '}'
+    let s:stylelist[s:id] = '.FoldColumn { ' .. s:CSS1(s:id) .. '}'
   endif
 endif
 
@@ -1734,7 +1803,7 @@ if !s:settings.no_doc
   call extend(s:lines, ["</body>", "</html>"])
 endif
 
-exe s:newwin . "wincmd w"
+exe s:newwin .. "wincmd w"
 call setline(1, s:lines)
 unlet s:lines
 
@@ -1757,17 +1826,17 @@ if s:settings.use_css && !s:settings.no_doc
 
   " Normal/global attributes
   if s:settings.no_pre
-    call append('.', "body { color: " . s:fgc . "; background-color: " . s:bgc 
. "; font-family: ". s:htmlfont ."; }")
+    call append('.', "body { color: " .. s:fgc .. "; background-color: " .. 
s:bgc .. "; font-family: ".. s:htmlfont .."; }")
     +
   else
-    call append('.', "pre { " . s:whitespace . "font-family: ". s:htmlfont ."; 
color: " . s:fgc . "; background-color: " . s:bgc . "; }")
+    call append('.', "pre { " .. s:whitespace .. "font-family: ".. s:htmlfont 
.."; color: " .. s:fgc .. "; background-color: " .. s:bgc .. "; }")
     +
     yank
     put
     execute "normal! ^cwbody "
     " body should not have the wrap formatting, only the pre section
     if s:whitespace != ''
-      exec 's#'.s:whitespace
+      exec 's#'..s:whitespace
     endif
   endif
   " fix browser inconsistencies (sometimes within the same browser) of 
different
@@ -1778,13 +1847,13 @@ if s:settings.use_css && !s:settings.no_doc
   " like normal text
   if !empty(s:settings.prevent_copy)
     if s:settings.use_input_for_pc !=# "none"
-      call append('.', 'input { border: none; margin: 0; padding: 0; 
font-family: '.s:htmlfont.'; }')
+      call append('.', 'input { border: none; margin: 0; padding: 0; 
font-family: '..s:htmlfont..'; }')
       +
       " ch units for browsers which support them, em units for a somewhat
       " reasonable fallback.
       for w in range(1, 20, 1)
        call append('.', [
-             \ "input[size='".w."'] { width: ".w."em; width: ".w."ch; }"
+             \ "input[size='"..w.."'] { width: "..w.."em; width: "..w.."ch; }"
              \ ])
        +
       endfor
@@ -1828,14 +1897,15 @@ if s:settings.use_css && !s:settings.no_doc
       endif
       for s:style_name in s:unselectable_styles
        call append('.', [
-             \ '  .'.s:style_name.' { user-select: none; }',
-             \ '  [data-'.s:style_name.'-content]::before { content: 
attr(data-'.s:style_name.'-content); }',
-             \ '  [data-'.s:style_name.'-content]::before { padding-bottom: 
1px; display: inline-block; /* match the 1-px padding of standard items with 
background */ }',
-             \ '  span[data-'.s:style_name.'-content]::before { cursor: 
default; }',
+             \ '  .'..s:style_name..' { user-select: none; }',
+             \ '  [data-'..s:style_name..'-content]::before { content: 
attr(data-'..s:style_name..'-content); }',
+             \ '  [data-'..s:style_name..'-content]::before { padding-bottom: 
1px; display: inline-block; /* match the 1-px padding of standard items with 
background */ }',
+             \ '  span[data-'..s:style_name..'-content]::before { cursor: 
default; }',
              \ ])
        +4
       endfor
       if s:settings.use_input_for_pc !=# 'none'
+       " Note, the extra '}' is to match the "@supports" above
        call append('.', [
              \ '  input { display: none; }',
              \ '}'
@@ -1851,12 +1921,12 @@ if s:settings.use_css && !s:settings.no_doc
        " Make the cursor show active fold columns as active areas, and empty 
fold
        " columns as not interactive.
        call append('.', ['input.FoldColumn { cursor: pointer; }',
-             \ 'input.FoldColumn[value="'.repeat(' ', s:foldcolumn).'"] { 
cursor: default; }'
+             \ 'input.FoldColumn[value="'..repeat(' ', s:foldcolumn)..'"] { 
cursor: default; }'
              \ ])
        +2
        if s:settings.use_input_for_pc !=# 'all'
          call append('.', [
-               \ 'a[data-FoldColumn-content="'.repeat(' ', s:foldcolumn).'"] { 
cursor: default; }'
+               \ 'a[data-FoldColumn-content="'..repeat(' ', s:foldcolumn)..'"] 
{ cursor: default; }'
                \ ])
          +1
        end
@@ -1884,7 +1954,7 @@ endif
 if !s:settings.use_css && !s:settings.no_doc
   " For Netscape 4, set <body> attributes too, though, strictly speaking, it's
   " incorrect.
-  execute '%s:<body\([^>]*\):<body bgcolor="' . s:bgc . '" text="' . s:fgc . 
'" >
<font face="'. s:htmlfont .'"'
+  execute '%s:<body\([^>]*\):<body bgcolor="' .. s:bgc .. '" text="' .. s:fgc 
.. '" >
<font face="'.. s:htmlfont ..'"'
 endif
 
 " Gather attributes for all other classes. Do diff first so that normal
@@ -1935,7 +2005,7 @@ let @/ = s:old_search
 let &more = s:old_more
 
 " switch to original window to restore those settings
-exe s:orgwin . "wincmd w"
+exe s:orgwin .. "wincmd w"
 
 if !s:settings.expand_tabs
   let &l:isprint = s:old_isprint
@@ -1945,7 +2015,7 @@ let &l:et = s:old_et
 let &l:scrollbind = s:old_bind
 
 " and back to the new window again to end there
-exe s:newwin . "wincmd w"
+exe s:newwin .. "wincmd w"
 
 let &l:stl = s:newwin_stl
 exec 'resize' s:old_winheight
@@ -1982,10 +2052,13 @@ if !v:profiling
     delfunc s:progressbar.incr
     unlet s:pgb s:progressbar
   endif
+
+  delfunc s:Add_diff_fill
 endif
 
-unlet! s:new_lnum s:diffattr s:difffillchar s:foldfillchar s:HtmlSpace
+unlet! s:new_lnum s:diffattr s:difffillchar s:foldfillchar s:HtmlSpace 
s:diffstyle
 unlet! s:LeadingSpace s:HtmlEndline s:firstfold s:numcol s:foldcolumn
+unlet! s:wrapperfunc_lines s:build_fun_lines
 unlet s:foldstack s:allfolds s:foldId s:settings
 
 let &cpo = s:cpo_sav

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qefJ2-003WXI-0k%40256bit.org.

Raspunde prin e-mail lui