1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-21 17:07:58 +01:00

Add real mappings for most HINT mode keys. Lazily expand leader, and keep in sync with 'mapleader'.

--HG--
branch : bootstrapped
This commit is contained in:
Kris Maglione
2010-12-28 14:33:57 -05:00
parent 83aa5e4857
commit 9655d741b8
8 changed files with 166 additions and 132 deletions

View File

@@ -1021,11 +1021,10 @@ var Buffer = Module("buffer", {
this.callback(file); this.callback(file);
else { else {
this.file = io.createTempFile(); this.file = io.createTempFile();
var webBrowserPersist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] var persist = services.Persist();
.createInstance(Ci.nsIWebBrowserPersist); persist.persistFlags = persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
webBrowserPersist.persistFlags = webBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES; persist.progressListener = this;
webBrowserPersist.progressListener = this; persist.saveURI(uri, null, null, null, null, this.file);
webBrowserPersist.saveURI(uri, null, null, null, null, this.file);
} }
return null; return null;
}, },

View File

@@ -757,9 +757,6 @@ var CommandLine = Module("commandline", {
* the MOW. * the MOW.
*/ */
echo: function echo(str, highlightGroup, flags) { echo: function echo(str, highlightGroup, flags) {
if (String(str) == "undefined")
util.dumpStack();
// dactyl.echo uses different order of flags as it omits the highlight group, change commandline.echo argument order? --mst // dactyl.echo uses different order of flags as it omits the highlight group, change commandline.echo argument order? --mst
if (this._silent) if (this._silent)
return; return;

View File

@@ -2131,12 +2131,12 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
dactyl.log("All modules loaded", 3); dactyl.log("All modules loaded", 3);
AddonManager.getAddonByID(services["dactyl:"].addonID, function (addon) { AddonManager.getAddonByID(services["dactyl:"].addonID, this.wrapCallback(function (addon) {
// @DATE@ token replaced by the Makefile // @DATE@ token replaced by the Makefile
// TODO: Find it automatically // TODO: Find it automatically
prefs.set("extensions.dactyl.version", addon.version); prefs.set("extensions.dactyl.version", addon.version);
dactyl.version = addon.version + " (created: @DATE@)"; dactyl.version = addon.version + " (created: @DATE@)";
}); }));
if (!services.commandLineHandler) if (!services.commandLineHandler)
services.add("commandLineHandler", "@mozilla.org/commandlinehandler/general-startup;1?type=" + config.name); services.add("commandLineHandler", "@mozilla.org/commandlinehandler/general-startup;1?type=" + config.name);

View File

@@ -47,19 +47,29 @@ var Events = Module("events", {
this._keyTable = { this._keyTable = {
add: ["Plus", "Add"], add: ["Plus", "Add"],
back_space: ["BS"], back_space: ["BS"],
count: ["count"],
delete: ["Del"], delete: ["Del"],
escape: ["Esc", "Escape"], escape: ["Esc", "Escape"],
insert: ["Insert", "Ins"], insert: ["Insert", "Ins"],
leader: ["Leader"],
left_shift: ["LT", "<"], left_shift: ["LT", "<"],
nop: ["Nop"],
return: ["Return", "CR", "Enter"], return: ["Return", "CR", "Enter"],
right_shift: [">"], right_shift: [">"],
space: ["Space", " "], space: ["Space", " "],
subtract: ["Minus", "Subtract"] subtract: ["Minus", "Subtract"]
}; };
this._pseudoKeys = set(["count", "leader", "nop"]);
this._key_key = {};
this._code_key = {}; this._code_key = {};
this._key_code = {}; this._key_code = {};
for (let list in values(this._keyTable))
for (let v in values(list))
this._key_key[v.toLowerCase()] = v;
for (let [k, v] in Iterator(KeyEvent)) { for (let [k, v] in Iterator(KeyEvent)) {
k = k.substr(7).toLowerCase(); k = k.substr(7).toLowerCase();
let names = [k.replace(/(^|_)(.)/g, function (m, n1, n2) n2.toUpperCase()) let names = [k.replace(/(^|_)(.)/g, function (m, n1, n2) n2.toUpperCase())
@@ -67,8 +77,10 @@ var Events = Module("events", {
if (k in this._keyTable) if (k in this._keyTable)
names = this._keyTable[k]; names = this._keyTable[k];
this._code_key[v] = names[0]; this._code_key[v] = names[0];
for (let [, name] in Iterator(names)) for (let [, name] in Iterator(names)) {
this._key_key[name.toLowerCase()] = name;
this._key_code[name.toLowerCase()] = v; this._key_code[name.toLowerCase()] = v;
}
} }
// HACK: as Gecko does not include an event for <, we must add this in manually. // HACK: as Gecko does not include an event for <, we must add this in manually.
@@ -436,7 +448,7 @@ var Events = Module("events", {
keyname = String.fromCharCode(parseInt(keyname.substr(1), 16)); keyname = String.fromCharCode(parseInt(keyname.substr(1), 16));
if (keyname && (unknownOk || keyname.length == 1 || /mouse$/.test(keyname) || if (keyname && (unknownOk || keyname.length == 1 || /mouse$/.test(keyname) ||
this._key_code[keyname] || keyname == "nop")) { this._key_code[keyname] || set.has(this._pseudoKeys, keyname))) {
evt_obj.ctrlKey = /C-/.test(modifier); evt_obj.ctrlKey = /C-/.test(modifier);
evt_obj.altKey = /A-/.test(modifier); evt_obj.altKey = /A-/.test(modifier);
evt_obj.shiftKey = /S-/.test(modifier); evt_obj.shiftKey = /S-/.test(modifier);
@@ -451,8 +463,8 @@ var Events = Module("events", {
evt_obj.charCode = keyname.charCodeAt(0); evt_obj.charCode = keyname.charCodeAt(0);
} }
else if (keyname == "nop") { else if (set.has(this._pseudoKeys)) {
evt_obj.dactylString = "<Nop>"; evt_obj.dactylString = "<" + this._key_key[keyname] + ">";
} }
else if (/mouse$/.test(keyname)) { // mouse events else if (/mouse$/.test(keyname)) { // mouse events
evt_obj.type = (/2-/.test(modifier) ? "dblclick" : "click"); evt_obj.type = (/2-/.test(modifier) ? "dblclick" : "click");
@@ -576,7 +588,7 @@ var Events = Module("events", {
} }
} }
if (key == null) if (key == null)
key = event.dactylKeyname; key = this._key_key[event.dactylKeyname] || event.dactylKeyname;
if (key == null) if (key == null)
return null; return null;
} }
@@ -1070,9 +1082,9 @@ var Events = Module("events", {
const self = this; const self = this;
let key = events.toString(event); let key = events.toString(event);
let [, countStr, candidateCommand] = /^((?:[1-9][0-9]*)?)(.*)/.exec(this.buffer + key); let [, countStr, command] = /^((?:[1-9][0-9]*)?)(.*)/.exec(this.buffer + key);
let map = mappings[event.noremap ? "getDefault" : "get"](this.main, candidateCommand); let map = mappings[event.noremap ? "getDefault" : "get"](this.main, command);
function execute(map) { function execute(map) {
if (self.preExecute) if (self.preExecute)
@@ -1083,7 +1095,7 @@ var Events = Module("events", {
return res; return res;
} }
let candidates = mappings.getCandidates(this.main, candidateCommand); let candidates = mappings.getCandidates(this.main, command);
if (candidates.length == 0 && !map) { if (candidates.length == 0 && !map) {
map = this.pendingMap; map = this.pendingMap;
this.pendingMap = null; this.pendingMap = null;
@@ -1092,7 +1104,7 @@ var Events = Module("events", {
} }
// counts must be at the start of a complete mapping (10j -> go 10 lines down) // counts must be at the start of a complete mapping (10j -> go 10 lines down)
if (countStr && !candidateCommand) { if (countStr && !command) {
// no count for insert mode mappings // no count for insert mode mappings
if (!this.main.count) if (!this.main.count)
return this.append(event); return this.append(event);
@@ -1102,9 +1114,9 @@ var Events = Module("events", {
this.append(event); this.append(event);
} }
else if (this.pendingArgMap) { else if (this.pendingArgMap) {
let map = this.pendingArgMap; let [map, command] = this.pendingArgMap;
if (!Events.isEscape(key)) if (!Events.isEscape(key))
execute(map, null, this.count, key); execute(map, null, this.count, key, command);
return true; return true;
} }
else if (map && !event.skipmap && candidates.length == 0) { else if (map && !event.skipmap && candidates.length == 0) {
@@ -1118,27 +1130,28 @@ var Events = Module("events", {
if (map.arg) { if (map.arg) {
this.append(event); this.append(event);
this.pendingArgMap = map; this.pendingArgMap = [map, command];
} }
else if (this.pendingMotionMap) { else if (this.pendingMotionMap) {
let [map, command] = this.pendingMotionMap;
if (!Events.isEscape(key)) if (!Events.isEscape(key))
execute(this.pendingMotionMap, candidateCommand, this.motionCount || this.count, null); execute(map, command, this.motionCount || this.count, null, command);
return true; return true;
} }
else if (map.motion) { else if (map.motion) {
this.buffer = ""; this.buffer = "";
this.pendingMotionMap = map; this.pendingMotionMap = [map, command];
} }
else { else {
if (modes.replaying && !this.waitForPageLoad()) if (modes.replaying && !this.waitForPageLoad())
return true; return true;
return !execute(map, null, this.count) || !map.route return !execute(map, null, this.count, null, command) || !map.route
} }
} }
else if (mappings.getCandidates(this.main, candidateCommand).length > 0 && !event.skipmap) { else if (mappings.getCandidates(this.main, command).length > 0 && !event.skipmap) {
this.append(event); this.append(event);
this.pendingMap = map; this.pendingMap = [map, command];
} }
else { else {
this.append(event); this.append(event);

View File

@@ -74,6 +74,15 @@ var Hints = Module("hints", {
Buffer.isScrollable(elem, 0, true) || Buffer.isScrollable(elem, 0, false); Buffer.isScrollable(elem, 0, true) || Buffer.isScrollable(elem, 0, false);
}, },
/**
* Clear any timeout which might be active after pressing a number
*/
clearTimeout: function () {
if (this._activeTimeout)
this._activeTimeout.cancel();
this._activeTimeout = null;
},
/** /**
* Reset hints, so that they can be cleanly used again. * Reset hints, so that they can be cleanly used again.
*/ */
@@ -92,10 +101,7 @@ var Hints = Module("hints", {
this._pageHints = []; this._pageHints = [];
this._validHints = []; this._validHints = [];
this._docs = []; this._docs = [];
this.clearTimeout();
if (this._activeTimeout)
this._activeTimeout.cancel();
this._activeTimeout = null;
}, },
__reset: function __reset() { __reset: function __reset() {
if (!this._usedTabKey) if (!this._usedTabKey)
@@ -582,11 +588,7 @@ var Hints = Module("hints", {
_onInput: function _onInput(event) { _onInput: function _onInput(event) {
this.prevInput = "text"; this.prevInput = "text";
// clear any timeout which might be active after pressing a number this.clearTimeout();
if (this._activeTimeout) {
this._activeTimeout.cancel();
this._activeTimeout = null;
}
this._hintNumber = 0; this._hintNumber = 0;
this._hintString = commandline.command; this._hintString = commandline.command;
@@ -896,104 +898,38 @@ var Hints = Module("hints", {
*/ */
onEvent: function onEvent(event) { onEvent: function onEvent(event) {
let key = events.toString(event); let key = events.toString(event);
let followFirst = false;
// clear any timeout which might be active after pressing a number this.clearTimeout();
if (this._activeTimeout) {
this._activeTimeout.cancel();
this._activeTimeout = null;
}
switch (key) { if (!this.escNumbers && this.isHintKey(key)) {
case "<Return>": this.prevInput = "number";
followFirst = true;
break;
case "<Tab>": let oldHintNumber = this._hintNumber;
case "<S-Tab>": if (this._usedTabKey) {
this._usedTabKey = true;
if (this._hintNumber == 0)
this._hintNumber = 1;
let oldId = this._hintNumber;
if (key == "<Tab>") {
if (++this._hintNumber > this._validHints.length)
this._hintNumber = 1;
}
else {
if (--this._hintNumber < 1)
this._hintNumber = this._validHints.length;
}
this._showActiveHint(this._hintNumber, oldId);
this._updateStatusline();
return false;
case "<BS>":
if (this.prevInput !== "number")
return true;
if (this._hintNumber > 0 && !this._usedTabKey) {
this._hintNumber = Math.floor(this._hintNumber / this.hintKeys.length);
if (this._hintNumber == 0)
this.prevInput = "text";
}
else {
this._usedTabKey = false;
this._hintNumber = 0; this._hintNumber = 0;
dactyl.beep(); this._usedTabKey = false;
}
this._hintNumber = this._hintNumber * this.hintKeys.length +
this.hintKeys.indexOf(key);
this._updateStatusline();
if (!this._canUpdate)
return; return;
}
break;
case options["mapleader"]: if (this._docs.length == 0) {
hints.escNumbers = !hints.escNumbers;
if (hints.escNumbers && this._usedTabKey)
this._hintNumber = 0;
this._updateStatusline();
return false;
default:
if (!this.escNumbers && this.isHintKey(key)) {
this.prevInput = "number";
let oldHintNumber = this._hintNumber;
if (this._usedTabKey) {
this._hintNumber = 0;
this._usedTabKey = false;
}
this._hintNumber = this._hintNumber * this.hintKeys.length +
this.hintKeys.indexOf(key);
this._updateStatusline();
if (!this._canUpdate)
return;
if (this._docs.length == 0) {
this._generate();
this._showHints();
}
this._showActiveHint(this._hintNumber, oldHintNumber || 1);
dactyl.assert(this._hintNumber != 0);
this._checkUnique();
return false;
}
return true;
}
this._updateStatusline();
if (this._canUpdate) {
if (this._docs.length == 0 && this._hintString.length > 0)
this._generate(); this._generate();
this._showHints();
}
this._showActiveHint(this._hintNumber, oldHintNumber || 1);
this._showHints(); dactyl.assert(this._hintNumber != 0);
this._processHints(followFirst);
this._checkUnique();
return false;
} }
return false;
return !Events.isEscape(key);
} }
//}}} //}}}
}, { }, {
@@ -1118,6 +1054,84 @@ var Hints = Module("hints", {
"Start an extended hint mode and stay there until <Esc> is pressed", "Start an extended hint mode and stay there until <Esc> is pressed",
function (count) { hints.open("g;", { continue: true, count: count }); }, function (count) { hints.open("g;", { continue: true, count: count }); },
{ count: true }); { count: true });
function update(followFirst) {
hints.clearTimeout();
hints._updateStatusline();
if (hints._canUpdate) {
if (hints._docs.length == 0 && hints._hintString.length > 0)
hints._generate();
hints._showHints();
hints._processHints(followFirst);
}
}
mappings.add(modes.HINTS, ["<Return>"],
"Follow the selected hint",
function () { update(true) });
function tab(previous) {
hints.clearTimeout();
this._usedTabKey = true;
if (this._hintNumber == 0)
this._hintNumber = 1;
let oldId = this._hintNumber;
if (!previous) {
if (++this._hintNumber > this._validHints.length)
this._hintNumber = 1;
}
else {
if (--this._hintNumber < 1)
this._hintNumber = this._validHints.length;
}
this._showActiveHint(this._hintNumber, oldId);
this._updateStatusline();
}
mappings.add(modes.HINTS, ["<Tab>"],
"Focus the next matching hint",
function () { tab.call(hints, false) });
mappings.add(modes.HINTS, ["<S-Tab>"],
"Focus the previous matching hint",
function () { tab.call(hints, true) });
mappings.add(modes.HINTS, ["<BS>", "<C-h>"],
"Delete the previous character",
function () {
hints.clearTimeout();
if (hints.prevInput !== "number")
return true;
if (hints._hintNumber > 0 && !hints._usedTabKey) {
hints._hintNumber = Math.floor(hints._hintNumber / hints.hintKeys.length);
if (hints._hintNumber == 0)
hints.prevInput = "text";
update(false);
}
else {
hints._usedTabKey = false;
hints._hintNumber = 0;
dactyl.beep();
}
return false;
},
{ route: true });
mappings.add(modes.HINTS, ["<Leader>"],
"Toggle hint filtering",
function () {
hints.clearTimeout();
hints.escNumbers = !hints.escNumbers;
if (hints.escNumbers && hints._usedTabKey)
hints._hintNumber = 0;
hints._updateStatusline();
});
}, },
options: function () { options: function () {
const DEFAULT_HINTTAGS = const DEFAULT_HINTTAGS =

View File

@@ -90,7 +90,9 @@ var Map = Class("Map", {
* @param {string} name The name to query. * @param {string} name The name to query.
* @returns {boolean} * @returns {boolean}
*/ */
hasName: function (name) this.names.indexOf(name) >= 0, hasName: function (name) this.keys.indexOf(name) >= 0,
keys: Class.memoize(function () this.names.map(mappings._expandLeader)),
/** /**
* Execute the action for this mapping. * Execute the action for this mapping.
@@ -102,7 +104,7 @@ var Map = Class("Map", {
* @param {string} argument The normal argument if accepted by this * @param {string} argument The normal argument if accepted by this
* mapping. E.g. "a" for "ma" * mapping. E.g. "a" for "ma"
*/ */
execute: function (motion, count, argument) { execute: function (motion, count, argument, command) {
let args = []; let args = [];
if (this.motion) if (this.motion)
@@ -111,6 +113,7 @@ var Map = Class("Map", {
args.push(count); args.push(count);
if (this.arg) if (this.arg)
args.push(argument); args.push(argument);
args.push(command);
let self = this; let self = this;
function repeat() self.action.apply(self, args); function repeat() self.action.apply(self, args);
@@ -153,10 +156,9 @@ var Mappings = Module("mappings", {
_getMap: function (mode, cmd, stack) { _getMap: function (mode, cmd, stack) {
let maps = stack[mode] || []; let maps = stack[mode] || [];
for (let [, map] in Iterator(maps)) { for (let [, map] in Iterator(maps))
if (map.hasName(cmd)) if (map.hasName(cmd))
return map; return map;
}
return null; return null;
}, },
@@ -233,7 +235,6 @@ var Mappings = Module("mappings", {
* @optional * @optional
*/ */
addUserMap: function (modes, keys, description, action, extra) { addUserMap: function (modes, keys, description, action, extra) {
keys = keys.map(this._expandLeader);
extra = extra || {}; extra = extra || {};
extra.user = true; extra.user = true;
let map = Map(modes, keys, description, action, extra); let map = Map(modes, keys, description, action, extra);
@@ -631,7 +632,16 @@ var Mappings = Module("mappings", {
options: function () { options: function () {
options.add(["mapleader", "ml"], options.add(["mapleader", "ml"],
"Define the replacement keys for the <Leader> pseudo-key", "Define the replacement keys for the <Leader> pseudo-key",
"string", "\\"); "string", "\\", {
setter: function (value) {
if (this.hasChanged)
for (let hive in values([mappings._user, mappings._main]))
for (let mode in values(hive))
for (let map in values(mode))
delete map.keys;
return value;
}
});
} }
}); });

View File

@@ -66,6 +66,7 @@ var Services = Module("Services", {
this.addClass("Find", "@mozilla.org/embedcomp/rangefind;1", Ci.nsIFind); this.addClass("Find", "@mozilla.org/embedcomp/rangefind;1", Ci.nsIFind);
this.addClass("HtmlConverter","@mozilla.org/widget/htmlformatconverter;1", Ci.nsIFormatConverter); this.addClass("HtmlConverter","@mozilla.org/widget/htmlformatconverter;1", Ci.nsIFormatConverter);
this.addClass("HtmlEncoder", "@mozilla.org/layout/htmlCopyEncoder;1", Ci.nsIDocumentEncoder); this.addClass("HtmlEncoder", "@mozilla.org/layout/htmlCopyEncoder;1", Ci.nsIDocumentEncoder);
this.addClass("Persist", "@mozilla.org/embedding/browser/nsWebBrowserPersist;1", Ci.nsIWebBrowserPersist);
this.addClass("Process", "@mozilla.org/process/util;1", Ci.nsIProcess, "init"); this.addClass("Process", "@mozilla.org/process/util;1", Ci.nsIProcess, "init");
this.addClass("String", "@mozilla.org/supports-string;1", Ci.nsISupportsString); this.addClass("String", "@mozilla.org/supports-string;1", Ci.nsISupportsString);
this.addClass("Timer", "@mozilla.org/timer;1", Ci.nsITimer, "initWithCallback"); this.addClass("Timer", "@mozilla.org/timer;1", Ci.nsITimer, "initWithCallback");

View File

@@ -486,7 +486,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
*/ */
dumpStack: function dumpStack(msg, frames) { dumpStack: function dumpStack(msg, frames) {
let stack = util.stackLines(Error().stack); let stack = util.stackLines(Error().stack);
stack = stack.slice(2, 2 + (frames || stack.length)).join("\n").replace(/^/gm, " "); stack = stack.slice(1, 1 + (frames || stack.length)).join("\n").replace(/^/gm, " ");
util.dump((arguments.length == 0 ? "Stack" : msg) + "\n" + stack + "\n"); util.dump((arguments.length == 0 ? "Stack" : msg) + "\n" + stack + "\n");
}, },