Skip to content

Commit

Permalink
VS.Vim.Window, VS.Vim.Window.FloatingWindow, VS.Vim.Syntax.Markdown: …
Browse files Browse the repository at this point in the history
…Implement
  • Loading branch information
hrsh7th committed Nov 16, 2020
1 parent 73dfb1c commit 6d81afe
Show file tree
Hide file tree
Showing 5 changed files with 412 additions and 0 deletions.
78 changes: 78 additions & 0 deletions autoload/vital/__vital__/VS/Vim/Syntax/Markdown.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
function! s:apply(text, ...) abort
if !exists('b:___VS_Vim_Syntax_Markdown')
runtime! syntax/markdown.vim
let b:___VS_Vim_Syntax_Markdown = {}
endif

try
for [l:mark, l:filetype] in items(s:_get_filetype_map(a:text, get(a:000, 0, {})))
let l:group = substitute(toupper(l:filetype), '\.', '_', 'g')
if has_key(b:___VS_Vim_Syntax_Markdown, l:group)
continue
endif
let b:___VS_Vim_Syntax_Markdown[l:group] = v:true

unlet b:current_syntax
execute printf('syntax include @%s syntax/%s.vim', l:group, l:filetype)
execute printf('syntax region %s matchgroup=Conceal start=/%s/rs=e matchgroup=Conceal end=/%s/re=s contains=@%s containedin=ALL keepend concealends',
\ l:group,
\ printf('^\s*```\s*%s\s*', l:mark),
\ '\s*```\s*$',
\ l:group
\ )
endfor
catch /.*/
echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint })
endtry
endfunction

"
" _get_filetype_map
"
function! s:_get_filetype_map(text, filetype_map) abort
let l:filetype_map = {}
for l:mark in s:_find_marks(a:text)
let l:filetype_map[l:mark] = s:_get_filetype_from_mark(l:mark, a:filetype_map)
endfor
return l:filetype_map
endfunction

"
" _find_marks
"
function! s:_find_marks(text) abort
let l:marks = {}

" find from buffer contents.
let l:pos = 0
while 1
let l:match = matchlist(a:text, '```\s*\(\w\+\)', l:pos, 1)
if empty(l:match)
break
endif
let l:marks[l:match[1]] = v:true
let l:pos = matchend(a:text, '```\s*\(\w\+\)', l:pos, 1)
endwhile

return keys(l:marks)
endfunction

"
" _get_filetype_from_mark
"
function! s:_get_filetype_from_mark(mark, filetype_map) abort
for l:config in get(g:, 'markdown_fenced_languages', [])
if l:config !~# '='
if l:config ==# a:mark
return a:mark
endif
else
let l:config = split(l:config, '=')
if l:config[1] ==# a:mark
return l:config[0]
endif
endif
endfor
return get(a:filetype_map, a:mark, a:mark)
endfunction

43 changes: 43 additions & 0 deletions autoload/vital/__vital__/VS/Vim/Window.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
let s:Do = { -> {} }

"
" do
"
function! s:do(winid, func) abort
let l:curr_winid = win_getid()
if l:curr_winid == a:winid
call a:func()
return
endif

if exists('*win_execute')
let s:Do = a:func
try
noautocmd keepalt keepjumps call win_execute(a:winid, 'call s:Do()')
catch /.*/
echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint })
endtry
unlet s:Do
return
endif

noautocmd keepalt keepjumps call win_gotoid(a:winid)
try
call a:func()
catch /.*/
echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint })
endtry
noautocmd keepalt keepjumps call win_gotoid(l:curr_winid)
endfunction

"
" screenpos
"
function! s:screenpos(pos) abort
let l:pos = getpos('.')
let l:scroll_x = (l:pos[2] + l:pos[3]) - wincol()
let l:scroll_y = l:pos[1] - winline()
let l:winpos = win_screenpos(win_getid())
return [l:winpos[0] + (a:pos[0] - l:scroll_y) - 2, l:winpos[1] + (a:pos[1] - l:scroll_x) - 2]
endfunction

25 changes: 25 additions & 0 deletions autoload/vital/__vital__/VS/Vim/Window.vimspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
let s:expect = themis#helper('expect')
let s:Window = vital#vital#import('VS.Vim.Window')

Describe vital#__vital__#VS#Vim#Window

Describe #do

It should restore modes
enew!
let l:winid1 = win_getid()
call setline(1, 'foo')
vnew!
let l:winid2 = win_getid()
call setline(1, 'bar')

normal! 1G1|v$
call s:expect(s:Window.do(l:winid1, { -> getline('1') })).to_equal('foo')
call s:expect(mode()).to_equal('v')
quit!
End

End

End

243 changes: 243 additions & 0 deletions autoload/vital/__vital__/VS/Vim/Window/FloatingWindow.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
"
" _vital_loaded
"
function! s:_vital_loaded(V) abort
let s:Window = a:V.import('VS.Vim.Window')
let s:Markdown = a:V.import('VS.Vim.Syntax.Markdown')
endfunction

"
" _vital_depends
"
function! s:_vital_depends() abort
return ['VS.Vim.Window', 'VS.Vim.Syntax.Markdown']
endfunction

let s:id = 0

"
" new
"
function! s:new() abort
return s:FloatingWindow.new()
endfunction

let s:FloatingWindow = {}

"
" new
"
function! s:FloatingWindow.new() abort
let s:id += 1

let l:buf = bufnr(printf('VS.Vim.Window.FloatingWindow-%s', s:id), v:true)
call setbufvar(l:buf, '&buflisted', 0)
call setbufvar(l:buf, '&modeline', 0)
call setbufvar(l:buf, '&buftype', 'nofile')

return extend(deepcopy(s:FloatingWindow), {
\ 'id': s:id,
\ 'buf': l:buf,
\ 'win': v:null,
\ })
endfunction

"
" open
"
" @param {number} args.row
" @param {number} args.col
" @param {string} args.filetype
" @param {string[]} args.contents
" @param {number?} args.maxwidth
" @param {number?} args.minwidth
" @param {number?} args.maxheight
" @param {number?} args.minheight
"
function! s:FloatingWindow.open(args) abort
let l:size = self.get_size(a:args)
let l:style = {
\ 'row': a:args.row,
\ 'col': a:args.col,
\ 'width': l:size.width,
\ 'height': l:size.height,
\ }

if self.is_visible()
call s:_move(self.win, l:style)
else
let self.win = s:_open(self.buf, l:style)
call setwinvar(self.win, '&conceallevel', 3)
endif

call self.set_contents(a:args.filetype, a:args.contents)
endfunction

"
" close
"
function! s:FloatingWindow.close() abort
if self.is_visible()
call s:_close(self.win)
endif
endfunction

"
" enter
"
function! s:FloatingWindow.enter() abort
call s:_enter(self.win)
endfunction

"
" is_visible
"
function! s:FloatingWindow.is_visible() abort
return s:_exists(self.win)
endfunction

"
" get_size
"
function! s:FloatingWindow.get_size(args) abort
let l:maxwidth = get(a:args, 'maxwidth', -1)
let l:minwidth = get(a:args, 'minwidth', -1)
let l:maxheight = get(a:args, 'maxheight', -1)
let l:minheight = get(a:args, 'minheight', -1)

" width
let l:width = 0
for l:content in a:args.contents
let l:width = max([l:width, strdisplaywidth(l:content)])
endfor
let l:width = l:minwidth == -1 ? l:width : max([l:minwidth, l:width])
let l:width = l:maxwidth == -1 ? l:width : min([l:maxwidth, l:width])

" height
let l:height = len(a:args.contents)
for l:content in a:args.contents
let l:wrap = float2nr(ceil(strdisplaywidth(l:content) / str2float('' . l:width)))
if l:wrap > 1
let l:height += l:wrap - 1
endif
endfor
let l:height = l:minheight == -1 ? l:height : max([l:minheight, l:height])
let l:height = l:maxheight == -1 ? l:height : min([l:maxheight, l:height])

return {
\ 'width': max([1, l:width]),
\ 'height': max([1, l:height]),
\ }
endfunction

"
" set_contents
"
function! s:FloatingWindow.set_contents(filetype, contents) abort
call deletebufline(self.buf, '^', '$')
call setbufline(self.buf, 1, a:contents)

if a:filetype ==# 'markdown'
call s:Window.do(self.win, { -> s:Markdown.apply(join(a:contents, "\n")) })
else
call setbufvar(self.buf, '&filetype', a:filetype)
endif
endfunction

"
" open
"
if has('nvim')
function! s:_open(buf, style) abort
return nvim_open_win(a:buf, v:false, s:_style(a:style))
endfunction
else
function! s:_open(buf, style) abort
return popup_create(a:buf, s:_style(a:style))
endfunction
endif

"
" close
"
if has('nvim')
function! s:_close(win) abort
call nvim_win_close(a:win, v:true)
endfunction
else
function! s:_close(win) abort
call popup_hide(a:win)
endfunction
endif

"
" move
"
if has('nvim')
function! s:_move(win, style) abort
call nvim_win_set_config(a:win, s:_style(a:style))
endfunction
else
function! s:_move(win, style) abort
call popup_move(a:win, s:_style(a:style))
endfunction
endif

"
" enter
"
if has('nvim')
function! s:_enter(win) abort
call win_gotoid(a:win)
endfunction
else
function! s:_enter(win) abort
" not supported.
endfunction
endif

"
" exists
"
if has('nvim')
function! s:_exists(win) abort
return type(a:win) == type(0) && nvim_win_is_valid(a:win) && nvim_win_get_number(a:win) != -1
endfunction
else
function! s:_exists(win) abort
return type(a:win) == type(0) && win_id2win(a:win) != -1
endfunction
endif

"
" style
"
if has('nvim')
function! s:_style(style) abort
return {
\ 'relative': 'editor',
\ 'width': a:style.width,
\ 'height': a:style.height,
\ 'row': a:style.row,
\ 'col': a:style.col,
\ 'focusable': v:true,
\ 'style': 'minimal',
\ }
endfunction
else
function! s:_style(style) abort
return {
\ 'line': a:style.row + 1,
\ 'col': a:style.col + 1,
\ 'pos': 'topleft',
\ 'moved': [0, 0, 0],
\ 'scrollbar': 0,
\ 'maxwidth': a:style.width,
\ 'maxheight': a:style.height,
\ 'minwidth': a:style.width,
\ 'minheight': a:style.height,
\ 'tabpage': 0,
\ }
endfunction
endif

Loading

0 comments on commit 6d81afe

Please sign in to comment.