mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-23 10:37:59 +01:00
Add search keyword-history completion (try typing a keyword), better JS completion, better errors in :so, check "preload" before preloading history/bookmarks, Object/Function highlighting, some other bug fixes.
This commit is contained in:
@@ -193,6 +193,11 @@ liberator.Bookmarks = function () //{{{
|
|||||||
liberator.storage.removeObserver("bookmark-cache", bookmarkObserver)
|
liberator.storage.removeObserver("bookmark-cache", bookmarkObserver)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
liberator.registerObserver("enter", function () {
|
||||||
|
if (liberator.options["preload"])
|
||||||
|
cache.bookmarks; // Forces a load, if not already loaded.
|
||||||
|
});
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////}}}
|
/////////////////////////////////////////////////////////////////////////////}}}
|
||||||
////////////////////// OPTIONS /////////////////////////////////////////////////
|
////////////////////// OPTIONS /////////////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
@@ -533,12 +538,9 @@ liberator.History = function () //{{{
|
|||||||
return faviconService.getFaviconImageForPage(ioService.newURI(uri, null, null)).spec;
|
return faviconService.getFaviconImageForPage(ioService.newURI(uri, null, null)).spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
var history = [];
|
var history;
|
||||||
var cachedHistory = []; // add pages here after loading the initial Places history
|
var cachedHistory = []; // add pages here after loading the initial Places history
|
||||||
|
|
||||||
if (liberator.options["preload"])
|
|
||||||
setTimeout(function () { load(); }, 100);
|
|
||||||
|
|
||||||
function load()
|
function load()
|
||||||
{
|
{
|
||||||
history = [];
|
history = [];
|
||||||
@@ -556,7 +558,7 @@ liberator.History = function () //{{{
|
|||||||
for (let i = 0; i < rootNode.childCount; i++)
|
for (let i = 0; i < rootNode.childCount; i++)
|
||||||
{
|
{
|
||||||
var node = rootNode.getChild(i);
|
var node = rootNode.getChild(i);
|
||||||
//liberator.dump("History child " + node.itemId + ": " + node.title + " - " + node.type + "\n");
|
// liberator.dump("History child " + node.itemId + ": " + node.title + " - " + node.type);
|
||||||
if (node.type == node.RESULT_TYPE_URI) // just make sure it's a bookmark
|
if (node.type == node.RESULT_TYPE_URI) // just make sure it's a bookmark
|
||||||
history.push([node.uri, node.title || "[No title]", getIcon(node.uri)]);
|
history.push([node.uri, node.title || "[No title]", getIcon(node.uri)]);
|
||||||
}
|
}
|
||||||
@@ -565,6 +567,11 @@ liberator.History = function () //{{{
|
|||||||
rootNode.containerOpen = false;
|
rootNode.containerOpen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
liberator.registerObserver("enter", function () {
|
||||||
|
if (liberator.options["preload"])
|
||||||
|
load();
|
||||||
|
});
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////}}}
|
/////////////////////////////////////////////////////////////////////////////}}}
|
||||||
////////////////////// MAPPINGS ////////////////////////////////////////////////
|
////////////////////// MAPPINGS ////////////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
@@ -710,6 +717,8 @@ liberator.History = function () //{{{
|
|||||||
if (!history)
|
if (!history)
|
||||||
load();
|
load();
|
||||||
|
|
||||||
|
if (!filter)
|
||||||
|
return cachedHistory.concat(history);
|
||||||
return liberator.completion.cached("history", filter, function() cachedHistory.concat(history),
|
return liberator.completion.cached("history", filter, function() cachedHistory.concat(history),
|
||||||
"filterURLArray");
|
"filterURLArray");
|
||||||
},
|
},
|
||||||
@@ -721,14 +730,17 @@ liberator.History = function () //{{{
|
|||||||
if (!history)
|
if (!history)
|
||||||
load();
|
load();
|
||||||
|
|
||||||
// don' let cachedHistory grow too large
|
let filter = function (h) h[0] != url;
|
||||||
|
// don't let cachedHistory grow too large
|
||||||
if (cachedHistory.length > 1000)
|
if (cachedHistory.length > 1000)
|
||||||
{
|
{
|
||||||
history = cachedHistory.concat(history);
|
history = cachedHistory.concat(history);
|
||||||
cachedHistory = [];
|
cachedHistory = [];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cachedHistory = cachedHistory.filter(function (elem) elem[0] != url);
|
cachedHistory = cachedHistory.filter(filter);
|
||||||
|
if (history.some(function (h) h[0] == url))
|
||||||
|
history = history.filter(filter);
|
||||||
|
|
||||||
cachedHistory.unshift([url, title || "[No title]", getIcon(url)]);
|
cachedHistory.unshift([url, title || "[No title]", getIcon(url)]);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ liberator.Buffer = function () //{{{
|
|||||||
/////////////////////////////////////////////////////////////////////////////{{{
|
/////////////////////////////////////////////////////////////////////////////{{{
|
||||||
|
|
||||||
const highlightClasses = ["Boolean", "ErrorMsg", "Filter", "Function", "InfoMsg", "Keyword",
|
const highlightClasses = ["Boolean", "ErrorMsg", "Filter", "Function", "InfoMsg", "Keyword",
|
||||||
"LineNr", "ModeMsg", "MoreMsg", "Normal", "Null", "Number", "Question",
|
"LineNr", "ModeMsg", "MoreMsg", "Normal", "Null", "Number", "Object", "Question",
|
||||||
"StatusLine", "StatusLineBroken", "StatusLineSecure", "String", "Tag",
|
"StatusLine", "StatusLineBroken", "StatusLineSecure", "String", "Tag",
|
||||||
"Title", "URL", "WarningMsg",
|
"Title", "URL", "WarningMsg",
|
||||||
["Hint", ".liberator-hint", "*"],
|
["Hint", ".liberator-hint", "*"],
|
||||||
@@ -84,18 +84,18 @@ liberator.Buffer = function () //{{{
|
|||||||
{
|
{
|
||||||
let sheets = system ? systemSheets : userSheets;
|
let sheets = system ? systemSheets : userSheets;
|
||||||
|
|
||||||
if (!force)
|
|
||||||
{
|
|
||||||
let errors = checkSyntax(css);
|
|
||||||
if (errors.length)
|
|
||||||
return errors.map(function (e) "CSS: " + filter + ": " + e).join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sheets.some(function (s) s[0] == filter && s[1] == css))
|
if (sheets.some(function (s) s[0] == filter && s[1] == css))
|
||||||
return null;
|
return null;
|
||||||
filter = filter.split(",");
|
filter = filter.split(",");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.registerSheet(cssUri(wrapCSS(filter, css)), !force);
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
return e.echoerr || e;
|
||||||
|
}
|
||||||
sheets.push([filter, css]);
|
sheets.push([filter, css]);
|
||||||
this.registerSheet(cssUri(wrapCSS(filter, css)));
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,8 +136,10 @@ liberator.Buffer = function () //{{{
|
|||||||
return matches.length;
|
return matches.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.registerSheet = function (uri)
|
this.registerSheet = function (uri, doCheckSyntax)
|
||||||
{
|
{
|
||||||
|
if (doCheckSyntax)
|
||||||
|
checkSyntax(uri);
|
||||||
uri = ios.newURI(uri, null, null);
|
uri = ios.newURI(uri, null, null);
|
||||||
if (!sss.sheetRegistered(uri, sss.USER_SHEET))
|
if (!sss.sheetRegistered(uri, sss.USER_SHEET))
|
||||||
sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
|
sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
|
||||||
@@ -166,9 +168,8 @@ liberator.Buffer = function () //{{{
|
|||||||
let queryinterface = XPCOMUtils.generateQI([Components.interfaces.nsIConsoleListener]);
|
let queryinterface = XPCOMUtils.generateQI([Components.interfaces.nsIConsoleListener]);
|
||||||
/* What happens if more than one thread tries to use this? */
|
/* What happens if more than one thread tries to use this? */
|
||||||
let testDoc = document.implementation.createDocument(XHTML, "doc", null);
|
let testDoc = document.implementation.createDocument(XHTML, "doc", null);
|
||||||
function checkSyntax(css)
|
function checkSyntax(uri)
|
||||||
{
|
{
|
||||||
let uri = cssUri(namespace + css);
|
|
||||||
let errors = [];
|
let errors = [];
|
||||||
let listener = {
|
let listener = {
|
||||||
QueryInterface: queryinterface,
|
QueryInterface: queryinterface,
|
||||||
@@ -178,7 +179,7 @@ liberator.Buffer = function () //{{{
|
|||||||
{
|
{
|
||||||
message = message.QueryInterface(Components.interfaces.nsIScriptError);
|
message = message.QueryInterface(Components.interfaces.nsIScriptError);
|
||||||
if (message.sourceName == uri)
|
if (message.sourceName == uri)
|
||||||
errors.push(message.errorMessage);
|
errors.push(message);
|
||||||
}
|
}
|
||||||
catch (e) {}
|
catch (e) {}
|
||||||
}
|
}
|
||||||
@@ -212,7 +213,14 @@ liberator.Buffer = function () //{{{
|
|||||||
{
|
{
|
||||||
consoleService.unregisterListener(listener);
|
consoleService.unregisterListener(listener);
|
||||||
}
|
}
|
||||||
return errors;
|
if (errors.length)
|
||||||
|
{
|
||||||
|
let err = new Error("", errors[0].sourceName.replace(/^(data:text\/css,).*/, "$1..."), errors[0].lineNumber);
|
||||||
|
err.name = "CSSError"
|
||||||
|
err.message = errors.reduce(function (msg, e) msg + "; " + e.lineNumber + ": " + e.errorMessage, errors.shift().errorMessage);
|
||||||
|
err.echoerr = err.fileName + ":" + err.lineNumber + ": " + err.message;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Styles.prototype = {
|
Styles.prototype = {
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ liberator.Completion = function () //{{{
|
|||||||
catch (e) {}
|
catch (e) {}
|
||||||
|
|
||||||
// the completion substrings, used for showing the longest common match
|
// the completion substrings, used for showing the longest common match
|
||||||
var cacheFilter = {};
|
var cacheFilter = {}
|
||||||
var cacheResults = {};
|
var cacheResults = {}
|
||||||
var substrings = [];
|
var substrings = [];
|
||||||
var historyCache = [];
|
var historyCache = [];
|
||||||
var historyResult = null;
|
var historyResult = null;
|
||||||
@@ -84,13 +84,14 @@ liberator.Completion = function () //{{{
|
|||||||
{
|
{
|
||||||
for (let k in obj)
|
for (let k in obj)
|
||||||
{
|
{
|
||||||
|
// Some object members are only accessible as function calls
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
yield [k, obj[k]];
|
yield [k, obj[k]];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
catch (e) {}
|
catch (e) {}
|
||||||
yield [k, "inaccessable"]
|
yield [k, <>inaccessable</>]
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
try
|
try
|
||||||
@@ -124,6 +125,8 @@ liberator.Completion = function () //{{{
|
|||||||
if (!(objects instanceof Array))
|
if (!(objects instanceof Array))
|
||||||
objects = [objects];
|
objects = [objects];
|
||||||
|
|
||||||
|
// See if we can use the cached member list from a previous
|
||||||
|
// call.
|
||||||
if (key.indexOf(lastKey) != 0)
|
if (key.indexOf(lastKey) != 0)
|
||||||
continuing = false;
|
continuing = false;
|
||||||
if (continuing && objects != lastObjs)
|
if (continuing && objects != lastObjs)
|
||||||
@@ -143,33 +146,33 @@ liberator.Completion = function () //{{{
|
|||||||
|
|
||||||
if (!continuing)
|
if (!continuing)
|
||||||
{
|
{
|
||||||
|
// Can't use the cache. Build a member list.
|
||||||
compl = [];
|
compl = [];
|
||||||
for (let [,obj] in Iterator(objects))
|
for (let [,obj] in Iterator(objects))
|
||||||
{
|
{
|
||||||
if (typeof obj == "string")
|
if (typeof obj == "string")
|
||||||
obj = eval("with (liberator) {" + obj + "}");
|
obj = eval("with (liberator) {" + obj + "}");
|
||||||
if (typeof obj != "object")
|
// Things we can dereference
|
||||||
|
if (["object", "string", "function"].indexOf(typeof obj) == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (let [k, v] in iter(obj))
|
for (let [k, v] in iter(obj))
|
||||||
{
|
compl.push([k, liberator.template.highlight(v, true)]);
|
||||||
let type = typeof v;
|
|
||||||
if (["string", "number", "boolean"].indexOf(type) > -1)
|
|
||||||
type += ": " + String(v).replace("\n", "\\n", "g");
|
|
||||||
if (type == "function")
|
|
||||||
type += ": " + String(v).replace(/{(.|\n)*/, "{ ... }"); /* } vim */
|
|
||||||
|
|
||||||
compl.push([k, type]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (last != undefined)
|
if (last != undefined) // We're looking for a quoted string, so, strip whatever prefix we have and quote the rest
|
||||||
compl.forEach(function (a) a[0] = liberator.util.escapeString(a[0].substr(offset), last));
|
compl.forEach(function (a) a[0] = liberator.util.escapeString(a[0].substr(offset), last));
|
||||||
else
|
else // We're not looking for a quoted string, so filter out anything that's not a valid identifier
|
||||||
compl = compl.filter(function (a) /^[\w$][\w\d$]*$/.test(a[0]));
|
compl = compl.filter(function (a) /^[\w$][\w\d$]*$/.test(a[0]));
|
||||||
}
|
}
|
||||||
if (last != undefined)
|
if (last != undefined)
|
||||||
key = last + key.substr(offset)
|
{
|
||||||
return buildLongestStartingSubstring(compl, key);
|
// Filter the results, escaping the key first (without adding quotes), otherwise, it might not match
|
||||||
|
let res = buildLongestCommonSubstring(compl, liberator.util.escapeString(key.substr(offset), ""));
|
||||||
|
// Also, prepend the quote delimiter to the substrings list, so it's not stripped on <Tab>
|
||||||
|
substrings = substrings.map(function (s) last + s);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return buildLongestCommonSubstring(compl, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
function eval(arg)
|
function eval(arg)
|
||||||
@@ -211,6 +214,9 @@ liberator.Completion = function () //{{{
|
|||||||
{
|
{
|
||||||
if (top[CHAR] != arg)
|
if (top[CHAR] != arg)
|
||||||
throw new Error("Invalid JS");
|
throw new Error("Invalid JS");
|
||||||
|
// The closing character of this stack frame will have pushed a new
|
||||||
|
// statement, leaving us with an empty statement. This doesn't matter,
|
||||||
|
// now, as we simply throw away the frame when we pop it, but it may later.
|
||||||
if (top[STATEMENTS][top[STATEMENTS].length - 1] == i)
|
if (top[STATEMENTS][top[STATEMENTS].length - 1] == i)
|
||||||
top[STATEMENTS].pop();
|
top[STATEMENTS].pop();
|
||||||
top = get(-2);
|
top = get(-2);
|
||||||
@@ -219,31 +225,28 @@ liberator.Completion = function () //{{{
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the first non-whitespace character fillowing i. */
|
|
||||||
let firstNonwhite = function () {
|
|
||||||
let j = i + 1;
|
|
||||||
while (str[j] && /\s/.test(str[j]))
|
|
||||||
j++;
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
let i = start, c = ""; /* Current index and character, respectively. */
|
let i = start, c = ""; /* Current index and character, respectively. */
|
||||||
|
|
||||||
|
// We're starting afresh.
|
||||||
if (start == 0)
|
if (start == 0)
|
||||||
{
|
{
|
||||||
stack = [];
|
stack = [];
|
||||||
push("");
|
push("#root");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// A new statement may have been pushed onto the stack just after
|
||||||
|
// the end of the last string. We'll throw it away for now, and
|
||||||
|
// add it again later if it turns out to be valid.
|
||||||
let s = top[STATEMENTS];
|
let s = top[STATEMENTS];
|
||||||
if (s[s.length - 1] == start)
|
if (s[s.length - 1] == start)
|
||||||
s.pop();
|
s.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build a parse stack, discarding entries opening characters
|
/* Build a parse stack, discarding entries as opening characters
|
||||||
* match closing characters. The last open entry is used to
|
* match closing characters. The stack is walked from the top entry
|
||||||
* figure out what to complete.
|
* and down as many levels as it takes us to figure out what it is
|
||||||
|
* that we're completing.
|
||||||
*/
|
*/
|
||||||
let length = str.length;
|
let length = str.length;
|
||||||
for (; i < length; lastChar = c, i++)
|
for (; i < length; lastChar = c, i++)
|
||||||
@@ -251,7 +254,7 @@ liberator.Completion = function () //{{{
|
|||||||
c = str[i];
|
c = str[i];
|
||||||
if (last == '"' || last == "'" || last == "/")
|
if (last == '"' || last == "'" || last == "/")
|
||||||
{
|
{
|
||||||
if (lastChar == "\\")
|
if (lastChar == "\\") // Escape. Skip the next char, whatever it may be.
|
||||||
{
|
{
|
||||||
c = "";
|
c = "";
|
||||||
i++;
|
i++;
|
||||||
@@ -261,6 +264,8 @@ liberator.Completion = function () //{{{
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// A word character following a non-word character, or simply a non-word
|
||||||
|
// character. Start a new statement.
|
||||||
if (/[\w$]/.test(c) && !/[\w\d$]/.test(lastChar) || !/[\w\d\s]/.test(c))
|
if (/[\w$]/.test(c) && !/[\w\d$]/.test(lastChar) || !/[\w\d\s]/.test(c))
|
||||||
top[STATEMENTS].push(i);
|
top[STATEMENTS].push(i);
|
||||||
|
|
||||||
@@ -275,7 +280,10 @@ liberator.Completion = function () //{{{
|
|||||||
case "(":
|
case "(":
|
||||||
/* Function call, or if/while/for/... */
|
/* Function call, or if/while/for/... */
|
||||||
if (/\w/.test(lastNonwhite))
|
if (/\w/.test(lastNonwhite))
|
||||||
|
{
|
||||||
top[FUNCTIONS].push(i);
|
top[FUNCTIONS].push(i);
|
||||||
|
top[STATEMENTS].pop();
|
||||||
|
}
|
||||||
case '"':
|
case '"':
|
||||||
case "'":
|
case "'":
|
||||||
case "/":
|
case "/":
|
||||||
@@ -325,14 +333,16 @@ liberator.Completion = function () //{{{
|
|||||||
|
|
||||||
/* Okay, have parse stack. Figure out what we're completing. */
|
/* Okay, have parse stack. Figure out what we're completing. */
|
||||||
|
|
||||||
/* Find any complete statements that we can eval. */
|
// Find any complete statements that we can eval before we eval our object.
|
||||||
|
// This allows for things like: let doc = window.content.document; let elem = doc.createElement...; elem.<Tab>
|
||||||
let end = get(0, 0, FULL_STATEMENTS) || 0;
|
let end = get(0, 0, FULL_STATEMENTS) || 0;
|
||||||
let preEval = str.substring(0, end) + ";";
|
let preEval = str.substring(0, end) + ";";
|
||||||
|
|
||||||
/* In a string. */
|
// In a string. Check if we're dereferencing an object.
|
||||||
// TODO: Make this work with unquoted integers.
|
// Otherwise, do nothing.
|
||||||
if (last == "'" || last == '"')
|
if (last == "'" || last == '"')
|
||||||
{
|
{
|
||||||
|
// TODO: Make this work with unquoted integers.
|
||||||
/* Stack:
|
/* Stack:
|
||||||
* [-1]: "...
|
* [-1]: "...
|
||||||
* [-2]: [...
|
* [-2]: [...
|
||||||
@@ -341,7 +351,7 @@ liberator.Completion = function () //{{{
|
|||||||
|
|
||||||
/* Is this an object accessor? */
|
/* Is this an object accessor? */
|
||||||
if (get(-2)[CHAR] != "[" // Are we inside of []?
|
if (get(-2)[CHAR] != "[" // Are we inside of []?
|
||||||
// Okay, if the [ starts at the begining of a logical
|
// Yes. If the [ starts at the begining of a logical
|
||||||
// statement, we're in an array literal, and we're done.
|
// statement, we're in an array literal, and we're done.
|
||||||
|| get(-3, 0, STATEMENTS) == get(-2)[OFFSET])
|
|| get(-3, 0, STATEMENTS) == get(-2)[OFFSET])
|
||||||
return [0, []];
|
return [0, []];
|
||||||
@@ -352,16 +362,19 @@ liberator.Completion = function () //{{{
|
|||||||
* key = "bar + ''"
|
* key = "bar + ''"
|
||||||
*/
|
*/
|
||||||
let string = str.substring(top[OFFSET] + 1);
|
let string = str.substring(top[OFFSET] + 1);
|
||||||
string = eval(last + string + last);
|
string = eval(last + string + last); // Process escape sequences
|
||||||
|
|
||||||
|
// Begining of the statement upto the opening [
|
||||||
let obj = preEval + str.substring(get(-3, 0, STATEMENTS), get(-2)[OFFSET]);
|
let obj = preEval + str.substring(get(-3, 0, STATEMENTS), get(-2)[OFFSET]);
|
||||||
|
// After the opening [ upto the opening ", plus '' to take care of any operators before it
|
||||||
let key = preEval + str.substring(get(-2)[OFFSET] + 1, top[OFFSET]) + "''";
|
let key = preEval + str.substring(get(-2)[OFFSET] + 1, top[OFFSET]) + "''";
|
||||||
|
// Now eval the key, to process any referenced variables.
|
||||||
key = eval(key);
|
key = eval(key);
|
||||||
return [top[OFFSET], objectKeys(obj, key + string, last, key.length)];
|
return [top[OFFSET], objectKeys(obj, key + string, last, key.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is this an object reference? */
|
/* Is this an object reference? */
|
||||||
if (top[DOTS].length)
|
if (top[DOTS].length && get(-1, 0, DOTS) > get(-1, 0, STATEMENTS))
|
||||||
{
|
{
|
||||||
let dot = get(-1, 0, DOTS);
|
let dot = get(-1, 0, DOTS);
|
||||||
/*
|
/*
|
||||||
@@ -378,7 +391,7 @@ liberator.Completion = function () //{{{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Okay, assume it's an identifier and try to complete it from the window
|
/* Okay, assume it's an identifier and try to complete it from the window
|
||||||
* and liberator objects.
|
* and liberator objects. It would be nice to be able to check the local scope.
|
||||||
*/
|
*/
|
||||||
let offset = get(-1, 0, STATEMENTS) || 0;
|
let offset = get(-1, 0, STATEMENTS) || 0;
|
||||||
let key = str.substring(offset);
|
let key = str.substring(offset);
|
||||||
@@ -528,13 +541,10 @@ liberator.Completion = function () //{{{
|
|||||||
|
|
||||||
cached: function (key, filter, generate, method)
|
cached: function (key, filter, generate, method)
|
||||||
{
|
{
|
||||||
let oldFilter = cacheFilter[key];
|
if (!filter || filter.indexOf(cacheFilter[key]) != 0)
|
||||||
|
cacheResults[key] = generate(filter);
|
||||||
cacheFilter[key] = filter;
|
cacheFilter[key] = filter;
|
||||||
let results = cacheResults[key];
|
return cacheResults[key] = this[method].apply(this, [cacheResults[key], filter].concat(Array.splice(arguments, 4)));
|
||||||
if (!oldFilter || filter.indexOf(oldFilter) != 0)
|
|
||||||
results = generate(filter);
|
|
||||||
cacheResults[key] = this[method].apply(this, [results, filter].concat(Array.splice(arguments, 4)));
|
|
||||||
return cacheResults[key];
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// discard all entries in the 'urls' array, which don't match 'filter
|
// discard all entries in the 'urls' array, which don't match 'filter
|
||||||
@@ -810,11 +820,34 @@ liberator.Completion = function () //{{{
|
|||||||
|
|
||||||
search: function (filter)
|
search: function (filter)
|
||||||
{
|
{
|
||||||
let results = this.cached("search", filter,
|
let [, keyword, args] = filter.match(/^\s*(\S*)\s*(.*)/);
|
||||||
function () Array.concat(liberator.bookmarks.getKeywords().map(function (k) [k[0], k[1], k[3]]),
|
let keywords = liberator.bookmarks.getKeywords().map(function (k) [k[0], k[1], k[3], k[2]]);
|
||||||
liberator.bookmarks.getSearchEngines()),
|
let engines = this.filter(keywords.concat(liberator.bookmarks.getSearchEngines()), filter, false, true);
|
||||||
"filter", false, true);
|
|
||||||
return [0, results];
|
let history = liberator.history.get();
|
||||||
|
let searches = [];
|
||||||
|
for (let [, k] in Iterator(keywords))
|
||||||
|
{
|
||||||
|
if (k[0].toLowerCase() != keyword.toLowerCase() || k[3].indexOf("%s") == -1)
|
||||||
|
continue;
|
||||||
|
let [begin, end] = k[3].split("%s");
|
||||||
|
for (let [, h] in Iterator(history))
|
||||||
|
{
|
||||||
|
if (h[0].indexOf(begin) == 0 && (!end.length || h[0].substr(-end.length) == end))
|
||||||
|
{
|
||||||
|
let query = h[0].substr(begin.length, h[0].length - end.length);
|
||||||
|
searches.push([decodeURIComponent(query),
|
||||||
|
<>{begin}<span class="hl-Filter">{query}</span>{end}</>,
|
||||||
|
k[2]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (searches.length)
|
||||||
|
{
|
||||||
|
searches = this.filter(searches, args, false, true);
|
||||||
|
searches.forEach(function (a) a[0] = keyword + " " + a[0]);
|
||||||
|
}
|
||||||
|
return [0, searches.concat(engines)];
|
||||||
},
|
},
|
||||||
|
|
||||||
// XXX: Move to bookmarks.js?
|
// XXX: Move to bookmarks.js?
|
||||||
|
|||||||
@@ -537,7 +537,7 @@ liberator.Events = function () //{{{
|
|||||||
function waitForPageLoaded()
|
function waitForPageLoaded()
|
||||||
{
|
{
|
||||||
liberator.dump("start waiting in loaded state: " + liberator.buffer.loaded);
|
liberator.dump("start waiting in loaded state: " + liberator.buffer.loaded);
|
||||||
liberator.threadyield(true); // clear queue
|
liberator.threadYield(true); // clear queue
|
||||||
|
|
||||||
if (liberator.buffer.loaded == 1)
|
if (liberator.buffer.loaded == 1)
|
||||||
return true;
|
return true;
|
||||||
@@ -546,7 +546,7 @@ liberator.Events = function () //{{{
|
|||||||
var then = new Date().getTime();
|
var then = new Date().getTime();
|
||||||
for (let now = then; now - then < ms; now = new Date().getTime())
|
for (let now = then; now - then < ms; now = new Date().getTime())
|
||||||
{
|
{
|
||||||
liberator.threadyield();
|
liberator.threadYield();
|
||||||
if ((now - then) % 1000 < 10)
|
if ((now - then) % 1000 < 10)
|
||||||
liberator.dump("waited: " + (now - then) + " ms");
|
liberator.dump("waited: " + (now - then) + " ms");
|
||||||
|
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ liberator.Search = function () //{{{
|
|||||||
this.startPt.setStart(node, node.childNodes.length);
|
this.startPt.setStart(node, node.childNodes.length);
|
||||||
this.startPt.setEnd(node, node.childNodes.length);
|
this.startPt.setEnd(node, node.childNodes.length);
|
||||||
if (n++ % 20 == 0)
|
if (n++ % 20 == 0)
|
||||||
liberator.threadyield();
|
liberator.threadYield();
|
||||||
if (liberator.interrupted)
|
if (liberator.interrupted)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -643,7 +643,7 @@ liberator.Hints = function () //{{{
|
|||||||
generate(win);
|
generate(win);
|
||||||
|
|
||||||
// get all keys from the input queue
|
// get all keys from the input queue
|
||||||
liberator.threadyield(true);
|
liberator.threadYield(true);
|
||||||
|
|
||||||
canUpdate = true;
|
canUpdate = true;
|
||||||
showHints();
|
showHints();
|
||||||
|
|||||||
@@ -763,12 +763,22 @@ lookup:
|
|||||||
// handle pure javascript files specially
|
// handle pure javascript files specially
|
||||||
if (/\.js$/.test(filename))
|
if (/\.js$/.test(filename))
|
||||||
{
|
{
|
||||||
liberator.eval(str);
|
var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
|
||||||
|
.getService(Components.interfaces.mozIJSSubScriptLoader);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
loader.loadSubScript("file://" + file.path, liberator)
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
e.echoerr = file.path + ":" + e.lineNumber + ": " + e;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (/\.css$/.test(filename))
|
else if (/\.css$/.test(filename))
|
||||||
{
|
{
|
||||||
liberator.storage.styles.unregisterSheet("file://" + file.path);
|
liberator.storage.styles.unregisterSheet("file://" + file.path);
|
||||||
liberator.storage.styles.registerSheet("file://" + file.path);
|
liberator.storage.styles.registerSheet("file://" + file.path, !silent);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -858,9 +868,9 @@ lookup:
|
|||||||
}
|
}
|
||||||
catch (e)
|
catch (e)
|
||||||
{
|
{
|
||||||
let message = "Sourcing file: " + file.path + ": " + e;
|
let message = "Sourcing file: " + (e.echoerr || file.path + ": " + e);
|
||||||
if (Components.utils.reportError)
|
if (Components.utils.reportError)
|
||||||
Components.utils.reportError(message);
|
Components.utils.reportError(e);
|
||||||
if (!silent)
|
if (!silent)
|
||||||
liberator.echoerr(message);
|
liberator.echoerr(message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1162,6 +1162,7 @@ const liberator = (function () //{{{
|
|||||||
option.reset();
|
option.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
liberator.triggerObserver("enter", null);
|
||||||
liberator.autocommands.trigger(liberator.config.name + "Enter", "");
|
liberator.autocommands.trigger(liberator.config.name + "Enter", "");
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
@@ -1193,7 +1194,7 @@ const liberator = (function () //{{{
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
threadyield: function (flush)
|
threadYield: function (flush)
|
||||||
{
|
{
|
||||||
let mainThread = threadManager.mainThread;
|
let mainThread = threadManager.mainThread;
|
||||||
do
|
do
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ liberator.template = {
|
|||||||
if (fn.length > 1)
|
if (fn.length > 1)
|
||||||
{
|
{
|
||||||
iter = Iterator(iter);
|
iter = Iterator(iter);
|
||||||
fn = function (x) fn.apply(null, x);
|
let oldfn = fn;
|
||||||
|
fn = function (x) oldfn.apply(null, x);
|
||||||
}
|
}
|
||||||
else if (iter.length) /* Kludge? */
|
else if (iter.length) /* Kludge? */
|
||||||
iter = liberator.util.arrayIter(iter);
|
iter = liberator.util.arrayIter(iter);
|
||||||
@@ -56,8 +57,9 @@ liberator.template = {
|
|||||||
case "boolean":
|
case "boolean":
|
||||||
return <span class="hl-Boolean">{arg}</span>;
|
return <span class="hl-Boolean">{arg}</span>;
|
||||||
case "function":
|
case "function":
|
||||||
return <span class="hl-Function">{arg}</span>;
|
if (processStrings)
|
||||||
return <span class="hl-Function">{String(arg).replace(/\{(.|\n)*/, "{ ... }")}</span>; /* } vim */
|
return <span class="hl-Function">{String(arg).replace(/\{(.|\n)*/, "{ ... }")}</span>; /* } vim */
|
||||||
|
return <>{arg}</>;
|
||||||
case "undefined":
|
case "undefined":
|
||||||
return <span class="hl-Null">{arg}</span>;
|
return <span class="hl-Null">{arg}</span>;
|
||||||
case "object":
|
case "object":
|
||||||
@@ -65,7 +67,9 @@ liberator.template = {
|
|||||||
// that we cannot even try/catch it
|
// that we cannot even try/catch it
|
||||||
if (/^\[JavaPackage.*\]$/.test(arg))
|
if (/^\[JavaPackage.*\]$/.test(arg))
|
||||||
return <>[JavaPackage]</>;
|
return <>[JavaPackage]</>;
|
||||||
return <>{arg}</>;
|
if (processStrings)
|
||||||
|
arg = String(arg).replace("\n", "\\n", "g");
|
||||||
|
return <span class="hl-Object">{arg}</span>;
|
||||||
default:
|
default:
|
||||||
return <![CDATA[<unknown type>]]>;
|
return <![CDATA[<unknown type>]]>;
|
||||||
}
|
}
|
||||||
@@ -78,9 +82,13 @@ liberator.template = {
|
|||||||
|
|
||||||
highlightFilter: function (str, filter)
|
highlightFilter: function (str, filter)
|
||||||
{
|
{
|
||||||
let lcstr = str.toLowerCase();
|
if (typeof str == "xml")
|
||||||
|
return str;
|
||||||
|
if (str == "")
|
||||||
|
return <>{str}</>;
|
||||||
|
let lcstr = String(str).toLowerCase();
|
||||||
let lcfilter = filter.toLowerCase();
|
let lcfilter = filter.toLowerCase();
|
||||||
str = str.replace(" ", " ");
|
str = String(str).replace(" ", " ");
|
||||||
let s = <></>;
|
let s = <></>;
|
||||||
let start = 0;
|
let start = 0;
|
||||||
let i;
|
let i;
|
||||||
|
|||||||
@@ -874,6 +874,8 @@ liberator.CommandLine = function () //{{{
|
|||||||
{
|
{
|
||||||
setCommand(command.substring(0, completionStartIndex) + compl + completionPostfix);
|
setCommand(command.substring(0, completionStartIndex) + compl + completionPostfix);
|
||||||
commandWidget.selectionStart = commandWidget.selectionEnd = completionStartIndex + compl.length;
|
commandWidget.selectionStart = commandWidget.selectionEnd = completionStartIndex + compl.length;
|
||||||
|
if (longest)
|
||||||
|
liberator.triggerCallback("change", currentExtendedMode, this.getCommand());
|
||||||
|
|
||||||
// Start a new completion in the next iteration. Useful for commands like :source
|
// Start a new completion in the next iteration. Useful for commands like :source
|
||||||
// RFC: perhaps the command can indicate whether the completion should be restarted
|
// RFC: perhaps the command can indicate whether the completion should be restarted
|
||||||
@@ -1236,8 +1238,8 @@ liberator.ItemList = function (id) //{{{
|
|||||||
let filter = liberator.completion.filterString;
|
let filter = liberator.completion.filterString;
|
||||||
if (filter)
|
if (filter)
|
||||||
{
|
{
|
||||||
b = liberator.template.highlightFilter(String(b), filter);
|
b = liberator.template.highlightFilter(b, filter);
|
||||||
c = liberator.template.highlightFilter(String(c), filter);
|
c = liberator.template.highlightFilter(c, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof a == "function")
|
if (typeof a == "function")
|
||||||
|
|||||||
@@ -119,7 +119,8 @@ liberator.util = { //{{{
|
|||||||
|
|
||||||
escapeString: function (str, delimiter)
|
escapeString: function (str, delimiter)
|
||||||
{
|
{
|
||||||
delimiter = delimiter || '"';
|
if (delimiter == undefined)
|
||||||
|
delimiter = '"';
|
||||||
return delimiter + str.replace(/([\\'"])/g, "\\$1").replace("\n", "\\n").replace("\t", "\\t") + delimiter;
|
return delimiter + str.replace(/([\\'"])/g, "\\$1").replace("\n", "\\n").replace("\t", "\\t") + delimiter;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -246,7 +247,7 @@ liberator.util = { //{{{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (color)
|
if (color)
|
||||||
obj = <span class="hl-Title">{obj}</span>.toXMLString();
|
obj = <span class="hl-Title hl-Object">{obj}</span>.toXMLString();
|
||||||
string += obj + "::\n";
|
string += obj + "::\n";
|
||||||
|
|
||||||
try // window.content often does not want to be queried with "var i in object"
|
try // window.content often does not want to be queried with "var i in object"
|
||||||
@@ -260,9 +261,10 @@ liberator.util = { //{{{
|
|||||||
}
|
}
|
||||||
catch (e) {}
|
catch (e) {}
|
||||||
|
|
||||||
|
value = liberator.template.highlight(value, true);
|
||||||
if (color)
|
if (color)
|
||||||
{
|
{
|
||||||
value = liberator.template.highlight(value, true).toXMLString();
|
value = value.toXMLString();
|
||||||
i = <span style="font-weight: bold;">{i}</span>.toXMLString();
|
i = <span style="font-weight: bold;">{i}</span>.toXMLString();
|
||||||
}
|
}
|
||||||
string += i + ": " + value + "\n";
|
string += i + ": " + value + "\n";
|
||||||
|
|||||||
@@ -95,11 +95,13 @@ the terms of any one of the MPL, the GPL or the LGPL.
|
|||||||
.hl-String { color: green; }
|
.hl-String { color: green; }
|
||||||
.hl-Boolean { color: blue; }
|
.hl-Boolean { color: blue; }
|
||||||
.hl-Null { color: blue; }
|
.hl-Null { color: blue; }
|
||||||
|
.hl-Object { color: maroon; }
|
||||||
|
.hl-Function{ color: navy; }
|
||||||
|
|
||||||
.hl-Keyword { color: red; }
|
.hl-Keyword { color: red; }
|
||||||
.hl-Tag { color: blue; }
|
.hl-Tag { color: blue; }
|
||||||
|
|
||||||
.hl-Filter { font-weight: bold; }
|
.hl-Filter { font-weight: bold !important; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user