)
" Transform a file into HTML, using the current syntax highlighting.
+" this file uses line continuations
+let s:cpo_sav = &cpo
+set cpo-=C
+
" Number lines when explicitely requested or when `number' is set
if exists("html_number_lines")
let s:numblines = html_number_lines
@@ -22,6 +27,37 @@
let s:htmlfont = "monospace"
endif
+" make copies of the user-defined settings that we may overrule
+if exists("html_dynamic_folds")
+ let s:html_dynamic_folds = 1
+endif
+if exists("html_hover_unfold")
+ let s:html_hover_unfold = 1
+endif
+if exists("html_use_css")
+ let s:html_use_css = 1
+endif
+
+" hover opening implies dynamic folding
+if exists("s:html_hover_unfold")
+ let s:html_dynamic_folds = 1
+endif
+
+" dynamic folding with no foldcolumn implies hover opens
+if exists("s:html_dynamic_folds") && exists("html_no_foldcolumn")
+ let s:html_hover_unfold = 1
+endif
+
+" ignore folding overrides dynamic folding
+if exists("html_ignore_folding") && exists("s:html_dynamic_folds")
+ unlet s:html_dynamic_folds
+endif
+
+" dynamic folding implies css
+if exists("s:html_dynamic_folds")
+ let s:html_use_css = 1
+endif
+
" When not in gui we can only guess the colors.
if has("gui_running")
let s:whatterm = "gui"
@@ -62,7 +98,7 @@
endfun
endif
-if !exists("html_use_css")
+if !exists("s:html_use_css")
" Return opening HTML tag for given highlight id
function! s:HtmlOpening(id)
let a = ""
@@ -150,6 +186,26 @@
return a
endfun
+if exists("s:html_dynamic_folds")
+
+ " compares two folds as stored in our list of folds
+ " A fold is "less" than another if it starts at an earlier line number,
+ " or ends at a later line number, ties broken by fold level
+ function! s:FoldCompare(f1, f2)
+ if a:f1.firstline != a:f2.firstline
+ " put it before if it starts earlier
+ return a:f1.firstline - a:f2.firstline
+ elseif a:f1.lastline != a:f2.lastline
+ " put it before if it ends later
+ return a:f2.lastline - a:f1.lastline
+ else
+ " if folds begin and end on the same lines, put lowest fold level first
+ return a:f1.level - a:f2.level
+ endif
+ endfunction
+
+endif
+
" Figure out proper MIME charset from the 'encoding' option.
if exists("html_use_encoding")
let s:html_encoding = html_use_encoding
@@ -223,13 +279,13 @@
let s:tag_close = '>'
endif
-" Cache html_no_pre incase we have to turn it on for non-css mode
+" Cache html_no_pre in case we have to turn it on for non-css mode
if exists("html_no_pre")
let s:old_html_no_pre = html_no_pre
endif
-if !exists("html_use_css")
- " Cant put font tags in
+if !exists("s:html_use_css")
+ " Can't put font tags in
let html_no_pre=1
endif
@@ -251,9 +307,86 @@
exe "normal! a\n\n\n\e"
+if exists("s:html_use_css")
+ if exists("s:html_dynamic_folds")
+ if exists("s:html_hover_unfold")
+ " if we are doing hover_unfold, use css 2 with css 1 fallback for IE6
+ exe "normal! a".
+ \ "\n"
+ exe "normal! a\n"
+ else
+ " if we aren't doing hover_unfold, use CSS 1 only
+ exe "normal! a\n"
+ endif
+ else
+ " if we aren't doing any dynamic folding, no need for any special rules
+ exe "normal! a\n\e"
+ endif
+endif
+
+" insert javascript to toggle folds open and closed
+if exists("s:html_dynamic_folds")
+ exe "normal! a\n".
+ \ "\n\e"
endif
+
if exists("html_no_pre")
exe "normal! a\n\n\e"
else
@@ -265,7 +398,81 @@
" List of all id's
let s:idlist = ","
-" Loop over all lines in the original text.
+" 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 = []
+
+if exists("s:html_dynamic_folds")
+ let s:lnum = 1
+ let s:end = line('$')
+ " save the fold text and set it to the default so we can find fold levels
+ let s:foldtext_save = &foldtext
+ set foldtext&
+
+ " we will set the foldcolumn in the html to the greater of the maximum fold
+ " level and the current foldcolumn setting
+ let s:foldcolumn = &foldcolumn
+
+ " get all info needed to describe currently closed folds
+ while s:lnum < s:end
+ if foldclosed(s:lnum) == s:lnum
+ " default fold text has '+-' and then a number of dashes equal to fold
+ " level, so subtract 2 from index of first non-dash after the dashes
+ " in order to get the fold level of the current fold
+ let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2
+ if s:level+1 > s:foldcolumn
+ let s:foldcolumn = s:level+1
+ endif
+ " store fold info for later use
+ 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"
+ else
+ let s:lnum = s:lnum + 1
+ endif
+ endwhile
+
+ " close all folds to get info for originally open folds
+ silent! %foldclose!
+ let s:lnum = 1
+
+ " the originally open folds will be all folds we encounter that aren't
+ " already in the list of closed folds
+ while s:lnum < s:end
+ if foldclosed(s:lnum) == s:lnum
+ " default fold text has '+-' and then a number of dashes equal to fold
+ " level, so subtract 2 from index of first non-dash after the dashes
+ " in order to get the fold level of the current fold
+ let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2
+ if s:level+1 > s:foldcolumn
+ let s:foldcolumn = s:level+1
+ endif
+ let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"}
+ " only add the fold if we don't already have it
+ if empty(s:allfolds) || index(s:allfolds, s:newfold) == -1
+ let s:newfold.type = "open-fold"
+ call add(s:allfolds, s:newfold)
+ endif
+ " open the fold so we can find any contained folds
+ execute s:lnum."foldopen"
+ else
+ let s:lnum = s:lnum + 1
+ endif
+ endwhile
+
+ " sort the folds so that we only ever need to look at the first item in the
+ " list of folds
+ call sort(s:allfolds, "s:FoldCompare")
+
+ let &foldtext = s:foldtext_save
+ unlet s:foldtext_save
+
+ " close all folds again so we can get the fold text as we go
+ silent! %foldclose!
+endif
+
+" Now loop over all lines in the original text to convert to html.
" Use html_start_line and html_end_line if they are set.
if exists("html_start_line")
let s:lnum = html_start_line
@@ -284,6 +491,15 @@
let s:end = line("$")
endif
+" stack to keep track of all the folds containing the current line
+let s:foldstack = []
+
+if s:numblines
+ let s:margin = strlen(s:end) + 1
+else
+ let s:margin = 0
+endif
+
if has('folding') && !exists('html_ignore_folding')
let s:foldfillchar = &fillchars[matchend(&fillchars, 'fold:')]
if s:foldfillchar == ''
@@ -295,6 +511,7 @@
let s:difffillchar = '-'
endif
+let s:foldId = 0
while s:lnum <= s:end
@@ -303,12 +520,7 @@
if s:filler > 0
let s:n = s:filler
while s:n > 0
- if s:numblines
- " Indent if line numbering is on
- let s:new = repeat(s:LeadingSpace, strlen(s:end) + 1) . repeat(s:difffillchar, 3)
- else
- let s:new = repeat(s:difffillchar, 3)
- endif
+ let s:new = repeat(s:difffillchar, 3)
if s:n > 2 && s:n < s:filler && !exists("html_whole_filler")
let s:new = s:new . " " . s:filler . " inserted lines "
@@ -317,10 +529,16 @@
if !exists("html_no_pre")
" HTML line wrapping is off--go ahead and fill to the margin
- let s:new = s:new . repeat(s:difffillchar, &columns - strlen(s:new))
+ 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")
+ if s:numblines
+ " Indent if line numbering is on; must be after escaping.
+ let s:new = repeat(s:LeadingSpace, s:margin) . s:new
+ endif
exe s:newwin . "wincmd w"
exe "normal! a" . s:new . s:HtmlEndline . "\n\e"
exe s:orgwin . "wincmd w"
@@ -333,16 +551,18 @@
" Start the line with the line number.
if s:numblines
- let s:new = repeat(' ', strlen(s:end) - strlen(s:lnum)) . s:lnum . ' '
+ let s:numcol = repeat(' ', s:margin - 1 - strlen(s:lnum)) . s:lnum . ' '
else
- let s:new = ""
+ let s:numcol = ""
endif
- if has('folding') && !exists('html_ignore_folding') && foldclosed(s:lnum) > -1
+ let s:new = ""
+
+ if has('folding') && !exists('html_ignore_folding') && foldclosed(s:lnum) > -1 && !exists('s:html_dynamic_folds')
"
- " This is the beginning of a folded block
+ " This is the beginning of a folded block (with no dynamic folding)
"
- let s:new = s:new . foldtextresult(s:lnum)
+ let s:new = s:numcol . foldtextresult(s:lnum)
if !exists("html_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))
@@ -355,14 +575,96 @@
else
"
- " A line that is not folded.
+ " A line that is not folded, or doing dynamic folding.
"
let s:line = getline(s:lnum)
-
let s:len = strlen(s:line)
+ if exists("s:html_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.""
+ call remove(s:foldstack, 0)
+ endwhile
+
+ " Now insert an opening any new folds that start on this line
+ let s:firstfold = 1
+ while !empty(s:allfolds) && get(s:allfolds,0).firstline == s:lnum
+ let s:foldId = s:foldId + 1
+ let s:new = s:new . ""
+
+ " Unless disabled, add a fold column for the opening line of a fold.
+ "
+ " Note that dynamic folds require using css so we just use css to take
+ " care of the leading spaces rather than using in the case of
+ " html_no_pre to make it easier
+ if !exists("html_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) . ""
+ endif
+ let s:new = s:new . "+"
+ let s:new = s:new . ""
+ let s:new = s:new . repeat(" ", s:foldcolumn - s:allfolds[0].level) . ""
+
+ " 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
+ if get(s:allfolds, 1, {'firstline': 0}).firstline != s:lnum
+ let s:new = s:new . repeat(" ", s:foldcolumn - s:allfolds[0].level)
+ 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.'\r\0', '')
+ let s:new = s:new . ""
+
+ " open the fold now that we have the fold text to allow retrieval of
+ " fold text for subsequent folds
+ execute s:lnum."foldopen"
+ call insert(s:foldstack, remove(s:allfolds,0))
+ let s:foldstack[0].id = s:foldId
+ endwhile
+
+ " Unless disabled, add a fold column for other lines.
+ "
+ " Note that dynamic folds require using css so we just use css to take
+ " care of the leading spaces rather than using in the case of
+ " html_no_pre to make it easier
+ if !exists("html_no_foldcolumn")
+ if empty(s:foldstack)
+ " add the empty foldcolumn for unfolded lines
+ let s:new = s:new . s:HtmlFormat(repeat(' ', s:foldcolumn), "FoldColumn")
+ 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) . ""
+ endif
+ endif
+ endif
+ endif
+
+ " Now continue with the unfolded line text
if s:numblines
- let s:new = s:HtmlFormat(s:new, "lnr")
+ let s:new = s:new . s:HtmlFormat(s:numcol, "lnr")
endif
" Get the diff attribute, if any.
@@ -380,7 +682,7 @@
while s:col <= s:len && s:id == diff_hlID(s:lnum, s:col) | let s:col = s:col + 1 | endwhile
if s:len < &columns && !exists("html_no_pre")
" Add spaces at the end to mark the changed line.
- let s:line = s:line . repeat(' ', &columns - s:len)
+ let s:line = s:line . repeat(' ', &columns - virtcol([s:lnum, s:len]) - s:margin)
let s:len = &columns
endif
else
@@ -393,11 +695,27 @@
" Expand tabs
let s:expandedtab = strpart(s:line, s:startcol - 1, s:col - s:startcol)
- let idx = stridx(s:expandedtab, "\t")
- while idx >= 0
- let i = &ts - ((idx + s:startcol - 1) % &ts)
- let s:expandedtab = substitute(s:expandedtab, '\t', repeat(' ', i), '')
- let idx = stridx(s:expandedtab, "\t")
+ let s:offset = 0
+ let s:idx = stridx(s:expandedtab, "\t")
+ while s:idx >= 0
+ if has("multi_byte_encoding")
+ if s:startcol + s:idx == 1
+ let s:i = &ts
+ else
+ if s:idx == 0
+ let s:prevc = matchstr(s:line, '.\%' . (s:startcol + s:idx + s:offset) . 'c')
+ else
+ 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)])
+ let s:i = &ts - (s:vcol % &ts)
+ endif
+ let s:offset -= s:i - 1
+ else
+ let s:i = &ts - ((s:idx + s:startcol - 1) % &ts)
+ endif
+ let s:expandedtab = substitute(s:expandedtab, '\t', repeat(' ', s:i), '')
+ let s:idx = stridx(s:expandedtab, "\t")
endwhile
" Output the text with the same synID, with class set to {s:id_name}
@@ -415,8 +733,22 @@
" Finish with the last line
exe s:newwin . "wincmd w"
+if exists("s:html_dynamic_folds")
+ " finish off any open folds
+ while !empty(s:foldstack)
+ exe "normal! a"
+ call remove(s:foldstack, 0)
+ endwhile
+
+ " add fold column to the style list if not already there
+ let s:id = hlID('FoldColumn')
+ if stridx(s:idlist, "," . s:id . ",") == -1
+ let s:idlist = s:idlist . s:id . ","
+ endif
+endif
+
" Close off the font tag that encapsulates the whole
-if !exists("html_use_css")
+if !exists("s:html_use_css")
exe "normal! a\e"
endif
@@ -428,7 +760,7 @@
" Now, when we finally know which, we define the colors and styles
-if exists("html_use_css")
+if exists("s:html_use_css")
1;/