@@ -643,6 +643,25 @@ define(function (require, exports, module) {
643643
644644 const scrollPositionMap = new Map ( ) ;
645645
646+ function _noProviderReturnedResults ( currentDoc , fullFilePath ) {
647+ // No provider for current file
648+ _hasErrors = false ;
649+ _currentPromise = null ;
650+ updatePanelTitleAndStatusBar ( 0 , [ ] , false ,
651+ fullFilePath ? path . basename ( fullFilePath ) : Strings . ERRORS_NO_FILE ) ;
652+ if ( problemsPanel ) {
653+ problemsPanel . hide ( ) ;
654+ }
655+ const language = currentDoc && LanguageManager . getLanguageForPath ( currentDoc . file . fullPath ) ;
656+ if ( language ) {
657+ StatusBar . updateIndicator ( INDICATOR_ID , true , "inspection-disabled" ,
658+ StringUtils . format ( Strings . NO_LINT_AVAILABLE , language . getName ( ) ) ) ;
659+ } else {
660+ StatusBar . updateIndicator ( INDICATOR_ID , true , "inspection-disabled" , Strings . NOTHING_TO_LINT ) ;
661+ }
662+ setGotoEnabled ( false ) ;
663+ }
664+
646665 /**
647666 * Run inspector applicable to current document. Updates status bar indicator and refreshes error list in
648667 * bottom panel. Does not run if inspection is disabled or if a providerName is given and does not
@@ -687,6 +706,14 @@ define(function (require, exports, module) {
687706
688707 // run all the providers registered for this file type
689708 ( _currentPromise = inspectFile ( currentDoc . file , providerList ) ) . then ( function ( results ) {
709+ // filter out any ignored results
710+ results = results . filter ( function ( providerResult ) {
711+ return ! providerResult . result || ! providerResult . result . isIgnored ;
712+ } ) ;
713+ if ( ! results . length ) {
714+ _noProviderReturnedResults ( currentDoc , fullFilePath ) ;
715+ return ;
716+ }
690717 editor . clearAllMarks ( CODE_MARK_TYPE_INSPECTOR ) ;
691718 editor . clearGutter ( CODE_INSPECTION_GUTTER ) ;
692719 _updateEditorMarksAndFixResults ( results ) ;
@@ -780,56 +807,73 @@ define(function (require, exports, module) {
780807 } ) ;
781808
782809 } else {
783- // No provider for current file
784- _hasErrors = false ;
785- _currentPromise = null ;
786- updatePanelTitleAndStatusBar ( 0 , [ ] , false ,
787- fullFilePath ? path . basename ( fullFilePath ) : Strings . ERRORS_NO_FILE ) ;
788- if ( problemsPanel ) {
789- problemsPanel . hide ( ) ;
790- }
791- var language = currentDoc && LanguageManager . getLanguageForPath ( currentDoc . file . fullPath ) ;
792- if ( language ) {
793- StatusBar . updateIndicator ( INDICATOR_ID , true , "inspection-disabled" , StringUtils . format ( Strings . NO_LINT_AVAILABLE , language . getName ( ) ) ) ;
794- } else {
795- StatusBar . updateIndicator ( INDICATOR_ID , true , "inspection-disabled" , Strings . NOTHING_TO_LINT ) ;
796- }
797- setGotoEnabled ( false ) ;
810+ _noProviderReturnedResults ( currentDoc , fullFilePath ) ;
798811 }
799812 }
800813
801814 let gutterRegistrationInProgress = false ;
802815
803816 /**
804- * The provider is passed the text of the file and its fullPath. Providers should not assume
805- * that the file is open (i.e. DocumentManager.getOpenDocumentForPath() may return null) or
806- * that the file on disk matches the text given (file may have unsaved changes).
817+ * Registers a provider for a specific language to inspect files and provide linting results.
818+ *
819+ * The provider is passed the text of the file and its full path. Providers should not assume that
820+ * the file is open (i.e., `DocumentManager.getOpenDocumentForPath()` may return `null`) or that the
821+ * file on disk matches the text given (the file may have unsaved changes).
807822 *
808823 * Registering any provider for the "javascript" language automatically unregisters the built-in
809- * Brackets JSLint provider. This is a temporary convenience until UI exists for disabling
824+ * Brackets JSLint provider. This is a temporary convenience until a UI exists for disabling
810825 * registered providers.
811826 *
812- * Providers implement scanFile() if results are available synchronously, or scanFileAsync() if results
813- * may require an async wait (if both are implemented, scanFile() is ignored). scanFileAsync() returns
814- * a {$.Promise} object resolved with the same type of value as scanFile() is expected to return.
815- * Rejecting the promise is treated as an internal error in the provider.
827+ * Providers must implement `canInspect()`, `scanFile()`, or `scanFileAsync()`. If both `scanFile()`
828+ * and `scanFileAsync()` are implemented, `scanFile()` is ignored.
816829 *
817- * @param {string } languageId
818- * @param {{name:string, scanFileAsync:?function(string, string):!{$.Promise},
819- * scanFile:?function(string, string):?{errors:!Array, aborted:boolean} }} provider
830+ * - `canInspect(fullPath)`: A synchronous call to determine if the file can be scanned by this provider.
831+ * - `scanFile(text, fullPath)`: A synchronous function returning linting results or `null`.
832+ * - `scanFileAsync(text, fullPath)`: An asynchronous function returning a jQuery Promise resolved with
833+ * the same type of value as `scanFile()`. Rejecting the promise is treated as an internal error in the provider.
820834 *
821- * Each error is: { pos:{line,ch}, endPos:?{line,ch}, message:string, htmlMessage:string, type:?Type ,
822- * fix: { // an optional fix, if present will show the fix button
835+ * Each error object in the results should have the following structure:
836+ * { pos:{line,ch},
837+ * endPos:?{line,ch},
838+ * message:string,
839+ * htmlMessage:string,
840+ * type:?Type ,
841+ * fix: { // an optional fix, if present will show the fix button
823842 * replace: "text to replace the offset given below",
824843 * rangeOffset: {
825844 * start: number,
826845 * end: number
827- * }}}
828- * If type is unspecified, Type.WARNING is assumed.
829- * If no errors found, return either null or an object with a zero-length `errors` array.
830- * `message` will be printed as text as is. This is needed when the error text contains HTML that may be
831- * mis interpreted as html to display. If you want to display html, pass in `htmlMessage`. Both can be used
832- * at the same time, in which case both will be displayed.
846+ * }}}
847+ * @typedef {Object } Error
848+ * @property {Object } pos - The start position of the error.
849+ * @property {number } pos.line - The line number (0-based).
850+ * @property {number } pos.ch - The character position within the line (0-based).
851+ * @property {?Object } endPos - The end position of the error.
852+ * @property {number } endPos.line - The end line number (0-based).
853+ * @property {number } endPos.ch - The end character position within the line (0-based).
854+ * @property {string } message - The error message to be displayed as text.
855+ * @property {string } htmlMessage - The error message to be displayed as HTML.
856+ * @property {?Type } type - The type of the error. Defaults to `Type.WARNING` if unspecified.
857+ * @property {?Object } fix - An optional fix object.
858+ * @property {string } fix.replace - The text to replace the error with.
859+ * @property {Object } fix.rangeOffset - The range within the text to replace.
860+ * @property {number } fix.rangeOffset.start - The start offset of the range.
861+ * @property {number } fix.rangeOffset.end - The end offset of the range.
862+ *
863+ * If no errors are found, return either `null`(treated as file is problem free) or an object with a
864+ * zero-length `errors` array. Always use `message` to safely display the error as text. If you want to display HTML
865+ * error message, then explicitly use `htmlMessage` to display it. Both `message` and `htmlMessage` can
866+ * be used simultaneously.
867+ *
868+ * After scanning the file, if you need to omit the lint result, return or resolve with `{isIgnored: true}`.
869+ * This prevents the file from being marked with a no errors tick mark in the status bar and excludes the linter
870+ * from the problems panel.
871+ *
872+ * @param {string } languageId - The language ID for which the provider is registered.
873+ * @param {Object } provider - The provider object.
874+ * @param {string } provider.name - The name of the provider.
875+ * @param {?function(string, string): { errors: Array<Error>, aborted: boolean } } provider.scanFile - Synchronous scan function.
876+ * @param {?function(string, string): jQuery.Promise } provider.scanFileAsync - Asynchronous scan function returning a Promise.
833877 */
834878 function register ( languageId , provider ) {
835879 if ( ! _providers [ languageId ] ) {
0 commit comments