1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-23 20:02:25 +01:00

Beginnings of bettter incsearch support

This commit is contained in:
Kris Maglione
2008-10-18 02:58:05 +00:00
parent f0318d9675
commit 0dab4f86cf
4 changed files with 169 additions and 50 deletions

View File

@@ -28,6 +28,8 @@ the terms of any one of the MPL, the GPL or the LGPL.
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const Point = new Struct("x", "y");
function Buffer() //{{{ function Buffer() //{{{
{ {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -1278,17 +1280,13 @@ function Buffer() //{{{
if (!selection) if (!selection)
{ {
var selectionController = getBrowser().docShell let selController = this.selectionController;
.QueryInterface(Components.interfaces.nsIInterfaceRequestor) let caretmode = selController.getCaretEnabled();
.getInterface(Components.interfaces.nsISelectionDisplay) selController.setCaretEnabled(true);
.QueryInterface(Components.interfaces.nsISelectionController); selController.wordMove(false, false);
selController.wordMove(true, true);
var caretmode = selectionController.getCaretEnabled();
selectionController.setCaretEnabled(true);
selectionController.wordMove(false, false);
selectionController.wordMove(true, true);
selection = window.content.getSelection().toString(); selection = window.content.getSelection().toString();
selectionController.setCaretEnabled(caretmode); selController.setCaretEnabled(caretmode);
} }
return selection; return selection;
@@ -1481,6 +1479,11 @@ function Buffer() //{{{
}) })
}, },
get selectionController() getBrowser().docShell
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsISelectionDisplay)
.QueryInterface(Components.interfaces.nsISelectionController),
saveLink: function (elem, skipPrompt) saveLink: function (elem, skipPrompt)
{ {
var doc = elem.ownerDocument; var doc = elem.ownerDocument;

View File

@@ -149,8 +149,16 @@ function Completion() //{{{
// Things we can dereference // Things we can dereference
if (["object", "string", "function"].indexOf(typeof obj) == -1) if (["object", "string", "function"].indexOf(typeof obj) == -1)
continue; continue;
/* Try harder.
if (/^\[XPCNativeWrapper /.test(obj)) if (/^\[XPCNativeWrapper /.test(obj))
obj = obj.wrappedJSObject; obj = obj.wrappedJSObject;
*/
try
{
if (obj.wrappedJSObject)
obj = obj.wrappedJSObject;
}
catch (e) {}
for (let [k, v] in this.iter(obj)) for (let [k, v] in this.iter(obj))
compl.push([k, v]); compl.push([k, v]);
@@ -381,7 +389,7 @@ function Completion() //{{{
let statement = get(frame, 0, STATEMENTS) || 0; // Current statement. let statement = get(frame, 0, STATEMENTS) || 0; // Current statement.
let prev = statement; let prev = statement;
let obj; let obj;
for (let [i, dot] in Iterator(get(frame)[DOTS])) for (let [i, dot] in Iterator(get(frame)[DOTS].concat(stop)))
{ {
if (dot < statement) if (dot < statement)
continue; continue;

View File

@@ -1,4 +1,4 @@
/***** BEGIN LICENSE BLOCK ***** {{{ /***** B/GIN LICENSE BLOCK ***** {{{
Version: MPL 1.1/GPL 2.0/LGPL 2.1 Version: MPL 1.1/GPL 2.0/LGPL 2.1
The contents of this file are subject to the Mozilla Public License Version The contents of this file are subject to the Mozilla Public License Version
@@ -54,6 +54,7 @@ function Search() //{{{
var lastSearchBackwards = false; // like "backwards", but for the last search, so if you cancel a search with <esc> this is not set var lastSearchBackwards = false; // like "backwards", but for the last search, so if you cancel a search with <esc> this is not set
var caseSensitive = false; // search string is case sensitive var caseSensitive = false; // search string is case sensitive
var linksOnly = false; // search is limited to link text only var linksOnly = false; // search is limited to link text only
var rangeFind;
// Event handlers for search - closure is needed // Event handlers for search - closure is needed
liberator.registerCallback("change", modes.SEARCH_FORWARD, function (command) { search.searchKeyPressed(command); }); liberator.registerCallback("change", modes.SEARCH_FORWARD, function (command) { search.searchKeyPressed(command); });
@@ -109,6 +110,129 @@ function Search() //{{{
searchString = pattern; searchString = pattern;
} }
function RangeFind(matchCase, backward)
{
var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"]
.createInstance()
.QueryInterface(Components.interfaces.nsIFind);
finder.caseSensitive = matchCase;
var sel = buffer.selectionController;
var doc = content.document;
var win = content;
var pageRange = doc.createRange();
pageRange.setStartBefore(doc.body);
pageRange.setEndAfter(doc.body);
var pageStart = pageRange.cloneRange();
var pageEnd = pageRange.cloneRange();
pageStart.collapse(true);
pageEnd.collapse(false);
// This doesn't work yet.
this.resetCaret = function ()
{
let equal = function (r1, r2) !r1.compareToRange(Range.START_TO_START, r2) && !r1.compareToRange(Range.END_TO_END, r2);
let selection = win.getSelection();
if (selection.rangeCount == 0)
selection.addRange(pageStart);
function getLines()
{
let orig = selection.getRangeAt(0);
function getRanges(forward)
{
selection.removeAllRanges();
selection.addRange(orig);
let cur = orig;
while (true)
{
var last = cur;
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 (sel.checkVisibility(range.startContainer, range.startOffset, range.startOffset))
return range;
}
return null;
}
var start = new Point(win.pageXOffset, win.pageYOffset);
let selection = sel.getSelection(sel.SELECTION_NORMAL);
var startRange = selection.rangeCount ? selection.getRangeAt(0) : pageStart;
startRange.collapse(true);
var lastString = "";
var lastRange;
var forward;
this.__defineGetter__("searchString", function () lastString);
this.__defineGetter__("backward", function () finder.findBackwards);
this.search = function (word, reverse)
{
finder.findBackwards = reverse ? !backward : backward;
let again = word == null;
if (again)
word = lastString;
if (!matchCase)
word = word.toLowerCase();
if (word == "")
var range = startRange;
else
{
if (lastRange)
{
if (again)
lastRange.collapse(this.backward);
else if (word.indexOf(lastString) != 0 || this.backward)
lastRange = null;
else
lastRange.collapse(true);
}
var range = finder.Find(word, pageRange,
lastRange || startRange,
pageEnd);
}
lastString = word;
if (range == null)
{
liberator.dump(this.wrapped);
if (this.wrapped)
return null;
this.wrapped = true;
lastRange = this.backward ? pageEnd : pageStart;
return this.search(again ? null : word, reverse);
}
this.wrapped = false;
selection.removeAllRanges();
selection.addRange(range);
sel.scrollSelectionIntoView(sel.SELECTION_NORMAL, 0, false);
lastRange = range.cloneRange();
return range;
}
this.cancel = function ()
{
selection.removeAllRanges();
selection.addRange(startRange);
win.scrollTo(start.x, start.y);
}
}
/* Stolen from toolkit.jar in Firefox, for the time being. The private /* Stolen from toolkit.jar in Firefox, for the time being. The private
* methods were unstable, and changed. The new version is not remotely * methods were unstable, and changed. The new version is not remotely
* compatible with what we do. * compatible with what we do.
@@ -328,19 +452,17 @@ function Search() //{{{
backwards = false; backwards = false;
} }
this.find("", backwards);
// TODO: focus the top of the currently visible screen // TODO: focus the top of the currently visible screen
}, },
// Finds text in a page // Finds text in a page
// TODO: backwards seems impossible i fear :(
find: function (str, backwards) find: function (str, backwards)
{ {
var fastFind = getBrowser().fastFind;
processUserPattern(str); processUserPattern(str);
fastFind.caseSensitive = caseSensitive; rangeFind = new RangeFind(caseSensitive, backwards);
found = fastFind.find(searchString, linksOnly) != Components.interfaces.nsITypeAheadFind.FIND_NOTFOUND; found = rangeFind.search(searchString);
if (!found) if (!found)
setTimeout(function () { liberator.echoerr("E486: Pattern not found: " + searchPattern); }, 0); setTimeout(function () { liberator.echoerr("E486: Pattern not found: " + searchPattern); }, 0);
@@ -351,25 +473,14 @@ function Search() //{{{
// Called when the current search needs to be repeated // Called when the current search needs to be repeated
findAgain: function (reverse) findAgain: function (reverse)
{ {
// this hack is needed to make n/N work with the correct string, if if (!rangeFind || !rangeFind.search(null, reverse))
// we typed /foo<esc> after the original search. Since searchString is
// readonly we have to call find() again to update it.
if (getBrowser().fastFind.searchString != lastSearchString)
this.find(lastSearchString, false);
var up = reverse ? !lastSearchBackwards : lastSearchBackwards;
var result = getBrowser().fastFind.findAgain(up, linksOnly);
if (result == Components.interfaces.nsITypeAheadFind.FIND_NOTFOUND)
{
liberator.echoerr("E486: Pattern not found: " + lastSearchPattern); liberator.echoerr("E486: Pattern not found: " + lastSearchPattern);
} else if (rangeFind.wrapped)
else if (result == Components.interfaces.nsITypeAheadFind.FIND_WRAPPED)
{ {
// hack needed, because wrapping causes a "scroll" event which clears // hack needed, because wrapping causes a "scroll" event which clears
// our command line // our command line
setTimeout(function () { setTimeout(function () {
if (up) if (rangeFind.backward)
commandline.echo("search hit TOP, continuing at BOTTOM", commandline.echo("search hit TOP, continuing at BOTTOM",
commandline.HL_WARNINGMSG, commandline.APPEND_TO_MESSAGES); commandline.HL_WARNINGMSG, commandline.APPEND_TO_MESSAGES);
else else
@@ -379,7 +490,7 @@ function Search() //{{{
} }
else else
{ {
liberator.echo((up ? "?" : "/") + lastSearchPattern, null, commandline.FORCE_SINGLELINE); liberator.echo((rangeFind.backward ? "?" : "/") + lastSearchPattern, null, commandline.FORCE_SINGLELINE);
if (options["hlsearch"]) if (options["hlsearch"])
this.highlight(lastSearchString); this.highlight(lastSearchString);
@@ -390,7 +501,7 @@ function Search() //{{{
searchKeyPressed: function (command) searchKeyPressed: function (command)
{ {
if (options["incsearch"]) if (options["incsearch"])
this.find(command, backwards); rangeFind.search(command);
}, },
// Called when the enter key is pressed to trigger a search // Called when the enter key is pressed to trigger a search
@@ -404,22 +515,19 @@ function Search() //{{{
if (!command) if (!command)
command = lastSearchPattern; command = lastSearchPattern;
this.clear();
if (!options["incsearch"] || !found) if (!options["incsearch"] || !found)
{
this.clear();
this.find(command, backwards); this.find(command, backwards);
}
lastSearchBackwards = backwards; lastSearchBackwards = backwards;
//lastSearchPattern = command.replace(backwards ? /\?.*/ : /\/.*/, ""); // XXX //lastSearchPattern = command.replace(backwards ? /\?.*/ : /\/.*/, ""); // XXX
lastSearchPattern = command; lastSearchPattern = command;
lastSearchString = searchString; lastSearchString = searchString;
// TODO: move to find() when reverse incremental searching is kludged in
// need to find again for reverse searching
if (backwards)
setTimeout(function () { search.findAgain(false); }, 0);
if (options["hlsearch"]) if (options["hlsearch"])
this.highlight(searchString); this.highlight(rangeFind.searchString);
modes.reset(); modes.reset();
}, },
@@ -430,15 +538,15 @@ function Search() //{{{
{ {
this.clear(); this.clear();
// TODO: code to reposition the document to the place before search started // TODO: code to reposition the document to the place before search started
if (rangeFind)
rangeFind.cancel();
rangeFind = null;
}, },
// FIXME: thunderbird incompatible // FIXME: thunderbird incompatible
// this is not dependent on the value of 'hlsearch' // this is not dependent on the value of 'hlsearch'
highlight: function (text) highlight: function (text)
{ {
if (config.name == "Muttator")
return;
// already highlighted? // already highlighted?
if (window.content.document.getElementsByClassName("__liberator-search").length > 0) if (window.content.document.getElementsByClassName("__liberator-search").length > 0)
return; return;
@@ -449,7 +557,8 @@ function Search() //{{{
highlightObj.highlightDoc(window.content, text); highlightObj.highlightDoc(window.content, text);
// recreate selection since _highlightDoc collapses the selection backwards // recreate selection since _highlightDoc collapses the selection backwards
getBrowser().fastFind.findAgain(false, linksOnly); if (rangeFind)
rangeFind.search(null);
// TODO: remove highlighting from non-link matches (HTML - A/AREA with href attribute; XML - Xlink [type="simple"]) // TODO: remove highlighting from non-link matches (HTML - A/AREA with href attribute; XML - Xlink [type="simple"])
}, },
@@ -457,10 +566,9 @@ function Search() //{{{
clear: function () clear: function ()
{ {
highlightObj.highlightDoc(window.content); highlightObj.highlightDoc(window.content);
// need to manually collapse the selection if the document is not },
// highlighted
getBrowser().fastFind.collapseSelection(); rangeFind: RangeFind
}
}; };
//}}} //}}}

View File

@@ -24,6 +24,7 @@
Components.utils.import("resource://liberator/storage.jsm", modules); Components.utils.import("resource://liberator/storage.jsm", modules);
["liberator.js", ["liberator.js",
"util.js",
"config.js", "config.js",
"buffer.js", "buffer.js",
"commands.js", "commands.js",
@@ -37,8 +38,7 @@
"modes.js", "modes.js",
"options.js", "options.js",
"template.js", "template.js",
"ui.js", "ui.js"].forEach(load);
"util.js"].forEach(load);
modules.config.scripts.forEach(load); modules.config.scripts.forEach(load);
})() })()