import { VimMode } from '../neovim/types' ; import { BufferType } from '../../common/types' ; import { EventEmitter } from 'events' ; const state = { mode : VimMode . Normal , bufferType : BufferType . Normal , file : '' , filetype : '' , dir : '' , cwd : '' , colorscheme : '' , revision : - 1 , line : 0 , column : 0 , editorTopLine : 0 , editorBottomLine : 0 , absoluteFilepath : '' , } ; export type NeovimState = typeof state ; type StateKeys = keyof NeovimState ; type WatchState = { [ Key in StateKeys ] : ( fn : ( value : NeovimState [ Key ] , previousValue : NeovimState [ Key ] ) => void ) => void ; } ; type OnStateValue1 = { [ Key in StateKeys ] : ( value : NeovimState [ Key ] , fn : ( ) => void ) => void ; } ; type OnStateValue2 = { [ Key in StateKeys ] : ( value : NeovimState [ Key ] , previousValue : NeovimState [ Key ] , fn : ( ) => void ) => void ; } ; type OnStateValue = OnStateValue1 & OnStateValue2 ; type UntilStateValue1 = { [ Key in StateKeys ] : { is : ( value : NeovimState [ Key ] ) => Promise < NeovimState [ Key ] > ; } ; } ; type UntilStateValue2 = { [ Key in StateKeys ] : { is : ( value : NeovimState [ Key ] , previousValue : NeovimState [ Key ] ) => Promise < NeovimState [ Key ] > ; } ; } ; type UntilStateValue = UntilStateValue1 & UntilStateValue2 ; const StateConstructor = ( _stateName ) => { const watchers = new EventEmitter ( ) ; const stateChangeFns = new Set < Function > ( ) ; const watchState = new Proxy ( Object . create ( null ) , { get : ( _ , key ) => ( fn ) => watchers . on ( key , fn ) , } ) ; const onStateChange = ( fn ) => { stateChangeFns . add ( fn ) ; } ; const onStateValue = new Proxy ( Object . create ( null ) , { get : ( _ , key ) => ( matchValue , ... args ) => { const matchPreviousValue = args . find ( ( a ) => typeof a === 'string' ) ; const fn = args . find ( ( a ) => typeof a === 'function' ) ; watchers . on ( key , ( value , previousValue ) => { const same = value === matchValue ; const prevSame = typeof matchPreviousValue == null ? true : previousValue === matchPreviousValue ; if ( same && prevSame ) fn ( ) ; } ) ; } , } ) ; const untilStateValue = new Proxy ( Object . create ( null ) , { get : ( _ , key ) => ( { is : ( matchValue , matchPreviousValue ? ) => new Promise ( ( done ) => { const callback = ( value , previousValue ) => { const same = value === matchValue ; const prevSame = matchPreviousValue == null ? true : previousValue === matchPreviousValue ; if ( same && prevSame ) { done ( value ) ; watchers . removeListener ( key , callback ) ; } } ; watchers . on ( key , callback ) ; } ) , } ) , } ) ; const notifyStateChange = ( nextState , key , value , previousValue ) => { watchers . emit ( key , value , previousValue ) ; stateChangeFns . forEach ( ( fn ) => fn ( nextState , key , value , previousValue ) ) ; } ; const stateProxy = new Proxy ( state , { get : ( _ , key ) => Reflect . get ( state , key ) , set : ( _ , key , val ) => { const currentVal = Reflect . get ( state , key ) ; if ( currentVal === val ) return true ; const nextState = { ... state , [ key ] : val } ; Reflect . set ( state , key , val ) ; notifyStateChange ( nextState , key , val , currentVal ) ; return true ; } , } ) ; return { state : stateProxy , watchState , onStateChange , onStateValue , untilStateValue , } ; } ; export type State = ReturnType < typeof StateConstructor > ; export default StateConstructor ;