-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
VS.Vim.Window, VS.Vim.Window.FloatingWindow, VS.Vim.Syntax.Markdown: …
…Implement
- Loading branch information
Showing
5 changed files
with
412 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
243
autoload/vital/__vital__/VS/Vim/Window/FloatingWindow.vim
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
Oops, something went wrong.