Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit c06e73d

Browse files
committed
Merge pull request #5125 from zaggino/codeInspectionApi
Expose API to run code inspection as a headless one-off on an arbitrary file
2 parents b4497a6 + 3ca4f26 commit c06e73d

1 file changed

Lines changed: 116 additions & 49 deletions

File tree

src/language/CodeInspection.js

Lines changed: 116 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ define(function (require, exports, module) {
4545
CommandManager = require("command/CommandManager"),
4646
DocumentManager = require("document/DocumentManager"),
4747
EditorManager = require("editor/EditorManager"),
48+
FileUtils = require("file/FileUtils"),
4849
LanguageManager = require("language/LanguageManager"),
4950
PreferencesManager = require("preferences/PreferencesManager"),
5051
PerfUtils = require("utils/PerfUtils"),
@@ -72,7 +73,6 @@ define(function (require, exports, module) {
7273
META: "problem_type_meta"
7374
};
7475

75-
7676
/**
7777
* @private
7878
* @type {PreferenceStorage}
@@ -100,6 +100,12 @@ define(function (require, exports, module) {
100100
*/
101101
var $problemsPanel;
102102

103+
/**
104+
* @private
105+
* @type {$.Element}
106+
*/
107+
var $problemsPanelTable;
108+
103109
/**
104110
* @private
105111
* @type {boolean}
@@ -145,7 +151,69 @@ define(function (require, exports, module) {
145151
}
146152
_providers[languageId] = provider;
147153
}
148-
154+
155+
/**
156+
* Returns a provider for given file path, if one is available.
157+
* Decision is made depending on the file extension.
158+
*
159+
* @param {!string} filePath
160+
* @return ?{{name:string, scanFile:function(string, string):?{!errors:Array, aborted:boolean}} provider
161+
*/
162+
function getProviderForPath(filePath) {
163+
return _providers[LanguageManager.getLanguageForPath(filePath).getId()];
164+
}
165+
166+
/**
167+
* Runs a file inspection over passed file, specifying a provider is optional.
168+
* This method doesn't update the Brackets UI, just provides inspection results.
169+
* These results will reflect any unsaved changes present in the file that is currently opened.
170+
*
171+
* @param {!FileEntry} fileEntry File that will be inspected for errors.
172+
* @param ?{{name:string, scanFile:function(string, string):?{!errors:Array, aborted:boolean}} provider
173+
* @return {$.Promise} a jQuery promise that will be resolved with ?{!errors:Array, aborted:boolean}
174+
*/
175+
function inspectFile(fileEntry, provider) {
176+
var response = new $.Deferred();
177+
provider = provider || getProviderForPath(fileEntry.fullPath);
178+
179+
if (!provider) {
180+
response.resolve(null);
181+
return response.promise();
182+
}
183+
184+
var doc = DocumentManager.getOpenDocumentForPath(fileEntry.fullPath),
185+
fileTextPromise;
186+
187+
if (doc) {
188+
fileTextPromise = new $.Deferred().resolve(doc.getText());
189+
} else {
190+
fileTextPromise = FileUtils.readAsText(fileEntry);
191+
}
192+
193+
fileTextPromise
194+
.done(function (fileText) {
195+
var result,
196+
perfTimerInspector = PerfUtils.markStart("CodeInspection '" + provider.name + "':\t" + fileEntry.fullPath);
197+
198+
try {
199+
result = provider.scanFile(fileText, fileEntry.fullPath);
200+
} catch (err) {
201+
console.error("[CodeInspection] Provider " + provider.name + " threw an error: " + err);
202+
response.reject(err);
203+
return;
204+
}
205+
206+
PerfUtils.addMeasurement(perfTimerInspector);
207+
response.resolve(result);
208+
})
209+
.fail(function (err) {
210+
console.error("[CodeInspection] Could not read file for inspection: " + fileEntry.fullPath);
211+
response.reject(err);
212+
});
213+
214+
return response.promise();
215+
}
216+
149217
/**
150218
* Run inspector applicable to current document. Updates status bar indicator and refreshes error list in
151219
* bottom panel.
@@ -159,30 +227,31 @@ define(function (require, exports, module) {
159227
return;
160228
}
161229

162-
var currentDoc = DocumentManager.getCurrentDocument();
163-
164-
var perfTimerDOM,
165-
perfTimerInspector;
166-
167-
var language = currentDoc ? LanguageManager.getLanguageForPath(currentDoc.file.fullPath) : "";
168-
var languageId = language && language.getId();
169-
var provider = language && _providers[languageId];
230+
var currentDoc = DocumentManager.getCurrentDocument(),
231+
provider = currentDoc && getProviderForPath(currentDoc.file.fullPath);
170232

171233
if (provider) {
172-
perfTimerInspector = PerfUtils.markStart("CodeInspection '" + languageId + "':\t" + currentDoc.file.fullPath);
173-
174-
var result = provider.scanFile(currentDoc.getText(), currentDoc.file.fullPath);
175-
_lastResult = result;
176-
177-
PerfUtils.addMeasurement(perfTimerInspector);
178-
perfTimerDOM = PerfUtils.markStart("ProblemsPanel render:\t" + currentDoc.file.fullPath);
179-
180-
if (result && result.errors.length) {
234+
inspectFile(currentDoc.file, provider).then(function (result) {
235+
// check if current document wasn't changed while inspectFile was running
236+
if (currentDoc !== DocumentManager.getCurrentDocument()) {
237+
return;
238+
}
239+
240+
_lastResult = result;
241+
242+
if (!result || !result.errors.length) {
243+
Resizer.hide($problemsPanel);
244+
StatusBar.updateIndicator(INDICATOR_ID, true, "inspection-valid", StringUtils.format(Strings.NO_ERRORS, provider.name));
245+
setGotoEnabled(false);
246+
return;
247+
}
248+
249+
var perfTimerDOM = PerfUtils.markStart("ProblemsPanel render:\t" + currentDoc.file.fullPath);
250+
181251
// Augment error objects with additional fields needed by Mustache template
182252
var numProblems = 0;
183253
result.errors.forEach(function (error) {
184254
error.friendlyLine = error.pos.line + 1;
185-
186255
error.codeSnippet = currentDoc.getLine(error.pos.line);
187256
error.codeSnippet = error.codeSnippet.substr(0, Math.min(175, error.codeSnippet.length)); // limit snippet width
188257

@@ -193,27 +262,11 @@ define(function (require, exports, module) {
193262

194263
// Update results table
195264
var html = Mustache.render(ResultsTemplate, {reportList: result.errors});
196-
var $selectedRow;
197265

198-
$problemsPanel.find(".table-container")
266+
$problemsPanelTable
199267
.empty()
200268
.append(html)
201-
.scrollTop(0) // otherwise scroll pos from previous contents is remembered
202-
.on("click", "tr", function (e) {
203-
if ($selectedRow) {
204-
$selectedRow.removeClass("selected");
205-
}
206-
207-
$selectedRow = $(e.currentTarget);
208-
$selectedRow.addClass("selected");
209-
var lineTd = $selectedRow.find(".line-number");
210-
var line = parseInt(lineTd.text(), 10) - 1; // convert friendlyLine back to pos.line
211-
var character = lineTd.data("character");
212-
213-
var editor = EditorManager.getCurrentFullEditor();
214-
editor.setCursorPos(line, character, true);
215-
EditorManager.focusEditor();
216-
});
269+
.scrollTop(0); // otherwise scroll pos from previous contents is remembered
217270

218271
$problemsPanel.find(".title").text(StringUtils.format(Strings.ERRORS_PANEL_TITLE, provider.name));
219272
if (!_collapsed) {
@@ -231,19 +284,14 @@ define(function (require, exports, module) {
231284
StringUtils.format(Strings.MULTIPLE_ERRORS, provider.name, numProblems));
232285
}
233286
setGotoEnabled(true);
234-
235-
} else {
236-
Resizer.hide($problemsPanel);
237-
StatusBar.updateIndicator(INDICATOR_ID, true, "inspection-valid", StringUtils.format(Strings.NO_ERRORS, provider.name));
238-
setGotoEnabled(false);
239-
}
240-
241-
PerfUtils.addMeasurement(perfTimerDOM);
242287

288+
PerfUtils.addMeasurement(perfTimerDOM);
289+
});
243290
} else {
244291
// No provider for current file
245292
_lastResult = null;
246293
Resizer.hide($problemsPanel);
294+
var language = currentDoc && LanguageManager.getLanguageForPath(currentDoc.file.fullPath);
247295
if (language) {
248296
StatusBar.updateIndicator(INDICATOR_ID, true, "inspection-disabled", StringUtils.format(Strings.NO_LINT_AVAILABLE, language.getName()));
249297
} else {
@@ -339,6 +387,24 @@ define(function (require, exports, module) {
339387
var resultsPanel = PanelManager.createBottomPanel("errors", $(panelHtml), 100);
340388
$problemsPanel = $("#problems-panel");
341389

390+
var $selectedRow;
391+
$problemsPanelTable = $problemsPanel.find(".table-container")
392+
.on("click", "tr", function (e) {
393+
if ($selectedRow) {
394+
$selectedRow.removeClass("selected");
395+
}
396+
397+
$selectedRow = $(e.currentTarget);
398+
$selectedRow.addClass("selected");
399+
var lineTd = $selectedRow.find(".line-number");
400+
var line = parseInt(lineTd.text(), 10) - 1; // convert friendlyLine back to pos.line
401+
var character = lineTd.data("character");
402+
403+
var editor = EditorManager.getCurrentFullEditor();
404+
editor.setCursorPos(line, character, true);
405+
EditorManager.focusEditor();
406+
});
407+
342408
$("#problems-panel .close").click(function () {
343409
toggleCollapsed(true);
344410
});
@@ -363,7 +429,8 @@ define(function (require, exports, module) {
363429

364430

365431
// Public API
366-
exports.register = register;
367-
exports.Type = Type;
368-
exports.toggleEnabled = toggleEnabled;
432+
exports.register = register;
433+
exports.Type = Type;
434+
exports.toggleEnabled = toggleEnabled;
435+
exports.inspectFile = inspectFile;
369436
});

0 commit comments

Comments
 (0)