import * as vscode from 'vscode' ; import { Plugin } from '../plugin' ; import { ThemeConfig , getConfigValue } from '../config/config' ; const ENABLED = true ; const SHAKE_INTENSITY = 5 ; export class ScreenShakerConfig { enableShake : boolean ; shakeIntensity ? : number ; } export class ScreenShaker implements Plugin { private negativeX : vscode . TextEditorDecorationType ; private positiveX : vscode . TextEditorDecorationType ; private negativeY : vscode . TextEditorDecorationType ; private positiveY : vscode . TextEditorDecorationType ; private shakeDecorations : vscode . TextEditorDecorationType [ ] = [ ] ; private shakeTimeout : NodeJS . Timer ; private config : ScreenShakerConfig = { } as ScreenShakerConfig ; private fullRange = [ new vscode . Range ( new vscode . Position ( 0 , 0 ) , new vscode . Position ( Number . MAX_SAFE_INTEGER , Number . MAX_SAFE_INTEGER ) ) ] ; constructor ( public themeConfig ) { } public activate = ( ) => { this . dispose ( ) ; this . negativeX = vscode . window . createTextEditorDecorationType ( < vscode . DecorationRenderOptions > { textDecoration : `none; margin-left: 0px;` } ) ; this . positiveX = vscode . window . createTextEditorDecorationType ( < vscode . DecorationRenderOptions > { textDecoration : `none; margin-left: ${ this . config . shakeIntensity }px;` } ) ; this . negativeY = vscode . window . createTextEditorDecorationType ( < vscode . DecorationRenderOptions > { textDecoration : `none; margin-top: 0px;` } ) ; this . positiveY = vscode . window . createTextEditorDecorationType ( < vscode . DecorationRenderOptions > { textDecoration : `none; margin-top: ${ this . config . shakeIntensity }px;` } ) ; this . shakeDecorations = [ this . negativeX , this . positiveX , this . negativeY , this . positiveY ] ; } ; public dispose = ( ) => { clearTimeout ( this . shakeTimeout ) ; this . shakeDecorations . forEach ( decoration => decoration . dispose ( ) ) ; } ; public onPowermodeStart = ( combo ) => { } ; public onPowermodeStop = ( combo ) => { this . unshake ( ) ; } ; public onDidChangeTextDocument = ( combo , powermode , event ) => { if ( ! this . config . enableShake || ! powermode ) { return ; } this . shake ( ) ; } ; public onDidChangeConfiguration = ( config ) => { const newConfig = { enableShake : getConfigValue < boolean > ( 'enableShake' , config , this . themeConfig ) , shakeIntensity : getConfigValue < number > ( 'shakeIntensity' , config , this . themeConfig ) , } ; let changed = false ; Object . keys ( newConfig ) . forEach ( key => { if ( this . config [ key ] !== newConfig [ key ] ) { changed = true ; } } ) ; if ( ! changed ) { return ; } const oldConfig = this . config ; this . config = newConfig ; if ( this . config . enableShake && ! oldConfig . enableShake ) { this . activate ( ) ; return ; } if ( this . config . shakeIntensity !== oldConfig . shakeIntensity ) { this . activate ( ) ; return ; } if ( ! this . config . enableShake ) { this . dispose ( ) ; return ; } } ; /**
     * "Shake" the screen by applying decorations that set margins
     * to move them horizontally or vertically
     */ private shake = ( ) => { if ( ! this . config . enableShake ) { return ; } const activeEditor = vscode . window . activeTextEditor ; const xRanges = [ ] ; for ( let i = 0 ; i < activeEditor . document . lineCount ; i ++ ) { xRanges . push ( new vscode . Range ( new vscode . Position ( i , 0 ) , new vscode . Position ( i , 1 ) ) ) ; } if ( Math . random ( ) > 0.5 ) { activeEditor . setDecorations ( this . negativeX , [ ] ) ; activeEditor . setDecorations ( this . positiveX , xRanges ) ; } else { activeEditor . setDecorations ( this . positiveX , [ ] ) ; activeEditor . setDecorations ( this . negativeX , xRanges ) ; } if ( Math . random ( ) > 0.5 ) { activeEditor . setDecorations ( this . negativeY , [ ] ) ; activeEditor . setDecorations ( this . positiveY , this . fullRange ) ; } else { activeEditor . setDecorations ( this . positiveY , [ ] ) ; activeEditor . setDecorations ( this . negativeY , this . fullRange ) ; } clearTimeout ( this . shakeTimeout ) ; this . shakeTimeout = setTimeout ( ( ) => { this . unshake ( ) ; } , 1000 ) ; } ; /**
     * Unset all shake decorations
     */ private unshake = ( ) => { this . shakeDecorations . forEach ( decoration => { vscode . window . activeTextEditor . setDecorations ( decoration , [ ] ) ; } ) ; } ; }