1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2026-01-06 19:54:12 +01:00

Mapping refactoring and bug fixes.

This commit is contained in:
Kris Maglione
2011-01-18 05:17:34 -05:00
parent 53248645c2
commit c096804e0f
3 changed files with 204 additions and 185 deletions

View File

@@ -1008,20 +1008,14 @@ var CommandLine = Module("commandline", {
} }
// user pressed <Up> or <Down> arrow to cycle history completion // user pressed <Up> or <Down> arrow to cycle history completion
else if (/^<(Up|Down|S-Up|S-Down)>$/.test(key)) { else if (/^<(Up|Down|S-Up|S-Down)>$/.test(key)) {
// prevent tab from moving to the next field
event.preventDefault();
event.stopPropagation();
dactyl.assert(this._history); dactyl.assert(this._history);
this._history.select(/Up/.test(key), !/S-/.test(key)); this._history.select(/Up/.test(key), !/S-/.test(key));
return KILL;
} }
// user pressed <Tab> to get completions of a command // user pressed <Tab> to get completions of a command
else if (/^<(?:A-)?(?:S-)?Tab>$/.test(key)) { else if (/^<(?:A-)?(?:S-)?Tab>$/.test(key)) {
// prevent tab from moving to the next field
event.preventDefault();
event.stopPropagation();
this._tabTimer.tell(event); this._tabTimer.tell(event);
return KILL;
} }
else if (key == "<BS>") { else if (key == "<BS>") {
// reset the tab completion // reset the tab completion

View File

@@ -366,8 +366,9 @@ var Events = Module("events", {
}; };
var t = TYPES[type]; var t = TYPES[type];
var evt = doc.createEvent((t || "HTML") + "Events"); var evt = doc.createEvent((t || "HTML") + "Events");
evt["init" + t + "Event"].apply(evt,
[v for ([k, v] in Iterator(util.extend(DEFAULTS[t || "HTML"], opts)))]); let defaults = DEFAULTS[t || "HTML"]
evt["init" + t + "Event"].apply(evt, Object.keys(defaults).map(function (k) k in opts ? opts[k] : defaults[k]));
return evt; return evt;
}, },
@@ -874,7 +875,6 @@ var Events = Module("events", {
// the command-line has focus // the command-line has focus
// TODO: ...help me...please... // TODO: ...help me...please...
onKeyPress: function onKeyPress(event) { onKeyPress: function onKeyPress(event) {
function kill(event) { function kill(event) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@@ -889,7 +889,7 @@ var Events = Module("events", {
if (!key) if (!key)
return null; return null;
if (modes.recording && (!this._input || !mappings.hasMap(modes.main, this._input.buffer + key))) if (modes.recording && (!this._input || !mappings.userHive.hasMap(modes.main, this._input.buffer + key)))
events._macroKeys.push(key); events._macroKeys.push(key);
// feedingKeys needs to be separate from interrupted so // feedingKeys needs to be separate from interrupted so
@@ -953,61 +953,74 @@ var Events = Module("events", {
if (key == "<C-c>") if (key == "<C-c>")
util.interrupted = true; util.interrupted = true;
if (key in config.ignoreKeys && (config.ignoreKeys[key] & mode.main)) if (config.ignoreKeys[key] & mode.main)
return null; return null;
let keyModes = array(mode.keyModes || []).concat([mode.params.mainMode, mode.main]).compact();
if (overrideMode) if (overrideMode)
processors = [Events.KeyProcessor(overrideMode, mode.extended)]; processors = [Events.KeyProcessor(overrideMode, mode.extended)];
else { else {
for (let m in keyModes.iterValues()) let keyModes = array(mode.params.keyModes || []).concat([mode.params.mainMode, mode.main]).compact();
if (m)
processors.push(Events.KeyProcessor(m, mode.extended));
let input = processors[processors.length - 1]; let hives = mappings.hives.slice(event.noremap ? -1 : 0);
if (mode.params.preExecute)
input.preExecute = mode.params.preExecute;
if (mode.params.postExecute)
input.postExecute = mode.params.postExecute;
if (mode.params.onEvent)
input.fallthrough = function (event) {
// Bloody hell.
if (events.toString(event) === "<C-h>")
event.dactylString = "<BS>";
return mode.params.onEvent(event) === false; processors = keyModes.map(function (m) hives.map(function (h) Events.KeyProcessor(m, mode.extended, h)))
}; .flatten().array;
for (let [i, input] in Iterator(processors)) {
if (input.main == mode.main) {
if (mode.params.preExecute)
input.preExecute = mode.params.preExecute;
if (mode.params.postExecute)
input.postExecute = mode.params.postExecute;
if (mode.params.onEvent && i == processors.length - 1)
input.fallthrough = function (event) {
// Bloody hell.
if (events.toString(event) === "<C-h>")
event.dactylString = "<BS>";
return mode.params.onEvent(event) === false ? KILL : PASS;
};
}}
} }
} }
const KILL = true, PASS = false, WAIT = null; const KILL = true, PASS = false, WAIT = null;
let refeed; let refeed, ownsBuffer = 0, buffer, waiting = 0;
for (let input in values(processors)) { for (let input in values(processors)) {
var res = input.process(event); var res = input.process(event);
if (isArray(res)) ownsBuffer += !!input.main.ownsBuffer;
waiting += res == WAIT;
buffer = buffer || input.inputBuffer;
if (isArray(res) && !waiting)
refeed = res; refeed = res;
else if (res == WAIT || res === PASS) else if (res !== PASS)
continue;
else if (res === KILL) {
refeed = null; refeed = null;
if (res === KILL)
break; break;
}
} }
if (res == WAIT) if (!ownsBuffer)
statusline.updateInputBuffer(buffer);
if (waiting)
this._processors = processors; this._processors = processors;
else if (res !== KILL && (mode.main & (modes.TEXT_EDIT | modes.VISUAL))) else if (res !== KILL && (mode.main & (modes.TEXT_EDIT | modes.VISUAL)))
dactyl.beep(); dactyl.beep();
if (refeed && refeed.length == 1 && !refeed[0].getPreventDefault())
[refeed, res] = [null, PASS];
if (res !== PASS) if (res !== PASS)
kill(event); kill(event);
if (refeed) if (refeed)
for (let [i, event] in Iterator(refeed)) for (let [i, event] in Iterator(refeed))
if (event.originalTarget) if (event.originalTarget) {
events.dispatch(event.originalTarget, event, i == 0 && { skipmap: true }); let evt = events.create(event.originalTarget.ownerDocument, event.type, event);
events.dispatch(event.originalTarget, evt, i == 0 && { skipmap: true });
}
else if (i > 0) else if (i > 0)
events.onKeyPress(event); events.onKeyPress(event);
} }
@@ -1085,13 +1098,14 @@ var Events = Module("events", {
} }
}, { }, {
KeyProcessor: Class("KeyProcessor", { KeyProcessor: Class("KeyProcessor", {
init: function init(main, extended) { init: function init(main, extended, hive) {
this.main = main; this.main = main;
this.extended = extended; this.extended = extended;
this.events = []; this.events = [];
this.hive = hive;
}, },
toString: function () "[instance KeyProcessor(" + this.main.name + ")]", toString: function () ["[instance KeyProcessor(" + this.main.name, this.extended, this.hive.name + ")]"].join(", "),
buffer: "", // partial command storage buffer: "", // partial command storage
pendingMotionMap: null, // e.g. "d{motion}" if we wait for a motion of the "d" command pendingMotionMap: null, // e.g. "d{motion}" if we wait for a motion of the "d" command
@@ -1116,28 +1130,25 @@ var Events = Module("events", {
let res = this.onKeyPress(event); let res = this.onKeyPress(event);
if (res === KILL) if (res === KILL)
kill(event); kill(event);
else if (isArray(res)) { else if (this.fallthrough) {
if (this.fallthrough) { let evt = isArray(res) ? res[0] : event;
let r = dactyl.trapErrors(this.fallthrough, this, res[0]); let r = dactyl.trapErrors(this.fallthrough, this, evt);
if (r === KILL) if (r === KILL)
kill(res[0]); kill(evt);
res = r === KILL ? KILL : PASS; res = r === KILL ? KILL : PASS;
/* /*
if (r === KILL) if (r === KILL)
res = res.slice(1); res = res.slice(1);
else else
res = r == WAIT ? res : false; res = r == WAIT ? res : false;
*/ */
}
} }
if (!this.main.ownsBuffer) { if (res != WAIT)
if (res != WAIT) this.inputBuffer = "";
statusline.updateInputBuffer(""); else {
else { let motionMap = (this.pendingMotionMap && this.pendingMotionMap.names[0]) || "";
let motionMap = (this.pendingMotionMap && this.pendingMotionMap.names[0]) || ""; this.inputBuffer = motionMap + this.buffer;
statusline.updateInputBuffer(motionMap + this.buffer);
}
} }
return res; return res;
@@ -1150,7 +1161,7 @@ var Events = Module("events", {
let key = events.toString(event); let key = events.toString(event);
let [, countStr, command] = /^((?:[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, command); let map = this.hive.get(this.main, command);
function execute(map) { function execute(map) {
if (self.preExecute) if (self.preExecute)
@@ -1161,7 +1172,7 @@ var Events = Module("events", {
return res; return res;
} }
let candidates = mappings.getCandidates(this.main, command); let candidates = this.hive.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;
@@ -1215,7 +1226,7 @@ var Events = Module("events", {
return execute(map, null, this.count, null, command) && map.route ? PASS : KILL; return execute(map, null, this.count, null, command) && map.route ? PASS : KILL;
} }
} }
else if (!event.skipmap && mappings.getCandidates(this.main, command).length > 0) { else if (!event.skipmap && this.hive.getCandidates(this.main, command).length > 0) {
this.append(event); this.append(event);
this.pendingMap = [map, command]; this.pendingMap = [map, command];
} }

View File

@@ -95,7 +95,7 @@ var Map = Class("Map", {
*/ */
hasName: function (name) this.keys.indexOf(name) >= 0, hasName: function (name) this.keys.indexOf(name) >= 0,
keys: Class.memoize(function () this.names.map(mappings._expandLeader)), keys: Class.memoize(function () this.names.map(mappings.expandLeader)),
/** /**
* Execute the action for this mapping. * Execute the action for this mapping.
@@ -122,87 +122,150 @@ var Map = Class("Map", {
id: 0 id: 0
}); });
/** var MapHive = Class("MapHive", {
* @instance mappings init: function init(name) {
*/ this.name = name;
var Mappings = Module("mappings", { this.stacks = {};
init: function () {
this._main = []; // default mappings
this._user = []; // user created mappings
dactyl.registerObserver("mode-add", function (mode) {
if (!(mode.mask in this._user || mode.mask in this._main)) {
this._main[mode.mask] = [];
this._user[mode.mask] = [];
}
});
}, },
_addMap: function (map) { /**
let where = map.user ? this._user : this._main; * Iterates over all mappings present in all of the given *modes*.
map.definedAt = commands.getCaller(Components.stack.caller.caller); *
map.modes.forEach(function (mode) { * @param {[Modes.Mode]} modes The modes for which to return mappings.
if (!(mode in where)) */
where[mode] = []; iterate: function (modes) {
where[mode].push(map); let stacks = Array.concat(modes).map(this.closure.getStack);
}); return values(stacks.shift().sort(function (m1, m2) String.localeCompare(m1.name, m2.name))
.filter(function (map) map.rhs &&
stacks.every(function (stack) stack.some(function (m) m.rhs && m.rhs === map.rhs && m.name === map.name))));
}, },
_getMap: function (mode, cmd, stack) { /**
let maps = stack[mode] || []; * Returns the mapping stack for the given mode.
*
for (let [, map] in Iterator(maps)) * @param {Modes.Mode} mode The mode to search.
if (map.hasName(cmd)) * @returns {[Map]}
return map; */
getStack: function getStack(mode) {
return null; if (!(mode in this.stacks))
return this.stacks[mode] = [];
return this.stacks[mode];
}, },
_removeMap: function (mode, cmd) { /**
let maps = this._user[mode] || []; * Adds a new Map object to the given mode.
let names; *
* @param {Modes.Mode} mode The mode to search.
* @param {string} cmd The map name to match.
* @returns {Map|null}
*/
add: function (mode, map) {
this.getStack(mode).push(map);
},
for (let [i, map] in Iterator(maps)) { /**
* Returns the map from *mode* named *cmd*.
*
* @param {Modes.Mode} mode The mode to search.
* @param {string} cmd The map name to match.
* @returns {Map|null}
*/
get: function (mode, cmd) array.nth(this.getStack(mode), function (m) m.hasName(cmd), 0),
/**
* Returns an array of maps with names starting with but not equal to
* *prefix*.
*
* @param {Modes.Mode} mode The mode to search.
* @param {string} prefix The map prefix string to match.
* @returns {Map[]}
*/
getCandidates: function (mode, prefix) {
let filter = util.regexp("^" + util.regexp.escape(prefix) + ".").closure.test;
return this.getStack(mode)
.filter(function (map) map.keys.some(filter));
},
/**
* Returns whether there is a user-defined mapping *cmd* for the specified
* *mode*.
*
* @param {Modes.Mode} mode The mode to search.
* @param {string} cmd The candidate key mapping.
* @returns {boolean}
*/
has: function (mode, cmd) this.getStack(mode).some(function (map) map.hasName(cmd)),
/**
* Remove the mapping named *cmd* for *mode*.
*
* @param {Modes.Mode} mode The mode to search.
* @param {string} cmd The map name to match.
*/
remove: function (mode, cmd) {
for (let [i, map] in Iterator(this.getStack(mode))) {
let j = map.names.indexOf(cmd); let j = map.names.indexOf(cmd);
if (j >= 0) { if (j >= 0) {
map.names.splice(j, 1); map.names.splice(j, 1);
if (map.names.length == 0) // FIX ME. if (map.names.length == 0) // FIX ME.
for (let [mode, stack] in Iterator(this._user)) for (let [mode, stack] in Iterator(this.stacks))
this._user[mode] = (stack || []).filter(function (m) m != map); this.stacks[mode] = stack.filter(function (m) m != map);
return; return;
} }
} }
}, },
_expandLeader: function (keyString) keyString.replace(/<Leader>/i, options["mapleader"]), /**
* Remove all user-defined mappings for *mode*.
*
* @param {Modes.Mode} mode The mode to remove all mappings from.
*/
clear: function (mode) {
this.stacks[mode] = [];
}
});
// Return all mappings present in all @modes /**
_mappingsIterator: function (modes, stack) { * @instance mappings
modes = modes.slice(); */
return (map for ([i, map] in Iterator(stack[modes.shift()].sort(function (m1, m2) String.localeCompare(m1.name, m2.name)))) var Mappings = Module("mappings", {
if (map.rhs && modes.every(function (mode) stack[mode]. init: function () {
some(function (m) m.rhs && m.rhs === map.rhs && m.name === map.name)))); this.userHive = MapHive("user");
this.builtinHive = MapHive("builtin");
this.hives = array([this.userHive, this.builtinHive]);
}, },
_addMap: function (map) {
let hive = map.user ? this.userHive : this.builtinHive;
map.definedAt = commands.getCaller(Components.stack.caller.caller);
map.modes.forEach(function (mode) {
hive.add(mode, map);
});
},
expandLeader: function (keyString) keyString.replace(/<Leader>/i, options["mapleader"]),
iterate: function (mode) { iterate: function (mode) {
let seen = {}; let seen = {};
for (let map in iter(values(this._user[mode]), values(this._main[mode]))) for (let hive in this.hives.iterValues())
if (!set.add(seen, map.name)) for (let map in values(hive.getStack(mode)))
yield map; if (!set.add(seen, map.name))
yield map;
}, },
// NOTE: just normal mode for now // NOTE: just normal mode for now
/** @property {Iterator(Map)} */ /** @property {Iterator(Map)} */
__iterator__: function () this.iterate(modes.NORMAL), __iterator__: function () this.iterate(modes.NORMAL),
// used by :mkpentadactylrc to save mappings getDefault: deprecated("mappings.builtinHive.get",
/** function getDefault(mode, cmd) this.builtinHive.get(mode, cmd)),
* Returns a user-defined mappings iterator for the specified *mode*. getUserIterator: deprecated("mappings.userHive.iterator",
* function getUserIterator(modes) this.userHive.iterator(modes)),
* @param {number} mode The mode to return mappings from. hasMap: deprecated("mappings.userHive.has", function hasMap(mode, cmd) this.userHive.has(mode, cmd)),
* @returns {Iterator(Map)} remove: deprecated("mappings.userHive.remove", function remove(mode, cmd) this.userHive.remove(mode, cmd)),
*/ removeAll: deprecated("mappings.userHive.clear", function removeAll(mode) this.userHive.clear(mode)),
getUserIterator: function (mode) this._mappingsIterator(mode, this._user),
/** /**
* Adds a new default key mapping. * Adds a new default key mapping.
@@ -237,7 +300,7 @@ var Mappings = Module("mappings", {
// remove all old mappings to this key sequence // remove all old mappings to this key sequence
for (let [, name] in Iterator(map.names)) for (let [, name] in Iterator(map.names))
for (let [, mode] in Iterator(map.modes)) for (let [, mode] in Iterator(map.modes))
this._removeMap(mode, name); this.userHive.remove(mode, name);
this._addMap(map); this._addMap(map);
}, },
@@ -249,21 +312,8 @@ var Mappings = Module("mappings", {
* @param {string} cmd The map name to match. * @param {string} cmd The map name to match.
* @returns {Map} * @returns {Map}
*/ */
get: function (mode, cmd) { get: function get(mode, cmd) {
mode = mode || modes.NORMAL; return this.hives.nth(function (h) h.get(mode, command), 0);
return this._getMap(mode, cmd, this._user) || this._getMap(mode, cmd, this._main);
},
/**
* Returns the default map from *mode* named *cmd*.
*
* @param {number} mode The mode to search.
* @param {string} cmd The map name to match.
* @returns {Map}
*/
getDefault: function (mode, cmd) {
mode = mode || modes.NORMAL;
return this._getMap(mode, cmd, this._main);
}, },
/** /**
@@ -275,39 +325,8 @@ var Mappings = Module("mappings", {
* @returns {Map[]} * @returns {Map[]}
*/ */
getCandidates: function (mode, prefix) getCandidates: function (mode, prefix)
this._user[mode].concat(this._main[mode]) this.hives.map(function (h) h.getCandidates(mode, prefix))
.filter(function (map) map.keys.some( .flatten(),
function (name) name.indexOf(prefix) == 0 && name.length > prefix.length
&& (prefix != "<" || !/^<.+>/.test(name)))),
/**
* Returns whether there is a user-defined mapping *cmd* for the specified
* *mode*.
*
* @param {number} mode The mode to search.
* @param {string} cmd The candidate key mapping.
* @returns {boolean}
*/
hasMap: function (mode, cmd) this._user[mode].some(function (map) map.hasName(cmd)),
/**
* Remove the user-defined mapping named *cmd* for *mode*.
*
* @param {number} mode The mode to search.
* @param {string} cmd The map name to match.
*/
remove: function (mode, cmd) {
this._removeMap(mode, cmd);
},
/**
* Remove all user-defined mappings for *mode*.
*
* @param {number} mode The mode to remove all mappings from.
*/
removeAll: function (mode) {
this._user[mode] = [];
},
/** /**
* Lists all user-defined mappings matching *filter* for the specified * Lists all user-defined mappings matching *filter* for the specified
@@ -327,7 +346,7 @@ var Mappings = Module("mappings", {
modeSign += m.char; modeSign += m.char;
}); });
let maps = this._mappingsIterator(modes, this._user); let maps = this.userHive.iterate(modes);
if (filter) if (filter)
maps = [map for (map in maps) if (map.names[0] == filter)]; maps = [map for (map in maps) if (map.names[0] == filter)];
@@ -365,7 +384,7 @@ var Mappings = Module("mappings", {
args["-builtin"] = true; args["-builtin"] = true;
if (!rhs) // list the mapping if (!rhs) // list the mapping
mappings.list(mapmodes, mappings._expandLeader(lhs)); mappings.list(mapmodes, mappings.expandLeader(lhs));
else { else {
mappings.addUserMap(mapmodes, [lhs], mappings.addUserMap(mapmodes, [lhs],
args["-description"], args["-description"],
@@ -453,7 +472,7 @@ var Mappings = Module("mappings", {
}; };
function userMappings() { function userMappings() {
let seen = {}; let seen = {};
for (let [, stack] in Iterator(mappings._user)) for (let stack in values(mappings.userHive.stacks))
for (let map in values(stack)) for (let map in values(stack))
if (!set.add(seen, map.id)) if (!set.add(seen, map.id))
yield map; yield map;
@@ -472,7 +491,7 @@ var Mappings = Module("mappings", {
commands.add([ch + "mapc[lear]"], commands.add([ch + "mapc[lear]"],
"Remove all mappings" + modeDescription, "Remove all mappings" + modeDescription,
function () { mapmodes.forEach(function (mode) { mappings.removeAll(mode); }); }, function () { mapmodes.forEach(function (mode) { mappings.userHive.clear(mode); }); },
{ {
argCount: "0", argCount: "0",
options: [ update({}, modeFlag, { options: [ update({}, modeFlag, {
@@ -491,8 +510,8 @@ var Mappings = Module("mappings", {
let found = false; let found = false;
for (let [, mode] in Iterator(mapmodes)) { for (let [, mode] in Iterator(mapmodes)) {
if (mappings.hasMap(mode, args[0])) { if (mappings.userHive.hasMap(mode, args[0])) {
mappings.remove(mode, args[0]); mappings.userHive.remove(mode, args[0]);
found = true; found = true;
} }
} }
@@ -608,7 +627,8 @@ var Mappings = Module("mappings", {
completion.userMapping = function userMapping(context, modes) { completion.userMapping = function userMapping(context, modes) {
// FIXME: have we decided on a 'standard' way to handle this clash? --djk // FIXME: have we decided on a 'standard' way to handle this clash? --djk
modes = modes || [modules.modes.NORMAL]; modes = modes || [modules.modes.NORMAL];
context.completions = [[m.names[0], m.description + ": " + m.action] for (m in mappings.getUserIterator(modes))]; context.keys = { text: function (m) m.names[0], description: function (m) m.description + ": " + m.action };
context.completions = mappings.userHive.iterate(modes);
}; };
}, },
javascript: function () { javascript: function () {
@@ -619,26 +639,20 @@ var Mappings = Module("mappings", {
let mode = args[0]; let mode = args[0];
return array.flatten([ return array.flatten([
[[name, map.description] for ([i, name] in Iterator(map.names))] [[name, map.description] for ([i, name] in Iterator(map.names))]
for ([i, map] in Iterator(mappings._user[mode].concat(mappings._main[mode]))) for (map in mappings.iterate(mode))
]); ]);
} }
]); ]);
}, },
modes: function () {
for (let mode in modes) {
this._main[mode] = [];
this._user[mode] = [];
}
},
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) { setter: function (value) {
if (this.hasChanged) if (this.hasChanged)
for (let hive in values([mappings._user, mappings._main])) for (let hive in mappings.hives.iterValues())
for (let mode in values(hive)) for (let stack in values(hive.stacks))
for (let map in values(mode)) for (let map in values(stack))
delete map.keys; delete map.keys;
return value; return value;
} }