mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-19 20:17:59 +01:00
First work towards cleaning up the commandline.js rat's nest. Don't expect any of these new interfaces to stay remotely as they are.
--HG-- branch : key-processing
This commit is contained in:
@@ -115,9 +115,8 @@ var Bookmarks = Module("bookmarks", {
|
||||
if (charset != null && charset !== "UTF-8")
|
||||
options["-charset"] = charset;
|
||||
|
||||
commandline.open(":",
|
||||
commands.commandToString({ command: "bmark", options: options, arguments: [url] }) + " -keyword ",
|
||||
modes.EX);
|
||||
CommandExMode().open(
|
||||
commands.commandToString({ command: "bmark", options: options, arguments: [url] }) + " -keyword ");
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -582,9 +581,8 @@ var Bookmarks = Module("bookmarks", {
|
||||
options["-charset"] = content.document.characterSet;
|
||||
}
|
||||
|
||||
commandline.open(":",
|
||||
commands.commandToString({ command: "bmark", options: options, arguments: [buffer.uri.spec] }),
|
||||
modes.EX);
|
||||
CommandExMode().open(
|
||||
commands.commandToString({ command: "bmark", options: options, arguments: [buffer.uri.spec] }));
|
||||
});
|
||||
|
||||
mappings.add(myModes, ["A"],
|
||||
|
||||
@@ -71,27 +71,27 @@ var Browser = Module("browser", {
|
||||
// opening websites
|
||||
mappings.add([modes.NORMAL],
|
||||
["o"], "Open one or more URLs",
|
||||
function () { commandline.open(":", "open ", modes.EX); });
|
||||
function () { CommandExMode().open("open "); });
|
||||
|
||||
mappings.add([modes.NORMAL], ["O"],
|
||||
"Open one or more URLs, based on current location",
|
||||
function () { commandline.open(":", "open " + buffer.uri.spec, modes.EX); });
|
||||
function () { CommandExMode().open("open " + buffer.uri.spec); });
|
||||
|
||||
mappings.add([modes.NORMAL], ["t"],
|
||||
"Open one or more URLs in a new tab",
|
||||
function () { commandline.open(":", "tabopen ", modes.EX); });
|
||||
function () { CommandExMode().open("tabopen "); });
|
||||
|
||||
mappings.add([modes.NORMAL], ["T"],
|
||||
"Open one or more URLs in a new tab, based on current location",
|
||||
function () { commandline.open(":", "tabopen " + buffer.uri.spec, modes.EX); });
|
||||
function () { CommandExMode().open("tabopen " + buffer.uri.spec); });
|
||||
|
||||
mappings.add([modes.NORMAL], ["w"],
|
||||
"Open one or more URLs in a new window",
|
||||
function () { commandline.open(":", "winopen ", modes.EX); });
|
||||
function () { CommandExMode().open("winopen "); });
|
||||
|
||||
mappings.add([modes.NORMAL], ["W"],
|
||||
"Open one or more URLs in a new window, based on current location",
|
||||
function () { commandline.open(":", "winopen " + buffer.uri.spec, modes.EX); });
|
||||
function () { CommandExMode().open("winopen " + buffer.uri.spec); });
|
||||
|
||||
mappings.add([modes.NORMAL],
|
||||
["<C-a>"], "Increment last number in URL",
|
||||
|
||||
@@ -766,7 +766,8 @@ var Buffer = Module("buffer", {
|
||||
try {
|
||||
window.urlSecurityCheck(uri.spec, doc.nodePrincipal);
|
||||
|
||||
commandline.input("Save link: ", function (path) {
|
||||
io.CommandFileMode("Save link: ", {
|
||||
onSubmit: function (path) {
|
||||
let file = io.File(path);
|
||||
if (file.exists() && file.isDirectory())
|
||||
file.append(buffer.getDefaultNames(elem)[0][0]);
|
||||
@@ -780,11 +781,10 @@ var Buffer = Module("buffer", {
|
||||
}
|
||||
|
||||
buffer.saveURI(uri, file);
|
||||
}, {
|
||||
autocomplete: true,
|
||||
completer: function (context) completion.savePage(context, elem),
|
||||
history: "file"
|
||||
});
|
||||
},
|
||||
|
||||
completer: function (context) completion.savePage(context, elem)
|
||||
}).open();
|
||||
}
|
||||
catch (e) {
|
||||
dactyl.echoerr(e);
|
||||
@@ -1360,17 +1360,15 @@ var Buffer = Module("buffer", {
|
||||
},
|
||||
|
||||
openUploadPrompt: function openUploadPrompt(elem) {
|
||||
commandline.input("Upload file: ", function (path) {
|
||||
io.CommandFileMode("Upload file: ", {
|
||||
onSubmit: function (path) {
|
||||
let file = io.File(path);
|
||||
dactyl.assert(file.exists());
|
||||
|
||||
elem.value = file.path;
|
||||
events.dispatch(elem, events.create(elem.ownerDocument, "change", {}));
|
||||
}, {
|
||||
completer: function (context) completion.file(context),
|
||||
default: elem.value,
|
||||
history: "file"
|
||||
});
|
||||
}
|
||||
}).open(elem.value);
|
||||
}
|
||||
}, {
|
||||
commands: function () {
|
||||
@@ -1530,7 +1528,8 @@ var Buffer = Module("buffer", {
|
||||
if (/^>>/.test(context.filter))
|
||||
context.advance(/^>>\s*/.exec(context.filter)[0].length);
|
||||
|
||||
return completion.savePage(context, content.document);
|
||||
completion.savePage(context, content.document);
|
||||
context.fork("file", 0, completion, "file");
|
||||
},
|
||||
literal: 0
|
||||
});
|
||||
@@ -1642,7 +1641,6 @@ var Buffer = Module("buffer", {
|
||||
this, function (context) {
|
||||
context.completions = buffer.getDefaultNames(node);
|
||||
});
|
||||
return context.fork("files", 0, completion, "file");
|
||||
};
|
||||
},
|
||||
events: function () {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,11 +40,15 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
||||
this.commands["dactyl.restart"] = function (event) {
|
||||
dactyl.restart();
|
||||
};
|
||||
|
||||
styles.registerSheet("resource://dactyl-skin/dactyl.css");
|
||||
},
|
||||
|
||||
cleanup: function () {
|
||||
delete window.dactyl;
|
||||
delete window.liberator;
|
||||
|
||||
styles.unregisterSheet("resource://dactyl-skin/dactyl.css");
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
@@ -1285,6 +1289,8 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
||||
*/
|
||||
trapErrors: function trapErrors(func, self) {
|
||||
try {
|
||||
if (isString(func))
|
||||
func = self[func];
|
||||
return func.apply(self || this, Array.slice(arguments, 2));
|
||||
}
|
||||
catch (e) {
|
||||
|
||||
@@ -19,7 +19,7 @@ var ProcessorStack = Class("ProcessorStack", {
|
||||
.flatten().array;
|
||||
|
||||
for (let [i, input] in Iterator(this.processors)) {
|
||||
let params = input.main == mode.main ? mode.params : input.main.params;
|
||||
let params = input.main.params;
|
||||
if (params.preExecute)
|
||||
input.preExecute = params.preExecute;
|
||||
if (params.postExecute)
|
||||
@@ -101,7 +101,8 @@ var ProcessorStack = Class("ProcessorStack", {
|
||||
result = res === Events.PASS ? Events.PASS : Events.KILL;
|
||||
}
|
||||
}
|
||||
else if (result !== Events.KILL && processors.some(function (p) !p.main.passUnknown)) {
|
||||
else if (result !== Events.KILL && !this.actions.length &&
|
||||
processors.some(function (p) !p.main.passUnknown)) {
|
||||
result = Events.KILL;
|
||||
dactyl.beep();
|
||||
}
|
||||
@@ -157,12 +158,13 @@ var KeyProcessor = Class("KeyProcessor", {
|
||||
return this.onKeyPress(event);
|
||||
},
|
||||
|
||||
execute: function execute(map)
|
||||
let (self = this, args = arguments)
|
||||
execute: function execute(map, args)
|
||||
let (self = this)
|
||||
function execute() {
|
||||
if (self.preExecute)
|
||||
self.preExecute.apply(self, args);
|
||||
let res = map.execute.apply(map, Array.slice(args, 1));
|
||||
let res = map.execute.call(map, update({ self: self.main.params.mappingSelf || self.main.mappingSelf || map },
|
||||
args))
|
||||
if (self.postExecute)
|
||||
self.postExecute.apply(self, args);
|
||||
return res;
|
||||
@@ -1092,7 +1094,8 @@ var Events = Module("events", {
|
||||
|
||||
let hives = mappings.hives.slice(event.noremap ? -1 : 0);
|
||||
|
||||
let keyModes = array([mode.params.keyModes, mode.main, mode.main.allBases]).flatten().compact();
|
||||
let main = { __proto__: mode.main, params: mode.params };
|
||||
let keyModes = array([mode.params.keyModes, main, mode.main.allBases]).flatten().compact();
|
||||
|
||||
this.processor = ProcessorStack(mode, hives, keyModes);
|
||||
}
|
||||
@@ -1175,7 +1178,7 @@ var Events = Module("events", {
|
||||
// Huh? --djk
|
||||
onFocusChange: function onFocusChange(event) {
|
||||
// command line has its own focus change handler
|
||||
if (modes.main == modes.COMMAND_LINE)
|
||||
if (modes.main.input)
|
||||
return;
|
||||
|
||||
function hasHTMLDocument(win) win && win.document && win.document instanceof HTMLDocument
|
||||
|
||||
@@ -9,16 +9,18 @@
|
||||
/** @scope modules */
|
||||
/** @instance hints */
|
||||
|
||||
var HintSession = Class("HintSession", {
|
||||
var HintSession = Class("HintSession", CommandMode, {
|
||||
init: function init(mode, opts) {
|
||||
init.supercall(this);
|
||||
|
||||
opts = opts || {};
|
||||
|
||||
// Hack.
|
||||
if (!opts.window && modes.main == modes.OUTPUT_MULTILINE)
|
||||
opts.window = commandline.widgets.multilineOutput.contentWindow;
|
||||
|
||||
this.mode = hints.modes[mode];
|
||||
dactyl.assert(this.mode);
|
||||
this.hintMode = hints.modes[mode];
|
||||
dactyl.assert(this.hintMode);
|
||||
|
||||
this.activeTimeout = null; // needed for hinttimeout > 0
|
||||
this.continue = Boolean(opts.continue);
|
||||
@@ -31,8 +33,7 @@ var HintSession = Class("HintSession", {
|
||||
this.usedTabKey = false;
|
||||
this.validHints = []; // store the indices of the "hints" array with valid elements
|
||||
|
||||
commandline.input(UTF8(this.mode.prompt) + ": ", null, this.closure);
|
||||
modes.extended = modes.HINTS;
|
||||
this.open();
|
||||
|
||||
this.top = opts.window || content;
|
||||
this.top.addEventListener("resize", hints.resizeTimer.closure.tell, true);
|
||||
@@ -51,7 +52,22 @@ var HintSession = Class("HintSession", {
|
||||
this.checkUnique();
|
||||
},
|
||||
|
||||
get extended() modes.HINTS,
|
||||
get mode() modes.HINTS,
|
||||
|
||||
get prompt() ["Question", UTF8(this.hintMode.prompt) + ": "],
|
||||
|
||||
leave: function leave(stack) {
|
||||
leave.superapply(this, arguments);
|
||||
|
||||
if (!stack.push) {
|
||||
if (hints.hintSession == this)
|
||||
hints.hintSession = null;
|
||||
if (this.top)
|
||||
this.top.removeEventListener("resize", hints.resizeTimer.closure.tell, true);
|
||||
|
||||
this.removeHints(0);
|
||||
}
|
||||
},
|
||||
|
||||
checkUnique: function _checkUnique() {
|
||||
if (this.hintNumber == 0)
|
||||
@@ -236,7 +252,7 @@ var HintSession = Class("HintSession", {
|
||||
|
||||
let baseNodeAbsolute = util.xmlToDom(<span highlight="Hint" style="display: none"/>, doc);
|
||||
|
||||
let mode = this.mode;
|
||||
let mode = this.hintMode;
|
||||
let res = util.evaluateXPath(mode.xpath, doc, true);
|
||||
|
||||
let start = this.pageHints.length;
|
||||
@@ -289,18 +305,6 @@ var HintSession = Class("HintSession", {
|
||||
return true;
|
||||
},
|
||||
|
||||
leave: function leave(stack) {
|
||||
if (!stack.push) {
|
||||
if (hints.hintSession == this)
|
||||
hints.hintSession = null;
|
||||
this.continue = false;
|
||||
if (this.top)
|
||||
this.top.removeEventListener("resize", hints.resizeTimer.closure.tell, true);
|
||||
|
||||
this.removeHints(0);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle user input.
|
||||
*
|
||||
@@ -429,7 +433,7 @@ var HintSession = Class("HintSession", {
|
||||
if ((modes.extended & modes.HINTS) && !this.continue)
|
||||
modes.pop();
|
||||
commandline.lastEcho = null; // Hack.
|
||||
dactyl.trapErrors(this.mode.action, this.mode,
|
||||
dactyl.trapErrors("action", this.hintMode,
|
||||
elem, elem.href || elem.src || "",
|
||||
this.extendedhintCount, top);
|
||||
if (this.continue && this.top)
|
||||
@@ -662,6 +666,7 @@ var Hints = Module("hints", {
|
||||
if (modes.extended & modes.HINTS)
|
||||
modes.getStack(0).params.onResize();
|
||||
});
|
||||
|
||||
let appContent = document.getElementById("appcontent");
|
||||
if (appContent)
|
||||
events.addSessionListener(appContent, "scroll", this.resizeTimer.closure.tell, false);
|
||||
@@ -681,9 +686,9 @@ var Hints = Module("hints", {
|
||||
this.addMode("t", "Follow hint in a new tab", function (elem) buffer.followLink(elem, dactyl.NEW_TAB));
|
||||
this.addMode("b", "Follow hint in a background tab", function (elem) buffer.followLink(elem, dactyl.NEW_BACKGROUND_TAB));
|
||||
this.addMode("w", "Follow hint in a new window", function (elem) buffer.followLink(elem, dactyl.NEW_WINDOW));
|
||||
this.addMode("O", "Generate an ‘:open URL’ prompt", function (elem, loc) commandline.open(":", "open " + loc, modes.EX));
|
||||
this.addMode("T", "Generate a ‘:tabopen URL’ prompt", function (elem, loc) commandline.open(":", "tabopen " + loc, modes.EX));
|
||||
this.addMode("W", "Generate a ‘:winopen URL’ prompt", function (elem, loc) commandline.open(":", "winopen " + loc, modes.EX));
|
||||
this.addMode("O", "Generate an ‘:open URL’ prompt", function (elem, loc) CommandExMode.open("open " + loc));
|
||||
this.addMode("T", "Generate a ‘:tabopen URL’ prompt", function (elem, loc) CommandExMode.open("tabopen " + loc));
|
||||
this.addMode("W", "Generate a ‘:winopen URL’ prompt", function (elem, loc) CommandExMode.open("winopen " + loc));
|
||||
this.addMode("a", "Add a bookmark", function (elem) bookmarks.addSearchKeyword(elem));
|
||||
this.addMode("S", "Add a search keyword", function (elem) bookmarks.addSearchKeyword(elem));
|
||||
this.addMode("v", "View hint source", function (elem, loc) buffer.viewSource(loc, false));
|
||||
@@ -952,20 +957,19 @@ var Hints = Module("hints", {
|
||||
|
||||
open: function open(mode, opts) {
|
||||
this._extendedhintCount = opts.count;
|
||||
commandline.input(mode, null, {
|
||||
commandline.input(["Normal", mode], "", {
|
||||
completer: function (context) {
|
||||
context.compare = function () 0;
|
||||
context.completions = [[k, v.prompt] for ([k, v] in Iterator(hints.modes))];
|
||||
},
|
||||
onAccept: function (arg) {
|
||||
onSubmit: function (arg) {
|
||||
if (arg)
|
||||
util.timeout(function () {
|
||||
dactyl.trapErrors(hints.show, hints, arg, opts);
|
||||
});
|
||||
hints.show(arg, opts);
|
||||
},
|
||||
onChange: function () {
|
||||
this.accepted = true;
|
||||
modes.pop();
|
||||
},
|
||||
get onCancel() this.onAccept,
|
||||
onChange: function () { modes.pop(); },
|
||||
promptHighlight: "Normal"
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1075,6 +1079,15 @@ var Hints = Module("hints", {
|
||||
|
||||
Mode: Struct("name", "prompt", "action", "tags", "filter")
|
||||
}, {
|
||||
modes: function () {
|
||||
modes.addMode("HINTS", {
|
||||
extended: true,
|
||||
description: "Active when selecting elements in QuickHint or ExtendedHint mode",
|
||||
bases: [modes.COMMAND_LINE],
|
||||
input: true,
|
||||
ownsBuffer: true
|
||||
});
|
||||
},
|
||||
mappings: function () {
|
||||
var myModes = config.browserModes.concat(modes.OUTPUT_MULTILINE);
|
||||
mappings.add(myModes, ["f"],
|
||||
@@ -1097,25 +1110,23 @@ var Hints = Module("hints", {
|
||||
|
||||
mappings.add(modes.HINTS, ["<Return>"],
|
||||
"Follow the selected hint",
|
||||
function () { hints.hintSession.update(true); });
|
||||
function ({ self }) { self.update(true); });
|
||||
|
||||
mappings.add(modes.HINTS, ["<Tab>"],
|
||||
"Focus the next matching hint",
|
||||
function () { hints.hintSession.tab(false); });
|
||||
function ({ self }) { self.tab(false); });
|
||||
|
||||
mappings.add(modes.HINTS, ["<S-Tab>"],
|
||||
"Focus the previous matching hint",
|
||||
function () { hints.hintSession.tab(true); });
|
||||
function ({ self }) { self.tab(true); });
|
||||
|
||||
mappings.add(modes.HINTS, ["<BS>", "<C-h>"],
|
||||
"Delete the previous character",
|
||||
function () hints.hintSession.backspace());
|
||||
function ({ self }) self.backspace());
|
||||
|
||||
mappings.add(modes.HINTS, ["<Leader>"],
|
||||
"Toggle hint filtering",
|
||||
function () {
|
||||
hints.hintSession.escapeNumbers = !hints.hintSession.escapeNumbers;
|
||||
});
|
||||
function ({ self }) { self.escapeNumbers = !self.escapeNumbers; });
|
||||
},
|
||||
options: function () {
|
||||
const DEFAULT_HINTTAGS =
|
||||
|
||||
@@ -295,6 +295,8 @@ var Mappings = Module("mappings", {
|
||||
this.allHives = [this.user, this.builtin];
|
||||
},
|
||||
|
||||
repeat: Modes.boundProperty(),
|
||||
|
||||
hives: Class.memoize(function () array(this.allHives.filter(function (h) h.filter(buffer.uri)))),
|
||||
|
||||
get userHives() this.allHives.filter(function (h) h !== this.builtin, this),
|
||||
|
||||
@@ -119,12 +119,6 @@ var Modes = Module("modes", {
|
||||
input: true,
|
||||
ownsFocus: true
|
||||
});
|
||||
this.addMode("COMMAND_LINE", {
|
||||
char: "c",
|
||||
description: "Active when the command line is focused",
|
||||
input: true
|
||||
});
|
||||
|
||||
|
||||
this.addMode("EMBED", {
|
||||
input: true,
|
||||
@@ -160,18 +154,6 @@ var Modes = Module("modes", {
|
||||
input: true
|
||||
});
|
||||
|
||||
// this._extended modes, can include multiple modes, and even main modes
|
||||
this.addMode("EX", {
|
||||
extended: true,
|
||||
description: "Ex command mode, active when the command line is open for Ex commands",
|
||||
input: true
|
||||
}, { history: "command" });
|
||||
this.addMode("HINTS", {
|
||||
extended: true,
|
||||
description: "Active when selecting elements in QuickHint or ExtendedHint mode",
|
||||
count: false,
|
||||
ownsBuffer: true
|
||||
});
|
||||
this.addMode("INPUT_MULTILINE", {
|
||||
extended: true,
|
||||
hidden: true,
|
||||
@@ -180,11 +162,6 @@ var Modes = Module("modes", {
|
||||
this.addMode("LINE", {
|
||||
extended: true, hidden: true
|
||||
});
|
||||
this.addMode("PROMPT", {
|
||||
extended: true,
|
||||
description: "Active when a prompt is open in the command line",
|
||||
input: true
|
||||
});
|
||||
|
||||
this.push(this.NORMAL, 0, {
|
||||
enter: function (stack, prev) {
|
||||
@@ -214,9 +191,9 @@ var Modes = Module("modes", {
|
||||
_getModeMessage: function () {
|
||||
// when recording a macro
|
||||
let macromode = "";
|
||||
if (modes.recording)
|
||||
if (this.recording)
|
||||
macromode = "recording";
|
||||
else if (modes.replaying)
|
||||
else if (this.replaying)
|
||||
macromode = "replaying";
|
||||
|
||||
let val = this._modeMap[this._main].display();
|
||||
@@ -317,13 +294,15 @@ var Modes = Module("modes", {
|
||||
}
|
||||
|
||||
if (stack && stack.pop && stack.pop.params.leave)
|
||||
stack.pop.params.leave(stack, this.topOfStack);
|
||||
dactyl.trapErrors("leave", stack.pop.params,
|
||||
stack, this.topOfStack);
|
||||
|
||||
let push = mainMode != null && !(stack && stack.pop) &&
|
||||
Modes.StackElement(this._main, this._extended, params, {});
|
||||
if (push && this.topOfStack) {
|
||||
if (this.topOfStack.params.leave)
|
||||
this.topOfStack.params.leave({ push: push }, push);
|
||||
dactyl.trapErrors("leave", this.topOfStack.params,
|
||||
{ push: push }, push);
|
||||
for (let [id, { obj, prop }] in Iterator(this.boundProperties)) {
|
||||
if (!obj.get())
|
||||
delete this.boundProperties[id];
|
||||
@@ -332,7 +311,7 @@ var Modes = Module("modes", {
|
||||
}
|
||||
}
|
||||
|
||||
this.delayed.forEach(function ([fn, self]) fn.call(self));
|
||||
let delayed = this.delayed;
|
||||
this.delayed = [];
|
||||
|
||||
let prev = stack && stack.pop || this.topOfStack;
|
||||
@@ -343,8 +322,13 @@ var Modes = Module("modes", {
|
||||
for (let { obj, prop, value } in values(this.topOfStack.saved))
|
||||
obj[prop] = value;
|
||||
|
||||
this.show();
|
||||
|
||||
delayed.forEach(function ([fn, self]) dactyl.trapErrors(fn, self));
|
||||
|
||||
if (this.topOfStack.params.enter && prev)
|
||||
this.topOfStack.params.enter(push ? { push: push } : stack || {},
|
||||
dactyl.trapErrors("enter", this.topOfStack.params,
|
||||
push ? { push: push } : stack || {},
|
||||
prev);
|
||||
|
||||
dactyl.triggerObserver("modeChange", [oldMain, oldExtended], [this._main, this._extended], stack);
|
||||
@@ -439,7 +423,7 @@ var Modes = Module("modes", {
|
||||
|
||||
input: false,
|
||||
|
||||
passUnknown: false,
|
||||
get passUnknown() this.input,
|
||||
|
||||
get mask() this,
|
||||
|
||||
|
||||
352
common/content/mow.js
Normal file
352
common/content/mow.js
Normal file
@@ -0,0 +1,352 @@
|
||||
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
|
||||
// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
|
||||
//
|
||||
// This work is licensed for reuse under an MIT license. Details are
|
||||
// given in the LICENSE.txt file included with this file.
|
||||
|
||||
var MOW = Module("mow", {
|
||||
init: function () {
|
||||
|
||||
XML.ignoreWhitespace = true;
|
||||
util.overlayWindow(window, {
|
||||
objects: {
|
||||
eventTarget: this
|
||||
},
|
||||
append: <e4x xmlns={XUL} xmlns:dactyl={NS}>
|
||||
<window id={document.documentElement.id}>
|
||||
<popupset>
|
||||
<menupopup id="dactyl-contextmenu" highlight="Events" events="contextEvents">
|
||||
<menuitem id="dactyl-context-copylink"
|
||||
label="Copy Link Location" dactyl:group="link"
|
||||
oncommand="goDoCommand('cmd_copyLink');"/>
|
||||
<menuitem id="dactyl-context-copypath"
|
||||
label="Copy File Path" dactyl:group="link path"
|
||||
oncommand="dactyl.clipboardWrite(document.popupNode.getAttribute('path'));"/>
|
||||
<menuitem id="dactyl-context-copy"
|
||||
label="Copy" dactyl:group="selection"
|
||||
command="cmd_copy"/>
|
||||
<menuitem id="dactyl-context-selectall"
|
||||
label="Select All"
|
||||
command="cmd_selectAll"/>
|
||||
</menupopup>
|
||||
</popupset>
|
||||
</window>
|
||||
<vbox id={config.commandContainer}>
|
||||
<vbox class="dactyl-container" id="dactyl-multiline-output-container" hidden="false" collapsed="true">
|
||||
<iframe id="dactyl-multiline-output" src="dactyl://content/buffer.xhtml"
|
||||
flex="1" hidden="false" collapsed="false" contextmenu="dactyl-contextmenu"
|
||||
highlight="Events" />
|
||||
</vbox>
|
||||
</vbox>
|
||||
</e4x>
|
||||
});
|
||||
},
|
||||
|
||||
__noSuchMethod__: function (meth, args) Buffer[meth].apply(Buffer, [this.body].concat(args)),
|
||||
|
||||
get widget() this.widgets.multilineOutput,
|
||||
widgets: Class.memoize(function () commandline.widgets),
|
||||
|
||||
body: Class.memoize(function () this.widget.contentDocument.documentElement),
|
||||
document: Class.memoize(function () this.widget.contentDocument),
|
||||
window: Class.memoize(function () this.widget.contentWindow),
|
||||
|
||||
/**
|
||||
* Display a multi-line message.
|
||||
*
|
||||
* @param {string} data
|
||||
* @param {string} highlightGroup
|
||||
*/
|
||||
echo: function echo(data, highlightGroup, silent) {
|
||||
let body = this.document.body;
|
||||
|
||||
this.widgets.message = null;
|
||||
if (!commandline.commandVisible)
|
||||
commandline.hide();
|
||||
|
||||
this._startHints = false;
|
||||
if (modes.main != modes.OUTPUT_MULTILINE) {
|
||||
modes.push(modes.OUTPUT_MULTILINE, null, {
|
||||
onKeyPress: this.closure.onKeyPress,
|
||||
leave: this.closure(function leave(stack) {
|
||||
if (stack.pop)
|
||||
for (let message in values(this.messages))
|
||||
if (message.leave)
|
||||
message.leave(stack);
|
||||
})
|
||||
});
|
||||
this.messages = [];
|
||||
}
|
||||
|
||||
// If it's already XML, assume it knows what it's doing.
|
||||
// Otherwise, white space is significant.
|
||||
// The problem elsewhere is that E4X tends to insert new lines
|
||||
// after interpolated data.
|
||||
XML.ignoreWhitespace = XML.prettyPrinting = false;
|
||||
|
||||
if (isObject(data)) {
|
||||
this.lastOutput = null;
|
||||
|
||||
var output = util.xmlToDom(<div class="ex-command-output" style="white-space: nowrap" highlight={highlightGroup}/>,
|
||||
this.document);
|
||||
data.document = this.document;
|
||||
output.appendChild(data.message);
|
||||
|
||||
this.messages.push(data);
|
||||
}
|
||||
else {
|
||||
let style = isString(data) ? "pre" : "nowrap";
|
||||
this.lastOutput = <div class="ex-command-output" style={"white-space: " + style} highlight={highlightGroup}>{data}</div>;
|
||||
|
||||
var output = util.xmlToDom(this.lastOutput, this.document);
|
||||
}
|
||||
|
||||
// FIXME: need to make sure an open MOW is closed when commands
|
||||
// that don't generate output are executed
|
||||
if (this.widgets.mowContainer.collapsed) {
|
||||
this.body.scrollTop = 0;
|
||||
while (body.firstChild)
|
||||
body.removeChild(body.firstChild);
|
||||
}
|
||||
|
||||
body.appendChild(output);
|
||||
|
||||
let str = typeof data !== "xml" && data.message || data;
|
||||
if (!silent)
|
||||
dactyl.triggerObserver("echoMultiline", data, highlightGroup, output);
|
||||
|
||||
this.resize(true);
|
||||
|
||||
if (options["more"] && this.isScrollable(1)) {
|
||||
// start the last executed command's output at the top of the screen
|
||||
let elements = this.document.getElementsByClassName("ex-command-output");
|
||||
elements[elements.length - 1].scrollIntoView(true);
|
||||
}
|
||||
else
|
||||
this.body.scrollTop = this.body.scrollHeight;
|
||||
|
||||
dactyl.focus(this.window);
|
||||
this.updateMorePrompt();
|
||||
},
|
||||
|
||||
events: {
|
||||
click: function onClick(event) {
|
||||
if (event.getPreventDefault())
|
||||
return;
|
||||
|
||||
const openLink = function openLink(where) {
|
||||
event.preventDefault();
|
||||
dactyl.open(event.target.href, where);
|
||||
}
|
||||
|
||||
if (event.target instanceof HTMLAnchorElement)
|
||||
switch (events.toString(event)) {
|
||||
case "<LeftMouse>":
|
||||
openLink(dactyl.CURRENT_TAB);
|
||||
break;
|
||||
case "<MiddleMouse>":
|
||||
case "<C-LeftMouse>":
|
||||
case "<C-M-LeftMouse>":
|
||||
openLink({ where: dactyl.NEW_TAB, background: true });
|
||||
break;
|
||||
case "<S-MiddleMouse>":
|
||||
case "<C-S-LeftMouse>":
|
||||
case "<C-M-S-LeftMouse>":
|
||||
openLink({ where: dactyl.NEW_TAB, background: false });
|
||||
break;
|
||||
case "<S-LeftMouse>":
|
||||
openLink(dactyl.NEW_WINDOW);
|
||||
break;
|
||||
}
|
||||
},
|
||||
unload: function onUnload(event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
contextEvents: {
|
||||
popupshowing: function (event) {
|
||||
let enabled = {
|
||||
link: window.document.popupNode instanceof HTMLAnchorElement,
|
||||
path: window.document.popupNode.hasAttribute("path"),
|
||||
selection: !window.document.commandDispatcher.focusedWindow.getSelection().isCollapsed
|
||||
};
|
||||
|
||||
for (let node in array.iterValues(event.target.children)) {
|
||||
let group = node.getAttributeNS(NS, "group");
|
||||
node.hidden = group && !group.split(/\s+/).every(function (g) enabled[g]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onContext: function onContext(event) {
|
||||
return true;
|
||||
},
|
||||
|
||||
onKeyPress: function onKeyPress(event) {
|
||||
const KILL = false, PASS = true;
|
||||
|
||||
if (options["more"] && mow.isScrollable(1))
|
||||
commandline.updateMorePrompt(false, true);
|
||||
else {
|
||||
modes.pop();
|
||||
events.feedkeys(events.toString(event));
|
||||
return KILL;
|
||||
}
|
||||
return PASS;
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes the height of the message window to fit in the available space.
|
||||
*
|
||||
* @param {boolean} open If true, the widget will be opened if it's not
|
||||
* already so.
|
||||
*/
|
||||
resize: function updateOutputHeight(open, extra) {
|
||||
if (!open && this.widgets.mowContainer.collapsed)
|
||||
return;
|
||||
|
||||
let doc = this.widget.contentDocument;
|
||||
|
||||
let availableHeight = config.outputHeight;
|
||||
if (!this.widgets.mowContainer.collapsed)
|
||||
availableHeight += parseFloat(this.widgets.mowContainer.height);
|
||||
availableHeight -= extra || 0;
|
||||
|
||||
doc.body.style.minWidth = this.widgets.commandbar.commandline.scrollWidth + "px";
|
||||
this.widgets.mowContainer.height = Math.min(doc.body.clientHeight, availableHeight) + "px";
|
||||
this.timeout(function ()
|
||||
this.widgets.mowContainer.height = Math.min(doc.body.clientHeight, availableHeight) + "px",
|
||||
0);
|
||||
|
||||
doc.body.style.minWidth = "";
|
||||
this.visible = true;
|
||||
},
|
||||
|
||||
get spaceNeeded() {
|
||||
let rect = this.widgets.commandbar.commandline.getBoundingClientRect();
|
||||
let offset = rect.bottom - window.innerHeight;
|
||||
return Math.max(0, offset);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update or remove the multi-line output widget's "MORE" prompt.
|
||||
*
|
||||
* @param {boolean} force If true, "-- More --" is shown even if we're
|
||||
* at the end of the output.
|
||||
* @param {boolean} showHelp When true, show the valid key sequences
|
||||
* and what they do.
|
||||
*/
|
||||
updateMorePrompt: function updateMorePrompt(force, showHelp) {
|
||||
if (this.widgets.mowContainer.collapsed)
|
||||
return this.widgets.message = null;
|
||||
let elem = this.widget.contentDocument.documentElement;
|
||||
|
||||
if (showHelp)
|
||||
this.widgets.message = ["MoreMsg", "-- More -- SPACE/<C-f>/j: screen/page/line down, <C-b>/<C-u>/k: up, q: quit"];
|
||||
else if (force || (options["more"] && Buffer.isScrollable(elem, 1)))
|
||||
this.widgets.message = ["MoreMsg", "-- More --"];
|
||||
else
|
||||
this.widgets.message = ["Question", "Press ENTER or type command to continue"];
|
||||
},
|
||||
|
||||
visible: Modes.boundProperty({
|
||||
set: function set_mowVisible(value) {
|
||||
this.widgets.mowContainer.collapsed = !value;
|
||||
|
||||
let elem = this.widget;
|
||||
if (!value && elem && elem.contentWindow == document.commandDispatcher.focusedWindow)
|
||||
document.commandDispatcher.focusedWindow = content;
|
||||
}
|
||||
}),
|
||||
|
||||
}, {
|
||||
}, {
|
||||
mappings: function () {
|
||||
const PASS = true;
|
||||
const DROP = false;
|
||||
const BEEP = {};
|
||||
|
||||
mappings.add([modes.COMMAND],
|
||||
["g<lt>"], "Redisplay the last command output",
|
||||
function () {
|
||||
dactyl.assert(commandline.lastOutput, "No previous command output");
|
||||
mow.echo(mow.lastOutput, "Normal");
|
||||
});
|
||||
|
||||
bind = function bind(keys, description, action, test, default_) {
|
||||
mappings.add([modes.OUTPUT_MULTILINE],
|
||||
keys, description,
|
||||
function (command) {
|
||||
if (!options["more"])
|
||||
var res = PASS;
|
||||
else if (test && !test(command))
|
||||
res = default_;
|
||||
else
|
||||
res = action.call(command);
|
||||
|
||||
if (res === PASS || res === DROP)
|
||||
modes.pop();
|
||||
else
|
||||
mow.updateMorePrompt();
|
||||
if (res === BEEP)
|
||||
dactyl.beep();
|
||||
else if (res === PASS)
|
||||
events.feedkeys(command);
|
||||
});
|
||||
}
|
||||
|
||||
bind(["j", "<C-e>", "<Down>"], "Scroll down one line",
|
||||
function () { mow.scrollVertical("lines", 1); },
|
||||
function () mow.isScrollable(1), BEEP);
|
||||
|
||||
bind(["k", "<C-y>", "<Up>"], "Scroll up one line",
|
||||
function () { mow.scrollVertical("lines", -1); },
|
||||
function () mow.isScrollable(-1), BEEP);
|
||||
|
||||
bind(["<C-j>", "<C-m>", "<Return>"], "Scroll down one line, exit on last line",
|
||||
function () { mow.scrollVertical("lines", 1); },
|
||||
function () mow.isScrollable(1), DROP);
|
||||
|
||||
// half page down
|
||||
bind(["<C-d>"], "Scroll down half a page",
|
||||
function () { mow.scrollVertical("pages", .5); },
|
||||
function () mow.isScrollable(1), BEEP);
|
||||
|
||||
bind(["<C-f>", "<PageDown>"], "Scroll down one page",
|
||||
function () { mow.scrollVertical("pages", 1); },
|
||||
function () mow.isScrollable(1), BEEP);
|
||||
|
||||
bind(["<Space>"], "Scroll down one page",
|
||||
function () { mow.scrollVertical("pages", 1); },
|
||||
function () mow.isScrollable(1), DROP);
|
||||
|
||||
bind(["<C-u>"], "Scroll up half a page",
|
||||
function () { mow.scrollVertical("pages", -.5); },
|
||||
function () mow.isScrollable(-1), BEEP);
|
||||
|
||||
bind(["<C-b>", "<PageUp>"], "Scroll up half a page",
|
||||
function () { mow.scrollVertical("pages", -1); },
|
||||
function () mow.isScrollable(-1), BEEP);
|
||||
|
||||
bind(["gg"], "Scroll to the beginning of output",
|
||||
function () { mow.scrollToPercent(null, 0); })
|
||||
|
||||
bind(["G"], "Scroll to the end of output",
|
||||
function () { mow.body.scrollTop = mow.body.scrollHeight; })
|
||||
|
||||
// copy text to clipboard
|
||||
bind(["<C-y>"], "Yank selection to clipboard",
|
||||
function () { dactyl.clipboardWrite(buffer.getCurrentWord(mow.window)); });
|
||||
|
||||
// close the window
|
||||
bind(["q"], "Close the output window",
|
||||
function () {},
|
||||
function () false, DROP);
|
||||
},
|
||||
options: function () {
|
||||
options.add(["more"],
|
||||
"Pause the message list window when the full output will not fit on one page",
|
||||
"boolean", true);
|
||||
}
|
||||
});
|
||||
@@ -908,7 +908,7 @@ var Tabs = Module("tabs", {
|
||||
if (count != null)
|
||||
tabs.switchTo(String(count));
|
||||
else
|
||||
commandline.open(":", "buffer! ", modes.EX);
|
||||
CommandExMode.open("buffer! ");
|
||||
},
|
||||
{ count: true });
|
||||
|
||||
|
||||
@@ -314,7 +314,7 @@ var AddonList = Class("AddonList", {
|
||||
if (addon && addon.id in this.addons)
|
||||
this.addons[addon.id].update();
|
||||
if (this.ready)
|
||||
this.modules.commandline.updateOutputHeight(false);
|
||||
this.modules.mow.resize(false);
|
||||
},
|
||||
|
||||
onDisabled: function (addon) { this.update(addon); },
|
||||
|
||||
@@ -985,9 +985,10 @@ let StructBase = Class("StructBase", Array, {
|
||||
});
|
||||
|
||||
var Timer = Class("Timer", {
|
||||
init: function (minInterval, maxInterval, callback) {
|
||||
init: function (minInterval, maxInterval, callback, self) {
|
||||
this._timer = services.Timer();
|
||||
this.callback = callback;
|
||||
this.self = self || this;
|
||||
this.minInterval = minInterval;
|
||||
this.maxInterval = maxInterval;
|
||||
this.doneAt = 0;
|
||||
@@ -1004,7 +1005,7 @@ var Timer = Class("Timer", {
|
||||
// minInterval is the time between the completion of the command and the next firing
|
||||
this.doneAt = Date.now() + this.minInterval;
|
||||
|
||||
this.callback(this.arg);
|
||||
this.callback.call(this.self, this.arg);
|
||||
}
|
||||
catch (e) {
|
||||
if (typeof util === "undefined")
|
||||
@@ -1042,8 +1043,8 @@ var Timer = Class("Timer", {
|
||||
this.doneAt = 0;
|
||||
},
|
||||
|
||||
flush: function () {
|
||||
if (this.doneAt == -1)
|
||||
flush: function (force) {
|
||||
if (this.doneAt == -1 || force)
|
||||
this.notify();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -296,7 +296,7 @@ var DownloadList = Class("DownloadList",
|
||||
else {
|
||||
this.addDownload(download.id);
|
||||
|
||||
this.modules.commandline.updateOutputHeight(false);
|
||||
this.modules.mow.resize(false);
|
||||
this.nodes.list.scrollIntoView(false);
|
||||
}
|
||||
this.update();
|
||||
|
||||
@@ -15,20 +15,22 @@ var RangeFinder = Module("rangefinder", {
|
||||
Local: function (dactyl, modules, window) ({
|
||||
init: function () {
|
||||
this.dactyl = dactyl;
|
||||
this.commandline = modules.commandline;
|
||||
this.modes = modules.modes;
|
||||
this.modules = modules;
|
||||
this.window = window;
|
||||
this.options = modules.options;
|
||||
this.lastFindPattern = "";
|
||||
},
|
||||
|
||||
get commandline() this.modules.commandline,
|
||||
get modes() this.modules.modes,
|
||||
get options() this.modules.options(),
|
||||
|
||||
get rangeFind() modules.buffer.localStore.rangeFind,
|
||||
set rangeFind(val) modules.buffer.localStore.rangeFind = val
|
||||
}),
|
||||
|
||||
openPrompt: function (mode) {
|
||||
let backwards = mode == this.modes.FIND_BACKWARD;
|
||||
this.commandline.open(backwards ? "?" : "/", "", mode);
|
||||
this.CommandMode(mode).open(backwards ? "?" : "/");
|
||||
|
||||
if (this.rangeFind && this.rangeFind.window.get() === this.window)
|
||||
this.rangeFind.reset();
|
||||
@@ -184,15 +186,6 @@ var RangeFinder = Module("rangefinder", {
|
||||
input: true
|
||||
}, { history: "search" });
|
||||
},
|
||||
commandline: function (dactyl, modules, window) {
|
||||
const { commandline, modes, rangefinder } = modules;
|
||||
commandline.registerCallback("change", modes.FIND_FORWARD, rangefinder.closure.onKeyPress);
|
||||
commandline.registerCallback("submit", modes.FIND_FORWARD, rangefinder.closure.onSubmit);
|
||||
commandline.registerCallback("cancel", modes.FIND_FORWARD, rangefinder.closure.onCancel);
|
||||
commandline.registerCallback("change", modes.FIND_BACKWARD, rangefinder.closure.onKeyPress);
|
||||
commandline.registerCallback("submit", modes.FIND_BACKWARD, rangefinder.closure.onSubmit);
|
||||
commandline.registerCallback("cancel", modes.FIND_BACKWARD, rangefinder.closure.onCancel);
|
||||
},
|
||||
commands: function (dactyl, modules, window) {
|
||||
const { commands, rangefinder } = modules;
|
||||
commands.add(["noh[lfind]"],
|
||||
@@ -200,6 +193,17 @@ var RangeFinder = Module("rangefinder", {
|
||||
function () { rangefinder.clear(); },
|
||||
{ argCount: "0" });
|
||||
},
|
||||
commandline: function (dactyl, modules, window) {
|
||||
this.CommandMode = modules.CommandMode("CommandFindMode", {
|
||||
init: function init(mode) {
|
||||
this.mode = mode;
|
||||
},
|
||||
historyKey: "find",
|
||||
onCancel: rangefinder.closure.onCancel,
|
||||
onChange: rangefinder.closure.onKeyPress,
|
||||
onSubmit: rangefinder.closure.onSubmit
|
||||
});
|
||||
},
|
||||
mappings: function (dactyl, modules, window) {
|
||||
const { buffer, config, mappings, modes, rangefinder } = modules;
|
||||
var myModes = config.browserModes.concat([modes.CARET]);
|
||||
|
||||
@@ -61,6 +61,27 @@ var IO = Module("io", {
|
||||
services.downloadManager.addListener(this.downloadListener);
|
||||
},
|
||||
|
||||
CommandFileMode: Class("CommandFileMode", modules.CommandMode, {
|
||||
init: function init(prompt, params) {
|
||||
init.supercall(this);
|
||||
this.prompt = isArray(prompt) ? prompt : ["Question", prompt];
|
||||
update(this, params);
|
||||
},
|
||||
|
||||
historyKey: "file",
|
||||
|
||||
get mode() modules.modes.FILE_INPUT,
|
||||
|
||||
complete: function (context) {
|
||||
if (this.completer)
|
||||
this.completer(context);
|
||||
|
||||
context = context.fork("files", 0);
|
||||
modules.completion.file(context);
|
||||
context.filters = context.filters.concat(this.filters || []);
|
||||
}
|
||||
}),
|
||||
|
||||
destroy: function destroy() {
|
||||
services.downloadManager.removeListener(this.downloadListener);
|
||||
for (let [, plugin] in Iterator(plugins.contexts))
|
||||
@@ -1002,6 +1023,16 @@ unlet s:cpo_save
|
||||
}]);
|
||||
|
||||
},
|
||||
modes: function (dactyl, modules, window) {
|
||||
const { commandline, modes } = modules;
|
||||
|
||||
modes.addMode("FILE_INPUT", {
|
||||
extended: true,
|
||||
description: "Active when selecting a file",
|
||||
bases: [modes.COMMAND_LINE],
|
||||
input: true
|
||||
});
|
||||
},
|
||||
options: function (dactyl, modules, window) {
|
||||
const { options } = modules;
|
||||
|
||||
|
||||
@@ -176,6 +176,7 @@ var Overlay = Module("Overlay", {
|
||||
"io",
|
||||
"mappings",
|
||||
"marks",
|
||||
"mow",
|
||||
"options",
|
||||
"statusline",
|
||||
"styles",
|
||||
|
||||
@@ -138,7 +138,9 @@ var Template = Module("Template", {
|
||||
init.supercall(this, node);
|
||||
|
||||
let obj = params.eventTarget;
|
||||
for (let [event, handler] in Iterator(obj[this.getAttribute("events") || "events"]))
|
||||
let events = obj[this.getAttribute("events") || "events"];
|
||||
|
||||
for (let [event, handler] in Iterator(events))
|
||||
node.addEventListener(event, obj.closure(handler), false);
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user