GIF89a;
"]) endif 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 ) . "}" } 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 " ProgressBar Indicator let s:progressbar={} " Progessbar specific functions func! s:ProgressBar(title, max_value, winnr) let pgb=copy(s:progressbar) let pgb.title = a:title.' ' let pgb.max_value = a:max_value let pgb.winnr = a:winnr let pgb.cur_value = 0 let pgb.items = { 'title' : { 'color' : 'Statusline' }, \'bar' : { 'color' : 'Statusline' , 'fillcolor' : 'DiffDelete' , 'bg' : 'Statusline' } , \'counter' : { 'color' : 'Statusline' } } let pgb.last_value = 0 let pgb.needs_redraw = 0 " Note that you must use len(split) instead of len() if you want to use " unicode in title. " " Subtract 3 for spacing around the title. " Subtract 4 for the percentage display. " Subtract 2 for spacing before this. " Subtract 2 more for the '|' on either side of the progress bar let pgb.subtractedlen=len(split(pgb.title, '\zs'))+3+4+2+2 let pgb.max_len = 0 set laststatus=2 return pgb endfun " Function: progressbar.calculate_ticks() {{{1 func! s:progressbar.calculate_ticks(pb_len) if a:pb_len<=0 let pb_len = 100 else let pb_len = a:pb_len endif let self.progress_ticks = map(range(pb_len+1), "v:val * self.max_value / pb_len") endfun "Function: progressbar.paint() func! s:progressbar.paint() " Recalculate widths. let max_len = winwidth(self.winnr) let pb_len = 0 " always true on first call because of initial value of self.max_len if max_len != self.max_len let self.max_len = max_len " Progressbar length let pb_len = max_len - self.subtractedlen call self.calculate_ticks(pb_len) let self.needs_redraw = 1 let cur_value = 0 let self.pb_len = pb_len else " start searching at the last found index to make the search for the " appropriate tick value normally take 0 or 1 comparisons let cur_value = self.last_value let pb_len = self.pb_len endif let cur_val_max = pb_len > 0 ? pb_len : 100 " find the current progress bar position based on precalculated thresholds while cur_value < cur_val_max && self.cur_value > self.progress_ticks[cur_value] let cur_value += 1 endwhile " update progress bar if self.last_value != cur_value || self.needs_redraw || self.cur_value == self.max_value let self.needs_redraw = 1 let self.last_value = cur_value let t_color = self.items.title.color let b_fcolor = self.items.bar.fillcolor let b_color = self.items.bar.color let c_color = self.items.counter.color let stl = "%#".t_color."#%-( ".self.title." %)". \"%#".b_color."#". \(pb_len>0 ? \ ('|%#'.b_fcolor."#%-(".repeat(" ",cur_value)."%)". \ '%#'.b_color."#".repeat(" ",pb_len-cur_value)."|"): \ ('')). \"%=%#".c_color."#%( ".printf("%3.d ",100*self.cur_value/self.max_value)."%% %)" call setwinvar(self.winnr, '&stl', stl) endif endfun func! s:progressbar.incr( ... ) let self.cur_value += (a:0 ? a:1 : 1) " if we were making a general-purpose progress bar, we'd need to limit to a " lower limit as well, but since we always increment with a positive value " in this script, we only need limit the upper value let self.cur_value = (self.cur_value > self.max_value ? self.max_value : self.cur_value) call self.paint() endfun " }}} if s:settings.dynamic_folds " to process folds we make two passes through each line let s:pgb = s:ProgressBar("Processing folds:", line('$')*2, s:orgwin) endif endif " 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 s:settings.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 setlocal 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 " 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 if !s:settings.no_progress call s:pgb.incr() if s:pgb.needs_redraw redrawstatus let s:pgb.needs_redraw = 0 endif endif 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 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 if !s:settings.no_progress call s:pgb.incr() if s:pgb.needs_redraw redrawstatus let s:pgb.needs_redraw = 0 endif endif 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 &l:foldtext = s:foldtext_save unlet s:foldtext_save " close all folds again so we can get the fold text as we go silent! %foldclose! " Go through and remove folds we don't need to (or cannot) process in the " current conversion range " " If a fold is removed which contains other folds, which are included, we need " to adjust the level of the included folds as used by the conversion logic " (avoiding special cases is good) " " Note any time we remove a fold, either all of the included folds are in it, " or none of them, because we only remove a fold if neither its start nor its " end are within the conversion range. let leveladjust = 0 for afold in s:allfolds let removed = 0 if exists("g:html_start_line") && exists("g:html_end_line") if afold.firstline < g:html_start_line if afold.lastline <= g:html_end_line && afold.lastline >= g:html_start_line " if a fold starts before the range to convert but stops within the " range, we need to include it. Make it start on the first converted " line. let afold.firstline = g:html_start_line else " if the fold lies outside the range or the start and stop enclose " the entire range, don't bother parsing it call remove(s:allfolds, index(s:allfolds, afold)) let removed = 1 if afold.lastline > g:html_end_line let leveladjust += 1 endif endif elseif afold.firstline > g:html_end_line " If the entire fold lies outside the range we need to remove it. call remove(s:allfolds, index(s:allfolds, afold)) let removed = 1 endif elseif exists("g:html_start_line") if afold.firstline < g:html_start_line " if there is no last line, but there is a first line, the end of the " fold will always lie within the region of interest, so keep it let afold.firstline = g:html_start_line endif elseif exists("g:html_end_line") " if there is no first line we default to the first line in the buffer so " the fold start will always be included if the fold itself is included. " If however the entire fold lies outside the range we need to remove it. if afold.firstline > g:html_end_line call remove(s:allfolds, index(s:allfolds, afold)) let removed = 1 endif endif if !removed let afold.level -= leveladjust if afold.level+1 > s:foldcolumn let s:foldcolumn = afold.level+1 endif endif endfor " if we've removed folds containing the conversion range from processing, " getting foldtext as we go won't know to open the removed folds, so the " foldtext would be wrong; open them now. " " 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" let leveladjust -= 1 endwhile 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("g:html_start_line") let s:lnum = html_start_line if s:lnum < 1 || s:lnum > line("$") let s:lnum = 1 endif else let s:lnum = 1 endif if exists("g:html_end_line") let s:end = html_end_line if s:end < s:lnum || s:end > line("$") let s:end = line("$") endif else let s:end = line("$") endif " stack to keep track of all the folds containing the current line let s:foldstack = [] if !s:settings.no_progress let s:pgb = s:ProgressBar("Processing lines:", s:end - s:lnum + 1, s:orgwin) endif if s:settings.number_lines let s:margin = strlen(s:end) + 1 else let s:margin = 0 endif if has('folding') && !s:settings.ignore_folding let s:foldfillchar = &fillchars[matchend(&fillchars, 'fold:')] if s:foldfillchar == '' let s:foldfillchar = '-' endif endif let s:difffillchar = &fillchars[matchend(&fillchars, 'diff:')] if s:difffillchar == '' let s:difffillchar = '-' endif let s:foldId = 0 if !s:settings.expand_tabs " If keeping tabs, add them to printable characters so we keep them when " formatting text (strtrans() doesn't replace printable chars) let s:old_isprint = &isprint setlocal isprint+=9 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 " Start the line with the line number. if s:settings.number_lines let s:numcol = repeat(' ', s:margin - 1 - strlen(s:lnum)) . s:lnum . ' ' endif let s:new = "" 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 = 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 " 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) " Skip to the end of the fold let s:new_lnum = foldclosedend(s:lnum) if !s:settings.no_progress call s:pgb.incr(s:new_lnum - s:lnum) endif let s:lnum = s:new_lnum else " " A line that is not folded, or doing dynamic folding. " let s:line = getline(s:lnum) let s:len = strlen(s:line) 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."" call remove(s:foldstack, 0) endwhile " Now insert an opening for 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 .= "" " 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 !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.'");') 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.'");') " 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.'");') " add fold column that can close the new fold " 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: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.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.'");') endif let s:firstfold = 0 endif " 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), '', s:HtmlEndline.'\n\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 !s:settings.no_foldcolumn if empty(s:foldstack) " 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() 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.'");') endif endif endif endif " 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) elseif s:settings.line_ids let s:new = s:new . s:HtmlFormat_n("", s:LINENR_ID, 0, s:lnum) endif " Get the diff attribute, if any. let s:diffattr = diff_hlID(s:lnum, 1) " initialize conceal info to act like not concealed, just in case let s:concealinfo = [0, ''] " Loop over each character in the line let s:col = 1 " most of the time we won't use the diff_id, initialize to zero let s:diff_id = 0 while s:col <= s:len || (s:col == 1 && s:diffattr) let s:startcol = s:col " The start column for processing text if !s:settings.ignore_conceal && has('conceal') let s:concealinfo = synconcealed(s:lnum, s:col) endif if !s:settings.ignore_conceal && s:concealinfo[0] let s:col = s:col + 1 " Speed loop (it's small - that's the trick) " Go along till we find a change in the match sequence number (ending " the specific concealed region) or until there are no more concealed " characters. while s:col <= s:len && s:concealinfo == synconcealed(s:lnum, s:col) | let s:col = s:col + 1 | endwhile elseif s:diffattr let s:diff_id = diff_hlID(s:lnum, s:col) let s:id = synID(s:lnum, s:col, 1) let s:col = s:col + 1 " Speed loop (it's small - that's the trick) " Go along till we find a change in hlID while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) \ && s:diff_id == diff_hlID(s:lnum, s:col) | \ let s:col = s:col + 1 | \ endwhile 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:len = &columns endif else let s:id = synID(s:lnum, s:col, 1) let s:col = s:col + 1 " Speed loop (it's small - that's the trick) " Go along till we find a change in synID while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) | let s:col = s:col + 1 | endwhile endif if s:settings.ignore_conceal || !s:concealinfo[0] " Expand tabs if needed let s:expandedtab = strpart(s:line, s:startcol - 1, s:col - s:startcol) if s:settings.expand_tabs 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 end " get the highlight group name to use let s:id = synIDtrans(s:id) else " use Conceal highlighting for concealed text let s:id = s:CONCEAL_ID let s:expandedtab = s:concealinfo[1] endif " 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) endif endwhile endif call extend(s:lines, split(s:new.s:HtmlEndline, '\n', 1)) if !s:settings.no_progress && s:pgb.needs_redraw redrawstatus let s:pgb.needs_redraw = 0 endif let s:lnum = s:lnum + 1 if !s:settings.no_progress call s:pgb.incr() endif endwhile if s:settings.dynamic_folds " finish off any open folds while !empty(s:foldstack) let s:lines[-1].="" 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) . '}' endif endif if s:settings.no_pre if !s:settings.use_css " Close off the font tag that encapsulates the whole call extend(s:lines, ["", "", ""]) else call extend(s:lines, ["