diff -u -r --new-file runtime/syntax.orig/2html.vim runtime/syntax/2html.vim --- runtime/syntax.orig/2html.vim 2008-07-17 16:03:05.000000000 -0500 +++ runtime/syntax/2html.vim 2009-07-26 06:44:10.000000000 -0500 @@ -1,13 +1,18 @@ " Vim syntax support file " Maintainer: Bram Moolenaar -" Last Change: 2008 Jul 17 +" Last Change: 2009 Jul 14 " (modified by David Ne\v{c}as (Yeti) ) " (XHTML support by Panagiotis Issaris ) " (made w3 compliant by Edd Barrett ) " (added html_font. Edd Barrett ) +" (dynamic folding by Ben Fritz ) " 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 . ""
+
+	  " 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;/