1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2026-03-04 06:35:46 +01:00

Back out most of the changes accidentally merged from key-processing.

--HG--
extra : rebase_source : a00510584f7e13917f8496e15b7dd36852d98ea7
This commit is contained in:
Kris Maglione
2011-01-27 15:12:33 -05:00
parent 2c3fd51812
commit d16c0b0d06
47 changed files with 9350 additions and 1141 deletions

View File

@@ -115,8 +115,9 @@ var Bookmarks = Module("bookmarks", {
if (charset != null && charset !== "UTF-8")
options["-charset"] = charset;
CommandExMode().open(
commands.commandToString({ command: "bmark", options: options, arguments: [url] }) + " -keyword ");
commandline.open(":",
commands.commandToString({ command: "bmark", options: options, arguments: [url] }) + " -keyword ",
modes.EX);
},
/**
@@ -581,8 +582,9 @@ var Bookmarks = Module("bookmarks", {
options["-charset"] = content.document.characterSet;
}
CommandExMode().open(
commands.commandToString({ command: "bmark", options: options, arguments: [buffer.uri.spec] }));
commandline.open(":",
commands.commandToString({ command: "bmark", options: options, arguments: [buffer.uri.spec] }),
modes.EX);
});
mappings.add(myModes, ["A"],

View File

@@ -65,33 +65,33 @@ var Browser = Module("browser", {
mappings: function () {
mappings.add([modes.NORMAL],
["y", "<yank-location>"], "Yank current location to the clipboard",
["y"], "Yank current location to the clipboard",
function () { dactyl.clipboardWrite(buffer.uri.spec, true); });
// opening websites
mappings.add([modes.NORMAL],
["o"], "Open one or more URLs",
function () { CommandExMode().open("open "); });
function () { commandline.open(":", "open ", modes.EX); });
mappings.add([modes.NORMAL], ["O"],
"Open one or more URLs, based on current location",
function () { CommandExMode().open("open " + buffer.uri.spec); });
function () { commandline.open(":", "open " + buffer.uri.spec, modes.EX); });
mappings.add([modes.NORMAL], ["t"],
"Open one or more URLs in a new tab",
function () { CommandExMode().open("tabopen "); });
function () { commandline.open(":", "tabopen ", modes.EX); });
mappings.add([modes.NORMAL], ["T"],
"Open one or more URLs in a new tab, based on current location",
function () { CommandExMode().open("tabopen " + buffer.uri.spec); });
function () { commandline.open(":", "tabopen " + buffer.uri.spec, modes.EX); });
mappings.add([modes.NORMAL], ["w"],
"Open one or more URLs in a new window",
function () { CommandExMode().open("winopen "); });
function () { commandline.open(":", "winopen ", modes.EX); });
mappings.add([modes.NORMAL], ["W"],
"Open one or more URLs in a new window, based on current location",
function () { CommandExMode().open("winopen " + buffer.uri.spec); });
function () { commandline.open(":", "winopen " + buffer.uri.spec, modes.EX); });
mappings.add([modes.NORMAL],
["<C-a>"], "Increment last number in URL",

View File

@@ -766,25 +766,25 @@ var Buffer = Module("buffer", {
try {
window.urlSecurityCheck(uri.spec, doc.nodePrincipal);
io.CommandFileMode("Save link: ", {
onSubmit: function (path) {
let file = io.File(path);
if (file.exists() && file.isDirectory())
file.append(buffer.getDefaultNames(elem)[0][0]);
commandline.input("Save link: ", function (path) {
let file = io.File(path);
if (file.exists() && file.isDirectory())
file.append(buffer.getDefaultNames(elem)[0][0]);
try {
if (!file.exists())
file.create(File.NORMAL_FILE_TYPE, octal(644));
}
catch (e) {
util.assert(false, "Invalid destination: " + e.name);
}
try {
if (!file.exists())
file.create(File.NORMAL_FILE_TYPE, octal(644));
}
catch (e) {
util.assert(false, "Invalid destination: " + e.name);
}
buffer.saveURI(uri, file);
},
completer: function (context) completion.savePage(context, elem)
}).open();
buffer.saveURI(uri, file);
}, {
autocomplete: true,
completer: function (context) completion.savePage(context, elem),
history: "file"
});
}
catch (e) {
dactyl.echoerr(e);
@@ -1360,15 +1360,17 @@ var Buffer = Module("buffer", {
},
openUploadPrompt: function openUploadPrompt(elem) {
io.CommandFileMode("Upload file: ", {
onSubmit: function (path) {
let file = io.File(path);
dactyl.assert(file.exists());
commandline.input("Upload file: ", function (path) {
let file = io.File(path);
dactyl.assert(file.exists());
elem.value = file.path;
events.dispatch(elem, events.create(elem.ownerDocument, "change", {}));
}
}).open(elem.value);
elem.value = file.path;
events.dispatch(elem, events.create(elem.ownerDocument, "change", {}));
}, {
completer: function (context) completion.file(context),
default: elem.value,
history: "file"
});
}
}, {
commands: function () {
@@ -1528,8 +1530,7 @@ var Buffer = Module("buffer", {
if (/^>>/.test(context.filter))
context.advance(/^>>\s*/.exec(context.filter)[0].length);
completion.savePage(context, content.document);
context.fork("file", 0, completion, "file");
return completion.savePage(context, content.document);
},
literal: 0
});
@@ -1641,6 +1642,7 @@ var Buffer = Module("buffer", {
this, function (context) {
context.completions = buffer.getDefaultNames(node);
});
return context.fork("files", 0, completion, "file");
};
},
events: function () {
@@ -1651,7 +1653,7 @@ var Buffer = Module("buffer", {
mappings: function () {
var myModes = config.browserModes;
mappings.add(myModes, [".", "<repeat-key>"],
mappings.add(myModes, ["."],
"Repeat the last key event",
function (args) {
if (mappings.repeat) {
@@ -1670,31 +1672,31 @@ var Buffer = Module("buffer", {
function () { ex.stop(); });
// scrolling
mappings.add(myModes, ["j", "<Down>", "<C-e>", "<scroll-down-line>"],
mappings.add(myModes, ["j", "<Down>", "<C-e>"],
"Scroll document down",
function (args) { buffer.scrollVertical("lines", Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, ["k", "<Up>", "<C-y>", "<scroll-up-line>"],
mappings.add(myModes, ["k", "<Up>", "<C-y>"],
"Scroll document up",
function (args) { buffer.scrollVertical("lines", -Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, dactyl.has("mail") ? ["h", "<scroll-left-column>"] : ["h", "<Left>", "<scroll-left-column>"],
mappings.add(myModes, dactyl.has("mail") ? ["h"] : ["h", "<Left>"],
"Scroll document to the left",
function (args) { buffer.scrollHorizontal("columns", -Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, dactyl.has("mail") ? ["l", "<scroll-right-column>"] : ["l", "<Right>", "<scroll-right-column>"],
mappings.add(myModes, dactyl.has("mail") ? ["l"] : ["l", "<Right>"],
"Scroll document to the right",
function (args) { buffer.scrollHorizontal("columns", Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, ["0", "^", "<scroll-begin>"],
mappings.add(myModes, ["0", "^"],
"Scroll to the absolute left of the document",
function () { buffer.scrollToPercent(0, null); });
mappings.add(myModes, ["$", "<scroll-end>"],
mappings.add(myModes, ["$"],
"Scroll to the absolute right of the document",
function () { buffer.scrollToPercent(100, null); });
@@ -1708,7 +1710,7 @@ var Buffer = Module("buffer", {
function (args) { buffer.scrollToPercent(null, args.count != null ? args.count : 100); },
{ count: true });
mappings.add(myModes, ["%", "<scroll-percent>"],
mappings.add(myModes, ["%"],
"Scroll to {count} percent of the document",
function (args) {
dactyl.assert(args.count > 0 && args.count <= 100);
@@ -1716,59 +1718,59 @@ var Buffer = Module("buffer", {
},
{ count: true });
mappings.add(myModes, ["<C-d>", "<scroll-down>"],
mappings.add(myModes, ["<C-d>"],
"Scroll window downwards in the buffer",
function (args) { buffer._scrollByScrollSize(args.count, true); },
{ count: true });
mappings.add(myModes, ["<C-u>", "<scroll-up>"],
mappings.add(myModes, ["<C-u>"],
"Scroll window upwards in the buffer",
function (args) { buffer._scrollByScrollSize(args.count, false); },
{ count: true });
mappings.add(myModes, ["<C-b>", "<PageUp>", "<S-Space>", "<scroll-page-up>"],
mappings.add(myModes, ["<C-b>", "<PageUp>", "<S-Space>"],
"Scroll up a full page",
function (args) { buffer.scrollVertical("pages", -Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, ["<C-f>", "<PageDown>", "<Space>", "<scroll-page-down>"],
mappings.add(myModes, ["<C-f>", "<PageDown>", "<Space>"],
"Scroll down a full page",
function (args) { buffer.scrollVertical("pages", Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, ["]f", "<previous-frame>"],
mappings.add(myModes, ["]f"],
"Focus next frame",
function (args) { buffer.shiftFrameFocus(Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, ["[f", "<next-frame>"],
mappings.add(myModes, ["[f"],
"Focus previous frame",
function (args) { buffer.shiftFrameFocus(-Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, ["]]", "<next-page>"],
mappings.add(myModes, ["]]"],
"Follow the link labeled 'next' or '>' if it exists",
function (args) {
buffer.findLink("next", options["nextpattern"], (args.count || 1) - 1, true);
},
{ count: true });
mappings.add(myModes, ["[[", "<previous-page>"],
mappings.add(myModes, ["[["],
"Follow the link labeled 'prev', 'previous' or '<' if it exists",
function (args) {
buffer.findLink("previous", options["previouspattern"], (args.count || 1) - 1, true);
},
{ count: true });
mappings.add(myModes, ["gf", "<view-source>"],
mappings.add(myModes, ["gf"],
"Toggle between rendered and source view",
function () { buffer.viewSource(null, false); });
mappings.add(myModes, ["gF", "<view-source-externally>"],
mappings.add(myModes, ["gF"],
"View source with an external editor",
function () { buffer.viewSource(null, true); });
mappings.add(myModes, ["gi", "<focus-input>"],
mappings.add(myModes, ["gi"],
"Focus last used input field",
function (args) {
let elem = buffer.lastInputField;
@@ -1808,7 +1810,7 @@ var Buffer = Module("buffer", {
dactyl.open(url, { from: "paste", where: dactyl.NEW_TAB, background: true });
});
mappings.add(myModes, ["p", "<MiddleMouse>", "<open-clipboard-url>"],
mappings.add(myModes, ["p", "<MiddleMouse>"],
"Open (put) a URL based on the current clipboard contents in the current buffer",
function () {
let url = dactyl.clipboardRead();
@@ -1816,7 +1818,7 @@ var Buffer = Module("buffer", {
dactyl.open(url);
});
mappings.add(myModes, ["P", "<tab-open-clipboard-url>"],
mappings.add(myModes, ["P"],
"Open (put) a URL based on the current clipboard contents in a new buffer",
function () {
let url = dactyl.clipboardRead();
@@ -1825,16 +1827,16 @@ var Buffer = Module("buffer", {
});
// reloading
mappings.add(myModes, ["r", "<reload>"],
mappings.add(myModes, ["r"],
"Reload the current web page",
function () { tabs.reload(tabs.getTab(), false); });
mappings.add(myModes, ["R", "<full-reload>"],
mappings.add(myModes, ["R"],
"Reload while skipping the cache",
function () { tabs.reload(tabs.getTab(), true); });
// yanking
mappings.add(myModes, ["Y", "<yank-word>"],
mappings.add(myModes, ["Y"],
"Copy selected text or current word",
function () {
let sel = buffer.getCurrentWord();
@@ -1843,62 +1845,62 @@ var Buffer = Module("buffer", {
});
// zooming
mappings.add(myModes, ["zi", "+", "<text-zoom-in>"],
mappings.add(myModes, ["zi", "+"],
"Enlarge text zoom of current web page",
function (args) { buffer.zoomIn(Math.max(args.count, 1), false); },
{ count: true });
mappings.add(myModes, ["zm", "<text-zoom-more>"],
mappings.add(myModes, ["zm"],
"Enlarge text zoom of current web page by a larger amount",
function (args) { buffer.zoomIn(Math.max(args.count, 1) * 3, false); },
{ count: true });
mappings.add(myModes, ["zo", "-", "<text-zoom-out>"],
mappings.add(myModes, ["zo", "-"],
"Reduce text zoom of current web page",
function (args) { buffer.zoomOut(Math.max(args.count, 1), false); },
{ count: true });
mappings.add(myModes, ["zr", "<text-zoom-reduce>"],
mappings.add(myModes, ["zr"],
"Reduce text zoom of current web page by a larger amount",
function (args) { buffer.zoomOut(Math.max(args.count, 1) * 3, false); },
{ count: true });
mappings.add(myModes, ["zz", "<text-zoom>"],
mappings.add(myModes, ["zz"],
"Set text zoom value of current web page",
function (args) { buffer.setZoom(args.count > 1 ? args.count : 100, false); },
{ count: true });
mappings.add(myModes, ["ZI", "zI", "<full-zoom-in>"],
mappings.add(myModes, ["ZI", "zI"],
"Enlarge full zoom of current web page",
function (args) { buffer.zoomIn(Math.max(args.count, 1), true); },
{ count: true });
mappings.add(myModes, ["ZM", "zM", "<full-zoom-more>"],
mappings.add(myModes, ["ZM", "zM"],
"Enlarge full zoom of current web page by a larger amount",
function (args) { buffer.zoomIn(Math.max(args.count, 1) * 3, true); },
{ count: true });
mappings.add(myModes, ["ZO", "zO", "<full-zoom-out>"],
mappings.add(myModes, ["ZO", "zO"],
"Reduce full zoom of current web page",
function (args) { buffer.zoomOut(Math.max(args.count, 1), true); },
{ count: true });
mappings.add(myModes, ["ZR", "zR", "<full-zoom-reduce>"],
mappings.add(myModes, ["ZR", "zR"],
"Reduce full zoom of current web page by a larger amount",
function (args) { buffer.zoomOut(Math.max(args.count, 1) * 3, true); },
{ count: true });
mappings.add(myModes, ["zZ", "<full-zoom>"],
mappings.add(myModes, ["zZ"],
"Set full zoom value of current web page",
function (args) { buffer.setZoom(args.count > 1 ? args.count : 100, true); },
{ count: true });
// page info
mappings.add(myModes, ["<C-g>", "<page-info>"],
mappings.add(myModes, ["<C-g>"],
"Print the current file name",
function () { buffer.showPageInfo(false); });
mappings.add(myModes, ["g<C-g>", "<more-page-info>"],
mappings.add(myModes, ["g<C-g>"],
"Print file information",
function () { buffer.showPageInfo(true); });
},

File diff suppressed because it is too large Load Diff

View File

@@ -40,15 +40,11 @@ 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 () {
@@ -1131,7 +1127,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
});
params = params || {};
if (isString(params))
if (isArray(params))
params = { where: params };
let flags = 0;
@@ -1319,8 +1315,6 @@ 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) {

View File

@@ -11,17 +11,15 @@
var ProcessorStack = Class("ProcessorStack", {
init: function (mode, hives, keyModes) {
this.main = mode.main;
this._actions = [];
this.actions = [];
this.buffer = "";
this.events = [];
this.processors = keyModes.map(function (m) hives.map(function (h) KeyProcessor(m, h)))
.flatten().array;
this.ownsBuffer = !this.processors.some(function (p) p.main.ownsBuffer);
for (let [i, input] in Iterator(this.processors)) {
let params = input.main.params;
let params = input.main == mode.main ? mode.params : input.main.params;
if (params.preExecute)
input.preExecute = params.preExecute;
if (params.postExecute)
@@ -33,70 +31,9 @@ var ProcessorStack = Class("ProcessorStack", {
}
},
notify: function () {
this.execute(Events.KILL, true);
},
execute: function execute(result, force) {
if (force && this.actions.length)
this.processors.length = 0;
if (this.ownsBuffer)
statusline.updateInputBuffer(this.processors.length ? this.buffer : "");
if (this.processors.length) {
result = Events.KILL;
if (this.actions.length && options["timeout"])
this.timer = services.Timer(this, options["timeoutlen"], services.Timer.TYPE_ONE_SHOT);
}
else if (this.actions.length) {
if (this._actions.length == 0) {
dactyl.beep();
events.feedingKeys = false;
}
for (var res = this.actions[0]; callable(res);)
res = res();
result = res === Events.PASS ? Events.PASS : Events.KILL;
}
else if (result !== Events.KILL && !this.actions.length &&
this.processors.some(function (p) !p.main.passUnknown)) {
result = Events.KILL;
dactyl.beep();
events.feedingKeys = false;
}
else if (result === undefined)
result = Events.PASS;
if (result !== Events.PASS)
Events.kill(this.events[this.events.length - 1]);
if (result === Events.PASS || result === Events.ABORT)
this.events.filter(function (e) e.getPreventDefault())
.forEach(function (event, i) {
let elem = event.originalTarget;
if (event.originalTarget) {
let doc = elem.ownerDocument || elem.document || elem;
let evt = events.create(doc, event.type, event);
events.dispatch(elem, evt, { skipmap: true, isMacro: true, isReplay: true });
}
else if (i > 0)
events.events.keypress.call(events, event);
});
if (force && this.processors.length === 0)
events.processor = null;
return this.processors.length == 0;
},
process: function process(event) {
function dbg() {}
if (this.timer)
this.timer.cancel();
let key = events.toString(event);
this.events.push(event);
@@ -133,7 +70,9 @@ var ProcessorStack = Class("ProcessorStack", {
dbg("ACTIONS: " + actions.length + " " + this.actions.length);
dbg("PROCESSORS:", processors);
this._actions = actions;
if (!processors.some(function (p) p.main.ownsBuffer))
statusline.updateInputBuffer(processors.length ? this.buffer : "");
this.actions = actions.concat(this.actions);
if (result === Events.KILL)
@@ -148,7 +87,41 @@ var ProcessorStack = Class("ProcessorStack", {
this.processors = processors;
return this.execute(result, options["timeout"] && options["timeoutlen"] === 0)
if (processors.length)
result = Events.KILL;
else if (this.actions.length) {
if (actions.length == 0)
dactyl.beep();
if (modes.replaying && !events.waitForPageLoad())
result = Events.KILL;
else {
for (var res = this.actions[0]; callable(res);)
res = res();
result = res === Events.PASS ? Events.PASS : Events.KILL;
}
}
else if (result !== Events.KILL && processors.some(function (p) !p.main.passUnknown)) {
result = Events.KILL;
dactyl.beep();
}
else if (result === undefined)
result = Events.PASS;
if (result !== Events.PASS)
Events.kill(event);
if (result === Events.PASS || result === Events.ABORT)
this.events.filter(function (e) e.getPreventDefault())
.forEach(function (event, i) {
if (event.originalTarget) {
let evt = events.create(event.originalTarget.ownerDocument, event.type, event);
events.dispatch(event.originalTarget, evt, { skipmap: true, isMacro: true });
}
else if (i > 0)
events.events.keypress.call(events, event);
});
return this.processors.length == 0;
}
});
@@ -184,13 +157,12 @@ var KeyProcessor = Class("KeyProcessor", {
return this.onKeyPress(event);
},
execute: function execute(map, args)
let (self = this)
execute: function execute(map)
let (self = this, args = arguments)
function execute() {
if (self.preExecute)
self.preExecute.apply(self, args);
let res = map.execute.call(map, update({ self: self.main.params.mappingSelf || self.main.mappingSelf || map },
args))
let res = map.execute.apply(map, Array.slice(args, 1));
if (self.postExecute)
self.postExecute.apply(self, args);
return res;
@@ -515,7 +487,6 @@ var Events = Module("events", {
util.threadYield(1, true);
for (let [, evt_obj] in Iterator(events.fromString(keys))) {
let now = Date.now();
for (let type in values(["keydown", "keyup", "keypress"])) {
let evt = update({}, evt_obj, { type: type });
@@ -616,14 +587,9 @@ var Events = Module("events", {
* of x.
*
* @param {string} keys Messy form.
* @param {boolean} unknownOk Whether unknown keys are passed
* through rather than being converted to <lt>keyname>.
* @default false
* @returns {string} Canonical form.
*/
canonicalKeys: function (keys, unknownOk) {
if (arguments.length === 1)
unknownOk = true;
return events.fromString(keys, unknownOk).map(events.closure.toString).join("");
},
@@ -678,17 +644,11 @@ var Events = Module("events", {
* <S-@> where @ is a non-case-changeable, non-space character.
*
* @param {string} keys The string to parse.
* @param {boolean} unknownOk Whether unknown keys are passed
* through rather than being converted to <lt>keyname>.
* @default false
* @returns {Array[Object]}
*/
fromString: function (input, unknownOk) {
if (arguments.length === 1)
unknownOk = true;
let out = [];
let re = RegExp("<.*?>?>|[^<]|<(?!.*>)", "g");
let match;
while ((match = re.exec(input))) {
@@ -895,7 +855,10 @@ var Events = Module("events", {
isContentNode: function isContentNode(node) {
let win = (node.ownerDocument || node).defaultView || node;
return XPCNativeWrapper(win).top == content;
for (; win; win = win.parent != win && win.parent)
if (win == content)
return true;
return false;
},
/**
@@ -904,24 +867,39 @@ var Events = Module("events", {
*
* @returns {boolean}
*/
waitForPageLoad: function (time) {
waitForPageLoad: function () {
util.threadYield(true); // clear queue
if (buffer.loaded)
if (buffer.loaded == 1)
return true;
dactyl.echo("Waiting for page to load...", commandline.DISALLOW_MULTILINE);
const maxWaitTime = (time || 25);
const maxWaitTime = 25;
let start = Date.now();
let end = start + (maxWaitTime * 1000);
let end = start + (maxWaitTime * 1000); // maximum time to wait - TODO: add option
let now;
while (now = Date.now(), now < end) {
util.threadYield();
util.waitFor(function () !events.feedingKeys || buffer.loaded || Date.now() > end);
if (!events.feedingKeys)
return false;
if (buffer.loaded > 0) {
util.sleep(250);
break;
}
else
dactyl.echo("Waiting for page to load...", commandline.DISALLOW_MULTILINE);
}
commandline.clear();
// TODO: allow macros to be continued when page does not fully load with an option
if (!buffer.loaded)
dactyl.echoerr("Page did not load completely in " + maxWaitTime + " seconds. Macro stopped.");
// sometimes the input widget had focus when replaying a macro
// maybe this call should be moved somewhere else?
// dactyl.focusContent(true);
return buffer.loaded;
},
@@ -1014,8 +992,7 @@ var Events = Module("events", {
*/
input: function onInput(event) {
if ("dactylKeyPress" in event.originalTarget)
delete event.originalTarget.dactylKeyPress;
delete event.originalTarget.dactylKeyPress;
},
// this keypress handler gets always called first, even if e.g.
@@ -1039,17 +1016,18 @@ var Events = Module("events", {
let duringFeed = this.duringFeed || [];
this.duringFeed = [];
try {
if (this.feedingEvent)
if (this.feedingEvent && [!(k in event) || event[k] === v for ([k, v] in Iterator(this.feedingEvent))].every(util.identity)) {
for (let [k, v] in Iterator(this.feedingEvent))
if (!(k in event))
event[k] = v;
this.feedingEvent = null;
this.feedingEvent = null;
}
let key = events.toString(event);
if (!key)
return null;
if (modes.recording && !event.isReplay)
if (modes.recording && (!this._input || !mappings.user.hasMap(modes.main, this._input.buffer + key)))
events._macroKeys.push(key);
// feedingKeys needs to be separate from interrupted so
@@ -1057,6 +1035,8 @@ var Events = Module("events", {
// interrupting whatever it's started and a real <C-c>
// interrupting our playback.
if (events.feedingKeys && !event.isMacro) {
if (!event.originalTarget)
util.dumpStack();
if (key == "<C-c>") {
events.feedingKeys = false;
if (modes.replaying) {
@@ -1106,8 +1086,7 @@ var Events = Module("events", {
let hives = mappings.hives.slice(event.noremap ? -1 : 0);
let main = { __proto__: mode.main, params: mode.params };
let keyModes = array([mode.params.keyModes, main, mode.main.allBases]).flatten().compact();
let keyModes = array([mode.params.keyModes, mode.main, mode.main.allBases]).flatten().compact();
this.processor = ProcessorStack(mode, hives, keyModes);
}
@@ -1189,6 +1168,10 @@ var Events = Module("events", {
// access to the real focus target
// Huh? --djk
onFocusChange: function onFocusChange(event) {
// command line has its own focus change handler
if (modes.main == modes.COMMAND_LINE)
return;
function hasHTMLDocument(win) win && win.document && win.document instanceof HTMLDocument
let win = window.document.commandDispatcher.focusedWindow;
@@ -1210,7 +1193,7 @@ var Events = Module("events", {
}
if (Events.isInputElement(elem)) {
if (!modes.main.input)
if (!(modes.main & (modes.INSERT | modes.TEXT_EDIT | modes.VISUAL)))
modes.push(modes.INSERT);
if (hasHTMLDocument(win))
@@ -1224,7 +1207,7 @@ var Events = Module("events", {
if (modes.main == modes.VISUAL && elem.selectionEnd == elem.selectionStart)
modes.pop();
if (!modes.main.input)
if (!(modes.main & (modes.INSERT | modes.TEXT_EDIT | modes.VISUAL)))
if (options["insertmode"])
modes.push(modes.INSERT);
else {
@@ -1330,59 +1313,39 @@ var Events = Module("events", {
};
},
mappings: function () {
mappings.add(modes.MAIN,
["<C-z>", "<pass-all-keys>"], "Temporarily ignore all " + config.appName + " key bindings",
mappings.add(modes.all,
["<C-z>"], "Temporarily ignore all " + config.appName + " key bindings",
function () { modes.push(modes.PASS_THROUGH); });
mappings.add(modes.MAIN,
["<C-v>", "<pass-next-key>"], "Pass through next key",
mappings.add(modes.all,
["<C-v>"], "Pass through next key",
function () {
if (modes.main == modes.QUOTE)
return Events.PASS;
modes.push(modes.QUOTE);
});
mappings.add(modes.BASE,
mappings.add(modes.all,
["<Nop>"], "Do nothing",
function () {});
// macros
mappings.add([modes.COMMAND],
["q", "<record-macro>"], "Record a key sequence into a macro",
mappings.add([modes.NORMAL, modes.TEXT_AREA, modes.PLAYER].filter(util.identity),
["q"], "Record a key sequence into a macro",
function ({ arg }) {
events._macroKeys.pop();
events[modes.recording ? "finishRecording" : "startRecording"](arg);
},
{ get arg() !modes.recording });
mappings.add([modes.COMMAND],
["@", "<play-macro>"], "Play a macro",
mappings.add([modes.NORMAL, modes.TEXT_AREA, modes.PLAYER].filter(util.identity),
["@"], "Play a macro",
function ({ arg, count }) {
count = Math.max(count, 1);
while (count-- && events.playMacro(arg))
;
},
{ arg: true, count: true });
mappings.add([modes.COMMAND],
["<A-m>s", "<sleep>"], "Sleep for {count} milliseconds before continuing macro playback",
function ({ command, count }) {
let now = Date.now();
dactyl.assert(count, "Count required for " + command);
if (events.feedingKeys)
util.sleep(count);
},
{ count: true });
mappings.add([modes.COMMAND],
["<A-m>l", "<wait-for-page-load>"], "Wait for the current page to finish loading before continuing macro playback",
function ({ count }) {
if (events.feedingKeys && !events.waitForPageLoad(count)) {
util.interrupted = true;
throw Error("Interrupted");
}
},
{ count: true });
},
options: function () {
options.add(["passkeys", "pk"],
@@ -1403,18 +1366,9 @@ var Events = Module("events", {
return values;
}
});
options.add(["strictfocus", "sf"],
"Prevent scripts from focusing input elements without user intervention",
"boolean", true);
options.add(["timeout", "tmo"],
"Whether to execute a shorter key command after a timeout when a longer command exists",
"boolean", true);
options.add(["timeoutlen", "tmol"],
"Maximum time (milliseconds) to wait for a longer key command when a shorter one exists",
"number", 1000);
},
sanitizer: function () {
sanitizer.addItem("macros", {

View File

@@ -9,18 +9,16 @@
/** @scope modules */
/** @instance hints */
var HintSession = Class("HintSession", CommandMode, {
var HintSession = Class("HintSession", {
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.hintMode = hints.modes[mode];
dactyl.assert(this.hintMode);
this.mode = hints.modes[mode];
dactyl.assert(this.mode);
this.activeTimeout = null; // needed for hinttimeout > 0
this.continue = Boolean(opts.continue);
@@ -33,7 +31,8 @@ var HintSession = Class("HintSession", CommandMode, {
this.usedTabKey = false;
this.validHints = []; // store the indices of the "hints" array with valid elements
this.open();
commandline.input(UTF8(this.mode.prompt) + ": ", null, this.closure);
modes.extended = modes.HINTS;
this.top = opts.window || content;
this.top.addEventListener("resize", hints.resizeTimer.closure.tell, true);
@@ -52,22 +51,7 @@ var HintSession = Class("HintSession", CommandMode, {
this.checkUnique();
},
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);
}
},
get extended() modes.HINTS,
checkUnique: function _checkUnique() {
if (this.hintNumber == 0)
@@ -252,7 +236,7 @@ var HintSession = Class("HintSession", CommandMode, {
let baseNodeAbsolute = util.xmlToDom(<span highlight="Hint" style="display: none"/>, doc);
let mode = this.hintMode;
let mode = this.mode;
let res = util.evaluateXPath(mode.xpath, doc, true);
let start = this.pageHints.length;
@@ -305,6 +289,18 @@ var HintSession = Class("HintSession", CommandMode, {
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.
*
@@ -433,7 +429,7 @@ var HintSession = Class("HintSession", CommandMode, {
if ((modes.extended & modes.HINTS) && !this.continue)
modes.pop();
commandline.lastEcho = null; // Hack.
dactyl.trapErrors("action", this.hintMode,
dactyl.trapErrors(this.mode.action, this.mode,
elem, elem.href || elem.src || "",
this.extendedhintCount, top);
if (this.continue && this.top)
@@ -666,7 +662,6 @@ 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);
@@ -686,9 +681,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) 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("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("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));
@@ -957,19 +952,20 @@ var Hints = Module("hints", {
open: function open(mode, opts) {
this._extendedhintCount = opts.count;
commandline.input(["Normal", mode], "", {
commandline.input(mode, null, {
completer: function (context) {
context.compare = function () 0;
context.completions = [[k, v.prompt] for ([k, v] in Iterator(hints.modes))];
},
onSubmit: function (arg) {
onAccept: function (arg) {
if (arg)
hints.show(arg, opts);
},
onChange: function () {
this.accepted = true;
modes.pop();
util.timeout(function () {
dactyl.trapErrors(hints.show, hints, arg, opts);
});
},
get onCancel() this.onAccept,
onChange: function () { modes.pop(); },
promptHighlight: "Normal"
});
},
@@ -1079,15 +1075,6 @@ 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"],
@@ -1110,23 +1097,25 @@ var Hints = Module("hints", {
mappings.add(modes.HINTS, ["<Return>"],
"Follow the selected hint",
function ({ self }) { self.update(true); });
function () { hints.hintSession.update(true); });
mappings.add(modes.HINTS, ["<Tab>"],
"Focus the next matching hint",
function ({ self }) { self.tab(false); });
function () { hints.hintSession.tab(false); });
mappings.add(modes.HINTS, ["<S-Tab>"],
"Focus the previous matching hint",
function ({ self }) { self.tab(true); });
function () { hints.hintSession.tab(true); });
mappings.add(modes.HINTS, ["<BS>", "<C-h>"],
"Delete the previous character",
function ({ self }) self.backspace());
function () hints.hintSession.backspace());
mappings.add(modes.HINTS, ["<Leader>"],
"Toggle hint filtering",
function ({ self }) { self.escapeNumbers = !self.escapeNumbers; });
function () {
hints.hintSession.escapeNumbers = !hints.hintSession.escapeNumbers;
});
},
options: function () {
const DEFAULT_HINTTAGS =

View File

@@ -113,17 +113,9 @@ var Map = Class("Map", {
if (this.executing)
util.dumpStack("Attempt to execute mapping recursively: " + args.command);
dactyl.assert(!this.executing, "Attempt to execute mapping recursively: " + args.command);
try {
this.executing = true;
var res = repeat();
}
catch (e) {
events.feedingKeys = false;
}
finally {
this.executing = false;
}
this.executing = true;
let res = dactyl.trapErrors(repeat);
this.executing = false;
return res;
}
@@ -303,8 +295,6 @@ 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),

View File

@@ -119,6 +119,12 @@ 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,
@@ -154,9 +160,31 @@ 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,
input: true
});
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) {
@@ -186,9 +214,9 @@ var Modes = Module("modes", {
_getModeMessage: function () {
// when recording a macro
let macromode = "";
if (this.recording)
if (modes.recording)
macromode = "recording";
else if (this.replaying)
else if (modes.replaying)
macromode = "replaying";
let val = this._modeMap[this._main].display();
@@ -264,11 +292,11 @@ var Modes = Module("modes", {
delayed: [],
delay: function (callback, self) { this.delayed.push([callback, self]); },
save: function save(id, obj, prop, test) {
save: function save(id, obj, prop) {
if (!(id in this.boundProperties))
for (let elem in array.iterValues(this._modeStack))
elem.saved[id] = { obj: obj, prop: prop, value: obj[prop], test: test };
this.boundProperties[id] = { obj: Cu.getWeakReference(obj), prop: prop, test: test };
elem.saved[id] = { obj: obj, prop: prop, value: obj[prop] };
this.boundProperties[id] = { obj: Cu.getWeakReference(obj), prop: prop };
},
// helper function to set both modes in one go
@@ -289,26 +317,22 @@ var Modes = Module("modes", {
}
if (stack && stack.pop && stack.pop.params.leave)
dactyl.trapErrors("leave", stack.pop.params,
stack, this.topOfStack);
stack.pop.params.leave(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)
dactyl.trapErrors("leave", this.topOfStack.params,
{ push: push }, push);
for (let [id, { obj, prop, test }] in Iterator(this.boundProperties)) {
this.topOfStack.params.leave({ push: push }, push);
for (let [id, { obj, prop }] in Iterator(this.boundProperties)) {
if (!obj.get())
delete this.boundProperties[id];
else
this.topOfStack.saved[id] = { obj: obj.get(), prop: prop, value: obj.get()[prop], test: test };
this.topOfStack.saved[id] = { obj: obj.get(), prop: prop, value: obj.get()[prop] };
}
}
let delayed = this.delayed;
this.delayed.forEach(function ([fn, self]) fn.call(self));
this.delayed = [];
let prev = stack && stack.pop || this.topOfStack;
@@ -316,18 +340,12 @@ var Modes = Module("modes", {
this._modeStack.push(push);
if (stack && stack.pop)
for (let { obj, prop, value, test } in values(this.topOfStack.saved))
if (!test || !test(stack, prev))
obj[prop] = value;
this.show();
delayed.forEach(function ([fn, self]) dactyl.trapErrors(fn, self));
for (let { obj, prop, value } in values(this.topOfStack.saved))
obj[prop] = value;
if (this.topOfStack.params.enter && prev)
dactyl.trapErrors("enter", this.topOfStack.params,
push ? { push: push } : stack || {},
prev);
this.topOfStack.params.enter(push ? { push: push } : stack || {},
prev);
dactyl.triggerObserver("modeChange", [oldMain, oldExtended], [this._main, this._extended], stack);
this.show();
@@ -421,7 +439,7 @@ var Modes = Module("modes", {
input: false,
get passUnknown() this.input,
passUnknown: false,
get mask() this,
@@ -458,7 +476,7 @@ var Modes = Module("modes", {
return val === undefined ? value : val;
},
set: function (val) {
modes.save(id, this, prop, desc.test);
modes.save(id, this, prop);
if (desc.set)
value = desc.set.call(this, val);
value = !desc.set || value === undefined ? val : value;

View File

@@ -1,358 +0,0 @@
// 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 () {
let fontSize = util.computedStyle(document.documentElement).fontSize;
styles.system.add("font-size", "dactyl://content/buffer.xhtml",
"body { font-size: " + fontSize + "; } \
html|html > xul|scrollbar { visibility: collapse !important; }",
true);
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);
}
});

View File

@@ -910,7 +910,7 @@ var Tabs = Module("tabs", {
if (count != null)
tabs.switchTo(String(count));
else
CommandExMode.open("buffer! ");
commandline.open(":", "buffer! ", modes.EX);
},
{ count: true });