1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-03 12:40:05 +08:00
SpaceVim/bundle/calendar.vim/autoload/calendar/view.vim

467 lines
15 KiB
VimL
Raw Normal View History

" =============================================================================
" Filename: autoload/calendar/view.vim
" Author: itchyny
" License: MIT License
" Last Change: 2019/08/07 21:22:19.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#view#new() abort
let self = copy(s:self)
call self.set_view_source(calendar#setting#get('view_source'))
call self.set_calendar_views(calendar#setting#get('views'))
call self.set_index(calendar#setting#get('view'))
call self.set_task_visibility(calendar#setting#get('task'))
return self
endfunction
let s:self = {}
let s:self.index = 0
let s:self.calendar_views = ['year', 'month', 'week', 'day_4', 'day_1', 'clock']
let s:self.index_max = len(s:self.calendar_views) - 1
let s:self.updated = 1
let s:self._help = 0
let s:self._task = 0
let s:self._event = 0
let s:self._help_order = []
let s:self._event_order = []
function! s:self.set_calendar_views(views) dict abort
let views = [ 'year', 'month', 'week', 'weekday', 'day_7', 'day_6', 'day_5', 'day_4', 'day_3', 'day_2', 'day_1', 'day', 'clock', 'event', 'agenda' ]
let calendar_views = filter(a:views, 'index(views, v:val) >= 0')
if len(calendar_views) > 0
let self.calendar_views = calendar_views
let self.index_max = len(self.calendar_views) - 1
endif
return self
endfunction
function! s:self.get_calendar_views() dict abort
return self.calendar_views[self.index]
endfunction
function! s:self.set_index(view) dict abort
let i = index(self.calendar_views, a:view)
if i < 0
if a:view ==# 'day'
let i = index(self.calendar_views, 'day_1')
elseif a:view ==# 'days'
let days = filter(copy(self.calendar_views), 'v:val =~# "^day_[2-6]"')
if len(days)
let i = index(self.calendar_views, days[0])
endif
elseif a:view ==# 'week'
let i = index(self.calendar_views, 'day_7')
endif
endif
let self.index = i < 0 ? 0 : i
let self.updated = 1
return self
endfunction
function! s:self.change_index(diff) dict abort
if calendar#setting#get('cyclic_view')
let m = self.index_max + 1
let self.index = (((self.index + a:diff) % m) + m) % m
else
let self.index = min([max([self.index + a:diff, 0]), self.index_max])
endif
let self.updated = 1
endfunction
function! s:self.event_visible() dict abort
return self._event
endfunction
function! s:self.task_visible() dict abort
return self._task
endfunction
function! s:self.set_task_visibility(_task) dict abort
let self._task = type(a:_task) == type('') ? a:_task ==# '1' : a:_task
endfunction
function! s:self.help_visible() dict abort
return self._help
endfunction
function! s:self.set_view_source(source) dict abort
let self.source = a:source
let self.views = map(deepcopy(self.source), 'calendar#view#{v:val.type}#new(v:val)')
let self.order = range(len(self.source))
return self
endfunction
function! s:self.current_view() dict abort
return self.views[self.current_view_index()]
endfunction
function! s:self.current_view_index() dict abort
let i = len(self.order) - 1
while !self.views[self.order[i]].is_visible()
let i -= 1
endwhile
return self.order[i]
endfunction
function! s:self.view_count() dict abort
let num = 0
for i in range(len(self.order))
let num += self.views[self.order[i]].is_visible()
endfor
return num
endfunction
function! s:self.visible_num() dict abort
let num = 0
for i in range(len(self.views))
if self.views[i].is_visible()
let num += 1
endif
endfor
return num
endfunction
function! s:self.event_view() dict abort
for i in range(len(self.views))
if self.views[i].source.type ==# 'event'
return self.views[i]
endif
endfor
endfunction
function! s:self.get_overlap() dict abort
let height = calendar#util#winheight()
let diffy = max([(height - self.ymax()) / 2, 0])
let o = []
let lw = []
for i in range(height)
call add(o, [])
call add(lw, [])
endfor
let f = 0
if self.visible_num() > 1
for i in range(len(self.order))
let c = self.views[self.order[i]]
if c.is_visible()
let [p, l, h, w] = [c.get_top() + (c.is_absolute() ? 0 : diffy), c.get_left(), c.sizey(), c.sizex()]
let r = range(p, p + h - 1)
for j in r
if j < len(o)
call add(o[j], i)
call add(lw[j], [l, w])
if len(o[j]) <= 1
continue
else
let f = 1
if len(o[j]) == 2
if lw[j][0][0] <= l && lw[j][0][0] + lw[j][0][1] >= l
call insert(o[j], -1)
elseif lw[j][0][0] >= l
if lw[j][0][0] < l + w
call insert(o[j], -1)
else
let o[j] = [o[j][1], o[j][0]]
endif
endif
else
call insert(o[j], -1)
endif
endif
endif
endfor
endif
endfor
endif
return [f, o, diffy]
endfunction
function! s:self.ymax() dict abort
let d = len(self.order)
let ymax = 0
for i in range(d)
let c = self.views[self.order[i]]
if c.is_visible() && !c.is_absolute()
let ymax = max([ymax, c.get_top() + c.sizey()])
endif
endfor
return ymax
endfunction
let [s:height, s:width] = [0, 0]
function! s:self.gather(...) dict abort
let d = len(self.order)
let updated = self.updated || a:0 && a:1
for i in range(d)
let c = self.views[self.order[i]]
call c.set_index(self.calendar_views[self.index])
call c.set_size()
let updated = updated || (c.is_visible() && c.updated()) " Do not break
endfor
if !updated | return 1 | endif
let self.updated = 0
let [height, width] = [calendar#util#winheight(), calendar#util#winwidth()]
if [s:height, s:width] != [height, width]
let [s:height, s:width] = [height, width]
let s:texts = map(range(s:height), 'calendar#text#new(repeat(" ", s:width), 0, v:val, "")')
let s:llen = map(range(s:height), '0')
endif
let texts = deepcopy(s:texts)
let llen = deepcopy(s:llen)
let index = self.current_view_index()
let [f, v, diffy] = self.get_overlap()
for i in range(d)
let c = self.views[self.order[i]]
if !c.is_visible()
continue
endif
call c.set_selected(self.order[i] == index)
let r = c.gather(c.is_absolute() ? 0 : diffy)
for t in r
if 0 <= t.y && t.y < height
if t.t && llen[t.y]
call t.move(llen[t.y], 0)
endif
if f && t.t
call s:split_over(t, texts, v, llen, i, height)
endif
let l = texts[t.y].over(t)
if !t.t | let llen[t.y] = l | endif
endif
endfor
endfor
return texts
endfunction
function! s:split_over(t, texts, v, llen, i, height) abort
let t = a:t
if len(t.syn) && len(t.syn[0]) == 5
let flg = 0
for k in range(len(t.syn))
for j in range(min([t.syn[k][4], a:height - t.y]))
let flg = flg || len(a:v[t.y + j]) > 1 && a:v[t.y + j][0] != a:i
endfor
if flg | break | endif
endfor
if flg
for s in t.split()
if s.y < a:height
call s.move(a:llen[s.y] - a:llen[t.y], 0)
call a:texts[s.y].over(s)
endif
endfor
endif
endif
endfunction
function! s:self.action(action) dict abort
let ret = self.current_view().action(a:action)
if type(ret) == 0 && ret == 0
if a:action ==# 'redraw'
call b:calendar.update_force_redraw()
return 1
elseif a:action ==# 'tab'
if self.view_count() > 1 && !self.current_view().on_top()
let index = self.current_view_index()
let next = index
while !self.views[next].is_visible() || next == index
let next = (next + 1) % len(self.views)
endwhile
let idx = index(self.order, next)
if idx >= 0
call remove(self.order, idx)
let self.order = add(self.order, next)
endif
endif
elseif a:action ==# 'shift_tab'
if self.view_count() > 1 && !self.current_view().on_top()
let index = self.current_view_index()
let next = index
while !self.views[next].is_visible() || next == index
let next = (next - 1 + len(self.views)) % len(self.views)
endwhile
let idx = index(self.order, next)
if idx >= 0
call remove(self.order, idx)
let self.order = add(self.order, next)
endif
endif
elseif a:action ==# 'status'
let select = calendar#day#join_date(b:calendar.day().get_ymd())
let selectmd = calendar#day#join_date(b:calendar.day().get_ymd()[1:])
let today = calendar#day#join_date(calendar#day#today().get_ymd())
let diffnum = b:calendar.day().sub(calendar#day#today())
let diff = diffnum >= 0 ? '+' . diffnum : '' . diffnum
let todaystr = calendar#message#get('today')
let dayof = b:calendar.day().sub(b:calendar.day().year().head_day()) + 1
let yeardays = b:calendar.day().year().last_day().sub(b:calendar.day().year().head_day()) + 1
let daypercent = 100 * dayof / yeardays
let message = printf('%s %s/%s --%d%%-- %s %s %s', select, dayof, yeardays, daypercent, todaystr, today, diff)
let winw = calendar#util#winwidth() - 14
if calendar#string#strdisplaywidth(message) > winw
let message = printf('%s %s/%s --%d%%-- %s %s', select, dayof, yeardays, daypercent, today, diff)
if calendar#string#strdisplaywidth(message) > winw
let message = printf('%s %s/%s %s %s', select, dayof, yeardays, today, diff)
if calendar#string#strdisplaywidth(message) > winw
let message = printf('%s %s/%s', select, dayof, yeardays)
if calendar#string#strdisplaywidth(message) > winw
let message = printf('%s', select)
if calendar#string#strdisplaywidth(message) > winw
let message = printf('%s', selectmd)
endif
endif
endif
endif
endif
call calendar#echo#message(message)
elseif a:action ==# 'today'
call b:calendar.move_day(-b:calendar.day().sub(calendar#day#today()))
call b:calendar.move_second(-b:calendar.time().sub(calendar#time#now()))
elseif a:action ==# 'help'
let self.updated = 1
let ii = -1
for i in range(len(self.order))
if self.views[i].source.type ==# 'help'
let ii = i
endif
endfor
let self._help = !self._help
if ii >= 0 && self._help
let self._help_order = copy(self.order)
let i = index(self.order, ii)
if i >= 0
call remove(self.order, i)
let self.order = add(self.order, ii)
endif
elseif has_key(self, '_help_order')
let self.order = self._help_order
let self._help = 0
endif
elseif a:action ==# 'task'
if self.current_view().on_top() && self.current_view().source.type !=# 'task'
return
endif
let self.updated = 1
let ii = -1
for i in range(len(self.order))
if self.views[i].source.type ==# 'task'
let ii = i
endif
endfor
let self._task = !self._task
if ii >= 0 && self._task
let self._task_order = copy(self.order)
let i = index(self.order, ii)
if i >= 0
let self.order = self.order[i + 1:] + self.order[:i]
endif
elseif has_key(self, '_task_order')
let self.order = self._task_order
let self._task = 0
elseif ii >= 0 && !self._task
let self.order = filter(copy(self.order), 'v:val != ii') + [ii]
endif
elseif a:action ==# 'close_task'
if self._task
call self.action('task')
endif
elseif a:action ==# 'event'
if self.current_view().on_top() && self.current_view().source.type !=# 'event'
return
endif
let self.updated = 1
let ii = -1
for i in range(len(self.order))
if self.views[i].source.type ==# 'event'
let ii = i
endif
endfor
let self._event = !self._event
if ii >= 0 && self._event
let self._event_order = copy(self.order)
let i = index(self.order, ii)
if i >= 0
let self.order = self.order[i + 1:] + self.order[:i]
endif
elseif has_key(self, '_event_order')
let self.order = self._event_order
let self._event = 0
endif
elseif a:action ==# 'close_event'
if self._event
call self.action('event')
endif
elseif a:action ==# 'hide'
try
bunload!
catch
enew!
endtry
return 1
elseif a:action ==# 'exit'
bwipeout!
return 1
elseif a:action ==# 'view_left'
call self.change_index(-v:count1)
elseif a:action ==# 'view_right'
call self.change_index(v:count1)
elseif a:action ==# 'command_enter' && mode() ==# 'c'
if getcmdtype() ==# ':'
let cmd = calendar#util#getcmdline()
let digits = []
if cmd =~# '\v^\s*marks\s*$'
call b:calendar.mark.showmarks()
return calendar#util#update_keys()
elseif cmd =~# '\v^\s*(ma%[rk]\s+|k\s*)[a-z]\s*$'
let mark = matchstr(cmd, '\v[a-z](\s*$)@=')
call b:calendar.mark.set(mark)
return calendar#util#update_keys()
elseif cmd =~# '\v^\s*delm%[arks]!\s*$'
call b:calendar.mark.delmarks()
return calendar#util#update_keys()
elseif cmd =~# '\v^\s*delm%[arks]\s+[a-z]\s*$'
let mark = matchstr(cmd, '\v[a-z](\s*$)@=')
call b:calendar.mark.delmarks(mark)
return calendar#util#update_keys()
elseif cmd =~# '\v^\s*\d+\s*$'
return calendar#util#update_keys()
elseif cmd =~# '\v^\s*\d+\s*/\s*\d+\s*(/\s*\d+\s*)?$'
let digits = map(split(cmd, '/'), 'matchstr(v:val, "\\v\\d+") * 1')
elseif cmd =~# '\v^\s*\d+\s*-\s*\d+\s*(-\s*\d+\s*)?$'
let digits = map(split(cmd, '-'), 'matchstr(v:val, "\\v\\d+") * 1')
elseif cmd =~# '\v^\s*\d+\s*\.\s*\d+\s*(\.\s*\d+\s*)?$'
let digits = map(split(cmd, '\.'), 'matchstr(v:val, "\\v\\d+") * 1')
elseif cmd =~# '\v^\s*\d+\s+\d+\s*(\s+\d+\s*)?$'
let digits = map(split(cmd, '\s\+'), 'matchstr(v:val, "\\v\\d+") * 1')
elseif cmd =~# '\v^\s*\d*\s*(\<\s*)+\d*$'
let c = matchstr(cmd, '\d\+')
let d = len(cmd) - len(substitute(cmd, '<', '', 'g'))
call self.change_index(-max([len(c) ? c + 0 : 1, 1]) * d)
return calendar#util#update_keys()
elseif cmd =~# '\v^\s*\d*\s*(\>\s*)+\d*$'
let c = matchstr(cmd, '\d\+')
let d = len(cmd) - len(substitute(cmd, '>', '', 'g'))
call self.change_index(max([len(c) ? c + 0 : 1, 1]) * d)
return calendar#util#update_keys()
endif
if len(digits)
call b:calendar.set_day(calendar#argument#day(digits, b:calendar.day().get_ymd()))
call b:calendar.set_month()
return calendar#util#update_keys()
else
return "\<CR>"
endif
else
return "\<CR>"
endif
endif
endif
return ret
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo