import * as vscode from 'vscode' ; import * as interfaces from './interfaces' ; export default class MergeDectorator implements vscode . Disposable { private decorations : { [ key ] : vscode . TextEditorDecorationType ; } = { } ; private decorationUsesWholeLine : boolean = true ; private currentColorRgb = `32,200,94` ; private incomingColorRgb = `24,134,255` ; private config : interfaces . IExtensionConfiguration = null ; constructor ( private context , private tracker ) { } begin ( config ) { this . config = config ; this . registerDecorationTypes ( config ) ; vscode . window . visibleTextEditors . forEach ( e => this . applyDecorations ( e ) ) ; vscode . workspace . onDidOpenTextDocument ( event => { this . applyDecorationsFromEvent ( event ) ; } , null , this . context . subscriptions ) ; vscode . workspace . onDidChangeTextDocument ( event => { this . applyDecorationsFromEvent ( event . document ) ; } , null , this . context . subscriptions ) ; vscode . window . onDidChangeActiveTextEditor ( ( e ) => { this . applyDecorations ( e ) ; } , null , this . context . subscriptions ) ; } configurationUpdated ( config ) { this . config = config ; this . registerDecorationTypes ( config ) ; vscode . window . visibleTextEditors . forEach ( e => { this . removeDecorations ( e ) ; this . applyDecorations ( e ) ; } ) ; } private registerDecorationTypes ( config ) { Object . keys ( this . decorations ) . forEach ( k => this . decorations [ k ] . dispose ( ) ) ; this . decorations = { } ; if ( ! config . enableDecorations || ! config . enableEditorOverview ) { return ; } if ( config . enableDecorations || config . enableEditorOverview ) { this . decorations [ 'current.content' ] = vscode . window . createTextEditorDecorationType ( this . generateBlockRenderOptions ( this . currentColorRgb , config ) ) ; this . decorations [ 'incoming.content' ] = vscode . window . createTextEditorDecorationType ( this . generateBlockRenderOptions ( this . incomingColorRgb , config ) ) ; } if ( config . enableDecorations ) { this . decorations [ 'current.header' ] = vscode . window . createTextEditorDecorationType ( { isWholeLine : this . decorationUsesWholeLine , backgroundColor : `rgba(${ this . currentColorRgb }, 1.0)` , color : 'white' , after : { contentText : ' (Current change)' , color : 'rgba(0, 0, 0, 0.7)' } } ) ; this . decorations [ 'splitter' ] = vscode . window . createTextEditorDecorationType ( { backgroundColor : 'rgba(0, 0, 0, 0.25)' , color : 'white' , isWholeLine : this . decorationUsesWholeLine , } ) ; this . decorations [ 'incoming.header' ] = vscode . window . createTextEditorDecorationType ( { backgroundColor : `rgba(${ this . incomingColorRgb }, 1.0)` , color : 'white' , isWholeLine : this . decorationUsesWholeLine , after : { contentText : ' (Incoming change)' , color : 'rgba(0, 0, 0, 0.7)' } } ) ; } } dispose ( ) { if ( this . decorations ) { Object . keys ( this . decorations ) . forEach ( name => { this . decorations [ name ] . dispose ( ) ; } ) ; this . decorations = null ; } } private generateBlockRenderOptions ( color , config ) { let renderOptions = { } ; if ( config . enableDecorations ) { renderOptions . backgroundColor = `rgba(${ color }, 0.2)` ; renderOptions . isWholeLine = this . decorationUsesWholeLine ; } if ( config . enableEditorOverview ) { renderOptions . overviewRulerColor = `rgba(${ color }, 0.5)` ; renderOptions . overviewRulerLane = vscode . OverviewRulerLane . Full ; } return renderOptions ; } private applyDecorationsFromEvent ( eventDocument ) { for ( var i = 0 ; i < vscode . window . visibleTextEditors . length ; i ++ ) { if ( vscode . window . visibleTextEditors [ i ] . document === eventDocument ) { this . applyDecorations ( vscode . window . visibleTextEditors [ i ] ) ; } } } private async applyDecorations ( editor ) { if ( ! editor || ! editor . document ) { return ; } if ( ! this . config || ( ! this . config . enableDecorations && ! this . config . enableEditorOverview ) ) { return ; } let conflicts = await this . tracker . getConflicts ( editor . document ) ; if ( conflicts . length === 0 ) { this . removeDecorations ( editor ) ; return ; } let matchDecorations = { } ; let pushDecoration = ( key , d ) => { matchDecorations [ key ] = matchDecorations [ key ] || [ ] ; matchDecorations [ key ] . push ( d ) ; } ; conflicts . forEach ( conflict => { pushDecoration ( 'current.content' , { range : conflict . current . content } ) ; pushDecoration ( 'incoming.content' , { range : conflict . incoming . content } ) ; if ( this . config . enableDecorations ) { pushDecoration ( 'current.header' , { range : conflict . current . header } ) ; pushDecoration ( 'splitter' , { range : conflict . splitter } ) ; pushDecoration ( 'incoming.header' , { range : conflict . incoming . header } ) ; } } ) ; Object . keys ( matchDecorations ) . forEach ( decorationKey => { let decorationType = this . decorations [ decorationKey ] ; if ( decorationType ) { editor . setDecorations ( decorationType , matchDecorations [ decorationKey ] ) ; } } ) ; } private removeDecorations ( editor ) { Object . keys ( this . decorations ) . forEach ( decorationKey => { let decorationType = this . decorations [ decorationKey ] ; if ( decorationType ) { editor . setDecorations ( decorationType , [ ] ) ; } } ) ; } }