1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2026-01-10 07:24: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
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);
this._history.select(/Up/.test(key), !/S-/.test(key));
return KILL;
}
// user pressed <Tab> to get completions of a command
else if (/^<(?:A-)?(?:S-)?Tab>$/.test(key)) {
// prevent tab from moving to the next field
event.preventDefault();
event.stopPropagation();
this._tabTimer.tell(event);
return KILL;
}
else if (key == "<BS>") {
// reset the tab completion

View File

@@ -366,8 +366,9 @@ var Events = Module("events", {
};
var t = TYPES[type];
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;
},
@@ -874,7 +875,6 @@ var Events = Module("events", {
// the command-line has focus
// TODO: ...help me...please...
onKeyPress: function onKeyPress(event) {
function kill(event) {
event.preventDefault();
event.stopPropagation();
@@ -889,7 +889,7 @@ var Events = Module("events", {
if (!key)
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);
// feedingKeys needs to be separate from interrupted so
@@ -953,61 +953,74 @@ var Events = Module("events", {
if (key == "<C-c>")
util.interrupted = true;
if (key in config.ignoreKeys && (config.ignoreKeys[key] & mode.main))
if (config.ignoreKeys[key] & mode.main)
return null;
let keyModes = array(mode.keyModes || []).concat([mode.params.mainMode, mode.main]).compact();
if (overrideMode)
processors = [Events.KeyProcessor(overrideMode, mode.extended)];
else {
for (let m in keyModes.iterValues())
if (m)
processors.push(Events.KeyProcessor(m, mode.extended));
let keyModes = array(mode.params.keyModes || []).concat([mode.params.mainMode, mode.main]).compact();
let input = processors[processors.length - 1];
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>";
let hives = mappings.hives.slice(event.noremap ? -1 : 0);
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;
let refeed;
let refeed, ownsBuffer = 0, buffer, waiting = 0;
for (let input in values(processors)) {
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;
else if (res == WAIT || res === PASS)
continue;
else if (res === KILL) {
else if (res !== PASS)
refeed = null;
if (res === KILL)
break;
}
}
if (res == WAIT)
if (!ownsBuffer)
statusline.updateInputBuffer(buffer);
if (waiting)
this._processors = processors;
else if (res !== KILL && (mode.main & (modes.TEXT_EDIT | modes.VISUAL)))
dactyl.beep();
if (refeed && refeed.length == 1 && !refeed[0].getPreventDefault())
[refeed, res] = [null, PASS];
if (res !== PASS)
kill(event);
if (refeed)
for (let [i, event] in Iterator(refeed))
if (event.originalTarget)
events.dispatch(event.originalTarget, event, i == 0 && { skipmap: true });
if (event.originalTarget) {
let evt = events.create(event.originalTarget.ownerDocument, event.type, event);
events.dispatch(event.originalTarget, evt, i == 0 && { skipmap: true });
}
else if (i > 0)
events.onKeyPress(event);
}
@@ -1085,13 +1098,14 @@ var Events = Module("events", {
}
}, {
KeyProcessor: Class("KeyProcessor", {
init: function init(main, extended) {
init: function init(main, extended, hive) {
this.main = main;
this.extended = extended;
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
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);
if (res === KILL)
kill(event);
else if (isArray(res)) {
if (this.fallthrough) {
let r = dactyl.trapErrors(this.fallthrough, this, res[0]);
if (r === KILL)
kill(res[0]);
res = r === KILL ? KILL : PASS;
/*
if (r === KILL)
res = res.slice(1);
else
res = r == WAIT ? res : false;
*/
}
else if (this.fallthrough) {
let evt = isArray(res) ? res[0] : event;
let r = dactyl.trapErrors(this.fallthrough, this, evt);
if (r === KILL)
kill(evt);
res = r === KILL ? KILL : PASS;
/*
if (r === KILL)
res = res.slice(1);
else
res = r == WAIT ? res : false;
*/
}
if (!this.main.ownsBuffer) {
if (res != WAIT)
statusline.updateInputBuffer("");
else {
let motionMap = (this.pendingMotionMap && this.pendingMotionMap.names[0]) || "";
statusline.updateInputBuffer(motionMap + this.buffer);
}
if (res != WAIT)
this.inputBuffer = "";
else {
let motionMap = (this.pendingMotionMap && this.pendingMotionMap.names[0]) || "";
this.inputBuffer = motionMap + this.buffer;
}
return res;
@@ -1150,7 +1161,7 @@ var Events = Module("events", {
let key = events.toString(event);
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) {
if (self.preExecute)
@@ -1161,7 +1172,7 @@ var Events = Module("events", {
return res;
}
let candidates = mappings.getCandidates(this.main, command);
let candidates = this.hive.getCandidates(this.main, command);
if (candidates.length == 0 && !map) {
[map] = this.pendingMap || [];
this.pendingMap = null;
@@ -1215,7 +1226,7 @@ var Events = Module("events", {
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.pendingMap = [map, command];
}

View File

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