diff --git a/runtime/autoload/tohtml.vim b/runtime/autoload/tohtml.vim
index ad33cee1da..2e9021a48e 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
-" Last Change: 2011 Apr 05
+" Last Change: 2012 Jun 30
"
" Additional contributors:
"
@@ -11,7 +11,7 @@
" this file uses line continuations
let s:cpo_sav = &cpo
-set cpo-=C
+set cpo&vim
" Automatically find charsets from all encodings supported natively by Vim. With
" the 8bit- and 2byte- prefixes, Vim can actually support more encodings than
@@ -391,12 +391,25 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{
call add(html, '')
let body_line_num = len(html)
- call add(html, '')
- call add(html, '
')
for buf in a:win_list
@@ -454,16 +467,19 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{
let insert_index = diff_style_start
endif
- " Delete those parts that are not needed so
- " we can include the rest into the resulting table
- 1,/^\_s\+.*id='oneCharWidth'.*\_s\+.*id='oneInputWidth'.*\_s\+.*id='oneEmWidth'\)\?\zs/d_
$
??,$d_
let temp = getline(1,'$')
+ " clean out id on the main content container because we already set it on
+ " the table
+ let temp[0] = substitute(temp[0], " id='vimCodeElement'", "", "")
" undo deletion of start and end part
" so we can later save the file as valid html
" TODO: restore using grabbed lines if undolevel is 1?
- normal 2u
+ normal! 2u
if s:settings.use_css
call add(html, '
')
elseif s:settings.use_xhtml
@@ -520,12 +536,47 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{
1
let style_start = search('^')-1
+ " add required javascript in reverse order so we can just call append again
+ " and again without adjusting {{{
+
+ " insert script closing tag if any javascript is needed
+ if s:settings.dynamic_folds || !empty(s:settings.prevent_copy)
+ call append(style_start, [
+ \ '',
+ \ s:settings.use_xhtml ? '//]]>' : '-->',
+ \ ""
+ \ ])
+ endif
+
+ " insert script which corrects the size of small input elements in
+ " prevent_copy mode. See 2html.vim for details on why this is needed and how
+ " it works.
+ if !empty(s:settings.prevent_copy)
+ call append(style_start, [
+ \ '',
+ \ '/* simulate a "ch" unit by asking the browser how big a zero character is */',
+ \ 'function FixCharWidth() {',
+ \ ' /* get the hidden element which gives the width of a single character */',
+ \ ' var goodWidth = document.getElementById("oneCharWidth").clientWidth;',
+ \ ' /* get all input elements, we''ll filter on class later */',
+ \ ' var inputTags = document.getElementsByTagName("input");',
+ \ ' var ratio = 5;',
+ \ ' var inputWidth = document.getElementById("oneInputWidth").clientWidth;',
+ \ ' var emWidth = document.getElementById("oneEmWidth").clientWidth;',
+ \ ' if (inputWidth > goodWidth) {',
+ \ ' while (ratio < 100*goodWidth/emWidth && ratio < 100) {',
+ \ ' ratio += 5;',
+ \ ' }',
+ \ ' document.getElementById("vimCodeElement").className = "em"+ratio;',
+ \ ' }',
+ \ '}'
+ \ ])
+ endif
+
" Insert javascript to toggle matching folds open and closed in all windows,
- " if dynamic folding is active. {{{
+ " if dynamic folding is active.
if s:settings.dynamic_folds
call append(style_start, [
- \ ""
\ ])
+ endif
+
+ " insert script tag if any javascript is needed
+ if s:settings.dynamic_folds || s:settings.prevent_copy != ""
+ call append(style_start, [
+ \ ""
+ \ "}"
\])
endif
-if s:settings.no_pre
- call extend(s:lines, ["", ""])
+" Small text columns like the foldcolumn and line number column need a weird
+" hack to work around Webkit's and (in versions prior to 9) IE's lack of support
+" for the 'ch' unit without messing up Opera, which also doesn't support it but
+" works anyway.
+"
+" The problem is that without the 'ch' unit, it is not possible to specify a
+" size of an in terms of character widths. Only Opera seems to do the
+" "sensible" thing and make the sized to fit exactly as many characters
+" as specified by its "size" attribute, but the spec actually says "at least
+" wide enough to fit 'size' characters", so the other browsers are technically
+" correct as well.
+"
+" Anyway, this leads to two diffculties:
+" 1. The foldcolumn is made up of multiple elements side-by-side with
+" different sizes, each of which has their own extra padding added. Thus, a
+" column made up of one item of size 1 and another of size 2 would not
+" necessarily be equal in size to another line's foldcolumn with a single
+" item of size 3.
+" 2. The extra padding added to the elements adds up to make the
+" foldcolumn and line number column too wide, especially in Webkit
+" browsers.
+"
+" So, the full workaround is:
+" 1. Define a default size in em, equal to the number of characters in the
+" input element, in case javascript is disabled and the browser does not
+" support the 'ch' unit. Unfortunately this makes Opera no longer work
+" properly without javascript. 1em per character is much too wide but it
+" looks better in webkit browsers than unaligned columns.
+" 2. Insert the following javascript to run at page load, which checks for the
+" width of a single character (in an extraneous page element inserted
+" before the page title, and set to hidden) and compares it to the width of
+" another extra element with only one character. If the width
+" matches, the script does nothing more, but if not, it will figure out the
+" fraction of an em unit which would correspond with a ch unit if there
+" were one, and set the containing element (
or
) to a class with
+" pre-defined rules which is closest to that fraction of an em. Rules are
+" defined from 0.05 em to 1em per ch.
+if !empty(s:settings.prevent_copy)
+ call extend(s:lines, [
+ \ '',
+ \ '/* simulate a "ch" unit by asking the browser how big a zero character is */',
+ \ 'function FixCharWidth() {',
+ \ ' /* get the hidden element which gives the width of a single character */',
+ \ ' var goodWidth = document.getElementById("oneCharWidth").clientWidth;',
+ \ ' /* get all input elements, we''ll filter on class later */',
+ \ ' var inputTags = document.getElementsByTagName("input");',
+ \ ' var ratio = 5;',
+ \ ' var inputWidth = document.getElementById("oneInputWidth").clientWidth;',
+ \ ' var emWidth = document.getElementById("oneEmWidth").clientWidth;',
+ \ ' if (inputWidth > goodWidth) {',
+ \ ' while (ratio < 100*goodWidth/emWidth && ratio < 100) {',
+ \ ' ratio += 5;',
+ \ ' }',
+ \ ' document.getElementById("vimCodeElement").className = "em"+ratio;',
+ \ ' }',
+ \ '}'
+ \ ])
+endif
+
+" insert script closing tag if any javascript is needed
+if s:settings.dynamic_folds || s:settings.prevent_copy != ""
+ call extend(s:lines, [
+ \ '',
+ \ s:settings.use_xhtml ? '//]]>' : '-->',
+ \ ""
+ \ ])
+endif
+
+call extend(s:lines, [""])
+if !empty(s:settings.prevent_copy)
+ call extend(s:lines,
+ \ ["",
+ \ "",
+ \ "
"])
+ call extend(s:lines, [""])
+endif
+if s:settings.no_pre
+ " if we're not using CSS we use a font tag which can't have a div inside
+ if s:settings.use_css
+ call extend(s:lines, ["
"])
+ endif
+else
+ call extend(s:lines, ["
"])
endif
exe s:orgwin . "wincmd w"
-" List of all id's
-let s:idlist = []
+" 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 ) . "}" }
+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 ) . "}"
+ \ }
" set up progress bar in the status line
if !s:settings.no_progress
@@ -772,15 +1232,22 @@ while s:lnum <= s:end
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(s:new, "DiffDelete", "")
+ let s:new = s:HtmlFormat_d(s:new, s:DIFF_D_ID, 0)
if s:settings.number_lines
- " Indent if line numbering is on; must be after escaping.
- let s:new = repeat(s:LeadingSpace, s:margin) . s:new
+ " 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) . 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)
@@ -793,8 +1260,6 @@ while s:lnum <= s:end
" Start the line with the line number.
if s:settings.number_lines
let s:numcol = repeat(' ', s:margin - 1 - strlen(s:lnum)) . s:lnum . ' '
- else
- let s:numcol = ""
endif
let s:new = ""
@@ -802,14 +1267,14 @@ while s:lnum <= s:end
if has('folding') && !s:settings.ignore_folding && foldclosed(s:lnum) > -1 && !s:settings.dynamic_folds
"
" This is the beginning of a folded block (with no dynamic folding)
- "
- let s:new = s:numcol . foldtextresult(s:lnum)
+ 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))
endif
- let s:new = s:HtmlFormat(s:new, "Folded", "")
+ " 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:HtmlFormat_t(s:new, s:FOLDED_ID, 0)
" Skip to the end of the fold
let s:new_lnum = foldclosedend(s:lnum)
@@ -851,38 +1316,46 @@ 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 . ""
- let s:new = s:new . repeat('|', s:allfolds[0].level - 1) . ""
+ let s:new = s:new . s:FoldColumn_build('|', s:allfolds[0].level - 1, 0, "",
+ \ 'toggle-open FoldColumn','javascript:toggleFold("fold'.s:foldstack[0].id.'");')
endif
- let s:new = s:new . "+"
- let s:new = s:new . ""
- let s:new = s:new . repeat(" ", s:foldcolumn - s:allfolds[0].level) . ""
+ 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.'");')
" add fold column that can close the new fold
- let s:new = s:new . ""
- if s:firstfold
- let s:new = s:new . repeat('|', s:allfolds[0].level - 1)
- endif
- let s:new = s:new . "-"
- " only add spaces if we aren't opening another fold on the same line
+ " only add extra blank space if we aren't opening another fold on the
+ " same line
if get(s:allfolds, 1, {'firstline': 0}).firstline != s:lnum
- let s:new = s:new . repeat(" ", s:foldcolumn - s:allfolds[0].level)
+ let s:extra_space = s:foldcolumn - s:allfolds[0].level
+ else
+ let s:extra_space = 0
+ endif
+ 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.'");')
+ 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.'");')
endif
- let s:new = s:new . ""
let s:firstfold = 0
endif
- " add fold text, moving the span ending to the next line so collapsing
- " of folds works correctly
- let s:new = s:new . substitute(s:HtmlFormat(s:numcol . foldtextresult(s:lnum), "Folded", ""), '', s:HtmlEndline.'\n\0', '')
+ " 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) : "") . substitute(s:HtmlFormat_t(foldtextresult(s:lnum), s:FOLDED_ID, 0), '', s:HtmlEndline.'\n\0', '')
let s:new = s:new . ""
" open the fold now that we have the fold text to allow retrieval of
@@ -902,14 +1375,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:HtmlFormat(repeat(' ', s:foldcolumn), "FoldColumn", "")
+ 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 . ""
- let s:new = s:new . repeat('|', s:foldstack[0].level)
- let s:new = s:new . repeat(' ', s:foldcolumn - s:foldstack[0].level) . ""
+ 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.'");')
endif
endif
endif
@@ -917,8 +1389,7 @@ while s:lnum <= s:end
" Now continue with the unfolded line text
if s:settings.number_lines
- " TODO: why not use the real highlight name here?
- let s:new = s:new . s:HtmlFormat(s:numcol, "lnr", "")
+ let s:new = s:new . s:HtmlFormat_n(s:numcol, s:LINENR_ID, 0)
endif
" Get the diff attribute, if any.
@@ -932,7 +1403,6 @@ while s:lnum <= s:end
" most of the time we won't use the diff_id, initialize to zero
let s:diff_id = 0
- let s:diff_id_name = ""
while s:col <= s:len || (s:col == 1 && s:diffattr)
let s:startcol = s:col " The start column for processing text
@@ -1000,20 +1470,16 @@ while s:lnum <= s:end
" get the highlight group name to use
let s:id = synIDtrans(s:id)
- let s:id_name = synIDattr(s:id, "name", s:whatterm)
- if s:diff_id
- let s:diff_id_name = synIDattr(s:diff_id, "name", s:whatterm)
- endif
else
" use Conceal highlighting for concealed text
- let s:id_name = 'Conceal'
+ let s:id = s:CONCEAL_ID
let s:expandedtab = s:concealinfo[1]
endif
- " Output the text with the same synID, with class set to {s:id_name},
- " unless it has been concealed completely.
+ " 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_name, s:diff_id_name)
+ let s:new = s:new . s:HtmlFormat(s:expandedtab, s:id, s:diff_id, 0)
endif
endwhile
endif
@@ -1038,9 +1504,9 @@ if s:settings.dynamic_folds
endwhile
" add fold column to the style list if not already there
- let s:id = hlID('FoldColumn')
- if index(s:idlist, s:id) == -1
- call insert(s:idlist, s:id)
+ let s:id = s:FOLD_C_ID
+ if !has_key(s:stylelist, s:id)
+ let s:stylelist[s:id] = '.FoldColumn { ' . s:CSS1(s:id) . '}'
endif
endif
@@ -1049,7 +1515,7 @@ if s:settings.no_pre
" Close off the font tag that encapsulates the whole
call extend(s:lines, ["", "", ""])
else
- call extend(s:lines, ["", ""])
+ call extend(s:lines, ["