@@ -43,6 +43,7 @@ define(function (require, exports, module) {
4343 CommandManager = require ( "command/CommandManager" ) ,
4444 DocumentManager = require ( "document/DocumentManager" ) ,
4545 EditorManager = require ( "editor/EditorManager" ) ,
46+ Dialogs = require ( "widgets/Dialogs" ) ,
4647 Editor = require ( "editor/Editor" ) . Editor ,
4748 MainViewManager = require ( "view/MainViewManager" ) ,
4849 LanguageManager = require ( "language/LanguageManager" ) ,
@@ -61,6 +62,8 @@ define(function (require, exports, module) {
6162 const CODE_INSPECTION_GUTTER_PRIORITY = 500 ,
6263 CODE_INSPECTION_GUTTER = "code-inspection-gutter" ;
6364
65+ const EDIT_ORIGIN_LINT_FIX = "lint_fix" ;
66+
6467 const INDICATOR_ID = "status-inspection" ;
6568
6669 /** Values for problem's 'type' property */
@@ -504,20 +507,35 @@ define(function (require, exports, module) {
504507 } ) ;
505508 }
506509
510+ let fixIDCounter = 1 ;
511+ let documentFixes = new Map ( ) , lastDocumentScanTimeStamp ;
512+ function _registerNewFix ( editor , fix ) {
513+ if ( ! editor || ! fix || ! fix . rangeOffset ) {
514+ return null ;
515+ }
516+ if ( editor . document . lastChangeTimestamp !== lastDocumentScanTimeStamp ) {
517+ // the document changed from the last time the fixes where registered, we have to
518+ // invalidate all existing fixes in that case.
519+ lastDocumentScanTimeStamp = editor . document . lastChangeTimestamp ;
520+ documentFixes . clear ( ) ;
521+ }
522+ fixIDCounter ++ ;
523+ documentFixes . set ( `${ fixIDCounter } ` , fix ) ;
524+ return fixIDCounter ;
525+ }
507526
508527 /**
509528 * Adds gutter icons and squiggly lines under err/warn/info to editor after lint.
529+ * also updates the passed in resultProviderEntries with fixes that can be applied.
510530 * @param resultProviderEntries
511531 * @private
512532 */
513- function _updateEditorMarks ( resultProviderEntries ) {
533+ function _updateEditorMarksAndFixResults ( resultProviderEntries ) {
514534 let editor = EditorManager . getCurrentFullEditor ( ) ;
515535 if ( ! ( editor && resultProviderEntries && resultProviderEntries . length ) ) {
516536 return ;
517537 }
518538 editor . operation ( function ( ) {
519- editor . clearAllMarks ( CODE_MARK_TYPE_INSPECTOR ) ;
520- editor . clearGutter ( CODE_INSPECTION_GUTTER ) ;
521539 editor . off ( "viewportChange.codeInspection" ) ;
522540 editor . on ( "viewportChange.codeInspection" , _editorVieportChangeHandler ) ;
523541 let gutterErrorMessages = { } ;
@@ -532,11 +550,16 @@ define(function (require, exports, module) {
532550 // add squiggly lines
533551 if ( _shouldMarkTokenAtPosition ( editor , error ) ) {
534552 let mark ;
553+ const markOptions = _getMarkOptions ( error ) ;
554+ const fixID = _registerNewFix ( editor , error . fix ) ;
555+ if ( fixID ) {
556+ markOptions . metadata = fixID ;
557+ error . fix . id = fixID ;
558+ }
535559 if ( error . endPos ) {
536- mark = editor . markText ( CODE_MARK_TYPE_INSPECTOR , error . pos , error . endPos ,
537- _getMarkOptions ( error ) ) ;
560+ mark = editor . markText ( CODE_MARK_TYPE_INSPECTOR , error . pos , error . endPos , markOptions ) ;
538561 } else {
539- mark = editor . markToken ( CODE_MARK_TYPE_INSPECTOR , error . pos , _getMarkOptions ( error ) ) ;
562+ mark = editor . markToken ( CODE_MARK_TYPE_INSPECTOR , error . pos , markOptions ) ;
540563 }
541564 mark . type = error . type ;
542565 mark . message = error . message ;
@@ -547,6 +570,7 @@ define(function (require, exports, module) {
547570 } ) ;
548571 }
549572
573+ let linterHadRun = false ;
550574 /**
551575 * Run inspector applicable to current document. Updates status bar indicator and refreshes error list in
552576 * bottom panel. Does not run if inspection is disabled or if a providerName is given and does not
@@ -574,6 +598,14 @@ define(function (require, exports, module) {
574598 return ! provider . canInspect || provider . canInspect ( currentDoc . file . fullPath ) ;
575599 } ) ;
576600
601+ let editor = EditorManager . getCurrentFullEditor ( ) ;
602+ if ( editor ) {
603+ lastDocumentScanTimeStamp = editor . document . lastChangeTimestamp ;
604+ documentFixes . clear ( ) ;
605+ editor . clearAllMarks ( CODE_MARK_TYPE_INSPECTOR ) ;
606+ editor . clearGutter ( CODE_INSPECTION_GUTTER ) ;
607+ }
608+
577609 if ( providerList && providerList . length ) {
578610 var numProblems = 0 ;
579611 var aborted = false ;
@@ -584,7 +616,7 @@ define(function (require, exports, module) {
584616
585617 // run all the providers registered for this file type
586618 ( _currentPromise = inspectFile ( currentDoc . file , providerList ) ) . then ( function ( results ) {
587- _updateEditorMarks ( results ) ;
619+ _updateEditorMarksAndFixResults ( results ) ;
588620 // check if promise has not changed while inspectFile was running
589621 if ( this !== _currentPromise ) {
590622 return ;
@@ -675,6 +707,7 @@ define(function (require, exports, module) {
675707 // No provider for current file
676708 _hasErrors = false ;
677709 _currentPromise = null ;
710+ updatePanelTitleAndStatusBar ( 0 , [ ] , false ) ;
678711 if ( problemsPanel ) {
679712 problemsPanel . hide ( ) ;
680713 }
@@ -708,9 +741,18 @@ define(function (require, exports, module) {
708741 * @param {{name:string, scanFileAsync:?function(string, string):!{$.Promise},
709742 * scanFile:?function(string, string):?{errors:!Array, aborted:boolean} }} provider
710743 *
711- * Each error is: { pos:{line,ch}, endPos:?{line,ch}, message:string, type:?Type }
744+ * Each error is: { pos:{line,ch}, endPos:?{line,ch}, message:string, htmlMessage:string, type:?Type ,
745+ * fix: { // an optional fix, if present will show the fix button
746+ * replace: "text to replace the offset given below",
747+ * rangeOffset: {
748+ * start: number,
749+ * end: number
750+ * }}}
712751 * If type is unspecified, Type.WARNING is assumed.
713752 * If no errors found, return either null or an object with a zero-length `errors` array.
753+ * `message` will be printed as text as is. This is needed when the error text contains HTML that may be
754+ * mis interpreted as html to display. If you want to display html, pass in `htmlMessage`. Both can be used
755+ * at the same time, in which case both will be displayed.
714756 */
715757 function register ( languageId , provider ) {
716758 if ( ! _providers [ languageId ] ) {
@@ -898,11 +940,35 @@ define(function (require, exports, module) {
898940 var $selectedRow ;
899941 $problemsPanelTable = $problemsPanel . find ( ".table-container" )
900942 . on ( "click" , "tr" , function ( e ) {
901- if ( $ ( e . target ) . hasClass ( 'table -copy-err-button ' ) ) {
943+ if ( $ ( e . target ) . hasClass ( 'ph -copy-problem ' ) ) {
902944 // Retrieve the message from the data attribute of the clicked element
903945 const message = $ ( e . target ) . parent ( ) . parent ( ) . find ( ".line-text" ) . text ( ) ;
904946 message && Phoenix . app . copyToClipboard ( message ) ;
947+ e . preventDefault ( ) ;
948+ e . stopPropagation ( ) ;
949+ MainViewManager . focusActivePane ( ) ;
950+ return ;
951+ }
952+ if ( $ ( e . target ) . hasClass ( 'ph-fix-problem' ) ) {
953+ // Retrieve the message from the data attribute of the clicked element
954+ const fixid = "" + $ ( e . target ) . data ( "fixid" ) ;
955+ const fixDetails = documentFixes . get ( fixid ) ;
956+ const editor = EditorManager . getCurrentFullEditor ( ) ;
957+ if ( ! editor || ! fixDetails || editor . document . lastChangeTimestamp !== lastDocumentScanTimeStamp ) {
958+ Dialogs . showErrorDialog ( Strings . CANNOT_FIX_TITLE , Strings . CANNOT_FIX_MESSAGE ) ;
959+ } else {
960+ const from = editor . posFromIndex ( fixDetails . rangeOffset . start ) ,
961+ to = editor . posFromIndex ( fixDetails . rangeOffset . end ) ;
962+ editor . setSelection ( from , to , true , Editor . BOUNDARY_BULLSEYE , EDIT_ORIGIN_LINT_FIX ) ;
963+ editor . replaceSelection ( fixDetails . replaceText , "around" ) ;
964+ }
965+ e . preventDefault ( ) ;
966+ e . stopPropagation ( ) ;
967+ MainViewManager . focusActivePane ( ) ;
968+ run ( ) ;
969+ return ;
905970 }
971+
906972 if ( $selectedRow ) {
907973 $selectedRow . removeClass ( "selected" ) ;
908974 }
0 commit comments