import * as vscode from 'vscode' ; import { buildifierLint , getBuildifierFileType } from './execute' ; import { IBuildifierWarning } from './result' ; import { BuildifierSettings } from './settings' ; /**
 * The delay to wait for the user to finish typing before invoking buildifier to
 * determine lint warnings.
 */ const DIAGNOSTICS_ON_TYPE_DELAY_MILLIS = 500 ; /** Manages diagnostics emitted by buildifier's lint mode. */ export class BuildifierDiagnosticsManager { /** The diagnostics collection for buildifier lint warnings. */ private diagnosticsCollection = vscode . languages . createDiagnosticCollection ( 'buildifier' ) ; /**
     * Initializes a new buildifier diagnostics manager and hooks into workspace
     * and window events so that diagnostics are updated live.
     */ constructor ( private settings , disposables ) { let didChangeTextTimer ; disposables . push ( vscode . workspace . onDidChangeTextDocument ( e => { if ( didChangeTextTimer ) { clearTimeout ( didChangeTextTimer ) ; } didChangeTextTimer = setTimeout ( ( ) => { this . updateDiagnostics ( e . document ) ; didChangeTextTimer = null ; } , DIAGNOSTICS_ON_TYPE_DELAY_MILLIS ) ; } ) ) ; disposables . push ( vscode . window . onDidChangeActiveTextEditor ( e => { if ( ! e ) { return ; } this . updateDiagnostics ( e . document ) ; } ) ) ; if ( vscode . window . activeTextEditor ) { this . updateDiagnostics ( vscode . window . activeTextEditor . document ) ; } } param document public async error ( document , range , message ) { const diagnostic = new vscode . Diagnostic ( range , message , vscode . DiagnosticSeverity . Error ) ; diagnostic . source = 'buildifier' ; this . diagnosticsCollection . set ( document . uri , [ diagnostic ] ) ; } param document public async updateDiagnostics ( document ) { const cfg = await this . settings . get ( ) ; if ( ! cfg ) { return ; } if ( ! cfg . enabled ) { return ; } if ( ! ( document . languageId === 'bazel' || document . languageId === 'starlark' ) ) { return ; } const result = await buildifierLint ( cfg , document . getText ( ) , getBuildifierFileType ( document . uri . fsPath ) , 'warn' ) ; if ( ! result . stderr ) { this . diagnosticsCollection . set ( document . uri , result . file . warnings . map ( warning => { const range = new vscode . Range ( warning . start . line - 1 , warning . start . column - 1 , warning . end . line - 1 , warning . end . column - 1 ) ; const diagnostic = new vscode . Diagnostic ( range , warning . message , vscode . DiagnosticSeverity . Warning ) ; diagnostic . source = 'buildifier' ; diagnostic . code = warning . category ; return diagnostic ; } ) ) ; } else { const warnings = [ ] ; const syntaxError = parseStderr ( result . stderr ) ; if ( syntaxError ) { warnings . push ( syntaxError ) ; } this . diagnosticsCollection . set ( document . uri , warnings . map ( warning => { const range = new vscode . Range ( warning . start . line - 1 , warning . start . column - 1 , warning . end . line - 1 , warning . end . column - 1 ) ; const diagnostic = new vscode . Diagnostic ( range , warning . message , vscode . DiagnosticSeverity . Error ) ; diagnostic . source = 'buildifier' ; diagnostic . code = warning . category ; return diagnostic ; } ) ) ; } } } function parseStderr ( input ) { if ( ! input . startsWith ( '<stdin>' ) ) { return undefined ; } const parts = input . slice ( '<stdin>:' . length ) . split ( ':' ) ; const line = parseInt ( parts [ 0 ] ) ; const column = parseInt ( parts [ 1 ] ) ; const rest = parts . slice ( 2 ) . join ( ':' ) ; const pos = { line , column } ; return { start : pos , end : pos , category : 'invalid-input' , actionable : false , message : rest , } ; }