import { app } from 'electron' ; import { asColor , merge , getPipeName } from '../../common/utils' ; import Worker , { Worker as WorkerType } from '../workers/messaging/worker' ; import { Color , Highlight } from '../neovim/types' ; import { ChildProcess , spawn } from 'child_process' ; import InstanceApi from '../core/instance-api' ; import * as neovim from 'neovim' ; import { BrowserWindow } from 'electron' ; import { resolve } from 'path' ; type RedrawFn = ( m : any [ ] ) => void ; type ExitFn = ( code : number ) => void ; interface NvimInstance { proc : ChildProcess ; attached : boolean ; pipeName : string ; } const nvimOptions = { ext_popupmenu : true , ext_tabline : true , ext_wildmenu : true , ext_cmdline : true , ext_messages : true , ext_multigrid : true , ext_hlstate : true , } ; const clientSize = { width : 80 , height : 80 , } ; let onExitFn = ( ) => { } ; const spawnNvimInstance = ( pipeName , useWsl , nvimBinary ? ) => { const runtimeDir = app . isPackaged ? resolve ( __dirname , '..' , '..' , 'runtime' ) : resolve ( __dirname , '..' , '..' , '..' , 'runtime' ) ; const args = [ '--cmd' , `let $PATH .= ':${ runtimeDir }/${ process . platform }' | let &runtimepath .= ',${ runtimeDir }'` , '--cmd' , `com! -nargs=+ -range -complete=custom,UivonimCmdCompletions Uivonim call Uivonim(<f-args>)` , '--cmd' , `source ${ runtimeDir }/uivonim.vim` , '--embed' , '--listen' , pipeName , ] ; return useWsl ? spawn ( 'wsl' , [ nvimBinary ?? 'nvim' , ... args ] ) : spawn ( nvimBinary ?? 'nvim' , args ) ; } ; const attachNvim = ( nvimInstance ) => { const nvimApi = neovim . attach ( { proc : nvimInstance . proc } ) ; if ( ! nvimInstance ) { console . warn ( 'Tried attaching nvim before initializing it, and/or setup api' ) ; } if ( nvimInstance . attached ) { console . warn ( 'Already attached nvim' ) ; } nvimApi . uiAttach ( clientSize . width , clientSize . height , nvimOptions ) ; nvimApi . command ( `highlight ${ Highlight . Undercurl } gui=undercurl` ) ; nvimApi . command ( `highlight ${ Highlight . Underline } gui=underline` ) ; nvimInstance . attached = true ; return nvimApi ; } ; const createAndSetupNvimInstance = ( useWsl , nvimBinary ? ) => { const pipeName = getPipeName ( 'veonim-instance' ) ; const proc = spawnNvimInstance ( pipeName , useWsl , nvimBinary ) ; const nvimInstance = { proc , pipeName , attached : false } ; proc . on ( 'error' , ( e ) => console . error ( `nvim err ${ e }` ) ) ; proc . stdout ! . on ( 'error' , ( e ) => console . error ( `nvim stdout err ${ JSON . stringify ( e ) }` ) ) ; proc . stdin ! . on ( 'error' , ( e ) => console . error ( `nvim stdin err ${ JSON . stringify ( e ) }` ) ) ; proc . on ( 'exit' , ( c ) => onExitFn ( c ) ) ; const nvimApi = attachNvim ( nvimInstance ) ; if ( ! nvimApi ) throw new Error ( "Couldn't attach to neovim instance; this shouldn't happen." ) ; const { attached } = nvimInstance ; if ( attached ) nvimApi . uiTryResize ( clientSize . width , clientSize . height ) ; return { instance : nvimInstance , api : nvimApi } ; } ; const createNvim = async ( useWsl , nvimBinaryPath ? , dir ? ) => { const { instance : nvimInstance , api : nvimApi } = createAndSetupNvimInstance ( useWsl , nvimBinaryPath ) ; const { pipeName : path } = nvimInstance ! ; const workerInstance = Worker ( 'instance' , { workerData : { nvimPath : path } , } ) ; dir && ( await nvimApi ! . command ( `cd ${ dir }` ) ) ; return { workerInstance , nvimInstance , nvimApi } ; } ; const masterControlInternal = ( winRef , { nvimInstance , nvimApi , workerInstance , } ) => { const instanceApi = InstanceApi ( workerInstance , winRef ) ; return { nvimInstance , instanceApi , onExit : ( fn ) => ( onExitFn = fn ) , onRedraw : ( fn ) => nvimApi . on ( 'notification' , ( method , args ) => { method === 'redraw' ? fn ( args ) : { } ; } ) , input : ( keys ) => nvimApi . input ( keys ) , getMode : async ( ) => { const mode = await nvimApi . mode ; console . log ( `getmode: ${ mode }` ) ; return mode as { mode : string ; blocking : boolean ; } ; } , resizeGrid : ( grid , width , height ) => { nvimApi . uiTryResizeGrid ( grid , width , height ) ; } , resize : ( width , height ) => { merge ( clientSize , { width , height } ) ; nvimApi . uiTryResize ( width , height ) ; } , getColor : async ( id ) => { const { foreground , background } = ( await nvimApi . getHighlightById ( id , true ) ) as Color ; return { fg : asColor ( foreground ) , bg : asColor ( background ) , } ; } , } ; } ; const MasterControl = async ( winRef , opts ) => { return masterControlInternal ( winRef , await createNvim ( opts . useWsl , opts . nvimBinaryPath , opts . dir ) ) ; } ; export default MasterControl ; export type MasterControl = ReturnType < typeof masterControlInternal > ;