colabbd/adapters/vim/collab.vim

119 lines
2.7 KiB
VimL

vim9script
# collab.vim - collaborative editing adapter for collabd
# requires: bun, collabd daemon running
var bridge_job: job
var bridge_channel: channel
var connected = false
var room = ""
var suppressing = false
# path to bridge script (adjust as needed)
const bridge_script = expand('<sfile>:p:h') .. '/bridge.ts'
def Send(msg: dict<any>)
if bridge_channel != null
ch_sendraw(bridge_channel, json_encode(msg) .. "\n")
endif
enddef
def OnOutput(ch: channel, msg: string)
if empty(msg)
return
endif
var data: dict<any>
try
data = json_decode(msg)
catch
return
endtry
if data.type == 'connected'
connected = true
echom '[collab] connected to room: ' .. data.room
elseif data.type == 'disconnected'
connected = false
echom '[collab] disconnected'
elseif data.type == 'content'
ApplyRemoteContent(data.text)
elseif data.type == 'peers'
echom '[collab] peers: ' .. data.count
elseif data.type == 'error'
echoerr '[collab] ' .. data.message
endif
enddef
def ApplyRemoteContent(content: string)
if suppressing
return
endif
suppressing = true
var lines = split(content, "\n", true)
var view = winsaveview()
silent! :%delete _
setline(1, lines)
winrestview(view)
suppressing = false
enddef
def SendBuffer()
if !connected || suppressing
return
endif
var lines = getline(1, '$')
var content = join(lines, "\n")
Send({type: 'content', text: content})
enddef
export def Connect(room_name: string)
if bridge_job != null
Disconnect()
endif
room = room_name
bridge_job = job_start(['bun', 'run', bridge_script], {
mode: 'nl',
out_cb: OnOutput,
err_io: 'null'
})
bridge_channel = job_getchannel(bridge_job)
# give it a moment to start
sleep 100m
Send({type: 'connect', room: room_name})
# set up autocmds to send changes
augroup CollabVim
autocmd!
autocmd TextChanged,TextChangedI * call SendBuffer()
augroup END
enddef
export def Disconnect()
if bridge_job != null
Send({type: 'disconnect'})
job_stop(bridge_job)
bridge_job = null
bridge_channel = null
endif
connected = false
room = ""
augroup CollabVim
autocmd!
augroup END
echom '[collab] disconnected'
enddef
export def Status()
if connected
echom '[collab] connected to room: ' .. room
else
echom '[collab] not connected'
endif
enddef
# commands
command! -nargs=1 CollabJoin call Connect(<q-args>)
command! CollabLeave call Disconnect()
command! CollabStatus call Status()