const template = {
add: function (a, b) a + b,
join: function (c) function (a, b) a + c + b,
map: function (iter, fn, sep)
{
if (iter.length) /* Kludge? */
iter = util.Array.iterator(iter);
let ret = <>>;
let n = 0;
for each (let i in Iterator(iter))
{
let val = fn(i);
if (val == undefined)
continue;
if (sep && n++)
ret += sep;
ret += val;
}
return ret;
},
maybeXML: function (xml)
{
if (typeof xml == "xml")
return xml;
try
{
return new XMLList(xml);
}
catch (e) {}
return <>{xml}>;
},
completionRow: function (context, item, class)
{
let text = item.text || item[0] || "";
let description = item.description || item[1] || "";
let icon = item.icon || item[2];
/* Kludge until we have completion contexts. */
let map = completion.filterMap;
if (map)
{
text = map[0] ? map[0](text) : text;
description = map[1] ? map[1](description) : description;
}
// FIXME: Move.
let filter = context.filter;
if (filter)
{
text = template.highlightFilter(text, filter);
description = template.highlightFilter(description, filter);
}
if (typeof icon == "function")
icon = icon();
return
- {icon ?
: <>>}
- {text}
- {description}
;
},
// if "processStrings" is true, any passed strings will be surrounded by " and
// any line breaks are displayed as \n
highlight: function (arg, processStrings)
{
// some objects like window.JSON or getBrowsers()._browsers need the try/catch
try
{
switch (arg == null ? "undefined" : typeof arg)
{
case "number":
return {arg};
case "string":
if (processStrings)
arg = <>{util.escapeString(arg)}>;
return {arg};
case "boolean":
return {arg};
case "function":
// Vim generally doesn't like /foo*/, because */ looks like a comment terminator.
// Using /foo*(:?)/ instead.
if (processStrings)
return {String(arg).replace(/\{(.|\n)*(?:)/g, "{ ... }")};
return <>{arg}>;
case "undefined":
return {arg};
case "object":
// for java packages value.toString() would crash so badly
// that we cannot even try/catch it
if (/^\[JavaPackage.*\]$/.test(arg))
return <>[JavaPackage]>;
if (processStrings && false)
arg = String(arg).replace("\n", "\\n", "g");
return {arg};
default:
return ]]>;
}
}
catch (e)
{
return]]>;
}
},
highlightFilter: function (str, filter)
{
if (typeof str == "xml")
return str;
return this.highlightSubstrings(str, (function ()
{
let lcstr = String.toLowerCase(str);
let lcfilter = filter.toLowerCase();
let start = 0;
while ((start = lcstr.indexOf(lcfilter, start)) > -1)
{
yield [start, filter.length];
start += filter.length;
}
})());
},
highlightRegexp: function (str, re)
{
if (typeof str == "xml")
return str;
return this.highlightSubstrings(str, (function ()
{
while (res = re.exec(str))
yield [res.index, res[0].length];
})());
},
highlightSubstrings: function (str, iter)
{
if (typeof str == "xml")
return str;
if (str == "")
return <>{str}>;
str = String(str).replace(" ", "\u00a0");
let s = <>>;
let start = 0;
for (let [i, length] in iter)
{
XML.ignoreWhitespace = false;
s += <>{str.substring(start, i)}>;
s += {str.substr(i, length)};
start = i + length;
}
return s + <>{str.substr(start)}>;
},
highlightURL: function (str, force)
{
if (force || /^[a-zA-Z]+:\/\//.test(str))
return {str};
else
return str;
},
generic: function (xml)
{
return <>:{commandline.getCommand()}
> + xml;
},
// every item must have a .xml property which defines how to draw itself
// @param headers is an array of strings, the text for the header columns
genericTable: function (headers, items)
{
return this.generic(
{
headers.reduce(function (prev, cur) prev + | {cur} | , <>>)
}
{
this.map(items, function (item) item.xml)
}
);
},
// returns a single row for a bookmark or history item
bookmarkItem: function (item)
{
var extra = [];
if (item.keyword)
extra.push(['keyword', item.keyword, "hl-Keyword"]);
if (item.tags && item.tags.length > 0)
extra.push(["tags", item.tags.join(","), "hl-Tag"]); // no space, otherwise it looks strange, since we just have spaces to seperate tags from keywords
return

- {util.clip(item.title || "", 50)}
-
{item.url}
{
!(extra.length) ? "" :
}
},
jumps: function (index, elems)
{
return this.generic(
| jump | title | URI |
{
this.map(Iterator(elems), function ([idx, val])
| {idx == index ? ">" : ""} |
{Math.abs(idx - index)} |
{val.title} |
{val.URI.spec} |
)
}
);
},
options: function (title, opts)
{
return this.generic(
| --- {title} --- |
{
this.map(opts, function (opt)
|
{opt.pre}{opt.name}{opt.value}
{opt.isDefault || opt.default == null ? "" : }
|
)
}
);
},
table: function (title, data, indent)
{
let table =
| {title} |
{
this.map(data, function (datum)
| {datum[0]} |
{template.maybeXML(datum[1])} |
)
}
;
if (table.tr.length() > 1)
return table;
},
tabular: function (headings, style, iter)
{
/* This might be mind-bogglingly slow. We'll see. */
return this.generic(
{
this.map(headings, function (h)
| {h} | )
}
{
this.map(iter, function (row)
{
template.map(Iterator(row), function ([i, d])
| {d} | )
}
)
}
);
},
usage: function (iter)
{
return this.generic(
{
this.map(iter, function (item)
| {item.name || item.names[0]} |
{item.description} |
)
}
);
}
};
// vim: set fdm=marker sw=4 ts=4 et: