mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2026-03-11 23:15:47 +01:00
Initial work towards making <C-o> and <C-i> more Vim-like.
This commit is contained in:
@@ -270,11 +270,18 @@ var Buffer = Module("buffer", {
|
|||||||
* tab.
|
* tab.
|
||||||
*/
|
*/
|
||||||
get localStore() {
|
get localStore() {
|
||||||
if (!content.document.dactylStore)
|
let doc = content.document;
|
||||||
content.document.dactylStore = {};
|
if (!doc.dactylStore || !buffer.localStorePrototype.isPrototypeOf(doc.dactylStore))
|
||||||
return content.document.dactylStore;
|
doc.dactylStore = Object.create(buffer.localStorePrototype);
|
||||||
|
return doc.dactylStore.instance = doc.dactylStore;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
localStorePrototype: memoize({
|
||||||
|
instance: {},
|
||||||
|
get jumps() [],
|
||||||
|
jumpsIndex: 0
|
||||||
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {Node} The last focused input field in the buffer. Used
|
* @property {Node} The last focused input field in the buffer. Used
|
||||||
* by the "gi" key binding.
|
* by the "gi" key binding.
|
||||||
@@ -1263,9 +1270,8 @@ var Buffer = Module("buffer", {
|
|||||||
* null, to not alter the vertical scroll offset.
|
* null, to not alter the vertical scroll offset.
|
||||||
*/
|
*/
|
||||||
scrollTo: function scrollTo(elem, left, top) {
|
scrollTo: function scrollTo(elem, left, top) {
|
||||||
// Temporary hack. Should be done better.
|
|
||||||
if (elem.ownerDocument == buffer.focusedFrame.document)
|
if (elem.ownerDocument == buffer.focusedFrame.document)
|
||||||
marks.add("'");
|
marks.push();
|
||||||
|
|
||||||
if (left != null)
|
if (left != null)
|
||||||
elem.scrollLeft = left;
|
elem.scrollLeft = left;
|
||||||
|
|||||||
@@ -63,7 +63,20 @@ var History = Module("history", {
|
|||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
|
|
||||||
stepTo: function stepTo(steps) {
|
/**
|
||||||
|
* Step to the given offset in the history stack.
|
||||||
|
*
|
||||||
|
* @param {number} steps The possibly negative number of steps to
|
||||||
|
* step.
|
||||||
|
* @param {boolean} jumps If true, take into account jumps in the
|
||||||
|
* marks stack. @optional
|
||||||
|
*/
|
||||||
|
stepTo: function stepTo(steps, jumps) {
|
||||||
|
if (jumps)
|
||||||
|
steps -= marks.jump(steps);
|
||||||
|
if (steps == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
let start = 0;
|
let start = 0;
|
||||||
let end = window.getWebNavigation().sessionHistory.count - 1;
|
let end = window.getWebNavigation().sessionHistory.count - 1;
|
||||||
let current = window.getWebNavigation().sessionHistory.index;
|
let current = window.getWebNavigation().sessionHistory.index;
|
||||||
@@ -274,12 +287,12 @@ var History = Module("history", {
|
|||||||
|
|
||||||
mappings.add(myModes,
|
mappings.add(myModes,
|
||||||
["<C-o>"], "Go to an older position in the jump list",
|
["<C-o>"], "Go to an older position in the jump list",
|
||||||
function (args) { history.stepTo(-Math.max(args.count, 1)); },
|
function (args) { history.stepTo(-Math.max(args.count, 1), true); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add(myModes,
|
mappings.add(myModes,
|
||||||
["<C-i>"], "Go to a newer position in the jump list",
|
["<C-i>"], "Go to a newer position in the jump list",
|
||||||
function (args) { history.stepTo(Math.max(args.count, 1)); },
|
function (args) { history.stepTo(Math.max(args.count, 1), true); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add(myModes,
|
mappings.add(myModes,
|
||||||
|
|||||||
@@ -34,6 +34,19 @@ var Marks = Module("marks", {
|
|||||||
|
|
||||||
get localURI() buffer.focusedFrame.document.documentURI,
|
get localURI() buffer.focusedFrame.document.documentURI,
|
||||||
|
|
||||||
|
Mark: function Mark(params) {
|
||||||
|
let win = buffer.focusedFrame;
|
||||||
|
let doc = win.document;
|
||||||
|
|
||||||
|
params = params || {};
|
||||||
|
|
||||||
|
params.location = doc.documentURI,
|
||||||
|
params.offset = buffer.scrollPosition;
|
||||||
|
params.path = util.generateXPath(buffer.findScrollable(0, params.offset.x));
|
||||||
|
params.timestamp = Date.now() * 1000;
|
||||||
|
return params;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a named mark for the current buffer, at its current position.
|
* Add a named mark for the current buffer, at its current position.
|
||||||
* If mark matches [A-Z], it's considered a URL mark, and will jump to
|
* If mark matches [A-Z], it's considered a URL mark, and will jump to
|
||||||
@@ -41,39 +54,58 @@ var Marks = Module("marks", {
|
|||||||
* selected from. If it matches [a-z], it's a local mark, and can
|
* selected from. If it matches [a-z], it's a local mark, and can
|
||||||
* only be recalled from a buffer with a matching URL.
|
* only be recalled from a buffer with a matching URL.
|
||||||
*
|
*
|
||||||
* @param {string} mark The mark name.
|
* @param {string} name The mark name.
|
||||||
* @param {boolean} silent Whether to output error messages.
|
* @param {boolean} silent Whether to output error messages.
|
||||||
*/
|
*/
|
||||||
add: function (mark, silent) {
|
add: function (name, silent) {
|
||||||
let win = buffer.focusedFrame;
|
let mark = this.Mark();
|
||||||
let doc = win.document;
|
|
||||||
|
|
||||||
let position = buffer.scrollPosition;
|
if (Marks.isURLMark(name)) {
|
||||||
let path = util.generateXPath(buffer.findScrollable(0, position.x));
|
mark.tab = Cu.getWeakReference(tabs.getTab());
|
||||||
|
this._urlMarks.set(name, mark);
|
||||||
if (Marks.isURLMark(mark)) {
|
var message = "mark.addURL";
|
||||||
let res = this._urlMarks.set(mark, {
|
|
||||||
location: doc.documentURI,
|
|
||||||
offset: position,
|
|
||||||
xpath: path,
|
|
||||||
tab: Cu.getWeakReference(tabs.getTab()),
|
|
||||||
timestamp: Date.now()*1000
|
|
||||||
});
|
|
||||||
if (!silent)
|
|
||||||
dactyl.log(_("mark.addURL", Marks.markToString(mark, res)), 5);
|
|
||||||
}
|
}
|
||||||
else if (Marks.isLocalMark(mark)) {
|
else if (Marks.isLocalMark(name)) {
|
||||||
let marks = this._localMarks.get(doc.documentURI, {});
|
this._localMarks.get(mark.location, {})[name] = mark;
|
||||||
marks[mark] = {
|
|
||||||
location: doc.documentURI,
|
|
||||||
offset: position,
|
|
||||||
xpath: path,
|
|
||||||
timestamp: Date.now()*1000
|
|
||||||
};
|
|
||||||
this._localMarks.changed();
|
this._localMarks.changed();
|
||||||
if (!silent)
|
message = "mark.addLocal";
|
||||||
dactyl.log(_("mark.addLocal", Marks.markToString(mark, marks[mark])), 5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!silent)
|
||||||
|
dactyl.log(_(message, Marks.markToString(name, mark)), 5);
|
||||||
|
return mark;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push the current buffer position onto the jump stack.
|
||||||
|
*/
|
||||||
|
push: function push() {
|
||||||
|
if (!this.jumping) {
|
||||||
|
let mark = this.add("'");
|
||||||
|
let store = buffer.localStore;
|
||||||
|
store.jumps[store.jumpsIndex++] = mark;
|
||||||
|
store.jumps.length = store.jumpsIndex;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jump to the given offset in the jump stack.
|
||||||
|
*
|
||||||
|
* @param {number} offset The offset from the current position in
|
||||||
|
* the jump stack to jump to.
|
||||||
|
* @returns {number} The actual change in offset.
|
||||||
|
*/
|
||||||
|
jump: function jump(offset) {
|
||||||
|
return this.withSavedValues(["jumping"], function _jump() {
|
||||||
|
this.jumping = true;
|
||||||
|
let store = buffer.localStore;
|
||||||
|
let idx = Math.constrain(store.jumpsIndex + offset, 0, store.jumps.length - 1);
|
||||||
|
let orig = store.jumpsIndex;
|
||||||
|
|
||||||
|
if (idx in store.jumps && !dactyl.trapErrors("_scrollTo", this, store.jumps[idx]))
|
||||||
|
store.jumpsIndex = idx;
|
||||||
|
return store.jumpsIndex - orig;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -176,10 +208,10 @@ var Marks = Module("marks", {
|
|||||||
util.assert(node);
|
util.assert(node);
|
||||||
util.scrollIntoView(node);
|
util.scrollIntoView(node);
|
||||||
|
|
||||||
if (mark.position)
|
if (mark.offset)
|
||||||
Buffer.scrollToPercent(node, mark.position.x * 100, mark.position.y * 100);
|
|
||||||
else if (mark.offset)
|
|
||||||
Buffer.scrollToPosition(node, mark.offset.x, mark.offset.y);
|
Buffer.scrollToPosition(node, mark.offset.x, mark.offset.y);
|
||||||
|
else if (mark.position)
|
||||||
|
Buffer.scrollToPercent(node, mark.position.x * 100, mark.position.y * 100);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -203,10 +235,10 @@ var Marks = Module("marks", {
|
|||||||
["Mark", "HPos", "VPos", "File"],
|
["Mark", "HPos", "VPos", "File"],
|
||||||
["", "text-align: right", "text-align: right", "color: green"],
|
["", "text-align: right", "text-align: right", "color: green"],
|
||||||
([name,
|
([name,
|
||||||
mark.position ? Math.round(mark.position.x * 100) + "%"
|
mark.offset ? Math.round(mark.offset.x)
|
||||||
: Math.round(mark.offset.x),
|
: Math.round(mark.position.x * 100) + "%",
|
||||||
mark.position ? Math.round(mark.position.y * 100) + "%"
|
mark.offset ? Math.round(mark.offset.y)
|
||||||
: Math.round(mark.offset.y),
|
: Math.round(mark.position.y * 100) + "%",
|
||||||
mark.location]
|
mark.location]
|
||||||
for ([, [name, mark]] in Iterator(marks)))));
|
for ([, [name, mark]] in Iterator(marks)))));
|
||||||
},
|
},
|
||||||
@@ -224,6 +256,13 @@ var Marks = Module("marks", {
|
|||||||
}, {
|
}, {
|
||||||
markToString: function markToString(name, mark) {
|
markToString: function markToString(name, mark) {
|
||||||
let tab = mark.tab && mark.tab.get();
|
let tab = mark.tab && mark.tab.get();
|
||||||
|
if (mark.offset)
|
||||||
|
return [name, mark.location,
|
||||||
|
"(" + Math.round(mark.offset.x * 100),
|
||||||
|
Math.round(mark.offset.y * 100) + ")",
|
||||||
|
(tab && "tab: " + tabs.index(tab))
|
||||||
|
].filter(util.identity).join(", ");
|
||||||
|
|
||||||
if (mark.position)
|
if (mark.position)
|
||||||
return [name, mark.location,
|
return [name, mark.location,
|
||||||
"(" + Math.round(mark.position.x * 100) + "%",
|
"(" + Math.round(mark.position.x * 100) + "%",
|
||||||
@@ -231,11 +270,6 @@ var Marks = Module("marks", {
|
|||||||
(tab && "tab: " + tabs.index(tab))
|
(tab && "tab: " + tabs.index(tab))
|
||||||
].filter(util.identity).join(", ");
|
].filter(util.identity).join(", ");
|
||||||
|
|
||||||
return [name, mark.location,
|
|
||||||
"(" + Math.round(mark.offset.x * 100),
|
|
||||||
Math.round(mark.offset.y * 100) + ")",
|
|
||||||
(tab && "tab: " + tabs.index(tab))
|
|
||||||
].filter(util.identity).join(", ");
|
|
||||||
},
|
},
|
||||||
|
|
||||||
isLocalMark: function isLocalMark(mark) /^[a-z`']$/.test(mark),
|
isLocalMark: function isLocalMark(mark) /^[a-z`']$/.test(mark),
|
||||||
@@ -309,7 +343,9 @@ var Marks = Module("marks", {
|
|||||||
function percent(i) Math.round(i * 100);
|
function percent(i) Math.round(i * 100);
|
||||||
|
|
||||||
context.title = ["Mark", "HPos VPos File"];
|
context.title = ["Mark", "HPos VPos File"];
|
||||||
context.keys.description = function ([, m]) percent(m.position.x) + "% " + percent(m.position.y) + "% " + m.location;
|
context.keys.description = function ([, m]) (m.offset ? Math.round(m.offset.x) + " " + Math.round(m.offset.y)
|
||||||
|
: percent(m.position.x) + "% " + percent(m.position.y) + "%"
|
||||||
|
) + " " + m.location;
|
||||||
context.completions = marks.all;
|
context.completions = marks.all;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -127,12 +127,7 @@ var Tabs = Module("tabs", {
|
|||||||
/**
|
/**
|
||||||
* @property {Object} The local options store for the current tab.
|
* @property {Object} The local options store for the current tab.
|
||||||
*/
|
*/
|
||||||
get options() {
|
get options() this.localStore.options,
|
||||||
let store = this.localStore;
|
|
||||||
if (!("options" in store))
|
|
||||||
store.options = {};
|
|
||||||
return store.options;
|
|
||||||
},
|
|
||||||
|
|
||||||
get visibleTabs() config.tabbrowser.visibleTabs || this.allTabs.filter(function (tab) !tab.hidden),
|
get visibleTabs() config.tabbrowser.visibleTabs || this.allTabs.filter(function (tab) !tab.hidden),
|
||||||
|
|
||||||
@@ -151,8 +146,8 @@ var Tabs = Module("tabs", {
|
|||||||
getLocalStore: function getLocalStore(tabIndex) {
|
getLocalStore: function getLocalStore(tabIndex) {
|
||||||
let tab = this.getTab(tabIndex);
|
let tab = this.getTab(tabIndex);
|
||||||
if (!tab.dactylStore)
|
if (!tab.dactylStore)
|
||||||
tab.dactylStore = {};
|
tab.dactylStore = Object.create(this.localStorePrototype);
|
||||||
return tab.dactylStore;
|
return tab.dactylStore.instance = tab.dactylStore;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -161,6 +156,11 @@ var Tabs = Module("tabs", {
|
|||||||
*/
|
*/
|
||||||
get localStore() this.getLocalStore(),
|
get localStore() this.getLocalStore(),
|
||||||
|
|
||||||
|
localStorePrototype: memoize({
|
||||||
|
instance: {},
|
||||||
|
get options() ({})
|
||||||
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {[Object]} The array of closed tabs for the current
|
* @property {[Object]} The array of closed tabs for the current
|
||||||
* session.
|
* session.
|
||||||
|
|||||||
@@ -264,10 +264,9 @@ want to bypass &dactyl.appName;'s key handling and pass keys directly to
|
|||||||
<h2 tag="navigating">Navigating</h2>
|
<h2 tag="navigating">Navigating</h2>
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags><![CDATA[H <C-o> CTRL-O :ba :back]]></tags>
|
<tags><![CDATA[H CTRL-O :ba :back]]></tags>
|
||||||
<spec>:<oa>count</oa>ba<oa>ck</oa> <oa>url</oa></spec>
|
<spec>:<oa>count</oa>ba<oa>ck</oa> <oa>url</oa></spec>
|
||||||
<spec>:ba<oa>ck</oa>!</spec>
|
<spec>:ba<oa>ck</oa>!</spec>
|
||||||
<spec><oa>count</oa><C-o></spec>
|
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
Go <oa>count</oa> pages back in the browser history. If
|
Go <oa>count</oa> pages back in the browser history. If
|
||||||
@@ -279,10 +278,9 @@ want to bypass &dactyl.appName;'s key handling and pass keys directly to
|
|||||||
</item>
|
</item>
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags><![CDATA[L <C-i> CTRL-I :fo :fw :forward]]></tags>
|
<tags><![CDATA[L CTRL-I :fo :fw :forward]]></tags>
|
||||||
<spec>:<oa>count</oa>fo<oa>rward</oa> <oa>url</oa></spec>
|
<spec>:<oa>count</oa>fo<oa>rward</oa> <oa>url</oa></spec>
|
||||||
<spec>:fo<oa>rward</oa>!</spec>
|
<spec>:fo<oa>rward</oa>!</spec>
|
||||||
<spec><oa>count</oa><C-i></spec>
|
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
Go <oa>count</oa> pages forward in the browser history.
|
Go <oa>count</oa> pages forward in the browser history.
|
||||||
@@ -293,6 +291,26 @@ want to bypass &dactyl.appName;'s key handling and pass keys directly to
|
|||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<tags><![CDATA[<C-o>]]></tags>
|
||||||
|
<spec><oa>count</oa><C-o></spec>
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
Go <oa>count</oa> steps back in the jumps stack.
|
||||||
|
</p>
|
||||||
|
</description>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<tags><![CDATA[<C-i>]]></tags>
|
||||||
|
<spec><oa>count</oa><C-i></spec>
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
Go <oa>count</oa> steps forward in the jumps stack.
|
||||||
|
</p>
|
||||||
|
</description>
|
||||||
|
</item>
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>:ju :jumps</tags>
|
<tags>:ju :jumps</tags>
|
||||||
<spec>:ju<oa>mps</oa></spec>
|
<spec>:ju<oa>mps</oa></spec>
|
||||||
|
|||||||
@@ -611,8 +611,7 @@ function call(fn) {
|
|||||||
*/
|
*/
|
||||||
function memoize(obj, key, getter) {
|
function memoize(obj, key, getter) {
|
||||||
if (arguments.length == 1) {
|
if (arguments.length == 1) {
|
||||||
obj = update({ __proto__: obj.__proto__ }, obj);
|
for each (let prop in Object.getOwnPropertyNames(obj)) {
|
||||||
for (let prop in Object.getOwnPropertyNames(obj)) {
|
|
||||||
let get = __lookupGetter__.call(obj, prop);
|
let get = __lookupGetter__.call(obj, prop);
|
||||||
if (get)
|
if (get)
|
||||||
memoize(obj, prop, get);
|
memoize(obj, prop, get);
|
||||||
|
|||||||
@@ -77,6 +77,7 @@
|
|||||||
• Mapping changes:
|
• Mapping changes:
|
||||||
- It's now possible to map keys in many more modes, including
|
- It's now possible to map keys in many more modes, including
|
||||||
Hint, Multi-line Output, and Menu. [b4]
|
Hint, Multi-line Output, and Menu. [b4]
|
||||||
|
- <C-o> and <C-i> now behave more like Vim. [b8]
|
||||||
- Added Operator mode for motion maps, per Vim. [b8]
|
- Added Operator mode for motion maps, per Vim. [b8]
|
||||||
- Added site-specific mapping groups and related command
|
- Added site-specific mapping groups and related command
|
||||||
changes. [b6]
|
changes. [b6]
|
||||||
|
|||||||
Reference in New Issue
Block a user