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
|
||||
// objects are problematic, to say the least.
|
||||
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,
|
||||
|
||||
@@ -1063,6 +1063,9 @@ const Events = Module("events", {
|
||||
if (stop)
|
||||
killEvent();
|
||||
}
|
||||
catch (e) {
|
||||
liberator.reportError(e);
|
||||
}
|
||||
finally {
|
||||
let motionMap = (this._input.pendingMotionMap && this._input.pendingMotionMap.names[0]) || "";
|
||||
if (!(modes.extended & modes.HINTS))
|
||||
|
||||
@@ -224,7 +224,7 @@ const Finder = Module("finder", {
|
||||
// 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>.
|
||||
*
|
||||
@@ -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:
|
||||
|
||||
@@ -23,6 +23,7 @@ window.addEventListener("load", function () {
|
||||
const start = Date.now();
|
||||
const deferredInit = { load: [] };
|
||||
const seen = set();
|
||||
const loaded = [];
|
||||
|
||||
function load(module, prereq) {
|
||||
try {
|
||||
@@ -36,23 +37,26 @@ window.addEventListener("load", function () {
|
||||
load(Module.constructors[dep], module.name);
|
||||
|
||||
dump("Load" + (isstring(prereq) ? " " + prereq + " dependency: " : ": ") + module.name);
|
||||
loaded.push(module.name);
|
||||
modules[module.name] = module();
|
||||
|
||||
function init(mod, module)
|
||||
function () module.INIT[mod].call(modules[module.name], modules[mod]);
|
||||
for (let [mod, ] in iter(module.INIT))
|
||||
for (let mod in values(loaded)) {
|
||||
try {
|
||||
if (mod in modules)
|
||||
if (mod in module.INIT)
|
||||
init(mod, module)();
|
||||
else {
|
||||
deferredInit[mod] = deferredInit[mod] || [];
|
||||
deferredInit[mod].push(init(mod, module));
|
||||
}
|
||||
delete module.INIT[mod]
|
||||
}
|
||||
catch(e) {
|
||||
if (modules.liberator)
|
||||
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] || []))
|
||||
fn();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user