Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated frontend: fixed search through Drawer panel. #621

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions front-end-node/inspector.json
Expand Up @@ -5,6 +5,7 @@
{ "name": "node/settings", "type": "autostart" },
{ "name": "node/sources", "type": "autostart" },
{ "name": "node/console", "type": "autostart" },
{ "name": "node/search", "type": "autostart" },
{ "name": "node/main", "type": "autostart" },
{ "name": "platform", "type": "autostart" },
{ "name": "main", "type": "autostart" },
Expand Down
103 changes: 103 additions & 0 deletions front-end-node/search/SearchOverrides.js
@@ -0,0 +1,103 @@
/*jshint browser:true, nonew:false*/
/*global WebInspector:true, InspectorFrontendHost:true, InspectorFrontendHostAPI:true*/

(function() {
var createSearchRegex = function(query, caseSensitive, isRegex)
{
var regexFlags = caseSensitive ? "g" : "gi";
var regexObject;

if (isRegex) {
try {
regexObject = new RegExp('^.*?'+query+'.*?$|^.*?'+query+'.*?\n|\n.*?'+query+'.*?\n|\n.*?'+query+'.*?$', regexFlags);
} catch (e) {
// Silent catch.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the try-catch block really necessary? which case the RegExp will throw an error?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yorkie , I'm not sure that this is a best time to review internal structure of this pr. At current step we need to decide how to avoid caching. Read my last comments.

Relative to your question:

new RegExp('abc[')

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway it would be nice if you'll help me with review!

}
}

if (!regexObject)
regexObject = createPlainTextSearchRegex(query, regexFlags);

return regexObject;
}

var createPlainTextSearchRegex = function(query, flags)
{
// This should be kept the same as the one in ContentSearchUtils.cpp.
var regexSpecialCharacters = "^[]{}()\\.^$*+?|-,";
var regex = "";
for (var i = 0; i < query.length; ++i) {
var c = query.charAt(i);
if (regexSpecialCharacters.indexOf(c) != -1)
regex += "\\";
regex += c;
}
return new RegExp('^.*?'+regex+'.*?$|^.*?'+regex+'.*?\n|\n.*?'+regex+'.*?\n|\n.*?'+regex+'.*?$', flags || "");
}

// performSearchInContent is based on /front-end/common/ContentProvider.js implementation
WebInspector.ContentProvider.performSearchInContent = function(content, query, caseSensitive, isRegex)
{
var regex = createSearchRegex(query, caseSensitive, isRegex);

var isMinified = false;

var firstNewLine = content.indexOf('\n');
if (content.length > 1024) {
if (firstNewLine > 1024 || firstNewLine === -1) {
isMinified = true;
}
}

var contentString = new String(content);
var result = [];
for (var i = 0; i < contentString.lineCount(); ++i) {
var lineContent = contentString.lineAt(i);
regex.lastIndex = 0;
if (regex.exec(lineContent)) {
result.push(new WebInspector.ContentProvider.SearchMatch(i, lineContent));
}
}
return result;
}

// _performSearchInContent tries to use regexp to gain performance
/*WebInspector.ContentProvider._performSearchInContent = function(content, query, caseSensitive, isRegex)
{
var regex = createSearchRegex(query, caseSensitive, isRegex);

var result = [];
var lastMatch;
var isMinified = false;

var firstNewLine = content.indexOf('\n');
if (content.length > 1024) {
if (firstNewLine > 1024 || firstNewLine === -1) {
isMinified = true;
}
}

while(lastMatch=regex.exec(content)) {
var lineContent = lastMatch[0];
var firstChar = lineContent.charCodeAt(0);
var lastChar = lineContent.charCodeAt(lineContent.length-1);
var lineMatchesBefore = content.substr(0,regex.lastIndex).match(/\n/g);
if (lineMatchesBefore){
var i = lineMatchesBefore.length;
if (lastChar !== 10){
++i;
} else {
lineContent = lineContent.substr(0,lineContent.length-1);
}
if (firstChar === 10){
lineContent = lineContent.substr(1);
}
if (isMinified === true && lineContent.length > 1024) {
lineContent = ' ... (line too long)';
}
result.push(new WebInspector.ContentProvider.SearchMatch(i-1, lineContent));
}
}
return result;
}*/
})()
9 changes: 9 additions & 0 deletions front-end-node/search/module.json
@@ -0,0 +1,9 @@
{
"dependencies": [
"sources",
"console"
],
"scripts": [
"SearchOverrides.js"
]
}
17 changes: 17 additions & 0 deletions lib/DebuggerAgent.js
Expand Up @@ -5,6 +5,7 @@ var convert = require('./convert.js'),
format = require('util').format,
path = require('path'),
async = require('async'),
search = require('./search.js'),
ScriptFileStorage = require('./ScriptFileStorage').ScriptFileStorage;

/**
Expand Down Expand Up @@ -510,6 +511,22 @@ DebuggerAgent.prototype = {
done(new Error('Not implemented.'));
else
done();
},

searchInContent: function(params, done) {

function initSearch(content) {
if (content) {
done(null, {result: search.performSearchInContent(content, params.query, params.caseSensitive, params.isRegex)});
} else {
done(null, {result: []});
}
}

this._scriptManager.getScriptSourceById(Number(params.scriptId), function (err, data) {
if (err) return done(null, {result: []});
initSearch(data.scriptSource);
});
}
};

Expand Down
17 changes: 17 additions & 0 deletions lib/PageAgent.js
Expand Up @@ -6,6 +6,7 @@ var fs = require('fs'),
EventEmitter = require('events').EventEmitter,
async = require('async'),
convert = require('./convert.js'),
search = require('./search.js'),
ScriptFileStorage = require('./ScriptFileStorage.js').ScriptFileStorage;


Expand Down Expand Up @@ -186,6 +187,22 @@ extend(PageAgent.prototype, {
reload: function(params, done) {
// This is called when user press Cmd+R (F5?), do we want to perform an action on this?
done();
},

searchInResource: function(params, done){

function initSearch(content){
if (content) {
done(null,{ result: search.performSearchInContent(content, params.query, params.caseSensitive, params.isRegex) });
} else {
done(null,{ result: [] });
}
}

this.getResourceContent({ url: params.url }, function(err,data){
if (err) return done(null,{ result: [] });
initSearch(data.content);
});
}
});

Expand Down
2 changes: 1 addition & 1 deletion lib/ScriptManager.js
Expand Up @@ -143,7 +143,7 @@ ScriptManager.prototype = Object.create(events.EventEmitter.prototype, {
this._debuggerClient.request(
'scripts',
{
includeSource: false,
includeSource: true,
filter: id
},
function(error, scripts) {
Expand Down
172 changes: 172 additions & 0 deletions lib/search.js
@@ -0,0 +1,172 @@
// code extracted and adapted from /front-end/platform/utilities.js
// performSearchInContent is based on /front-end/common/ContentProvider.js implementation
// _performSearchInContent tries to use regexp to gain performance


var findAll = function(content, string)
{
var matches = [];
var i = content.indexOf(string);
while (i !== -1) {
matches.push(i);
i = content.indexOf(string, i + string.length);
}
return matches;
}

var getlineEndings = function(content)
{
var _lineEndings = findAll(content, "\n");
_lineEndings.push(content.length);
return _lineEndings;
}

var getlineAt = function(content, lineNumber, lineEndings) {
var lineStart = lineNumber > 0 ? lineEndings[lineNumber - 1] + 1 : 0;
var lineEnd = lineEndings[lineNumber];
var lineContent = content.substring(lineStart, lineEnd);
if (lineContent.length > 0 && lineContent.charAt(lineContent.length - 1) === "\r")
lineContent = lineContent.substring(0, lineContent.length - 1);
return lineContent;
}

var createSearchRegex = function(query, caseSensitive, isRegex)
{
var regexFlags = caseSensitive ? "g" : "gi";
var regexObject;

if (isRegex) {
try {
regexObject = new RegExp(query, regexFlags);
} catch (e) {
// Silent catch.
}
}

if (!regexObject)
regexObject = createPlainTextSearchRegex(query, regexFlags);

return regexObject;
}

var createPlainTextSearchRegex = function(query, flags)
{
// This should be kept the same as the one in ContentSearchUtils.cpp.
var regexSpecialCharacters = "^[]{}()\\.^$*+?|-,";
var regex = "";
for (var i = 0; i < query.length; ++i) {
var c = query.charAt(i);
if (regexSpecialCharacters.indexOf(c) != -1)
regex += "\\";
regex += c;
}
return new RegExp(regex, flags || "");
}

exports.performSearchInContent = function(content, query, caseSensitive, isRegex)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@3y3 this code is adapted from /front-end/common/ContentProvider.js implementation...

{
var regex = createSearchRegex(query, caseSensitive, isRegex);

var isMinified = false;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@3y3 I've experienced problem at front-end with long minified lines rendering... the client freezes... so I try to guess if the file has been minified in one line... (does not solve all cases but most of them)


var firstNewLine = content.indexOf('\n');
if (content.length > 1024) {
if (firstNewLine > 1024 || firstNewLine === -1) {
isMinified = true;
}
}

var result = [];
var lineEndings = getlineEndings(content);
var lineCount = lineEndings.length;
for (var i = 0; i < lineCount; ++i) {
var lineContent = getlineAt(content, i, lineEndings);
regex.lastIndex = 0;
if (regex.exec(lineContent)) {
if (isMinified === true && lineContent.length > 1024) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@3y3 we could just check here for lineContent length and replace it with "... (too long line)"

lineContent = ' ... (line too long)';
}
result.push(new SearchMatch(i, lineContent));
}
}
return result;
}

var SearchMatch = function(lineNumber, lineContent) {
this.lineNumber = lineNumber;
this.lineContent = lineContent;
}

var _createSearchRegex = function(query, caseSensitive, isRegex)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@3y3 functions below are my attempt to gain performance but I think the incresed complexity of regexps and the allocation of match results to get line numbers are crazy... so these lines could be deleted (are now here just for reference)

{
var regexFlags = caseSensitive ? "g" : "gi";
var regexObject;

if (isRegex) {
try {
regexObject = new RegExp('^.*?'+query+'.*?$|^.*?'+query+'.*?\n|\n.*?'+query+'.*?\n|\n.*?'+query+'.*?$', regexFlags);
} catch (e) {
// Silent catch.
}
}

if (!regexObject)
regexObject = _createPlainTextSearchRegex(query, regexFlags);

return regexObject;
}

var _createPlainTextSearchRegex = function(query, flags)
{
// This should be kept the same as the one in ContentSearchUtils.cpp.
var regexSpecialCharacters = "^[]{}()\\.^$*+?|-,";
var regex = "";
for (var i = 0; i < query.length; ++i) {
var c = query.charAt(i);
if (regexSpecialCharacters.indexOf(c) != -1)
regex += "\\";
regex += c;
}
return new RegExp('^.*?'+regex+'.*?$|^.*?'+regex+'.*?\n|\n.*?'+regex+'.*?\n|\n.*?'+regex+'.*?$', flags || "");
}

exports._performSearchInContent = function(content, query, caseSensitive, isRegex)
{
var regex = _createSearchRegex(query, caseSensitive, isRegex);

var result = [];
var lastMatch;
var isMinified = false;

var firstNewLine = content.indexOf('\n');
if (content.length > 1024) {
if (firstNewLine > 1024 || firstNewLine === -1) {
isMinified = true;
}
}

while(lastMatch=regex.exec(content)) {
var lineContent = lastMatch[0];
var firstChar = lineContent.charCodeAt(0);
var lastChar = lineContent.charCodeAt(lineContent.length-1);
var lineMatchesBefore = content.substr(0,regex.lastIndex).match(/\n/g);
if (lineMatchesBefore){
var i = lineMatchesBefore.length;
if (lastChar !== 10){
++i;
} else {
lineContent = lineContent.substr(0,lineContent.length-1);
}
if (firstChar === 10){
lineContent = lineContent.substr(1);
}
if (isMinified === true && lineContent.length > 1024) {
lineContent = ' ... (line too long)';
}
result.push(new SearchMatch(i-1, lineContent));
}
}
return result;
}

//exports.performSearchInContent = exports._performSearchInContent;