" ============================================================================= " 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 "\" endif else return "\" endif endif endif return ret endfunction let &cpo = s:save_cpo unlet s:save_cpo