add multiline string support to editor find
(works for plain text searches not regexps)
This commit is contained in:
parent
a6e2d756ee
commit
707adc2ff5
1 changed files with 112 additions and 119 deletions
|
|
@ -63,7 +63,7 @@ var Range = require("./range").Range;
|
||||||
* * `wholeWord`: `false`
|
* * `wholeWord`: `false`
|
||||||
* * `scope`: `ALL`
|
* * `scope`: `ALL`
|
||||||
* * `regExp`: `false`
|
* * `regExp`: `false`
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
|
|
||||||
var Search = function() {
|
var Search = function() {
|
||||||
|
|
@ -88,7 +88,7 @@ Search.SELECTION = 2;
|
||||||
* - options (Object): An object containing all the new search properties
|
* - options (Object): An object containing all the new search properties
|
||||||
*
|
*
|
||||||
* Sets the search options via the `options` parameter.
|
* Sets the search options via the `options` parameter.
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
this.set = function(options) {
|
this.set = function(options) {
|
||||||
oop.mixin(this.$options, options);
|
oop.mixin(this.$options, options);
|
||||||
|
|
@ -99,8 +99,8 @@ Search.SELECTION = 2;
|
||||||
* Search.getOptions() -> Object
|
* Search.getOptions() -> Object
|
||||||
*
|
*
|
||||||
* [Returns an object containing all the search options.]{: #Search.getOptions}
|
* [Returns an object containing all the search options.]{: #Search.getOptions}
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
this.getOptions = function() {
|
this.getOptions = function() {
|
||||||
return lang.copyObject(this.$options);
|
return lang.copyObject(this.$options);
|
||||||
};
|
};
|
||||||
|
|
@ -110,16 +110,14 @@ Search.SELECTION = 2;
|
||||||
* - session (EditSession): The session to search with
|
* - session (EditSession): The session to search with
|
||||||
*
|
*
|
||||||
* Searches for `options.needle`. If found, this method returns the [[Range `Range`]] where the text first occurs. If `options.backwards` is `true`, the search goes backwards in the session.
|
* Searches for `options.needle`. If found, this method returns the [[Range `Range`]] where the text first occurs. If `options.backwards` is `true`, the search goes backwards in the session.
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
this.find = function(session) {
|
this.find = function(session) {
|
||||||
if (!this.$options.needle)
|
if (!this.$options.needle)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var iterator = this.$options.backwards
|
var iterator = this.$matchIterator(session);
|
||||||
? this.$backwardMatchIterator(session)
|
|
||||||
: this.$forwardMatchIterator(session);
|
|
||||||
|
|
||||||
if (!iterator)
|
if (!iterator)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -137,17 +135,15 @@ Search.SELECTION = 2;
|
||||||
* - session (EditSession): The session to search with
|
* - session (EditSession): The session to search with
|
||||||
*
|
*
|
||||||
* Searches for all occurances `options.needle`. If found, this method returns an array of [[Range `Range`s]] where the text first occurs. If `options.backwards` is `true`, the search goes backwards in the session.
|
* Searches for all occurances `options.needle`. If found, this method returns an array of [[Range `Range`s]] where the text first occurs. If `options.backwards` is `true`, the search goes backwards in the session.
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
this.findAll = function(session) {
|
this.findAll = function(session) {
|
||||||
var options = this.$options;
|
var options = this.$options;
|
||||||
if (!options.needle)
|
if (!options.needle)
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
var iterator = options.backwards
|
var iterator = this.$matchIterator(session);
|
||||||
? this.$backwardMatchIterator(session)
|
|
||||||
: this.$forwardMatchIterator(session);
|
|
||||||
|
|
||||||
if (!iterator)
|
if (!iterator)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -173,16 +169,14 @@ Search.SELECTION = 2;
|
||||||
* + (String): If `options.regExp` is `true`, this function returns `input` with the replacement already made. Otherwise, this function just returns `replacement`.<br/>
|
* + (String): If `options.regExp` is `true`, this function returns `input` with the replacement already made. Otherwise, this function just returns `replacement`.<br/>
|
||||||
* If `options.needle` was not found, this function returns `null`.
|
* If `options.needle` was not found, this function returns `null`.
|
||||||
*
|
*
|
||||||
* Searches for `options.needle` in `input`, and, if found, replaces it with `replacement`.
|
* Searches for `options.needle` in `input`, and, if found, replaces it with `replacement`.
|
||||||
*
|
*
|
||||||
*
|
**/
|
||||||
*
|
|
||||||
**/
|
|
||||||
this.replace = function(input, replacement) {
|
this.replace = function(input, replacement) {
|
||||||
var re = this.$assembleRegExp();
|
var re = this.$assembleRegExp();
|
||||||
if (!re)
|
if (!re)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var match = re.exec(input);
|
var match = re.exec(input);
|
||||||
if (match && match[0].length == input.length) {
|
if (match && match[0].length == input.length) {
|
||||||
if (this.$options.regExp) {
|
if (this.$options.regExp) {
|
||||||
|
|
@ -196,89 +190,97 @@ Search.SELECTION = 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** internal, hide
|
/** internal, hide
|
||||||
* Search.$forwardMatchIterator(session) -> String | Boolean
|
* Search.$matchIterator(session) -> String | Boolean
|
||||||
* - session (EditSession): The session to search with
|
* - session (EditSession): The session to search with
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
this.$forwardMatchIterator = function(session) {
|
this.$matchIterator = function(session) {
|
||||||
var re = this.$assembleRegExp();
|
var re = this.$assembleRegExp();
|
||||||
if (!re)
|
if (!re)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
return {
|
var self = this, callback, backwards = this.$options.backwards;
|
||||||
forEach: function(callback) {
|
|
||||||
self.$forwardLineIterator(session).forEach(function(line, startIndex, row) {
|
|
||||||
if (startIndex) {
|
|
||||||
line = line.substring(startIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
var matches = [];
|
if (this.$options.$isMultiLine) {
|
||||||
|
var matchIterator = function(line, startIndex, row) {
|
||||||
|
var startLine = line;
|
||||||
|
if (startIndex)
|
||||||
|
line = line.substring(startIndex);
|
||||||
|
|
||||||
line.replace(re, function(str) {
|
var len = re.length;
|
||||||
var offset = arguments[arguments.length-2];
|
var part = re[0];
|
||||||
matches.push({
|
if (line.slice(-part.length) != part)
|
||||||
str: str,
|
return;
|
||||||
offset: startIndex + offset
|
|
||||||
});
|
|
||||||
return str;
|
|
||||||
});
|
|
||||||
|
|
||||||
for (var i=0; i<matches.length; i++) {
|
for (var i = 1; i < len - 1; i++)
|
||||||
var match = matches[i];
|
if (re[i] != session.getLine(row + i))
|
||||||
var range = self.$rangeFromMatch(row, match.offset, match.str.length);
|
return;
|
||||||
if (callback(range))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
part = re[len - 1];
|
||||||
|
if (session.getLine(row + len - 1).slice(0, part.length) != part)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var range = new Range(
|
||||||
|
row, startLine.length - re[0].length,
|
||||||
|
row + len - 1, re[len - 1].length
|
||||||
|
);
|
||||||
|
if (callback(range))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
} else if (backwards) {
|
||||||
};
|
var matchIterator = function(line, startIndex, row) {
|
||||||
|
if (startIndex)
|
||||||
|
line = line.substring(startIndex);
|
||||||
|
|
||||||
/** internal, hide
|
var matches = [];
|
||||||
* Search.$backwardMatchIterator(session) -> String
|
|
||||||
* - session (EditSession): The session to search with
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
this.$backwardMatchIterator = function(session) {
|
|
||||||
var re = this.$assembleRegExp();
|
|
||||||
if (!re)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
return {
|
line.replace(re, function(str) {
|
||||||
forEach: function(callback) {
|
var offset = arguments[arguments.length-2];
|
||||||
self.$backwardLineIterator(session).forEach(function(line, startIndex, row) {
|
matches.push({
|
||||||
if (startIndex) {
|
str: str,
|
||||||
line = line.substring(startIndex);
|
offset: startIndex + offset
|
||||||
}
|
|
||||||
|
|
||||||
var matches = [];
|
|
||||||
|
|
||||||
line.replace(re, function(str, offset) {
|
|
||||||
matches.push({
|
|
||||||
str: str,
|
|
||||||
offset: startIndex + offset
|
|
||||||
});
|
|
||||||
return str;
|
|
||||||
});
|
});
|
||||||
|
return str;
|
||||||
for (var i=matches.length-1; i>= 0; i--) {
|
|
||||||
var match = matches[i];
|
|
||||||
var range = self.$rangeFromMatch(row, match.offset, match.str.length);
|
|
||||||
if (callback(range))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (var i=matches.length-1; i>= 0; i--) {
|
||||||
|
var match = matches[i];
|
||||||
|
var range = self.$rangeFromMatch(row, match.offset, match.str.length);
|
||||||
|
if (callback(range))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
} else {
|
||||||
|
var matchIterator = function(line, startIndex, row) {
|
||||||
|
if (startIndex)
|
||||||
|
line = line.substring(startIndex);
|
||||||
|
|
||||||
|
var matches = [];
|
||||||
|
|
||||||
|
line.replace(re, function(str) {
|
||||||
|
var offset = arguments[arguments.length-2];
|
||||||
|
matches.push({
|
||||||
|
str: str,
|
||||||
|
offset: startIndex + offset
|
||||||
|
});
|
||||||
|
return str;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var i=0; i<matches.length; i++) {
|
||||||
|
var match = matches[i];
|
||||||
|
var range = self.$rangeFromMatch(row, match.offset, match.str.length);
|
||||||
|
if (callback(range))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {forEach: function(_callback) {
|
||||||
|
callback = _callback;
|
||||||
|
self.$lineIterator(session).forEach(matchIterator);
|
||||||
|
}};
|
||||||
};
|
};
|
||||||
|
|
||||||
this.$rangeFromMatch = function(row, column, length) {
|
this.$rangeFromMatch = function(row, column, length) {
|
||||||
|
|
@ -289,12 +291,18 @@ Search.SELECTION = 2;
|
||||||
if (typeof this.$options.needle != 'string')
|
if (typeof this.$options.needle != 'string')
|
||||||
return this.$options.needle;
|
return this.$options.needle;
|
||||||
|
|
||||||
if (this.$options.regExp) {
|
var needle = this.$options.needle;
|
||||||
var needle = this.$options.needle;
|
|
||||||
} else {
|
if (!this.$options.regExp) {
|
||||||
needle = lang.escapeRegExp(this.$options.needle);
|
if (/[\n\r]/.test(needle)){
|
||||||
|
this.$options.$isMultiLine = true;
|
||||||
|
return needle.split(/\r\n|\r|\n/)
|
||||||
|
}
|
||||||
|
needle = lang.escapeRegExp(needle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.$options.$isMultiLine = false;
|
||||||
|
|
||||||
if (this.$options.wholeWord) {
|
if (this.$options.wholeWord) {
|
||||||
needle = "\\b" + needle + "\\b";
|
needle = "\\b" + needle + "\\b";
|
||||||
}
|
}
|
||||||
|
|
@ -310,15 +318,16 @@ Search.SELECTION = 2;
|
||||||
catch(e) {
|
catch(e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return re;
|
return re;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.$forwardLineIterator = function(session) {
|
this.$lineIterator = function(session) {
|
||||||
var searchSelection = this.$options.scope == Search.SELECTION;
|
var searchSelection = this.$options.scope == Search.SELECTION;
|
||||||
|
var backwards = this.$options.backwards;
|
||||||
|
|
||||||
var range = this.$options.range || session.getSelection().getRange();
|
var range = this.$options.range || session.getSelection().getRange();
|
||||||
var start = this.$options.start || range[searchSelection ? "start" : "end"];
|
var start = this.$options.start || range[searchSelection != backwards ? "start" : "end"];
|
||||||
|
|
||||||
var firstRow = searchSelection ? range.start.row : 0;
|
var firstRow = searchSelection ? range.start.row : 0;
|
||||||
var firstColumn = searchSelection ? range.start.column : 0;
|
var firstColumn = searchSelection ? range.start.column : 0;
|
||||||
|
|
@ -338,8 +347,8 @@ Search.SELECTION = 2;
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
if (!backwards) {
|
||||||
forEach: function(callback) {
|
var forEach = function(callback) {
|
||||||
var row = start.row;
|
var row = start.row;
|
||||||
|
|
||||||
var line = getLine(row);
|
var line = getLine(row);
|
||||||
|
|
@ -349,10 +358,8 @@ Search.SELECTION = 2;
|
||||||
inWrap = false;
|
inWrap = false;
|
||||||
|
|
||||||
while (!callback(line, startIndex, row)) {
|
while (!callback(line, startIndex, row)) {
|
||||||
|
if (stop)
|
||||||
if (stop) {
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
row++;
|
row++;
|
||||||
startIndex = 0;
|
startIndex = 0;
|
||||||
|
|
@ -373,23 +380,8 @@ Search.SELECTION = 2;
|
||||||
line = getLine(row);
|
line = getLine(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
} else {
|
||||||
};
|
var forEach = function(callback) {
|
||||||
|
|
||||||
this.$backwardLineIterator = function(session) {
|
|
||||||
var searchSelection = this.$options.scope == Search.SELECTION;
|
|
||||||
|
|
||||||
var range = this.$options.range || session.getSelection().getRange();
|
|
||||||
var start = this.$options.start || range[searchSelection ? "end" : "start"];
|
|
||||||
|
|
||||||
var firstRow = searchSelection ? range.start.row : 0;
|
|
||||||
var firstColumn = searchSelection ? range.start.column : 0;
|
|
||||||
var lastRow = searchSelection ? range.end.row : session.getLength() - 1;
|
|
||||||
|
|
||||||
var wrap = this.$options.wrap;
|
|
||||||
|
|
||||||
return {
|
|
||||||
forEach : function(callback) {
|
|
||||||
var row = start.row;
|
var row = start.row;
|
||||||
|
|
||||||
var line = session.getLine(row).substring(0, start.column);
|
var line = session.getLine(row).substring(0, start.column);
|
||||||
|
|
@ -398,7 +390,6 @@ Search.SELECTION = 2;
|
||||||
var inWrap = false;
|
var inWrap = false;
|
||||||
|
|
||||||
while (!callback(line, startIndex, row)) {
|
while (!callback(line, startIndex, row)) {
|
||||||
|
|
||||||
if (stop)
|
if (stop)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -429,7 +420,9 @@ Search.SELECTION = 2;
|
||||||
startIndex = start.column;
|
startIndex = start.column;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
return {forEach: forEach};
|
||||||
};
|
};
|
||||||
|
|
||||||
}).call(Search.prototype);
|
}).call(Search.prototype);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue