mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-20 05:08:00 +01:00
Move the standard type completers to appropriate modules.
This commit is contained in:
@@ -399,6 +399,93 @@ function Bookmarks() //{{{
|
||||
literal: 0
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
completion.bookmark = function bookmark(context, tags, extra) {
|
||||
context.title = ["Bookmark", "Title"];
|
||||
context.format = bookmarks.format;
|
||||
for (let val in Iterator(extra || []))
|
||||
{
|
||||
let [k, v] = val; // Need block scope here for the closure
|
||||
if (v)
|
||||
context.filters.push(function (item) this._match(v, item[k]));
|
||||
}
|
||||
// Need to make a copy because set completions() checks instanceof Array,
|
||||
// and this may be an Array from another window.
|
||||
context.completions = Array.slice(storage["bookmark-cache"].bookmarks);
|
||||
completion.urls(context, tags);
|
||||
};
|
||||
|
||||
completion.search = function search(context, noSuggest) {
|
||||
let [, keyword, space, args] = context.filter.match(/^\s*(\S*)(\s*)(.*)$/);
|
||||
let keywords = bookmarks.getKeywords();
|
||||
let engines = bookmarks.getSearchEngines();
|
||||
|
||||
context.title = ["Search Keywords"];
|
||||
context.completions = keywords.concat(engines);
|
||||
context.keys = { text: 0, description: 1, icon: 2 };
|
||||
|
||||
if (!space || noSuggest)
|
||||
return;
|
||||
|
||||
context.fork("suggest", keyword.length + space.length, this, "searchEngineSuggest",
|
||||
keyword, true);
|
||||
|
||||
let item = keywords.filter(function (k) k.keyword == keyword)[0];
|
||||
if (item && item.url.indexOf("%s") > -1)
|
||||
context.fork("keyword/" + keyword, keyword.length + space.length, null, function (context) {
|
||||
context.format = history.format;
|
||||
context.title = [keyword + " Quick Search"];
|
||||
// context.background = true;
|
||||
context.compare = CompletionContext.Sort.unsorted;
|
||||
context.generate = function () {
|
||||
let [begin, end] = item.url.split("%s");
|
||||
|
||||
return history.get({ uri: window.makeURI(begin), uriIsPrefix: true }).map(function (item) {
|
||||
let rest = item.url.length - end.length;
|
||||
let query = item.url.substring(begin.length, rest);
|
||||
if (item.url.substr(rest) == end && query.indexOf("&") == -1)
|
||||
{
|
||||
item.url = decodeURIComponent(query);
|
||||
return item;
|
||||
}
|
||||
}).filter(util.identity);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
completion.searchEngineSuggest = function searchEngineSuggest(context, engineAliases, kludge) {
|
||||
if (!context.filter)
|
||||
return;
|
||||
|
||||
let engineList = (engineAliases || options["suggestengines"] || "google").split(",");
|
||||
|
||||
let completions = [];
|
||||
engineList.forEach(function (name) {
|
||||
let engine = services.get("browserSearch").getEngineByAlias(name);
|
||||
if (!engine)
|
||||
return;
|
||||
let [,word] = /^\s*(\S+)/.exec(context.filter) || [];
|
||||
if (!kludge && word == name) // FIXME: Check for matching keywords
|
||||
return;
|
||||
let ctxt = context.fork(name, 0);
|
||||
|
||||
ctxt.title = [engine.description + " Suggestions"];
|
||||
ctxt.compare = CompletionContext.Sort.unsorted;
|
||||
ctxt.incomplete = true;
|
||||
bookmarks.getSuggestions(name, ctxt.filter, function (compl) {
|
||||
ctxt.incomplete = false;
|
||||
ctxt.completions = compl;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
completion.addUrlCompleter("S", "Suggest engines", completion.searchEngineSuggest);
|
||||
completion.addUrlCompleter("b", "Bookmarks", completion.bookmark);
|
||||
completion.addUrlCompleter("s", "Search engines and keyword URLs", completion.search);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
@@ -840,6 +927,23 @@ function History() //{{{
|
||||
options: [[["-max", "-m"], options.OPTION_INT]]
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
completion.history = function _history(context, maxItems) {
|
||||
context.format = history.format;
|
||||
context.title = ["History"]
|
||||
context.compare = CompletionContext.Sort.unsorted;
|
||||
//context.background = true;
|
||||
if (context.maxItems == null)
|
||||
context.maxItems = 100;
|
||||
context.regenerate = true;
|
||||
context.generate = function () history.get(context.filter, this.maxItems);
|
||||
};
|
||||
|
||||
completion.addUrlCompleter("h", "History", completion.history);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
@@ -673,6 +673,61 @@ function Buffer() //{{{
|
||||
bang: true
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
liberator.registerObserver("load_completion", function () {
|
||||
completion.alternateStyleSheet = function alternateStylesheet(context) {
|
||||
context.title = ["Stylesheet", "Location"];
|
||||
|
||||
// unify split style sheets
|
||||
let styles = {};
|
||||
|
||||
buffer.alternateStyleSheets.forEach(function (style) {
|
||||
if (!(style.title in styles))
|
||||
styles[style.title] = [];
|
||||
|
||||
styles[style.title].push(style.href || "inline");
|
||||
});
|
||||
|
||||
context.completions = [[s, styles[s].join(", ")] for (s in styles)];
|
||||
};
|
||||
|
||||
completion.buffer = function buffer(context) {
|
||||
filter = context.filter.toLowerCase();
|
||||
context.anchored = false;
|
||||
context.title = ["Buffer", "URL"];
|
||||
context.keys = { text: "text", description: "url", icon: "icon" };
|
||||
context.compare = CompletionContext.Sort.number;
|
||||
let process = context.process[0];
|
||||
context.process = [function (item, text)
|
||||
<>
|
||||
<span highlight="Indicator" style="display: inline-block; width: 1.5em; text-align: center">{item.item.indicator}</span>
|
||||
{ process.call(this, item, text) }
|
||||
</>];
|
||||
|
||||
context.completions = util.map(tabs.browsers, function ([i, browser]) {
|
||||
let indicator = " ";
|
||||
if (i == tabs.index())
|
||||
indicator = "%"
|
||||
else if (i == tabs.index(tabs.alternate))
|
||||
indicator = "#";
|
||||
|
||||
let tab = tabs.getTab(i);
|
||||
let url = browser.contentDocument.location.href;
|
||||
i = i + 1;
|
||||
|
||||
return {
|
||||
text: [i + ": " + (tab.label || "(Untitled)"), i + ": " + url],
|
||||
url: template.highlightURL(url),
|
||||
indicator: indicator,
|
||||
icon: tab.image || DEFAULT_FAVICON
|
||||
};
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PAGE INFO ///////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
@@ -1769,6 +1824,19 @@ function Marks() //{{{
|
||||
marks.list(filter);
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
completion.mark = function mark(context) {
|
||||
function percent(i) Math.round(i * 100);
|
||||
|
||||
// FIXME: Line/Column doesn't make sense with %
|
||||
context.title = ["Mark", "Line Column File"];
|
||||
context.keys.description = function ([,m]) percent(m.position.y) + "% " + percent(m.position.x) + "% " + m.location;
|
||||
context.completions = marks.all;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
@@ -392,10 +392,6 @@ function Commands() //{{{
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
liberator.registerObserver("load_completion", function () {
|
||||
completion.setFunctionCompleter(commands.get, [function () ([c.name, c.description] for (c in commands))]);
|
||||
});
|
||||
|
||||
const self = {
|
||||
|
||||
// FIXME: remove later, when our option handler is better
|
||||
@@ -1156,6 +1152,77 @@ function Commands() //{{{
|
||||
completer: function (context) completion.userCommand(context)
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
liberator.registerObserver("load_completion", function () {
|
||||
completion.setFunctionCompleter(commands.get, [function () ([c.name, c.description] for (c in commands))]);
|
||||
|
||||
completion.command = function command(context) {
|
||||
context.title = ["Command"];
|
||||
context.keys = { text: "longNames", description: "description" };
|
||||
context.completions = [k for (k in commands)];
|
||||
};
|
||||
|
||||
// provides completions for ex commands, including their arguments
|
||||
completion.ex = function ex(context) {
|
||||
// if there is no space between the command name and the cursor
|
||||
// then get completions of the command name
|
||||
let [count, cmd, bang, args] = commands.parseCommand(context.filter);
|
||||
let [, prefix, junk] = context.filter.match(/^(:*\d*)\w*(.?)/) || [];
|
||||
context.advance(prefix.length)
|
||||
if (!junk)
|
||||
return context.fork("", 0, this, "command");
|
||||
|
||||
// dynamically get completions as specified with the command's completer function
|
||||
let command = commands.get(cmd);
|
||||
if (!command)
|
||||
{
|
||||
context.highlight(0, cmd.length, "SPELLCHECK");
|
||||
return;
|
||||
}
|
||||
|
||||
[prefix] = context.filter.match(/^(?:\w*[\s!]|!)\s*/);
|
||||
let cmdContext = context.fork(cmd, prefix.length);
|
||||
let argContext = context.fork("args", prefix.length);
|
||||
args = command.parseArgs(cmdContext.filter, argContext, { count: count, bang: bang });
|
||||
if (args)
|
||||
{
|
||||
// FIXME: Move to parseCommand
|
||||
args.count = count;
|
||||
args.bang = bang;
|
||||
if (!args.completeOpt && command.completer)
|
||||
{
|
||||
cmdContext.advance(args.completeStart);
|
||||
cmdContext.quote = args.quote;
|
||||
cmdContext.filter = args.completeFilter;
|
||||
try
|
||||
{
|
||||
let compObject = command.completer.call(command, cmdContext, args);
|
||||
if (compObject instanceof Array) // for now at least, let completion functions return arrays instead of objects
|
||||
compObject = { start: compObject[0], items: compObject[1] };
|
||||
if (compObject != null)
|
||||
{
|
||||
cmdContext.advance(compObject.start);
|
||||
cmdContext.filterFunc = null;
|
||||
cmdContext.completions = compObject.items;
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
liberator.reportError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
completion.userCommand = function userCommand(context) {
|
||||
context.title = ["User Command", "Definition"];
|
||||
context.keys = { text: "name", description: "replacementText" };
|
||||
context.completions = commands.getUserCommands();
|
||||
};
|
||||
});
|
||||
//}}}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -1340,533 +1340,10 @@ function Completion() //{{{
|
||||
////////////////////// COMPLETION TYPES ////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
// TODO: shouldn't all of these have a standard signature (context, args, ...)? --djk
|
||||
abbreviation: function abbreviation(context, args, mode)
|
||||
{
|
||||
mode = mode || "!";
|
||||
|
||||
if (args.completeArg == 0)
|
||||
{
|
||||
let abbreviations = editor.getAbbreviations(mode);
|
||||
context.completions = [[lhs, ""] for ([, [, lhs,]] in Iterator(abbreviations))];
|
||||
}
|
||||
},
|
||||
|
||||
alternateStyleSheet: function alternateStylesheet(context)
|
||||
{
|
||||
context.title = ["Stylesheet", "Location"];
|
||||
|
||||
// unify split style sheets
|
||||
let styles = {};
|
||||
|
||||
buffer.alternateStyleSheets.forEach(function (style) {
|
||||
if (!(style.title in styles))
|
||||
styles[style.title] = [];
|
||||
|
||||
styles[style.title].push(style.href || "inline");
|
||||
});
|
||||
|
||||
context.completions = [[s, styles[s].join(", ")] for (s in styles)];
|
||||
},
|
||||
|
||||
autocmdEvent: function autocmdEvent(context)
|
||||
{
|
||||
context.completions = config.autocommands;
|
||||
},
|
||||
|
||||
// TODO: shouldn't these app-specific completers be moved to config.js? --djk
|
||||
bookmark: function bookmark(context, tags, extra)
|
||||
{
|
||||
context.title = ["Bookmark", "Title"];
|
||||
context.format = bookmarks.format;
|
||||
for (let val in Iterator(extra || []))
|
||||
{
|
||||
let [k, v] = val; // Need block scope here for the closure
|
||||
if (v)
|
||||
context.filters.push(function (item) this._match(v, item[k]));
|
||||
}
|
||||
// Need to make a copy because set completions() checks instanceof Array,
|
||||
// and this may be an Array from another window.
|
||||
context.completions = Array.slice(storage["bookmark-cache"].bookmarks);
|
||||
completion.urls(context, tags);
|
||||
},
|
||||
|
||||
song: function song(context, args)
|
||||
{
|
||||
// TODO: useful descriptions?
|
||||
function map(list) list.map(function (i) [i, ""]);
|
||||
let [artist, album] = [args[0], args[1]];
|
||||
|
||||
if (args.completeArg == 0)
|
||||
{
|
||||
context.title = ["Artists"];
|
||||
context.completions = map(library.getArtists());
|
||||
}
|
||||
else if (args.completeArg == 1)
|
||||
{
|
||||
context.title = ["Albums by " + artist];
|
||||
context.completions = map(library.getAlbums(artist));
|
||||
}
|
||||
else if (args.completeArg == 2)
|
||||
{
|
||||
context.title = ["Tracks from " + album + " by " + artist];
|
||||
context.completions = map(library.getTracks(artist, album));
|
||||
}
|
||||
},
|
||||
|
||||
playlist: function playlist(context, args)
|
||||
{
|
||||
context.title = ["Playlist", "Type"];
|
||||
context.keys = { text: "name", description: "type" };
|
||||
context.completions = player.getPlaylists();
|
||||
},
|
||||
|
||||
buffer: function buffer(context)
|
||||
{
|
||||
filter = context.filter.toLowerCase();
|
||||
context.anchored = false;
|
||||
context.title = ["Buffer", "URL"];
|
||||
context.keys = { text: "text", description: "url", icon: "icon" };
|
||||
context.compare = CompletionContext.Sort.number;
|
||||
let process = context.process[0];
|
||||
context.process = [function (item, text)
|
||||
<>
|
||||
<span highlight="Indicator" style="display: inline-block; width: 1.5em; text-align: center">{item.item.indicator}</span>
|
||||
{ process.call(this, item, text) }
|
||||
</>];
|
||||
|
||||
context.completions = util.map(tabs.browsers, function ([i, browser]) {
|
||||
let indicator = " ";
|
||||
if (i == tabs.index())
|
||||
indicator = "%"
|
||||
else if (i == tabs.index(tabs.alternate))
|
||||
indicator = "#";
|
||||
|
||||
let tab = tabs.getTab(i);
|
||||
let url = browser.contentDocument.location.href;
|
||||
i = i + 1;
|
||||
|
||||
return {
|
||||
text: [i + ": " + (tab.label || "(Untitled)"), i + ": " + url],
|
||||
url: template.highlightURL(url),
|
||||
indicator: indicator,
|
||||
icon: tab.image || DEFAULT_FAVICON
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
charset: function (context)
|
||||
{
|
||||
context.anchored = false;
|
||||
context.generate = function () {
|
||||
let names = util.Array(
|
||||
'more1 more2 more3 more4 more5 unicode'.split(' ').map(function (key)
|
||||
options.getPref('intl.charsetmenu.browser.' + key).split(', ')))
|
||||
.flatten().uniq();
|
||||
let bundle = document.getElementById('liberator-charset-bundle');
|
||||
return names.map(function (name) [name, bundle.getString(name.toLowerCase() + '.title')]);
|
||||
};
|
||||
},
|
||||
|
||||
colorScheme: function colorScheme(context)
|
||||
{
|
||||
let colors = [];
|
||||
|
||||
io.getRuntimeDirectories("colors").forEach(function (dir) {
|
||||
io.readDirectory(dir).forEach(function (file) {
|
||||
if (/\.vimp$/.test(file.leafName) && !colors.some(function (c) c.leafName == file.leafName))
|
||||
colors.push(file);
|
||||
});
|
||||
});
|
||||
|
||||
context.title = ["Color Scheme", "Runtime Path"];
|
||||
context.completions = [[c.leafName.replace(/\.vimp$/, ""), c.parent.path] for ([,c] in Iterator(colors))]
|
||||
},
|
||||
|
||||
command: function command(context)
|
||||
{
|
||||
context.title = ["Command"];
|
||||
context.keys = { text: "longNames", description: "description" };
|
||||
context.completions = [k for (k in commands)];
|
||||
},
|
||||
|
||||
dialog: function dialog(context)
|
||||
{
|
||||
context.title = ["Dialog"];
|
||||
context.completions = config.dialogs;
|
||||
},
|
||||
|
||||
directory: function directory(context, full)
|
||||
{
|
||||
this.file(context, full);
|
||||
context.filters.push(function ({ item: f }) f.isDirectory());
|
||||
},
|
||||
|
||||
environment: function environment(context)
|
||||
{
|
||||
let command = liberator.has("Win32") ? "set" : "env";
|
||||
let lines = io.system(command).split("\n");
|
||||
lines.pop();
|
||||
|
||||
context.title = ["Environment Variable", "Value"];
|
||||
context.generate = function () lines.map(function (line) (line.match(/([^=]+)=(.+)/) || []).slice(1));
|
||||
},
|
||||
|
||||
// provides completions for ex commands, including their arguments
|
||||
ex: function ex(context)
|
||||
{
|
||||
// if there is no space between the command name and the cursor
|
||||
// then get completions of the command name
|
||||
let [count, cmd, bang, args] = commands.parseCommand(context.filter);
|
||||
let [, prefix, junk] = context.filter.match(/^(:*\d*)\w*(.?)/) || [];
|
||||
context.advance(prefix.length)
|
||||
if (!junk)
|
||||
return context.fork("", 0, this, "command");
|
||||
|
||||
// dynamically get completions as specified with the command's completer function
|
||||
let command = commands.get(cmd);
|
||||
if (!command)
|
||||
{
|
||||
context.highlight(0, cmd.length, "SPELLCHECK");
|
||||
return;
|
||||
}
|
||||
|
||||
[prefix] = context.filter.match(/^(?:\w*[\s!]|!)\s*/);
|
||||
let cmdContext = context.fork(cmd, prefix.length);
|
||||
let argContext = context.fork("args", prefix.length);
|
||||
args = command.parseArgs(cmdContext.filter, argContext, { count: count, bang: bang });
|
||||
if (args)
|
||||
{
|
||||
// FIXME: Move to parseCommand
|
||||
args.count = count;
|
||||
args.bang = bang;
|
||||
if (!args.completeOpt && command.completer)
|
||||
{
|
||||
cmdContext.advance(args.completeStart);
|
||||
cmdContext.quote = args.quote;
|
||||
cmdContext.filter = args.completeFilter;
|
||||
try
|
||||
{
|
||||
let compObject = command.completer.call(command, cmdContext, args);
|
||||
if (compObject instanceof Array) // for now at least, let completion functions return arrays instead of objects
|
||||
compObject = { start: compObject[0], items: compObject[1] };
|
||||
if (compObject != null)
|
||||
{
|
||||
cmdContext.advance(compObject.start);
|
||||
cmdContext.filterFunc = null;
|
||||
cmdContext.completions = compObject.items;
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
liberator.reportError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: support file:// and \ or / path separators on both platforms
|
||||
// if "tail" is true, only return names without any directory components
|
||||
file: function file(context, full)
|
||||
{
|
||||
// dir == "" is expanded inside readDirectory to the current dir
|
||||
let [dir] = context.filter.match(/^(?:.*[\/\\])?/);
|
||||
|
||||
if (!full)
|
||||
context.advance(dir.length);
|
||||
|
||||
context.title = [full ? "Path" : "Filename", "Type"];
|
||||
context.keys = {
|
||||
text: !full ? "leafName" : function (f) dir + f.leafName,
|
||||
description: function (f) f.isDirectory() ? "Directory" : "File",
|
||||
isdir: function (f) f.isDirectory(),
|
||||
icon: function (f) f.isDirectory() ? "resource://gre/res/html/folder.png"
|
||||
: "moz-icon://" + f.leafName
|
||||
};
|
||||
context.compare = function (a, b)
|
||||
b.isdir - a.isdir || String.localeCompare(a.text, b.text);
|
||||
|
||||
if (options["wildignore"])
|
||||
{
|
||||
let wigRegexp = RegExp("(^" + options.get("wildignore").values.join("|") + ")$");
|
||||
context.filters.push(function ({item: f}) f.isDirectory() || !wigRegexp.test(f.leafName));
|
||||
}
|
||||
|
||||
// context.background = true;
|
||||
context.key = dir;
|
||||
context.generate = function generate_file()
|
||||
{
|
||||
try
|
||||
{
|
||||
return io.readDirectory(dir);
|
||||
}
|
||||
catch (e) {}
|
||||
};
|
||||
},
|
||||
|
||||
help: function help(context)
|
||||
{
|
||||
context.title = ["Help"];
|
||||
context.anchored = false;
|
||||
context.generate = function ()
|
||||
{
|
||||
let res = config.helpFiles.map(function (file) {
|
||||
let resp = util.httpGet("chrome://liberator/locale/" + file);
|
||||
if (!resp)
|
||||
return [];
|
||||
let doc = resp.responseXML;
|
||||
return Array.map(doc.getElementsByClassName("tag"),
|
||||
function (elem) [elem.textContent, file]);
|
||||
});
|
||||
return util.Array.flatten(res);
|
||||
}
|
||||
},
|
||||
|
||||
// XXX
|
||||
highlightGroup: function highlightGroup(context, args) commands.get("highlight").completer(context, args),
|
||||
|
||||
history: function _history(context, maxItems)
|
||||
{
|
||||
context.format = history.format;
|
||||
context.title = ["History"]
|
||||
context.compare = CompletionContext.Sort.unsorted;
|
||||
//context.background = true;
|
||||
if (context.maxItems == null)
|
||||
context.maxItems = 100;
|
||||
context.regenerate = true;
|
||||
context.generate = function () history.get(context.filter, this.maxItems);
|
||||
},
|
||||
|
||||
get javascriptCompleter() javascript,
|
||||
|
||||
javascript: function _javascript(context) javascript.complete(context),
|
||||
|
||||
location: function location(context)
|
||||
{
|
||||
if (!services.get("autoCompleteSearch"))
|
||||
return;
|
||||
|
||||
context.anchored = false;
|
||||
context.title = ["Smart Completions"];
|
||||
context.keys.icon = 2;
|
||||
context.incomplete = true;
|
||||
context.hasItems = context.completions.length > 0; // XXX
|
||||
context.filterFunc = null;
|
||||
context.cancel = function () services.get("autoCompleteSearch").stopSearch();
|
||||
context.compare = CompletionContext.Sort.unsorted;
|
||||
let timer = new Timer(50, 100, function (result) {
|
||||
context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
|
||||
context.completions = [
|
||||
[result.getValueAt(i), result.getCommentAt(i), result.getImageAt(i)]
|
||||
for (i in util.range(0, result.matchCount))
|
||||
];
|
||||
});
|
||||
services.get("autoCompleteSearch").stopSearch();
|
||||
services.get("autoCompleteSearch").startSearch(context.filter, "", context.result, {
|
||||
onSearchResult: function onSearchResult(search, result)
|
||||
{
|
||||
context.result = result;
|
||||
timer.tell(result);
|
||||
if (result.searchResult <= result.RESULT_SUCCESS)
|
||||
timer.flush();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
macro: function macro(context)
|
||||
{
|
||||
context.title = ["Macro", "Keys"];
|
||||
context.completions = [item for (item in events.getMacros())];
|
||||
},
|
||||
|
||||
mark: function mark(context)
|
||||
{
|
||||
function percent(i) Math.round(i * 100);
|
||||
|
||||
// FIXME: Line/Column doesn't make sense with %
|
||||
context.title = ["Mark", "Line Column File"];
|
||||
context.keys.description = function ([,m]) percent(m.position.y) + "% " + percent(m.position.x) + "% " + m.location;
|
||||
context.completions = marks.all;
|
||||
},
|
||||
|
||||
mediaView: function mediaView(context)
|
||||
{
|
||||
context.title = ["Media View", "URL"];
|
||||
context.anchored = false;
|
||||
context.keys = { text: "contentTitle", description: "contentUrl" };
|
||||
context.completions = player.getMediaPages();
|
||||
},
|
||||
|
||||
menuItem: function menuItem(context)
|
||||
{
|
||||
context.title = ["Menu Path", "Label"];
|
||||
context.anchored = false;
|
||||
context.keys = { text: "fullMenuPath", description: function (item) item.getAttribute("label") };
|
||||
context.completions = liberator.menuItems;
|
||||
},
|
||||
|
||||
option: function option(context, scope)
|
||||
{
|
||||
context.title = ["Option"];
|
||||
context.keys = { text: "names", description: "description" };
|
||||
context.completions = options;
|
||||
if (scope)
|
||||
context.filters.push(function ({ item: opt }) opt.scope & scope);
|
||||
},
|
||||
|
||||
optionValue: function (context, name, op, curValue)
|
||||
{
|
||||
let opt = options.get(name);
|
||||
let completer = opt.completer;
|
||||
if (!completer)
|
||||
return;
|
||||
|
||||
let curValues = curValue != null ? opt.parseValues(curValue) : opt.values;
|
||||
let newValues = opt.parseValues(context.filter);
|
||||
|
||||
let len = context.filter.length;
|
||||
switch (opt.type)
|
||||
{
|
||||
case "boolean":
|
||||
if (!completer)
|
||||
completer = function () [["true", ""], ["false", ""]];
|
||||
break;
|
||||
case "stringlist":
|
||||
let target = newValues.pop();
|
||||
len = target ? target.length : 0;
|
||||
break;
|
||||
case "charlist":
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
// TODO: Highlight when invalid
|
||||
context.advance(context.filter.length - len);
|
||||
|
||||
context.title = ["Option Value"];
|
||||
let completions = completer(context);
|
||||
if (!completions)
|
||||
return;
|
||||
// Not Vim compatible, but is a significant enough improvement
|
||||
// that it's worth breaking compatibility.
|
||||
if (newValues instanceof Array)
|
||||
{
|
||||
completions = completions.filter(function (val) newValues.indexOf(val[0]) == -1);
|
||||
switch (op)
|
||||
{
|
||||
case "+":
|
||||
completions = completions.filter(function (val) curValues.indexOf(val[0]) == -1);
|
||||
break;
|
||||
case "-":
|
||||
completions = completions.filter(function (val) curValues.indexOf(val[0]) > -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
context.completions = completions;
|
||||
},
|
||||
|
||||
preference: function preference(context)
|
||||
{
|
||||
context.anchored = false;
|
||||
context.title = ["Firefox Preference", "Value"];
|
||||
context.keys = { text: function (item) item, description: function (item) options.getPref(item) };
|
||||
context.completions = services.get("pref").getChildList("", { value: 0 });
|
||||
},
|
||||
|
||||
search: function search(context, noSuggest)
|
||||
{
|
||||
let [, keyword, space, args] = context.filter.match(/^\s*(\S*)(\s*)(.*)$/);
|
||||
let keywords = bookmarks.getKeywords();
|
||||
let engines = bookmarks.getSearchEngines();
|
||||
|
||||
context.title = ["Search Keywords"];
|
||||
context.completions = keywords.concat(engines);
|
||||
context.keys = { text: 0, description: 1, icon: 2 };
|
||||
|
||||
if (!space || noSuggest)
|
||||
return;
|
||||
|
||||
context.fork("suggest", keyword.length + space.length, this, "searchEngineSuggest",
|
||||
keyword, true);
|
||||
|
||||
let item = keywords.filter(function (k) k.keyword == keyword)[0];
|
||||
if (item && item.url.indexOf("%s") > -1)
|
||||
context.fork("keyword/" + keyword, keyword.length + space.length, null, function (context) {
|
||||
context.format = history.format;
|
||||
context.title = [keyword + " Quick Search"];
|
||||
// context.background = true;
|
||||
context.compare = CompletionContext.Sort.unsorted;
|
||||
context.generate = function () {
|
||||
let [begin, end] = item.url.split("%s");
|
||||
|
||||
return history.get({ uri: window.makeURI(begin), uriIsPrefix: true }).map(function (item) {
|
||||
let rest = item.url.length - end.length;
|
||||
let query = item.url.substring(begin.length, rest);
|
||||
if (item.url.substr(rest) == end && query.indexOf("&") == -1)
|
||||
{
|
||||
item.url = decodeURIComponent(query);
|
||||
return item;
|
||||
}
|
||||
}).filter(util.identity);
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
searchEngineSuggest: function searchEngineSuggest(context, engineAliases, kludge)
|
||||
{
|
||||
if (!context.filter)
|
||||
return;
|
||||
|
||||
let engineList = (engineAliases || options["suggestengines"] || "google").split(",");
|
||||
|
||||
let completions = [];
|
||||
engineList.forEach(function (name) {
|
||||
let engine = services.get("browserSearch").getEngineByAlias(name);
|
||||
if (!engine)
|
||||
return;
|
||||
let [,word] = /^\s*(\S+)/.exec(context.filter) || [];
|
||||
if (!kludge && word == name) // FIXME: Check for matching keywords
|
||||
return;
|
||||
let ctxt = context.fork(name, 0);
|
||||
|
||||
ctxt.title = [engine.description + " Suggestions"];
|
||||
ctxt.compare = CompletionContext.Sort.unsorted;
|
||||
ctxt.incomplete = true;
|
||||
bookmarks.getSuggestions(name, ctxt.filter, function (compl) {
|
||||
ctxt.incomplete = false;
|
||||
ctxt.completions = compl;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
shellCommand: function shellCommand(context)
|
||||
{
|
||||
context.title = ["Shell Command", "Path"];
|
||||
context.generate = function ()
|
||||
{
|
||||
let dirNames = services.get("environment").get("PATH").split(RegExp(liberator.has("Win32") ? ";" : ":"));
|
||||
let commands = [];
|
||||
|
||||
for (let [,dirName] in Iterator(dirNames))
|
||||
{
|
||||
let dir = io.getFile(dirName);
|
||||
if (dir.exists() && dir.isDirectory())
|
||||
{
|
||||
commands.push([[file.leafName, dir.path] for ([i, file] in Iterator(io.readDirectory(dir)))
|
||||
if (file.isFile() && file.isExecutable())]);
|
||||
}
|
||||
}
|
||||
|
||||
return util.Array.flatten(commands);
|
||||
}
|
||||
},
|
||||
|
||||
sidebar: function sidebar(context)
|
||||
{
|
||||
let menu = document.getElementById("viewSidebarMenu");
|
||||
context.title = ["Sidebar Panel"];
|
||||
context.completions = Array.map(menu.childNodes, function (n) [n.label, ""]);
|
||||
},
|
||||
|
||||
// filter a list of urls
|
||||
//
|
||||
// may consist of search engines, filenames, bookmarks and history,
|
||||
@@ -1938,36 +1415,11 @@ function Completion() //{{{
|
||||
function (item, text) highlight.call(this, item, text, 1)
|
||||
];
|
||||
});
|
||||
},
|
||||
|
||||
userCommand: function userCommand(context)
|
||||
{
|
||||
context.title = ["User Command", "Definition"];
|
||||
context.keys = { text: "name", description: "replacementText" };
|
||||
context.completions = commands.getUserCommands();
|
||||
},
|
||||
|
||||
userMapping: function userMapping(context, args, modes)
|
||||
{
|
||||
// FIXME: have we decided on a 'standard' way to handle this clash? --djk
|
||||
modes = modes || [modules.modes.NORMAL];
|
||||
|
||||
if (args.completeArg == 0)
|
||||
{
|
||||
let maps = [[m.names[0], ""] for (m in mappings.getUserIterator(modes))];
|
||||
context.completions = maps;
|
||||
}
|
||||
}
|
||||
//}}}
|
||||
};
|
||||
|
||||
const UrlCompleter = new Struct("name", "description", "completer");
|
||||
self.addUrlCompleter("S", "Suggest engines", self.searchEngineSuggest);
|
||||
self.addUrlCompleter("b", "Bookmarks", self.bookmark);
|
||||
self.addUrlCompleter("h", "History", self.history);
|
||||
self.addUrlCompleter("f", "Local files", self.file);
|
||||
self.addUrlCompleter("l", "Firefox location bar entries (bookmarks and history sorted in an intelligent way)", self.location);
|
||||
self.addUrlCompleter("s", "Search engines and keyword URLs", self.search);
|
||||
|
||||
return self;
|
||||
//}}}
|
||||
|
||||
@@ -565,6 +565,23 @@ function Editor() //{{{
|
||||
addAbbreviationCommands("i", "insert");
|
||||
addAbbreviationCommands("c", "command line");
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
liberator.registerObserver("load_completion", function () {
|
||||
// TODO: shouldn't all of these have a standard signature (context, args, ...)? --djk
|
||||
completion.abbreviation = function abbreviation(context, args, mode) {
|
||||
mode = mode || "!";
|
||||
|
||||
if (args.completeArg == 0)
|
||||
{
|
||||
let abbreviations = editor.getAbbreviations(mode);
|
||||
context.completions = [[lhs, ""] for ([, [, lhs,]] in Iterator(abbreviations))];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
@@ -161,13 +161,26 @@ function AutoCommands() //{{{
|
||||
);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
liberator.registerObserver("load_completion", function () {
|
||||
completion.setFunctionCompleter(autocommands.get, [function () config.autocommands]);
|
||||
|
||||
completion.autocmdEvent = function autocmdEvent(context) {
|
||||
context.completions = config.autocommands;
|
||||
};
|
||||
|
||||
completion.macro = function macro(context) {
|
||||
context.title = ["Macro", "Keys"];
|
||||
context.completions = [item for (item in events.getMacros())];
|
||||
};
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
return {
|
||||
|
||||
__iterator__: function () util.Array.itervalues(store),
|
||||
|
||||
@@ -386,7 +386,7 @@ function IO() //{{{
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
liberator.registerObserver("load_completion", function () {
|
||||
@@ -395,8 +395,100 @@ function IO() //{{{
|
||||
context.quote[2] = "";
|
||||
completion.file(context, true);
|
||||
}]);
|
||||
|
||||
completion.charset = function (context) {
|
||||
context.anchored = false;
|
||||
context.generate = function () {
|
||||
let names = util.Array(
|
||||
"more1 more2 more3 more4 more5 unicode".split(" ").map(function (key)
|
||||
options.getPref("intl.charsetmenu.browser." + key).split(', '))
|
||||
).flatten().uniq();
|
||||
let bundle = document.getElementById("liberator-charset-bundle");
|
||||
return names.map(function (name) [name, bundle.getString(name.toLowerCase() + ".title")]);
|
||||
};
|
||||
};
|
||||
|
||||
completion.directory = function directory(context, full) {
|
||||
this.file(context, full);
|
||||
context.filters.push(function ({ item: f }) f.isDirectory());
|
||||
};
|
||||
|
||||
completion.environment = function environment(context) {
|
||||
let command = liberator.has("Win32") ? "set" : "env";
|
||||
let lines = io.system(command).split("\n");
|
||||
lines.pop();
|
||||
|
||||
context.title = ["Environment Variable", "Value"];
|
||||
context.generate = function () lines.map(function (line) (line.match(/([^=]+)=(.+)/) || []).slice(1));
|
||||
};
|
||||
|
||||
// TODO: support file:// and \ or / path separators on both platforms
|
||||
// if "tail" is true, only return names without any directory components
|
||||
completion.file = function file(context, full) {
|
||||
// dir == "" is expanded inside readDirectory to the current dir
|
||||
let [dir] = context.filter.match(/^(?:.*[\/\\])?/);
|
||||
|
||||
if (!full)
|
||||
context.advance(dir.length);
|
||||
|
||||
context.title = [full ? "Path" : "Filename", "Type"];
|
||||
context.keys = {
|
||||
text: !full ? "leafName" : function (f) dir + f.leafName,
|
||||
description: function (f) f.isDirectory() ? "Directory" : "File",
|
||||
isdir: function (f) f.isDirectory(),
|
||||
icon: function (f) f.isDirectory() ? "resource://gre/res/html/folder.png"
|
||||
: "moz-icon://" + f.leafName
|
||||
};
|
||||
context.compare = function (a, b)
|
||||
b.isdir - a.isdir || String.localeCompare(a.text, b.text);
|
||||
|
||||
if (options["wildignore"])
|
||||
{
|
||||
let wigRegexp = RegExp("(^" + options.get("wildignore").values.join("|") + ")$");
|
||||
context.filters.push(function ({item: f}) f.isDirectory() || !wigRegexp.test(f.leafName));
|
||||
}
|
||||
|
||||
// context.background = true;
|
||||
context.key = dir;
|
||||
context.generate = function generate_file()
|
||||
{
|
||||
try
|
||||
{
|
||||
return io.readDirectory(dir);
|
||||
}
|
||||
catch (e) {}
|
||||
};
|
||||
};
|
||||
|
||||
completion.shellCommand = function shellCommand(context) {
|
||||
context.title = ["Shell Command", "Path"];
|
||||
context.generate = function ()
|
||||
{
|
||||
let dirNames = services.get("environment").get("PATH").split(RegExp(liberator.has("Win32") ? ";" : ":"));
|
||||
let commands = [];
|
||||
|
||||
for (let [,dirName] in Iterator(dirNames))
|
||||
{
|
||||
let dir = io.getFile(dirName);
|
||||
if (dir.exists() && dir.isDirectory())
|
||||
{
|
||||
commands.push([[file.leafName, dir.path] for ([i, file] in Iterator(io.readDirectory(dir)))
|
||||
if (file.isFile() && file.isExecutable())]);
|
||||
}
|
||||
}
|
||||
|
||||
return util.Array.flatten(commands);
|
||||
}
|
||||
};
|
||||
|
||||
completion.addUrlCompleter("f", "Local files", completion.file);
|
||||
});
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
const self = {
|
||||
|
||||
/**
|
||||
|
||||
@@ -87,6 +87,72 @@ const liberator = (function () //{{{
|
||||
}
|
||||
}
|
||||
|
||||
// initially hide all GUI, it is later restored unless the user has :set go= or something
|
||||
// similar in his config
|
||||
function hideGUI()
|
||||
{
|
||||
let guioptions = config.guioptions;
|
||||
for (let option in guioptions)
|
||||
{
|
||||
guioptions[option].forEach(function (elem) {
|
||||
try
|
||||
{
|
||||
document.getElementById(elem).collapsed = true;
|
||||
}
|
||||
catch (e) {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// return the platform normalized to Vim values
|
||||
function getPlatformFeature()
|
||||
{
|
||||
let platform = navigator.platform;
|
||||
|
||||
return /^Mac/.test(platform) ? "MacUnix" : platform == "Win32" ? "Win32" : "Unix";
|
||||
}
|
||||
|
||||
// TODO: move this
|
||||
function getMenuItems()
|
||||
{
|
||||
function addChildren(node, parent)
|
||||
{
|
||||
for (let [,item] in Iterator(node.childNodes))
|
||||
{
|
||||
if (item.childNodes.length == 0 && item.localName == "menuitem"
|
||||
&& !/rdf:http:/.test(item.getAttribute("label"))) // FIXME
|
||||
{
|
||||
item.fullMenuPath = parent + item.getAttribute("label");
|
||||
items.push(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
let path = parent;
|
||||
if (item.localName == "menu")
|
||||
path += item.getAttribute("label") + ".";
|
||||
addChildren(item, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let items = [];
|
||||
addChildren(document.getElementById(config.guioptions["m"][1]), "");
|
||||
return items;
|
||||
}
|
||||
|
||||
// show a usage index either in the MOW or as a full help page
|
||||
function showHelpIndex(tag, items, inMow)
|
||||
{
|
||||
if (inMow)
|
||||
liberator.echo(template.usage(items), commandline.FORCE_MULTILINE);
|
||||
else
|
||||
liberator.help(tag);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// OPTIONS /////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
// Only general options are added here, which are valid for all Vimperator like extensions
|
||||
registerObserver("load_options", function () {
|
||||
|
||||
@@ -191,6 +257,10 @@ const liberator = (function () //{{{
|
||||
});
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// MAPPINGS ////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
registerObserver("load_mappings", function () {
|
||||
|
||||
mappings.add(modes.all, ["<F1>"],
|
||||
@@ -209,33 +279,9 @@ const liberator = (function () //{{{
|
||||
function () { liberator.quit(true); });
|
||||
});
|
||||
|
||||
// TODO: move this
|
||||
function getMenuItems()
|
||||
{
|
||||
function addChildren(node, parent)
|
||||
{
|
||||
for (let [,item] in Iterator(node.childNodes))
|
||||
{
|
||||
if (item.childNodes.length == 0 && item.localName == "menuitem"
|
||||
&& !/rdf:http:/.test(item.getAttribute("label"))) // FIXME
|
||||
{
|
||||
item.fullMenuPath = parent + item.getAttribute("label");
|
||||
items.push(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
let path = parent;
|
||||
if (item.localName == "menu")
|
||||
path += item.getAttribute("label") + ".";
|
||||
addChildren(item, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let items = [];
|
||||
addChildren(document.getElementById(config.guioptions["m"][1]), "");
|
||||
return items;
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMMANDS ////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
registerObserver("load_commands", function () {
|
||||
|
||||
@@ -544,39 +590,40 @@ const liberator = (function () //{{{
|
||||
});
|
||||
});
|
||||
|
||||
// initially hide all GUI, it is later restored unless the user has :set go= or something
|
||||
// similar in his config
|
||||
function hideGUI()
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
registerObserver("load_completion", function () {
|
||||
completion.dialog = function dialog(context) {
|
||||
context.title = ["Dialog"];
|
||||
context.completions = config.dialogs;
|
||||
};
|
||||
|
||||
completion.help = function help(context) {
|
||||
context.title = ["Help"];
|
||||
context.anchored = false;
|
||||
context.generate = function ()
|
||||
{
|
||||
let guioptions = config.guioptions;
|
||||
for (let option in guioptions)
|
||||
{
|
||||
guioptions[option].forEach(function (elem) {
|
||||
try
|
||||
{
|
||||
document.getElementById(elem).collapsed = true;
|
||||
}
|
||||
catch (e) {}
|
||||
let res = config.helpFiles.map(function (file) {
|
||||
let resp = util.httpGet("chrome://liberator/locale/" + file);
|
||||
if (!resp)
|
||||
return [];
|
||||
let doc = resp.responseXML;
|
||||
return Array.map(doc.getElementsByClassName("tag"),
|
||||
function (elem) [elem.textContent, file]);
|
||||
});
|
||||
return util.Array.flatten(res);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// return the platform normalized to Vim values
|
||||
function getPlatformFeature()
|
||||
{
|
||||
let platform = navigator.platform;
|
||||
|
||||
return /^Mac/.test(platform) ? "MacUnix" : platform == "Win32" ? "Win32" : "Unix";
|
||||
}
|
||||
|
||||
// show a usage index either in the MOW or as a full help page
|
||||
function showHelpIndex(tag, items, inMow)
|
||||
{
|
||||
if (inMow)
|
||||
liberator.echo(template.usage(items), commandline.FORCE_MULTILINE);
|
||||
else
|
||||
liberator.help(tag);
|
||||
}
|
||||
completion.menuItem = function menuItem(context) {
|
||||
context.title = ["Menu Path", "Label"];
|
||||
context.anchored = false;
|
||||
context.keys = { text: "fullMenuPath", description: function (item) item.getAttribute("label") };
|
||||
context.completions = liberator.menuItems;
|
||||
};
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
|
||||
@@ -297,6 +297,23 @@ function Mappings() //{{{
|
||||
[m.mask for (m in modes.mainModes) if (m.char == mode.char)],
|
||||
[mode.disp.toLowerCase()]);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
liberator.registerObserver("load_completion", function () {
|
||||
completion.userMapping = function userMapping(context, args, modes) {
|
||||
// FIXME: have we decided on a 'standard' way to handle this clash? --djk
|
||||
modes = modes || [modules.modes.NORMAL];
|
||||
|
||||
if (args.completeArg == 0)
|
||||
{
|
||||
let maps = [[m.names[0], ""] for (m in mappings.getUserIterator(modes))];
|
||||
context.completions = maps;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
@@ -913,18 +913,85 @@ function Options() //{{{
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
// TODO: Does this belong elsewhere?
|
||||
liberator.registerObserver("load_completion", function () {
|
||||
completion.setFunctionCompleter(options.get, [function () ([o.name, o.description] for (o in options))]);
|
||||
completion.setFunctionCompleter([options.getPref, options.safeSetPref, options.setPref, options.resetPref, options.invertPref],
|
||||
[function () services.get("pref")
|
||||
.getChildList("", { value: 0 })
|
||||
.map(function (pref) [pref, ""])]);
|
||||
|
||||
completion.option = function option(context, scope) {
|
||||
context.title = ["Option"];
|
||||
context.keys = { text: "names", description: "description" };
|
||||
context.completions = options;
|
||||
if (scope)
|
||||
context.filters.push(function ({ item: opt }) opt.scope & scope);
|
||||
};
|
||||
|
||||
completion.optionValue = function (context, name, op, curValue) {
|
||||
let opt = options.get(name);
|
||||
let completer = opt.completer;
|
||||
if (!completer)
|
||||
return;
|
||||
|
||||
let curValues = curValue != null ? opt.parseValues(curValue) : opt.values;
|
||||
let newValues = opt.parseValues(context.filter);
|
||||
|
||||
let len = context.filter.length;
|
||||
switch (opt.type)
|
||||
{
|
||||
case "boolean":
|
||||
if (!completer)
|
||||
completer = function () [["true", ""], ["false", ""]];
|
||||
break;
|
||||
case "stringlist":
|
||||
let target = newValues.pop();
|
||||
len = target ? target.length : 0;
|
||||
break;
|
||||
case "charlist":
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
// TODO: Highlight when invalid
|
||||
context.advance(context.filter.length - len);
|
||||
|
||||
context.title = ["Option Value"];
|
||||
let completions = completer(context);
|
||||
if (!completions)
|
||||
return;
|
||||
// Not Vim compatible, but is a significant enough improvement
|
||||
// that it's worth breaking compatibility.
|
||||
if (newValues instanceof Array)
|
||||
{
|
||||
completions = completions.filter(function (val) newValues.indexOf(val[0]) == -1);
|
||||
switch (op)
|
||||
{
|
||||
case "+":
|
||||
completions = completions.filter(function (val) curValues.indexOf(val[0]) == -1);
|
||||
break;
|
||||
case "-":
|
||||
completions = completions.filter(function (val) curValues.indexOf(val[0]) > -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
context.completions = completions;
|
||||
};
|
||||
|
||||
completion.preference = function preference(context) {
|
||||
context.anchored = false;
|
||||
context.title = ["Firefox Preference", "Value"];
|
||||
context.keys = { text: function (item) item, description: function (item) options.getPref(item) };
|
||||
context.completions = services.get("pref").getChildList("", { value: 0 });
|
||||
};
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
const self = {
|
||||
|
||||
/**
|
||||
|
||||
@@ -534,16 +534,9 @@ if (highlight.CSS != Highlights.prototype.CSS)
|
||||
liberator.triggerObserver("load_styles", "styles");
|
||||
liberator.triggerObserver("load_highlight", "highlight");
|
||||
|
||||
liberator.registerObserver("load_completion", function () {
|
||||
completion.setFunctionCompleter(["get", "addSheet", "removeSheet", "findSheets"].map(function (m) styles[m]),
|
||||
[ // Prototype: (system, name, filter, css, index)
|
||||
null,
|
||||
function (context, obj, args) args[0] ? styles.systemNames : styles.userNames,
|
||||
function (context, obj, args) styles.completeSite(context, content),
|
||||
null,
|
||||
function (context, obj, args) args[0] ? styles.systemSheets : styles.userSheets
|
||||
]);
|
||||
});
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMMANDS ////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
liberator.registerObserver("load_commands", function () {
|
||||
|
||||
@@ -711,5 +704,40 @@ liberator.registerObserver("load_commands", function () {
|
||||
]
|
||||
});
|
||||
});
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
liberator.registerObserver("load_completion", function () {
|
||||
completion.setFunctionCompleter(["get", "addSheet", "removeSheet", "findSheets"].map(function (m) styles[m]),
|
||||
[ // Prototype: (system, name, filter, css, index)
|
||||
null,
|
||||
function (context, obj, args) args[0] ? styles.systemNames : styles.userNames,
|
||||
function (context, obj, args) styles.completeSite(context, content),
|
||||
null,
|
||||
function (context, obj, args) args[0] ? styles.systemSheets : styles.userSheets
|
||||
]);
|
||||
|
||||
completion.colorScheme = function colorScheme(context) {
|
||||
let colors = [];
|
||||
|
||||
io.getRuntimeDirectories("colors").forEach(function (dir) {
|
||||
io.readDirectory(dir).forEach(function (file) {
|
||||
if (/\.vimp$/.test(file.leafName) && !colors.some(function (c) c.leafName == file.leafName))
|
||||
colors.push(file);
|
||||
});
|
||||
});
|
||||
|
||||
context.title = ["Color Scheme", "Runtime Path"];
|
||||
context.completions = [[c.leafName.replace(/\.vimp$/, ""), c.parent.path] for ([,c] in Iterator(colors))]
|
||||
};
|
||||
|
||||
// FIXME: extract from :highlight
|
||||
completion.highlightGroup = function highlightGroup(context, args) {
|
||||
return commands.get("highlight").completer(context, args);
|
||||
};
|
||||
|
||||
});
|
||||
//}}}
|
||||
|
||||
// vim: set fdm=marker sw=4 ts=4 et:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
/** @scope modules */
|
||||
|
||||
const template = {
|
||||
const template = { //{{{
|
||||
add: function add(a, b) a + b,
|
||||
join: function join(c) function (a, b) a + c + b,
|
||||
|
||||
@@ -332,6 +332,6 @@ const template = {
|
||||
</table>);
|
||||
// </e4x>
|
||||
}
|
||||
};
|
||||
}; //}}}
|
||||
|
||||
// vim: set fdm=marker sw=4 ts=4 et:
|
||||
|
||||
@@ -505,6 +505,50 @@ const config = { //{{{
|
||||
"Set the separator regexp used to separate multiple URL args",
|
||||
"string", ",\\s");
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
completion.location = function location(context) {
|
||||
if (!services.get("autoCompleteSearch"))
|
||||
return;
|
||||
|
||||
context.anchored = false;
|
||||
context.title = ["Smart Completions"];
|
||||
context.keys.icon = 2;
|
||||
context.incomplete = true;
|
||||
context.hasItems = context.completions.length > 0; // XXX
|
||||
context.filterFunc = null;
|
||||
context.cancel = function () services.get("autoCompleteSearch").stopSearch();
|
||||
context.compare = CompletionContext.Sort.unsorted;
|
||||
let timer = new Timer(50, 100, function (result) {
|
||||
context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
|
||||
context.completions = [
|
||||
[result.getValueAt(i), result.getCommentAt(i), result.getImageAt(i)]
|
||||
for (i in util.range(0, result.matchCount))
|
||||
];
|
||||
});
|
||||
services.get("autoCompleteSearch").stopSearch();
|
||||
services.get("autoCompleteSearch").startSearch(context.filter, "", context.result, {
|
||||
onSearchResult: function onSearchResult(search, result) {
|
||||
context.result = result;
|
||||
timer.tell(result);
|
||||
if (result.searchResult <= result.RESULT_SUCCESS)
|
||||
timer.flush();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
completion.sidebar = function sidebar(context) {
|
||||
let menu = document.getElementById("viewSidebarMenu");
|
||||
context.title = ["Sidebar Panel"];
|
||||
context.completions = Array.map(menu.childNodes, function (n) [n.label, ""]);
|
||||
};
|
||||
|
||||
completion.addUrlCompleter("l",
|
||||
"Firefox location bar entries (bookmarks and history sorted in an intelligent way)",
|
||||
completion.location);
|
||||
|
||||
//}}}
|
||||
}
|
||||
}; //}}}
|
||||
|
||||
@@ -406,6 +406,45 @@ function Player() // {{{
|
||||
},
|
||||
{ argCount: "1" });
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
completion.song = function song(context, args) {
|
||||
// TODO: useful descriptions?
|
||||
function map(list) list.map(function (i) [i, ""]);
|
||||
let [artist, album] = [args[0], args[1]];
|
||||
|
||||
if (args.completeArg == 0)
|
||||
{
|
||||
context.title = ["Artists"];
|
||||
context.completions = map(library.getArtists());
|
||||
}
|
||||
else if (args.completeArg == 1)
|
||||
{
|
||||
context.title = ["Albums by " + artist];
|
||||
context.completions = map(library.getAlbums(artist));
|
||||
}
|
||||
else if (args.completeArg == 2)
|
||||
{
|
||||
context.title = ["Tracks from " + album + " by " + artist];
|
||||
context.completions = map(library.getTracks(artist, album));
|
||||
}
|
||||
};
|
||||
|
||||
completion.playlist = function playlist(context, args) {
|
||||
context.title = ["Playlist", "Type"];
|
||||
context.keys = { text: "name", description: "type" };
|
||||
context.completions = player.getPlaylists();
|
||||
};
|
||||
|
||||
completion.mediaView = function mediaView(context) {
|
||||
context.title = ["Media View", "URL"];
|
||||
context.anchored = false;
|
||||
context.keys = { text: "contentTitle", description: "contentUrl" };
|
||||
context.completions = player.getMediaPages();
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////}}}
|
||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////{{{
|
||||
|
||||
Reference in New Issue
Block a user