1071d4279SBram Moolenaar" Vim syntax support file 2349b2fb0SBram Moolenaar" Maintainer: Ben Fritz <[email protected]> 3*60cce2fbSBram Moolenaar" Last Change: 2015 Sep 08 4349b2fb0SBram Moolenaar" 5349b2fb0SBram Moolenaar" Additional contributors: 6349b2fb0SBram Moolenaar" 7349b2fb0SBram Moolenaar" Original by Bram Moolenaar <[email protected]> 8349b2fb0SBram Moolenaar" Modified by David Ne\v{c}as (Yeti) <[email protected]> 9349b2fb0SBram Moolenaar" XHTML support by Panagiotis Issaris <[email protected]> 10349b2fb0SBram Moolenaar" Made w3 compliant by Edd Barrett <[email protected]> 11349b2fb0SBram Moolenaar" Added html_font. Edd Barrett <[email protected]> 12349b2fb0SBram Moolenaar" Progress bar based off code from "progressbar widget" plugin by 13349b2fb0SBram Moolenaar" Andreas Politz, heavily modified: 14349b2fb0SBram Moolenaar" http://www.vim.org/scripts/script.php?script_id=2006 15349b2fb0SBram Moolenaar" 16349b2fb0SBram Moolenaar" See Mercurial change logs for more! 17071d4279SBram Moolenaar 18071d4279SBram Moolenaar" Transform a file into HTML, using the current syntax highlighting. 19071d4279SBram Moolenaar 205c73622aSBram Moolenaar" this file uses line continuations 215c73622aSBram Moolenaarlet s:cpo_sav = &cpo 22349b2fb0SBram Moolenaarlet s:ls = &ls 236c35beaaSBram Moolenaarset cpo&vim 245c73622aSBram Moolenaar 25349b2fb0SBram Moolenaarlet s:end=line('$') 26349b2fb0SBram Moolenaar 27313b7237SBram Moolenaar" Font 28b02cbe34SBram Moolenaarif exists("g:html_font") 29*60cce2fbSBram Moolenaar if type(g:html_font) == type([]) 30*60cce2fbSBram Moolenaar let s:htmlfont = "'". join(g:html_font,"','") . "', monospace" 31*60cce2fbSBram Moolenaar else 32076e8b2aSBram Moolenaar let s:htmlfont = "'". g:html_font . "', monospace" 33*60cce2fbSBram Moolenaar endif 34313b7237SBram Moolenaarelse 35313b7237SBram Moolenaar let s:htmlfont = "monospace" 36313b7237SBram Moolenaarendif 37313b7237SBram Moolenaar 38076e8b2aSBram Moolenaarlet s:settings = tohtml#GetUserSettings() 395c73622aSBram Moolenaar 406c35beaaSBram Moolenaarif !exists('s:FOLDED_ID') 416c35beaaSBram Moolenaar let s:FOLDED_ID = hlID("Folded") | lockvar s:FOLDED_ID 426c35beaaSBram Moolenaar let s:FOLD_C_ID = hlID("FoldColumn") | lockvar s:FOLD_C_ID 436c35beaaSBram Moolenaar let s:LINENR_ID = hlID('LineNr') | lockvar s:LINENR_ID 446c35beaaSBram Moolenaar let s:DIFF_D_ID = hlID("DiffDelete") | lockvar s:DIFF_D_ID 456c35beaaSBram Moolenaar let s:DIFF_A_ID = hlID("DiffAdd") | lockvar s:DIFF_A_ID 466c35beaaSBram Moolenaar let s:DIFF_C_ID = hlID("DiffChange") | lockvar s:DIFF_C_ID 476c35beaaSBram Moolenaar let s:DIFF_T_ID = hlID("DiffText") | lockvar s:DIFF_T_ID 486c35beaaSBram Moolenaar let s:CONCEAL_ID = hlID('Conceal') | lockvar s:CONCEAL_ID 496c35beaaSBram Moolenaarendif 506c35beaaSBram Moolenaar 518e5af3e5SBram Moolenaar" Whitespace 528e5af3e5SBram Moolenaarif s:settings.pre_wrap 538e5af3e5SBram Moolenaar let s:whitespace = "white-space: pre-wrap; " 548e5af3e5SBram Moolenaarelse 558e5af3e5SBram Moolenaar let s:whitespace = "" 568e5af3e5SBram Moolenaarendif 578e5af3e5SBram Moolenaar 586c35beaaSBram Moolenaarif !empty(s:settings.prevent_copy) 596c35beaaSBram Moolenaar if s:settings.no_invalid 606c35beaaSBram Moolenaar " User has decided they don't want invalid markup. Still works in 616c35beaaSBram Moolenaar " OpenOffice, and for text editors, but when pasting into Microsoft Word the 626c35beaaSBram Moolenaar " input elements get pasted too and they cannot be deleted (at least not 636c35beaaSBram Moolenaar " easily). 646c35beaaSBram Moolenaar let s:unselInputType = "" 656c35beaaSBram Moolenaar else 666c35beaaSBram Moolenaar " Prevent from copy-pasting the input elements into Microsoft Word where 676c35beaaSBram Moolenaar " they cannot be deleted easily by deliberately inserting invalid markup. 686c35beaaSBram Moolenaar let s:unselInputType = " type='invalid_input_type'" 696c35beaaSBram Moolenaar endif 706c35beaaSBram Moolenaarendif 716c35beaaSBram Moolenaar 72071d4279SBram Moolenaar" When not in gui we can only guess the colors. 736c35beaaSBram Moolenaar" TODO - is this true anymore? 74071d4279SBram Moolenaarif has("gui_running") 75071d4279SBram Moolenaar let s:whatterm = "gui" 76071d4279SBram Moolenaarelse 77071d4279SBram Moolenaar let s:whatterm = "cterm" 78071d4279SBram Moolenaar if &t_Co == 8 796c35beaaSBram Moolenaar let s:cterm_color = { 806c35beaaSBram Moolenaar \ 0: "#808080", 1: "#ff6060", 2: "#00ff00", 3: "#ffff00", 816c35beaaSBram Moolenaar \ 4: "#8080ff", 5: "#ff40ff", 6: "#00ffff", 7: "#ffffff" 826c35beaaSBram Moolenaar \ } 83071d4279SBram Moolenaar else 846c35beaaSBram Moolenaar let s:cterm_color = { 856c35beaaSBram Moolenaar \ 0: "#000000", 1: "#c00000", 2: "#008000", 3: "#804000", 866c35beaaSBram Moolenaar \ 4: "#0000c0", 5: "#c000c0", 6: "#008080", 7: "#c0c0c0", 876c35beaaSBram Moolenaar \ 8: "#808080", 9: "#ff6060", 10: "#00ff00", 11: "#ffff00", 886c35beaaSBram Moolenaar \ 12: "#8080ff", 13: "#ff40ff", 14: "#00ffff", 15: "#ffffff" 896c35beaaSBram Moolenaar \ } 90313b7237SBram Moolenaar 91313b7237SBram Moolenaar " Colors for 88 and 256 come from xterm. 92313b7237SBram Moolenaar if &t_Co == 88 936c35beaaSBram Moolenaar call extend(s:cterm_color, { 946c35beaaSBram Moolenaar \ 16: "#000000", 17: "#00008b", 18: "#0000cd", 19: "#0000ff", 956c35beaaSBram Moolenaar \ 20: "#008b00", 21: "#008b8b", 22: "#008bcd", 23: "#008bff", 966c35beaaSBram Moolenaar \ 24: "#00cd00", 25: "#00cd8b", 26: "#00cdcd", 27: "#00cdff", 976c35beaaSBram Moolenaar \ 28: "#00ff00", 29: "#00ff8b", 30: "#00ffcd", 31: "#00ffff", 986c35beaaSBram Moolenaar \ 32: "#8b0000", 33: "#8b008b", 34: "#8b00cd", 35: "#8b00ff", 996c35beaaSBram Moolenaar \ 36: "#8b8b00", 37: "#8b8b8b", 38: "#8b8bcd", 39: "#8b8bff", 1006c35beaaSBram Moolenaar \ 40: "#8bcd00", 41: "#8bcd8b", 42: "#8bcdcd", 43: "#8bcdff", 1016c35beaaSBram Moolenaar \ 44: "#8bff00", 45: "#8bff8b", 46: "#8bffcd", 47: "#8bffff", 1026c35beaaSBram Moolenaar \ 48: "#cd0000", 49: "#cd008b", 50: "#cd00cd", 51: "#cd00ff", 1036c35beaaSBram Moolenaar \ 52: "#cd8b00", 53: "#cd8b8b", 54: "#cd8bcd", 55: "#cd8bff", 1046c35beaaSBram Moolenaar \ 56: "#cdcd00", 57: "#cdcd8b", 58: "#cdcdcd", 59: "#cdcdff", 1056c35beaaSBram Moolenaar \ 60: "#cdff00", 61: "#cdff8b", 62: "#cdffcd", 63: "#cdffff", 1066c35beaaSBram Moolenaar \ 64: "#ff0000" 1076c35beaaSBram Moolenaar \ }) 1086c35beaaSBram Moolenaar call extend(s:cterm_color, { 1096c35beaaSBram Moolenaar \ 65: "#ff008b", 66: "#ff00cd", 67: "#ff00ff", 68: "#ff8b00", 1106c35beaaSBram Moolenaar \ 69: "#ff8b8b", 70: "#ff8bcd", 71: "#ff8bff", 72: "#ffcd00", 1116c35beaaSBram Moolenaar \ 73: "#ffcd8b", 74: "#ffcdcd", 75: "#ffcdff", 76: "#ffff00", 1126c35beaaSBram Moolenaar \ 77: "#ffff8b", 78: "#ffffcd", 79: "#ffffff", 80: "#2e2e2e", 1136c35beaaSBram Moolenaar \ 81: "#5c5c5c", 82: "#737373", 83: "#8b8b8b", 84: "#a2a2a2", 1146c35beaaSBram Moolenaar \ 85: "#b9b9b9", 86: "#d0d0d0", 87: "#e7e7e7" 1156c35beaaSBram Moolenaar \ }) 116313b7237SBram Moolenaar elseif &t_Co == 256 1176c35beaaSBram Moolenaar call extend(s:cterm_color, { 1186c35beaaSBram Moolenaar \ 16: "#000000", 17: "#00005f", 18: "#000087", 19: "#0000af", 1196c35beaaSBram Moolenaar \ 20: "#0000d7", 21: "#0000ff", 22: "#005f00", 23: "#005f5f", 1206c35beaaSBram Moolenaar \ 24: "#005f87", 25: "#005faf", 26: "#005fd7", 27: "#005fff", 1216c35beaaSBram Moolenaar \ 28: "#008700", 29: "#00875f", 30: "#008787", 31: "#0087af", 1226c35beaaSBram Moolenaar \ 32: "#0087d7", 33: "#0087ff", 34: "#00af00", 35: "#00af5f", 1236c35beaaSBram Moolenaar \ 36: "#00af87", 37: "#00afaf", 38: "#00afd7", 39: "#00afff", 1246c35beaaSBram Moolenaar \ 40: "#00d700", 41: "#00d75f", 42: "#00d787", 43: "#00d7af", 1256c35beaaSBram Moolenaar \ 44: "#00d7d7", 45: "#00d7ff", 46: "#00ff00", 47: "#00ff5f", 1266c35beaaSBram Moolenaar \ 48: "#00ff87", 49: "#00ffaf", 50: "#00ffd7", 51: "#00ffff", 1276c35beaaSBram Moolenaar \ 52: "#5f0000", 53: "#5f005f", 54: "#5f0087", 55: "#5f00af", 1286c35beaaSBram Moolenaar \ 56: "#5f00d7", 57: "#5f00ff", 58: "#5f5f00", 59: "#5f5f5f", 1296c35beaaSBram Moolenaar \ 60: "#5f5f87", 61: "#5f5faf", 62: "#5f5fd7", 63: "#5f5fff", 1306c35beaaSBram Moolenaar \ 64: "#5f8700" 1316c35beaaSBram Moolenaar \ }) 1326c35beaaSBram Moolenaar call extend(s:cterm_color, { 1336c35beaaSBram Moolenaar \ 65: "#5f875f", 66: "#5f8787", 67: "#5f87af", 68: "#5f87d7", 1346c35beaaSBram Moolenaar \ 69: "#5f87ff", 70: "#5faf00", 71: "#5faf5f", 72: "#5faf87", 1356c35beaaSBram Moolenaar \ 73: "#5fafaf", 74: "#5fafd7", 75: "#5fafff", 76: "#5fd700", 1366c35beaaSBram Moolenaar \ 77: "#5fd75f", 78: "#5fd787", 79: "#5fd7af", 80: "#5fd7d7", 1376c35beaaSBram Moolenaar \ 81: "#5fd7ff", 82: "#5fff00", 83: "#5fff5f", 84: "#5fff87", 1386c35beaaSBram Moolenaar \ 85: "#5fffaf", 86: "#5fffd7", 87: "#5fffff", 88: "#870000", 1396c35beaaSBram Moolenaar \ 89: "#87005f", 90: "#870087", 91: "#8700af", 92: "#8700d7", 1406c35beaaSBram Moolenaar \ 93: "#8700ff", 94: "#875f00", 95: "#875f5f", 96: "#875f87", 1416c35beaaSBram Moolenaar \ 97: "#875faf", 98: "#875fd7", 99: "#875fff", 100: "#878700", 1426c35beaaSBram Moolenaar \ 101: "#87875f", 102: "#878787", 103: "#8787af", 104: "#8787d7", 1436c35beaaSBram Moolenaar \ 105: "#8787ff", 106: "#87af00", 107: "#87af5f", 108: "#87af87", 1446c35beaaSBram Moolenaar \ 109: "#87afaf", 110: "#87afd7", 111: "#87afff", 112: "#87d700" 1456c35beaaSBram Moolenaar \ }) 1466c35beaaSBram Moolenaar call extend(s:cterm_color, { 1476c35beaaSBram Moolenaar \ 113: "#87d75f", 114: "#87d787", 115: "#87d7af", 116: "#87d7d7", 1486c35beaaSBram Moolenaar \ 117: "#87d7ff", 118: "#87ff00", 119: "#87ff5f", 120: "#87ff87", 1496c35beaaSBram Moolenaar \ 121: "#87ffaf", 122: "#87ffd7", 123: "#87ffff", 124: "#af0000", 1506c35beaaSBram Moolenaar \ 125: "#af005f", 126: "#af0087", 127: "#af00af", 128: "#af00d7", 1516c35beaaSBram Moolenaar \ 129: "#af00ff", 130: "#af5f00", 131: "#af5f5f", 132: "#af5f87", 1526c35beaaSBram Moolenaar \ 133: "#af5faf", 134: "#af5fd7", 135: "#af5fff", 136: "#af8700", 1536c35beaaSBram Moolenaar \ 137: "#af875f", 138: "#af8787", 139: "#af87af", 140: "#af87d7", 1546c35beaaSBram Moolenaar \ 141: "#af87ff", 142: "#afaf00", 143: "#afaf5f", 144: "#afaf87", 1556c35beaaSBram Moolenaar \ 145: "#afafaf", 146: "#afafd7", 147: "#afafff", 148: "#afd700", 1566c35beaaSBram Moolenaar \ 149: "#afd75f", 150: "#afd787", 151: "#afd7af", 152: "#afd7d7", 1576c35beaaSBram Moolenaar \ 153: "#afd7ff", 154: "#afff00", 155: "#afff5f", 156: "#afff87", 1586c35beaaSBram Moolenaar \ 157: "#afffaf", 158: "#afffd7" 1596c35beaaSBram Moolenaar \ }) 1606c35beaaSBram Moolenaar call extend(s:cterm_color, { 1616c35beaaSBram Moolenaar \ 159: "#afffff", 160: "#d70000", 161: "#d7005f", 162: "#d70087", 1626c35beaaSBram Moolenaar \ 163: "#d700af", 164: "#d700d7", 165: "#d700ff", 166: "#d75f00", 1636c35beaaSBram Moolenaar \ 167: "#d75f5f", 168: "#d75f87", 169: "#d75faf", 170: "#d75fd7", 1646c35beaaSBram Moolenaar \ 171: "#d75fff", 172: "#d78700", 173: "#d7875f", 174: "#d78787", 1656c35beaaSBram Moolenaar \ 175: "#d787af", 176: "#d787d7", 177: "#d787ff", 178: "#d7af00", 1666c35beaaSBram Moolenaar \ 179: "#d7af5f", 180: "#d7af87", 181: "#d7afaf", 182: "#d7afd7", 1676c35beaaSBram Moolenaar \ 183: "#d7afff", 184: "#d7d700", 185: "#d7d75f", 186: "#d7d787", 1686c35beaaSBram Moolenaar \ 187: "#d7d7af", 188: "#d7d7d7", 189: "#d7d7ff", 190: "#d7ff00", 1696c35beaaSBram Moolenaar \ 191: "#d7ff5f", 192: "#d7ff87", 193: "#d7ffaf", 194: "#d7ffd7", 1706c35beaaSBram Moolenaar \ 195: "#d7ffff", 196: "#ff0000", 197: "#ff005f", 198: "#ff0087", 1716c35beaaSBram Moolenaar \ 199: "#ff00af", 200: "#ff00d7", 201: "#ff00ff", 202: "#ff5f00", 1726c35beaaSBram Moolenaar \ 203: "#ff5f5f", 204: "#ff5f87" 1736c35beaaSBram Moolenaar \ }) 1746c35beaaSBram Moolenaar call extend(s:cterm_color, { 1756c35beaaSBram Moolenaar \ 205: "#ff5faf", 206: "#ff5fd7", 207: "#ff5fff", 208: "#ff8700", 1766c35beaaSBram Moolenaar \ 209: "#ff875f", 210: "#ff8787", 211: "#ff87af", 212: "#ff87d7", 1776c35beaaSBram Moolenaar \ 213: "#ff87ff", 214: "#ffaf00", 215: "#ffaf5f", 216: "#ffaf87", 1786c35beaaSBram Moolenaar \ 217: "#ffafaf", 218: "#ffafd7", 219: "#ffafff", 220: "#ffd700", 1796c35beaaSBram Moolenaar \ 221: "#ffd75f", 222: "#ffd787", 223: "#ffd7af", 224: "#ffd7d7", 1806c35beaaSBram Moolenaar \ 225: "#ffd7ff", 226: "#ffff00", 227: "#ffff5f", 228: "#ffff87", 1816c35beaaSBram Moolenaar \ 229: "#ffffaf", 230: "#ffffd7", 231: "#ffffff", 232: "#080808", 1826c35beaaSBram Moolenaar \ 233: "#121212", 234: "#1c1c1c", 235: "#262626", 236: "#303030", 1836c35beaaSBram Moolenaar \ 237: "#3a3a3a", 238: "#444444", 239: "#4e4e4e", 240: "#585858", 1846c35beaaSBram Moolenaar \ 241: "#626262", 242: "#6c6c6c", 243: "#767676", 244: "#808080", 1856c35beaaSBram Moolenaar \ 245: "#8a8a8a", 246: "#949494", 247: "#9e9e9e", 248: "#a8a8a8", 1866c35beaaSBram Moolenaar \ 249: "#b2b2b2", 250: "#bcbcbc", 251: "#c6c6c6", 252: "#d0d0d0", 1876c35beaaSBram Moolenaar \ 253: "#dadada", 254: "#e4e4e4", 255: "#eeeeee" 1886c35beaaSBram Moolenaar \ }) 189313b7237SBram Moolenaar endif 190071d4279SBram Moolenaar endif 191071d4279SBram Moolenaarendif 192071d4279SBram Moolenaar 193071d4279SBram Moolenaar" Return good color specification: in GUI no transformation is done, in 194313b7237SBram Moolenaar" terminal return RGB values of known colors and empty string for unknown 195071d4279SBram Moolenaarif s:whatterm == "gui" 196071d4279SBram Moolenaar function! s:HtmlColor(color) 197071d4279SBram Moolenaar return a:color 198071d4279SBram Moolenaar endfun 199071d4279SBram Moolenaarelse 200071d4279SBram Moolenaar function! s:HtmlColor(color) 201313b7237SBram Moolenaar if has_key(s:cterm_color, a:color) 202313b7237SBram Moolenaar return s:cterm_color[a:color] 203071d4279SBram Moolenaar else 204071d4279SBram Moolenaar return "" 205071d4279SBram Moolenaar endif 206071d4279SBram Moolenaar endfun 207071d4279SBram Moolenaarendif 208071d4279SBram Moolenaar 2096c35beaaSBram Moolenaar" Find out the background and foreground color for use later 2106c35beaaSBram Moolenaarlet s:fgc = s:HtmlColor(synIDattr(hlID("Normal"), "fg#", s:whatterm)) 2116c35beaaSBram Moolenaarlet s:bgc = s:HtmlColor(synIDattr(hlID("Normal"), "bg#", s:whatterm)) 2126c35beaaSBram Moolenaarif s:fgc == "" 2136c35beaaSBram Moolenaar let s:fgc = ( &background == "dark" ? "#ffffff" : "#000000" ) 2146c35beaaSBram Moolenaarendif 2156c35beaaSBram Moolenaarif s:bgc == "" 2166c35beaaSBram Moolenaar let s:bgc = ( &background == "dark" ? "#000000" : "#ffffff" ) 2176c35beaaSBram Moolenaarendif 2186c35beaaSBram Moolenaar 219bebca9daSBram Moolenaarif !s:settings.use_css 220071d4279SBram Moolenaar " Return opening HTML tag for given highlight id 221543b7ef7SBram Moolenaar function! s:HtmlOpening(id, extra_attrs) 222071d4279SBram Moolenaar let a = "" 223071d4279SBram Moolenaar if synIDattr(a:id, "inverse") 224071d4279SBram Moolenaar " For inverse, we always must set both colors (and exchange them) 225071d4279SBram Moolenaar let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) 226543b7ef7SBram Moolenaar let a = a . '<span '.a:extra_attrs.'style="background-color: ' . ( x != "" ? x : s:fgc ) . '">' 227071d4279SBram Moolenaar let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) 228071d4279SBram Moolenaar let a = a . '<font color="' . ( x != "" ? x : s:bgc ) . '">' 229071d4279SBram Moolenaar else 230071d4279SBram Moolenaar let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) 231543b7ef7SBram Moolenaar if x != "" 232543b7ef7SBram Moolenaar let a = a . '<span '.a:extra_attrs.'style="background-color: ' . x . '">' 233543b7ef7SBram Moolenaar elseif !empty(a:extra_attrs) 234543b7ef7SBram Moolenaar let a = a . '<span '.a:extra_attrs.'>' 235543b7ef7SBram Moolenaar endif 236071d4279SBram Moolenaar let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) 237071d4279SBram Moolenaar if x != "" | let a = a . '<font color="' . x . '">' | endif 238071d4279SBram Moolenaar endif 239071d4279SBram Moolenaar if synIDattr(a:id, "bold") | let a = a . "<b>" | endif 240071d4279SBram Moolenaar if synIDattr(a:id, "italic") | let a = a . "<i>" | endif 241071d4279SBram Moolenaar if synIDattr(a:id, "underline") | let a = a . "<u>" | endif 242071d4279SBram Moolenaar return a 243071d4279SBram Moolenaar endfun 244071d4279SBram Moolenaar 245071d4279SBram Moolenaar " Return closing HTML tag for given highlight id 246543b7ef7SBram Moolenaar function! s:HtmlClosing(id, has_extra_attrs) 247071d4279SBram Moolenaar let a = "" 248071d4279SBram Moolenaar if synIDattr(a:id, "underline") | let a = a . "</u>" | endif 249071d4279SBram Moolenaar if synIDattr(a:id, "italic") | let a = a . "</i>" | endif 250071d4279SBram Moolenaar if synIDattr(a:id, "bold") | let a = a . "</b>" | endif 251071d4279SBram Moolenaar if synIDattr(a:id, "inverse") 252071d4279SBram Moolenaar let a = a . '</font></span>' 253071d4279SBram Moolenaar else 254071d4279SBram Moolenaar let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) 255071d4279SBram Moolenaar if x != "" | let a = a . '</font>' | endif 256071d4279SBram Moolenaar let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) 257543b7ef7SBram Moolenaar if x != "" || a:has_extra_attrs | let a = a . '</span>' | endif 258071d4279SBram Moolenaar endif 259071d4279SBram Moolenaar return a 260071d4279SBram Moolenaar endfun 261071d4279SBram Moolenaarendif 262071d4279SBram Moolenaar 2636c35beaaSBram Moolenaar" Use a different function for formatting based on user options. This way we 2646c35beaaSBram Moolenaar" can avoid a lot of logic during the actual execution. 2656c35beaaSBram Moolenaar" 2666c35beaaSBram Moolenaar" Build the function line by line containing only what is needed for the options 2676c35beaaSBram Moolenaar" in use for maximum code sharing with minimal branch logic for greater speed. 2686c35beaaSBram Moolenaar" 2696c35beaaSBram Moolenaar" Note, 'exec' commands do not recognize line continuations, so must concatenate 2706c35beaaSBram Moolenaar" lines rather than continue them. 2716c35beaaSBram Moolenaarif s:settings.use_css 2726c35beaaSBram Moolenaar " save CSS to a list of rules to add to the output at the end of processing 2736c35beaaSBram Moolenaar 2746c35beaaSBram Moolenaar " first, get the style names we need 2756c35beaaSBram Moolenaar let wrapperfunc_lines = [ 276543b7ef7SBram Moolenaar \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, make_unselectable, unformatted)', 2776c35beaaSBram Moolenaar \ '', 2786c35beaaSBram Moolenaar \ ' let l:style_name = synIDattr(a:style_id, "name", s:whatterm)' 2796c35beaaSBram Moolenaar \ ] 2806c35beaaSBram Moolenaar if &diff 2816c35beaaSBram Moolenaar let wrapperfunc_lines += [ 2826c35beaaSBram Moolenaar \ ' let l:diff_style_name = synIDattr(a:diff_style_id, "name", s:whatterm)'] 2836c35beaaSBram Moolenaar 2846c35beaaSBram Moolenaar " Add normal groups and diff groups to separate lists so we can order them to 2856c35beaaSBram Moolenaar " allow diff highlight to override normal highlight 2866c35beaaSBram Moolenaar 2876c35beaaSBram Moolenaar " if primary style IS a diff style, grab it from the diff cache instead 2886c35beaaSBram Moolenaar " (always succeeds because we pre-populate it) 2896c35beaaSBram Moolenaar let wrapperfunc_lines += [ 2906c35beaaSBram Moolenaar \ '', 2916c35beaaSBram Moolenaar \ ' if a:style_id == s:DIFF_D_ID || a:style_id == s:DIFF_A_ID ||'. 2926c35beaaSBram Moolenaar \ ' a:style_id == s:DIFF_C_ID || a:style_id == s:DIFF_T_ID', 2936c35beaaSBram Moolenaar \ ' let l:saved_style = get(s:diffstylelist,a:style_id)', 2946c35beaaSBram Moolenaar \ ' else' 2956c35beaaSBram Moolenaar \ ] 2966c35beaaSBram Moolenaar endif 2976c35beaaSBram Moolenaar 2986c35beaaSBram Moolenaar " get primary style info from cache or build it on the fly if not found 2996c35beaaSBram Moolenaar let wrapperfunc_lines += [ 3006c35beaaSBram Moolenaar \ ' let l:saved_style = get(s:stylelist,a:style_id)', 3016c35beaaSBram Moolenaar \ ' if type(l:saved_style) == type(0)', 3026c35beaaSBram Moolenaar \ ' unlet l:saved_style', 3036c35beaaSBram Moolenaar \ ' let l:saved_style = s:CSS1(a:style_id)', 3046c35beaaSBram Moolenaar \ ' if l:saved_style != ""', 3056c35beaaSBram Moolenaar \ ' let l:saved_style = "." . l:style_name . " { " . l:saved_style . "}"', 3066c35beaaSBram Moolenaar \ ' endif', 3076c35beaaSBram Moolenaar \ ' let s:stylelist[a:style_id]= l:saved_style', 3086c35beaaSBram Moolenaar \ ' endif' 3096c35beaaSBram Moolenaar \ ] 3106c35beaaSBram Moolenaar if &diff 3116c35beaaSBram Moolenaar let wrapperfunc_lines += [ ' endif' ] 3126c35beaaSBram Moolenaar endif 3136c35beaaSBram Moolenaar 3146c35beaaSBram Moolenaar " Build the wrapper tags around the text. It turns out that caching these 3156c35beaaSBram Moolenaar " gives pretty much zero performance gain and adds a lot of logic. 3166c35beaaSBram Moolenaar 3176c35beaaSBram Moolenaar let wrapperfunc_lines += [ 3186c35beaaSBram Moolenaar \ '', 319543b7ef7SBram Moolenaar \ ' if l:saved_style == "" && empty(a:extra_attrs)' 3206c35beaaSBram Moolenaar \ ] 3216c35beaaSBram Moolenaar if &diff 3226c35beaaSBram Moolenaar let wrapperfunc_lines += [ 3236c35beaaSBram Moolenaar \ ' if a:diff_style_id <= 0' 3246c35beaaSBram Moolenaar \ ] 3256c35beaaSBram Moolenaar endif 3266c35beaaSBram Moolenaar " no surroundings if neither primary nor diff style has any info 3276c35beaaSBram Moolenaar let wrapperfunc_lines += [ 3286c35beaaSBram Moolenaar \ ' return a:text' 3296c35beaaSBram Moolenaar \ ] 3306c35beaaSBram Moolenaar if &diff 3316c35beaaSBram Moolenaar " no primary style, but diff style 3326c35beaaSBram Moolenaar let wrapperfunc_lines += [ 3336c35beaaSBram Moolenaar \ ' else', 3346c35beaaSBram Moolenaar \ ' return "<span class=\"" .l:diff_style_name . "\">".a:text."</span>"', 3356c35beaaSBram Moolenaar \ ' endif' 3366c35beaaSBram Moolenaar \ ] 3376c35beaaSBram Moolenaar endif 3386c35beaaSBram Moolenaar " open tag for non-empty primary style 3396c35beaaSBram Moolenaar let wrapperfunc_lines += [ 3406c35beaaSBram Moolenaar \ ' else'] 3416c35beaaSBram Moolenaar " non-empty primary style. handle either empty or non-empty diff style. 3426c35beaaSBram Moolenaar " 3436c35beaaSBram Moolenaar " separate the two classes by a space to apply them both if there is a diff 3446c35beaaSBram Moolenaar " style name, unless the primary style is empty, then just use the diff style 3456c35beaaSBram Moolenaar " name 3466c35beaaSBram Moolenaar let diffstyle = 3476c35beaaSBram Moolenaar \ (&diff ? '(a:diff_style_id <= 0 ? "" : " ". l:diff_style_name) .' 3486c35beaaSBram Moolenaar \ : "") 3496c35beaaSBram Moolenaar if s:settings.prevent_copy == "" 3506c35beaaSBram Moolenaar let wrapperfunc_lines += [ 351543b7ef7SBram Moolenaar \ ' return "<span ".a:extra_attrs."class=\"" . l:style_name .'.diffstyle.'"\">".a:text."</span>"' 3526c35beaaSBram Moolenaar \ ] 3536c35beaaSBram Moolenaar else 3546c35beaaSBram Moolenaar 3556c35beaaSBram Moolenaar " 3566c35beaaSBram Moolenaar " Wrap the <input> in a <span> to allow fixing the stupid bug in some fonts 3576c35beaaSBram Moolenaar " which cause browsers to display a 1px gap between lines when these 3586c35beaaSBram Moolenaar " <input>s have a background color (maybe not really a bug, this isn't 3596c35beaaSBram Moolenaar " well-defined) 3606c35beaaSBram Moolenaar " 3616c35beaaSBram Moolenaar " use strwidth, because we care only about how many character boxes are 3626c35beaaSBram Moolenaar " needed to size the input, we don't care how many characters (including 3636c35beaaSBram Moolenaar " separately counted composing chars, from strchars()) or bytes (from 3646c35beaaSBram Moolenaar " len())the string contains. strdisplaywidth() is not needed because none of 3656c35beaaSBram Moolenaar " the unselectable groups can contain tab characters (fold column, fold 3666c35beaaSBram Moolenaar " text, line number). 3676c35beaaSBram Moolenaar " 3686c35beaaSBram Moolenaar " Note, if maxlength property needs to be added in the future, it will need 3696c35beaaSBram Moolenaar " to use strchars(), because HTML specifies that the maxlength parameter 3706c35beaaSBram Moolenaar " uses the number of unique codepoints for its limit. 3716c35beaaSBram Moolenaar let wrapperfunc_lines += [ 3726c35beaaSBram Moolenaar \ ' if a:make_unselectable', 373543b7ef7SBram Moolenaar \ ' return "<span ".a:extra_attrs."class=\"" . l:style_name .'.diffstyle.'"\">'. 3746c35beaaSBram Moolenaar \ '<input'.s:unselInputType.' class=\"" . l:style_name .'.diffstyle.'"\"'. 3756c35beaaSBram Moolenaar \ ' value=\"".substitute(a:unformatted,''\s\+$'',"","")."\"'. 3766c35beaaSBram Moolenaar \ ' onselect=''this.blur(); return false;'''. 3776c35beaaSBram Moolenaar \ ' onmousedown=''this.blur(); return false;'''. 3786c35beaaSBram Moolenaar \ ' onclick=''this.blur(); return false;'''. 3796c35beaaSBram Moolenaar \ ' readonly=''readonly'''. 3806c35beaaSBram Moolenaar \ ' size=\"".strwidth(a:unformatted)."\"'. 3816c35beaaSBram Moolenaar \ (s:settings.use_xhtml ? '/' : '').'></span>"', 3826c35beaaSBram Moolenaar \ ' else', 383543b7ef7SBram Moolenaar \ ' return "<span ".a:extra_attrs."class=\"" . l:style_name .'. diffstyle .'"\">".a:text."</span>"' 3846c35beaaSBram Moolenaar \ ] 3856c35beaaSBram Moolenaar endif 3866c35beaaSBram Moolenaar let wrapperfunc_lines += [ 3876c35beaaSBram Moolenaar \ ' endif', 3886c35beaaSBram Moolenaar \ 'endfun' 3896c35beaaSBram Moolenaar \ ] 3906c35beaaSBram Moolenaarelse 3916c35beaaSBram Moolenaar " Non-CSS method just needs the wrapper. 3926c35beaaSBram Moolenaar " 3936c35beaaSBram Moolenaar " Functions used to get opening/closing automatically return null strings if 3946c35beaaSBram Moolenaar " no styles exist. 3956c35beaaSBram Moolenaar if &diff 3966c35beaaSBram Moolenaar let wrapperfunc_lines = [ 397543b7ef7SBram Moolenaar \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2)', 398543b7ef7SBram Moolenaar \ ' return s:HtmlOpening(a:style_id, a:extra_attrs).(a:diff_style_id <= 0 ? "" :'. 399543b7ef7SBram Moolenaar \ 's:HtmlOpening(a:diff_style_id, "")).a:text.'. 400543b7ef7SBram Moolenaar \ '(a:diff_style_id <= 0 ? "" : s:HtmlClosing(a:diff_style_id, 0)).s:HtmlClosing(a:style_id, !empty(a:extra_attrs))', 4016c35beaaSBram Moolenaar \ 'endfun' 4026c35beaaSBram Moolenaar \ ] 4036c35beaaSBram Moolenaar else 4046c35beaaSBram Moolenaar let wrapperfunc_lines = [ 405543b7ef7SBram Moolenaar \ 'function! s:BuildStyleWrapper(style_id, diff_style_id, extra_attrs, text, unusedarg, unusedarg2)', 406543b7ef7SBram Moolenaar \ ' return s:HtmlOpening(a:style_id, a:extra_attrs).a:text.s:HtmlClosing(a:style_id, !empty(a:extra_attrs))', 4076c35beaaSBram Moolenaar \ 'endfun' 4086c35beaaSBram Moolenaar \ ] 4096c35beaaSBram Moolenaar endif 4106c35beaaSBram Moolenaarendif 4116c35beaaSBram Moolenaar 4126c35beaaSBram Moolenaar" create the function we built line by line above 4136c35beaaSBram Moolenaarexec join(wrapperfunc_lines, "\n") 4146c35beaaSBram Moolenaar 4156c35beaaSBram Moolenaarlet s:diff_mode = &diff 4166c35beaaSBram Moolenaar 41735a9aaabSBram Moolenaar" Return HTML valid characters enclosed in a span of class style_name with 41835a9aaabSBram Moolenaar" unprintable characters expanded and double spaces replaced as necessary. 4196c35beaaSBram Moolenaar" 4206c35beaaSBram Moolenaar" TODO: eliminate unneeded logic like done for BuildStyleWrapper 421543b7ef7SBram Moolenaarfunction! s:HtmlFormat(text, style_id, diff_style_id, extra_attrs, make_unselectable) 42235a9aaabSBram Moolenaar " Replace unprintable characters 4236c35beaaSBram Moolenaar let unformatted = strtrans(a:text) 42435a9aaabSBram Moolenaar 4256c35beaaSBram Moolenaar let formatted = unformatted 4268ada2ccaSBram Moolenaar 42735a9aaabSBram Moolenaar " Replace the reserved html characters 4282a8a3ecbSBram Moolenaar let formatted = substitute(formatted, '&', '\&', 'g') 4292a8a3ecbSBram Moolenaar let formatted = substitute(formatted, '<', '\<', 'g') 4302a8a3ecbSBram Moolenaar let formatted = substitute(formatted, '>', '\>', 'g') 4312a8a3ecbSBram Moolenaar let formatted = substitute(formatted, '"', '\"', 'g') 4326c35beaaSBram Moolenaar " ' is not valid in HTML but it is in XHTML, so just use the numeric 4336c35beaaSBram Moolenaar " reference for it instead. Needed because it could appear in quotes 4346c35beaaSBram Moolenaar " especially if unselectable regions is turned on. 4356c35beaaSBram Moolenaar let formatted = substitute(formatted, '"', '\'', 'g') 4362a8a3ecbSBram Moolenaar 4372a8a3ecbSBram Moolenaar " Replace a "form feed" character with HTML to do a page break 4386c35beaaSBram Moolenaar " TODO: need to prevent this in unselectable areas? Probably it should never 4396c35beaaSBram Moolenaar " BE in an unselectable area... 4402a8a3ecbSBram Moolenaar let formatted = substitute(formatted, "\x0c", '<hr class="PAGE-BREAK">', 'g') 4412a8a3ecbSBram Moolenaar 4428df7f888SBram Moolenaar " Replace double spaces, leading spaces, and trailing spaces if needed 44335a9aaabSBram Moolenaar if ' ' != s:HtmlSpace 44435a9aaabSBram Moolenaar let formatted = substitute(formatted, ' ', s:HtmlSpace . s:HtmlSpace, 'g') 4458424a624SBram Moolenaar let formatted = substitute(formatted, '^ ', s:HtmlSpace, 'g') 4468df7f888SBram Moolenaar let formatted = substitute(formatted, ' \+$', s:HtmlSpace, 'g') 44735a9aaabSBram Moolenaar endif 44835a9aaabSBram Moolenaar 4496c35beaaSBram Moolenaar " Enclose in the correct format 450543b7ef7SBram Moolenaar return s:BuildStyleWrapper(a:style_id, a:diff_style_id, a:extra_attrs, formatted, a:make_unselectable, unformatted) 45135a9aaabSBram Moolenaarendfun 45235a9aaabSBram Moolenaar 4536c35beaaSBram Moolenaar" set up functions to call HtmlFormat in certain ways based on whether the 4546c35beaaSBram Moolenaar" element is supposed to be unselectable or not 4556c35beaaSBram Moolenaarif s:settings.prevent_copy =~# 'n' 456543b7ef7SBram Moolenaar if s:settings.number_lines 45731c31679SBram Moolenaar if s:settings.line_ids 458543b7ef7SBram Moolenaar function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr) 459543b7ef7SBram Moolenaar if a:lnr > 0 46031c31679SBram Moolenaar return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 'id="'.(exists('g:html_diff_win_num') ? 'W'.g:html_diff_win_num : "").'L'.a:lnr.s:settings.id_suffix.'" ', 1) 461543b7ef7SBram Moolenaar else 462543b7ef7SBram Moolenaar return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1) 463543b7ef7SBram Moolenaar endif 4646c35beaaSBram Moolenaar endfun 4656c35beaaSBram Moolenaar else 46631c31679SBram Moolenaar function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr) 46731c31679SBram Moolenaar return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1) 46831c31679SBram Moolenaar endfun 46931c31679SBram Moolenaar endif 47031c31679SBram Moolenaar elseif s:settings.line_ids 471543b7ef7SBram Moolenaar " if lines are not being numbered the only reason this function gets called 472543b7ef7SBram Moolenaar " is to put the line IDs on each line; "text" will be emtpy but lnr will 473543b7ef7SBram Moolenaar " always be non-zero, however we don't want to use the <input> because that 474543b7ef7SBram Moolenaar " won't work as nice for empty text 475543b7ef7SBram Moolenaar function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr) 47631c31679SBram Moolenaar return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 'id="'.(exists('g:html_diff_win_num') ? 'W'.g:html_diff_win_num : "").'L'.a:lnr.s:settings.id_suffix.'" ', 0) 477543b7ef7SBram Moolenaar endfun 478543b7ef7SBram Moolenaar endif 479543b7ef7SBram Moolenaarelse 48031c31679SBram Moolenaar if s:settings.line_ids 481543b7ef7SBram Moolenaar function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr) 482543b7ef7SBram Moolenaar if a:lnr > 0 48331c31679SBram Moolenaar return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, 'id="'.(exists('g:html_diff_win_num') ? 'W'.g:html_diff_win_num : "").'L'.a:lnr.s:settings.id_suffix.'" ', 0) 484543b7ef7SBram Moolenaar else 485543b7ef7SBram Moolenaar return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0) 486543b7ef7SBram Moolenaar endif 4876c35beaaSBram Moolenaar endfun 48831c31679SBram Moolenaar else 48931c31679SBram Moolenaar function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr) 49031c31679SBram Moolenaar return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0) 49131c31679SBram Moolenaar endfun 49231c31679SBram Moolenaar endif 4936c35beaaSBram Moolenaarendif 4946c35beaaSBram Moolenaarif s:settings.prevent_copy =~# 'd' 4956c35beaaSBram Moolenaar function! s:HtmlFormat_d(text, style_id, diff_style_id) 496543b7ef7SBram Moolenaar return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1) 4976c35beaaSBram Moolenaar endfun 4986c35beaaSBram Moolenaarelse 4996c35beaaSBram Moolenaar function! s:HtmlFormat_d(text, style_id, diff_style_id) 500543b7ef7SBram Moolenaar return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0) 5016c35beaaSBram Moolenaar endfun 5026c35beaaSBram Moolenaarendif 5036c35beaaSBram Moolenaarif s:settings.prevent_copy =~# 'f' 5046c35beaaSBram Moolenaar " Note the <input> elements for fill spaces will have a single space for 5056c35beaaSBram Moolenaar " content, to allow active cursor CSS selection to work. 5066c35beaaSBram Moolenaar " 5076c35beaaSBram Moolenaar " Wrap the whole thing in a span for the 1px padding workaround for gaps. 5086c35beaaSBram Moolenaar function! s:FoldColumn_build(char, len, numfill, char2, class, click) 5096c35beaaSBram Moolenaar let l:input_open = "<input readonly='readonly'".s:unselInputType. 5106c35beaaSBram Moolenaar \ " onselect='this.blur(); return false;'". 5116c35beaaSBram Moolenaar \ " onmousedown='this.blur(); ".a:click." return false;'". 5126c35beaaSBram Moolenaar \ " onclick='return false;' size='". 5136c35beaaSBram Moolenaar \ string(a:len + (empty(a:char2) ? 0 : 1) + a:numfill) . 5146c35beaaSBram Moolenaar \ "' " 5156c35beaaSBram Moolenaar let l:common_attrs = "class='FoldColumn' value='" 5166c35beaaSBram Moolenaar let l:input_close = (s:settings.use_xhtml ? "' />" : "'>") 5176c35beaaSBram Moolenaar return "<span class='".a:class."'>". 5186c35beaaSBram Moolenaar \ l:input_open.l:common_attrs.repeat(a:char, a:len). 5196c35beaaSBram Moolenaar \ (!empty(a:char2) ? a:char2 : ""). 5206c35beaaSBram Moolenaar \ l:input_close . "</span>" 5216c35beaaSBram Moolenaar endfun 5226c35beaaSBram Moolenaar function! s:FoldColumn_fill() 5236c35beaaSBram Moolenaar return s:FoldColumn_build('', s:foldcolumn, 0, '', 'FoldColumn', '') 5246c35beaaSBram Moolenaar endfun 5256c35beaaSBram Moolenaarelse 5266c35beaaSBram Moolenaar " For normal fold columns, simply space-pad to the desired width (note that 5276c35beaaSBram Moolenaar " the FoldColumn definition includes a whitespace:pre rule) 5286c35beaaSBram Moolenaar function! s:FoldColumn_build(char, len, numfill, char2, class, click) 5296c35beaaSBram Moolenaar return "<a href='#' class='".a:class."' onclick='".a:click."'>". 5306c35beaaSBram Moolenaar \ repeat(a:char, a:len).a:char2.repeat(' ', a:numfill). 5316c35beaaSBram Moolenaar \ "</a>" 5326c35beaaSBram Moolenaar endfun 5336c35beaaSBram Moolenaar function! s:FoldColumn_fill() 534543b7ef7SBram Moolenaar return s:HtmlFormat(repeat(' ', s:foldcolumn), s:FOLD_C_ID, 0, "", 0) 5356c35beaaSBram Moolenaar endfun 5366c35beaaSBram Moolenaarendif 5376c35beaaSBram Moolenaarif s:settings.prevent_copy =~# 't' 5386c35beaaSBram Moolenaar " put an extra empty span at the end for dynamic folds, so the linebreak can 5396c35beaaSBram Moolenaar " be surrounded. Otherwise do it as normal. 5406c35beaaSBram Moolenaar " 5416c35beaaSBram Moolenaar " TODO: isn't there a better way to do this, than placing it here and using a 5426c35beaaSBram Moolenaar " substitute later? 5436c35beaaSBram Moolenaar if s:settings.dynamic_folds 5446c35beaaSBram Moolenaar function! s:HtmlFormat_t(text, style_id, diff_style_id) 545543b7ef7SBram Moolenaar return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1) . 546543b7ef7SBram Moolenaar \ s:HtmlFormat("", a:style_id, 0, "", 0) 5476c35beaaSBram Moolenaar endfun 5486c35beaaSBram Moolenaar else 5496c35beaaSBram Moolenaar function! s:HtmlFormat_t(text, style_id, diff_style_id) 550543b7ef7SBram Moolenaar return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 1) 5516c35beaaSBram Moolenaar endfun 5526c35beaaSBram Moolenaar endif 5536c35beaaSBram Moolenaarelse 5546c35beaaSBram Moolenaar function! s:HtmlFormat_t(text, style_id, diff_style_id) 555543b7ef7SBram Moolenaar return s:HtmlFormat(a:text, a:style_id, a:diff_style_id, "", 0) 5566c35beaaSBram Moolenaar endfun 5576c35beaaSBram Moolenaarendif 5586c35beaaSBram Moolenaar 559071d4279SBram Moolenaar" Return CSS style describing given highlight id (can be empty) 560071d4279SBram Moolenaarfunction! s:CSS1(id) 561071d4279SBram Moolenaar let a = "" 562071d4279SBram Moolenaar if synIDattr(a:id, "inverse") 563071d4279SBram Moolenaar " For inverse, we always must set both colors (and exchange them) 564071d4279SBram Moolenaar let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) 565071d4279SBram Moolenaar let a = a . "color: " . ( x != "" ? x : s:bgc ) . "; " 566071d4279SBram Moolenaar let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) 567071d4279SBram Moolenaar let a = a . "background-color: " . ( x != "" ? x : s:fgc ) . "; " 568071d4279SBram Moolenaar else 569071d4279SBram Moolenaar let x = s:HtmlColor(synIDattr(a:id, "fg#", s:whatterm)) 570071d4279SBram Moolenaar if x != "" | let a = a . "color: " . x . "; " | endif 571071d4279SBram Moolenaar let x = s:HtmlColor(synIDattr(a:id, "bg#", s:whatterm)) 5726c35beaaSBram Moolenaar if x != "" 5736c35beaaSBram Moolenaar let a = a . "background-color: " . x . "; " 5746c35beaaSBram Moolenaar " stupid hack because almost every browser seems to have at least one font 5756c35beaaSBram Moolenaar " which shows 1px gaps between lines which have background 5766c35beaaSBram Moolenaar let a = a . "padding-bottom: 1px; " 5776c35beaaSBram Moolenaar elseif (a:id == s:FOLDED_ID || a:id == s:LINENR_ID || a:id == s:FOLD_C_ID) && !empty(s:settings.prevent_copy) 5786c35beaaSBram Moolenaar " input elements default to a different color than the rest of the page 5796c35beaaSBram Moolenaar let a = a . "background-color: " . s:bgc . "; " 5806c35beaaSBram Moolenaar endif 581071d4279SBram Moolenaar endif 582071d4279SBram Moolenaar if synIDattr(a:id, "bold") | let a = a . "font-weight: bold; " | endif 583071d4279SBram Moolenaar if synIDattr(a:id, "italic") | let a = a . "font-style: italic; " | endif 584071d4279SBram Moolenaar if synIDattr(a:id, "underline") | let a = a . "text-decoration: underline; " | endif 585071d4279SBram Moolenaar return a 586071d4279SBram Moolenaarendfun 587071d4279SBram Moolenaar 588076e8b2aSBram Moolenaarif s:settings.dynamic_folds 5895c73622aSBram Moolenaar " compares two folds as stored in our list of folds 5905c73622aSBram Moolenaar " A fold is "less" than another if it starts at an earlier line number, 5915c73622aSBram Moolenaar " or ends at a later line number, ties broken by fold level 5925c73622aSBram Moolenaar function! s:FoldCompare(f1, f2) 5935c73622aSBram Moolenaar if a:f1.firstline != a:f2.firstline 5945c73622aSBram Moolenaar " put it before if it starts earlier 5955c73622aSBram Moolenaar return a:f1.firstline - a:f2.firstline 5965c73622aSBram Moolenaar elseif a:f1.lastline != a:f2.lastline 5975c73622aSBram Moolenaar " put it before if it ends later 5985c73622aSBram Moolenaar return a:f2.lastline - a:f1.lastline 5995c73622aSBram Moolenaar else 6005c73622aSBram Moolenaar " if folds begin and end on the same lines, put lowest fold level first 6015c73622aSBram Moolenaar return a:f1.level - a:f2.level 6025c73622aSBram Moolenaar endif 6035c73622aSBram Moolenaar endfunction 6045c73622aSBram Moolenaar 6055c73622aSBram Moolenaarendif 6065c73622aSBram Moolenaar 607071d4279SBram Moolenaar 608071d4279SBram Moolenaar" Set some options to make it work faster. 609071d4279SBram Moolenaar" Don't report changes for :substitute, there will be many of them. 6108df7f888SBram Moolenaar" Don't change other windows; turn off scroll bind temporarily 611071d4279SBram Moolenaarlet s:old_title = &title 612071d4279SBram Moolenaarlet s:old_icon = &icon 613071d4279SBram Moolenaarlet s:old_et = &l:et 6148df7f888SBram Moolenaarlet s:old_bind = &l:scrollbind 615071d4279SBram Moolenaarlet s:old_report = &report 616071d4279SBram Moolenaarlet s:old_search = @/ 617349b2fb0SBram Moolenaarlet s:old_more = &more 618071d4279SBram Moolenaarset notitle noicon 619071d4279SBram Moolenaarsetlocal et 620349b2fb0SBram Moolenaarset nomore 621071d4279SBram Moolenaarset report=1000000 6228df7f888SBram Moolenaarsetlocal noscrollbind 623071d4279SBram Moolenaar 6247510fe74SBram Moolenaarif exists(':ownsyntax') && exists('w:current_syntax') 6257510fe74SBram Moolenaar let s:current_syntax = w:current_syntax 6267510fe74SBram Moolenaarelseif exists('b:current_syntax') 6277510fe74SBram Moolenaar let s:current_syntax = b:current_syntax 6287510fe74SBram Moolenaarelse 6297510fe74SBram Moolenaar let s:current_syntax = 'none' 6307510fe74SBram Moolenaarendif 6317510fe74SBram Moolenaar 6327510fe74SBram Moolenaarif s:current_syntax == '' 6337510fe74SBram Moolenaar let s:current_syntax = 'none' 6347510fe74SBram Moolenaarendif 6357510fe74SBram Moolenaar 636071d4279SBram Moolenaar" Split window to create a buffer with the HTML file. 637071d4279SBram Moolenaarlet s:orgbufnr = winbufnr(0) 638349b2fb0SBram Moolenaarlet s:origwin_stl = &l:stl 639071d4279SBram Moolenaarif expand("%") == "" 640543b7ef7SBram Moolenaar if exists('g:html_diff_win_num') 641543b7ef7SBram Moolenaar exec 'new Untitled_win'.g:html_diff_win_num.'.'.(s:settings.use_xhtml ? 'x' : '').'html' 642543b7ef7SBram Moolenaar else 643076e8b2aSBram Moolenaar exec 'new Untitled.'.(s:settings.use_xhtml ? 'x' : '').'html' 644543b7ef7SBram Moolenaar endif 645071d4279SBram Moolenaarelse 646076e8b2aSBram Moolenaar exec 'new %.'.(s:settings.use_xhtml ? 'x' : '').'html' 647071d4279SBram Moolenaarendif 648349b2fb0SBram Moolenaar 649349b2fb0SBram Moolenaar" Resize the new window to very small in order to make it draw faster 650349b2fb0SBram Moolenaarlet s:old_winheight = winheight(0) 651349b2fb0SBram Moolenaarlet s:old_winfixheight = &l:winfixheight 652349b2fb0SBram Moolenaarif s:old_winheight > 2 653349b2fb0SBram Moolenaar resize 1 " leave enough room to view one line at a time 654349b2fb0SBram Moolenaar norm! G 655349b2fb0SBram Moolenaar norm! zt 656349b2fb0SBram Moolenaarendif 657349b2fb0SBram Moolenaarsetlocal winfixheight 658349b2fb0SBram Moolenaar 659349b2fb0SBram Moolenaarlet s:newwin_stl = &l:stl 660349b2fb0SBram Moolenaar 661349b2fb0SBram Moolenaar" on the new window, set the least time-consuming fold method 6628df7f888SBram Moolenaarlet s:old_fen = &foldenable 663349b2fb0SBram Moolenaarsetlocal foldmethod=manual 6648df7f888SBram Moolenaarsetlocal nofoldenable 665349b2fb0SBram Moolenaar 666071d4279SBram Moolenaarlet s:newwin = winnr() 667071d4279SBram Moolenaarlet s:orgwin = bufwinnr(s:orgbufnr) 668071d4279SBram Moolenaar 669349b2fb0SBram Moolenaarsetlocal modifiable 670071d4279SBram Moolenaar%d 671071d4279SBram Moolenaarlet s:old_paste = &paste 672071d4279SBram Moolenaarset paste 673071d4279SBram Moolenaarlet s:old_magic = &magic 674071d4279SBram Moolenaarset magic 675071d4279SBram Moolenaar 676166af9bbSBram Moolenaar" set the fileencoding to match the charset we'll be using 677166af9bbSBram Moolenaarlet &l:fileencoding=s:settings.vim_encoding 678166af9bbSBram Moolenaar 679166af9bbSBram Moolenaar" According to http://www.w3.org/TR/html4/charset.html#doc-char-set, the byte 680166af9bbSBram Moolenaar" order mark is highly recommend on the web when using multibyte encodings. But, 681166af9bbSBram Moolenaar" it is not a good idea to include it on UTF-8 files. Otherwise, let Vim 682166af9bbSBram Moolenaar" determine when it is actually inserted. 683166af9bbSBram Moolenaarif s:settings.vim_encoding == 'utf-8' 684166af9bbSBram Moolenaar setlocal nobomb 685166af9bbSBram Moolenaarelse 686166af9bbSBram Moolenaar setlocal bomb 687166af9bbSBram Moolenaarendif 688166af9bbSBram Moolenaar 689349b2fb0SBram Moolenaarlet s:lines = [] 690349b2fb0SBram Moolenaar 691076e8b2aSBram Moolenaarif s:settings.use_xhtml 692bebca9daSBram Moolenaar if s:settings.encoding != "" 693bebca9daSBram Moolenaar call add(s:lines, "<?xml version=\"1.0\" encoding=\"" . s:settings.encoding . "\"?>") 6941cd871b5SBram Moolenaar else 695349b2fb0SBram Moolenaar call add(s:lines, "<?xml version=\"1.0\"?>") 6961cd871b5SBram Moolenaar endif 69735a9aaabSBram Moolenaar let s:tag_close = ' />' 698071d4279SBram Moolenaarelse 69935a9aaabSBram Moolenaar let s:tag_close = '>' 70035a9aaabSBram Moolenaarendif 70135a9aaabSBram Moolenaar 70235a9aaabSBram Moolenaarlet s:HtmlSpace = ' ' 703c1e37901SBram Moolenaarlet s:LeadingSpace = ' ' 70435a9aaabSBram Moolenaarlet s:HtmlEndline = '' 705076e8b2aSBram Moolenaarif s:settings.no_pre 70635a9aaabSBram Moolenaar let s:HtmlEndline = '<br' . s:tag_close 707543b7ef7SBram Moolenaar let s:LeadingSpace = s:settings.use_xhtml ? ' ' : ' ' 708c1e37901SBram Moolenaar let s:HtmlSpace = '\' . s:LeadingSpace 709071d4279SBram Moolenaarendif 710071d4279SBram Moolenaar 711071d4279SBram Moolenaar" HTML header, with the title and generator ;-). Left free space for the CSS, 712071d4279SBram Moolenaar" to be filled at the end. 713349b2fb0SBram Moolenaarcall extend(s:lines, [ 714349b2fb0SBram Moolenaar \ "<html>", 715bebca9daSBram Moolenaar \ "<head>"]) 716bebca9daSBram Moolenaar" include encoding as close to the top as possible, but only if not already 717bebca9daSBram Moolenaar" contained in XML information (to avoid haggling over content type) 718bebca9daSBram Moolenaarif s:settings.encoding != "" && !s:settings.use_xhtml 719bebca9daSBram Moolenaar call add(s:lines, "<meta http-equiv=\"content-type\" content=\"text/html; charset=" . s:settings.encoding . '"' . s:tag_close) 720bebca9daSBram Moolenaarendif 721bebca9daSBram Moolenaarcall extend(s:lines, [ 722349b2fb0SBram Moolenaar \ ("<title>".expand("%:p:~")."</title>"), 723349b2fb0SBram Moolenaar \ ("<meta name=\"Generator\" content=\"Vim/".v:version/100.".".v:version%100.'"'.s:tag_close), 724bebca9daSBram Moolenaar \ ("<meta name=\"plugin-version\" content=\"".g:loaded_2html_plugin.'"'.s:tag_close) 725349b2fb0SBram Moolenaar \ ]) 7267510fe74SBram Moolenaarcall add(s:lines, '<meta name="syntax" content="'.s:current_syntax.'"'.s:tag_close) 727076e8b2aSBram Moolenaarcall add(s:lines, '<meta name="settings" content="'. 728076e8b2aSBram Moolenaar \ join(filter(keys(s:settings),'s:settings[v:val]'),','). 7296c35beaaSBram Moolenaar \ ',prevent_copy='.s:settings.prevent_copy. 730076e8b2aSBram Moolenaar \ '"'.s:tag_close) 7316c35beaaSBram Moolenaarcall add(s:lines, '<meta name="colorscheme" content="'. 7326c35beaaSBram Moolenaar \ (exists('g:colors_name') 7336c35beaaSBram Moolenaar \ ? g:colors_name 7346c35beaaSBram Moolenaar \ : 'none'). '"'.s:tag_close) 735313b7237SBram Moolenaar 736076e8b2aSBram Moolenaarif s:settings.use_css 737076e8b2aSBram Moolenaar if s:settings.dynamic_folds 738076e8b2aSBram Moolenaar if s:settings.hover_unfold 7395c73622aSBram Moolenaar " if we are doing hover_unfold, use css 2 with css 1 fallback for IE6 740349b2fb0SBram Moolenaar call extend(s:lines, [ 741349b2fb0SBram Moolenaar \ "<style type=\"text/css\">", 742bebca9daSBram Moolenaar \ s:settings.use_xhtml ? "" : "<!--", 743349b2fb0SBram Moolenaar \ ".FoldColumn { text-decoration: none; white-space: pre; }", 744349b2fb0SBram Moolenaar \ "", 745349b2fb0SBram Moolenaar \ "body * { margin: 0; padding: 0; }", "", 746349b2fb0SBram Moolenaar \ ".open-fold > .Folded { display: none; }", 747349b2fb0SBram Moolenaar \ ".open-fold > .fulltext { display: inline; }", 748349b2fb0SBram Moolenaar \ ".closed-fold > .fulltext { display: none; }", 749349b2fb0SBram Moolenaar \ ".closed-fold > .Folded { display: inline; }", 750349b2fb0SBram Moolenaar \ "", 751349b2fb0SBram Moolenaar \ ".open-fold > .toggle-open { display: none; }", 752349b2fb0SBram Moolenaar \ ".open-fold > .toggle-closed { display: inline; }", 753349b2fb0SBram Moolenaar \ ".closed-fold > .toggle-open { display: inline; }", 754349b2fb0SBram Moolenaar \ ".closed-fold > .toggle-closed { display: none; }", 755349b2fb0SBram Moolenaar \ "", "", 756349b2fb0SBram Moolenaar \ '/* opening a fold while hovering won''t be supported by IE6 and other', 757349b2fb0SBram Moolenaar \ "similar browsers, but it should fail gracefully. */", 758349b2fb0SBram Moolenaar \ ".closed-fold:hover > .fulltext { display: inline; }", 759349b2fb0SBram Moolenaar \ ".closed-fold:hover > .toggle-filler { display: none; }", 760349b2fb0SBram Moolenaar \ ".closed-fold:hover > .Folded { display: none; }", 761bebca9daSBram Moolenaar \ s:settings.use_xhtml ? "" : '-->', 7628df7f888SBram Moolenaar \ '</style>']) 763bebca9daSBram Moolenaar " TODO: IE7 doesn't *actually* support XHTML, maybe we should remove this. 764bebca9daSBram Moolenaar " But if it's served up as tag soup, maybe the following will work, so 765bebca9daSBram Moolenaar " leave it in for now. 766bebca9daSBram Moolenaar call extend(s:lines, [ 767349b2fb0SBram Moolenaar \ "<!--[if lt IE 7]><style type=\"text/css\">", 768349b2fb0SBram Moolenaar \ ".open-fold .Folded { display: none; }", 769349b2fb0SBram Moolenaar \ ".open-fold .fulltext { display: inline; }", 770349b2fb0SBram Moolenaar \ ".open-fold .toggle-open { display: none; }", 771349b2fb0SBram Moolenaar \ ".closed-fold .toggle-closed { display: inline; }", 772349b2fb0SBram Moolenaar \ "", 773349b2fb0SBram Moolenaar \ ".closed-fold .fulltext { display: none; }", 774349b2fb0SBram Moolenaar \ ".closed-fold .Folded { display: inline; }", 775349b2fb0SBram Moolenaar \ ".closed-fold .toggle-open { display: inline; }", 776349b2fb0SBram Moolenaar \ ".closed-fold .toggle-closed { display: none; }", 777349b2fb0SBram Moolenaar \ "</style>", 778349b2fb0SBram Moolenaar \ "<![endif]-->", 779349b2fb0SBram Moolenaar \]) 7805c73622aSBram Moolenaar else 7815c73622aSBram Moolenaar " if we aren't doing hover_unfold, use CSS 1 only 782349b2fb0SBram Moolenaar call extend(s:lines, [ 783349b2fb0SBram Moolenaar \ "<style type=\"text/css\">", 784bebca9daSBram Moolenaar \ s:settings.use_xhtml ? "" :"<!--", 785349b2fb0SBram Moolenaar \ ".FoldColumn { text-decoration: none; white-space: pre; }", 786349b2fb0SBram Moolenaar \ ".open-fold .Folded { display: none; }", 787349b2fb0SBram Moolenaar \ ".open-fold .fulltext { display: inline; }", 788349b2fb0SBram Moolenaar \ ".open-fold .toggle-open { display: none; }", 789349b2fb0SBram Moolenaar \ ".closed-fold .toggle-closed { display: inline; }", 790349b2fb0SBram Moolenaar \ "", 791349b2fb0SBram Moolenaar \ ".closed-fold .fulltext { display: none; }", 792349b2fb0SBram Moolenaar \ ".closed-fold .Folded { display: inline; }", 793349b2fb0SBram Moolenaar \ ".closed-fold .toggle-open { display: inline; }", 794349b2fb0SBram Moolenaar \ ".closed-fold .toggle-closed { display: none; }", 795bebca9daSBram Moolenaar \ s:settings.use_xhtml ? "" : '-->', 796349b2fb0SBram Moolenaar \ '</style>' 797349b2fb0SBram Moolenaar \]) 7985c73622aSBram Moolenaar endif 7995c73622aSBram Moolenaar else 8005c73622aSBram Moolenaar " if we aren't doing any dynamic folding, no need for any special rules 801349b2fb0SBram Moolenaar call extend(s:lines, [ 802349b2fb0SBram Moolenaar \ "<style type=\"text/css\">", 803bebca9daSBram Moolenaar \ s:settings.use_xhtml ? "" : "<!--", 804bebca9daSBram Moolenaar \ s:settings.use_xhtml ? "" : '-->', 805349b2fb0SBram Moolenaar \ "</style>", 806349b2fb0SBram Moolenaar \]) 807071d4279SBram Moolenaar endif 8085c73622aSBram Moolenaarendif 8095c73622aSBram Moolenaar 810543b7ef7SBram Moolenaar" insert script tag; javascript is always needed for the line number 811543b7ef7SBram Moolenaar" normalization for URL hashes 8126c35beaaSBram Moolenaarcall extend(s:lines, [ 8136c35beaaSBram Moolenaar \ "", 8146c35beaaSBram Moolenaar \ "<script type='text/javascript'>", 8156c35beaaSBram Moolenaar \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"]) 8166c35beaaSBram Moolenaar 8175c73622aSBram Moolenaar" insert javascript to toggle folds open and closed 818076e8b2aSBram Moolenaarif s:settings.dynamic_folds 819349b2fb0SBram Moolenaar call extend(s:lines, [ 820349b2fb0SBram Moolenaar \ "", 821349b2fb0SBram Moolenaar \ "function toggleFold(objID)", 822349b2fb0SBram Moolenaar \ "{", 823349b2fb0SBram Moolenaar \ " var fold;", 824349b2fb0SBram Moolenaar \ " fold = document.getElementById(objID);", 825349b2fb0SBram Moolenaar \ " if(fold.className == 'closed-fold')", 826349b2fb0SBram Moolenaar \ " {", 827349b2fb0SBram Moolenaar \ " fold.className = 'open-fold';", 828349b2fb0SBram Moolenaar \ " }", 829349b2fb0SBram Moolenaar \ " else if (fold.className == 'open-fold')", 830349b2fb0SBram Moolenaar \ " {", 831349b2fb0SBram Moolenaar \ " fold.className = 'closed-fold';", 832349b2fb0SBram Moolenaar \ " }", 8336c35beaaSBram Moolenaar \ "}" 8346c35beaaSBram Moolenaar \ ]) 8356c35beaaSBram Moolenaarendif 8366c35beaaSBram Moolenaar 83731c31679SBram Moolenaarif s:settings.line_ids 838543b7ef7SBram Moolenaar " insert javascript to get IDs from line numbers, and to open a fold before 839543b7ef7SBram Moolenaar " jumping to any lines contained therein 840543b7ef7SBram Moolenaar call extend(s:lines, [ 841543b7ef7SBram Moolenaar \ "", 842543b7ef7SBram Moolenaar \ "/* function to open any folds containing a jumped-to line before jumping to it */", 843543b7ef7SBram Moolenaar \ "function JumpToLine()", 844543b7ef7SBram Moolenaar \ "{", 845543b7ef7SBram Moolenaar \ " var lineNum;", 846543b7ef7SBram Moolenaar \ " lineNum = window.location.hash;", 847543b7ef7SBram Moolenaar \ " lineNum = lineNum.substr(1); /* strip off '#' */", 848543b7ef7SBram Moolenaar \ "", 849543b7ef7SBram Moolenaar \ " if (lineNum.indexOf('L') == -1) {", 850543b7ef7SBram Moolenaar \ " lineNum = 'L'+lineNum;", 851543b7ef7SBram Moolenaar \ " }", 852543b7ef7SBram Moolenaar \ " lineElem = document.getElementById(lineNum);" 853543b7ef7SBram Moolenaar \ ]) 854543b7ef7SBram Moolenaar if s:settings.dynamic_folds 855543b7ef7SBram Moolenaar call extend(s:lines, [ 856543b7ef7SBram Moolenaar \ "", 857543b7ef7SBram Moolenaar \ " /* navigate upwards in the DOM tree to open all folds containing the line */", 858543b7ef7SBram Moolenaar \ " var node = lineElem;", 85931c31679SBram Moolenaar \ " while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')", 860543b7ef7SBram Moolenaar \ " {", 861543b7ef7SBram Moolenaar \ " if (node.className == 'closed-fold')", 862543b7ef7SBram Moolenaar \ " {", 863543b7ef7SBram Moolenaar \ " node.className = 'open-fold';", 864543b7ef7SBram Moolenaar \ " }", 865543b7ef7SBram Moolenaar \ " node = node.parentNode;", 866543b7ef7SBram Moolenaar \ " }", 867543b7ef7SBram Moolenaar \ ]) 868543b7ef7SBram Moolenaar endif 869543b7ef7SBram Moolenaar call extend(s:lines, [ 870543b7ef7SBram Moolenaar \ " /* Always jump to new location even if the line was hidden inside a fold, or", 871543b7ef7SBram Moolenaar \ " * we corrected the raw number to a line ID.", 872543b7ef7SBram Moolenaar \ " */", 873543b7ef7SBram Moolenaar \ " if (lineElem) {", 874543b7ef7SBram Moolenaar \ " lineElem.scrollIntoView(true);", 875543b7ef7SBram Moolenaar \ " }", 876543b7ef7SBram Moolenaar \ " return true;", 877543b7ef7SBram Moolenaar \ "}", 878543b7ef7SBram Moolenaar \ "if ('onhashchange' in window) {", 879543b7ef7SBram Moolenaar \ " window.onhashchange = JumpToLine;", 880543b7ef7SBram Moolenaar \ "}" 881543b7ef7SBram Moolenaar \ ]) 88231c31679SBram Moolenaarendif 883543b7ef7SBram Moolenaar 8846c35beaaSBram Moolenaar" Small text columns like the foldcolumn and line number column need a weird 8856c35beaaSBram Moolenaar" hack to work around Webkit's and (in versions prior to 9) IE's lack of support 8866c35beaaSBram Moolenaar" for the 'ch' unit without messing up Opera, which also doesn't support it but 8876c35beaaSBram Moolenaar" works anyway. 8886c35beaaSBram Moolenaar" 8896c35beaaSBram Moolenaar" The problem is that without the 'ch' unit, it is not possible to specify a 8906c35beaaSBram Moolenaar" size of an <input> in terms of character widths. Only Opera seems to do the 8916c35beaaSBram Moolenaar" "sensible" thing and make the <input> sized to fit exactly as many characters 8926c35beaaSBram Moolenaar" as specified by its "size" attribute, but the spec actually says "at least 8936c35beaaSBram Moolenaar" wide enough to fit 'size' characters", so the other browsers are technically 8946c35beaaSBram Moolenaar" correct as well. 8956c35beaaSBram Moolenaar" 8966c35beaaSBram Moolenaar" Anyway, this leads to two diffculties: 8976c35beaaSBram Moolenaar" 1. The foldcolumn is made up of multiple elements side-by-side with 8986c35beaaSBram Moolenaar" different sizes, each of which has their own extra padding added. Thus, a 8996c35beaaSBram Moolenaar" column made up of one item of size 1 and another of size 2 would not 9006c35beaaSBram Moolenaar" necessarily be equal in size to another line's foldcolumn with a single 9016c35beaaSBram Moolenaar" item of size 3. 9026c35beaaSBram Moolenaar" 2. The extra padding added to the <input> elements adds up to make the 9036c35beaaSBram Moolenaar" foldcolumn and line number column too wide, especially in Webkit 9046c35beaaSBram Moolenaar" browsers. 9056c35beaaSBram Moolenaar" 9066c35beaaSBram Moolenaar" So, the full workaround is: 9076c35beaaSBram Moolenaar" 1. Define a default size in em, equal to the number of characters in the 9086c35beaaSBram Moolenaar" input element, in case javascript is disabled and the browser does not 9096c35beaaSBram Moolenaar" support the 'ch' unit. Unfortunately this makes Opera no longer work 9106c35beaaSBram Moolenaar" properly without javascript. 1em per character is much too wide but it 9116c35beaaSBram Moolenaar" looks better in webkit browsers than unaligned columns. 9126c35beaaSBram Moolenaar" 2. Insert the following javascript to run at page load, which checks for the 9136c35beaaSBram Moolenaar" width of a single character (in an extraneous page element inserted 9146c35beaaSBram Moolenaar" before the page title, and set to hidden) and compares it to the width of 9156c35beaaSBram Moolenaar" another extra <input> element with only one character. If the width 9166c35beaaSBram Moolenaar" matches, the script does nothing more, but if not, it will figure out the 9176c35beaaSBram Moolenaar" fraction of an em unit which would correspond with a ch unit if there 9186c35beaaSBram Moolenaar" were one, and set the containing element (<pre> or <div>) to a class with 9196c35beaaSBram Moolenaar" pre-defined rules which is closest to that fraction of an em. Rules are 9206c35beaaSBram Moolenaar" defined from 0.05 em to 1em per ch. 9216c35beaaSBram Moolenaarif !empty(s:settings.prevent_copy) 9226c35beaaSBram Moolenaar call extend(s:lines, [ 9236c35beaaSBram Moolenaar \ '', 9246c35beaaSBram Moolenaar \ '/* simulate a "ch" unit by asking the browser how big a zero character is */', 9256c35beaaSBram Moolenaar \ 'function FixCharWidth() {', 9266c35beaaSBram Moolenaar \ ' /* get the hidden element which gives the width of a single character */', 9276c35beaaSBram Moolenaar \ ' var goodWidth = document.getElementById("oneCharWidth").clientWidth;', 9286c35beaaSBram Moolenaar \ ' /* get all input elements, we''ll filter on class later */', 9296c35beaaSBram Moolenaar \ ' var inputTags = document.getElementsByTagName("input");', 9306c35beaaSBram Moolenaar \ ' var ratio = 5;', 9316c35beaaSBram Moolenaar \ ' var inputWidth = document.getElementById("oneInputWidth").clientWidth;', 9326c35beaaSBram Moolenaar \ ' var emWidth = document.getElementById("oneEmWidth").clientWidth;', 9336c35beaaSBram Moolenaar \ ' if (inputWidth > goodWidth) {', 9346c35beaaSBram Moolenaar \ ' while (ratio < 100*goodWidth/emWidth && ratio < 100) {', 9356c35beaaSBram Moolenaar \ ' ratio += 5;', 9366c35beaaSBram Moolenaar \ ' }', 93731c31679SBram Moolenaar \ ' document.getElementById("vimCodeElement'.s:settings.id_suffix.'").className = "em"+ratio;', 9386c35beaaSBram Moolenaar \ ' }', 9396c35beaaSBram Moolenaar \ '}' 9406c35beaaSBram Moolenaar \ ]) 9416c35beaaSBram Moolenaarendif 9426c35beaaSBram Moolenaar 943543b7ef7SBram Moolenaar" insert script closing tag 9446c35beaaSBram Moolenaarcall extend(s:lines, [ 9456c35beaaSBram Moolenaar \ '', 946bebca9daSBram Moolenaar \ s:settings.use_xhtml ? '//]]>' : '-->', 947349b2fb0SBram Moolenaar \ "</script>" 948349b2fb0SBram Moolenaar \ ]) 9495c73622aSBram Moolenaar 9506c35beaaSBram Moolenaarcall extend(s:lines, ["</head>"]) 9516c35beaaSBram Moolenaarif !empty(s:settings.prevent_copy) 9526c35beaaSBram Moolenaar call extend(s:lines, 95331c31679SBram Moolenaar \ ["<body onload='FixCharWidth();".(s:settings.line_ids ? " JumpToLine();" : "")."'>", 9546c35beaaSBram Moolenaar \ "<!-- hidden divs used by javascript to get the width of a char -->", 9556c35beaaSBram Moolenaar \ "<div id='oneCharWidth'>0</div>", 9566c35beaaSBram Moolenaar \ "<div id='oneInputWidth'><input size='1' value='0'".s:tag_close."</div>", 9576c35beaaSBram Moolenaar \ "<div id='oneEmWidth' style='width: 1em;'></div>" 9586c35beaaSBram Moolenaar \ ]) 959071d4279SBram Moolenaarelse 96031c31679SBram Moolenaar call extend(s:lines, ["<body".(s:settings.line_ids ? " onload='JumpToLine();'" : "").">"]) 9616c35beaaSBram Moolenaarendif 9626c35beaaSBram Moolenaarif s:settings.no_pre 9636c35beaaSBram Moolenaar " if we're not using CSS we use a font tag which can't have a div inside 9646c35beaaSBram Moolenaar if s:settings.use_css 96531c31679SBram Moolenaar call extend(s:lines, ["<div id='vimCodeElement".s:settings.id_suffix."'>"]) 9666c35beaaSBram Moolenaar endif 9676c35beaaSBram Moolenaarelse 96831c31679SBram Moolenaar call extend(s:lines, ["<pre id='vimCodeElement".s:settings.id_suffix."'>"]) 969071d4279SBram Moolenaarendif 970071d4279SBram Moolenaar 971071d4279SBram Moolenaarexe s:orgwin . "wincmd w" 972071d4279SBram Moolenaar 9736c35beaaSBram Moolenaar" caches of style data 9746c35beaaSBram Moolenaar" initialize to include line numbers if using them 9756c35beaaSBram Moolenaarif s:settings.number_lines 9766c35beaaSBram Moolenaar let s:stylelist = { s:LINENR_ID : ".LineNr { " . s:CSS1( s:LINENR_ID ) . "}" } 9776c35beaaSBram Moolenaarelse 9786c35beaaSBram Moolenaar let s:stylelist = {} 9796c35beaaSBram Moolenaarendif 9806c35beaaSBram Moolenaarlet s:diffstylelist = { 9816c35beaaSBram Moolenaar \ s:DIFF_A_ID : ".DiffAdd { " . s:CSS1( s:DIFF_A_ID ) . "}", 9826c35beaaSBram Moolenaar \ s:DIFF_C_ID : ".DiffChange { " . s:CSS1( s:DIFF_C_ID ) . "}", 9836c35beaaSBram Moolenaar \ s:DIFF_D_ID : ".DiffDelete { " . s:CSS1( s:DIFF_D_ID ) . "}", 9846c35beaaSBram Moolenaar \ s:DIFF_T_ID : ".DiffText { " . s:CSS1( s:DIFF_T_ID ) . "}" 9856c35beaaSBram Moolenaar \ } 986071d4279SBram Moolenaar 987349b2fb0SBram Moolenaar" set up progress bar in the status line 988076e8b2aSBram Moolenaarif !s:settings.no_progress 989349b2fb0SBram Moolenaar " ProgressBar Indicator 990349b2fb0SBram Moolenaar let s:progressbar={} 991349b2fb0SBram Moolenaar 992349b2fb0SBram Moolenaar " Progessbar specific functions 993349b2fb0SBram Moolenaar func! s:ProgressBar(title, max_value, winnr) 994349b2fb0SBram Moolenaar let pgb=copy(s:progressbar) 995349b2fb0SBram Moolenaar let pgb.title = a:title.' ' 996349b2fb0SBram Moolenaar let pgb.max_value = a:max_value 997349b2fb0SBram Moolenaar let pgb.winnr = a:winnr 998349b2fb0SBram Moolenaar let pgb.cur_value = 0 999349b2fb0SBram Moolenaar let pgb.items = { 'title' : { 'color' : 'Statusline' }, 1000349b2fb0SBram Moolenaar \'bar' : { 'color' : 'Statusline' , 'fillcolor' : 'DiffDelete' , 'bg' : 'Statusline' } , 1001349b2fb0SBram Moolenaar \'counter' : { 'color' : 'Statusline' } } 1002349b2fb0SBram Moolenaar let pgb.last_value = 0 1003349b2fb0SBram Moolenaar let pgb.needs_redraw = 0 1004349b2fb0SBram Moolenaar " Note that you must use len(split) instead of len() if you want to use 1005349b2fb0SBram Moolenaar " unicode in title. 1006349b2fb0SBram Moolenaar " 1007349b2fb0SBram Moolenaar " Subtract 3 for spacing around the title. 1008349b2fb0SBram Moolenaar " Subtract 4 for the percentage display. 1009349b2fb0SBram Moolenaar " Subtract 2 for spacing before this. 1010349b2fb0SBram Moolenaar " Subtract 2 more for the '|' on either side of the progress bar 1011349b2fb0SBram Moolenaar let pgb.subtractedlen=len(split(pgb.title, '\zs'))+3+4+2+2 1012349b2fb0SBram Moolenaar let pgb.max_len = 0 1013349b2fb0SBram Moolenaar set laststatus=2 1014349b2fb0SBram Moolenaar return pgb 1015349b2fb0SBram Moolenaar endfun 1016349b2fb0SBram Moolenaar 1017349b2fb0SBram Moolenaar " Function: progressbar.calculate_ticks() {{{1 1018349b2fb0SBram Moolenaar func! s:progressbar.calculate_ticks(pb_len) 1019349b2fb0SBram Moolenaar if a:pb_len<=0 1020349b2fb0SBram Moolenaar let pb_len = 100 1021349b2fb0SBram Moolenaar else 1022349b2fb0SBram Moolenaar let pb_len = a:pb_len 1023349b2fb0SBram Moolenaar endif 1024349b2fb0SBram Moolenaar let self.progress_ticks = map(range(pb_len+1), "v:val * self.max_value / pb_len") 1025349b2fb0SBram Moolenaar endfun 1026349b2fb0SBram Moolenaar 1027349b2fb0SBram Moolenaar "Function: progressbar.paint() 1028349b2fb0SBram Moolenaar func! s:progressbar.paint() 1029349b2fb0SBram Moolenaar " Recalculate widths. 1030349b2fb0SBram Moolenaar let max_len = winwidth(self.winnr) 1031349b2fb0SBram Moolenaar let pb_len = 0 1032349b2fb0SBram Moolenaar " always true on first call because of initial value of self.max_len 1033349b2fb0SBram Moolenaar if max_len != self.max_len 1034349b2fb0SBram Moolenaar let self.max_len = max_len 1035349b2fb0SBram Moolenaar 1036349b2fb0SBram Moolenaar " Progressbar length 1037349b2fb0SBram Moolenaar let pb_len = max_len - self.subtractedlen 1038349b2fb0SBram Moolenaar 1039349b2fb0SBram Moolenaar call self.calculate_ticks(pb_len) 1040349b2fb0SBram Moolenaar 1041349b2fb0SBram Moolenaar let self.needs_redraw = 1 1042349b2fb0SBram Moolenaar let cur_value = 0 1043349b2fb0SBram Moolenaar let self.pb_len = pb_len 1044349b2fb0SBram Moolenaar else 1045349b2fb0SBram Moolenaar " start searching at the last found index to make the search for the 1046349b2fb0SBram Moolenaar " appropriate tick value normally take 0 or 1 comparisons 1047349b2fb0SBram Moolenaar let cur_value = self.last_value 1048349b2fb0SBram Moolenaar let pb_len = self.pb_len 1049349b2fb0SBram Moolenaar endif 1050349b2fb0SBram Moolenaar 1051349b2fb0SBram Moolenaar let cur_val_max = pb_len > 0 ? pb_len : 100 1052349b2fb0SBram Moolenaar 1053349b2fb0SBram Moolenaar " find the current progress bar position based on precalculated thresholds 1054349b2fb0SBram Moolenaar while cur_value < cur_val_max && self.cur_value > self.progress_ticks[cur_value] 1055349b2fb0SBram Moolenaar let cur_value += 1 1056349b2fb0SBram Moolenaar endwhile 1057349b2fb0SBram Moolenaar 1058349b2fb0SBram Moolenaar " update progress bar 1059349b2fb0SBram Moolenaar if self.last_value != cur_value || self.needs_redraw || self.cur_value == self.max_value 1060349b2fb0SBram Moolenaar let self.needs_redraw = 1 1061349b2fb0SBram Moolenaar let self.last_value = cur_value 1062349b2fb0SBram Moolenaar 1063349b2fb0SBram Moolenaar let t_color = self.items.title.color 1064349b2fb0SBram Moolenaar let b_fcolor = self.items.bar.fillcolor 1065349b2fb0SBram Moolenaar let b_color = self.items.bar.color 1066349b2fb0SBram Moolenaar let c_color = self.items.counter.color 1067349b2fb0SBram Moolenaar 1068349b2fb0SBram Moolenaar let stl = "%#".t_color."#%-( ".self.title." %)". 1069349b2fb0SBram Moolenaar \"%#".b_color."#". 1070349b2fb0SBram Moolenaar \(pb_len>0 ? 1071349b2fb0SBram Moolenaar \ ('|%#'.b_fcolor."#%-(".repeat(" ",cur_value)."%)". 1072349b2fb0SBram Moolenaar \ '%#'.b_color."#".repeat(" ",pb_len-cur_value)."|"): 1073349b2fb0SBram Moolenaar \ ('')). 1074349b2fb0SBram Moolenaar \"%=%#".c_color."#%( ".printf("%3.d ",100*self.cur_value/self.max_value)."%% %)" 1075349b2fb0SBram Moolenaar call setwinvar(self.winnr, '&stl', stl) 1076349b2fb0SBram Moolenaar endif 1077349b2fb0SBram Moolenaar endfun 1078349b2fb0SBram Moolenaar 1079349b2fb0SBram Moolenaar func! s:progressbar.incr( ... ) 1080349b2fb0SBram Moolenaar let self.cur_value += (a:0 ? a:1 : 1) 1081349b2fb0SBram Moolenaar " if we were making a general-purpose progress bar, we'd need to limit to a 1082349b2fb0SBram Moolenaar " lower limit as well, but since we always increment with a positive value 1083349b2fb0SBram Moolenaar " in this script, we only need limit the upper value 1084349b2fb0SBram Moolenaar let self.cur_value = (self.cur_value > self.max_value ? self.max_value : self.cur_value) 1085349b2fb0SBram Moolenaar call self.paint() 1086349b2fb0SBram Moolenaar endfun 1087349b2fb0SBram Moolenaar " }}} 1088076e8b2aSBram Moolenaar if s:settings.dynamic_folds 1089349b2fb0SBram Moolenaar " to process folds we make two passes through each line 1090349b2fb0SBram Moolenaar let s:pgb = s:ProgressBar("Processing folds:", line('$')*2, s:orgwin) 1091349b2fb0SBram Moolenaar endif 1092349b2fb0SBram Moolenaarendif 1093349b2fb0SBram Moolenaar 10945c73622aSBram Moolenaar" First do some preprocessing for dynamic folding. Do this for the entire file 10955c73622aSBram Moolenaar" so we don't accidentally start within a closed fold or something. 10965c73622aSBram Moolenaarlet s:allfolds = [] 10975c73622aSBram Moolenaar 1098076e8b2aSBram Moolenaarif s:settings.dynamic_folds 10995c73622aSBram Moolenaar let s:lnum = 1 11005c73622aSBram Moolenaar let s:end = line('$') 11015c73622aSBram Moolenaar " save the fold text and set it to the default so we can find fold levels 11025c73622aSBram Moolenaar let s:foldtext_save = &foldtext 1103349b2fb0SBram Moolenaar setlocal foldtext& 11045c73622aSBram Moolenaar 11055c73622aSBram Moolenaar " we will set the foldcolumn in the html to the greater of the maximum fold 11065c73622aSBram Moolenaar " level and the current foldcolumn setting 11075c73622aSBram Moolenaar let s:foldcolumn = &foldcolumn 11085c73622aSBram Moolenaar 11095c73622aSBram Moolenaar " get all info needed to describe currently closed folds 1110349b2fb0SBram Moolenaar while s:lnum <= s:end 11115c73622aSBram Moolenaar if foldclosed(s:lnum) == s:lnum 11125c73622aSBram Moolenaar " default fold text has '+-' and then a number of dashes equal to fold 11135c73622aSBram Moolenaar " level, so subtract 2 from index of first non-dash after the dashes 11145c73622aSBram Moolenaar " in order to get the fold level of the current fold 11155c73622aSBram Moolenaar let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2 11165c73622aSBram Moolenaar " store fold info for later use 11175c73622aSBram Moolenaar let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"} 11185c73622aSBram Moolenaar call add(s:allfolds, s:newfold) 11195c73622aSBram Moolenaar " open the fold so we can find any contained folds 11205c73622aSBram Moolenaar execute s:lnum."foldopen" 11215c73622aSBram Moolenaar else 1122076e8b2aSBram Moolenaar if !s:settings.no_progress 1123349b2fb0SBram Moolenaar call s:pgb.incr() 1124349b2fb0SBram Moolenaar if s:pgb.needs_redraw 1125349b2fb0SBram Moolenaar redrawstatus 1126349b2fb0SBram Moolenaar let s:pgb.needs_redraw = 0 1127349b2fb0SBram Moolenaar endif 1128349b2fb0SBram Moolenaar endif 11295c73622aSBram Moolenaar let s:lnum = s:lnum + 1 11305c73622aSBram Moolenaar endif 11315c73622aSBram Moolenaar endwhile 11325c73622aSBram Moolenaar 11335c73622aSBram Moolenaar " close all folds to get info for originally open folds 11345c73622aSBram Moolenaar silent! %foldclose! 11355c73622aSBram Moolenaar let s:lnum = 1 11365c73622aSBram Moolenaar 11375c73622aSBram Moolenaar " the originally open folds will be all folds we encounter that aren't 11385c73622aSBram Moolenaar " already in the list of closed folds 1139349b2fb0SBram Moolenaar while s:lnum <= s:end 11405c73622aSBram Moolenaar if foldclosed(s:lnum) == s:lnum 11415c73622aSBram Moolenaar " default fold text has '+-' and then a number of dashes equal to fold 11425c73622aSBram Moolenaar " level, so subtract 2 from index of first non-dash after the dashes 11435c73622aSBram Moolenaar " in order to get the fold level of the current fold 11445c73622aSBram Moolenaar let s:level = match(foldtextresult(s:lnum), '+-*\zs[^-]') - 2 11455c73622aSBram Moolenaar let s:newfold = {'firstline': s:lnum, 'lastline': foldclosedend(s:lnum), 'level': s:level,'type': "closed-fold"} 11465c73622aSBram Moolenaar " only add the fold if we don't already have it 11475c73622aSBram Moolenaar if empty(s:allfolds) || index(s:allfolds, s:newfold) == -1 11485c73622aSBram Moolenaar let s:newfold.type = "open-fold" 11495c73622aSBram Moolenaar call add(s:allfolds, s:newfold) 11505c73622aSBram Moolenaar endif 11515c73622aSBram Moolenaar " open the fold so we can find any contained folds 11525c73622aSBram Moolenaar execute s:lnum."foldopen" 11535c73622aSBram Moolenaar else 1154076e8b2aSBram Moolenaar if !s:settings.no_progress 1155349b2fb0SBram Moolenaar call s:pgb.incr() 1156349b2fb0SBram Moolenaar if s:pgb.needs_redraw 1157349b2fb0SBram Moolenaar redrawstatus 1158349b2fb0SBram Moolenaar let s:pgb.needs_redraw = 0 1159349b2fb0SBram Moolenaar endif 1160349b2fb0SBram Moolenaar endif 11615c73622aSBram Moolenaar let s:lnum = s:lnum + 1 11625c73622aSBram Moolenaar endif 11635c73622aSBram Moolenaar endwhile 11645c73622aSBram Moolenaar 11655c73622aSBram Moolenaar " sort the folds so that we only ever need to look at the first item in the 11665c73622aSBram Moolenaar " list of folds 11675c73622aSBram Moolenaar call sort(s:allfolds, "s:FoldCompare") 11685c73622aSBram Moolenaar 1169349b2fb0SBram Moolenaar let &l:foldtext = s:foldtext_save 11705c73622aSBram Moolenaar unlet s:foldtext_save 11715c73622aSBram Moolenaar 11725c73622aSBram Moolenaar " close all folds again so we can get the fold text as we go 11735c73622aSBram Moolenaar silent! %foldclose! 11742a8a3ecbSBram Moolenaar 1175251e1912SBram Moolenaar " Go through and remove folds we don't need to (or cannot) process in the 1176251e1912SBram Moolenaar " current conversion range 1177251e1912SBram Moolenaar " 1178251e1912SBram Moolenaar " If a fold is removed which contains other folds, which are included, we need 1179251e1912SBram Moolenaar " to adjust the level of the included folds as used by the conversion logic 1180251e1912SBram Moolenaar " (avoiding special cases is good) 1181251e1912SBram Moolenaar " 1182251e1912SBram Moolenaar " Note any time we remove a fold, either all of the included folds are in it, 1183251e1912SBram Moolenaar " or none of them, because we only remove a fold if neither its start nor its 1184251e1912SBram Moolenaar " end are within the conversion range. 1185251e1912SBram Moolenaar let leveladjust = 0 11862a8a3ecbSBram Moolenaar for afold in s:allfolds 11872a8a3ecbSBram Moolenaar let removed = 0 11882a8a3ecbSBram Moolenaar if exists("g:html_start_line") && exists("g:html_end_line") 11892a8a3ecbSBram Moolenaar if afold.firstline < g:html_start_line 1190251e1912SBram Moolenaar if afold.lastline <= g:html_end_line && afold.lastline >= g:html_start_line 11912a8a3ecbSBram Moolenaar " if a fold starts before the range to convert but stops within the 11922a8a3ecbSBram Moolenaar " range, we need to include it. Make it start on the first converted 11932a8a3ecbSBram Moolenaar " line. 11942a8a3ecbSBram Moolenaar let afold.firstline = g:html_start_line 11952a8a3ecbSBram Moolenaar else 11962a8a3ecbSBram Moolenaar " if the fold lies outside the range or the start and stop enclose 11972a8a3ecbSBram Moolenaar " the entire range, don't bother parsing it 11982a8a3ecbSBram Moolenaar call remove(s:allfolds, index(s:allfolds, afold)) 11992a8a3ecbSBram Moolenaar let removed = 1 1200251e1912SBram Moolenaar if afold.lastline > g:html_end_line 1201251e1912SBram Moolenaar let leveladjust += 1 1202251e1912SBram Moolenaar endif 12032a8a3ecbSBram Moolenaar endif 12042a8a3ecbSBram Moolenaar elseif afold.firstline > g:html_end_line 12052a8a3ecbSBram Moolenaar " If the entire fold lies outside the range we need to remove it. 12062a8a3ecbSBram Moolenaar call remove(s:allfolds, index(s:allfolds, afold)) 12072a8a3ecbSBram Moolenaar let removed = 1 12082a8a3ecbSBram Moolenaar endif 12092a8a3ecbSBram Moolenaar elseif exists("g:html_start_line") 12102a8a3ecbSBram Moolenaar if afold.firstline < g:html_start_line 12112a8a3ecbSBram Moolenaar " if there is no last line, but there is a first line, the end of the 12122a8a3ecbSBram Moolenaar " fold will always lie within the region of interest, so keep it 12132a8a3ecbSBram Moolenaar let afold.firstline = g:html_start_line 12142a8a3ecbSBram Moolenaar endif 12152a8a3ecbSBram Moolenaar elseif exists("g:html_end_line") 12162a8a3ecbSBram Moolenaar " if there is no first line we default to the first line in the buffer so 12172a8a3ecbSBram Moolenaar " the fold start will always be included if the fold itself is included. 12182a8a3ecbSBram Moolenaar " If however the entire fold lies outside the range we need to remove it. 12192a8a3ecbSBram Moolenaar if afold.firstline > g:html_end_line 12202a8a3ecbSBram Moolenaar call remove(s:allfolds, index(s:allfolds, afold)) 12212a8a3ecbSBram Moolenaar let removed = 1 12222a8a3ecbSBram Moolenaar endif 12232a8a3ecbSBram Moolenaar endif 12242a8a3ecbSBram Moolenaar if !removed 1225251e1912SBram Moolenaar let afold.level -= leveladjust 12262a8a3ecbSBram Moolenaar if afold.level+1 > s:foldcolumn 12272a8a3ecbSBram Moolenaar let s:foldcolumn = afold.level+1 12282a8a3ecbSBram Moolenaar endif 12292a8a3ecbSBram Moolenaar endif 12302a8a3ecbSBram Moolenaar endfor 1231251e1912SBram Moolenaar 1232251e1912SBram Moolenaar " if we've removed folds containing the conversion range from processing, 1233251e1912SBram Moolenaar " getting foldtext as we go won't know to open the removed folds, so the 1234251e1912SBram Moolenaar " foldtext would be wrong; open them now. 1235251e1912SBram Moolenaar " 1236251e1912SBram Moolenaar " Note that only when a start and an end line is specified will a fold 1237251e1912SBram Moolenaar " containing the current range ever be removed. 1238251e1912SBram Moolenaar while leveladjust > 0 1239251e1912SBram Moolenaar exe g:html_start_line."foldopen" 1240251e1912SBram Moolenaar let leveladjust -= 1 1241251e1912SBram Moolenaar endwhile 12425c73622aSBram Moolenaarendif 12435c73622aSBram Moolenaar 12445c73622aSBram Moolenaar" Now loop over all lines in the original text to convert to html. 1245071d4279SBram Moolenaar" Use html_start_line and html_end_line if they are set. 1246b02cbe34SBram Moolenaarif exists("g:html_start_line") 1247071d4279SBram Moolenaar let s:lnum = html_start_line 1248071d4279SBram Moolenaar if s:lnum < 1 || s:lnum > line("$") 1249071d4279SBram Moolenaar let s:lnum = 1 1250071d4279SBram Moolenaar endif 1251071d4279SBram Moolenaarelse 1252071d4279SBram Moolenaar let s:lnum = 1 1253071d4279SBram Moolenaarendif 1254b02cbe34SBram Moolenaarif exists("g:html_end_line") 1255071d4279SBram Moolenaar let s:end = html_end_line 1256071d4279SBram Moolenaar if s:end < s:lnum || s:end > line("$") 1257071d4279SBram Moolenaar let s:end = line("$") 1258071d4279SBram Moolenaar endif 1259071d4279SBram Moolenaarelse 1260071d4279SBram Moolenaar let s:end = line("$") 1261071d4279SBram Moolenaarendif 1262071d4279SBram Moolenaar 12635c73622aSBram Moolenaar" stack to keep track of all the folds containing the current line 12645c73622aSBram Moolenaarlet s:foldstack = [] 12655c73622aSBram Moolenaar 1266076e8b2aSBram Moolenaarif !s:settings.no_progress 1267349b2fb0SBram Moolenaar let s:pgb = s:ProgressBar("Processing lines:", s:end - s:lnum + 1, s:orgwin) 1268349b2fb0SBram Moolenaarendif 1269349b2fb0SBram Moolenaar 1270076e8b2aSBram Moolenaarif s:settings.number_lines 12715c73622aSBram Moolenaar let s:margin = strlen(s:end) + 1 12725c73622aSBram Moolenaarelse 12735c73622aSBram Moolenaar let s:margin = 0 12745c73622aSBram Moolenaarendif 12755c73622aSBram Moolenaar 1276076e8b2aSBram Moolenaarif has('folding') && !s:settings.ignore_folding 127735a9aaabSBram Moolenaar let s:foldfillchar = &fillchars[matchend(&fillchars, 'fold:')] 127835a9aaabSBram Moolenaar if s:foldfillchar == '' 127935a9aaabSBram Moolenaar let s:foldfillchar = '-' 12807b0294cbSBram Moolenaar endif 128135a9aaabSBram Moolenaarendif 128235a9aaabSBram Moolenaarlet s:difffillchar = &fillchars[matchend(&fillchars, 'diff:')] 128335a9aaabSBram Moolenaarif s:difffillchar == '' 128435a9aaabSBram Moolenaar let s:difffillchar = '-' 12857b0294cbSBram Moolenaarendif 12867b0294cbSBram Moolenaar 12875c73622aSBram Moolenaarlet s:foldId = 0 12887b0294cbSBram Moolenaar 12892a8a3ecbSBram Moolenaarif !s:settings.expand_tabs 12902a8a3ecbSBram Moolenaar " If keeping tabs, add them to printable characters so we keep them when 12912a8a3ecbSBram Moolenaar " formatting text (strtrans() doesn't replace printable chars) 12922a8a3ecbSBram Moolenaar let s:old_isprint = &isprint 12932a8a3ecbSBram Moolenaar setlocal isprint+=9 12942a8a3ecbSBram Moolenaarendif 12952a8a3ecbSBram Moolenaar 1296071d4279SBram Moolenaarwhile s:lnum <= s:end 1297071d4279SBram Moolenaar 129847136d70SBram Moolenaar " If there are filler lines for diff mode, show these above the line. 129947136d70SBram Moolenaar let s:filler = diff_filler(s:lnum) 130047136d70SBram Moolenaar if s:filler > 0 130147136d70SBram Moolenaar let s:n = s:filler 130247136d70SBram Moolenaar while s:n > 0 130335a9aaabSBram Moolenaar let s:new = repeat(s:difffillchar, 3) 130447136d70SBram Moolenaar 1305076e8b2aSBram Moolenaar if s:n > 2 && s:n < s:filler && !s:settings.whole_filler 130635a9aaabSBram Moolenaar let s:new = s:new . " " . s:filler . " inserted lines " 130735a9aaabSBram Moolenaar let s:n = 2 130835a9aaabSBram Moolenaar endif 130935a9aaabSBram Moolenaar 1310076e8b2aSBram Moolenaar if !s:settings.no_pre 131135a9aaabSBram Moolenaar " HTML line wrapping is off--go ahead and fill to the margin 13126c35beaaSBram Moolenaar " TODO: what about when CSS wrapping is turned on? 13135c73622aSBram Moolenaar let s:new = s:new . repeat(s:difffillchar, &columns - strlen(s:new) - s:margin) 13145c73622aSBram Moolenaar else 13155c73622aSBram Moolenaar let s:new = s:new . repeat(s:difffillchar, 3) 131635a9aaabSBram Moolenaar endif 131735a9aaabSBram Moolenaar 13186c35beaaSBram Moolenaar let s:new = s:HtmlFormat_d(s:new, s:DIFF_D_ID, 0) 1319076e8b2aSBram Moolenaar if s:settings.number_lines 13206c35beaaSBram Moolenaar " Indent if line numbering is on. Indent gets style of line number 13216c35beaaSBram Moolenaar " column. 1322543b7ef7SBram Moolenaar let s:new = s:HtmlFormat_n(repeat(' ', s:margin), s:LINENR_ID, 0, 0) . s:new 13236c35beaaSBram Moolenaar endif 13246c35beaaSBram Moolenaar if s:settings.dynamic_folds && !s:settings.no_foldcolumn && s:foldcolumn > 0 13256c35beaaSBram Moolenaar " Indent for foldcolumn if there is one. Assume it's empty, there should 13266c35beaaSBram Moolenaar " not be a fold for deleted lines in diff mode. 13276c35beaaSBram Moolenaar let s:new = s:FoldColumn_fill() . s:new 13285c73622aSBram Moolenaar endif 1329349b2fb0SBram Moolenaar call add(s:lines, s:new.s:HtmlEndline) 133035a9aaabSBram Moolenaar 133147136d70SBram Moolenaar let s:n = s:n - 1 133247136d70SBram Moolenaar endwhile 133347136d70SBram Moolenaar unlet s:n 133447136d70SBram Moolenaar endif 133547136d70SBram Moolenaar unlet s:filler 133647136d70SBram Moolenaar 133747136d70SBram Moolenaar " Start the line with the line number. 1338076e8b2aSBram Moolenaar if s:settings.number_lines 13395c73622aSBram Moolenaar let s:numcol = repeat(' ', s:margin - 1 - strlen(s:lnum)) . s:lnum . ' ' 134047136d70SBram Moolenaar endif 134147136d70SBram Moolenaar 13425c73622aSBram Moolenaar let s:new = "" 13435c73622aSBram Moolenaar 1344076e8b2aSBram Moolenaar if has('folding') && !s:settings.ignore_folding && foldclosed(s:lnum) > -1 && !s:settings.dynamic_folds 13457b0294cbSBram Moolenaar " 13465c73622aSBram Moolenaar " This is the beginning of a folded block (with no dynamic folding) 13476c35beaaSBram Moolenaar let s:new = foldtextresult(s:lnum) 1348076e8b2aSBram Moolenaar if !s:settings.no_pre 134935a9aaabSBram Moolenaar " HTML line wrapping is off--go ahead and fill to the margin 135035a9aaabSBram Moolenaar let s:new = s:new . repeat(s:foldfillchar, &columns - strlen(s:new)) 13517b0294cbSBram Moolenaar endif 13527b0294cbSBram Moolenaar 13536c35beaaSBram Moolenaar " put numcol in a separate group for sake of unselectable text 1354543b7ef7SBram Moolenaar 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) 13557b0294cbSBram Moolenaar 13567b0294cbSBram Moolenaar " Skip to the end of the fold 1357349b2fb0SBram Moolenaar let s:new_lnum = foldclosedend(s:lnum) 1358349b2fb0SBram Moolenaar 1359076e8b2aSBram Moolenaar if !s:settings.no_progress 1360349b2fb0SBram Moolenaar call s:pgb.incr(s:new_lnum - s:lnum) 1361349b2fb0SBram Moolenaar endif 1362349b2fb0SBram Moolenaar 1363349b2fb0SBram Moolenaar let s:lnum = s:new_lnum 13647b0294cbSBram Moolenaar 13657b0294cbSBram Moolenaar else 13667b0294cbSBram Moolenaar " 13675c73622aSBram Moolenaar " A line that is not folded, or doing dynamic folding. 13687b0294cbSBram Moolenaar " 136935a9aaabSBram Moolenaar let s:line = getline(s:lnum) 13707b0294cbSBram Moolenaar let s:len = strlen(s:line) 13717b0294cbSBram Moolenaar 1372076e8b2aSBram Moolenaar if s:settings.dynamic_folds 13735c73622aSBram Moolenaar " First insert a closing for any open folds that end on this line 13745c73622aSBram Moolenaar while !empty(s:foldstack) && get(s:foldstack,0).lastline == s:lnum-1 13755c73622aSBram Moolenaar let s:new = s:new."</span></span>" 13765c73622aSBram Moolenaar call remove(s:foldstack, 0) 13775c73622aSBram Moolenaar endwhile 13785c73622aSBram Moolenaar 13792a8a3ecbSBram Moolenaar " Now insert an opening for any new folds that start on this line 13805c73622aSBram Moolenaar let s:firstfold = 1 13815c73622aSBram Moolenaar while !empty(s:allfolds) && get(s:allfolds,0).firstline == s:lnum 13825c73622aSBram Moolenaar let s:foldId = s:foldId + 1 1383349b2fb0SBram Moolenaar let s:new .= "<span id='" 1384349b2fb0SBram Moolenaar let s:new .= (exists('g:html_diff_win_num') ? "win".g:html_diff_win_num : "") 138531c31679SBram Moolenaar let s:new .= "fold".s:foldId.s:settings.id_suffix."' class='".s:allfolds[0].type."'>" 1386349b2fb0SBram Moolenaar 13875c73622aSBram Moolenaar 13885c73622aSBram Moolenaar " Unless disabled, add a fold column for the opening line of a fold. 13895c73622aSBram Moolenaar " 13905c73622aSBram Moolenaar " Note that dynamic folds require using css so we just use css to take 13915c73622aSBram Moolenaar " care of the leading spaces rather than using in the case of 13925c73622aSBram Moolenaar " html_no_pre to make it easier 1393076e8b2aSBram Moolenaar if !s:settings.no_foldcolumn 13945c73622aSBram Moolenaar " add fold column that can open the new fold 13955c73622aSBram Moolenaar if s:allfolds[0].level > 1 && s:firstfold 13966c35beaaSBram Moolenaar let s:new = s:new . s:FoldColumn_build('|', s:allfolds[0].level - 1, 0, "", 139731c31679SBram Moolenaar \ 'toggle-open FoldColumn','javascript:toggleFold("fold'.s:foldstack[0].id.s:settings.id_suffix.'");') 13985c73622aSBram Moolenaar endif 13996c35beaaSBram Moolenaar " add the filler spaces separately from the '+' char so that it can be 14006c35beaaSBram Moolenaar " shown/hidden separately during a hover unfold 14016c35beaaSBram Moolenaar let s:new = s:new . s:FoldColumn_build("+", 1, 0, "", 140231c31679SBram Moolenaar \ 'toggle-open FoldColumn', 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");') 14035c73622aSBram Moolenaar " If this is not the last fold we're opening on this line, we need 14045c73622aSBram Moolenaar " to keep the filler spaces hidden if the fold is opened by mouse 14055c73622aSBram Moolenaar " hover. If it is the last fold to open in the line, we shouldn't hide 14065c73622aSBram Moolenaar " them, so don't apply the toggle-filler class. 14076c35beaaSBram Moolenaar let s:new = s:new . s:FoldColumn_build(" ", 1, s:foldcolumn - s:allfolds[0].level - 1, "", 14086c35beaaSBram Moolenaar \ 'toggle-open FoldColumn'. (get(s:allfolds, 1, {'firstline': 0}).firstline == s:lnum ?" toggle-filler" :""), 140931c31679SBram Moolenaar \ 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");') 14105c73622aSBram Moolenaar 14115c73622aSBram Moolenaar " add fold column that can close the new fold 14126c35beaaSBram Moolenaar " only add extra blank space if we aren't opening another fold on the 14136c35beaaSBram Moolenaar " same line 14145c73622aSBram Moolenaar if get(s:allfolds, 1, {'firstline': 0}).firstline != s:lnum 14156c35beaaSBram Moolenaar let s:extra_space = s:foldcolumn - s:allfolds[0].level 14166c35beaaSBram Moolenaar else 14176c35beaaSBram Moolenaar let s:extra_space = 0 14185c73622aSBram Moolenaar endif 14196c35beaaSBram Moolenaar if s:firstfold 14206c35beaaSBram Moolenaar " the first fold in a line has '|' characters from folds opened in 14216c35beaaSBram Moolenaar " previous lines, before the '-' for this fold 14226c35beaaSBram Moolenaar let s:new .= s:FoldColumn_build('|', s:allfolds[0].level - 1, s:extra_space, '-', 142331c31679SBram Moolenaar \ 'toggle-closed FoldColumn', 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");') 14246c35beaaSBram Moolenaar else 14256c35beaaSBram Moolenaar " any subsequent folds in the line only add a single '-' 14266c35beaaSBram Moolenaar let s:new = s:new . s:FoldColumn_build("-", 1, s:extra_space, "", 142731c31679SBram Moolenaar \ 'toggle-closed FoldColumn', 'javascript:toggleFold("fold'.s:foldId.s:settings.id_suffix.'");') 14286c35beaaSBram Moolenaar endif 14295c73622aSBram Moolenaar let s:firstfold = 0 14305c73622aSBram Moolenaar endif 14315c73622aSBram Moolenaar 14326c35beaaSBram Moolenaar " Add fold text, moving the span ending to the next line so collapsing 14336c35beaaSBram Moolenaar " of folds works correctly. 14346c35beaaSBram Moolenaar " Put numcol in a separate group for sake of unselectable text. 1435543b7ef7SBram Moolenaar 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), '</span>', s:HtmlEndline.'\n\0', '') 14365c73622aSBram Moolenaar let s:new = s:new . "<span class='fulltext'>" 14375c73622aSBram Moolenaar 14385c73622aSBram Moolenaar " open the fold now that we have the fold text to allow retrieval of 14395c73622aSBram Moolenaar " fold text for subsequent folds 14405c73622aSBram Moolenaar execute s:lnum."foldopen" 14415c73622aSBram Moolenaar call insert(s:foldstack, remove(s:allfolds,0)) 14425c73622aSBram Moolenaar let s:foldstack[0].id = s:foldId 14435c73622aSBram Moolenaar endwhile 14445c73622aSBram Moolenaar 14455c73622aSBram Moolenaar " Unless disabled, add a fold column for other lines. 14465c73622aSBram Moolenaar " 14475c73622aSBram Moolenaar " Note that dynamic folds require using css so we just use css to take 14485c73622aSBram Moolenaar " care of the leading spaces rather than using in the case of 14495c73622aSBram Moolenaar " html_no_pre to make it easier 1450076e8b2aSBram Moolenaar if !s:settings.no_foldcolumn 14515c73622aSBram Moolenaar if empty(s:foldstack) 14527510fe74SBram Moolenaar " add the empty foldcolumn for unfolded lines if there is a fold 14537510fe74SBram Moolenaar " column at all 14547510fe74SBram Moolenaar if s:foldcolumn > 0 14556c35beaaSBram Moolenaar let s:new = s:new . s:FoldColumn_fill() 14567510fe74SBram Moolenaar endif 14575c73622aSBram Moolenaar else 14585c73622aSBram Moolenaar " add the fold column for folds not on the opening line 14595c73622aSBram Moolenaar if get(s:foldstack, 0).firstline < s:lnum 14606c35beaaSBram Moolenaar let s:new = s:new . s:FoldColumn_build('|', s:foldstack[0].level, s:foldcolumn - s:foldstack[0].level, "", 146131c31679SBram Moolenaar \ 'FoldColumn', 'javascript:toggleFold("fold'.s:foldstack[0].id.s:settings.id_suffix.'");') 14625c73622aSBram Moolenaar endif 14635c73622aSBram Moolenaar endif 14645c73622aSBram Moolenaar endif 14655c73622aSBram Moolenaar endif 14665c73622aSBram Moolenaar 14675c73622aSBram Moolenaar " Now continue with the unfolded line text 1468076e8b2aSBram Moolenaar if s:settings.number_lines 1469543b7ef7SBram Moolenaar let s:new = s:new . s:HtmlFormat_n(s:numcol, s:LINENR_ID, 0, s:lnum) 147031c31679SBram Moolenaar elseif s:settings.line_ids 1471543b7ef7SBram Moolenaar let s:new = s:new . s:HtmlFormat_n("", s:LINENR_ID, 0, s:lnum) 1472071d4279SBram Moolenaar endif 1473071d4279SBram Moolenaar 147447136d70SBram Moolenaar " Get the diff attribute, if any. 147547136d70SBram Moolenaar let s:diffattr = diff_hlID(s:lnum, 1) 147647136d70SBram Moolenaar 14777510fe74SBram Moolenaar " initialize conceal info to act like not concealed, just in case 14787510fe74SBram Moolenaar let s:concealinfo = [0, ''] 14797510fe74SBram Moolenaar 1480071d4279SBram Moolenaar " Loop over each character in the line 1481071d4279SBram Moolenaar let s:col = 1 14828ada2ccaSBram Moolenaar 14838ada2ccaSBram Moolenaar " most of the time we won't use the diff_id, initialize to zero 14848ada2ccaSBram Moolenaar let s:diff_id = 0 14858ada2ccaSBram Moolenaar 148635a9aaabSBram Moolenaar while s:col <= s:len || (s:col == 1 && s:diffattr) 1487071d4279SBram Moolenaar let s:startcol = s:col " The start column for processing text 1488076e8b2aSBram Moolenaar if !s:settings.ignore_conceal && has('conceal') 14897510fe74SBram Moolenaar let s:concealinfo = synconcealed(s:lnum, s:col) 14907510fe74SBram Moolenaar endif 1491076e8b2aSBram Moolenaar if !s:settings.ignore_conceal && s:concealinfo[0] 14927510fe74SBram Moolenaar let s:col = s:col + 1 14937510fe74SBram Moolenaar " Speed loop (it's small - that's the trick) 14947510fe74SBram Moolenaar " Go along till we find a change in the match sequence number (ending 14957510fe74SBram Moolenaar " the specific concealed region) or until there are no more concealed 14967510fe74SBram Moolenaar " characters. 14977510fe74SBram Moolenaar while s:col <= s:len && s:concealinfo == synconcealed(s:lnum, s:col) | let s:col = s:col + 1 | endwhile 14987510fe74SBram Moolenaar elseif s:diffattr 14998ada2ccaSBram Moolenaar let s:diff_id = diff_hlID(s:lnum, s:col) 15008ada2ccaSBram Moolenaar let s:id = synID(s:lnum, s:col, 1) 150147136d70SBram Moolenaar let s:col = s:col + 1 150247136d70SBram Moolenaar " Speed loop (it's small - that's the trick) 150347136d70SBram Moolenaar " Go along till we find a change in hlID 15048ada2ccaSBram Moolenaar while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) 15058ada2ccaSBram Moolenaar \ && s:diff_id == diff_hlID(s:lnum, s:col) | 15068ada2ccaSBram Moolenaar \ let s:col = s:col + 1 | 15078ada2ccaSBram Moolenaar \ endwhile 1508076e8b2aSBram Moolenaar if s:len < &columns && !s:settings.no_pre 15098ada2ccaSBram Moolenaar " Add spaces at the end of the raw text line to extend the changed 15108ada2ccaSBram Moolenaar " line to the full width. 15115c73622aSBram Moolenaar let s:line = s:line . repeat(' ', &columns - virtcol([s:lnum, s:len]) - s:margin) 151235a9aaabSBram Moolenaar let s:len = &columns 151335a9aaabSBram Moolenaar endif 151447136d70SBram Moolenaar else 1515071d4279SBram Moolenaar let s:id = synID(s:lnum, s:col, 1) 1516071d4279SBram Moolenaar let s:col = s:col + 1 1517071d4279SBram Moolenaar " Speed loop (it's small - that's the trick) 1518071d4279SBram Moolenaar " Go along till we find a change in synID 1519071d4279SBram Moolenaar while s:col <= s:len && s:id == synID(s:lnum, s:col, 1) | let s:col = s:col + 1 | endwhile 152047136d70SBram Moolenaar endif 1521071d4279SBram Moolenaar 1522076e8b2aSBram Moolenaar if s:settings.ignore_conceal || !s:concealinfo[0] 15232a8a3ecbSBram Moolenaar " Expand tabs if needed 152435a9aaabSBram Moolenaar let s:expandedtab = strpart(s:line, s:startcol - 1, s:col - s:startcol) 15252a8a3ecbSBram Moolenaar if s:settings.expand_tabs 15265c73622aSBram Moolenaar let s:offset = 0 15275c73622aSBram Moolenaar let s:idx = stridx(s:expandedtab, "\t") 15285c73622aSBram Moolenaar while s:idx >= 0 15295c73622aSBram Moolenaar if has("multi_byte_encoding") 15305c73622aSBram Moolenaar if s:startcol + s:idx == 1 15315c73622aSBram Moolenaar let s:i = &ts 15325c73622aSBram Moolenaar else 15335c73622aSBram Moolenaar if s:idx == 0 15345c73622aSBram Moolenaar let s:prevc = matchstr(s:line, '.\%' . (s:startcol + s:idx + s:offset) . 'c') 15355c73622aSBram Moolenaar else 15365c73622aSBram Moolenaar let s:prevc = matchstr(s:expandedtab, '.\%' . (s:idx + 1) . 'c') 15375c73622aSBram Moolenaar endif 15385c73622aSBram Moolenaar let s:vcol = virtcol([s:lnum, s:startcol + s:idx + s:offset - len(s:prevc)]) 15395c73622aSBram Moolenaar let s:i = &ts - (s:vcol % &ts) 15405c73622aSBram Moolenaar endif 15415c73622aSBram Moolenaar let s:offset -= s:i - 1 15425c73622aSBram Moolenaar else 15435c73622aSBram Moolenaar let s:i = &ts - ((s:idx + s:startcol - 1) % &ts) 15445c73622aSBram Moolenaar endif 15455c73622aSBram Moolenaar let s:expandedtab = substitute(s:expandedtab, '\t', repeat(' ', s:i), '') 15465c73622aSBram Moolenaar let s:idx = stridx(s:expandedtab, "\t") 154735a9aaabSBram Moolenaar endwhile 15482a8a3ecbSBram Moolenaar end 154935a9aaabSBram Moolenaar 15507510fe74SBram Moolenaar " get the highlight group name to use 1551071d4279SBram Moolenaar let s:id = synIDtrans(s:id) 15527510fe74SBram Moolenaar else 15537510fe74SBram Moolenaar " use Conceal highlighting for concealed text 15546c35beaaSBram Moolenaar let s:id = s:CONCEAL_ID 15557510fe74SBram Moolenaar let s:expandedtab = s:concealinfo[1] 15567510fe74SBram Moolenaar endif 15577510fe74SBram Moolenaar 15586c35beaaSBram Moolenaar " Output the text with the same synID, with class set to the highlight ID 15596c35beaaSBram Moolenaar " name, unless it has been concealed completely. 15607510fe74SBram Moolenaar if strlen(s:expandedtab) > 0 1561543b7ef7SBram Moolenaar let s:new = s:new . s:HtmlFormat(s:expandedtab, s:id, s:diff_id, "", 0) 15627510fe74SBram Moolenaar endif 1563071d4279SBram Moolenaar endwhile 15647b0294cbSBram Moolenaar endif 1565071d4279SBram Moolenaar 15667510fe74SBram Moolenaar call extend(s:lines, split(s:new.s:HtmlEndline, '\n', 1)) 1567076e8b2aSBram Moolenaar if !s:settings.no_progress && s:pgb.needs_redraw 1568349b2fb0SBram Moolenaar redrawstatus 1569349b2fb0SBram Moolenaar let s:pgb.needs_redraw = 0 1570349b2fb0SBram Moolenaar endif 1571071d4279SBram Moolenaar let s:lnum = s:lnum + 1 1572313b7237SBram Moolenaar 1573076e8b2aSBram Moolenaar if !s:settings.no_progress 1574349b2fb0SBram Moolenaar call s:pgb.incr() 1575349b2fb0SBram Moolenaar endif 1576349b2fb0SBram Moolenaarendwhile 1577349b2fb0SBram Moolenaar 1578076e8b2aSBram Moolenaarif s:settings.dynamic_folds 15795c73622aSBram Moolenaar " finish off any open folds 15805c73622aSBram Moolenaar while !empty(s:foldstack) 1581349b2fb0SBram Moolenaar let s:lines[-1].="</span></span>" 15825c73622aSBram Moolenaar call remove(s:foldstack, 0) 15835c73622aSBram Moolenaar endwhile 15845c73622aSBram Moolenaar 15855c73622aSBram Moolenaar " add fold column to the style list if not already there 15866c35beaaSBram Moolenaar let s:id = s:FOLD_C_ID 15876c35beaaSBram Moolenaar if !has_key(s:stylelist, s:id) 15886c35beaaSBram Moolenaar let s:stylelist[s:id] = '.FoldColumn { ' . s:CSS1(s:id) . '}' 15895c73622aSBram Moolenaar endif 15905c73622aSBram Moolenaarendif 15915c73622aSBram Moolenaar 1592076e8b2aSBram Moolenaarif s:settings.no_pre 1593076e8b2aSBram Moolenaar if !s:settings.use_css 15948ada2ccaSBram Moolenaar " Close off the font tag that encapsulates the whole <body> 1595bebca9daSBram Moolenaar call extend(s:lines, ["</font>", "</body>", "</html>"]) 15968ada2ccaSBram Moolenaar else 15976c35beaaSBram Moolenaar call extend(s:lines, ["</div>", "</body>", "</html>"]) 15988ada2ccaSBram Moolenaar endif 1599071d4279SBram Moolenaarelse 1600349b2fb0SBram Moolenaar call extend(s:lines, ["</pre>", "</body>", "</html>"]) 1601071d4279SBram Moolenaarendif 1602071d4279SBram Moolenaar 1603349b2fb0SBram Moolenaarexe s:newwin . "wincmd w" 1604349b2fb0SBram Moolenaarcall setline(1, s:lines) 1605349b2fb0SBram Moolenaarunlet s:lines 1606071d4279SBram Moolenaar 16076c35beaaSBram Moolenaar" Mangle modelines so Vim doesn't try to use HTML text as a modeline if editing 16086c35beaaSBram Moolenaar" this file in the future; need to do this after generating all the text in case 16096c35beaaSBram Moolenaar" the modeline text has different highlight groups which all turn out to be 16106c35beaaSBram Moolenaar" stripped from the final output. 1611dd007ed5SBram Moolenaar%s!\v(%(^|\s+)%([Vv]i%(m%([<=>]?\d+)?)?|ex)):!\1\:!ge 16126c35beaaSBram Moolenaar 1613543b7ef7SBram Moolenaar" The generated HTML is admittedly ugly and takes a LONG time to fold. 1614543b7ef7SBram Moolenaar" Make sure the user doesn't do syntax folding when loading a generated file, 1615543b7ef7SBram Moolenaar" using a modeline. 1616543b7ef7SBram Moolenaarcall append(line('$'), "<!-- vim: set foldmethod=manual : -->") 1617543b7ef7SBram Moolenaar 1618071d4279SBram Moolenaar" Now, when we finally know which, we define the colors and styles 1619076e8b2aSBram Moolenaarif s:settings.use_css 1620071d4279SBram Moolenaar 1;/<style type="text/+1 1621071d4279SBram Moolenaarendif 1622071d4279SBram Moolenaar 1623071d4279SBram Moolenaar" Normal/global attributes 1624071d4279SBram Moolenaar" For Netscape 4, set <body> attributes too, though, strictly speaking, it's 1625071d4279SBram Moolenaar" incorrect. 1626076e8b2aSBram Moolenaarif s:settings.use_css 1627076e8b2aSBram Moolenaar if s:settings.no_pre 16286c35beaaSBram Moolenaar call append('.', "body { color: " . s:fgc . "; background-color: " . s:bgc . "; font-family: ". s:htmlfont ."; }") 16296c35beaaSBram Moolenaar + 1630071d4279SBram Moolenaar else 16316c35beaaSBram Moolenaar call append('.', "pre { " . s:whitespace . "font-family: ". s:htmlfont ."; color: " . s:fgc . "; background-color: " . s:bgc . "; }") 16326c35beaaSBram Moolenaar + 1633071d4279SBram Moolenaar yank 1634071d4279SBram Moolenaar put 1635071d4279SBram Moolenaar execute "normal! ^cwbody\e" 16368e5af3e5SBram Moolenaar " body should not have the wrap formatting, only the pre section 16378e5af3e5SBram Moolenaar if s:whitespace != '' 16388e5af3e5SBram Moolenaar exec 's#'.s:whitespace 16398e5af3e5SBram Moolenaar endif 1640071d4279SBram Moolenaar endif 16416c35beaaSBram Moolenaar " fix browser inconsistencies (sometimes within the same browser) of different 16426c35beaaSBram Moolenaar " default font size for different elements 16436c35beaaSBram Moolenaar call append('.', '* { font-size: 1em; }') 16446c35beaaSBram Moolenaar + 16456c35beaaSBram Moolenaar " if we use any input elements for unselectable content, make sure they look 16466c35beaaSBram Moolenaar " like normal text 16476c35beaaSBram Moolenaar if !empty(s:settings.prevent_copy) 16486c35beaaSBram Moolenaar call append('.', 'input { border: none; margin: 0; padding: 0; font-family: '.s:htmlfont.'; }') 16496c35beaaSBram Moolenaar + 16506c35beaaSBram Moolenaar " ch units for browsers which support them, em units for a somewhat 16516c35beaaSBram Moolenaar " reasonable fallback. Also make sure the special elements for size 16526c35beaaSBram Moolenaar " calculations aren't seen. 16536c35beaaSBram Moolenaar call append('.', [ 16546c35beaaSBram Moolenaar \ "input[size='1'] { width: 1em; width: 1ch; }", 16556c35beaaSBram Moolenaar \ "input[size='2'] { width: 2em; width: 2ch; }", 16566c35beaaSBram Moolenaar \ "input[size='3'] { width: 3em; width: 3ch; }", 16576c35beaaSBram Moolenaar \ "input[size='4'] { width: 4em; width: 4ch; }", 16586c35beaaSBram Moolenaar \ "input[size='5'] { width: 5em; width: 5ch; }", 16596c35beaaSBram Moolenaar \ "input[size='6'] { width: 6em; width: 6ch; }", 16606c35beaaSBram Moolenaar \ "input[size='7'] { width: 7em; width: 7ch; }", 16616c35beaaSBram Moolenaar \ "input[size='8'] { width: 8em; width: 8ch; }", 16626c35beaaSBram Moolenaar \ "input[size='9'] { width: 9em; width: 9ch; }", 16636c35beaaSBram Moolenaar \ "input[size='10'] { width: 10em; width: 10ch; }", 16646c35beaaSBram Moolenaar \ "input[size='11'] { width: 11em; width: 11ch; }", 16656c35beaaSBram Moolenaar \ "input[size='12'] { width: 12em; width: 12ch; }", 16666c35beaaSBram Moolenaar \ "input[size='13'] { width: 13em; width: 13ch; }", 16676c35beaaSBram Moolenaar \ "input[size='14'] { width: 14em; width: 14ch; }", 16686c35beaaSBram Moolenaar \ "input[size='15'] { width: 15em; width: 15ch; }", 16696c35beaaSBram Moolenaar \ "input[size='16'] { width: 16em; width: 16ch; }", 16706c35beaaSBram Moolenaar \ "input[size='17'] { width: 17em; width: 17ch; }", 16716c35beaaSBram Moolenaar \ "input[size='18'] { width: 18em; width: 18ch; }", 16726c35beaaSBram Moolenaar \ "input[size='19'] { width: 19em; width: 19ch; }", 16736c35beaaSBram Moolenaar \ "input[size='20'] { width: 20em; width: 20ch; }", 16746c35beaaSBram Moolenaar \ "#oneCharWidth, #oneEmWidth, #oneInputWidth { padding: 0; margin: 0; position: absolute; left: -999999px; visibility: hidden; }" 16756c35beaaSBram Moolenaar \ ]) 16766c35beaaSBram Moolenaar +21 16776c35beaaSBram Moolenaar for w in range(5, 100, 5) 16786c35beaaSBram Moolenaar let base = 0.01 * w 16796c35beaaSBram Moolenaar call append('.', join(map(range(1,20), "'.em'.w.' input[size='''.v:val.'''] { width: '.string(v:val*base).'em; }'"))) 16806c35beaaSBram Moolenaar + 16816c35beaaSBram Moolenaar endfor 16826c35beaaSBram Moolenaar if s:settings.prevent_copy =~# 'f' 16836c35beaaSBram Moolenaar " Make the cursor show active fold columns as active areas, and empty fold 16846c35beaaSBram Moolenaar " columns as not interactive. 16856c35beaaSBram Moolenaar call append('.', ['input.FoldColumn { cursor: pointer; }', 16866c35beaaSBram Moolenaar \ 'input.FoldColumn[value=""] { cursor: default; }' 16876c35beaaSBram Moolenaar \ ]) 16886c35beaaSBram Moolenaar +2 16896c35beaaSBram Moolenaar endif 16906c35beaaSBram Moolenaar " make line number column show as non-interactive if not selectable 16916c35beaaSBram Moolenaar if s:settings.prevent_copy =~# 'n' 16926c35beaaSBram Moolenaar call append('.', 'input.LineNr { cursor: default; }') 16936c35beaaSBram Moolenaar + 16946c35beaaSBram Moolenaar endif 16956c35beaaSBram Moolenaar " make fold text and line number column within fold text show as 16966c35beaaSBram Moolenaar " non-interactive if not selectable 16976c35beaaSBram Moolenaar if (s:settings.prevent_copy =~# 'n' || s:settings.prevent_copy =~# 't') && !s:settings.ignore_folding 16986c35beaaSBram Moolenaar call append('.', 'input.Folded { cursor: default; }') 16996c35beaaSBram Moolenaar + 17006c35beaaSBram Moolenaar endif 17016c35beaaSBram Moolenaar endif 1702071d4279SBram Moolenaarelse 1703543b7ef7SBram Moolenaar execute '%s:<body\([^>]*\):<body bgcolor="' . s:bgc . '" text="' . s:fgc . '"\1>\r<font face="'. s:htmlfont .'"' 1704071d4279SBram Moolenaarendif 1705071d4279SBram Moolenaar 17066c35beaaSBram Moolenaar" Gather attributes for all other classes. Do diff first so that normal 17076c35beaaSBram Moolenaar" highlight groups are inserted before it. 1708076e8b2aSBram Moolenaarif s:settings.use_css 17096c35beaaSBram Moolenaar if s:diff_mode 17106c35beaaSBram Moolenaar call append('.', filter(map(keys(s:diffstylelist), "s:diffstylelist[v:val]"), 'v:val != ""')) 17116c35beaaSBram Moolenaar endif 17126c35beaaSBram Moolenaar if !empty(s:stylelist) 17136c35beaaSBram Moolenaar call append('.', filter(map(keys(s:stylelist), "s:stylelist[v:val]"), 'v:val != ""')) 1714071d4279SBram Moolenaar endif 1715071d4279SBram Moolenaarendif 1716071d4279SBram Moolenaar 1717071d4279SBram Moolenaar" Add hyperlinks 17186c35beaaSBram Moolenaar" TODO: add option to not do this? Maybe just make the color the same as the 17196c35beaaSBram Moolenaar" text highlight group normally is? 17201cd871b5SBram Moolenaar%s+\(https\=://\S\{-}\)\(\([.,;:}]\=\(\s\|$\)\)\|[\\"'<>]\|>\|<\|"\)+<a href="\1">\1</a>\2+ge 1721071d4279SBram Moolenaar 1722071d4279SBram Moolenaar" The DTD 1723076e8b2aSBram Moolenaarif s:settings.use_xhtml 1724076e8b2aSBram Moolenaar exe "normal! gg$a\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" 1725076e8b2aSBram Moolenaarelseif s:settings.use_css && !s:settings.no_pre 1726076e8b2aSBram Moolenaar exe "normal! gg0i<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n" 17271cd871b5SBram Moolenaarelse 1728076e8b2aSBram Moolenaar exe "normal! gg0i<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n" 17291cd871b5SBram Moolenaarendif 17301cd871b5SBram Moolenaar 1731076e8b2aSBram Moolenaarif s:settings.use_xhtml 17321cd871b5SBram Moolenaar exe "normal! gg/<html/e\na xmlns=\"http://www.w3.org/1999/xhtml\"\e" 17331cd871b5SBram Moolenaarendif 1734071d4279SBram Moolenaar 1735071d4279SBram Moolenaar" Cleanup 1736071d4279SBram Moolenaar%s:\s\+$::e 1737071d4279SBram Moolenaar 17382a8a3ecbSBram Moolenaar" Restore old settings (new window first) 1739543b7ef7SBram Moolenaar" 1740543b7ef7SBram Moolenaar" Don't bother restoring foldmethod in case it was syntax because the markup is 1741543b7ef7SBram Moolenaar" so weirdly formatted it can take a LONG time. 17428df7f888SBram Moolenaarlet &l:foldenable = s:old_fen 1743071d4279SBram Moolenaarlet &report = s:old_report 1744071d4279SBram Moolenaarlet &title = s:old_title 1745071d4279SBram Moolenaarlet &icon = s:old_icon 1746071d4279SBram Moolenaarlet &paste = s:old_paste 1747071d4279SBram Moolenaarlet &magic = s:old_magic 1748071d4279SBram Moolenaarlet @/ = s:old_search 1749349b2fb0SBram Moolenaarlet &more = s:old_more 17502a8a3ecbSBram Moolenaar 17512a8a3ecbSBram Moolenaar" switch to original window to restore those settings 1752071d4279SBram Moolenaarexe s:orgwin . "wincmd w" 17532a8a3ecbSBram Moolenaar 17542a8a3ecbSBram Moolenaarif !s:settings.expand_tabs 17552a8a3ecbSBram Moolenaar let &l:isprint = s:old_isprint 17562a8a3ecbSBram Moolenaarendif 1757166af9bbSBram Moolenaarlet &l:stl = s:origwin_stl 1758071d4279SBram Moolenaarlet &l:et = s:old_et 17598df7f888SBram Moolenaarlet &l:scrollbind = s:old_bind 17602a8a3ecbSBram Moolenaar 17612a8a3ecbSBram Moolenaar" and back to the new window again to end there 1762071d4279SBram Moolenaarexe s:newwin . "wincmd w" 17632a8a3ecbSBram Moolenaar 1764166af9bbSBram Moolenaarlet &l:stl = s:newwin_stl 1765349b2fb0SBram Moolenaarexec 'resize' s:old_winheight 1766349b2fb0SBram Moolenaarlet &l:winfixheight = s:old_winfixheight 1767071d4279SBram Moolenaar 1768349b2fb0SBram Moolenaarlet &ls=s:ls 1769349b2fb0SBram Moolenaar 1770071d4279SBram Moolenaar" Save a little bit of memory (worth doing?) 17718e5af3e5SBram Moolenaarunlet s:htmlfont s:whitespace 17728df7f888SBram Moolenaarunlet s:old_et s:old_paste s:old_icon s:old_report s:old_title s:old_search 1773543b7ef7SBram Moolenaarunlet s:old_magic s:old_more s:old_fen s:old_winheight 17742a8a3ecbSBram Moolenaarunlet! s:old_isprint 17756c35beaaSBram Moolenaarunlet s:whatterm s:stylelist s:diffstylelist s:lnum s:end s:margin s:fgc s:bgc s:old_winfixheight 17766c35beaaSBram Moolenaarunlet! s:col s:id s:attr s:len s:line s:new s:expandedtab s:concealinfo s:diff_mode 17778df7f888SBram Moolenaarunlet! s:orgwin s:newwin s:orgbufnr s:idx s:i s:offset s:ls s:origwin_stl 17788df7f888SBram Moolenaarunlet! s:newwin_stl s:current_syntax 177905159a0cSBram Moolenaarif !v:profiling 1780071d4279SBram Moolenaar delfunc s:HtmlColor 178135a9aaabSBram Moolenaar delfunc s:HtmlFormat 1782071d4279SBram Moolenaar delfunc s:CSS1 17836c35beaaSBram Moolenaar delfunc s:BuildStyleWrapper 1784076e8b2aSBram Moolenaar if !s:settings.use_css 1785071d4279SBram Moolenaar delfunc s:HtmlOpening 1786071d4279SBram Moolenaar delfunc s:HtmlClosing 1787071d4279SBram Moolenaar endif 1788076e8b2aSBram Moolenaar if s:settings.dynamic_folds 17895c73622aSBram Moolenaar delfunc s:FoldCompare 17905c73622aSBram Moolenaar endif 17915c73622aSBram Moolenaar 1792076e8b2aSBram Moolenaar if !s:settings.no_progress 1793349b2fb0SBram Moolenaar delfunc s:ProgressBar 1794349b2fb0SBram Moolenaar delfunc s:progressbar.paint 1795349b2fb0SBram Moolenaar delfunc s:progressbar.incr 1796349b2fb0SBram Moolenaar unlet s:pgb s:progressbar 1797349b2fb0SBram Moolenaar endif 1798349b2fb0SBram Moolenaarendif 1799349b2fb0SBram Moolenaar 18008df7f888SBram Moolenaarunlet! s:new_lnum s:diffattr s:difffillchar s:foldfillchar s:HtmlSpace 18016c35beaaSBram Moolenaarunlet! s:LeadingSpace s:HtmlEndline s:firstfold s:numcol s:foldcolumn 18026c35beaaSBram Moolenaarunlet s:foldstack s:allfolds s:foldId s:settings 18035c73622aSBram Moolenaar 18045c73622aSBram Moolenaarlet &cpo = s:cpo_sav 1805349b2fb0SBram Moolenaarunlet! s:cpo_sav 18065c73622aSBram Moolenaar 1807349b2fb0SBram Moolenaar" Make sure any patches will probably use consistent indent 18087c86f4ccSBram Moolenaar" vim: ts=8 sw=2 sts=2 noet 1809