@@ -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