mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-21 23:27:58 +01:00
Resurrect my range finder, Part I.
This commit is contained in:
@@ -828,7 +828,7 @@ const Completion = Module("completion", {
|
|||||||
// v[0] in orig and orig[v[0]] catch different cases. XPCOM
|
// v[0] in orig and orig[v[0]] catch different cases. XPCOM
|
||||||
// objects are problematic, to say the least.
|
// objects are problematic, to say the least.
|
||||||
compl = [v for (v in this.iter(obj))
|
compl = [v for (v in this.iter(obj))
|
||||||
if ((typeof orig == "object" && v[0] in orig) || getKey(orig, v[0]) !== undefined)];
|
if (v && (typeof orig == "object" && v[0] in orig || getKey(orig, v[0]) !== undefined))];
|
||||||
}
|
}
|
||||||
|
|
||||||
// And if wrappedJSObject happens to be available,
|
// And if wrappedJSObject happens to be available,
|
||||||
|
|||||||
@@ -1063,6 +1063,9 @@ const Events = Module("events", {
|
|||||||
if (stop)
|
if (stop)
|
||||||
killEvent();
|
killEvent();
|
||||||
}
|
}
|
||||||
|
catch (e) {
|
||||||
|
liberator.reportError(e);
|
||||||
|
}
|
||||||
finally {
|
finally {
|
||||||
let motionMap = (this._input.pendingMotionMap && this._input.pendingMotionMap.names[0]) || "";
|
let motionMap = (this._input.pendingMotionMap && this._input.pendingMotionMap.names[0]) || "";
|
||||||
if (!(modes.extended & modes.HINTS))
|
if (!(modes.extended & modes.HINTS))
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ const Finder = Module("finder", {
|
|||||||
// TODO: focus the top of the currently visible screen
|
// TODO: focus the top of the currently visible screen
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: backwards seems impossible i fear :(
|
// TODO: backwards seems impossible i fear
|
||||||
/**
|
/**
|
||||||
* Searches the current buffer for <b>str</b>.
|
* Searches the current buffer for <b>str</b>.
|
||||||
*
|
*
|
||||||
@@ -457,4 +457,287 @@ const Finder = Module("finder", {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const RangeFinder = Module("rangefinder", {
|
||||||
|
requires: ["config"],
|
||||||
|
|
||||||
|
init: function () {
|
||||||
|
},
|
||||||
|
|
||||||
|
openPrompt: function (mode) {
|
||||||
|
let backwards;
|
||||||
|
if (mode == modes.FIND_BACKWARD) {
|
||||||
|
commandline.open("?", "", modes.FIND_BACKWARD);
|
||||||
|
backwards = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
commandline.open("/", "", modes.FIND_FORWARD);
|
||||||
|
backwards = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.find("", backwards);
|
||||||
|
// TODO: focus the top of the currently visible screen
|
||||||
|
},
|
||||||
|
|
||||||
|
find: function (str, backwards) {
|
||||||
|
let caseSensitive = false;
|
||||||
|
this.rangeFind = RangeFind(caseSensitive, backwards);
|
||||||
|
|
||||||
|
if (!this.rangeFind.search(searchString))
|
||||||
|
setTimeout(function () { liberator.echoerr("E486: Pattern not found: " + searchPattern); }, 0);
|
||||||
|
|
||||||
|
return this.rangeFind.found;
|
||||||
|
},
|
||||||
|
|
||||||
|
findAgain: function (reverse) {
|
||||||
|
if (!this.rangeFind || !this.rangeFind.search(null, reverse))
|
||||||
|
liberator.echoerr("E486: Pattern not found: " + lastSearchPattern);
|
||||||
|
else if (this.rangeFind.wrapped) {
|
||||||
|
// hack needed, because wrapping causes a "scroll" event which clears
|
||||||
|
// our command line
|
||||||
|
setTimeout(function () {
|
||||||
|
if (rangfinder.rangeFind.backward)
|
||||||
|
commandline.echo("search hit TOP, continuing at BOTTOM",
|
||||||
|
commandline.HL_WARNINGMSG, commandline.APPEND_TO_MESSAGES);
|
||||||
|
else
|
||||||
|
commandline.echo("search hit BOTTOM, continuing at TOP",
|
||||||
|
commandline.HL_WARNINGMSG, commandline.APPEND_TO_MESSAGES);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
liberator.echo((this.rangeFind.backward ? "?" : "/") + lastSearchPattern, null, commandline.FORCE_SINGLELINE);
|
||||||
|
|
||||||
|
if (options["hlsearch"])
|
||||||
|
this.highlight(this.rangeFind.lastString);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Called when the user types a key in the search dialog. Triggers a find attempt if 'incsearch' is set
|
||||||
|
onKeyPress: function (command) {
|
||||||
|
if (options["incsearch"] && this.rangeFind)
|
||||||
|
this.rangeFind.search(command);
|
||||||
|
},
|
||||||
|
|
||||||
|
onSubmit: function (command) {
|
||||||
|
// use the last pattern if none specified
|
||||||
|
if (!command)
|
||||||
|
command = lastSearchPattern;
|
||||||
|
|
||||||
|
if (!options["incsearch"] || !this.rangeFind.found) {
|
||||||
|
this.clear();
|
||||||
|
this.find(command, this.rangeFind.backwards);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._lastSearchBackwards = this.rangeFind.backwards;
|
||||||
|
this._lastSearchPattern = command;
|
||||||
|
this._lastSearchString = command;
|
||||||
|
|
||||||
|
if (options["hlsearch"])
|
||||||
|
this.highlight(this.rangeFind.searchString);
|
||||||
|
|
||||||
|
modes.reset();
|
||||||
|
},
|
||||||
|
|
||||||
|
// Called when the search is canceled - for example if someone presses
|
||||||
|
// escape while typing a search
|
||||||
|
onCancel: function () {
|
||||||
|
// TODO: code to reposition the document to the place before search started
|
||||||
|
if (this.rangeFind)
|
||||||
|
this.rangeFind.cancel();
|
||||||
|
this.rangeFind = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
get rangeFind() tabs.localStore.rangeFind,
|
||||||
|
set rangeFind(val) tabs.localStore.rangeFind = val,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Highlights all occurances of <b>str</b> in the buffer.
|
||||||
|
*
|
||||||
|
* @param {string} str The string to highlight.
|
||||||
|
*/
|
||||||
|
highlight: function (str) {
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all search highlighting.
|
||||||
|
*/
|
||||||
|
clear: function () {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
}, {
|
||||||
|
commandline: function () {
|
||||||
|
// Event handlers for search - closure is needed
|
||||||
|
commandline.registerCallback("change", modes.FIND_FORWARD, this.closure.onKeyPress);
|
||||||
|
commandline.registerCallback("submit", modes.FIND_FORWARD, this.closure.onSubmit);
|
||||||
|
commandline.registerCallback("cancel", modes.FIND_FORWARD, this.closure.onCancel);
|
||||||
|
// TODO: allow advanced myModes in register/triggerCallback
|
||||||
|
commandline.registerCallback("change", modes.FIND_BACKWARD, this.closure.onKeyPress);
|
||||||
|
commandline.registerCallback("submit", modes.FIND_BACKWARD, this.closure.onSubmit);
|
||||||
|
commandline.registerCallback("cancel", modes.FIND_BACKWARD, this.closure.onCancel);
|
||||||
|
|
||||||
|
},
|
||||||
|
commands: function () {
|
||||||
|
},
|
||||||
|
mappings: function () {
|
||||||
|
var myModes = config.browserModes.concat([modes.CARET]);
|
||||||
|
|
||||||
|
mappings.add(myModes,
|
||||||
|
["g/"], "Search forward for a pattern",
|
||||||
|
function () { rangefinder.openPrompt(modes.FIND_FORWARD); });
|
||||||
|
|
||||||
|
mappings.add(myModes,
|
||||||
|
["g?"], "Search backwards for a pattern",
|
||||||
|
function () { rangefinder.openPrompt(modes.FIND_BACKWARD); });
|
||||||
|
|
||||||
|
mappings.add(myModes,
|
||||||
|
["g."], "Find next",
|
||||||
|
function () { rangefinder.findAgain(false); });
|
||||||
|
|
||||||
|
mappings.add(myModes,
|
||||||
|
["g,"], "Find previous",
|
||||||
|
function () { rangefinder.findAgain(true); });
|
||||||
|
|
||||||
|
mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["g*"],
|
||||||
|
"Find word under cursor",
|
||||||
|
function () {
|
||||||
|
rangefinder._found = false;
|
||||||
|
rangefinder.onSubmit(buffer.getCurrentWord(), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["g#"],
|
||||||
|
"Find word under cursor backwards",
|
||||||
|
function () {
|
||||||
|
rangefinder._found = false;
|
||||||
|
rangefinder.onSubmit(buffer.getCurrentWord(), true);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
modes: function () {
|
||||||
|
modes.addMode("FIND_FORWARD", true);
|
||||||
|
modes.addMode("FIND_BACKWARD", true);
|
||||||
|
},
|
||||||
|
options: function () {
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const RangeFind = Class("RangeFind", {
|
||||||
|
init: function (matchCase, backward) {
|
||||||
|
this.finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"]
|
||||||
|
.createInstance()
|
||||||
|
.QueryInterface(Components.interfaces.nsIFind);
|
||||||
|
this.finder.caseSensitive = matchCase;
|
||||||
|
this.matchCase = matchCase;
|
||||||
|
this._backward = backward;
|
||||||
|
this.sel = buffer.selectionController;
|
||||||
|
this.win = content;
|
||||||
|
this.doc = content.document;
|
||||||
|
|
||||||
|
this.pageRange = this.doc.createRange();
|
||||||
|
this.pageRange.setStartBefore(this.doc.body);
|
||||||
|
this.pageRange.setEndAfter(this.doc.body);
|
||||||
|
this.pageStart = this.pageRange.cloneRange();
|
||||||
|
this.pageEnd = this.pageRange.cloneRange();
|
||||||
|
this.pageStart.collapse(true);
|
||||||
|
this.pageEnd.collapse(false);
|
||||||
|
|
||||||
|
this.start = Point(this.win.pageXOffset, this.win.pageYOffset);
|
||||||
|
this.selection = this.sel.getSelection(this.sel.SELECTION_NORMAL);
|
||||||
|
this.startRange = this.selection.rangeCount ? this.selection.getRangeAt(0) : this.pageStart;
|
||||||
|
this.startRange.collapse(true);
|
||||||
|
|
||||||
|
this.lastString = "";
|
||||||
|
this.lastRange = null;
|
||||||
|
this.forward = null;
|
||||||
|
this.found = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
// This doesn't work yet.
|
||||||
|
resetCaret: function () {
|
||||||
|
let equal = function (r1, r2) !r1.compareToRange(Range.START_TO_START, r2) && !r1.compareToRange(Range.END_TO_END, r2);
|
||||||
|
letselection = this.win.getSelection();
|
||||||
|
if (selection.rangeCount == 0)
|
||||||
|
selection.addRange(this.pageStart);
|
||||||
|
function getLines() {
|
||||||
|
let orig = selection.getRangeAt(0);
|
||||||
|
function getRanges(forward) {
|
||||||
|
selection.removeAllRanges();
|
||||||
|
selection.addRange(orig);
|
||||||
|
let cur = orig;
|
||||||
|
while (true) {
|
||||||
|
var last = cur;
|
||||||
|
this.sel.lineMove(forward, false);
|
||||||
|
cur = selection.getRangeAt(0);
|
||||||
|
if (equal(cur, last))
|
||||||
|
break;
|
||||||
|
yield cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield orig;
|
||||||
|
for (let range in getRanges(true))
|
||||||
|
yield range;
|
||||||
|
for (let range in getRanges(false))
|
||||||
|
yield range;
|
||||||
|
}
|
||||||
|
for (let range in getLines()) {
|
||||||
|
if (this.sel.checkVisibility(range.startContainer, range.startOffset, range.startOffset))
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
get searchString() this.lastString,
|
||||||
|
get backward() this.finder.findBackwards,
|
||||||
|
|
||||||
|
search: function (word, reverse) {
|
||||||
|
this.finder.findBackwards = reverse ? !this._backward : this._backward;
|
||||||
|
let again = word == null;
|
||||||
|
if (again)
|
||||||
|
word = this.lastString;
|
||||||
|
if (!this.matchCase)
|
||||||
|
word = word.toLowerCase();
|
||||||
|
|
||||||
|
if (word == "")
|
||||||
|
var range = this.startRange;
|
||||||
|
else {
|
||||||
|
if (this.lastRange) {
|
||||||
|
if (again)
|
||||||
|
this.lastRange.collapse(this.backward);
|
||||||
|
else if (word.indexOf(this.lastString) != 0 || this.backward)
|
||||||
|
this.lastRange = null;
|
||||||
|
else
|
||||||
|
this.lastRange.collapse(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var range = this.finder.Find(word, this.pageRange,
|
||||||
|
this.lastRange || this.startRange,
|
||||||
|
this.pageEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastString = word;
|
||||||
|
if (range == null) {
|
||||||
|
if (this.wrapped) {
|
||||||
|
this.cancel();
|
||||||
|
this.found = false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
this.wrapped = true;
|
||||||
|
this.lastRange = this.backward ? this.pageEnd : this.pageStart;
|
||||||
|
return this.search(again ? null : word, reverse);
|
||||||
|
}
|
||||||
|
this.wrapped = false;
|
||||||
|
this.selection.removeAllRanges();
|
||||||
|
this.selection.addRange(range);
|
||||||
|
this.sel.scrollSelectionIntoView(this.sel.SELECTION_NORMAL, 0, false);
|
||||||
|
this.lastRange = range.cloneRange();
|
||||||
|
this.found = true;
|
||||||
|
return range;
|
||||||
|
},
|
||||||
|
|
||||||
|
cancel: function () {
|
||||||
|
this.selection.removeAllRanges();
|
||||||
|
this.selection.addRange(this.startRange);
|
||||||
|
this.win.scrollTo(this.start.x, this.start.y);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// vim: set fdm=marker sw=4 ts=4 et:
|
// vim: set fdm=marker sw=4 ts=4 et:
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ window.addEventListener("load", function () {
|
|||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
const deferredInit = { load: [] };
|
const deferredInit = { load: [] };
|
||||||
const seen = set();
|
const seen = set();
|
||||||
|
const loaded = [];
|
||||||
|
|
||||||
function load(module, prereq) {
|
function load(module, prereq) {
|
||||||
try {
|
try {
|
||||||
@@ -36,23 +37,26 @@ window.addEventListener("load", function () {
|
|||||||
load(Module.constructors[dep], module.name);
|
load(Module.constructors[dep], module.name);
|
||||||
|
|
||||||
dump("Load" + (isstring(prereq) ? " " + prereq + " dependency: " : ": ") + module.name);
|
dump("Load" + (isstring(prereq) ? " " + prereq + " dependency: " : ": ") + module.name);
|
||||||
|
loaded.push(module.name);
|
||||||
modules[module.name] = module();
|
modules[module.name] = module();
|
||||||
|
|
||||||
function init(mod, module)
|
function init(mod, module)
|
||||||
function () module.INIT[mod].call(modules[module.name], modules[mod]);
|
function () module.INIT[mod].call(modules[module.name], modules[mod]);
|
||||||
for (let [mod, ] in iter(module.INIT))
|
for (let mod in values(loaded)) {
|
||||||
try {
|
try {
|
||||||
if (mod in modules)
|
if (mod in module.INIT)
|
||||||
init(mod, module)();
|
init(mod, module)();
|
||||||
else {
|
delete module.INIT[mod]
|
||||||
deferredInit[mod] = deferredInit[mod] || [];
|
|
||||||
deferredInit[mod].push(init(mod, module));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
if (modules.liberator)
|
if (modules.liberator)
|
||||||
liberator.reportError(e);
|
liberator.reportError(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
for (let mod in keys(module.INIT)) {
|
||||||
|
deferredInit[mod] = deferredInit[mod] || [];
|
||||||
|
deferredInit[mod].push(init(mod, module));
|
||||||
|
}
|
||||||
for (let [, fn] in iter(deferredInit[module.name] || []))
|
for (let [, fn] in iter(deferredInit[module.name] || []))
|
||||||
fn();
|
fn();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user