+
diff --git a/src/htmlContent/search-results.html b/src/htmlContent/search-results.html
new file mode 100644
index 00000000000..0083b724e5b
--- /dev/null
+++ b/src/htmlContent/search-results.html
@@ -0,0 +1,16 @@
+
+
+ {{#searchList}}
+
+
{{{filename}}}
+
+ {{#items}}
+
+
+
{{line}}
+
{{pre}}{{highlight}}{{post}}
+
+ {{/items}}
+ {{/searchList}}
+
+
diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js
index b99250cd089..2036725d8a2 100644
--- a/src/nls/root/strings.js
+++ b/src/nls/root/strings.js
@@ -111,15 +111,18 @@ define({
"FIND_IN_FILES_TITLE" : "for \"{4}\" {5} - {0} {1} in {2} {3}",
"FIND_IN_FILES_SCOPED" : "in {0}",
- "FIND_IN_FILES_NO_SCOPE" : "in project",
+ "FIND_IN_FILES_WORKING_SET" : "in working set",
+ "FIND_IN_FILES_PROJECT" : "in project",
"FIND_IN_FILES_FILE" : "file",
"FIND_IN_FILES_FILES" : "files",
"FIND_IN_FILES_MATCH" : "match",
"FIND_IN_FILES_MATCHES" : "matches",
"FIND_IN_FILES_MORE_THAN" : "More than ",
- "FIND_IN_FILES_MAX" : " (showing the first {0} matches)",
+ "FIND_IN_FILES_PAGING" : " (showing matches {0} to {1})",
+ "FIND_IN_FILES_LESS" : " Less",
+ "FIND_IN_FILES_MORE" : " More",
"FIND_IN_FILES_FILE_PATH" : "File: {0}",
- "FIND_IN_FILES_LINE" : "line: {0}",
+ "FIND_IN_FILES_LINE" : "line: {0}",
"ERROR_FETCHING_UPDATE_INFO_TITLE" : "Error getting update info",
"ERROR_FETCHING_UPDATE_INFO_MSG" : "There was a problem getting the latest update information from the server. Please make sure you are connected to the internet and try again.",
@@ -188,12 +191,6 @@ define({
"CMD_PASTE" : "Paste",
"CMD_SELECT_ALL" : "Select All",
"CMD_SELECT_LINE" : "Select Line",
- "CMD_FIND" : "Find",
- "CMD_FIND_IN_FILES" : "Find in Files",
- "CMD_FIND_IN_SUBTREE" : "Find in\u2026",
- "CMD_FIND_NEXT" : "Find Next",
- "CMD_FIND_PREVIOUS" : "Find Previous",
- "CMD_REPLACE" : "Replace",
"CMD_INDENT" : "Indent",
"CMD_UNINDENT" : "Unindent",
"CMD_DUPLICATE" : "Duplicate",
@@ -204,6 +201,18 @@ define({
"CMD_LINE_DOWN" : "Move Line Down",
"CMD_TOGGLE_CLOSE_BRACKETS" : "Auto Close Braces",
+ // Search menu commands
+ "SEARCH_MENU" : "Search",
+ "CMD_FIND" : "Find",
+ "CMD_FIND_NEXT" : "Find Next",
+ "CMD_FIND_PREVIOUS" : "Find Previous",
+ "CMD_REPLACE" : "Replace",
+ "CMD_FIND_IN_FILES" : "Find in Project",
+ "CMD_FIND_IN_WORKING_SET" : "Find in Working Set",
+ "CMD_FIND_IN_SUBTREE" : "Find in File/Subtree",
+ "CMD_NEXT_RESULT" : "Next Result",
+ "CMD_PREVIOUS_RESULT" : "Previous Result",
+
// View menu commands
"VIEW_MENU" : "View",
"CMD_HIDE_SIDEBAR" : "Hide Sidebar",
diff --git a/src/project/ProjectManager.js b/src/project/ProjectManager.js
index 708aae7062a..c70ea8b83da 100644
--- a/src/project/ProjectManager.js
+++ b/src/project/ProjectManager.js
@@ -180,9 +180,9 @@ define(function (require, exports, module) {
}
/**
- * Returns the FileEntry or DirectoryEntry corresponding to the selected item, or null
- * if no item is selected.
- *
+ * Returns the FileEntry or DirectoryEntry corresponding to the item selected in the file tree, or null
+ * if no item is selected in the tree (though the working set may still have a selection; use
+ * getSidebarSelectedItem() to get the selection regardless of whether it's in the tree or working set).
* @return {?Entry}
*/
function getSelectedItem() {
@@ -192,6 +192,22 @@ define(function (require, exports, module) {
}
return null;
}
+
+ /**
+ * Returns the FileEntry or DirectoryEntry corresponding to the item selected in the sidebar panel, whether in
+ * the file tree OR in the working set; or null if no item is selected anywhere in the sidebar.
+ * @return {?Entry}
+ */
+ function getSidebarSelectedItem() {
+ // Prefer file tree selection, else use working set selection
+ var selectedEntry = getSelectedItem();
+ if (!selectedEntry) {
+ var doc = DocumentManager.getCurrentDocument();
+ selectedEntry = (doc && doc.file);
+ }
+ return selectedEntry;
+ }
+
function _fileViewFocusChange() {
_redraw(true);
@@ -1386,6 +1402,7 @@ define(function (require, exports, module) {
exports.shouldShow = shouldShow;
exports.openProject = openProject;
exports.getSelectedItem = getSelectedItem;
+ exports.getSidebarSelectedItem = getSidebarSelectedItem;
exports.getInitialProjectPath = getInitialProjectPath;
exports.isWelcomeProjectPath = isWelcomeProjectPath;
exports.updateWelcomeProjectPath = updateWelcomeProjectPath;
diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js
index 106981ac661..8a62800744a 100644
--- a/src/search/FindInFiles.js
+++ b/src/search/FindInFiles.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
-/*global define, $, PathUtils, window */
+/*global define, $, PathUtils, Mustache, window */
/*
* Adds a "find in files" command to allow the user to find all occurances of a string in all files in
@@ -33,7 +33,6 @@
* FUTURE:
* - Proper UI for both dialog and results
* - Refactor dialog class and share with Quick File Open
- * - Search files in working set that are *not* in the project
* - Handle matches that span mulitple lines
* - Refactor UI from functionality to enable unit testing
*/
@@ -42,27 +41,72 @@
define(function (require, exports, module) {
"use strict";
- var Async = require("utils/Async"),
- CommandManager = require("command/CommandManager"),
- Commands = require("command/Commands"),
- Strings = require("strings"),
- StringUtils = require("utils/StringUtils"),
- ProjectManager = require("project/ProjectManager"),
- DocumentManager = require("document/DocumentManager"),
- EditorManager = require("editor/EditorManager"),
- FileIndexManager = require("project/FileIndexManager"),
- KeyEvent = require("utils/KeyEvent"),
- AppInit = require("utils/AppInit"),
- StatusBar = require("widgets/StatusBar"),
- ModalBar = require("widgets/ModalBar").ModalBar;
-
- var searchResults = [];
+ var Async = require("utils/Async"),
+ NativeFileSystem = require("file/NativeFileSystem").NativeFileSystem,
+ FileUtils = require("file/FileUtils"),
+ CommandManager = require("command/CommandManager"),
+ Commands = require("command/Commands"),
+ Strings = require("strings"),
+ StringUtils = require("utils/StringUtils"),
+ ProjectManager = require("project/ProjectManager"),
+ FileViewController = require("project/FileViewController"),
+ FileIndexManager = require("project/FileIndexManager"),
+ DocumentManager = require("document/DocumentManager"),
+ EditorManager = require("editor/EditorManager"),
+ KeyEvent = require("utils/KeyEvent"),
+ AppInit = require("utils/AppInit"),
+ CollectionUtils = require("utils/CollectionUtils"),
+ StatusBar = require("widgets/StatusBar"),
+ ModalBar = require("widgets/ModalBar").ModalBar,
+ SearchDialogTemplate = require("text!htmlContent/search-dialog.html"),
+ SearchResultsTemplate = require("text!htmlContent/search-results.html");
+
+ var RESULTS_PER_PAGE = 100,
+ FIND_IN_FILE_MAX = 300;
+
+ /**
+ * Map of all the last search results
+ * @type {Object., collapsed: boolean}>}
+ */
+ var _searchResults = {};
+
+ /** @type {Array.} Keeps a copy of the search files sorted by name and with the selected file first */
+ var _searchFiles = [];
+
+ /** @type {Document} The current editor used to register the change and deleted events */
+ var _currentDocument = null;
+
+ /** @type {string} The current search query */
+ var _currentQuery = "";
+
+ /** @type {RegExp} The current regular expresion created from the search query */
+ var _currentQueryExpr = "";
+
+ /** @type {Array.} An array of the files where it should look or null/empty to search the entire project */
+ var _currentScope = null;
+
+ /** @type {number} The index of the first result that is displayed */
+ var _currentStart = 0;
+
+ /** @type {boolean} True if the matches in a file reached FIND_IN_FILE_MAX */
+ var _maxHitsFoundInFile = false;
+
+ /** @type {boolean} Tracks the automatically selection of the first result after the search is complete */
+ var _gotoFirstResult = false;
- var FIND_IN_FILES_MAX = 100,
- maxHitsFoundInFile = false,
- currentQuery = "",
- currentScope;
+ /** @type {$.Element} jQuery elements used in the search results */
+ var $searchResults,
+ $searchSummary,
+ $searchContent,
+ $selectedRow;
+
+ /**
+ * @private
+ * Returns a regular expression from the given query and shows an error in the modal-bar if it was invalid
+ * @param {!string} query - The query from the modal-bar input
+ * @return {RegExp}
+ */
function _getQueryRegExp(query) {
// Clear any pending RegEx error message
$(".modal-bar .message").css("display", "inline-block");
@@ -96,15 +140,19 @@ define(function (require, exports, module) {
/**
* Returns label text to indicate the search scope. Already HTML-escaped.
- * @param {?Entry} scope
+ * @param {?Array.} scope
*/
function _labelForScope(scope) {
var projName = ProjectManager.getProjectRoot().name;
if (scope) {
- var displayPath = StringUtils.htmlEscape(ProjectManager.makeProjectRelativeIfPossible(scope.fullPath));
- return StringUtils.format(Strings.FIND_IN_FILES_SCOPED, displayPath);
+ if (scope.length === 1) {
+ var displayPath = StringUtils.htmlEscape(ProjectManager.makeProjectRelativeIfPossible(scope[0].fullPath));
+ return StringUtils.format(Strings.FIND_IN_FILES_SCOPED, displayPath);
+ } else {
+ return Strings.FIND_IN_FILES_WORKING_SET;
+ }
} else {
- return Strings.FIND_IN_FILES_NO_SCOPE;
+ return Strings.FIND_IN_FILES_PROJECT;
}
}
@@ -113,18 +161,17 @@ define(function (require, exports, module) {
// class that everyone can use.
/**
- * FindInFilesDialog class
- * @constructor
- *
- */
+ * FindInFilesDialog class
+ * @constructor
+ */
function FindInFilesDialog() {
this.closed = false;
this.result = null; // $.Deferred
}
/**
- * Closes the search dialog and resolves the promise that showDialog returned
- */
+ * Closes the search dialog and resolves the promise that showDialog returned
+ */
FindInFilesDialog.prototype._close = function (value) {
if (this.closed) {
return;
@@ -137,26 +184,26 @@ define(function (require, exports, module) {
};
/**
- * Shows the search dialog
- * @param {?string} initialString Default text to prepopulate the search field with
- * @param {?Entry} scope Search scope, or null to search whole proj
- * @returns {$.Promise} that is resolved with the string to search for
- */
+ * Shows the search dialog
+ * @param {?string} initialString Default text to prepopulate the search field with
+ * @param {?Entry} scope Search scope, or null to search whole proj
+ * @returns {$.Promise} that is resolved with the string to search for
+ */
FindInFilesDialog.prototype.showDialog = function (initialString, scope) {
// Note the prefix label is a simple "Find:" - the "in ..." part comes after the text field
- var dialogHTML = Strings.CMD_FIND +
- ": " +
- "
(" + Strings.SEARCH_REGEXP_INFO + ")
";
- this.result = new $.Deferred();
+ var templateVars = {
+ value: initialString || "",
+ label: _labelForScope(scope)
+ };
+ var dialogHTML = Mustache.render(SearchDialogTemplate, $.extend(templateVars, Strings));
+
+ this.result = new $.Deferred();
this.modalBar = new ModalBar(dialogHTML, false);
- var $searchField = $("input#findInFilesInput");
+
+ var $searchField = $("input#searchInput");
var that = this;
- $searchField.attr("value", initialString || "");
$searchField.get(0).select();
-
- $("#findInFilesScope").html(_labelForScope(scope));
-
$searchField.bind("keydown", function (event) {
if (event.keyCode === KeyEvent.DOM_VK_RETURN || event.keyCode === KeyEvent.DOM_VK_ESCAPE) { // Enter/Return key or Esc key
event.stopPropagation();
@@ -185,6 +232,13 @@ define(function (require, exports, module) {
};
+ /**
+ * @private
+ * Searches throught the contents an returns an array of matches
+ * @param {!string} contents
+ * @param {!RegExp} queryExpr
+ * @return {Array.<{start: {line:number,ch:number}, end: {line:number,ch:number}, line: string}>}
+ */
function _getSearchMatches(contents, queryExpr) {
// Quick exit if not found
if (contents.search(queryExpr) === -1) {
@@ -196,13 +250,12 @@ define(function (require, exports, module) {
var matchStart;
var matches = [];
-
var match;
var lines = StringUtils.getLines(contents);
while ((match = queryExpr.exec(contents)) !== null) {
- var lineNum = StringUtils.offsetToLineNum(lines, match.index);
- var line = lines[lineNum];
- var ch = match.index - contents.lastIndexOf("\n", match.index) - 1; // 0-based index
+ var lineNum = StringUtils.offsetToLineNum(lines, match.index);
+ var line = lines[lineNum];
+ var ch = match.index - contents.lastIndexOf("\n", match.index) - 1; // 0-based index
var matchLength = match[0].length;
// Don't store more than 200 chars per line
@@ -210,38 +263,81 @@ define(function (require, exports, module) {
matches.push({
start: {line: lineNum, ch: ch},
- end: {line: lineNum, ch: ch + matchLength},
- line: line
+ end: {line: lineNum, ch: ch + matchLength},
+ line: line
});
// We have the max hits in just this 1 file. Stop searching this file.
// This fixed issue #1829 where code hangs on too many hits.
- if (matches.length >= FIND_IN_FILES_MAX) {
+ if (matches.length >= FIND_IN_FILE_MAX) {
queryExpr.lastIndex = 0;
- maxHitsFoundInFile = true;
+ _maxHitsFoundInFile = true;
break;
}
}
return matches;
}
+
+ /**
+ * @private
+ * Searches and stores the match results for the given file, if there are matches
+ * @param {!string} fullPath
+ * @param {!string} contents
+ * @param {!RegExp} queryExpr
+ */
+ function _addSearchMatches(fullPath, contents, queryExpr) {
+ var matches = _getSearchMatches(contents, queryExpr);
- function _showSearchResults(searchResults, query, scope) {
- var $searchResultsDiv = $("#search-results");
+ if (matches && matches.length) {
+ _searchResults[fullPath] = {
+ matches: matches,
+ collapsed: false
+ };
+ }
+ }
+
+ /**
+ * @private
+ * Sorts the file keys to show the selected result first and the rest sorted by path
+ */
+ function _sortResultFiles() {
+ var selectedEntry = ProjectManager.getSidebarSelectedItem();
+ _searchFiles = Object.keys(_searchResults);
- if (searchResults && searchResults.length) {
- var $resultTable = $("
")
- .append("");
+ _searchFiles.sort(function (key1, key2) {
+ if (selectedEntry.fullPath === key1) {
+ return -1;
+ } else if (selectedEntry.fullPath === key2) {
+ return 1;
+ } else {
+ return key1.toLocaleLowerCase().localeCompare(key2.toLocaleLowerCase());
+ }
+ });
+ }
+
+
+ /**
+ * @private
+ * Shows the results in a table and adds the necesary event listeners
+ */
+ function _showSearchResults() {
+ if (!$.isEmptyObject(_searchResults)) {
- // Count the total number of matches
- var numMatches = 0;
- searchResults.forEach(function (item) {
+ // Count the total number of files and matches
+ var numFiles = 0, numMatches = 0;
+ CollectionUtils.forEach(_searchResults, function (item) {
+ numFiles++;
numMatches += item.matches.length;
});
+ if (_currentStart > numMatches || _currentStart < 0) {
+ return;
+ }
+
// Show result summary in header
var numMatchesStr = "";
- if (maxHitsFoundInFile) {
+ if (_maxHitsFoundInFile) {
numMatchesStr = Strings.FIND_IN_FILES_MORE_THAN;
}
numMatchesStr += String(numMatches);
@@ -251,166 +347,291 @@ define(function (require, exports, module) {
Strings.FIND_IN_FILES_TITLE,
numMatchesStr,
(numMatches > 1) ? Strings.FIND_IN_FILES_MATCHES : Strings.FIND_IN_FILES_MATCH,
- searchResults.length,
- (searchResults.length > 1 ? Strings.FIND_IN_FILES_FILES : Strings.FIND_IN_FILES_FILE),
- StringUtils.htmlEscape(query),
- scope ? _labelForScope(scope) : ""
+ numFiles,
+ (numFiles > 1 ? Strings.FIND_IN_FILES_FILES : Strings.FIND_IN_FILES_FILE),
+ StringUtils.htmlEscape(_currentQuery),
+ _currentScope ? _labelForScope(_currentScope) : ""
);
- $("#search-result-summary")
+ // The last result index displayed
+ var last = _currentStart + RESULTS_PER_PAGE > numMatches ? numMatches : _currentStart + RESULTS_PER_PAGE;
+
+ // Insert the search summary
+ $searchSummary
.html(summary +
- (numMatches > FIND_IN_FILES_MAX ? StringUtils.format(Strings.FIND_IN_FILES_MAX, FIND_IN_FILES_MAX) : ""))
+ (numMatches > RESULTS_PER_PAGE ? StringUtils.format(Strings.FIND_IN_FILES_PAGING, _currentStart + 1, last) : "") +
+ (_currentStart > 0 ? Strings.FIND_IN_FILES_LESS : "") +
+ (last < numMatches ? Strings.FIND_IN_FILES_MORE : ""))
.prepend(" "); // putting a normal space before the "-" is not enough
- var resultsDisplayed = 0;
+ // Create the results template search list
+ var searchList = [];
+ var resultsDisplayed = 0, i;
+ var searchItems, item, match;
- searchResults.forEach(function (item) {
- if (item && resultsDisplayed < FIND_IN_FILES_MAX) {
- var makeCell = function (content) {
- return $("
").html(content);
- };
-
- // shorthand function name
- var esc = StringUtils.htmlEscape;
-
- var highlightMatch = function (line, start, end) {
- return esc(line.substr(0, start)) + "" + esc(line.substring(start, end)) + "" + esc(line.substr(end));
- };
+ _searchFiles.some(function (fullPath) {
+ item = _searchResults[fullPath];
+
+ // Skip the items that will not fit in the results page
+ if (resultsDisplayed + item.matches.length < _currentStart) {
+ resultsDisplayed += item.matches.length;
+ i = -1;
+
+ // Only the first matches will be displayed filling the remaining space of the table
+ } else if (resultsDisplayed < _currentStart) {
+ i = _currentStart - resultsDisplayed;
+ resultsDisplayed = _currentStart;
- // Add row for file name
- var displayFileName = StringUtils.format(Strings.FIND_IN_FILES_FILE_PATH,
- StringUtils.breakableUrl(esc(item.fullPath)));
- $("
")
- .append("
" + displayFileName + "
")
- .click(function () {
- // Clicking file section header collapses/expands result rows for that file
- var $fileHeader = $(this);
- $fileHeader.nextUntil(".file-section").toggle();
-
- var $triangle = $(".disclosure-triangle", $fileHeader);
- $triangle.toggleClass("expanded").toggleClass("collapsed");
- })
- .appendTo($resultTable);
+
+ // All the matches can be displayed
+ } else if (resultsDisplayed < last) {
+ i = 0;
+
+ // We can't display more items by now. Break the loop
+ } else {
+ return true;
+ }
+
+ if (i >= 0 && i < item.matches.length) {
+ // Add a row for each match in the file
+ searchItems = [];
+ while (i < item.matches.length && resultsDisplayed < last) {
+ match = item.matches[i];
+ searchItems.push({
+ file: searchList.length,
+ item: i,
+ line: StringUtils.format(Strings.FIND_IN_FILES_LINE, (match.start.line + 1)),
+ pre: match.line.substr(0, match.start.ch),
+ highlight: match.line.substring(match.start.ch, match.end.ch),
+ post: match.line.substr(match.end.ch),
+ start: match.start,
+ end: match.end
+ });
+ resultsDisplayed++;
+ i++;
+ }
- // Add row for each match in file
- item.matches.forEach(function (match) {
- if (resultsDisplayed < FIND_IN_FILES_MAX) {
- var $row = $("
")
- .append(makeCell(" ")) // Indent
- .append(makeCell(StringUtils.format(Strings.FIND_IN_FILES_LINE, (match.start.line + 1))))
- .append(makeCell(highlightMatch(match.line, match.start.ch, match.end.ch)))
- .appendTo($resultTable);
-
- $row.click(function () {
- CommandManager.execute(Commands.FILE_OPEN, {fullPath: item.fullPath})
- .done(function (doc) {
- // Opened document is now the current main editor
- EditorManager.getCurrentFullEditor().setSelection(match.start, match.end, true);
- });
- });
- resultsDisplayed++;
- }
+ // Add a row for each file
+ searchList.push({
+ file: searchList.length,
+ filename: StringUtils.breakableUrl(StringUtils.htmlEscape(fullPath)),
+ fullPath: fullPath,
+ items: searchItems
});
-
}
});
- $("#search-results .table-container")
+ // Insert the search results
+ $searchContent
.empty()
- .append($resultTable)
+ .append(Mustache.render(SearchResultsTemplate, {searchList: searchList}))
.scrollTop(0); // otherwise scroll pos from previous contents is remembered
- $("#search-results .close")
+ $searchResults.find(".close")
.one("click", function () {
- $searchResultsDiv.hide();
+ $searchResults.hide();
EditorManager.resizeEditor();
});
- $searchResultsDiv.show();
+ // The link to go the previous page
+ $searchResults.find(".find-less")
+ .one("click", function () {
+ _currentStart -= RESULTS_PER_PAGE;
+ _showSearchResults();
+ });
+
+ // The link to go to the next page
+ $searchResults.find(".find-more")
+ .one("click", function () {
+ _currentStart += RESULTS_PER_PAGE;
+ _showSearchResults();
+ });
+
+ // Add the click and double click event directly on the table parent
+ $searchContent
+ .off(".searchList") // Remove the old events. Needed for paging
+ .on("click.searchList", function (e) {
+ var $row = $(e.target).closest("tr");
+
+ if ($row.length) {
+ if ($selectedRow) {
+ $selectedRow.removeClass("selected");
+ }
+ $row.addClass("selected");
+ $selectedRow = $row;
+
+ var searchItem = searchList[$row.data("file")];
+ var fullPath = searchItem.fullPath;
+
+ // This is a file title row, expand/collapse on click
+ if ($row.hasClass("file-section")) {
+ // Clicking file section header collapses/expands result rows for that file
+ $row.nextUntil(".file-section").toggle();
+
+ var $triangle = $(".disclosure-triangle", $row);
+ $triangle.toggleClass("expanded").toggleClass("collapsed");
+
+ _searchResults[fullPath].collapsed = !_searchResults[fullPath].collapsed;
+
+ // This is a file row, show result click
+ } else {
+ // Grab the required item data
+ var item = searchItem.items[$row.data("item")];
+
+ CommandManager.execute(Commands.FILE_OPEN, {fullPath: fullPath})
+ .done(function (doc) {
+ // Opened document is now the current main editor
+ EditorManager.getCurrentFullEditor().setSelection(item.start, item.end, true);
+ });
+ }
+ }
+
+ // Add the file to the working set on double click
+ }).on("dblclick.searchList", function (e) {
+ var $row = $(e.target).closest("tr");
+ if ($row.length && !$row.hasClass("file-section")) {
+ // Grab the required item data
+ var item = searchList[$row.data("file")];
+
+ FileViewController.addToWorkingSetAndSelect(item.fullPath);
+ }
+
+ // Restore the collapsed files
+ }).find(".file-section").each(function () {
+ var searchItem = searchList[$(this).data("file")];
+ var fullPath = searchItem.fullPath;
+
+ if (_searchResults[fullPath].collapsed) {
+ _searchResults[fullPath].collapsed = false;
+ $(this).trigger("click");
+ }
+ });
+
+ $searchResults.show();
+ EditorManager.resizeEditor();
+
+ // Select the first result if the current file is the first result in the list
+ if (_gotoFirstResult && _searchResults[_currentDocument.file.fullPath]) {
+ $searchContent.find("tr:nth-child(2)").trigger("click");
+ _gotoFirstResult = false;
+ }
+
} else {
- $searchResultsDiv.hide();
+ $searchResults.hide();
+ EditorManager.resizeEditor();
}
-
- EditorManager.resizeEditor();
}
/**
- * @param {!FileInfo} fileInfo File in question
- * @param {?Entry} scope Search scope, or null if whole project
+ * @private
+ * Returns true if there is no scope or if the file is within one of the folder or is one of the files
+ * @param {!FileInfo} fileInfo - File in question
+ * @param {?Array.} scope - Search scope, or null/empty if whole project
* @return {boolean}
*/
- function inScope(fileInfo, scope) {
- if (scope) {
- if (scope.isDirectory) {
- // Dirs always have trailing slash, so we don't have to worry about being
- // a substring of another dir name
- return fileInfo.fullPath.indexOf(scope.fullPath) === 0;
- } else {
- return fileInfo.fullPath === scope.fullPath;
- }
+ function _inScope(fileInfo, scope) {
+ if (scope && scope.length) {
+ return scope.some(function (item) {
+ if (item.isDirectory) {
+ // Dirs always have trailing slash, so we don't have to worry about being
+ // a substring of another dir name
+ return fileInfo.fullPath.indexOf(item.fullPath) === 0;
+ } else {
+ return fileInfo.fullPath === item.fullPath;
+ }
+ });
}
return true;
}
/**
- * Displays a non-modal embedded dialog above the code mirror editor that allows the user to do
- * a find operation across all files in the project.
- * @param {?Entry} scope Project file/subfolder to search within; else searches whole project.
- */
- function doFindInFiles(scope) {
-
+ * @private
+ * Adds the files in the working set that arent in the project to the file index list
+ * @param {!Array.} fileListResult
+ */
+ function _addNonProjectFiles(fileListResult) {
+ var result = false;
+ var workingSet = DocumentManager.getWorkingSet();
+
+ workingSet.forEach(function (item) {
+ result = fileListResult.some(function (fileInfo) {
+ return fileInfo.fullPath === item.fullPath;
+ });
+ if (!result) {
+ fileListResult.push(item);
+ }
+ });
+ }
+
+ /**
+ * @private
+ * Displays a non-modal embedded dialog above the code mirror editor that allows the user to do
+ * a find operation across all files in the project or a given scope.
+ * @param {?Array.} scope - An array of file/subfolder to search within; else searches whole project.
+ */
+ function _handleFindInFiles(scope) {
var dialog = new FindInFilesDialog();
// Default to searching for the current selection
var currentEditor = EditorManager.getActiveEditor();
var initialString = currentEditor && currentEditor.getSelectedText();
-
- currentQuery = "";
- currentScope = scope;
- searchResults = [];
- maxHitsFoundInFile = false;
+
+ // Reset the private variables
+ _searchResults = {};
+ _searchFiles = [];
+ _currentQuery = "";
+ _currentQueryExpr = "";
+ _currentScope = scope;
+ _currentStart = 0;
+ _maxHitsFoundInFile = false;
+ _gotoFirstResult = true;
dialog.showDialog(initialString, scope)
.done(function (query) {
if (query) {
- currentQuery = query;
- var queryExpr = _getQueryRegExp(query);
- if (!queryExpr) {
+ _currentQuery = query;
+ _currentQueryExpr = _getQueryRegExp(query);
+
+ if (!_currentQueryExpr) {
return;
}
+
StatusBar.showBusyIndicator(true);
FileIndexManager.getFileInfoList("all")
.done(function (fileListResult) {
+ _addNonProjectFiles(fileListResult);
+
Async.doInParallel(fileListResult, function (fileInfo) {
var result = new $.Deferred();
- if (!inScope(fileInfo, scope)) {
+ if (!_inScope(fileInfo, scope)) {
result.resolve();
} else {
// Search one file
- DocumentManager.getDocumentForPath(fileInfo.fullPath)
- .done(function (doc) {
- var matches = _getSearchMatches(doc.getText(), queryExpr);
-
- if (matches && matches.length) {
- searchResults.push({
- fullPath: fileInfo.fullPath,
- matches: matches
- });
- }
- result.resolve();
- })
- .fail(function (error) {
- // Error reading this file. This is most likely because the file isn't a text file.
- // Resolve here so we move on to the next file.
- result.resolve();
- });
+ var file;
+ if (DocumentManager.findInWorkingSet(fileInfo.fullPath) > -1) {
+ file = DocumentManager.getDocumentForPath(fileInfo.fullPath);
+ } else {
+ var fileEntry = new NativeFileSystem.FileEntry(fileInfo.fullPath);
+ file = FileUtils.readAsText(fileEntry);
+ }
+ file.done(function (doc) {
+ var text = typeof doc === "object" ? doc.getText() : doc;
+ _addSearchMatches(fileInfo.fullPath, text, _currentQueryExpr);
+ result.resolve();
+
+ }).fail(function (error) {
+ // Error reading this file. This is most likely because the file isn't a text file.
+ // Resolve here so we move on to the next file.
+ result.resolve();
+ });
}
return result.promise();
})
.done(function () {
- // Done searching all files: show results
- _showSearchResults(searchResults, query, scope);
+ // Done searching all files: sort the files and show results
+ _sortResultFiles();
+ _showSearchResults();
StatusBar.hideBusyIndicator();
})
.fail(function () {
@@ -422,37 +643,282 @@ define(function (require, exports, module) {
});
}
- /** Search within the file/subtree defined by the sidebar selection */
- function doFindInSubtree() {
- // Prefer project tree selection, else use working set selection
- var selectedEntry = ProjectManager.getSelectedItem();
- if (!selectedEntry) {
- var doc = DocumentManager.getCurrentDocument();
- selectedEntry = (doc && doc.file);
+ /**
+ * @private
+ * Search within the file/subtree inside the project defined by the sidebar selection
+ */
+ function _handleFindInSubtree() {
+ var selectedEntry = ProjectManager.getSidebarSelectedItem();
+ _handleFindInFiles(selectedEntry ? [selectedEntry] : null);
+ }
+
+ /**
+ * @private
+ * Search within all the files in the working set inside the project
+ */
+ function _handleFindInWorkingSet() {
+ _handleFindInFiles(DocumentManager.getWorkingSet());
+ }
+
+
+
+ /**
+ * @private
+ * Triggers a click on the given row element and scrolls to it if needed
+ * @param {$.Element} $row - A table row jQuery element
+ */
+ function _triggerClick($row) {
+ // If this row is a ile header, just select it
+ if ($row.hasClass("file-section")) {
+ if ($selectedRow) {
+ $selectedRow.removeClass("selected");
+ }
+ $row.addClass("selected");
+ $selectedRow = $row;
+ } else {
+ $row.trigger("click");
}
- doFindInFiles(selectedEntry);
+ // Scroll to show the element at the top or bottom of the results, if needed
+ var tableScroll = $searchContent.scrollTop(),
+ tableHeight = $searchContent.outerHeight(),
+ rowTop = $row.offset().top + tableScroll - $searchContent.offset().top,
+ rowHeight = $row.outerHeight();
+
+ if (tableScroll + tableHeight - rowHeight < rowTop) {
+ $searchContent.scrollTop(rowTop - tableHeight + rowHeight);
+ } else if (tableScroll > rowTop) {
+ $searchContent.scrollTop(rowTop);
+ }
}
+ /**
+ * @private
+ * Selects the next result in the table or the first of the next page
+ */
+ function _handleNextResult() {
+ var $row;
+ if (!$selectedRow || !$selectedRow.length) {
+ $row = $searchContent.find("tr").first();
+ } else {
+ $row = $selectedRow.next();
+ if (!$row.length) {
+ _currentStart += RESULTS_PER_PAGE;
+ _showSearchResults();
+ $row = $searchContent.find("tr").first();
+ }
+ }
+ _triggerClick($row);
+ }
- // Initialize items dependent on HTML DOM
- AppInit.htmlReady(function () {
- var $searchResults = $("#search-results"),
- $searchContent = $("#search-results .table-container");
- });
-
+ /**
+ * @private
+ * Selects the previous result in the table or the last of the previous page
+ */
+ function _handlePreviousResult() {
+ var $row;
+ if (!$selectedRow || !$selectedRow.length) {
+ $row = $searchContent.find("tr").last();
+ } else {
+ $row = $selectedRow.prev();
+ if (!$row.length) {
+ _currentStart -= RESULTS_PER_PAGE;
+ _showSearchResults();
+ $row = $searchContent.find("tr").last();
+ }
+ }
+ _triggerClick($row);
+ }
+
+
+
+ /**
+ * @private
+ * Shows the search results and tryes to restore the previous scroll and selection
+ */
+ function _restoreSearchResults() {
+ var scrollTop = $searchContent.scrollTop();
+ var index = $selectedRow ? $selectedRow.index() : null;
+
+ _showSearchResults();
+
+ $searchContent.scrollTop(scrollTop);
+ if ($selectedRow) {
+ $selectedRow = $searchContent.find("tr:eq(" + index + ")");
+ $selectedRow.addClass("selected");
+ }
+ }
+
+ /**
+ * @private
+ * Move the search results from the previous path to the new one and update the results list
+ * @param {!$.Event} event
+ * @param {!string} oldName
+ * @param {!string} newName
+ */
function _fileNameChangeHandler(event, oldName, newName) {
- if ($("#search-results").is(":visible")) {
+ if ($searchResults.is(":visible")) {
+ var resultsChanged = false;
+
// Update the search results
- searchResults.forEach(function (item) {
- item.fullPath = item.fullPath.replace(oldName, newName);
+ CollectionUtils.forEach(_searchResults, function (item, key) {
+ if (key.match(oldName)) {
+ _searchResults[key.replace(oldName, newName)] = item;
+ delete _searchResults[key];
+ resultsChanged = true;
+ }
});
- _showSearchResults(searchResults, currentQuery, currentScope);
+
+ // Restore the reesults if needed
+ if (resultsChanged) {
+ _sortResultFiles();
+ _restoreSearchResults();
+ }
+ }
+ }
+
+ /**
+ * @private
+ * Update the result matches every time the content of a file changes
+ * @param {!$.Event} event
+ * @param {!Document} doc - The Document that changed, should be the current one
+ * @param {!Object} change - A linked list as described in the Document constructor
+ * @param {?boolean} resultsChanged - True when search results changed from a file change
+ */
+ function _fileChangeHandler(event, doc, change, resultsChanged) {
+ if ($searchResults.is(":visible")) {
+ var fullPath = doc.file.fullPath;
+
+ // There is no from or to positions, so the entire file changed, we must search all over again
+ if (!change.from || !change.to) {
+ _addSearchMatches(fullPath, doc.getText(), _currentQueryExpr);
+ _restoreSearchResults();
+
+ } else {
+ // Lests get only the lines that changed
+ var i, lines = [], diff;
+ for (i = 0; i < change.text.length; i++) {
+ lines.push(doc.getLine(change.from.line + i));
+ }
+
+ // If the change is a delete, define the lines difference as a negative value
+ if (change.from.line !== change.to.line && change.text.length === 1 && !change.text[0].length) {
+ diff = change.from.line - change.to.line;
+ // If the change was a replacement, define the lines difference as a positive value
+ } else if (change.from.line !== change.to.line) {
+ diff = change.from.line - change.to.line;
+ // If the change was an addition, define the lines difference as the lines added minus 1
+ } else {
+ diff = lines.length - 1;
+ }
+
+ var start = 0, howMany = 0;
+ if (_searchResults[fullPath]) {
+ // Lets search the last match before a replacement, the amount of matches deleted and update
+ // the lines values for all the matches after the change
+ _searchResults[fullPath].matches.forEach(function (item) {
+ if (item.end.line < change.from.line) {
+ start++;
+ } else if (item.end.line <= change.to.line) {
+ howMany++;
+ } else {
+ item.start.line += diff;
+ item.end.line += diff;
+ }
+ });
+
+ // Delete the lines that where deleted or replaced
+ if (howMany > 0) {
+ _searchResults[fullPath].matches.splice(start, howMany);
+ }
+ resultsChanged = true;
+ }
+
+ // Searches only over the lines that changed
+ var matches = _getSearchMatches(lines.join("\r\n"), _currentQueryExpr);
+ if (matches && matches.length) {
+ // Updates the lines, since the text didnt started on the first line
+ matches.forEach(function (value, key) {
+ matches[key].start.line += change.from.line;
+ matches[key].end.line += change.from.line;
+ });
+
+ // If the file index exists, add the new matches to the file at the start index found before
+ if (_searchResults[fullPath]) {
+ Array.prototype.splice.apply(_searchResults[fullPath].matches, [start, 0].concat(matches));
+ // If not, add the matches to a new file index
+ } else {
+ _searchResults[fullPath] = {
+ matches: matches,
+ collapsed: false
+ };
+ }
+ resultsChanged = true;
+ }
+
+ // All the matches where deleted, remove the file from the results
+ if (_searchResults[fullPath] && !_searchResults[fullPath].matches.length) {
+ delete _searchResults[fullPath];
+ resultsChanged = true;
+ }
+
+ // This is link to the next change objet, so we need to keep searching
+ if (change.next) {
+ _fileChangeHandler(event, doc, change.next, resultsChanged);
+
+ // If not we can show the results, but only if something changed
+ } else if (resultsChanged) {
+ _sortResultFiles();
+ _restoreSearchResults();
+ }
+ }
}
}
- $(DocumentManager).on("fileNameChange", _fileNameChangeHandler);
+ /**
+ * @private
+ * Update the results to delete the results from the deleted file
+ */
+ function _fileDeletedHandler() {
+ if ($searchResults.is(":visible")) {
+ if (_searchResults[_currentDocument.file.fullPath]) {
+ delete _searchResults[_currentDocument.file.fullPath];
+
+ _sortResultFiles();
+ _restoreSearchResults();
+ }
+ }
+ }
+
+ /**
+ * @private
+ * Updates the event listeners when the current document changes
+ */
+ function _currentDocumentChangeHandler() {
+ $(_currentDocument).off(".findInFiles");
+
+ _currentDocument = DocumentManager.getCurrentDocument();
+ $(_currentDocument)
+ .on("change.findInFiles", _fileChangeHandler)
+ .on("deleted.findInFiles", _fileDeletedHandler);
+ }
+
+
+ // Initialize items dependent on HTML DOM
+ AppInit.htmlReady(function () {
+ $searchResults = $("#search-results");
+ $searchSummary = $("#search-result-summary");
+ $searchContent = $("#search-results .table-container");
+ });
+
+ // Initialize: register listeners
+ $(DocumentManager).on("fileNameChange", _fileNameChangeHandler);
+ $(DocumentManager).on("currentDocumentChange", _currentDocumentChangeHandler);
- CommandManager.register(Strings.CMD_FIND_IN_FILES, Commands.EDIT_FIND_IN_FILES, doFindInFiles);
- CommandManager.register(Strings.CMD_FIND_IN_SUBTREE, Commands.EDIT_FIND_IN_SUBTREE, doFindInSubtree);
+ // Initialize: command handlers
+ CommandManager.register(Strings.CMD_FIND_IN_FILES, Commands.SEARCH_FIND_IN_FILES, _handleFindInFiles);
+ CommandManager.register(Strings.CMD_FIND_IN_SUBTREE, Commands.SEARCH_FIND_IN_SUBTREE, _handleFindInSubtree);
+ CommandManager.register(Strings.CMD_FIND_IN_WORKING_SET, Commands.SEARCH_FIND_IN_WORKING_SET, _handleFindInWorkingSet);
+ CommandManager.register(Strings.CMD_NEXT_RESULT, Commands.SEARCH_NEXT_RESULT, _handleNextResult);
+ CommandManager.register(Strings.CMD_PREVIOUS_RESULT, Commands.SEARCH_PREVIOUS_RESULT, _handlePreviousResult);
});
diff --git a/src/search/FindReplace.js b/src/search/FindReplace.js
index 1d5c1f7295f..418a933ab88 100644
--- a/src/search/FindReplace.js
+++ b/src/search/FindReplace.js
@@ -387,8 +387,8 @@ define(function (require, exports, module) {
}
}
- CommandManager.register(Strings.CMD_FIND, Commands.EDIT_FIND, _launchFind);
- CommandManager.register(Strings.CMD_FIND_NEXT, Commands.EDIT_FIND_NEXT, _findNext);
- CommandManager.register(Strings.CMD_REPLACE, Commands.EDIT_REPLACE, _replace);
- CommandManager.register(Strings.CMD_FIND_PREVIOUS, Commands.EDIT_FIND_PREVIOUS, _findPrevious);
+ CommandManager.register(Strings.CMD_FIND, Commands.SEARCH_FIND, _launchFind);
+ CommandManager.register(Strings.CMD_FIND_NEXT, Commands.SEARCH_FIND_NEXT, _findNext);
+ CommandManager.register(Strings.CMD_REPLACE, Commands.SEARCH_REPLACE, _replace);
+ CommandManager.register(Strings.CMD_FIND_PREVIOUS, Commands.SEARCH_FIND_PREVIOUS, _findPrevious);
});
diff --git a/test/spec/FindReplace-test.js b/test/spec/FindReplace-test.js
index 4447f86b8bf..8e707fde391 100644
--- a/test/spec/FindReplace-test.js
+++ b/test/spec/FindReplace-test.js
@@ -165,24 +165,24 @@ define(function (require, exports, module) {
it("should find all case-insensitive matches", function () {
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("foo");
expectHighlightedMatches(fooExpectedMatches);
expectSelection(fooExpectedMatches[0]);
expect(myEditor.centerOnCursor.calls.length).toEqual(1);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection(fooExpectedMatches[1]);
expect(myEditor.centerOnCursor.calls.length).toEqual(2);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection(fooExpectedMatches[2]);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection(fooExpectedMatches[3]);
expectHighlightedMatches(fooExpectedMatches); // no change in highlights
// wraparound
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection(fooExpectedMatches[0]);
expect(myEditor.centerOnCursor.calls.length).toEqual(5);
});
@@ -195,27 +195,27 @@ define(function (require, exports, module) {
];
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("Foo");
expectHighlightedMatches(expectedSelections);
expectSelection(expectedSelections[0]);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection(expectedSelections[1]);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection(expectedSelections[2]);
// note the lowercase "foo()" is NOT matched
// wraparound
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection(expectedSelections[0]);
});
it("should Find Next after search bar closed, including wraparound", function () {
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("foo");
pressEnter();
@@ -226,23 +226,23 @@ define(function (require, exports, module) {
expect(myEditor.centerOnCursor.calls.length).toEqual(1);
// Simple linear Find Next
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection({start: {line: LINE_FIRST_REQUIRE, ch: 31}, end: {line: LINE_FIRST_REQUIRE, ch: 34}});
expect(myEditor.centerOnCursor.calls.length).toEqual(2);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection({start: {line: 6, ch: 17}, end: {line: 6, ch: 20}});
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection({start: {line: 8, ch: 8}, end: {line: 8, ch: 11}});
// Wrap around to first result
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection({start: {line: LINE_FIRST_REQUIRE, ch: 8}, end: {line: LINE_FIRST_REQUIRE, ch: 11}});
});
it("should Find Previous after search bar closed, including wraparound", function () {
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("foo");
pressEnter();
@@ -251,22 +251,22 @@ define(function (require, exports, module) {
expectSelection({start: {line: LINE_FIRST_REQUIRE, ch: 8}, end: {line: LINE_FIRST_REQUIRE, ch: 11}});
// Wrap around to last result
- CommandManager.execute(Commands.EDIT_FIND_PREVIOUS);
+ CommandManager.execute(Commands.SEARCH_FIND_PREVIOUS);
expectSelection({start: {line: 8, ch: 8}, end: {line: 8, ch: 11}});
// Simple linear Find Previous
- CommandManager.execute(Commands.EDIT_FIND_PREVIOUS);
+ CommandManager.execute(Commands.SEARCH_FIND_PREVIOUS);
expectSelection({start: {line: 6, ch: 17}, end: {line: 6, ch: 20}});
- CommandManager.execute(Commands.EDIT_FIND_PREVIOUS);
+ CommandManager.execute(Commands.SEARCH_FIND_PREVIOUS);
expectSelection({start: {line: LINE_FIRST_REQUIRE, ch: 31}, end: {line: LINE_FIRST_REQUIRE, ch: 34}});
- CommandManager.execute(Commands.EDIT_FIND_PREVIOUS);
+ CommandManager.execute(Commands.SEARCH_FIND_PREVIOUS);
expectSelection({start: {line: LINE_FIRST_REQUIRE, ch: 8}, end: {line: LINE_FIRST_REQUIRE, ch: 11}});
});
it("shouldn't Find Next after search bar reopened", function () {
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("foo");
pressEnter();
@@ -274,19 +274,19 @@ define(function (require, exports, module) {
// Open search bar a second time
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
expectSearchBarOpen();
expect(myEditor).toHaveCursorPosition(0, 0);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expect(myEditor).toHaveCursorPosition(0, 0);
});
it("should open search bar on Find Next with no previous search", function () {
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSearchBarOpen();
expect(myEditor).toHaveCursorPosition(0, 0);
@@ -295,7 +295,7 @@ define(function (require, exports, module) {
it("should select-all without affecting search state if Find invoked while search bar open", function () { // #2478
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("foo"); // position cursor first
@@ -306,7 +306,7 @@ define(function (require, exports, module) {
expect(myEditor).toHaveCursorPosition(LINE_FIRST_REQUIRE, 11); // cursor left at end of last good match ("foo")
// Invoke Find a 2nd time - this time while search bar is open
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
expectSearchBarOpen();
expect(getSearchField().val()).toEqual("foobar");
@@ -324,7 +324,7 @@ define(function (require, exports, module) {
it("should re-search from original position when text changes", function () {
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("baz");
@@ -344,14 +344,14 @@ define(function (require, exports, module) {
it("should re-search from original position when text changes, even after Find Next", function () {
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("foo");
expectSelection(fooExpectedMatches[0]);
// get search highlight down below where the "bar" match will be
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection(fooExpectedMatches[2]);
enterSearchText("bar");
@@ -361,7 +361,7 @@ define(function (require, exports, module) {
it("should extend original selection when appending to prepopulated text", function () {
myEditor.setSelection({line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_START}, {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_PAREN});
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
expect(getSearchField().val()).toEqual("require");
var requireExpectedMatches = [
@@ -385,7 +385,7 @@ define(function (require, exports, module) {
it("should collapse selection when appending to prepopulated text causes no result", function () {
myEditor.setSelection({line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_START}, {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_PAREN});
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
expectSelection({start: {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_START}, end: {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_PAREN}});
enterSearchText("requireX");
@@ -396,7 +396,7 @@ define(function (require, exports, module) {
it("should clear selection, return cursor to start after backspacing to empty query", function () {
myEditor.setCursorPos(2, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("require");
expectSelection({start: {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_START}, end: {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_PAREN}});
@@ -413,7 +413,7 @@ define(function (require, exports, module) {
it("should go to next on Enter with prepopulated text & no Find Nexts", function () {
myEditor.setSelection({line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_START}, {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_PAREN});
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
expectSelection({start: {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_START}, end: {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_PAREN}});
pressEnter();
@@ -426,7 +426,7 @@ define(function (require, exports, module) {
it("shouldn't change selection on Esc with prepopulated text & no Find Nexts", function () {
myEditor.setSelection({line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_START}, {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_PAREN});
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
expectSelection({start: {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_START}, end: {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_PAREN}});
pressEscape();
@@ -439,10 +439,10 @@ define(function (require, exports, module) {
it("shouldn't change selection on Enter with prepopulated text & after Find Next", function () {
myEditor.setSelection({line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_START}, {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_PAREN});
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
expectSelection({start: {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_START}, end: {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_PAREN}});
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection({start: {line: LINE_FIRST_REQUIRE + 1, ch: CH_REQUIRE_START}, end: {line: LINE_FIRST_REQUIRE + 1, ch: CH_REQUIRE_PAREN}});
pressEnter();
@@ -454,7 +454,7 @@ define(function (require, exports, module) {
it("shouldn't change selection on Enter after typing text, no Find Nexts", function () {
myEditor.setCursorPos(LINE_FIRST_REQUIRE, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
expect(myEditor).toHaveCursorPosition(LINE_FIRST_REQUIRE, 0);
enterSearchText("require");
@@ -469,13 +469,13 @@ define(function (require, exports, module) {
it("shouldn't change selection on Enter after typing text & Find Next", function () {
myEditor.setCursorPos(LINE_FIRST_REQUIRE, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
expect(myEditor).toHaveCursorPosition(LINE_FIRST_REQUIRE, 0);
enterSearchText("require");
expectSelection({start: {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_START}, end: {line: LINE_FIRST_REQUIRE, ch: CH_REQUIRE_PAREN}});
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection({start: {line: LINE_FIRST_REQUIRE + 1, ch: CH_REQUIRE_START}, end: {line: LINE_FIRST_REQUIRE + 1, ch: CH_REQUIRE_PAREN}});
pressEnter();
@@ -487,10 +487,10 @@ define(function (require, exports, module) {
it("should no-op on Find Next with blank search", function () {
myEditor.setCursorPos(LINE_FIRST_REQUIRE, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
expect(myEditor).toHaveCursorPosition(LINE_FIRST_REQUIRE, 0);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expect(myEditor).toHaveCursorPosition(LINE_FIRST_REQUIRE, 0); // no change
});
@@ -498,7 +498,7 @@ define(function (require, exports, module) {
it("should no-op on Enter with blank search", function () {
myEditor.setCursorPos(LINE_FIRST_REQUIRE, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
expect(myEditor).toHaveCursorPosition(LINE_FIRST_REQUIRE, 0);
pressEnter();
@@ -521,21 +521,21 @@ define(function (require, exports, module) {
];
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("/Ba./");
expectHighlightedMatches(expectedSelections);
expectSelection(expectedSelections[0]);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection(expectedSelections[1]);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection(expectedSelections[2]);
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection(expectedSelections[3]);
// wraparound
- CommandManager.execute(Commands.EDIT_FIND_NEXT);
+ CommandManager.execute(Commands.SEARCH_FIND_NEXT);
expectSelection(expectedSelections[0]);
});
@@ -545,7 +545,7 @@ define(function (require, exports, module) {
];
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("/foo/");
expectHighlightedMatches(expectedSelections);
@@ -561,7 +561,7 @@ define(function (require, exports, module) {
];
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("/foo/i");
expectHighlightedMatches(expectedSelections);
@@ -575,7 +575,7 @@ define(function (require, exports, module) {
];
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
// This should be interpreted as a non-RegExp search, which actually does have a result thanks to "modules/Bar"
enterSearchText("/Ba");
@@ -586,7 +586,7 @@ define(function (require, exports, module) {
it("shouldn't choke on invalid regexp", function () {
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
// This is interpreted as a regexp (has both "/"es) but is invalid; should show error message
enterSearchText("/+/");
@@ -598,7 +598,7 @@ define(function (require, exports, module) {
it("shouldn't choke on empty regexp", function () {
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("//");
expectHighlightedMatches([]);
@@ -608,7 +608,7 @@ define(function (require, exports, module) {
it("shouldn't freeze on /.*/ regexp", function () {
myEditor.setCursorPos(0, 0);
- CommandManager.execute(Commands.EDIT_FIND);
+ CommandManager.execute(Commands.SEARCH_FIND);
enterSearchText("/.*/");
pressEnter();