forked from phcode-dev/staging.phcode.dev
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCodeInspection.js
More file actions
1 lines (1 loc) · 28 KB
/
CodeInspection.js
File metadata and controls
1 lines (1 loc) · 28 KB
1
define(function(require,exports,module){const _=require("thirdparty/lodash"),Commands=require("command/Commands"),WorkspaceManager=require("view/WorkspaceManager"),CommandManager=require("command/CommandManager"),DocumentManager=require("document/DocumentManager"),EditorManager=require("editor/EditorManager"),Dialogs=require("widgets/Dialogs"),Editor=require("editor/Editor").Editor,MainViewManager=require("view/MainViewManager"),LanguageManager=require("language/LanguageManager"),PreferencesManager=require("preferences/PreferencesManager"),PerfUtils=require("utils/PerfUtils"),Strings=require("strings"),StringUtils=require("utils/StringUtils"),AppInit=require("utils/AppInit"),StatusBar=require("widgets/StatusBar"),Async=require("utils/Async"),PanelTemplate=require("text!htmlContent/problems-panel.html"),ResultsTemplate=require("text!htmlContent/problems-panel-table.html"),Mustache=require("thirdparty/mustache/mustache"),QuickViewManager=require("features/QuickViewManager"),Metrics=require("utils/Metrics"),CODE_INSPECTION_GUTTER_PRIORITY=500,CODE_INSPECTION_GUTTER="code-inspection-gutter",EDIT_ORIGIN_LINT_FIX="lint_fix",INDICATOR_ID="status-inspection",Type={ERROR:"error",WARNING:"warning",META:"meta"};function _getIconClassForType(type,isFixable){switch(type){case Type.ERROR:return isFixable?"line-icon-problem_type_error fa-solid fa-wrench":"line-icon-problem_type_error fa-solid fa-times-circle";case Type.WARNING:return isFixable?"line-icon-problem_type_warning fa-solid fa-wrench":"line-icon-problem_type_warning fa-solid fa-exclamation-triangle";case Type.META:default:return isFixable?"line-icon-problem_type_info fa-solid fa-wrench":"line-icon-problem_type_info fa-solid fa-info-circle"}}const CODE_MARK_TYPE_INSPECTOR="codeInspector",PREF_ENABLED="enabled",PREF_ASYNC_TIMEOUT="asyncTimeout",PREF_PREFER_PROVIDERS="prefer",PREF_PREFERRED_ONLY="usePreferredOnly",prefs=PreferencesManager.getExtensionPrefs("linting");var _enabled=!1,$problemsPanel;let $fixAllBtn;var problemsPanel,$problemsPanelTable,_gotoEnabled=!1,_providers={};let _registeredLanguageIDs=[];var _hasErrors,_currentPromise=null;function setGotoEnabled(gotoEnabled){CommandManager.get(Commands.NAVIGATE_GOTO_FIRST_PROBLEM).setEnabled(gotoEnabled),CommandManager.get(Commands.NAVIGATE_GOTO_NEXT_PROBLEM).setEnabled(gotoEnabled),CommandManager.get(Commands.NAVIGATE_GOTO_PREV_PROBLEM).setEnabled(gotoEnabled),_gotoEnabled=gotoEnabled}function _unregisterAll(){_providers={}}function getProvidersForPath(filePath){var language=LanguageManager.getLanguageForPath(filePath).getId(),context=PreferencesManager._buildContext(filePath,language),installedProviders=getProvidersForLanguageId(language),preferredProviders,prefPreferredProviderNames=prefs.get(PREF_PREFER_PROVIDERS,context),prefPreferredOnly=prefs.get(PREF_PREFERRED_ONLY,context),providers;return prefPreferredProviderNames&&prefPreferredProviderNames.length?("string"==typeof prefPreferredProviderNames&&(prefPreferredProviderNames=[prefPreferredProviderNames]),preferredProviders=prefPreferredProviderNames.reduce(function(result,key){var provider=_.find(installedProviders,{name:key});return provider&&result.push(provider),result},[]),providers=prefPreferredOnly?preferredProviders:_.union(preferredProviders,installedProviders)):providers=installedProviders,providers}function getProviderIDsForLanguage(languageId){return _providers[languageId]?_providers[languageId].map(function(provider){return provider.name}):[]}function inspectFile(file,providerList){var response=new $.Deferred,results=[];return(providerList=providerList||getProvidersForPath(file.fullPath)).length?(providerList=providerList.filter(function(provider){return!provider.canInspect||provider.canInspect(file.fullPath)}),DocumentManager.getDocumentText(file).done(function(fileText){var perfTimerInspector=PerfUtils.markStart("CodeInspection:\t"+file.fullPath),masterPromise;(masterPromise=Async.doInParallel(providerList,function(provider){var perfTimerProvider=PerfUtils.markStart("CodeInspection '"+provider.name+"':\t"+file.fullPath),runPromise=new $.Deferred;if(runPromise.done(function(scanResult){results.push({provider:provider,result:scanResult})}),provider.scanFileAsync)window.setTimeout(function(){var errTimeout={pos:{line:-1,col:0},message:StringUtils.format(Strings.LINTER_TIMED_OUT,provider.name,prefs.get(PREF_ASYNC_TIMEOUT)),type:Type.ERROR};runPromise.resolve({errors:[errTimeout]})},prefs.get(PREF_ASYNC_TIMEOUT)),jsPromise(provider.scanFileAsync(fileText,file.fullPath)).then(function(scanResult){PerfUtils.addMeasurement(perfTimerProvider),runPromise.resolve(scanResult)}).catch(function(err){err=err||new Error("Unknown error while inspecting "+file.fullPath),PerfUtils.finalizeMeasurement(perfTimerProvider);var errError={pos:{line:-1,col:0},message:StringUtils.format(Strings.LINTER_FAILED,provider.name,err),type:Type.ERROR};console.error("[CodeInspection] Provider "+provider.name+" (async) failed: "+err.stack),runPromise.resolve({errors:[errError]})});else try{var scanResult=provider.scanFile(fileText,file.fullPath);PerfUtils.addMeasurement(perfTimerProvider),runPromise.resolve(scanResult)}catch(err){PerfUtils.finalizeMeasurement(perfTimerProvider);var errError={pos:{line:-1,col:0},message:StringUtils.format(Strings.LINTER_FAILED,provider.name,err),type:Type.ERROR};console.error("[CodeInspection] Provider "+provider.name+" (sync) threw an error: "+err&&(err.stack||err)),runPromise.resolve({errors:[errError]})}return runPromise.promise()},!1)).then(function(){results.sort(function(a,b){return providerList.indexOf(a.provider)-providerList.indexOf(b.provider)}),PerfUtils.addMeasurement(perfTimerInspector),response.resolve(results)})}).fail(function(err){console.error("[CodeInspection] Could not read file for inspection: "+file.fullPath),response.reject(err)}),response.promise()):(response.resolve(null),response.promise())}function updatePanelTitleAndStatusBar(numProblems,providersReportingProblems,aborted,fileName){var message,tooltip;if($fixAllBtn.addClass("forced-hidden"),1===providersReportingProblems.length)$problemsPanelTable.find(".inspector-section").hide(),$problemsPanelTable.find("tr").removeClass("forced-hidden"),1!==numProblems||aborted?(aborted&&(numProblems+="+"),message=documentFixes.size?StringUtils.format(Strings.MULTIPLE_ERRORS_FIXABLE,numProblems,providersReportingProblems[0].name,documentFixes.size,fileName):StringUtils.format(Strings.MULTIPLE_ERRORS,numProblems,providersReportingProblems[0].name,fileName)):message=documentFixes.size?StringUtils.format(Strings.SINGLE_ERROR_FIXABLE,providersReportingProblems[0].name,documentFixes.size,fileName):StringUtils.format(Strings.SINGLE_ERROR,providersReportingProblems[0].name,fileName);else{if(!(providersReportingProblems.length>1))return;$problemsPanelTable.find(".inspector-section").show(),aborted&&(numProblems+="+"),message=documentFixes.size?StringUtils.format(Strings.ERRORS_PANEL_TITLE_MULTIPLE_FIXABLE,numProblems,documentFixes.size,fileName):StringUtils.format(Strings.ERRORS_PANEL_TITLE_MULTIPLE,numProblems,fileName)}$problemsPanel.find(".title").text(message),tooltip=StringUtils.format(Strings.STATUSBAR_CODE_INSPECTION_TOOLTIP,message);let iconType="inspection-errors";documentFixes.size&&(iconType="inspection-repair",$fixAllBtn.removeClass("forced-hidden")),StatusBar.updateIndicator(INDICATOR_ID,!0,iconType,tooltip)}function _getMarkOptions(error){switch(error.type){case Type.ERROR:return Editor.getMarkOptionUnderlineError();case Type.WARNING:return Editor.getMarkOptionUnderlineWarn();case Type.META:return Editor.getMarkOptionUnderlineInfo()}}function _getMarkTypePriority(type){switch(type){case Type.ERROR:return 3;case Type.WARNING:return 2;case Type.META:return 1}}function _shouldMarkTokenAtPosition(editor,error){return!(isNaN(error.pos.line)||isNaN(error.pos.ch)||error.pos.line<0||error.pos.ch<0)||(console.warn("CodeInspector: Invalid error position: ",error),!1)}function _createMarkerElement(editor,line,ch,type,message,isFixable){let $marker=$("<div><span>").attr("title",(message||"").trim()).addClass(CODE_INSPECTION_GUTTER);return $marker.click(function(){editor.setCursorPos(line,ch),_showProblemsPanel(),scrollToProblem(line)}),$marker.find("span").addClass(_getIconClassForType(type,isFixable)).addClass("brackets-inspection-gutter-marker").html(" "),$marker[0]}function _addDummyGutterMarkerIfNotExist(editor,line){let marker;if(!editor.getGutterMarker(line,CODE_INSPECTION_GUTTER)){let $marker=$("<div>").addClass(CODE_INSPECTION_GUTTER);editor.setGutterMarker(line,CODE_INSPECTION_GUTTER,$marker[0])}}function _populateDummyGutterElements(editor,from,to){for(let line=from;line<=to;line++)_addDummyGutterMarkerIfNotExist(editor,line)}function _updateGutterMarks(editor,gutterErrorMessages){for(let lineno of Object.keys(gutterErrorMessages)){let highestPriorityMarkTypeSeen=Type.META,fixableMarkFound=!1,gutterMessage=gutterErrorMessages[lineno].reduce((prev,current)=>((current.fixable||prev.fixable)&&(fixableMarkFound=!0),_getMarkTypePriority(current.type)>_getMarkTypePriority(highestPriorityMarkTypeSeen)&&(highestPriorityMarkTypeSeen=current.type),{message:`${prev.message}\n${current.message} at column: ${current.ch+1}`}),{message:""}),line=gutterErrorMessages[lineno][0].line,ch=gutterErrorMessages[lineno][0].ch,message=gutterMessage.message,marker=_createMarkerElement(editor,line,ch,highestPriorityMarkTypeSeen,message,fixableMarkFound);editor.setGutterMarker(line,CODE_INSPECTION_GUTTER,marker)}_populateDummyGutterElements(editor,0,editor.getLastVisibleLine())}function _editorVieportChangeHandler(_evt,editor,from,to){if(gutterRegistrationInProgress)return editor.gutterViewportChangeTimer&&clearTimeout(editor.gutterViewportChangeTimer),void(editor.gutterViewportChangeTimer=setTimeout(()=>{const vp=editor.getViewport();_editorVieportChangeHandler(_evt,editor,vp.from,vp.to),clearTimeout(editor.gutterViewportChangeTimer),delete editor.gutterViewportChangeTimer}));_populateDummyGutterElements(editor,from,to)}function scrollToProblem(lineNumber){const $lineElement=$problemsPanelTable.find('td.line-number[data-line="'+lineNumber+'"]');return $lineElement.length?($lineElement[0].scrollIntoView({behavior:"instant",block:"start"}),$($lineElement[0]).parent()):null}function getQuickView(editor,pos,token,line){return new Promise((resolve,reject)=>{let codeInspectionMarks=editor.findMarksAt(pos,CODE_MARK_TYPE_INSPECTOR)||[],$hoverMessage=$('<div class="code-inspection-item"></div>'),quickViewPresent,startPos={line:pos.line,ch:token.start},endPos={line:pos.line,ch:token.end};for(let mark of codeInspectionMarks){let $problemView;quickViewPresent=!0;const fixID=`${mark.metadata}`;let errorMessageHTML=`<a style="cursor:pointer;color: unset;">${_.escape(mark.message)}</a>`;documentFixes.get(fixID)?(($problemView=$(`<div class="code-inspection-quick-view-item">\n <i title="${Strings.CLICK_VIEW_PROBLEM}" style="margin-right: 3px;cursor: pointer;"\n class="${_getIconClassForType(mark.type,mark.isFixable)}"></i>\n <button class="btn btn-mini fix-problem-btn" style="margin-right: 5px;">${Strings.FIX}</button>\n ${errorMessageHTML}\n <button class="btn btn-mini copy-qv-error-text-btn" title="${Strings.COPY_ERROR}">\n <i class="fas fa-copy copy-qv-error-text-btn"></i>\n </button>\n <br/>\n </div>`)).find(".fix-problem-btn").click(()=>{Metrics.countEvent(Metrics.EVENT_TYPE.LINT,"fixClick","quickView"),scrollToProblem(pos.line),_fixProblem(fixID)}),$hoverMessage.append($problemView)):($problemView=$(`<div class="code-inspection-quick-view-item">\n <i title="${Strings.CLICK_VIEW_PROBLEM}" style="margin-right: 5px; cursor: pointer;"\n class="${_getIconClassForType(mark.type,mark.isFixable)}"></i>\n ${errorMessageHTML}\n <button class="btn btn-mini copy-qv-error-text-btn" title="${Strings.COPY_ERROR}">\n <i class="fas fa-copy copy-qv-error-text-btn"></i>\n </button>\n <br/></div>`),$hoverMessage.append($problemView)),$problemView.click(function(){const selection=window.getSelection();selection&&selection.rangeCount>0&&!selection.isCollapsed||(_showProblemsPanel(),scrollToProblem(pos.line))}),$problemView.find(".copy-qv-error-text-btn").click(function(evt){evt.preventDefault(),evt.stopPropagation(),Phoenix.app.copyToClipboard(mark.message)});const markPos=mark.find();markPos.from&&markPos.from.line<startPos.line&&(startPos.line=markPos.from.line),markPos.from&&markPos.from.ch<startPos.ch&&(startPos.ch=markPos.from.ch),markPos.to&&markPos.to.line>endPos.line&&(endPos.line=markPos.to.line),markPos.to&&markPos.to.ch>endPos.ch&&(endPos.ch=markPos.to.ch)}if(quickViewPresent)return Metrics.countEvent(Metrics.EVENT_TYPE.LINT,"quickView","shown"),void resolve({start:startPos,end:endPos,content:$hoverMessage});reject()})}let fixIDCounter=1,documentFixes=new Map,lastDocumentScanTimeStamp;function _registerNewFix(editor,fix,providerName,maxOffset){return editor&&fix&&fix.rangeOffset?(editor.document.lastChangeTimestamp!==lastDocumentScanTimeStamp&&(lastDocumentScanTimeStamp=editor.document.lastChangeTimestamp,documentFixes.clear()),_isInvalidFix(fix,maxOffset)?null:(fixIDCounter++,fix.providerName=providerName,documentFixes.set(`${fixIDCounter}`,fix),fixIDCounter)):null}function _updateEditorMarksAndFixResults(resultProviderEntries){let editor=EditorManager.getCurrentFullEditor();if(!(editor&&resultProviderEntries&&resultProviderEntries.length))return;const maxOffset=editor.document.getText().length;editor.operation(function(){editor.off("viewportChange.codeInspection"),editor.on("viewportChange.codeInspection",_editorVieportChangeHandler);let gutterErrorMessages={};for(let resultProvider of resultProviderEntries){let errors=resultProvider.result&&resultProvider.result.errors||[];for(let error of errors){let line=error.pos.line||0,ch=error.pos.ch||0,fixable=!1;if(_shouldMarkTokenAtPosition(editor,error)){let mark;const markOptions=_getMarkOptions(error),fixID=_registerNewFix(editor,error.fix,resultProvider.provider.name,maxOffset);fixID&&(markOptions.metadata=fixID,markOptions.isFixable=!0,error.fix.id=fixID,fixable=!0),(mark=error.endPos&&!editor.isSamePosition(error.pos,error.endPos)?editor.markText(CODE_MARK_TYPE_INSPECTOR,error.pos,error.endPos,markOptions):editor.markToken(CODE_MARK_TYPE_INSPECTOR,error.pos,markOptions)).type=error.type,mark.message=error.message}let gutterMessage=gutterErrorMessages[line]||[];gutterMessage.push({message:error.message,type:error.type,fixable:fixable,line:line,ch:ch}),gutterErrorMessages[line]=gutterMessage}}_updateGutterMarks(editor,gutterErrorMessages)})}const scrollPositionMap=new Map;function _noProviderReturnedResults(currentDoc,fullFilePath){let message;_hasErrors=!1,_currentPromise=null;const language=currentDoc&&LanguageManager.getLanguageForPath(currentDoc.file.fullPath);message=language?StringUtils.format(Strings.NO_LINT_AVAILABLE,language.getName()):Strings.NOTHING_TO_LINT,$problemsPanel.find(".title").text(message),$problemsPanelTable.empty(),$fixAllBtn.addClass("forced-hidden"),StatusBar.updateIndicator(INDICATOR_ID,!0,"inspection-disabled",message),setGotoEnabled(!1)}function run(){if(!problemsPanel)return;if(!_enabled)return _hasErrors=!1,_currentPromise=null,$problemsPanel.find(".title").text(Strings.LINT_DISABLED),$problemsPanelTable.empty(),$fixAllBtn.addClass("forced-hidden"),StatusBar.updateIndicator(INDICATOR_ID,!0,"inspection-disabled",Strings.LINT_DISABLED),void setGotoEnabled(!1);let currentDoc=DocumentManager.getCurrentDocument(),providerList=currentDoc&&getProvidersForPath(currentDoc.file.fullPath);providerList=providerList&&providerList.filter(function(provider){return!provider.canInspect||provider.canInspect(currentDoc.file.fullPath)});let editor=EditorManager.getCurrentFullEditor(),fullFilePath;if(editor&&(lastDocumentScanTimeStamp=editor.document.lastChangeTimestamp,documentFixes.clear(),fullFilePath=editor.document.file.fullPath),providerList&&providerList.length){let numProblems=0,aborted=!1,allErrors=[],html,providersReportingProblems=[];scrollPositionMap.set($problemsPanelTable.lintFilePath||fullFilePath,$problemsPanelTable.scrollTop()),(_currentPromise=inspectFile(currentDoc.file,providerList)).then(function(results){if(!(results=results.filter(function(providerResult){return!providerResult.result||!providerResult.result.isIgnored})).length)return void _noProviderReturnedResults(currentDoc,fullFilePath);if(editor.clearAllMarks(CODE_MARK_TYPE_INSPECTOR),editor.clearGutter(CODE_INSPECTION_GUTTER),_updateEditorMarksAndFixResults(results),this!==_currentPromise)return;var errors=results.reduce(function(a,item){return a+(item.result?item.result.errors.length:0)},0);if(_hasErrors=Boolean(errors),!errors){var message=Strings.NO_ERRORS_MULTIPLE_PROVIDER;return 1===providerList.length&&(message=StringUtils.format(Strings.NO_ERRORS,providerList[0].name)),$problemsPanel.find(".title").text(message),$problemsPanelTable.empty(),$fixAllBtn.addClass("forced-hidden"),StatusBar.updateIndicator(INDICATOR_ID,!0,"inspection-valid",message),void setGotoEnabled(!1)}var perfTimerDOM=PerfUtils.markStart("ProblemsPanel render:\t"+currentDoc.file.fullPath);results.forEach(function(inspectionResult){var provider=inspectionResult.provider,isExpanded=!1!==prefs.get(provider.name+".collapsed");inspectionResult.result&&(inspectionResult.result.errors.forEach(function(error){!isNaN(error.pos.line)&&error.pos.line+1>0&&void 0!==(error.codeSnippet=currentDoc.getLine(error.pos.line))&&(error.friendlyLine=error.pos.line+1,error.codeSnippet=error.codeSnippet.substr(0,175)),error.type!==Type.META&&numProblems++,error.iconClass=_getIconClassForType(error.type,error.fix&&error.fix.id),error.display=isExpanded?"":"forced-hidden"}),inspectionResult.result.aborted&&(aborted=!0),inspectionResult.result.errors.length&&(allErrors.push({isExpanded:isExpanded,providerName:provider.name,results:inspectionResult.result.errors}),providersReportingProblems.push(provider)))}),html=Mustache.render(ResultsTemplate,{Strings:Strings,reportList:allErrors}),$problemsPanelTable.lintFilePath=fullFilePath,$problemsPanelTable.empty().append(html),updatePanelTitleAndStatusBar(numProblems,providersReportingProblems,aborted,path.basename(fullFilePath)),setGotoEnabled(!0);const scrollPosition=scrollPositionMap.get(fullFilePath)||0;$problemsPanelTable.scrollTop(scrollPosition),PerfUtils.addMeasurement(perfTimerDOM)})}else _noProviderReturnedResults(currentDoc,fullFilePath)}let gutterRegistrationInProgress=!1,lastRunTime;function register(languageId,provider){if(_providers[languageId]){var indexOfProvider=_.findIndex(_providers[languageId],function(entry){return entry.name===provider.name});-1!==indexOfProvider&&_providers[languageId].splice(indexOfProvider,1)}else _providers[languageId]=[];_providers[languageId].push(provider),_registeredLanguageIDs.includes(languageId)||(_registeredLanguageIDs.push(languageId),gutterRegistrationInProgress=!0,Editor.unregisterGutter(CODE_INSPECTION_GUTTER),gutterRegistrationInProgress=!1,Editor.registerGutter(CODE_INSPECTION_GUTTER,CODE_INSPECTION_GUTTER_PRIORITY,_registeredLanguageIDs)),run()}function getProvidersForLanguageId(languageId){var result=[];return _providers[languageId]&&(result=result.concat(_providers[languageId])),_providers["*"]&&(result=result.concat(_providers["*"])),result}function updateListeners(){_enabled?(MainViewManager.on("currentFileChange.codeInspection",function(){run()}),DocumentManager.on("currentDocumentLanguageChanged.codeInspection",function(){run()}).on("documentSaved.codeInspection documentRefreshed.codeInspection",function(event,document){document===DocumentManager.getCurrentDocument()&&run()})):(DocumentManager.off(".codeInspection"),MainViewManager.off(".codeInspection"))}function toggleEnabled(enabled,doNotSave){void 0===enabled&&(enabled=!_enabled),enabled!==_enabled&&(_enabled=enabled,CommandManager.get(Commands.VIEW_TOGGLE_INSPECTION).setChecked(_enabled),updateListeners(),doNotSave||(prefs.set(PREF_ENABLED,_enabled),prefs.save()),run())}function toggleProblems(){problemsPanel&&(problemsPanel.isVisible()?problemsPanel.hide():problemsPanel.show())}function _showProblemsPanel(){problemsPanel&&!problemsPanel.isVisible()&&problemsPanel.show()}function handleGotoFirstProblem(){run(),_gotoEnabled&&$problemsPanel.find("tr:not(.inspector-section)").first().trigger("click")}function handleGotoNextProblem(){if(_gotoEnabled){const editor=EditorManager.getCurrentFullEditor();if(!editor)return;const currentCursor=editor.getCursorPos(),nextMarks=editor.getMarksAfter(currentCursor,CODE_MARK_TYPE_INSPECTOR);if(!nextMarks.length||!nextMarks[0].find())return;let nextMark=null;for(let i=0;i<nextMarks.length;i++){const markRange=nextMarks[i].find();if(markRange&&(markRange.from.line>currentCursor.line||markRange.from.line===currentCursor.line&&markRange.from.ch>currentCursor.ch)){nextMark=nextMarks[i];break}}if(!nextMark)return;const nextMarkRange=nextMark.find();nextMarkRange&&editor.setCursorPos(nextMarkRange.from.line,nextMarkRange.from.ch)}}function handleGotoPrevProblem(){if(_gotoEnabled){const editor=EditorManager.getCurrentFullEditor();if(!editor)return;const currentCursor=editor.getCursorPos(),prevMarks=editor.getMarksBefore(currentCursor,CODE_MARK_TYPE_INSPECTOR);if(!prevMarks.length)return;let prevMark=null;for(let i=prevMarks.length-1;i>=0;i--){const markRange=prevMarks[i].find();if(markRange&&(markRange.to.line<currentCursor.line||markRange.to.line===currentCursor.line&&markRange.to.ch<currentCursor.ch)){prevMark=prevMarks[i];break}}if(!prevMark)return;const prevMarkRange=prevMark.find();prevMarkRange&&editor.setCursorPos(prevMarkRange.from.line,prevMarkRange.from.ch)}}function _isInvalidFix(fixDetails,maxOffset){return!_.isNumber(fixDetails.rangeOffset.start)||!_.isNumber(fixDetails.rangeOffset.end)||fixDetails.rangeOffset.start<0||fixDetails.rangeOffset.end<0||fixDetails.rangeOffset.start>maxOffset||fixDetails.rangeOffset.end>maxOffset||"string"!=typeof fixDetails.replaceText}function _fixProblem(fixID){const fixDetails=documentFixes.get(fixID),editor=EditorManager.getCurrentFullEditor(),maxOffset=editor.document.getText().length;if(editor&&fixDetails&&editor.document.lastChangeTimestamp===lastDocumentScanTimeStamp)if(_isInvalidFix(fixDetails,maxOffset))Metrics.countEvent(Metrics.EVENT_TYPE.LINT,"fixFail","invalid"),console.error("Invalid fix:",fixDetails);else{const from=editor.posFromIndex(fixDetails.rangeOffset.start),to=editor.posFromIndex(fixDetails.rangeOffset.end);editor.setSelection(from,to,!0,Editor.BOUNDARY_BULLSEYE,EDIT_ORIGIN_LINT_FIX),editor.replaceSelection(fixDetails.replaceText,"around")}else Metrics.countEvent(Metrics.EVENT_TYPE.LINT,"fixFail","dialogShown"),Dialogs.showErrorDialog(Strings.CANNOT_FIX_TITLE,Strings.CANNOT_FIX_MESSAGE);MainViewManager.focusActivePane(),run()}function _fixAllProblems(){const editor=EditorManager.getCurrentFullEditor();if(!editor||editor.document.lastChangeTimestamp!==lastDocumentScanTimeStamp)return void Dialogs.showErrorDialog(Strings.CANNOT_FIX_TITLE,Strings.CANNOT_FIX_MESSAGE);if(!documentFixes.size)return;const replacements=[],maxOffset=editor.document.getText().length;for(let fixDetails of documentFixes.values())_isInvalidFix(fixDetails,maxOffset)&&console.error("Invalid fix:",fixDetails),replacements.push({from:editor.posFromIndex(fixDetails.rangeOffset.start),to:editor.posFromIndex(fixDetails.rangeOffset.end),text:fixDetails.replaceText});editor.replaceMultipleRanges(replacements,EDIT_ORIGIN_LINT_FIX);const finalCursor=replacements[replacements.length-1].from;editor.setCursorPos(finalCursor.line,finalCursor.ch),MainViewManager.focusActivePane(),run()}$(window.document).on("mousemove",()=>{if(Phoenix.isTestWindow)return;const editor=EditorManager.getCurrentFullEditor();if(!editor||editor.document.lastChangeTimestamp===lastDocumentScanTimeStamp)return;const currentTime=Date.now();lastRunTime&¤tTime-lastRunTime<1e3||(lastRunTime=currentTime,run())}),CommandManager.register(Strings.CMD_VIEW_TOGGLE_INSPECTION,Commands.VIEW_TOGGLE_INSPECTION,toggleEnabled),CommandManager.register(Strings.CMD_VIEW_TOGGLE_PROBLEMS,Commands.VIEW_TOGGLE_PROBLEMS,toggleProblems),CommandManager.register(Strings.CMD_GOTO_FIRST_PROBLEM,Commands.NAVIGATE_GOTO_FIRST_PROBLEM,handleGotoFirstProblem),CommandManager.register(Strings.CMD_GOTO_NEXT_PROBLEM,Commands.NAVIGATE_GOTO_NEXT_PROBLEM,handleGotoNextProblem),CommandManager.register(Strings.CMD_GOTO_PREV_PROBLEM,Commands.NAVIGATE_GOTO_PREV_PROBLEM,handleGotoPrevProblem),prefs.definePreference(PREF_ENABLED,"boolean",brackets.config["linting.enabled_by_default"],{description:Strings.DESCRIPTION_LINTING_ENABLED}).on("change",function(e,data){toggleEnabled(prefs.get(PREF_ENABLED),!0)}),prefs.definePreference(PREF_ASYNC_TIMEOUT,"number",1e4,{description:Strings.DESCRIPTION_ASYNC_TIMEOUT}),prefs.definePreference(PREF_PREFER_PROVIDERS,"array",[],{description:Strings.DESCRIPTION_LINTING_PREFER,valueType:"string"}),prefs.definePreference(PREF_PREFERRED_ONLY,"boolean",!1,{description:Strings.DESCRIPTION_USE_PREFERED_ONLY}),AppInit.htmlReady(function(){Editor.registerGutter(CODE_INSPECTION_GUTTER,CODE_INSPECTION_GUTTER_PRIORITY);var panelHtml=Mustache.render(PanelTemplate,Strings),$selectedRow;function checkSelectionInsideElement(range,element){if(!range||range.endOffset===range.startOffset)return!1;const startNode=range.startContainer,endNode=range.endContainer;return $.contains(element,startNode)&&$.contains(element,endNode)}problemsPanel=WorkspaceManager.createBottomPanel("errors",$(panelHtml),100,Strings.CMD_VIEW_TOGGLE_PROBLEMS),$problemsPanel=$("#problems-panel"),($fixAllBtn=$problemsPanel.find(".problems-fix-all-btn")).click(()=>{Metrics.countEvent(Metrics.EVENT_TYPE.LINT,"fixAllClick","panel"),_fixAllProblems()}),$problemsPanelTable=$problemsPanel.find(".table-container").on("click","tr",function(e){if($(e.target).hasClass("ph-copy-problem")){let message=$(e.target).parent().parent().find(".line-text").text();return message||(message=$(e.target).parent().parent().parent().find(".line-text").text()),message&&Phoenix.app.copyToClipboard(message),e.preventDefault(),e.stopPropagation(),void MainViewManager.focusActivePane()}if($(e.target).hasClass("ph-fix-problem"))return Metrics.countEvent(Metrics.EVENT_TYPE.LINT,"fixClick","panel"),_fixProblem(""+$(e.target).data("fixid")),e.preventDefault(),void e.stopPropagation();if($selectedRow&&$selectedRow.removeClass("selected"),($selectedRow=$(e.currentTarget)).addClass("selected"),$selectedRow.hasClass("inspector-section")){var $triangle=$(".disclosure-triangle",$selectedRow),isExpanded=$triangle.hasClass("expanded");isExpanded?$selectedRow.nextUntil(".inspector-section").addClass("forced-hidden"):$selectedRow.nextUntil(".inspector-section").removeClass("forced-hidden"),$triangle.toggleClass("expanded");var providerName=$selectedRow.find("input[type='hidden']").val();prefs.set(providerName+".collapsed",!isExpanded),prefs.save()}else{const selection=window.getSelection();if(selection.rangeCount>0){const range=selection.getRangeAt(0);if(checkSelectionInsideElement(range,$problemsPanel[0]))return}var lineTd=$selectedRow.find(".line-number"),line=parseInt(lineTd.text(),10)-1;if(!isNaN(line)){var character=lineTd.data("character"),editor;EditorManager.getCurrentFullEditor().setCursorPos(line,character,!0),MainViewManager.focusActivePane()}}});var statusIconHtml=Mustache.render('<div id="status-inspection"> </div>',Strings);StatusBar.addIndicator(INDICATOR_ID,$(statusIconHtml),!0,"","","status-indent"),$("#status-inspection").click(function(){toggleProblems()}),toggleEnabled(prefs.get(PREF_ENABLED),!0),QuickViewManager.registerQuickViewProvider({getQuickView:getQuickView,QUICK_VIEW_NAME:"CodeInspection"},["all"])}),AppInit.appReady(function(){Phoenix.isTestWindow||setTimeout(run,2e3)}),exports._unregisterAll=_unregisterAll,exports._PREF_ASYNC_TIMEOUT=PREF_ASYNC_TIMEOUT,exports._PREF_PREFER_PROVIDERS=PREF_PREFER_PROVIDERS,exports._PREF_PREFERRED_ONLY=PREF_PREFERRED_ONLY,exports.CODE_INSPECTION_GUTTER=CODE_INSPECTION_GUTTER,exports.register=register,exports.Type=Type,exports.toggleEnabled=toggleEnabled,exports.inspectFile=inspectFile,exports.requestRun=run,exports.getProvidersForPath=getProvidersForPath,exports.getProviderIDsForLanguage=getProviderIDsForLanguage,exports.scrollToProblem=scrollToProblem});