Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 154 additions & 5 deletions autoload/medieval.vim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const s:fences = [#{start: '\([`~]\{3,}\)\s*\%({\s*\.\?\)\?\(\a\+\)\?', end: '\1', lang: 2,}, #{start: '\$\$'}]
let s:opts = ['name', 'target', 'require', 'tangle']
let s:opts = ['name', 'target', 'require', 'tangle', 'session']
let s:optspat = '\(' . join(s:opts, '\|') . '\):\s*\([0-9A-Za-z_+.$#&/-]\+\)'
let s:optionfmt = '<!-- %s -->'
let s:optionpat = '^\s*<!--\s*'
Expand Down Expand Up @@ -265,6 +265,150 @@ function! medieval#evalrange(line1, line2, target) abort
call winrestview(view)
endfunction

function! s:session_read(key, lines) abort

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow the conventions of the repo:

Suggested change
function! s:session_read(key, lines) abort
function! s:sessionread(key, lines) abort

if !has_key(s:active_sessions, a:key)
return
endif

let session = s:active_sessions[a:key]

if type(a:lines) == v:t_list
let data = a:lines
if !empty(data) && data[-1] ==# ''
let data = data[:-2]
let session.buffer += data
endif
else
let session.buffer += [a:lines]
endif


if !empty(session.token) && match(session.buffer, session.token) >= 0
let output = session.buffer
let token = session.token
let context = session.context

let session.token = ''
let session.context = {}

let token_idx = match(output, token)
if token_idx > 0
let output = output[:token_idx - 1]
elseif token_idx == 0
let output = []
endif

call context.cb(output)
endif
endfunction

function! s:vim_cb(channel, msg) abort
for [k, s] in items(s:active_sessions)
if s.id == a:channel
call s:session_read(k, a:msg)
break
endif
endfor
endfunction

function! s:nvim_cb(job_id, data, event) abort
for [k, s] in items(s:active_sessions)
if s.id == a:job_id
call s:session_read(k, a:data)
break
endif
endfor
endfunction
Comment on lines +305 to +321

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two functions are identical, let's consolidate (name it s:sessiondata since it's only used for sessions)


function! s:nvim_session_exit_cb(job_id, exit_code, event) abort
for [k, s] in items(s:active_sessions)
if s.id == a:job_id
call remove(s:active_sessions, k)
break
endif
endfor
endfunction

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you have an exit callback for Nvim but not Vim?

Let's rename this s:sessionexit and re-use it for both Nvim and Vim (use a lambda if needed, look at the existing pattern in s:jobstart as a reference)


function! s:eval_session(lang, session_name, block, cb) abort

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function! s:eval_session(lang, session_name, block, cb) abort
function! s:evalsession(lang, session_name, block, cb) abort

if !exists('s:active_sessions')
let s:active_sessions = {}
endif

if !exists('s:session_buffers')
let s:session_buffers = {}
endif

let key = a:lang . ':' . a:session_name
let eof_token = '__MEDIEVAL_SESSION_EOF__' . reltimestr(reltime())
let running = has_key(s:active_sessions, key)

if running
let session = s:active_sessions[key]
if !has('nvim')
let running = job_status(session.job) ==# 'run'
endif
endif

if !running
let cmd = [a:lang]
if a:lang ==# 'python' || a:lang ==# 'python3'
let cmd += ['-i', '-q']
endif
Comment on lines +354 to +356

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're not going to hard code languages in here (we have to do it for cmd to work around Windows wonkiness and even then I tried to avoid it). Let's find a way to make this work that is language agnostic and doesn't require special cases.


if has('nvim')
let id = jobstart(cmd, {
\ 'on_stdout': function('s:nvim_cb'),
\ 'on_stderr': function('s:nvim_cb'),
\ 'on_exit': function('s:nvim_session_exit_cb'),
\ 'stdout_buffered': 0,
\ 'stderr_buffered': 0,
\ })
if id <= 0
return s:error('Failed to start job for ' . a:lang)
endif
let s:active_sessions[key] = {
\ 'id': id,
\ 'buffer': [],
\ 'token': '',
\ 'context': {},
\ }
else
let job = job_start(l:cmd, {
\ 'out_cb': function('s:vim_cb'),
\ 'err_cb': function('s:vim_cb'),
\ 'mode': 'nl',
\ })
let s:active_sessions[key] = {
\ 'id': job_getchannel(job),
\ 'job': job,
\ 'buffer': [],
\ 'token': '',
\ 'context': {},
\ }
endif
endif
Comment on lines +358 to +389

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use exists('*jobstart') instead of has('nvim') (look at s:jobstart as a reference) and extract this entire block into a function s:sessionstart.


let session = s:active_sessions[key]
let session.buffer = []
let session.token = eof_token
let session.context = {'cb': a:cb}

let new_block = copy(a:block)
if a:lang =~# 'python'
let new_block += ['print("' . eof_token . '")']
else
let new_block += ['echo "' . eof_token . '"']
endif
Comment on lines +397 to +401

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar comment to earlier, we should not hard code language support here. And even then this is wrong, using echo for the else branch won't work.


if has('nvim')
call chansend(session.id, new_block + [''])
else
for line in new_block
call ch_sendraw(session.id, line . "\n")
endfor
endif
Comment on lines +403 to +409

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow the pattern of s:jobstart: make a function s:chansend that encapsulates the platform differences between Nvim and Vim and use exists('*chansend') instead of has('nvim')

endfunction

function! medieval#eval(...) abort
if !exists('g:medieval_langs')
call s:error('g:medieval_langs is unset')
Expand Down Expand Up @@ -378,11 +522,16 @@ function! medieval#eval(...) abort
if has_key(opts, 'setup')
call opts.setup(context, block)
endif
call writefile(block, fname)
if lang == "cmd"
call s:jobstart([fname], function('s:callback', [context]))

if has_key(opts, 'session')
call s:eval_session(lang, opts.session, block, function('s:callback', [context]))
else
call s:jobstart([lang, fname], function('s:callback', [context]))
call writefile(block, fname)
if lang == "cmd"
call s:jobstart([fname], function('s:callback', [context]))
else
call s:jobstart([lang, fname], function('s:callback', [context]))
endif
endif
call winrestview(view)
endfunction