vim: render msg table directly from cli (#238)

* vim: render msg table from cli directly

* doc: update changelog
This commit is contained in:
Clément DOUIN 2021-10-24 23:34:04 +02:00 committed by GitHub
parent e154481c5b
commit 43785b3c1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 106 additions and 79 deletions

View file

@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Change ### Change
- Remove error when empty subject [#229] - Remove error when empty subject [#229]
- Vim plugin does not render anymore the msg by itself, it uses the one available from the CLI [#220]
## [0.5.0] - 2021-10-10 ## [0.5.0] - 2021-10-10

View file

@ -1,34 +1,24 @@
let s:log = function("himalaya#shared#log#info") let s:log = function("himalaya#shared#log#info")
let s:trim = function("himalaya#shared#utils#trim") let s:trim = function("himalaya#shared#utils#trim")
let s:cli = function("himalaya#shared#cli#call") let s:cli = function("himalaya#shared#cli#call")
let s:plain_req = function("himalaya#request#plain")
let s:msg_id = 0 let s:msg_id = 0
let s:draft = "" let s:draft = ""
" Message
function! s:format_msg_for_list(msg)
let flag_new = index(a:msg.flags, "Seen") == -1 ? "✷" : " "
let flag_flagged = index(a:msg.flags, "Flagged") == -1 ? " " : "!"
let flag_replied = index(a:msg.flags, "Answered") == -1 ? " " : "↵"
let a:msg.flags = printf("%s %s %s", flag_new, flag_replied, flag_flagged)
return a:msg
endfunction
function! himalaya#msg#list_with(account, mbox, page, should_throw) function! himalaya#msg#list_with(account, mbox, page, should_throw)
let pos = getpos(".") let pos = getpos(".")
let msgs = s:cli( let msgs = s:plain_req({
\"--account %s --mailbox %s list --page %d", \'cmd': '--account %s --mailbox %s list --max-width %d --page %d',
\[shellescape(a:account), shellescape(a:mbox), a:page], \'args': [shellescape(a:account), shellescape(a:mbox), s:bufwidth(), a:page],
\printf("Fetching %s messages", a:mbox), \'msg': printf("Fetching %s messages", a:mbox),
\a:should_throw, \'should_throw': a:should_throw,
\) \})
let msgs = map(msgs, "s:format_msg_for_list(v:val)")
let buftype = stridx(bufname("%"), "Himalaya messages") == 0 ? "file" : "edit" let buftype = stridx(bufname("%"), "Himalaya messages") == 0 ? "file" : "edit"
execute printf("silent! %s Himalaya messages [%s] [page %d]", buftype, a:mbox, a:page) execute printf("silent! %s Himalaya messages [%s] [page %d]", buftype, a:mbox, a:page)
setlocal modifiable setlocal modifiable
silent execute "%d" silent execute "%d"
call append(0, s:render("list", msgs)) call append(0, split(msgs, '\n'))
silent execute "$d" silent execute "$d"
setlocal filetype=himalaya-msg-list setlocal filetype=himalaya-msg-list
let &modified = 0 let &modified = 0
@ -315,50 +305,25 @@ function! himalaya#msg#attachments()
endtry endtry
endfunction endfunction
" Render utils " Utils
let s:config = { " https://newbedev.com/get-usable-window-width-in-vim-script
\"list": { function! s:bufwidth()
\"columns": ["id", "flags", "subject", "sender", "date"], let width = winwidth(0)
\}, let numberwidth = max([&numberwidth, strlen(line('$'))+1])
\"labels": { let numwidth = (&number || &relativenumber)? numberwidth : 0
\"id": "ID", let foldwidth = &foldcolumn
\"flags": "FLAGS",
\"subject": "SUBJECT",
\"sender": "SENDER",
\"date": "DATE",
\},
\}
function! s:render(type, lines) if &signcolumn == 'yes'
let s:max_widths = s:get_max_widths(a:lines, s:config[a:type].columns) let signwidth = 2
let header = [s:render_line(s:config.labels, s:max_widths, a:type)] elseif &signcolumn == 'auto'
let line = map(copy(a:lines), "s:render_line(v:val, s:max_widths, a:type)") let signs = execute(printf('sign place buffer=%d', bufnr('')))
let signs = split(signs, '\n')
return header + line let signwidth = len(signs)>2? 2: 0
endfunction else
let signwidth = 0
function! s:render_line(line, max_widths, type) endif
return "|" . join(map( return width - numwidth - foldwidth - signwidth
\copy(s:config[a:type].columns),
\"s:render_cell(a:line[v:val], a:max_widths[v:key])",
\), "")
endfunction
function! s:render_cell(cell, max_width)
let cell_width = strdisplaywidth(a:cell[:a:max_width])
return a:cell[:a:max_width] . repeat(" ", a:max_width - cell_width) . " |"
endfunction
function! s:get_max_widths(msgs, columns)
let max_widths = map(copy(a:columns), "strlen(s:config.labels[v:val])")
for msg in a:msgs
let widths = map(copy(a:columns), "has_key(msg, v:val . '_len') ? msg[v:val . '_len'] : strlen(msg[v:val])")
call map(max_widths, "max([widths[v:key], v:val])")
endfor
return max_widths
endfunction endfunction
function! s:get_focused_msg_id() function! s:get_focused_msg_id()
@ -378,9 +343,9 @@ function! s:get_focused_msg_ids(from, to)
endfunction endfunction
function! s:close_open_buffers(name) function! s:close_open_buffers(name)
let l:open_buffers = filter(range(1, bufnr('$')), 'bufexists(v:val)') let open_buffers = filter(range(1, bufnr('$')), 'bufexists(v:val)')
let l:target_buffers = filter(l:open_buffers, 'buffer_name(v:val) =~ a:name') let target_buffers = filter(open_buffers, 'buffer_name(v:val) =~ a:name')
for buffer_to_close in l:target_buffers for buffer_to_close in target_buffers
execute ":bwipeout " . buffer_to_close execute ":bwipeout " . buffer_to_close
endfor endfor
endfunction endfunction

View file

@ -0,0 +1,59 @@
function! himalaya#request#json(opts)
let msg = get(a:, 'opts.msg', '')
let cmd = get(a:, 'opts.cmd', '')
let args = get(a:, 'opts.args', [])
let should_throw = get(a:, 'opts.should_throw', v:false)
call himalaya#shared#log#info(printf('%s…', msg))
let cmd = call('printf', ['himalaya --output json ' . cmd] + args)
let res = system(cmd)
if empty(res)
redraw | call himalaya#shared#log#info(printf('%s [OK]', msg))
else
try
let res = substitute(res, ':null', ':v:null', 'g')
let res = substitute(res, ':true', ':v:true', 'g')
let res = substitute(res, ':false', ':v:false', 'g')
let res = eval(res)
redraw | call himalaya#shared#log#info(printf('%s [OK]', msg))
return res.response
catch
redraw
for line in split(res, '\n')
call himalaya#shared#log#err(line)
endfor
if should_throw
throw ''
endif
endtry
endif
endfunction
function! himalaya#request#plain(opts)
let msg = get(a:opts, 'msg', '')
let cmd = get(a:opts, 'cmd', '')
let args = get(a:opts, 'args', [])
let should_throw = get(a:, 'opts.should_throw', v:false)
call himalaya#shared#log#info(printf('%s…', msg))
let cmd = call('printf', ['himalaya --output plain ' . cmd] + args)
let res = system(cmd)
if empty(res)
redraw | call himalaya#shared#log#info(printf('%s [OK]', msg))
else
try
redraw | call himalaya#shared#log#info(printf('%s [OK]', msg))
return trim(res)
catch
redraw
for line in split(res, '\n')
call himalaya#shared#log#err(line)
endfor
if should_throw
throw ''
endif
endtry
endif
endfunction

View file

@ -2,23 +2,25 @@ if exists("b:current_syntax")
finish finish
endif endif
syntax match hym_sep /|/ syntax match HimalayaSeparator /│/
syntax match hym_uid /^|.\{-}|/ contains=hym_sep syntax match HimalayaHead /.*\%1l/ contains=HimalayaSeparator
syntax match hym_flags /^|.\{-}|.\{-}|/ contains=hym_uid,hym_sep syntax match HimalayaId /^.\{-}│/ contains=HimalayaSeparator
syntax match hym_subject /^|.\{-}|.\{-}|.\{-}|/ contains=hym_uid,hym_flags,hym_sep syntax match HimalayaFlags /^.\{-}│.\{-}│/ contains=HimalayaId,HimalayaSeparator
syntax match hym_sender /^|.\{-}|.\{-}|.\{-}|.\{-}|/ contains=hym_uid,hym_flags,hym_subject,hym_sep syntax match HimalayaSubject /^.\{-}│.\{-}│.\{-}│/ contains=HimalayaId,HimalayaFlags,HimalayaSeparator
syntax match hym_date /^|.\{-}|.\{-}|.\{-}|.\{-}|.\{-}|/ contains=hym_uid,hym_flags,hym_subject,hym_sender,hym_sep syntax match HimalayaSender /^.\{-}│.\{-}│.\{-}│.\{-}│/ contains=HimalayaId,HimalayaFlags,HimalayaSubject,HimalayaSeparator
syntax match hym_head /.*\%1l/ contains=hym_sep syntax match HimalayaDate /^.\{-}│.\{-}│.\{-}│.\{-}│.\{-}/ contains=HimalayaId,HimalayaFlags,HimalayaSubject,HimalayaSender,HimalayaSeparator
syntax match hym_unseen /^|.\{-}|✷.*$/ contains=hym_sep
highlight hym_head term=bold,underline cterm=bold,underline gui=bold,underline " FIXME: Find a way to set the line bold AND to keep the style of each columns.
highlight hym_unseen term=bold cterm=bold gui=bold " syntax match HimalayaUnseen /^.\{-}│✷.*$/ contains=HimalayaSeparator
" highlight HimalayaUnseen term=bold cterm=bold gui=bold
highlight default link hym_sep VertSplit highlight HimalayaHead term=bold,underline cterm=bold,underline gui=bold,underline
highlight default link hym_uid Identifier
highlight default link hym_flags Special highlight default link HimalayaSeparator VertSplit
highlight default link hym_subject String highlight default link HimalayaId Identifier
highlight default link hym_sender Structure highlight default link HimalayaFlags Special
highlight default link hym_date Constant highlight default link HimalayaSubject String
highlight default link HimalayaSender Structure
highlight default link HimalayaDate Constant
let b:current_syntax = "himalaya-msg-list" let b:current_syntax = "himalaya-msg-list"