Skip to content

Commit

Permalink
Fix search through draw panel.
Browse files Browse the repository at this point in the history
  • Loading branch information
Marco Minetti committed Jun 8, 2015
1 parent d747efe commit 463de7b
Show file tree
Hide file tree
Showing 9 changed files with 405 additions and 40 deletions.
1 change: 1 addition & 0 deletions front-end-node/inspector.json
Expand Up @@ -4,6 +4,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
121 changes: 121 additions & 0 deletions front-end-node/search/SearchOverrides.js
@@ -0,0 +1,121 @@
/*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.
}
}

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 || "");
}



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, lineContent));
}
}
return result;
}
})()

WebInspector.FileBasedSearchResultsPane.FileTreeElement.prototype._appendSearchMatches = function(fromIndex, toIndex)
{
var searchResult = this._searchResult;
var uiSourceCode = searchResult.uiSourceCode;
var searchMatches = searchResult.searchMatches;

var queries = this._searchConfig.queries();
var regexes = [];
for (var i = 0; i < queries.length; ++i)
regexes.push(createSearchRegex(queries[i], !this._searchConfig.ignoreCase(), this._searchConfig.isRegex()));

for (var i = fromIndex; i < toIndex; ++i) {
var lineNumber = searchMatches[i].lineNumber;
var lineContent = searchMatches[i].lineContent;
var matchRanges = [];
for (var j = 0; j < regexes.length; ++j)
matchRanges = matchRanges.concat(this._regexMatchRanges(lineContent, regexes[j]));

var anchor;
if (!matchRanges[0]){
matchRanges[0] = new WebInspector.SourceRange(0,0);
anchor = this._createAnchor(uiSourceCode, lineNumber, matchRanges[0].offset);
} else {
anchor = this._createAnchor(uiSourceCode, lineNumber, matchRanges[0].offset);
}

var numberString = numberToStringWithSpacesPadding(lineNumber + 1, 4);
var lineNumberSpan = createElement("span");
lineNumberSpan.classList.add("search-match-line-number");
lineNumberSpan.textContent = numberString;
anchor.appendChild(lineNumberSpan);

var contentSpan = this._createContentSpan(lineContent, matchRanges);
anchor.appendChild(contentSpan);

var searchMatchElement = new TreeElement("");
searchMatchElement.selectable = false;
this.appendChild(searchMatchElement);
searchMatchElement.listItemElement.className = "search-match source-code";
searchMatchElement.listItemElement.appendChild(anchor);
}
}
9 changes: 9 additions & 0 deletions front-end-node/search/module.json
@@ -0,0 +1,9 @@
{
"dependencies": [
"sources",
"console"
],
"scripts": [
"SearchOverrides.js"
]
}
19 changes: 18 additions & 1 deletion 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 @@ -205,7 +206,7 @@ DebuggerAgent.prototype = {
},

getScriptSource: function(params, done) {
this._debuggerClient.getScriptSourceById(
this._scriptManager.getScriptSourceById(
Number(params.scriptId),
function(err, source) {
if (err) return done(err);
Expand Down Expand Up @@ -493,6 +494,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.getScriptSourceByIdFromCache(Number(params.scriptId), function (err, data) {
if (err) return done(null, {result: []});
initSearch(data.scriptSource);
});
}
};

Expand Down
25 changes: 0 additions & 25 deletions lib/DebuggerClient.js
Expand Up @@ -191,31 +191,6 @@ DebuggerClient.prototype.evaluateGlobal = function(expression, done) {
);
};

/**
* @param {number} id
* @param {function(Object, string?)} callback
*/
DebuggerClient.prototype.getScriptSourceById = function(id, callback) {
this.request(
'scripts',
{
includeSource: true,
types: 4,
ids: [id]
},
function handleScriptSourceResponse(err, result) {
if (err) return callback(err);

// Some modules gets unloaded (?) after they are parsed,
// e.g. node_modules/express/node_modules/methods/index.js
// V8 request 'scripts' returns an empty result in such case
var source = result.length > 0 ? result[0].source : undefined;

callback(null, source);
}
);
};

/**
* @param {string} message
* @constructor
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
37 changes: 25 additions & 12 deletions lib/ScriptFileStorage.js
Expand Up @@ -58,19 +58,32 @@ $class.save = function(path, content, callback) {
* @param {function(Object, string)} callback
*/
$class.load = function(path, callback) {
fs.readFile(
path,
'utf-8',
function(err, content) {
if (err) return callback(err);

// remove shebang
content = content.replace(/^\#\!.*/, '');

var source = MODULE_HEADER + content + MODULE_TRAILER;
return callback(null, source);
var cache = this._scriptManager._scriptSourceCache;
if (cache[path]) {
return callback(null, cache[path]);
} else {
var scriptId = this._scriptManager.findScriptIdByPath(path);
if (scriptId != null) {
this._scriptManager.getScriptSourceByIdFromCache(scriptId, function(err,data) {
if (err) return callback(err);
callback(null, data.scriptSource);
});
} else {
fs.readFile(
path,
'utf-8',
function(err, content) {
if (err) return callback(err);
// remove shebang
content = content.replace(/^\#\!.*/, '');
var source = MODULE_HEADER + content + MODULE_TRAILER;

cache[path] = source;
return callback(null, source);
}
);
}
);
}
};

/**
Expand Down
55 changes: 53 additions & 2 deletions lib/ScriptManager.js
Expand Up @@ -95,6 +95,46 @@ ScriptManager.prototype = Object.create(events.EventEmitter.prototype, {
}
}
},

_scriptSourceCache: {
value: {}
},

getScriptSourceByIdFromCache: {
value: function(id, callback) {
var cache = this._scriptSourceCache;
if (cache[id]) {
callback(null, { scriptSource: cache[id] });
} else {
this.getScriptSourceById(id,callback);
}
}
},

getScriptSourceById: {
value: function(id, callback) {
this._debuggerClient.request(
'scripts',
{
includeSource: true,
types: 4,
ids: [id]
},
(function handleScriptSourceResponse(cache, err, result) {
if (err) return callback(err);

// Some modules gets unloaded (?) after they are parsed,
// e.g. node_modules/express/node_modules/methods/index.js
// V8 request 'scripts' returns an empty result in such case
var source = result.length > 0 ? result[0].source : undefined;

if(source) cache[id] = source;

callback(null, source);
}).bind(null,this._scriptSourceCache)
);
}
},

_requireScriptFromApp: {
value: function(id, done) {
Expand All @@ -103,7 +143,7 @@ ScriptManager.prototype = Object.create(events.EventEmitter.prototype, {
this._debuggerClient.request(
'scripts',
{
includeSource: false,
includeSource: true,
filter: id
},
function(error, scripts) {
Expand All @@ -115,6 +155,14 @@ ScriptManager.prototype = Object.create(events.EventEmitter.prototype, {
);
}
},

findScriptIdByPath: {
value: function(path) {
return Object.keys(this._sources).filter(function(key) {
return this._sources[key].v8name == path;
}, this)[0];
}
},

findScriptByID: {
/**
Expand All @@ -141,6 +189,9 @@ ScriptManager.prototype = Object.create(events.EventEmitter.prototype, {

debug('addScript id: %s localPath: %s hidden? %s source? %s',
v8data.id, localPath, hidden, !!v8data.source);

var cache = this._scriptSourceCache;
cache[v8data.id] = v8data.source;

if (hidden) return done(null, inspectorScriptData);

Expand Down Expand Up @@ -232,7 +283,7 @@ ScriptManager.prototype = Object.create(events.EventEmitter.prototype, {
var getSource;
if (scriptSource == null) {
debug('_getSourceMapUrl(%s) - fetching source from V8', scriptId);
getSource = this._debuggerClient.getScriptSourceById
getSource = this.getScriptSourceById
.bind(this._debuggerClient, scriptId);
} else {
debug('_getSourceMapUrl(%s) - using the suplied source', scriptId);
Expand Down

0 comments on commit 463de7b

Please sign in to comment.