'use strict' ; import * as path from 'path' ; import * as cp from 'child_process' ; import ChildProcess = cp . ChildProcess ; import * as vscode from 'vscode' ; export default class HaskellLintingProvider implements vscode . CodeActionProvider { private static commandId : string = 'haskell.runCodeAction' ; private command : vscode . Disposable ; private diagnosticCollection : vscode . DiagnosticCollection ; public activate ( subscriptions ) { this . command = vscode . commands . registerCommand ( HaskellLintingProvider . commandId , this . runCodeAction , this ) ; subscriptions . push ( this ) ; this . diagnosticCollection = vscode . languages . createDiagnosticCollection ( ) ; vscode . workspace . onDidOpenTextDocument ( this . doHlint , this , subscriptions ) ; vscode . workspace . onDidCloseTextDocument ( ( textDocument ) => { this . diagnosticCollection . delete ( textDocument . uri ) ; } , null , subscriptions ) ; vscode . workspace . onDidSaveTextDocument ( this . doHlint , this ) ; vscode . workspace . textDocuments . forEach ( this . doHlint , this ) ; } public dispose ( ) { this . diagnosticCollection . clear ( ) ; this . diagnosticCollection . dispose ( ) ; this . command . dispose ( ) ; } private doHlint ( textDocument ) { if ( textDocument . languageId !== 'haskell' ) { return ; } let decoded = '' ; let diagnostics = [ ] ; let options = vscode . workspace . rootPath ? { cwd : vscode . workspace . rootPath } : undefined ; let args = [ '--json' , textDocument . fileName ] ; let childProcess = cp . spawn ( 'hlint' , [ '--json' , textDocument . fileName ] , options ) ; childProcess . on ( 'error' , ( error ) => { console . log ( error ) ; vscode . window . showInformationMessage ( `Cannot hlint the haskell file.` ) ; } ) ; if ( childProcess . pid ) { childProcess . stdout . on ( 'data' , ( data ) => { decoded += data ; } ) ; childProcess . stdout . on ( 'end' , ( ) => { JSON . parse ( decoded ) . forEach ( item => { let severity = item . severity . toLowerCase ( ) === "warning" ? vscode . DiagnosticSeverity . Warning : vscode . DiagnosticSeverity . Error ; let message = item . hint + " Replace: " + item . from + " ==> " + item . to ; let range = new vscode . Range ( item . startLine - 1 , item . startColumn - 1 , item . endLine - 1 , item . endColumn - 1 ) ; let diagnostic = new vscode . Diagnostic ( range , message , severity ) ; diagnostics . push ( diagnostic ) ; } ) ; this . diagnosticCollection . set ( textDocument . uri , diagnostics ) ; } ) ; } } public provideCodeActions ( document , range , context , token ) { let diagnostic = context . diagnostics [ 0 ] ; return [ { title : "Accept hlint suggestion" , command : HaskellLintingProvider . commandId , arguments : [ document , diagnostic . range , diagnostic . message ] } ] ; } private runCodeAction ( document , range , message ) { let fromRegex = /.*Replace:(.*)==>.*/g ; let fromMatch = fromRegex . exec ( message . replace ( /\s/g , '' ) ) ; let from = fromMatch [ 1 ] ; let to = document . getText ( range ) . replace ( /\s/g , '' ) ; if ( from === to ) { let newText = /.*==>\s(.*)/g . exec ( message ) [ 1 ] ; let edit = new vscode . WorkspaceEdit ( ) ; edit . replace ( document . uri , range , newText ) ; return vscode . workspace . applyEdit ( edit ) ; } else { vscode . window . showErrorMessage ( "The suggestion was not applied because it is out of date. You might have tried to apply the same edit twice." ) ; } } }