mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-20 07:07:59 +01:00
Move the standard type completers to appropriate modules.
This commit is contained in:
@@ -399,6 +399,93 @@ function Bookmarks() //{{{
|
|||||||
literal: 0
|
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 //////////////////////////////////////////
|
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
@@ -840,6 +927,23 @@ function History() //{{{
|
|||||||
options: [[["-max", "-m"], options.OPTION_INT]]
|
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 //////////////////////////////////////////
|
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
|
|||||||
@@ -673,6 +673,61 @@ function Buffer() //{{{
|
|||||||
bang: true
|
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 ///////////////////////////////////////////////
|
////////////////////// PAGE INFO ///////////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
@@ -1769,6 +1824,19 @@ function Marks() //{{{
|
|||||||
marks.list(filter);
|
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 //////////////////////////////////////////
|
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
|
|||||||
@@ -392,10 +392,6 @@ function Commands() //{{{
|
|||||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
|
|
||||||
liberator.registerObserver("load_completion", function () {
|
|
||||||
completion.setFunctionCompleter(commands.get, [function () ([c.name, c.description] for (c in commands))]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const self = {
|
const self = {
|
||||||
|
|
||||||
// FIXME: remove later, when our option handler is better
|
// FIXME: remove later, when our option handler is better
|
||||||
@@ -1156,6 +1152,77 @@ function Commands() //{{{
|
|||||||
completer: function (context) completion.userCommand(context)
|
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;
|
return self;
|
||||||
|
|||||||
@@ -1340,533 +1340,10 @@ function Completion() //{{{
|
|||||||
////////////////////// COMPLETION TYPES ////////////////////////////////////////
|
////////////////////// 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,
|
get javascriptCompleter() javascript,
|
||||||
|
|
||||||
javascript: function _javascript(context) javascript.complete(context),
|
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
|
// filter a list of urls
|
||||||
//
|
//
|
||||||
// may consist of search engines, filenames, bookmarks and history,
|
// may consist of search engines, filenames, bookmarks and history,
|
||||||
@@ -1938,36 +1415,11 @@ function Completion() //{{{
|
|||||||
function (item, text) highlight.call(this, item, text, 1)
|
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");
|
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;
|
return self;
|
||||||
//}}}
|
//}}}
|
||||||
|
|||||||
@@ -565,6 +565,23 @@ function Editor() //{{{
|
|||||||
addAbbreviationCommands("i", "insert");
|
addAbbreviationCommands("i", "insert");
|
||||||
addAbbreviationCommands("c", "command line");
|
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 //////////////////////////////////////////
|
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
|
|||||||
@@ -161,13 +161,26 @@ function AutoCommands() //{{{
|
|||||||
);
|
);
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////}}}
|
/////////////////////////////////////////////////////////////////////////////}}}
|
||||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
|
|
||||||
liberator.registerObserver("load_completion", function () {
|
liberator.registerObserver("load_completion", function () {
|
||||||
completion.setFunctionCompleter(autocommands.get, [function () config.autocommands]);
|
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 {
|
return {
|
||||||
|
|
||||||
__iterator__: function () util.Array.itervalues(store),
|
__iterator__: function () util.Array.itervalues(store),
|
||||||
|
|||||||
@@ -386,7 +386,7 @@ function IO() //{{{
|
|||||||
});
|
});
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////}}}
|
/////////////////////////////////////////////////////////////////////////////}}}
|
||||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
|
|
||||||
liberator.registerObserver("load_completion", function () {
|
liberator.registerObserver("load_completion", function () {
|
||||||
@@ -395,8 +395,100 @@ function IO() //{{{
|
|||||||
context.quote[2] = "";
|
context.quote[2] = "";
|
||||||
completion.file(context, true);
|
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 = {
|
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
|
// Only general options are added here, which are valid for all Vimperator like extensions
|
||||||
registerObserver("load_options", function () {
|
registerObserver("load_options", function () {
|
||||||
|
|
||||||
@@ -191,6 +257,10 @@ const liberator = (function () //{{{
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////}}}
|
||||||
|
////////////////////// MAPPINGS ////////////////////////////////////////////////
|
||||||
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
|
|
||||||
registerObserver("load_mappings", function () {
|
registerObserver("load_mappings", function () {
|
||||||
|
|
||||||
mappings.add(modes.all, ["<F1>"],
|
mappings.add(modes.all, ["<F1>"],
|
||||||
@@ -209,33 +279,9 @@ const liberator = (function () //{{{
|
|||||||
function () { liberator.quit(true); });
|
function () { liberator.quit(true); });
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: move this
|
/////////////////////////////////////////////////////////////////////////////}}}
|
||||||
function getMenuItems()
|
////////////////////// COMMANDS ////////////////////////////////////////////////
|
||||||
{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
registerObserver("load_commands", function () {
|
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
|
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||||
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
|
registerObserver("load_completion", function () {
|
||||||
function getPlatformFeature()
|
completion.dialog = function dialog(context) {
|
||||||
{
|
context.title = ["Dialog"];
|
||||||
let platform = navigator.platform;
|
context.completions = config.dialogs;
|
||||||
|
};
|
||||||
|
|
||||||
return /^Mac/.test(platform) ? "MacUnix" : platform == "Win32" ? "Win32" : "Unix";
|
completion.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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// show a usage index either in the MOW or as a full help page
|
completion.menuItem = function menuItem(context) {
|
||||||
function showHelpIndex(tag, items, inMow)
|
context.title = ["Menu Path", "Label"];
|
||||||
{
|
context.anchored = false;
|
||||||
if (inMow)
|
context.keys = { text: "fullMenuPath", description: function (item) item.getAttribute("label") };
|
||||||
liberator.echo(template.usage(items), commandline.FORCE_MULTILINE);
|
context.completions = liberator.menuItems;
|
||||||
else
|
};
|
||||||
liberator.help(tag);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////}}}
|
/////////////////////////////////////////////////////////////////////////////}}}
|
||||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||||
|
|||||||
@@ -297,6 +297,23 @@ function Mappings() //{{{
|
|||||||
[m.mask for (m in modes.mainModes) if (m.char == mode.char)],
|
[m.mask for (m in modes.mainModes) if (m.char == mode.char)],
|
||||||
[mode.disp.toLowerCase()]);
|
[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 //////////////////////////////////////////
|
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
|
|||||||
@@ -913,18 +913,85 @@ function Options() //{{{
|
|||||||
});
|
});
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////}}}
|
/////////////////////////////////////////////////////////////////////////////}}}
|
||||||
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
////////////////////// COMPLETIONS /////////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
|
|
||||||
// TODO: Does this belong elsewhere?
|
|
||||||
liberator.registerObserver("load_completion", function () {
|
liberator.registerObserver("load_completion", function () {
|
||||||
completion.setFunctionCompleter(options.get, [function () ([o.name, o.description] for (o in options))]);
|
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],
|
completion.setFunctionCompleter([options.getPref, options.safeSetPref, options.setPref, options.resetPref, options.invertPref],
|
||||||
[function () services.get("pref")
|
[function () services.get("pref")
|
||||||
.getChildList("", { value: 0 })
|
.getChildList("", { value: 0 })
|
||||||
.map(function (pref) [pref, ""])]);
|
.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 = {
|
const self = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -534,16 +534,9 @@ if (highlight.CSS != Highlights.prototype.CSS)
|
|||||||
liberator.triggerObserver("load_styles", "styles");
|
liberator.triggerObserver("load_styles", "styles");
|
||||||
liberator.triggerObserver("load_highlight", "highlight");
|
liberator.triggerObserver("load_highlight", "highlight");
|
||||||
|
|
||||||
liberator.registerObserver("load_completion", function () {
|
/////////////////////////////////////////////////////////////////////////////}}}
|
||||||
completion.setFunctionCompleter(["get", "addSheet", "removeSheet", "findSheets"].map(function (m) styles[m]),
|
////////////////////// COMMANDS ////////////////////////////////////////////////
|
||||||
[ // 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
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
liberator.registerObserver("load_commands", function () {
|
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:
|
// vim: set fdm=marker sw=4 ts=4 et:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
const template = {
|
const template = { //{{{
|
||||||
add: function add(a, b) a + b,
|
add: function add(a, b) a + b,
|
||||||
join: function join(c) function (a, b) a + c + b,
|
join: function join(c) function (a, b) a + c + b,
|
||||||
|
|
||||||
@@ -332,6 +332,6 @@ const template = {
|
|||||||
</table>);
|
</table>);
|
||||||
// </e4x>
|
// </e4x>
|
||||||
}
|
}
|
||||||
};
|
}; //}}}
|
||||||
|
|
||||||
// vim: set fdm=marker sw=4 ts=4 et:
|
// 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",
|
"Set the separator regexp used to separate multiple URL args",
|
||||||
"string", ",\\s");
|
"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" });
|
{ 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 //////////////////////////////////////////
|
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
|
|||||||
Reference in New Issue
Block a user