download

Sign in or create your account | Project List | Help

download Git Source Tree

Root/ScreenShot_mb.vim

1" Copyright (c) 2006, Michael Shvarts <shvarts@akmosoft.com>
2"
3"{{{-----------License:
4" ScreenShot.vim is free software; you can redistribute it and/or modify it under
5" the terms of the GNU General Public License as published by the Free
6" Software Foundation; either version 2, or (at your option) any later
7" version.
8"
9" ScreenShot.vim is distributed in the hope that it will be useful, but WITHOUT ANY
10" WARRANTY; without even the implied warranty of MERCHANTABILITY or
11" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12" for more details.
13"
14" You should have received a copy of the GNU General Public License along
15" with ScreenShot.vim; see the file COPYING. If not, write to the Free Software
16" Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
17"}}}
18"{{{-----------Info:
19" Version: 0.8
20" Description:
21" Generates screenshot of your current VIM session as HTML code
22"
23" FEEDBACK PLEASE
24"
25" Installation: Drop it into your plugin directory
26"
27" History:
28" 0.7: Initial upload
29" 0.8:
30" Added:
31" a) Full 'nowrap' option support
32" b) Non-printable characters support
33" c) 'showbreak' option support
34" d) 'display' option support (lastline and uhex both)
35" e) 'list' option support
36" 0.9:
37" Added:
38" a)Custom statusline (i.e. 'stl' option support)
39" b)Tabline bar(only for console or if 'guioptions' does not contain 'e'). Custom tabline also supported
40" c)Title bar with VIM logo (can be disabled). Custom title(i.e. option 'titlestring') also supported
41" d)Credits in right bottom corner(can be disabled)
42" 1.0:
43" Added:
44" a)Diff mode support
45" b)New command Diff2Html
46" 1.01:
47" Fixed:
48" 1. Italic, bold and underline was broken in 1.0 version, now repaired
49" 2. Proper highligting of number of buffers in tabline
50" 3. Proper rendering of too long tabline or too long titleline
51" 4. Proper title for 'nofile' current buffer
52" 1.02:
53" Fixed:
54" Reverse attribute improper handling in some cases
55" 1.03: A few bugfixes by Cyril Slobin <slobin@ice.ru>
56" Fixed:
57" 1. Unqualified variables in statusline are treated as global now
58" 3. When encoding is set to utf-8, non-ASCII letters are displayed now
59" 4. Flag options like [+] long ago haven't space before them, fixea
60" Fixed: (by MS)
61" 5. Incorrect highlighting in the case when foreground set and
62" background unset and reverse attribute set
63" 6. Incorrect HTML when vim compiled with gui but running in terminal
64" Added:
65" 7. Support for 256-color xterm added
66" 1.04:
67" Fixed:
68" 1. Proper colors for DOS and win32 console versions(suggestion by Cyril Slobin <slobin@ice.ru>)
69" 2. Black color is now default for background in console, even if no
70" "reverse" attribute set, because it is typical behaviour of terminals.
71" Added:
72" 3. 'force_background' option added to g:ScreenShot dictionary to enable
73" user to adjust HTML-generation to terminal behaviour distinct from typical.
74" (color should be specified as a string in HTML format #RRGGBB)
75" 1.05:
76" Added:
77" Good multibyte support(thanks Cyril Slobin <slobin@ice.ru> for suggestion)
78" 1.06:
79" Fixed:
80" 1. Folds are displayed correctly now(was broken in 1.05)
81" 2. Unprintable unicode chracters are displayed correctly now
82" 1.07:
83" Html size optimized
84" Fixed:
85" 1. Status line %V item
86" 2. Proper embedding in HTML page with defined default color
87"
88""
89" TODO:
90" 1.Very small windows proper rendering
91" 2.Linebreak option support
92" }}}
93"{{{-----------Status Line
94function! s:Dump(var,...)
95    let indent = a:0?(a:1):0
96    if type(a:var) == type({})
97        return "\n".repeat(' ',indent)."{\n".repeat(' ',indent).join(map(copy(items(a:var)),'string(v:val[0]).": ".Dump(v:val[1],indent + 4)'), ',')."\n".repeat(' ',indent)."}\n"
98    elseif type(a:var) == type([])
99        return "\n".repeat(' ',indent)."[\n".repeat(' ',indent).join(map(copy(a:var),'Dump(v:val,indent + 4)'),', ')."\n".repeat(' ',indent)."]\n"
100    else
101        return string(a:var)
102    endif
103
104endf
105function! s:Sum(array)
106    return len(a:array)?eval(join(map(copy(a:array),'strlen(v:val.value)'),' + ')):0
107endf
108
109let s:PrintfNode = {'type': ''}
110function! s:PrintfNode.Value()
111    if self.name == ''
112        return ''
113    elseif has_key(self,'expr')
114        return eval(self.expr)
115    endif
116    return '[unimplemented]'
117endf
118function! s:PrintfNode.Render(hi,lasttype,fillchar,invischar)
119    let res = self.Value()
120    if self.type == 'flag' && (res =~ '^,' && a:lasttype == 'plain' || res =~ '^ ' && a:lasttype == 'flag' || a:lasttype == 'start')
121        let res = strpart(res, 1)
122    endif
123    if strlen(self.minwid)&& strlen(res) < self.minwid
124        if self.left
125            let res .= repeat(a:fillchar, self.minwid - strlen(res))
126        else
127            let res = repeat(self.type=='num'&&self.zeropad?'0': a:fillchar, self.minwid - strlen(res)).res
128        endif
129    elseif strlen(self.maxwid) && strlen(res) > self.maxwid
130        let res = strpart(a:invischar.strpart(res,strlen(res) - self.maxwid + strlen(a:invischar)),0, self.maxwid)
131    endif
132    return [{'value': res,'hi': a:hi,'lasttype': (strlen(res)?(self.type):(a:lasttype))}]
133endf
134function! CopyArgs(args,...)
135    return filter((a:0)?extend(copy(a:args),map(eval('{'.join(map(items(filter(deepcopy(a:),'has_key(a:args,v:key)&&type(v:val) == type("")')),'string(v:val[1]).":".string(v:val[0])'),',').'}'), 'a:args[v:val[0]]')):copy(a:args),'v:key !~ "\\v^(\\d+|firstline|lastline)$"')
136endf
137function! s:PrintfNode.New(name,left,zeropad,minwid,maxwid,...)
138    return map(extend(has_key(s:Nodes,a:name)?(deepcopy(s:Nodes[a:name])):deepcopy(self),CopyArgs(a:,'value','root')), "v:key == 'minwid'&& a:0 < 2 && v:val > 50?50:(v:val)")
139endf
140let s:StringNode = extend({'type': 'str'},s:PrintfNode,'keep')
141let s:NumericNode = extend({'type': 'num'},s:PrintfNode,'keep')
142let s:FlagNode = extend({'type': 'flag'},s:StringNode,'keep')
143
144unlet s:FlagNode.Value
145function! s:FlagNode.Value()
146    if has_key(self,'expr')
147        let res = eval(self.expr)
148        if type(res) == type(1)
149            let res = res?(self.on):self.off
150        endif
151        return !strlen(res)?'':self.name =~ '\U'?' ['.res.']': ','.res
152    endif
153    return '[unimplemented]'
154endf
155
156let s:Nodes = {'f': copy(s:StringNode),
157            \'F': copy(s:StringNode),
158            \'t': copy(s:StringNode),
159            \'m': extend({'name': 'm','expr': '&modified','on': '+','off': '-'} ,s:FlagNode),
160            \'M': extend({'name': 'M','expr': '&modified','on': '+','off': '-'} ,s:FlagNode),
161            \'r': extend({'name': 'r','expr': '&readonly','on': 'RO','off': ''} ,s:FlagNode),
162            \'R': extend({'name': 'R','expr': '&readonly','on': 'RO','off': ''} ,s:FlagNode),
163            \'h': extend({'name': 'h','expr': '&buftype == "help"','on': 'help','off': ''} ,s:FlagNode),
164            \'H': extend({'name': 'H','expr': '&buftype == "help"','on': 'HLP','off': ''} ,s:FlagNode),
165            \'w': extend({'name': 'w','expr': '&previewwindow','on': 'Preview','off': ''} ,s:FlagNode),
166            \'W': extend({'name': 'W','expr': '&previewwindow','on': 'PRV','off': ''} ,s:FlagNode),
167            \'y': extend({'name': 'y','expr': '&filetype' } ,s:FlagNode),
168            \'Y': extend({'name': 'Y','expr': 'toupper(&filetype)'} ,s:FlagNode),
169            \'k': extend({'expr': '""'}, s:StringNode ),
170            \'n': extend({'expr': 'bufnr("%")'}, s:NumericNode),
171            \'b': copy(s:NumericNode),
172            \'B': copy(s:NumericNode),
173            \'o': copy(s:NumericNode),
174            \'O': copy(s:NumericNode),
175            \'N': copy(s:NumericNode),
176            \'l': extend({'expr': "line('.')" }, s:NumericNode),
177            \'L': extend({'expr': "line('$')" }, s:NumericNode),
178            \'c': extend({'expr': "col('$') - 1?col('.'):0" }, s:NumericNode),
179            \'v': extend({'expr': "virtcol('.')" }, s:NumericNode),
180            \'V': copy(s:StringNode),
181            \'p': copy(s:NumericNode),
182            \'P': copy(s:StringNode),
183            \'a': copy(s:StringNode),
184            \'{': copy(s:StringNode),
185            \'(': copy(s:PrintfNode),
186            \')': copy(s:PrintfNode),
187            \'T': copy(s:PrintfNode),
188            \'X': copy(s:NumericNode),
189            \'<': copy(s:PrintfNode),
190            \'=': copy(s:PrintfNode),
191            \'#': extend(copy(s:PrintfNode),{'type': 'hi'}),
192            \'*': extend(copy(s:PrintfNode),{'type': 'hi'})}
193unlet s:Nodes.T.Render
194function! s:Nodes.T.Render(hi,lasttype,fillchar,invischar)
195    return [{'value': '', 'hi': a:hi,'lasttype': a:lasttype}]
196endf
197unlet s:Nodes.M.Value
198function! s:Nodes.M.Value()
199    if !eval(self.expr) && !strlen(&buftype)
200        return ''
201    endif
202    return call(s:FlagNode.Value, [], self)
203endf
204let s:Nodes.m.Value = s:Nodes.M.Value
205unlet s:Nodes.f.Value
206function! s:Nodes.f.Value() " Path to the file in the buffer, relative to current directory.
207    return strlen(bufname('%'))?fnamemodify(bufname('%'),':.'): '[No Name]'
208endf
209unlet s:Nodes.F.Value
210function! s:Nodes.F.Value() " Full path to the file in the buffer.
211    return strlen(bufname('%'))?fnamemodify(bufname('%'),':p'): '[No Name]'
212endf
213unlet s:Nodes.t.Value
214function! s:Nodes.t.Value() " File name (tail) of file in the buffer.
215    return strlen(bufname('%'))?fnamemodify(bufname('%'),':t'): '[No Name]'
216endf
217unlet s:Nodes.k.Value
218function! s:Nodes.k.Value() " Value of \"b:keymap_name\" or 'keymap' when |:lmap| mappings are being used: \"<keymap>\"
219    return
220endf
221unlet s:Nodes.n.Value
222function! s:Nodes.n.Value() " Buffer number.
223    return bufnr('%')
224endf
225unlet s:Nodes.b.Value
226function! s:Nodes.b.Value() " Value of byte under cursor.
227    return char2nr(strpart(getline('.'),col('.')-1,1))
228endf
229unlet s:Nodes.B.Value
230function! s:Nodes.B.Value() " As above, in hexadecimal.
231    return printf('%x',s:Nodes.b.Value())
232endf
233unlet s:Nodes.o.Value
234function! s:Nodes.o.Value() " Byte number in file of byte under cursor, first byte is 1. Mnemonic: Offset from start of file (with one added) {not available when compiled without |+byte_offset| feature}
235    return line2byte('.') + col('.')
236endf
237unlet s:Nodes.O.Value
238function! s:Nodes.O.Value() " As above, in hexadecimal.
239    return printf('%x',s:Nodes.o.Value())
240endf
241unlet s:Nodes.N.Value
242function! s:Nodes.N.Value() " Printer page number. (Only works in the 'printheader' option.)
243    return
244endf
245unlet s:Nodes.V.Value
246function! s:Nodes.V.Value() " Virtual column number as -{num}. Not displayed if equal to 'c'.
247    return col('.') == virtcol('.')?'': '-'.virtcol('.')
248endf
249unlet s:Nodes.p.Value
250function! s:Nodes.p.Value() " Percentage through file in lines as in |CTRL-G|.
251    return line('.') * 100 / line('$')
252endf
253unlet s:Nodes.P.Value
254function! s:Nodes.P.Value() " Percentage through file of displayed window. This is like the percentage described for 'ruler'. Always 3 in length.
255    return line('w0') == 1?(line('$') == line('w$')?'All': 'Top'):line('w$') == line('$')?'Bot': printf('%02s',line('w0')*100/(line('$') - line('w$') + line('w0'))).'%'
256endf
257unlet s:Nodes.a.Value
258function! s:Nodes.a.Value() " Argument list status as in default title. ({current} of {max}) Empty if the argument file count is zero or one.
259    return
260endf
261unlet s:Nodes['{'].Value
262function! s:Nodes['{'].Value() " F Evaluate expression between '%{' and '}' and substitute result. Note that there is no '%' before the closing '}'.
263    for s:var in keys(g:)
264        execute "let " . s:var . " = g:" . s:var
265    endfor
266    let s:res = eval(self.value)
267    if type(s:res) == type("")
268        return s:res
269    else
270        return string(s:res)
271    endif
272endf
273function! s:TruncateArray(array,maxwid,left,invischar)
274    let array = a:left?(a:array):reverse(a:array)
275    let i = len(array)
276    let w = 0
277    while i > 0
278        let i -= 1
279        let w += strlen(array[i].value)
280        if w + strlen(a:invischar) >= a:maxwid
281            let array = array[(i):]
282            if a:left
283                let array[0].value = a:invischar.strpart(array[0].value,w - a:maxwid + strlen(a:invischar))
284                return array
285            else
286                let array[0].value = strpart(array[0].value, 0, strlen(array[0].value) - w + a:maxwid - strlen(a:invischar)).a:invischar
287                return reverse(array)
288            endif
289        endif
290
291    endwhile
292endf
293unlet s:Nodes['('].Render
294function! s:Nodes['('].Render(hi,lasttype,fillchar,invischar) " Start of item group. Can be used for setting the width and alignment of a section. Must be followed by %) somewhere.
295    let [hi, lasttype] = [a:hi, a:lasttype]
296    let array = []
297    let i = 0
298    let lt = 0
299    for node in self.value
300        if type(node) == type({})
301            let res = node.Render(hi,lasttype,a:fillchar,'<')
302            if node.name == '='
303                let eq = res[0]
304            elseif node.name == '<'
305                let lt = i
306            endif
307        else
308            let res = strlen(node)?[{'value': node, 'hi': hi, 'lasttype': 'plain'}]:[]
309        endif
310        let array += res
311        let hi = array[len(array) - 1].hi
312        let lasttype = array[len(array) - 1].lasttype
313        unlet node
314        let i += 1
315    endfor
316    let width = s:Sum(array)
317    if strlen(self.minwid) && width < self.minwid
318        let space = repeat(a:fillchar, self.minwid - width)
319        if exists('eq')
320            call extend(eq, {'value': space})
321        elseif self.left
322            let array += [{'value': space, 'hi': array[len(array) - 1].hi,'lasttype': lasttype}]
323        else
324            let array = [{'value': space, 'hi': a:hi,'lasttype': a:lasttype}] + array
325        endif
326    elseif strlen(self.maxwid) && width > self.maxwid
327        if !lt && get(array[0],'lasttype','') != 'plain'
328            let part1 = []
329        else
330            let part1 = array[:lt]
331        endif
332        let maxwid = self.maxwid - s:Sum(part1)
333        if maxwid >= 0
334            let array = part1 + s:TruncateArray(array,maxwid,1,a:invischar)
335        else
336            let array = s:TruncateArray(part1,self.maxwid,0,a:invischar)
337        endif
338    endif
339    return array
340endf
341unlet s:Nodes[')'].Value
342function! s:Nodes[')'].Value() " End of item group. No width fields allowed.
343    return
344endf
345unlet s:Nodes.T.Value
346function! s:Nodes.T.Value() " For 'tabline': start of tab page N label. Use %T after the last label. This information is used for mouse clicks.
347    return ""
348endf
349unlet s:Nodes.X.Value
350function! s:Nodes.X.Value() " For 'tabline': start of close tab N label. Use %X after the label, e.g.: %3Xclose%X. Use %999X for a \"close current tab\" mark. This information is used for mouse clicks.
351    return ""
352endf
353unlet s:Nodes['<'].Value
354function! s:Nodes['<'].Value() " Where to truncate line if too long. Default is at the start. No width fields allowed.
355    return ""
356endf
357unlet s:Nodes['='].Value
358function! s:Nodes['='].Value() " Separation point between left and right aligned items. No width fields allowed.
359    return ""
360endf
361unlet s:Nodes['#'].Render
362function! s:Nodes['#'].Render(hi,lasttype,fillchar,invischar) " Set highlight group. The name must follow and then a # again. Thus use %#HLname# for highlight group HLname. The same highlighting is used, also for the statusline of non-current windows.
363    return [{'value': '', 'hi': self.value,'lasttype': a:lasttype}]
364endf
365unlet s:Nodes['*'].Render
366function! s:Nodes['*'].Render(hi,lasttype,fillchar,invischar) " Set highlight group to User{N}, where {N} is taken from the minwid field, e.g. %1*. Restore normal highlight with %* or %0*. The difference between User{N} and StatusLine will be applied to StatusLineNC for the statusline of non-current windows. The number N must be between 1 and 9. See |hl-User1..9|
367    if !strlen(self.minwid) || !self.minwid
368        return [{'value': '', 'hi': '','lasttype': a:lasttype}]
369    endif
370    return [{'value': '', 'hi': 'User'.self.minwid,'lasttype': a:lasttype}]
371endf
372function! s:StlPrintf(expr,width,fillchar,invischar,hi)
373    let expr = a:expr =~ '^%!'?eval(strpart(a:expr,2)):a:expr
374
375    let str = 's:Nodes["("].New("(",1,0,'.a:width.','.a:width.',['.substitute(expr,'\([^%]*\)\%(%\(-\)\?\(0\)\?\([1-9]\d*\)\?\%(\.\(\d*\)\)\?\([a-zA-Z<=*()]\|{\([^}]*\)}\|#\([^#]*\)#\)\|$\)','\=
376                \(submatch(1) != ""?string(submatch(1)).",": "").
377                \(
378                \ submatch(6) == ")"?"]),": " get(s:Nodes,".string(strpart(submatch(6),0,1)).", s:PrintfNode".
379                \ ").New(".
380                \ string(strpart(submatch(6),0,1)).", ".strlen(submatch(2)).", ".strlen(submatch(3)).", ".string(submatch(4)).", ".string(submatch(5)).
381                \ (submatch(6)=="("?", [":
382                \ strlen(submatch(7))?", ".string(submatch(7))."),":
383                \ strlen(submatch(8))?", ".string(submatch(8))."),":
384                \ "),"
385                \ )
386                \)','g').'], 1)'
387    "echo str
388    let tree = eval(str)
389    "echo Dump(tree)
390    let array = tree.Render('','start',a:fillchar,a:invischar)
391    let res = s:SynIdStart(hlID(a:hi))
392    let id = a:hi
393    let type = 'start'
394    "echo Dump(array)
395    for node in array
396        if node.hi == ''
397            let node.hi = a:hi
398        endif
399        if node.hi != id && node.hi != 'TabLineTitle666'
400            let res .= s:SynIdEnd(hlID(id=='TabLineTitle666'?'Title':id)).s:SynIdStart(hlID(node.hi=='TabLineTitle666'?'Title':node.hi))
401            let id = node.hi
402        endif
403        if node.hi=='TabLineTitle666' " Dirty hack to provide non-standard tabline digit highlighting
404            let res .= '<font color='.s:GetColor(hlID('Title'),1).'>'.s:HtmlEscape(node.value).'</font>'
405        else
406            let res .= s:HtmlEscape(node.value)
407        endif
408    endfor
409    let res .= s:SynIdEnd(hlID(id))
410    return res
411endf
412function! s:Bufname(nr)
413    let name = bufname(a:nr)
414    if name == ''
415        let name = '[No name]'
416    endif
417    if strlen(getbufvar(a:nr,'&buftype'))
418        let name = fnamemodify(name,':t')
419    endif
420    return name
421endf
422function! s:TabTitle(nr)
423    let maxLen = (&columns - 1)*9/(9*tabpagenr('$') + 1) - 4
424    let title = substitute(s:Bufname(tabpagebuflist(a:nr)[tabpagewinnr(a:nr)-1]),'\([^\\]\)[^\\]*\\', '\1\\','g')
425    if strlen(title) > maxLen
426        return strpart(title, strlen(title) - maxLen)
427    endif
428    return title
429endf
430function! s:DefaultTabLine()
431    let sel = "v:val+1==tabpagenr()?'%#TabLineSel#':'%#TabLine#'"
432    let bufNum = 'len(tabpagebuflist(v:val+1))'
433    let isModified = "eval(join(map(tabpagebuflist(v:val+1),'getbufvar(v:'.'val,\"&modified\")'),'||'))"
434    return join(map(range(tabpagenr('$')),"eval(sel).(eval(bufNum) > 1 || eval(isModified)?' %#'.(v:val+1==tabpagenr()?'Title':'TabLineTitle666').'#'.(eval(bufNum) > 1?eval(bufNum):'').'%'.(v:val+1).'T'.eval(sel).repeat('+',eval(isModified)).'%*'.eval(sel).'\ ':'').s:TabTitle(v:val + 1).' '"),'').'%#TabLineFill#%T%=%#TabLine#%XX'
435endf
436function! GetTabLine()
437    if tabpagenr('$') > 1 && &showtabline == 1 || &showtabline == 2 && (!has('gui_running') || stridx(&guioptions,'e') == -1)
438        return s:StlPrintf(strlen(&tabline)?&tabline: s:DefaultTabLine(), &columns,' ','<','')
439    endif
440    return ''
441endf
442function! s:GetTitle()
443    if !&title
444        let title = 'VIM'
445    else
446        let VIM = get(v:,'servername','')
447        if VIM == ''
448            let VIM = has('gui_running')?'GVIM': 'VIM'
449        endif
450        let bufName = &buftype == 'help'?'help':fnamemodify(fnamemodify(fnamemodify(bufname("%"),":p"),":~"),":h")
451        if strlen(bufName) > 3
452            let partLen = 3
453            let bufName = strpart(bufName, 0, partLen).'%<'.strpart(bufName,partLen)
454        endif
455        if strlen(bufName)
456            let bufName = '('.bufName.')'
457        endif
458        let args = argc() <= 1?'': ' ('.(argv(argidx()) == bufname('%')?argidx() + 1: '('.(argidx() + 1).')').' of '.argc().')'
459        let titlestring = strlen(&titlestring)?&titlestring: '%t %M '.bufName.args.' - '.VIM
460        let title = substitute(s:StlPrintf(titlestring,(strlen(&titlestring)? &titlelen?&titlelen:&columns: 1000) - 1,' ','..',''),'\s*$','','')
461        if !strlen(&titlestring) && strlen(title) > &columns - 5
462            let title = title[0:(&columns - 5)/2 - 1 ].'...'.title[strlen(title) - (&columns - 5)/2 + 1:strlen(title)]
463        endif
464        let title = substitute(title, ' ', '\&nbsp;', 'g')
465    endif
466    if g:ScreenShot.Icon
467        return '<table align=left style="color:white;background:blue"><tr><th>'.s:ParseXpm(s:VimLogoXpm).'</th><th>'.title.'</th></tr></table>'
468    else
469        return title
470    endif
471endf
472function! s:SplitWithSpan(hi,str)
473    return eval(join(map(split(a:str,' '),"'s:SynIdWrap(a:hi,\"'.v:val.'\")'"), ".' '."))
474endf
475function! s:GetCredits()
476    return s:SynIdWrap('Question','Code syntax highlighting by ').'<a '.s:SynIdStyle(s:GetDefaultHlVect()).' href=http://www.vim.org><u>'.s:SynIdWrap('ModeMsg','VIM').'</u></a>'.s:SynIdWrap('Question',' captured with ').'<a '.s:SynIdStyle(s:GetDefaultHlVect()).' href=http://www.vim.org/scripts/script.php?script_id=1552><u>'.s:SynIdWrap('ModeMsg','ScreenShot').'</u></a>'.s:SynIdWrap('Question',' script ')
477endf
478"}}}
479"{{{-----------Menus
480function! s:GetMenu(mode,name)
481    redir => src
482    exec a:mode.'menu '.a:name
483    redir END
484    return src
485endf
486
487"}}}
488"{{{-----------Xpm
489function! s:ParseXpm(src)
490    let [all,comment,name,content;rest] = matchlist(tr(a:src,"\n"," "),'/\*\([^*]*\|\*[^/]\)\*/\s*static\s\+char\s*\*\s*\(\w*\)\[\]\s*=\s*{\(.*\)}')
491    let lines = eval('['.content.']')
492    let [width, height, colors_count, charwid; rest] = split(lines[0], '\s\+')
493    "echo l:
494    let colors = {}
495    for id in range(colors_count+1)[1:]
496        let [all, chars, key, color; rest] = matchlist(lines[id],'^\(.\{'.charwid.'\}\)\s\+\(.\)\s\+\(.*\)')
497        let colors[chars] = {'color': color, 'key': key}
498    endfor
499    "echo colors
500    let doc = '<table width='.width.' height='.height.' cellspacing=0 cellpadding=0>'
501    for num in range(height + colors_count + 1)[colors_count + 1:]
502        let doc .= '<tr>'
503        for i in range(width)
504            let col =get(colors,strpart(lines[num],i*charwid, charwid),{})
505            let doc .= '<td'.((has_key(col, 'color') && col.color !~? '^\(None\|\)$')?(' bgcolor='.col.color): '').'></td>'
506        endfor
507        let doc .= '</tr>'
508    endfor
509    return doc.'</table>'
510endf
511let s:VimLogoXpm = "/* XPM */
512            \static char * vim16x16[] = {
513            \'16 16 8 1',
514            \' c None',
515            \'. c #000000',
516            \'+ c #000080',
517            \'@ c #008000',
518            \'# c #00FF00',
519            \'$ c #808080',
520            \'% c #C0C0C0',
521            \'& c #FFFFFF',
522            \' .....#. .... ',
523            \' .&&&&&.@.&&&&. ',
524            \' .%%%%%$..%%%%$.',
525            \' .%%%$.@.&%%$. ',
526            \' .%%%$..&%%$. ',
527            \' .%%%$.&%%$.. ',
528            \' #.%%%$&%%$.@@. ',
529            \'#@.%%%&%%$.@@@@.',
530            \'.@.%%%%%..@@@@+ ',
531            \' ..%%%%.%...@. ',
532            \' .%%%%...%%.%. ',
533            \' .%%%.%%.%%%%%.',
534            \' .%%$..%.%.%.%.',
535            \' .%$.@.%.%.%.%.',
536            \' .. .%%.%.%.%.',
537            \' .. . . . '};"
538
539"}}}
540"{{{-----------Window's layout recognition functions
541function! s:Window_New(window,num)
542    call extend(a:window,{'num':a:num,'size': [winwidth(a:num),winheight(a:num)]})
543endf
544function! s:Window_TryMerge(self,new)
545    if has_key(a:self,'prev')
546        if a:self.size[!a:self.prevdir] == a:self.prev.size[!a:self.prevdir]
547            if !has_key(a:self.prev, 'dir')
548                let a:self.prev.dir = a:self.prevdir
549            endif
550            if a:self.prev.dir == a:self.prevdir && !has_key(a:self.prev, 'num')
551                call s:Container_Add(a:self.prev,a:self)
552            else
553                call s:Container_New(a:new,a:self.prev,a:self)
554            endif
555            return 1
556        endif
557    endif
558    return 0
559endf
560function! s:Window_DelParent(self)
561    if has_key(a:self,'parent')
562        call remove(a:self,'parent')
563    endif
564    if has_key(a:self,'prev')
565        call remove(a:self,'prev')
566    endif
567    for entry in items(a:self)
568        if type(entry[1]) == 2
569            unlet a:self[entry[0]]
570        endif
571    endfor
572    if !has_key(a:self, 'childs')
573        return
574    endif
575    for C in a:self.childs
576        call s:Window_DelParent(C)
577    endfor
578
579endf
580function! s:Window_IsTop(self,top)
581    let res = a:self
582    while has_key(res,'parent')
583        let res = res.parent
584    endwhile
585    return res is a:top
586endf
587function! s:Container_New(container,child1,child2)
588    call extend(a:container,{'dir':a:child2.prevdir,'childs':[], 'size': [0,0]})
589    let a:container.size[!a:container.dir] = a:child2.size[!a:container.dir]
590    call s:Container_Add(a:container,a:child1, a:child2)
591    if has_key(a:child1, 'prev')
592        let a:container.prev = a:child1.prev
593    endif
594    if has_key(a:child1, 'prevdir')
595        let a:container.prevdir = a:child1.prevdir
596    endif
597endf
598function! s:Container_Add(self,...)
599    for child in a:000
600        let a:self.size[a:self.dir] += child.size[a:self.dir] + (len(a:self.childs) != 0)
601        call add(a:self.childs,child)
602        let child.parent = a:self
603    endfor
604endf
605function! s:EnumWindows()
606    let ei_save = &ei
607    let winnr_save = winnr()
608    set ei=all
609    let windows=[]
610    let i = 1
611    while winwidth(i) > 0
612        let window = {'active': i == winnr_save}
613        call s:Window_New(window, i)
614        call add(windows, window)
615        let i += 1
616    endwhile
617    1wincmd w
618    let i = 1
619    let cur = {}
620
621    while i == winnr()
622
623
624        let window = windows[i - 1]
625        let window.pos = {'line':line('.'),'col':col('.'),'virtcol':virtcol('.'),'topline':line('w0'),'bottomline':line('w$'),'lastline':line('$')}
626        if i - 1
627            let window.prev = cur
628            wincmd k
629            if !s:Window_IsTop(windows[winnr() - 1],cur)
630                exec i.'wincmd w'
631                wincmd h
632                if !s:Window_IsTop(windows[winnr() - 1],cur)
633                    echoerr 'Can not enum window!'
634                    return 0
635                endif
636                let window.prevdir = 0
637            else
638                let window.prevdir = 1
639            endif
640            exec i.'wincmd w'
641            let new={}
642            while s:Window_TryMerge(window,new) && has_key(window,'prev')
643                if len(new)
644                    let window = new
645                    let new = {}
646                else
647                    let window = window.prev
648                endif
649            endwhile
650        endif
651        let cur = window
652        let i += 1
653        wincmd w
654    endwhile
655    " call s:Window_DelParent(cur)
656    let &ei = ei_save
657    exec winnr_save.'wincmd w'
658    return cur
659
660endf
661"}}}
662"{{{-----------Html generation functions
663if has('gui_running')
664    function! s:GetColor(id,type)
665        return synIDattr(a:id,a:type?'fg#': 'bg#')
666    endf
667else
668    if &t_Co == 8
669        if has('win32') || has('dos32') || has('dos16')
670            let s:Colors = ['#000000', '#0000ff', '#00ff00', '#00ffff', '#ff0000', '#ff00ff', '#ffff00', '#ffffff']
671        else
672            let s:Colors = ['#000000', '#ff0000', '#00ff00', '#ffff00', '#0000ff', '#ff00ff', '#00ffff', '#ffffff']
673        endif
674    else
675        if has('win32') || has('dos32') || has('dos16')
676            let s:Colors = ['#000000', '#0000c0', '#008000', '#008080', '#c00000', '#c000c0', '#808000', '#c0c0c0', '#808080', '#6060ff', '#00ff00', '#00ffff', '#ff8080', '#ff40ff', '#ffff00', '#ffffff']
677        else
678            let s:Colors = ['#000000', '#c00000', '#008000', '#808000', '#0000c0', '#c000c0', '#008080', '#c0c0c0', '#808080', '#ff6060', '#00ff00', '#ffff00', '#8080ff', '#ff40ff', '#00ffff', '#ffffff']
679        endif
680    endif
681    let s:valuerange = [0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF]
682    function! s:GetColor(id,type)
683        let c = synIDattr(a:id,a:type?'fg#': 'bg#')
684        if c == '-1' || c == ''
685            return ''
686        endif
687        let cc = eval(c)
688        if &t_Co != 256 || cc < 0x10
689            return s:Colors[cc]
690        else
691            let cc = cc - 16
692            return '#'.(cc <= 216?(printf('%.2x',s:valuerange[(cc/36)%6]).printf('%.2x',s:valuerange[(cc/6)%6]).printf('%.2x',s:valuerange[cc%6])):repeat(printf('%.2x',8 + (cc - 216)*0x0a),3))
693        endif
694    endf
695endif
696function! s:GetHlVect(id)
697    if type(a:id) != type([])
698        let id = synIDtrans((type(a:id) == type(1))?(a:id):hlID(a:id))
699        let reverse = synIDattr(id,'reverse') == '1' "&& id != hlID('Normal')
700        if id == hlID('Normal') && !reverse
701            return ['','','','','']
702" return s:GetDefaultHlVect()
703        endif
704        let color = s:GetColor(id,!reverse)
705        let background = s:GetColor(id,reverse)
706        if (color == '' || background == '') && reverse
707            if reverse
708                let style = s:GetDefaultHlVect()
709                let [color, background] = [color != ''?color : style[1] != ''?style[1] : '#ffffff', background != ''?background : style[0] != ''? style[0] : '#000000']
710            endif
711        endif
712        return [color, background, synIDattr(id, 'bold'), synIDattr(id, 'italic'), synIDattr(id, 'underline')]
713    else
714        let vec = s:GetHlVect(a:id[0])
715        let vecDiff = s:GetHlVect(a:id[1])
716        return [vec[0], vecDiff[1], vecDiff[2]||vec[2], vecDiff[3]||vec[3], vecDiff[4]||vec[4]]
717    endif
718endf
719function! s:GetDefaultHlVect()
720    let id = hlID('Normal')
721    let color = s:GetColor(id,1)
722    let background = s:GetColor(id,0)
723    let background = has_key(g:ScreenShot, 'force_background')?g:ScreenShot.force_background : background != ''? background : has('gui_running') ?'#ffffff' : '#000000'
724    let color = color != ''?color : has('gui_running') || has_key(g:ScreenShot, 'force_background')?'#000000' : '#ffffff'
725    return [color, background, synIDattr(id, 'bold'), synIDattr(id, 'italic'), synIDattr(id, 'underline')]
726endf
727function! s:DiffSynId(y,x,fl)
728    return [synID(a:y,a:x,a:fl), diff_hlID(a:y,a:x)]
729endf
730function! s:SynIdStyle(id)
731    return (a:id[0] == '' && a:id[1] == '')?'' : 'style="'.(strlen(a:id[0])?'color:'.a:id[0].';': '').(strlen(a:id[1])?'background:'.a:id[1] : '').'"'
732endf
733function! s:SynIdStart(id)
734    let vec = s:GetHlVect(a:id)
735    " TODO CHECK
736    "return (vec[1] != ''? '<span style="'.(strlen(vec[0])?'color:'.vec[0].';': '').(strlen(vec[1])?'background:'.vec[1] : '').'">' : vec[0] != ''? '<font color='.vec[0].'>': '').(vec[2]?'<b>': '').(vec[3]?'<i>': '').(vec[4]?'<u>': '')
737    return (vec[1] != ''? '<span style="'.(strlen(vec[0])?'color:'.vec[0].';': '').(strlen(vec[1])?'background:'.vec[1] : '').'">' : vec[0] != ''? '<font color='.vec[0].'>': '').(vec[2]?'<em>': '').(vec[3]?'<i>': '').(vec[4]?'<u>': '')
738endf
739function! s:SynIdEnd(id)
740    let vec = s:GetHlVect(a:id)
741    " TODO CHECK
742    "return (vec[4]?'</u>': '').(vec[3]?'</i>': '').(vec[2]?'</b>': '').(vec[1] != ''?'</span>': vec[0] != ''? '</font>': '')
743    return (vec[4]?'</u>': '').(vec[3]?'</i>': '').(vec[2]?'</em>': '').(vec[1] != ''?'</span>': vec[0] != ''? '</font>': '')
744endf
745function! s:SynIdWrap(id,text)
746    return s:SynIdStart(a:id).a:text.s:SynIdEnd(a:id)
747endf
748
749function! s:GetLinePrefix(y,numWidth,width,wrapped)
750    let prefix = ''
751    let closed = foldclosed(a:y) != -1
752    if &foldcolumn
753        let level = foldlevel(a:y) - closed
754        if level || closed
755            if &foldcolumn > 1
756                if level < &foldcolumn
757                    let prefix = repeat('|',level)
758
759                else
760                    let i = level - &foldcolumn + 2
761                    while i <= level
762                        let prefix .= i < 10? i : '>'
763                        let i += 1
764                    endw
765                endif
766                if closed
767                    let prefix .= '+'.repeat(' ',&foldcolumn - level - 1)
768                elseif level > foldlevel(a:y - 1)
769                    let prefix = strpart(prefix,0,strlen(prefix) - 1).'-'
770                endif
771                let prefix .= repeat(' ', &foldcolumn - strlen(prefix))
772            else
773                if level == 1
774                    let prefix = '|'
775                else
776                    let prefix = level < 10?level : '>'
777                endif
778                if closed
779                    let prefix = '+'
780                elseif level > foldlevel(a:y - 1)
781                    let prefix = '-'
782                endif
783            endif
784        else
785            let prefix = repeat(' ',&foldcolumn)
786        endif
787        let prefix = s:SynIdWrap('FoldColumn',strpart(prefix,0,a:width))
788    endif
789    if &number && a:y <= line('$')
790        if a:wrapped
791            let prefix .= s:SynIdWrap(a:wrapped?'LineNr': 'NonText',strpart(repeat(' ',a:numWidth),0,a:width - &foldcolumn))
792        else
793            let prefix .= s:SynIdWrap(closed?'Folded': 'LineNr',strpart(repeat(' ',a:numWidth - 1 - strlen(a:y)).a:y.' ',0,a:width - &foldcolumn))
794        endif
795    endif
796    return prefix
797endf
798function! s:HtmlEscape(text)
799    return substitute(a:text,'[<>&]','\={"<": "&lt;",">": "&gt;","&": "&amp;"}[submatch(0)]','g')
800endf
801function! s:HtmlDecode(text)
802    return substitute(a:text,'&\([^;]*\);','\={"lt":"<","gt":">","amp":"&"}[submatch(1)]','g')
803endf
804function! s:Opt2Dict(opt)
805    return eval('{'.substitute(a:opt,'\(\w\+\):\([^,]*\)\(,\|$\)',"'\\1':'\\2'\\3", 'g').'}')
806endf
807function! s:GetFillChars()
808    return extend({"fold": "-",'vert': '|','stl': ' ','stlnc': ' ','diff': '-'},s:Opt2Dict(&fillchars))
809endf
810function! s:synIDSpec(y,x,normal)
811    return !&diff?(a:normal):diff_hlID(a:y,a:x)?(s:DiffSynId(a:y,a:x,0)): [a:normal, 0]
812endf
813function! s:GetColoredText(lines,start,finish,height,topfill,lineEnd)
814    let y = a:start
815    " TODO CHECK
816    if exists("s:synIDfn")
817        unlet s:synIDfn
818    endif
819    let s:synIDfn = &diff? function('s:DiffSynId'): function('synID')
820    let realWidth = winwidth(winnr())
821    let foldWidth = &foldcolumn
822    let numWidth = &number?max([&numberwidth,strlen(line('$'))+1]):0
823    let width = realWidth - numWidth - foldWidth
824    let fillChars = s:GetFillChars()
825    let listChars = s:Opt2Dict(&listchars)
826    let expandTab = !&list || has_key(listChars, 'tab')
827    if !&list
828        let listChars.tab = ' '
829    endif
830    let fill_screen = strlen(a:lineEnd) || get(g:ScreenShot, 'fill_screen', 0)
831    let d_opts = split(&display,',')
832    let [uhex, lastline] = [0, 0]
833    for d_opt in d_opts
834        if d_opt == 'uhex'
835            let uhex = 1
836        elseif d_opt == 'lastline'
837            let lastline = 1
838        endif
839    endfor
840    let realX = 0
841    let view = winsaveview()
842    let topfill = a:topfill == -1?view.topfill : a:topfill
843    if a:height&&topfill
844        let inc = a:height?min([topfill,a:height]):topfill
845        for dd in range(inc)
846            call add(a:lines,s:GetLinePrefix(y - 1,numWidth,realWidth,0).s:SynIdWrap('DiffDelete',s:HtmlEscape(repeat(fillChars.diff,width))).a:lineEnd)
847        endfor
848    endif
849    let yReal = topfill
850    let skip = view.leftcol + (view.skipcol?(view.skipcol + strlen(&showbreak)):0)
851    let maxRealX = width + view.leftcol + view.skipcol
852    if width <= 0
853        let [width , maxRealX] = [0, 0]
854    endif
855    let cond = ((!a:height || !lastline))?((a:start == a:finish && a:height)?'yReal < a:height && y == a:start || y < a:finish': 'y <= a:finish'): 'yReal < a:height'
856    while eval(cond) && y <= line('$')
857        let x = 1
858        let xx = 0
859        let str = getline(y)
860        let chunk = ''
861        let xmax = len(str) + &list
862        let prefix = s:GetLinePrefix(y,numWidth,realWidth,0)
863        let realX = 0
864        let [oldId, oldId1] = &diff?[[0,0],[0, 0]] :[0, 0]
865        let folded = foldclosed(y)
866        if x > xmax
867            call add(a:lines, s:SynIdWrap(diff_hlID(y,x),prefix.(fill_screen || diff_hlID(y, x)?repeat(' ', width): '')).a:lineEnd)
868        elseif folded != -1
869            let text = matchstr(foldtextresult(y), '.'.'\{,'.width.'\}', 0)
870            call add(a:lines,prefix.s:SynIdWrap('Folded',s:HtmlEscape(text).repeat(fillChars.fold,width - strlen(substitute(text, ".", "x", "g"))).a:lineEnd))
871            let y = foldclosedend(y)
872        else
873            let tab = ''
874            let realX = 0
875            let eol = 0
876            if view.skipcol
877                let [oldId, oldId1, tab] = [&diff?[hlID('NonText'), 0] :hlID('NonText'), 0, s:SynIdStart(hlID('NonText')).s:HtmlEscape(&showbreak)]
878            endif
879            while x <= xmax && eval(cond)
880                let newLine = ((xx<maxRealX)?(prefix):s:GetLinePrefix(y,numWidth,realWidth,1)).tab
881                while realX < maxRealX
882                    let [whole, char, str; dummy] = matchlist(str, '^\(.\=\)\(.*\)$')
883                    let diffX = len(char)?len(char):1
884                    if char == ''
885                        if eol || !&list || !has_key(listChars,'eol')
886                            " TODO CHECK fill spaces
887                            let diff = maxRealX - realX
888                            let char = fill_screen || diff_hlID(y, x)?repeat(' ',diff): ' '
889                            let id = s:synIDSpec(y,x,0)
890                        else
891                            let id = s:synIDSpec(y,x,hlID('NonText'))
892                            let diff = 1
893                            let char = listChars.eol
894                            let eol = 1
895                        endif
896                    elseif (char < ' ' || char > '~') && char !~ '\p'
897                        if char == "\t" && expandTab
898                            let id = s:synIDSpec(y,x,&list?hlID('SpecialKey'):synIDtrans(synID(y, x, 0)))
899                            let diff = &tabstop - xx%&tabstop
900                            let char = strpart(listChars.tab,0,1).repeat(strpart(listChars.tab,1),diff-1)
901                        else
902                            let id = s:synIDSpec(y,x,hlID('SpecialKey'))
903                            if char2nr(char) < 0x100
904                                if uhex
905                                    let diff = 4
906                                    let char = char == "\n"?'<00>':printf('<%02x>',char2nr(char))
907                                else
908                                    let diff = 2
909                                    let charnr = char2nr(char)
910                                    if charnr == 10
911                                        let char = '^@'
912                                    elseif charnr < 32
913                                        let char = '^'.nr2char(64 + charnr)
914                                    elseif charnr == 127
915                                        let char = '^?'
916                                    elseif charnr < 160
917                                        let char = '~'.nr2char(64 + charnr - 128)
918                                    elseif charnr == 255
919                                        let char = '~?'
920                                    else
921                                        let char = '|'.nr2char(32 + charnr - 160)
922                                    endif
923                                endif
924                            else
925                                " TODO CHECK
926                                "let diff = 6
927                                "let char = printf('<%04x>',char2nr(char))
928                                let diff = strlen(char)
929                                let char = char
930                            endif
931                        endif
932                    else
933                        let diff = 1
934                        let id = s:synIDfn(y,x,0)
935                    endif
936                    if id != oldId
937                        if chunk != ''
938                            let newLine .= s:SynIdEnd(oldId1).s:SynIdStart(oldId).s:HtmlEscape(chunk)
939                        endif
940                        let [chunk, oldId, oldId1] = ['', id, oldId]
941                    endif
942                    if realX >= skip
943                        let chunk .= char
944                    elseif realX + strlen(substitute(char, ".", "x", "g")) >= skip
945                        let chunk .= matchstr(char,'.*',skip - realX)
946                    endif
947                    let realX += diff
948                    let xx += diff
949                    let x += diffX
950                endwhile
951                if chunk != ''
952                    let newLine .= s:SynIdEnd(oldId1).s:SynIdStart(oldId).s:HtmlEscape(chunk)
953                    let [chunk, oldId, oldId1] = ['', id, oldId]
954                endif
955                let save_id = oldId
956                if realX > maxRealX
957                    let realX = realX - maxRealX
958                    let [all, newLine, chunk; rest] = matchlist(newLine,'\(.*\)\(\%([^<>&;]\|&[^;]*;\)\{'.realX.'\}\)$')
959                    let chunk = s:HtmlDecode(chunk)
960                else
961                    let [chunk, realX] = ['', 0]
962                endif
963                let oldId1 = &diff?[0,0]: 0
964                if &showbreak != ''
965                    let xx += strlen(&showbreak)
966                    let tab = s:SynIdWrap('NonText',s:HtmlEscape(&showbreak))
967                    let realX += strlen(&showbreak)
968                else
969                    let tab = ''
970                endif
971                call add(a:lines, newLine.s:SynIdEnd(save_id).a:lineEnd)
972                if chunk == ''
973                    let oldId = &diff?[0,0]: 0
974                endif
975                let yReal += 1
976                if !&wrap
977                    break
978                endif
979                if view.skipcol
980                    let maxRealX -= view.skipcol
981                    let view.skipcol = 0
982                    let skip = 0
983                endif
984            endw
985            let yReal -= 1
986        endif
987        let yReal += 1
988        let y += 1
989        if diff_filler(y)
990            let inc = a:height?min([diff_filler(y),a:height - yReal]):diff_filler(y)
991            for dd in range(inc)
992                call add(a:lines,prefix.s:SynIdWrap('DiffDelete',s:HtmlEscape(repeat(fillChars.diff,width))).a:lineEnd)
993            endfor
994            let yReal += inc
995        endif
996    endw
997    while yReal < a:height
998        let prefix = s:GetLinePrefix(y,numWidth,realWidth,0)
999        let fill_screen = fill_screen || s:GetHlVect('NonText')[1] != ''
1000
1001        if y > line('$')
1002            call add(a:lines, prefix.s:SynIdStart(hlID('NonText')).'~'.(fill_screen?repeat(' ', width + numWidth - 1): '').s:SynIdEnd(hlID('NonText')).a:lineEnd)
1003        else
1004            call add(a:lines, s:GetLinePrefix(y,0,realWidth,1).s:SynIdStart(hlID('NonText')).'@'.(fill_screen?repeat(' ', width + numWidth - 1): '').s:SynIdEnd(hlID('NonText')).a:lineEnd)
1005        endif
1006        let yReal += 1
1007    endw
1008    let style = s:GetDefaultHlVect()
1009    if len(a:lines) && style[0] != ''
1010        let a:lines[0] = '<font color='.style[0].'>'.a:lines[0]
1011        let a:lines[len(a:lines) - 1] .= '</font>'
1012    endif
1013endf
1014function! s:GetColoredWindowText(window,lines,last)
1015    exec a:window.num.'wincmd w'
1016    let fillChars = s:GetFillChars()
1017    call s:GetColoredText(a:lines, line('w0'),line('w$'),winheight(a:window.num),-1,a:last[0]?'':s:SynIdWrap('VertSplit', fillChars.vert))
1018    let [fill_stl, synId] = (a:window.active)?[(fillChars.stl), 'StatusLine'] :[fillChars.stlnc, 'StatusLineNC']
1019    if strlen(&statusline)
1020        let StatusLine = s:StlPrintf(&statusline,winwidth('.'),fill_stl,'<',synId)
1021    else
1022        let name = s:Bufname('%')
1023        if &modified
1024            let name .= fillChars.stlnc.'[+]'
1025        endif
1026        if &readonly
1027            let name .= (&modified?'':fillChars.stlnc).'[RO]'
1028        endif
1029        if a:window.pos.topline == 1
1030            if a:window.pos.bottomline == a:window.pos.lastline
1031                let percents = 'All'
1032            else
1033                let percents = 'Top'
1034            endif
1035        elseif a:window.pos.bottomline == a:window.pos.lastline
1036            let percents = 'Bot'
1037        else
1038            let percents = (a:window.pos.topline*100/(a:window.pos.lastline + a:window.pos.topline - a:window.pos.bottomline )).'%'
1039            if strlen(percents) == 2
1040                let percents = ' '.percents
1041            endif
1042        endif
1043        let posInfo = a:window.pos.line.','.a:window.pos.col.((a:window.pos.col != a:window.pos.virtcol)?('-'.a:window.pos.virtcol): '')
1044        let width = winwidth('.')
1045        let magicLen = 18
1046        let lack = strlen(name) + magicLen + 1 - width
1047        if lack < 0
1048            let StatusLine = name.repeat(fillChars.stlnc, width - strlen(name) - magicLen).posInfo.repeat(fillChars.stlnc,magicLen - 3 - strlen(posInfo)).percents
1049        else
1050            let free = strlen(name) + magicLen - 1 - strlen(posInfo)
1051            let widthFree = width - 2 - strlen(posInfo)
1052            let newNameLen = (strlen(name) - 1)*widthFree/free
1053            let newInfoLen = (magicLen - strlen(posInfo))*widthFree/free
1054            let newNameLen += widthFree - newNameLen - newInfoLen
1055            let StatusLine = s:HtmlEscape('<'.strpart(name, strlen(name) - newNameLen)).' '.posInfo
1056            let percents = ' '.percents
1057            if (newInfoLen>4)
1058                let StatusLine .= repeat(fillChars.stlnc,newInfoLen - 4).percents
1059            elseif newInfoLen >= 0
1060                let StatusLine .= repeat(fillChars.stlnc,newInfoLen)
1061            else
1062                let StatusLine = strpart(StatusLine, 0, strlen(StatusLine) + newInfoLen)
1063            endif
1064
1065
1066        endif
1067        let StatusLine = s:SynIdWrap(synId,StatusLine)
1068    endif
1069    call add(a:lines,StatusLine.s:SynIdWrap(synId, a:last[0]?'':fill_stl))
1070endf
1071
1072function! s:InternalToHtml(self,lines,last)
1073    if has_key(a:self, 'childs')
1074        let lines = []
1075        let last = [0,0]
1076        let b = 0
1077        for C in range(len(a:self.childs))
1078            let last[a:self.dir] = a:last[a:self.dir] && C == len(a:self.childs) - 1
1079            let last[1 - a:self.dir] = a:last[1 - a:self.dir]
1080            if b
1081                let childLines = []
1082                call s:InternalToHtml(a:self.childs[C],childLines,last)
1083                if !a:self.dir
1084
1085                    let i = 0
1086                    while i < len(childLines)
1087                        let lines[i] .= childLines[i]
1088                        let i += 1
1089                    endw
1090                else
1091
1092                    let lines += childLines
1093                endif
1094            else
1095                call s:InternalToHtml(a:self.childs[C],lines,last)
1096                let b = 1
1097            endif
1098
1099        endfor
1100        call extend(a:lines, lines)
1101    elseif has_key(a:self, 'num')
1102        call s:GetColoredWindowText(a:self, a:lines, a:last)
1103    endif
1104
1105endf
1106function! s:SaveEvents()
1107    let saved = [&winwidth,&winheight,&winminheight,&winminwidth,&ei]
1108    let [&winwidth,&winheight,&winminheight,&winminwidth,&ei] = [1, 1, 1, 1, 'all']
1109    return saved
1110endf
1111function! s:RestoreEvents(saved)
1112    let [&winwidth,&winheight,&winminheight,&winminwidth,&ei] = a:saved
1113endf
1114"}}}
1115"{{{-----------Top-level functions and commands
1116if !exists('ScreenShot')
1117    let ScreenShot = {}
1118endif
1119call extend(ScreenShot,{'Title': 1,'Icon': 1,'Credits': 1},'keep')
1120function! ToHtml()
1121    let tabline = GetTabLine()
1122    if g:ScreenShot.Title
1123        let title = s:GetTitle()
1124    endif
1125    let saved = s:SaveEvents()
1126    let win = s:EnumWindows()
1127    let lines = []
1128    call s:InternalToHtml(win, lines, [1,1])
1129    call s:RestoreEvents(saved)
1130    if tabline != ''
1131        call insert(lines,tabline)
1132    endif
1133    let lines[0] = '<table cellspacing=0 cellpadding=0 '.s:SynIdStyle(s:GetDefaultHlVect()).' '.(exists('title')?' border=2><tr><th align=left style="color:white;background:blue">'.title.'</th></tr>': '>').'<tr><td><pre>'.lines[0]
1134    let lines[len(lines) - 1] .= '</pre></td></tr>'.(g:ScreenShot.Credits?'<tr><td><table align=right><tr><td width=20%></td><td width=80%><small><i>'.s:GetCredits().'</i></small></td></tr></table></td></tr>': '').'</table>'
1135    return lines
1136endf
1137function! Text2Html(line1,line2)
1138    let lines = []
1139    call s:GetColoredText(lines,a:line1,a:line2,0,0,'')
1140    exec 'new '.bufname('%').'.html'
1141    let lines[0] = '<table cellspacing=0 cellpadding=0 '.s:SynIdStyle(s:GetDefaultHlVect()).'><tr><td colspan><pre>'.lines[0]
1142    call append(0,lines + ['</pre></td></tr>'.(g:ScreenShot.Credits?'<tr><td><table align=right><tr><td width=20%></td><td width=80%><small><i>'.s:GetCredits().'</i></small></td></tr></table></td></tr>': '').'</table>'])
1143endf
1144
1145function! ScreenShot()
1146    let a = ToHtml()
1147    let shots = eval('['.substitute(glob('screenshot-*.html'),'\%(screenshot-\(\d*\).html\|.*\)\%(\n\|$\)','\=((submatch(1)!="")?submatch(1):0).","','g').']')
1148    exec 'new screenshot-'.(max(shots) + 1).'.html'
1149    call append(0,a)
1150endf
1151function! Diff2Html(line1,line2)
1152    let buffs = map(filter(tabpagebuflist(tabpagenr()),'getwinvar(bufwinnr(v:val),''&diff'')'),'bufwinnr(v:val)')
1153    if len(buffs) < 2
1154        echoerr 'Window in diff mode not found'
1155        return 0
1156    endif
1157    if buffs[0] == winnr()
1158        let num = 0
1159    else
1160        let num = index(buffs, winnr())
1161        if num == -1
1162            echoerr 'Can''t find current buffer!'
1163            return
1164        endif
1165        let buffs[1] = buffs[num]
1166        let num = 1
1167    endif
1168    let lineTop = eval(join(map(range(1,a:line1),'diff_filler(v:val) - (foldclosed(v:val)>0) + (v:val == foldclosedend(v:val) ) + 1'),'+'))
1169    let height = eval(join(map(range(a:line1,a:line2),'diff_filler(v:val) - (foldclosed(v:val)>0) + (v:val == foldclosedend(v:val)) + 1'),'+'))
1170    exec buffs[1-num].'wincmd w'
1171    let i = 0
1172    let val = 0
1173    while val < lineTop && i < line('$')
1174        let i += 1
1175        let val += diff_filler(i) - (foldclosed(i)>0) + (i == foldclosedend(i) ) + 1
1176    endw
1177    let [topfill{num+1}, topfill{2-num}] = [0, val - lineTop]
1178    let [startY{num+1}, startY{2-num}] = [a:line1, i]
1179    while val < lineTop + height && i < line('$')
1180        let i += 1
1181        let val += diff_filler(i) - (foldclosed(i)>0) + (i == foldclosedend(i) ) + 1
1182    endw
1183    let [endY{num+1}, endY{2-num}] = [a:line2, i-1]
1184    exec buffs[0].'wincmd w'
1185    let lines1 = []
1186    call s:GetColoredText(lines1,startY1,endY1,height,topfill1,s:SynIdWrap('VertSplit', s:GetFillChars().vert))
1187    exec buffs[1].'wincmd w'
1188    let lines2 = []
1189    call s:GetColoredText(lines2,startY2,endY2,height,topfill2,'')
1190    for i in range(len(lines1))
1191        let lines1[i] .= lines2[i]
1192    endfor
1193    exec 'new '.fnamemodify(bufname(winbufnr(buffs[0])),':t').'\ -\ '.fnamemodify(bufname(winbufnr(buffs[0])),':t').'.diff.html'
1194    let lines1[0] = '<table cellspacing=0 cellpadding=0 '.s:SynIdStyle(s:GetDefaultHlVect()).'><tr><td colspan><pre>'.lines1[0]
1195    call append(0,lines1 + ['</pre></td></tr>'.(g:ScreenShot.Credits?'<tr><td><table align=right><tr><td width=20%></td><td width=80%><small><i>'.s:GetCredits().'</i></small></td></tr></table></td></tr>': '').'</table>'])
1196
1197endf
1198command! -range=% Text2Html :call Text2Html(<line1>,<line2>)
1199command! ScreenShot :call ScreenShot()
1200command! -range=% Diff2Html :call Diff2Html(<line1>,<line2>)
1201"}}} vim:foldmethod=marker foldlevel=0
1202

Archive Download this file

Branches:
master