1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-23 07:00:04 +08:00

chore(calendar): use bundle calendar.vim

This commit is contained in:
wsdjeg 2022-05-28 15:29:51 +08:00
parent 6ed481a5c4
commit 09dac0d30a
178 changed files with 12036 additions and 1 deletions

View File

@ -22,7 +22,7 @@ function! SpaceVim#layers#tools#plugins() abort
call add(plugins, ['wsdjeg/vim-cheat', { 'on_cmd' : 'Cheat'}])
call add(plugins, ['wsdjeg/Mysql.vim', { 'on_cmd' : 'SQLGetConnection'}])
call add(plugins, ['wsdjeg/SourceCounter.vim', { 'on_cmd' : 'SourceCounter'}])
call add(plugins, ['itchyny/calendar.vim', { 'on_cmd' : 'Calendar'}])
call add(plugins, [g:_spacevim_root_dir . 'bundle/calendar.vim', { 'on_cmd' : 'Calendar'}])
call add(plugins, ['junegunn/limelight.vim', { 'on_cmd' : 'Limelight'}])
call add(plugins, ['junegunn/goyo.vim', { 'on_cmd' : 'Goyo', 'loadconf' : 1}])
call add(plugins, [g:_spacevim_root_dir . 'bundle/vim-bookmarks',

1
bundle/README.md vendored
View File

@ -32,3 +32,4 @@ In `bundle/` directory, there are two kinds of plugins: forked plugins without c
- [vim-assembly@2b1994a](https://github.com/wsdjeg/vim-assembly/tree/2b1994a5d23c90651754b4c75750100f63074d8b)
- [vim-autohotkey@6bf1e71](https://github.com/wsdjeg/vim-autohotkey/tree/6bf1e718c73cad22caad3ecd8c4db96db05b37f7)
- [vim-cmake-syntax@bcc3a97a](https://github.com/pboettch/vim-cmake-syntax/tree/bcc3a97ab934f03e112becd4ce79286793152b47)
- [itchyny/calendar.vim@896360bfd](https://github.com/itchyny/calendar.vim/tree/896360bfd9d5347b2726dd247df2d2cbdb8cf1d6)

View File

@ -0,0 +1,36 @@
name: CI
on:
push:
branches:
- master
pull_request:
jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
vim:
- v8.2.0000
- v8.1.0000
- v8.0.0000
- v7.4
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Checkout vim-themis
uses: actions/checkout@v3
with:
repository: thinca/vim-themis
path: vim-themis
- name: Setup Vim
uses: rhysd/action-setup-vim@v1
id: vim
with:
version: ${{ matrix.vim }}
- name: Test
env:
THEMIS_VIM: ${{ steps.vim.outputs.executable }}
run: ./vim-themis/bin/themis --reporter spec

1
bundle/calendar.vim/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/doc/tags

21
bundle/calendar.vim/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-2022 itchyny
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

129
bundle/calendar.vim/README.md vendored Normal file
View File

@ -0,0 +1,129 @@
# A calendar application for Vim
### Vim meets a next generation application
![calendar.vim](https://raw.githubusercontent.com/wiki/itchyny/calendar.vim/image/image.png)
Press E key to view the event list, and T key to view the task list.
Also, press ? key to view a quick help.
![calendar.vim](https://raw.githubusercontent.com/wiki/itchyny/calendar.vim/image/views.png)
## Basic Usage
:Calendar
![calendar.vim](https://raw.githubusercontent.com/wiki/itchyny/calendar.vim/image/image0.png)
:Calendar 2000 1 1
![calendar.vim](https://raw.githubusercontent.com/wiki/itchyny/calendar.vim/image/image1.png)
:Calendar -view=year
![calendar.vim](https://raw.githubusercontent.com/wiki/itchyny/calendar.vim/image/image2.png)
:Calendar -view=year -split=vertical -width=27
![calendar.vim](https://raw.githubusercontent.com/wiki/itchyny/calendar.vim/image/image3.png)
:Calendar -view=year -split=horizontal -position=below -height=12
![calendar.vim](https://raw.githubusercontent.com/wiki/itchyny/calendar.vim/image/image4.png)
:Calendar -first_day=monday
![calendar.vim](https://raw.githubusercontent.com/wiki/itchyny/calendar.vim/image/image5.png)
:Calendar -view=clock
![calendar.vim](https://raw.githubusercontent.com/wiki/itchyny/calendar.vim/image/image6.png)
You can switch between views with < and > keys.
![calendar.vim](https://raw.githubusercontent.com/wiki/itchyny/calendar.vim/image/frame.png)
If you have a trouble like the above screenshot, add the following configuration to your vimrc.
```vim
let g:calendar_frame = 'default'
```
## Concept
This is a calendar which is ...
### Comfortable
The key mappings are designed to match the default mappings of Vim.
### Powerful
The application can be connected to Google Calendar and used in your life.
### Elegant
The appearance is carefully designed, dropping any unnecessary information.
### Interesting
You can choose the calendar in Julian calendar or in Gregorian calendar.
### Useful
To conclude, very useful.
## Author
itchyny (https://github.com/itchyny)
## License
This software is released under the MIT License, see LICENSE.
## Installation
Install with your favorite plugin manager.
## Google Calendar and Google Task
In order to view and edit calendars on Google Calendar, or task on Google Task,
add the following configurations to your vimrc file.
```vim
let g:calendar_google_calendar = 1
let g:calendar_google_task = 1
```
It requires `wget` or `curl`.
### Important notice
The default client key is not provided anymore and you will get the **Authorization Error**.
You have to create your own Google API key and use for authentication with the following steps.
- Create a new project in [GCP](https://cloud.google.com/) and go to [Google APIs](https://console.developers.google.com/apis/).
- Click `ENABLE APIS AND SERVICES` add `Google Calendar API` and `Tasks API`.
- Go to [Google APIs](https://console.developers.google.com/apis/) and click `OAuth consent screen` from the sidebar.
- Choose `External` (Available to any user with a Google Account.) and click `CREATE`.
- Input your favorite name to `Application name`. In the `Scopes for Google APIs` section, click `Add scope` and add `Google Calendar API ../auth/calendar` and `Task API ../auth/tasks`.
- Click `Save` (DO NOT `Submit for verification`).
- Go to the `Credentials` page from the sidebar.
- Create a new API key and restrict key to the two APIs (`Google Calendar API`, `Tasks API`).
- You have the api key.
- Create a new `OAuth client ID`. Select `Desktop application` for the application type.
- You have the client id and client secret.
- Open your terminal and save the credentials.
- `mkdir -p ~/.cache/calendar.vim/ && touch ~/.cache/calendar.vim/credentials.vim`
- `chmod 700 ~/.cache/calendar.vim && chmod 600 ~/.cache/calendar.vim/credentials.vim`
- `vi ~/.cache/calendar.vim/credentials.vim`
- Add the following three lines and save it. Please be sure to keep this file securely.
```vim
let g:calendar_google_api_key = '...'
let g:calendar_google_client_id = '....apps.googleusercontent.com'
let g:calendar_google_client_secret = '...'
```
- Add `source ~/.cache/calendar.vim/credentials.vim` to your .vimrc.
- Restart Vim and open calendar.vim. You will get the unverified message but click `Advanced` and `Go to your-app (unsafe)`.
- Approve against some confirms (maybe three clicks) and you will get the login code. Copy and paste it into the prompt of calendar.vim. Now you'll be authenticated to your application..
## Terms of Use
Under no circumstances we are liable for any damages (including but not limited to damages for loss of business, loss of profits, interruption or the like) arising from use of this software.
This software deals with your events and tasks.
We are not liable for any circumstances; leakage of trade secrets due to the cache files of this software, loss of important events and tasks due to any kind of bugs and absence from important meetings due to any kind of failures of this software.
This software downloads your events from Google Calendar, and your tasks from Google Task.
DO NOT use this software with important events and tasks.
This software downloads your events or tasks to the cache directory.
Please be careful with the cache directory; DO NOT share the directory with any cloud storage softwares.
This software also uploads your events and tasks to Google APIs.
While it uses https, but DO NOT use this software for confidential matters.
This software NEVER uploads your events and tasks to any other server except Google's.
However, if `wget` or `curl` command are replaced with malicious softwares, your events or tasks can be uploaded to other sites.
Please use the official softwares for the commands.

View File

@ -0,0 +1,64 @@
" =============================================================================
" Filename: autoload/calendar.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:35:29.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Creates a new buffer and start calendar.
function! calendar#new(args) abort
" Argument parsing
let [isnewbuffer, command, variables, args] = calendar#argument#parse(a:args)
" Open a new buffer.
try | silent execute command | catch | return | endtry
" Clear the previous syntaxes.
silent! call b:calendar.clear()
" Store the options which are given as the argument.
let b:_calendar = variables
" Start calendar.
let b:calendar = calendar#controller#new()
" Set time
call b:calendar.set_time(calendar#time#now())
" Set day and update the buffer.
call b:calendar.go(calendar#argument#day(args, calendar#day#today().get_ymd()))
" Save b:calendar and b:_calendar.
call calendar#save()
endfunction
let s:calendar = {}
let s:_calendar = {}
" Save b:calendar and b:_calendar.
function! calendar#save() abort
let nr = bufnr('')
if has_key(b:, 'calendar')
let s:calendar[nr] = b:calendar
endif
if has_key(b:, '_calendar')
let s:_calendar[nr] = b:_calendar
endif
endfunction
" Revive b:calendar and b:_calendar.
function! calendar#revive() abort
let nr = bufnr('')
if !has_key(b:, 'calendar') && has_key(s:calendar, nr)
let b:calendar = get(s:calendar, nr, {})
endif
if !has_key(b:, '_calendar') && has_key(s:_calendar, nr)
let b:_calendar = get(s:_calendar, nr, {})
endif
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,320 @@
" =============================================================================
" Filename: autoload/calendar/argument.vim
" Author: itchyny
" License: MIT License
" Last Change: 2020/10/17 01:28:50.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Deal with argument for the :Calendar command.
let s:calendars = filter(map(split(globpath(&rtp, 'autoload/calendar/day/**.vim'), '\n'),
\ "substitute(v:val, '.*/\\|.vim', '', 'g')"),
\ 'v:val !~# "^\(default\\|gregorian\\|julian\)$"')
let s:all_value_options = {
\ '-year': [],
\ '-month': [],
\ '-day': [],
\ '-locale': [ 'default', 'en', 'ja' ],
\ '-calendar': ['default', 'gregorian', 'julian'] + sort(s:calendars),
\ '-calendar_candidates': [],
\ '-first_day': [ 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday' ],
\ '-time_zone': map(range(-12, 12), 'printf("%+03d00", v:val)'),
\ '-date_endian': [ 'little', 'big', 'middle' ],
\ '-date_separator': [ '/', '-', '.', '" "' ],
\ '-event_start_time_minwidth': [],
\ '-cache_directory': [],
\ '-updatetime': [],
\ '-view': [ 'year', 'month', 'week', 'days', 'day', 'clock', 'event', 'agenda' ],
\ '-frame': [ 'default', 'unicode', 'space', 'unicode_bold', 'unicode_round', 'unicode_double' ],
\ '-position': [ 'here', 'below', 'tab', 'left', 'right', 'topleft', 'topright' ],
\ '-split': [ 'horizontal', 'vertical' ],
\ '-width': [],
\ '-height': [],
\ '-message_prefix': [],
\ '-task_width': [],
\ }
let s:all_novalue_options = [
\ '-google_calendar',
\ '-google_task',
\ '-date_month_name',
\ '-date_full_month_name',
\ '-cyclic_view',
\ '-task',
\ '-event_start_time',
\ '-skip_event_delete_confirm',
\ '-skip_task_delete_confirm',
\ '-skip_task_clear_completed_confirm',
\ '-yank_deleting',
\ '-task_delete',
\ '-clock_12hour',
\ '-week_number',
\ '-debug' ]
let s:value_options = deepcopy(s:all_value_options)
let s:novalue_options = deepcopy(s:all_novalue_options)
if has_key(g:, 'calendar_hide_options') && type(g:calendar_hide_options) == type([]) && len(g:calendar_hide_options)
for s:k in g:calendar_hide_options
if has_key(s:value_options, s:k)
unlet s:value_options[s:k]
elseif has_key(s:value_options, '-' . s:k)
unlet s:value_options['-' . s:k]
endif
let s:i = index(s:novalue_options, s:k)
if s:i >= 0
call remove(s:novalue_options, s:i)
endif
let s:i = index(s:novalue_options, '-' . s:k)
if s:i >= 0
call remove(s:novalue_options, s:i)
endif
endfor
unlet s:k s:i
endif
let s:options = copy(s:novalue_options) + map(keys(deepcopy(s:value_options)), 'v:val . "="')
let s:all_options = copy(s:novalue_options)
for [s:key, s:val] in items(deepcopy(s:value_options))
call extend(s:all_options, map(s:val, 's:key . "=" . v:val'))
endfor
unlet s:key s:val
" Completion function.
function! calendar#argument#complete(arglead, cmdline, cursorpos) abort
try
for key in keys(s:value_options)
if a:cmdline =~# key
if a:cmdline =~# key . '=$'
return &wildmode =~# 'full'
\ ? map(copy(s:value_options[key]), 'key . "=" . v:val')
\ : copy(s:value_options[key])
elseif a:cmdline =~# key . '=\S\+$'
let lead = '^' . substitute(a:cmdline, '.*=', '', '')
let list = filter(copy(s:value_options[key]), 'v:val =~# lead')
if !len(list)
let lead = substitute(a:cmdline, '.*=', '', '')
let list = filter(copy(s:value_options[key]), 'v:val =~# lead')
endif
let arglead = substitute(a:arglead, '=.*', '=', '')
return map(list, 'arglead . v:val')
endif
endif
endfor
let s:options = copy(s:novalue_options)
\ + map(keys(deepcopy(s:value_options)), &wildmode =~# 'full' ? 'v:val' : 'v:val . "="')
let options = copy(s:options)
if a:arglead != ''
let options = sort(filter(copy(s:options), 'stridx(v:val, a:arglead) != -1'))
if len(options) == 0
let arglead = substitute(a:arglead, '^-\+', '', '')
let options = sort(filter(copy(s:options), 'stridx(v:val, arglead) != -1'))
if len(options) == 0
try
let argl = substitute(a:arglead, '\(.\)', '.*\1', 'g') . '.*'
let options = sort(filter(copy(s:options), 'v:val =~? argl'))
if len(options) == 0
let options = sort(filter(copy(s:all_options), 'stridx(v:val, arglead) != -1'))
endif
catch
let options = copy(s:options)
endtry
endif
endif
endif
return sort(filter(options, 'stridx(a:cmdline, v:val) == -1'))
catch
return s:options
endtry
endfunction
" Splitting the argument.
" This function deals with quotes.
function! calendar#argument#split(args) abort
let args = ['']
let quoteflag = 0
let quote = ''
for i in range(len(a:args))
if a:args[i] ==# ' '
if quoteflag
let args[-1] .= a:args[i]
elseif args[-1] !=# ''
call add(args, '')
endif
elseif (a:args[i] ==# '"' || a:args[i] ==# "'")
if quoteflag && quote ==# a:args[i]
call add(args, '')
let quoteflag = 0
let quote = ''
elseif quoteflag
let args[-1] .= a:args[i]
else
let quoteflag = 1
let quote = a:args[i]
endif
else
let args[-1] .= a:args[i]
endif
endfor
return filter(args, 'len(v:val)')
endfunction
" Option parsing and constructing the buffer-creating command.
function! calendar#argument#parse(args) abort
let args = calendar#argument#split(a:args)
let isnewbuffer = bufname('%') != '' || &l:filetype != '' || &modified
let name = " `='" . calendar#argument#buffername('calendar') . "'`"
let command = 'tabnew'
let commandprefix = ''
let addname = 1
let ymd = []
let variables = {}
let [width, height] = [-1, -1]
let [arg_year, flg_year] = [0, 0]
let [arg_month, flg_month] = [0, 0]
let [arg_day, flg_day] = [0, 0]
let flg_ymd = 0
for arg in args
let novalue = 0
if arg !~# '=' && arg !~# '^\d\+$'
if index(s:novalue_options, substitute(arg, '!$', '', '')) >= 0
let bang = arg =~# '!$'
let arg = substitute(arg, '!$', '', '') . '=' . (!bang)
let novalue = 1
else
let pat = substitute(substitute(arg, '^-', '=', ''), '!$', '', '') . '$'
let opts = filter(copy(s:all_options), 'v:val =~# pat')
let bang = arg =~# '!$' ? '!' : ''
if len(opts) == 1
let arg = opts[0] . bang
elseif len(opts) > 1
call calendar#echo#error(calendar#message#get('multiple_argument') . ': ' . join(opts, ', '))
endif
endif
endif
if arg =~# '='
let optvar = split(arg, '=')
if len(optvar) == 2 && (has_key(s:value_options, optvar[0]) || novalue)
let option = substitute(optvar[0], '^-\+', '', '')
if option ==# 'position'
if optvar[1] ==# 'here'
let command = 'try | edit' . name . ' | catch | tabnew' . name . ' | endtry'
let addname = 0
elseif optvar[1] ==# 'here!'
let command = 'edit!'
elseif optvar[1] ==# 'below'
if command ==# 'tabnew'
let command = 'new'
endif
let commandprefix = 'below '
let isnewbuffer = 1
elseif index(['left', 'right', 'topleft', 'topright'], optvar[1]) >= 0
if command ==# 'tabnew'
let command = 'vnew'
endif
let commandprefix = optvar[1] ==# 'left' ? 'leftabove '
\ : optvar[1] ==# 'right' ? 'rightbelow '
\ : optvar[1] ==# 'topleft' ? 'topleft '
\ : optvar[1] ==# 'topright' ? 'botright '
\ : ''
let isnewbuffer = 1
elseif optvar[1] ==# 'tab'
let command = 'tabnew'
let isnewbuffer = 1
endif
elseif option ==# 'split'
if optvar[1] ==# 'horizontal'
let command = 'new'
let isnewbuffer = 1
elseif optvar[1] ==# 'vertical'
let command = 'vnew'
let isnewbuffer = 1
endif
elseif option ==# 'width'
let width = optvar[1] + 0
elseif option ==# 'height'
let height = optvar[1] + 0
elseif option ==# 'year'
let [arg_year, flg_year, flg_ymd] = [optvar[1], 1, 1]
elseif option ==# 'month'
let [arg_month, flg_month, flg_ymd] = [optvar[1], 1, 1]
elseif option ==# 'day'
let [arg_day, flg_day, flg_ymd] = [optvar[1], 1, 1]
endif
let variables[option] = optvar[1]
endif
elseif arg =~# '^\d\+$'
call add(ymd, arg)
endif
endfor
if command ==# 'new' && height > 0
let command = height . ' ' . command
elseif command ==# 'vnew' && width > 0
let command = width . ' ' . command
endif
let cmd1 = 'keepalt '. commandprefix . command . (addname ? name : '')
let cmd2 = 'keepalt edit' . name
let command = 'if isnewbuffer | ' . cmd1 . ' | else | ' . cmd2 . '| endif'
if flg_ymd
let ymd = [arg_year, arg_month, arg_day, flg_year, flg_month, flg_day]
endif
return [isnewbuffer, command, variables, ymd]
endfunction
" :Calendar [year month day]
" The order is properly dealt with based on the endian setting.
function! calendar#argument#day(day, default) abort
let [y, m, d] = a:default
let l = len(a:day)
let endian = calendar#setting#get('date_endian')
if l == 1
let day0 = a:day[0] * 1
if 0 < day0 && day0 < 13
let [m, d] = [day0, 1]
else
let [y, m, d] = [day0, 1, 1]
endif
elseif l == 2
let [day0, day1] = [a:day[0] * 1, a:day[1] * 1]
if 0 < day0 && day0 < 13 && 0 < day1 && day1 < 32 && (endian ==# 'big' || endian ==# 'middle')
let [m, d] = [day0, day1]
elseif 0 < day0 && day0 < 32 && 0 < day1 && day1 < 13 && (endian ==# 'little')
let [m, d] = [day1, day0]
elseif 0 < day1 && day1 < 13 && endian ==# 'big'
let [y, m, d] = [day0, day1, 1]
elseif 0 < day0 && day0 < 13 && (endian ==# 'middle' || endian ==# 'little')
let [y, m, d] = [day1, day0, 1]
endif
elseif l == 3
if endian ==# 'big'
let [y, m, d] = [a:day[0] * 1, a:day[1] * 1, a:day[2] * 1]
elseif endian ==# 'middle'
let [m, d, y] = [a:day[0] * 1, a:day[1] * 1, a:day[2] * 1]
else
let [d, m, y] = [a:day[0] * 1, a:day[1] * 1, a:day[2] * 1]
endif
elseif l == 6
if a:day[3] | let y = a:day[0] | endif
if a:day[4] | let m = a:day[1] | endif
if a:day[5] | let d = a:day[2] | endif
endif
return calendar#day#new(y, m, d)
endfunction
" Decision of the buffer name.
function! calendar#argument#buffername(name) abort
let buflist = []
for i in range(tabpagenr('$'))
call extend(buflist, tabpagebuflist(i + 1))
endfor
let matcher = 'bufname(v:val) =~# ("\\[" . a:name . "\\( \\d\\+\\)\\?\\]") && index(buflist, v:val) >= 0'
let substituter = 'substitute(bufname(v:val), ".*\\(\\d\\+\\).*", "\\1", "") + 0'
let bufs = map(filter(range(1, bufnr('$')), matcher), substituter)
let i = 0
while index(bufs, i) >= 0
let i += 1
endwhile
return '[' . a:name . (len(bufs) && i ? ' ' . i : '') . ']'
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,122 @@
" =============================================================================
" Filename: autoload/calendar/async.vim
" Author: itchyny
" License: MIT License
" Last Change: 2016/11/27 09:07:11.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:use_timer = has('timers') && (v:version >= 800 || has('nvim'))
" Register a command to be executed asyncronously. Commands are executed using
" - timers if available
" - CursorHold recursion otherwise
" Optional argument: Allow duplication of commands.
function! calendar#async#new(command, ...) abort
if !exists('b:calendar_async')
let b:calendar_async = []
endif
if len(b:calendar_async) == 0
if s:use_timer
call timer_start(200, 'calendar#async#call')
execute 'augroup CalendarAsync' . bufnr('')
autocmd!
autocmd BufEnter,WinEnter <buffer> call calendar#async#call()
augroup END
else
execute 'augroup CalendarAsync' . bufnr('')
autocmd!
autocmd CursorHold <buffer> call calendar#async#call()
autocmd BufEnter <buffer> call calendar#async#set_updatetime()
autocmd BufLeave <buffer> call calendar#async#restore_updatetime()
call calendar#async#set_updatetime()
augroup END
endif
endif
let i = 0
for [c, num, dup] in b:calendar_async
if c ==# a:command
let i += 1
if i > 2 * (a:0 && a:1) || !a:0
return
endif
endif
endfor
call add(b:calendar_async, [a:command, 0, a:0 && a:1])
endfunction
" Set updatetime for the calendar buffer.
function! calendar#async#set_updatetime() abort
if !has_key(b:, 'calendar_set_updatetime') || !b:calendar_set_updatetime
let s:updatetime = &updatetime
let &updatetime = calendar#setting#get('updatetime')
endif
let b:calendar_set_updatetime = 1
endfunction
" Restore updatetime.
function! calendar#async#restore_updatetime() abort
if has_key(s:, 'updatetime')
let &updatetime = s:updatetime
endif
let b:calendar_set_updatetime = 0
endfunction
" Execute the registered commands.
" Ignore the timer argument (optional for CursorHold recursion).
function! calendar#async#call(...) abort
if !exists('b:calendar_async')
return
endif
if !s:use_timer && exists('b:calendar_async_reltime') && has('reltime')
let time = split(split(reltimestr(reltime(b:calendar_async_reltime)))[0], '\.')
if time[0] ==# '0' && len(time[1]) && time[1][0] ==# '0'
silent call feedkeys(mode() ==# 'i' ? "\<C-g>\<ESC>" : "g\<ESC>" . (v:count ? v:count : ''), 'n')
return
endif
endif
let del = []
let done = {}
let cnt = 0
let len = len(b:calendar_async)
for i in range(len)
let expression = b:calendar_async[i][0]
if has_key(done, expression)
call add(del, i)
continue
endif
if cnt > 1 && !b:calendar_async[i][2]
continue
endif
let done[expression] = 1
let cnt += 1
let ret = eval(expression)
let b:calendar_async[i][1] += 1
if !ret || b:calendar_async[i][1] > 100
call add(del, i)
endif
endfor
for i in reverse(del)
call remove(b:calendar_async, i)
endfor
if !s:use_timer && has('reltime')
let b:calendar_async_reltime = reltime()
endif
if len(b:calendar_async)
if s:use_timer
call timer_start(200, 'calendar#async#call')
else
silent call feedkeys(mode() ==# 'i' ? "\<C-g>\<ESC>" : "g\<ESC>" . (v:count ? v:count : ''), 'n')
endif
else
execute 'autocmd! CalendarAsync' . bufnr('')
if !s:use_timer
call calendar#async#restore_updatetime()
endif
endif
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,98 @@
" =============================================================================
" Filename: autoload/calendar/autocmd.vim
" Author: itchyny
" License: MIT License
" Last Change: 2016/09/20 22:09:40.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Autocmd commands.
function! calendar#autocmd#new() abort
if &l:filetype ==# 'calendar'
return
endif
augroup CalendarAutoUpdate
autocmd!
" Update a visible calendar buffer.
autocmd BufEnter,BufWritePost,VimResized *
\ silent! call s:update_visible(expand('<abuf>'), 0)
autocmd ColorScheme *
\ silent! call s:update_visible(expand('<abuf>'), 1)
augroup END
augroup CalendarBuffer
" When colorscheme is changed, all the calendar syntax groups will be gone.
" So set the filetype forcibly and load the syntax file again.
autocmd ColorScheme <buffer>
\ silent! call calendar#setlocal#filetype_force() |
\ silent! call calendar#color#refresh_syntax()
" On entering the buffer, update the calendar.
autocmd BufEnter,WinEnter,ColorScheme <buffer>
\ silent! call calendar#revive() |
\ silent! call b:calendar.update()
" On entering the buffer, fire CursorHold to update the clock.
autocmd BufEnter,WinEnter <buffer>
\ silent! doautocmd CursorHold
" On resizing the Vim window, check the window size and update if it is changed.
autocmd VimResized,CursorHold <buffer>
\ silent! call b:calendar.update_if_resized()
" When the cursor is moved, update the cursor appropriately.
" In mapping.vim, 'gg' is mapped to '<Plug>(calendar_first_line)' on default.
" However, if we press 'g' and 'g' slowly, '<Plug>(calendar_first_line)' will
" not be triggered. Pressing 'g' and '$' slowly also causes the same situation.
" To avoid this, check the cursor position on CursorMoved and move the cursor
" to the proper position.
autocmd CursorMoved <buffer>
\ silent! call b:calendar.cursor_moved()
augroup END
endfunction
" Search the calendar buffer and updates.
function! s:update_visible(bufnr, is_colorscheme) abort
try
let nr = -1
let newnr = str2nr(a:bufnr)
if bufname(newnr) ==# '[Command Line]'
return
endif
for buf in tabpagebuflist()
if type(getbufvar(buf, 'calendar')) == type({}) && buf != newnr
let nr = buf
break
endif
endfor
if nr == -1 | return | endif
let winnr = bufwinnr(nr)
let newbuf = bufwinnr(str2nr(a:bufnr))
let currentbuf = bufwinnr(bufnr('%'))
noautocmd execute winnr 'wincmd w'
if a:is_colorscheme
silent! call calendar#setlocal#filetype_force()
silent! call calendar#color#refresh_syntax()
endif
silent! call b:calendar.update_force()
if winnr != newbuf && newbuf != -1
call cursor(1, 1)
noautocmd execute newbuf 'wincmd w'
elseif winnr != currentbuf && currentbuf != -1
call cursor(1, 1)
noautocmd execute currentbuf 'wincmd w'
endif
catch
endtry
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,236 @@
" =============================================================================
" Filename: autoload/calendar/cache.vim
" Author: itchyny
" License: MIT License
" Last Change: 2020/11/20 00:09:42.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Cache object.
function! calendar#cache#new(...) abort
let self = copy(s:self)
let self.subpath = a:0 ? a:1 : ''
let self.subpath .= len(self.subpath) && self.subpath[len(self.subpath) - 1] !~ '^[/\\]$' ? '/' : ''
call s:setfperm_dir(self.dir())
return self
endfunction
function! calendar#cache#clear() abort
for path in s:clearpath
call calendar#util#rmdir(path, 'rf')
endfor
endfunction
let s:clearpath = []
augroup CalendarCache
autocmd!
autocmd VimLeavePre * call calendar#cache#clear()
augroup END
let s:self = {}
function! s:self.new(...) dict abort
return calendar#cache#new(self.subpath . (a:0 ? self.escape(a:1) : ''))
endfunction
function! s:self.escape(key) dict abort
return substitute(a:key, '[^a-zA-Z0-9_.-]', '\=printf("%%%02X",char2nr(submatch(0)))', 'g')
endfunction
if has('win32')
function! s:self.dir() dict abort
return substitute(substitute(s:expand_homedir(calendar#setting#get('cache_directory')), '[/\\]$', '', '') . '/' . self.subpath, '/', '\', 'g')
endfunction
else
function! s:self.dir() dict abort
return substitute(s:expand_homedir(calendar#setting#get('cache_directory')), '[/\\]$', '', '') . '/' . self.subpath
endfunction
endif
function! s:expand_homedir(path) abort
if a:path !~# '^[~]/'
return a:path
endif
return expand('~') . a:path[1:]
endfunction
function! s:self.path(key) dict abort
return self.dir() . self.escape(a:key)
endfunction
function! s:self.rmdir_on_exit() dict abort
call add(s:clearpath, self.dir())
endfunction
function! s:self.check_dir(...) dict abort
let dir = self.dir()
if !get(a:000, 0)
return !isdirectory(dir)
endif
if !isdirectory(dir)
try
if exists('*mkdir')
call mkdir(dir, 'p')
else
call calendar#util#system('mkdir -p ' . shellescape(dir))
endif
call s:setfperm(dir)
catch
endtry
endif
if !isdirectory(dir)
call calendar#echo#error(calendar#message#get('mkdir_fail') . ': ' . dir)
return 1
endif
endfunction
function! s:self.save(key, val) dict abort
if self.check_dir(1)
return 1
endif
let path = self.path(a:key)
if filereadable(path) && !filewritable(path)
call calendar#echo#error(calendar#message#get('cache_file_unwritable') . ': ' . path)
return 1
endif
try
call writefile(calendar#cache#string(a:val), path)
call s:setfperm_file(path)
catch
call calendar#echo#error(calendar#message#get('cache_write_fail') . ': ' . path)
return 1
endtry
endfunction
function! s:self.get(key) dict abort
if self.check_dir()
return 1
endif
let path = self.path(a:key)
if filereadable(path)
call s:setfperm_file(path)
let result = readfile(path)
try
if len(result)
if exists('*js_decode') && has('patch-8.0.0216')
return js_decode(len(result) > 1 ? join(result, '') : result[0])
endif
sandbox return eval(join(result, ''))
else
return 1
endif
catch
return 1
endtry
else
return 1
endif
endfunction
function! s:self.get_raw(key) dict abort
if self.check_dir()
return 1
endif
let path = self.path(a:key)
if filereadable(path)
call s:setfperm_file(path)
return readfile(path)
else
return 1
endif
endfunction
function! s:self.delete(key) dict abort
if self.check_dir()
return 1
endif
let path = self.path(a:key)
return delete(path)
endfunction
function! s:self.clear() dict abort
call calendar#util#rmdir(self.dir(), 'rf')
endfunction
if exists('*json_encode')
function! calendar#cache#string(v) abort
return [json_encode(a:v)]
endfunction
else
" string() with making newlines and indents properly.
function! calendar#cache#string(v, ...) abort
let r = []
let f = 1
let s = a:0 ? a:1 : ''
if type(a:v) == type([])
call add(r, '[ ')
let s .= ' '
for i in range(len(a:v))
call add(r, s . string(a:v[i]) . ',')
endfor
if r[-1][len(r[-1]) - 1] ==# ','
let r[-1] = r[-1][:-2]
endif
call add(r, ' ]')
elseif type(a:v) == type({})
call add(r, '{ ')
let s .= ' '
for k in keys(a:v)
if type(a:v[k]) == type({}) || type(a:v[k]) == type([]) && len(a:v[k]) > 2
let result = calendar#cache#string(a:v[k], s . repeat(' ', len(string(k)) + 2))
let result[-1] .= ','
call add(r, s . string(k) . ': ' . result[0])
call remove(result, 0)
call extend(r, result)
else
call add(r, s . string(k) . ': ' . string(a:v[k]) . ',')
endif
endfor
if r[-1][len(r[-1]) - 1] ==# ','
let r[-1] = r[-1][:-2]
endif
call add(r, ' }')
else
call add(r, s . string(a:v))
let f = 0
endif
if f
if len(r[1]) > len(s) + 1
let r[1] = r[1][len(s):]
endif
let r[0] .= r[1]
call remove(r, 1)
if len(r) > 1
let r[-2] .= r[-1]
call remove(r, -1)
endif
endif
return r
endfunction
endif
if exists('*getfperm') && exists('*setfperm')
function! s:setfperm_dir(dir) abort
let expected = 'rwx------'
if getfperm(a:dir) !=# expected
call setfperm(a:dir, expected)
endif
endfunction
function! s:setfperm_file(path) abort
let expected = 'rw-------'
if getfperm(a:path) !=# expected
call setfperm(a:path, expected)
endif
endfunction
else
function! s:setfperm_dir(dir) abort
endfunction
function! s:setfperm_file(path) abort
endfunction
endif
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,58 @@
" =============================================================================
" Filename: autoload/calendar/cipher.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:25:35.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Caesar cipher functions.
" This DOES NOT encrypt a message into a code difficult to revive the
" original message. This module is used for the client id and api key of
" the default google client in setting.vim, because I don't want to save
" the keys in raw strings, which can be extracted easily.
" Reference: http://en.wikipedia.org/wiki/Caesar_cipher
function! calendar#cipher#cipher(val, num) abort
if type(a:val) == type('')
return s:cipher(a:val, a:num)
elseif type(a:val) == type(0)
return s:cipher(a:val . '', a:num)
elseif type(a:val) == type([])
return map(a:val, 'calendar#cipher#cipher(v:val, a:num)')
elseif type(a:val) == type({})
let ret = {}
for key in keys(a:val)
let ret[key] = calendar#cipher#cipher(a:val[key], a:num)
endfor
return ret
endif
endfunction
function! calendar#cipher#decipher(val, num) abort
return calendar#cipher#cipher(a:val, - a:num)
endfunction
function! s:cipher(str, num) abort
let ret = ''
let r = range(len(a:str))
for i in r
let nr = char2nr(a:str[i])
if 32 <= nr && nr < 127
let nr = nr + a:num - 32
while nr < 0
let nr += 127 - 32
endwhile
let nr = nr % (127 - 32) + 32
let ret .= nr2char(nr)
else
return ''
endif
endfor
return ret
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,490 @@
" =============================================================================
" Filename: autoload/calendar/color.vim
" Author: itchyny
" License: MIT License
" Last Change: 2019/07/30 22:37:29.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Color utility
let s:is_gui = has('gui_running') || (has('termguicolors') && &termguicolors)
let s:is_cterm = !s:is_gui
let s:is_win32cui = has('win32') && !s:is_gui
let s:term = s:is_gui ? 'gui' : 'cterm'
let s:is_dark = -1
let s:colors_name = ''
let s:background = ''
" &background is not useful on non-GUI environment when colorscheme executes :highlight Normal ctermbg=23X.
" ref: syntax.c /set_option_value
function! calendar#color#is_dark() abort
if s:is_dark >= 0 && s:colors_name ==# get(g:, 'colors_name', '') && s:background ==# &background
return s:is_dark
endif
let s:colors_name = get(g:, 'colors_name', '')
let s:background = &background
if s:is_gui
let s:is_dark = &background ==# 'dark'
return s:is_dark
endif
let bg_color = synIDattr(synIDtrans(hlID('Normal')), 'bg', s:term)
if bg_color !=# ''
let [r, g, b] = calendar#color#nr_rgb(bg_color)
let s:is_dark = r + g + b < 7 || 232 <= bg_color && bg_color <= 243
return s:is_dark
endif
let fg_color = synIDattr(synIDtrans(hlID('Normal')), 'fg', s:term)
if fg_color !=# ''
let [r, g, b] = calendar#color#nr_rgb(fg_color)
let s:is_dark = r + g + b > 8 || 244 <= fg_color
return s:is_dark
endif
let bg_color = synIDattr(synIDtrans(hlID('Normal')), 'bg', 'gui')
if bg_color =~# '^#......$'
let s:is_dark = s:is_dark_color(bg_color)
return s:is_dark
endif
let fg_color = synIDattr(synIDtrans(hlID('Normal')), 'fg', 'gui')
if fg_color =~# '^#......$'
let s:is_dark = s:is_light_color(fg_color)
return s:is_dark
endif
let s:is_dark = &background ==# 'dark'
return s:is_dark
endfunction
function! calendar#color#new_syntax(id, fg, bg) abort
if has_key(b:, 'calendar')
if !has_key(b:calendar, 'syntaxnames')
let b:calendar.syntaxnames = []
endif
let syntaxnames = b:calendar.syntaxnames
if !has_key(b:calendar, 'syntax')
let b:calendar.syntax = {}
endif
let b:calendar.syntax[a:id] = [a:id, a:fg, a:bg]
else
let syntaxnames = []
endif
let name = s:shorten(substitute(a:id, '[^a-zA-Z0-9]', '', 'g'))
if len(name) && len(a:fg) && len(a:bg)
if index(syntaxnames, name) >= 0
return name
endif
let flg = 0
let is_dark = calendar#color#is_dark()
if is_dark && s:is_dark_color(a:fg) || !is_dark && s:is_light_color(a:fg)
let flg = 1
let [fg, bg] = [a:bg, '']
else
let [fg, bg] = [a:fg, a:bg]
endif
let cuifg = calendar#color#convert(fg)
let cuibg = calendar#color#convert(bg)
if flg
let _bg = bg
let _cuibg = cuibg
else
let _bg = calendar#color#whiten(bg)
let _cuibg = calendar#color#convert(_bg)
endif
if cuifg >= 0
if index(syntaxnames, name) < 0
call add(syntaxnames, name)
endif
if _cuibg >= 0
exec 'highlight Calendar' . name . ' ctermfg=' . cuifg . ' ctermbg=' . _cuibg . ' guifg=' . fg . ' guibg=' . _bg
else
exec 'highlight Calendar' . name . ' ctermfg=' . cuifg . ' guifg=' . fg
endif
let select_bg = s:select_color()
if type(select_bg) == type('') || select_bg >= 0
let nameselect = name . 'Select'
if index(syntaxnames, nameselect) < 0
call add(syntaxnames, nameselect)
endif
if s:is_gui
exec 'highlight Calendar' . nameselect . ' guifg=' . fg . ' guibg=' . (flg ? select_bg : bg)
else
exec 'highlight Calendar' . nameselect . ' ctermfg=' . cuifg . ' ctermbg=' . (flg ? select_bg : cuibg)
endif
endif
endif
return name
endif
return ''
endfunction
function! calendar#color#refresh_syntax() abort
if !has_key(b:, 'calendar') || !has_key(b:calendar, 'syntaxnames') || !has_key(b:calendar, 'syntax')
return
endif
let b:calendar.syntaxnames = []
for [id, fg, bg] in values(b:calendar.syntax)
call calendar#color#new_syntax(id, fg, bg)
endfor
endfunction
function! calendar#color#convert(rgb) abort
let rgb = map(matchlist(a:rgb, '#\(..\)\(..\)\(..\)')[1:3], '0 + ("0x".v:val)')
if len(rgb) == 0
return -1
endif
if rgb[0] == 0xc0 && rgb[1] == 0xc0 && rgb[2] == 0xc0
return 7
elseif rgb[0] == 0x80 && rgb[1] == 0x80 && rgb[2] == 0x80
return 8
elseif s:is_win32cui
if rgb[0] > 127 && rgb[1] > 127 && rgb[2] > 127
let min = 0
for r in rgb
let min = min([min, r])
endfor
let rgb[index(rgb, min)] -= 127
endif
let newrgb = [rgb[0] > 0xa0 ? 4 : 0, rgb[1] > 0xa0 ? 2 : 0, rgb[2] > 0xa0 ? 1 : 0]
return newrgb[0] + newrgb[1] + newrgb[2] + (rgb[0] > 196 || rgb[1] > 196 || rgb[2] > 196) * 8
elseif (rgb[0] == 0x80 || rgb[0] == 0x00) && (rgb[1] == 0x80 || rgb[1] == 0x00) && (rgb[2] == 0x80 || rgb[2] == 0x00)
return (rgb[0] / 0x80) + (rgb[1] / 0x80) * 2 + (rgb[1] / 0x80) * 4
elseif (rgb[0]-rgb[1] >= 0 ? rgb[0]-rgb[1] : -(rgb[0]-rgb[1])) < 3
\ && (rgb[1]-rgb[2] >= 0 ? rgb[1]-rgb[2] : -(rgb[1]-rgb[2])) < 3
\ && (rgb[2]-rgb[0] >= 0 ? rgb[2]-rgb[0] : -(rgb[2]-rgb[0])) < 3
return s:black((rgb[0] + rgb[1] + rgb[2]) / 3)
else
return 16 + ((s:nr(rgb[0]) * 6) + s:nr(rgb[1])) * 6 + s:nr(rgb[2])
endif
endfunction
function! calendar#color#whiten(rgb) abort
let rgb = map(matchlist(a:rgb, '#\(..\)\(..\)\(..\)')[1:3], '0 + ("0x".v:val)')
if len(rgb) == 0
return -1
endif
return printf('#%02x%02x%02x', min([rgb[0] + 0x36, 0xff]), min([rgb[1] + 0x36, 0xff]), min([rgb[2] + 0x36, 0xff]))
endfunction
function! s:black(x) abort
if a:x < 0x04
return 16
elseif a:x > 0xf4
return 231
elseif index([0x00, 0x5f, 0x87, 0xaf, 0xdf, 0xff], a:x) >= 0
let l = a:x / 0x30
return ((l * 6) + l) * 6 + l + 16
else
return 232 + (a:x < 8 ? 0 : a:x < 0x60 ? (a:x-8)/10 : a:x < 0x76 ? (a:x-0x60)/6+9 : (a:x-8)/10)
endif
endfunction
function! s:nr(x) abort
return a:x < 0x2f ? 0 : a:x < 0x73 ? 1 : a:x < 0x9b ? 2 : a:x < 0xc7 ? 3 : a:x < 0xef ? 4 : 5
endfunction
function! s:is_dark_color(rgb) abort
let rgb = map(matchlist(a:rgb, '#\(..\)\(..\)\(..\)')[1:3], '0 + ("0x".v:val)')
return len(rgb) == 3 && rgb[0] < 0x2f && rgb[1] < 0x2f && rgb[2] < 0x2f
endfunction
function! s:is_light_color(rgb) abort
let rgb = map(matchlist(a:rgb, '#\(..\)\(..\)\(..\)')[1:3], '0 + ("0x".v:val)')
return len(rgb) == 3 && rgb[0] > 0xd0 && rgb[1] > 0xd0 && rgb[2] > 0xd0
endfunction
function! calendar#color#gui_color() abort
if has_key(s:, '_gui_color') | return s:_gui_color | endif
let s:_gui_color = {
\ 'black' : '#000000',
\ 'white' : '#ffffff',
\
\ 'darkestgreen' : '#005f00',
\ 'darkgreen' : '#008700',
\ 'mediumgreen' : '#5faf00',
\ 'brightgreen' : '#afdf00',
\
\ 'darkestcyan' : '#005f5f',
\ 'mediumcyan' : '#87dfff',
\
\ 'darkestblue' : '#005f87',
\ 'darkblue' : '#0087af',
\
\ 'darkestred' : '#5f0000',
\ 'darkred' : '#870000',
\ 'mediumred' : '#af0000',
\ 'brightred' : '#df0000',
\ 'brightestred' : '#ff0000',
\
\ 'darkestpurple' : '#5f00af',
\ 'mediumpurple' : '#875fdf',
\ 'brightpurple' : '#dfdfff',
\
\ 'brightorange' : '#ff8700',
\ 'brightestorange': '#ffaf00',
\
\ 'gray0' : '#121212',
\ 'gray1' : '#262626',
\ 'gray2' : '#303030',
\ 'gray3' : '#4e4e4e',
\ 'gray4' : '#585858',
\ 'gray5' : '#606060',
\ 'gray6' : '#808080',
\ 'gray7' : '#8a8a8a',
\ 'gray8' : '#9e9e9e',
\ 'gray9' : '#bcbcbc',
\ 'gray10' : '#d0d0d0',
\
\ 'yellow' : '#b58900',
\ 'orange' : '#cb4b16',
\ 'red' : '#dc322f',
\ 'magenta' : '#d33682',
\ 'violet' : '#6c71c4',
\ 'blue' : '#268bd2',
\ 'cyan' : '#2aa198',
\ 'green' : '#859900',
\ }
return s:_gui_color
endfunction
function! calendar#color#to_256color(nr, fg) abort
if a:nr == 0 || a:nr == 16
return 232
elseif a:nr == 15 || a:nr == 231
return 255
elseif a:nr < 16
if a:fg
return calendar#color#is_dark() ? 255 : 232
else
return calendar#color#is_dark() ? 232 : 255
endif
else
return a:nr
endif
endfunction
function! calendar#color#fg_color(syntax_name) abort
let color = synIDattr(synIDtrans(hlID(a:syntax_name)), 'fg', s:term)
return s:is_gui ? color : calendar#color#to_256color((len(color) == 0 ? -1 : color) + 0, 1)
endfunction
function! calendar#color#bg_color(syntax_name) abort
let color = synIDattr(synIDtrans(hlID(a:syntax_name)), 'bg', s:term)
return s:is_gui ? color : calendar#color#to_256color((len(color) == 0 ? -1 : color) + 0, 0)
endfunction
function! calendar#color#normal_fg_color() abort
if s:is_win32cui
if calendar#color#is_dark()
return 15
else
return 0
endif
endif
let fg_color = calendar#color#fg_color('Normal')
if s:is_cterm && type(fg_color) == type(0) && fg_color < 0
if calendar#color#is_dark()
return 255
else
return 232
endif
endif
return fg_color
endfunction
function! calendar#color#normal_bg_color() abort
if s:is_win32cui
if calendar#color#is_dark()
return 0
else
return 15
endif
endif
let bg_color = calendar#color#bg_color('Normal')
if s:is_cterm && type(bg_color) == type(0) && bg_color < 0
if calendar#color#is_dark()
return 232
else
return 255
endif
endif
return bg_color
endfunction
function! calendar#color#comment_fg_color() abort
if s:is_win32cui
return 7
endif
let fg_color = calendar#color#fg_color('Comment')
if s:is_cterm && type(fg_color) == type(0) && fg_color < 0
if calendar#color#is_dark()
return 244
else
return 243
endif
endif
return fg_color
endfunction
function! calendar#color#comment_bg_color() abort
if s:is_win32cui
if calendar#color#is_dark()
return 0
else
return 15
endif
endif
let bg_color = calendar#color#bg_color('Comment')
if s:is_cterm && type(bg_color) == type(0) && bg_color < 0
if calendar#color#is_dark()
return 232
else
return 255
endif
endif
return bg_color
endfunction
function! calendar#color#nr_rgb(nr) abort
let x = a:nr * 1
if x < 8
let [b, rg] = [x / 4, x % 4]
let [g, r] = [rg / 2, rg % 2]
return [r * 3, g * 3, b * 3]
elseif x == 8
return [4, 4, 4]
elseif x < 16
let y = x - 8
let [b, rg] = [y / 4, y % 4]
let [g, r] = [rg / 2, rg % 2]
return [r * 5, g * 5, b * 5]
elseif x < 232
let y = x - 16
let [rg, b] = [y / 6, y % 6]
let [r, g] = [rg / 6, rg % 6]
return [r, g, b]
else
let k = (x - 232) * 5 / 23
return [k, k, k]
endif
endfunction
if s:is_win32cui
function! calendar#color#gen_color(fg, bg, weightfg, weightbg) abort
return a:weightfg > a:weightbg ? a:fg : a:bg
endfunction
elseif s:is_cterm
function! calendar#color#gen_color(fg, bg, weightfg, weightbg) abort
let fg = a:fg < 0 ? (s:is_dark ? 255 : 232) : a:fg
let bg = a:bg < 0 ? (s:is_dark ? 232 : 255) : a:bg
let fg_rgb = calendar#color#nr_rgb(fg)
let bg_rgb = calendar#color#nr_rgb(bg)
if fg > 231 && bg > 231
let color = (fg * a:weightfg + bg * a:weightbg) / (a:weightfg + a:weightbg)
elseif fg < 16 || bg < 16
let color = a:weightfg > a:weightbg ? fg : bg
else
let color_rgb = map([0, 1, 2], '(fg_rgb[v:val] * a:weightfg + bg_rgb[v:val] * a:weightbg) / (a:weightfg + a:weightbg)')
let color = ((color_rgb[0] * 6 + color_rgb[1]) * 6 + color_rgb[2]) + 16
endif
return color
endfunction
function! calendar#color#select_rgb(color, rgb, weight) abort
let c = calendar#color#nr_rgb(a:color < 0 ? (s:is_dark ? 255 : 232) : a:color)
let cc = max([(c[0] + c[1] + c[2]) / 3, 5])
let colors = [cc / a:weight, cc / a:weight, cc / a:weight]
let colors[a:rgb] = cc
let color = ((colors[0] * 6 + colors[1]) * 6 + colors[2]) + 16
return color
endfunction
else
function! calendar#color#gen_color(fg, bg, weightfg, weightbg) abort
let fg_rgb = map(matchlist(a:fg[0] == '#' ? a:fg : get(calendar#color#gui_color(), a:fg, ''), '#\(..\)\(..\)\(..\)')[1:3], '("0x".v:val) + 0')
let bg_rgb = map(matchlist(a:bg[0] == '#' ? a:bg : get(calendar#color#gui_color(), a:bg, ''), '#\(..\)\(..\)\(..\)')[1:3], '("0x".v:val) + 0')
if len(fg_rgb) != 3 | let fg_rgb = s:is_dark ? [0xe4, 0xe4, 0xe4] : [0x12, 0x12, 0x12] | endif
if len(bg_rgb) != 3 | let bg_rgb = s:is_dark ? [0x12, 0x12, 0x12] : [0xe4, 0xe4, 0xe4] | endif
let color_rgb = map(map([0, 1, 2], '(fg_rgb[v:val] * a:weightfg + bg_rgb[v:val] * a:weightbg) / (a:weightfg + a:weightbg)'), 'v:val < 0 ? 0 : v:val > 0xff ? 0xff : v:val')
let color = printf('0x%02x%02x%02x', color_rgb[0], color_rgb[1], color_rgb[2]) + 0
if color < 0 || 0xffffff < color | let color = s:is_dark ? 0x3a3a3a : 0xbcbcbc | endif
return printf('#%06x', color)
endfunction
function! calendar#color#select_rgb(color, rgb) abort
let c = map(matchlist(a:color[0] == '#' ? a:color : get(calendar#color#gui_color(), a:color, ''), '#\(..\)\(..\)\(..\)')[1:3], '("0x".v:val) + 0')
if len(c) != 3 | let c = s:is_dark ? [0xe4, 0xe4, 0xe4] : [0x12, 0x12, 0x12] | endif
let cc = max([(c[0] + c[1] + c[2]) / 3, 0x6f])
let color = printf('0x%02x%02x%02x', a:rgb % 2 ? cc : cc / 9, (a:rgb / 2) % 2 ? cc : cc / 9, (a:rgb / 4) % 2 ? cc : cc / 9) + 0
if color < 0 || 0xffffff < color | let color = s:is_dark ? 0x3a3a3a : 0xbcbcbc | endif
return printf('#%06x', color)
endfunction
endif
function! calendar#color#colors() abort
return [
\ '#16a765',
\ '#4986e7',
\ '#fad165',
\ '#b99aff',
\ '#f83a22',
\ '#9fe1e7',
\ '#ffad46',
\ '#9a9cff',
\ '#f691b2',
\ '#9fe1e7',
\ '#92e1c0',
\ '#ac725e',
\ '#ff7537',
\ '#b3dc6c',
\ '#9fc6e7',
\ '#fbe983',
\ '#d06b64',
\ ]
endfunction
function! calendar#color#syntax(name, fg, bg, attr) abort
let term = len(a:attr) ? ' term=' . a:attr . ' cterm=' . a:attr . ' gui=' . a:attr : ''
if s:is_gui
let fg = len(a:fg) ? ' guifg=' . a:fg : ''
let bg = len(a:bg) ? ' guibg=' . a:bg : ''
else
let fg = len(a:fg) ? ' ctermfg=' . a:fg : ''
let bg = len(a:bg) ? ' ctermbg=' . a:bg : ''
endif
exec 'highlight Calendar' . a:name . term . fg . bg
endfunction
let s:_select_color = {}
function! s:select_color() abort
let key = get(g:, 'colors_name', '') . &background
if has_key(s:_select_color, key)
return s:_select_color[key]
endif
let fg_color = calendar#color#normal_fg_color()
let bg_color = calendar#color#normal_bg_color()
let select_color = calendar#color#gen_color(fg_color, bg_color, 1, 4)
if s:is_win32cui
let select_color = s:is_dark ? 8 : 7
endif
let s:_select_color[key] = select_color
return select_color
endfunction
let s:num = 0
let s:nums = {}
function! s:shorten(name) abort
let name = matchstr(a:name, '...')
let name = name ==# '' ? a:name : name
let s:num = (s:num + 1) % 26
let s:nums[a:name] = get(s:nums, a:name, s:num)
return name . 'abcdefghijklmnopqrstuvwxyz'[s:nums[a:name]]
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,155 @@
" =============================================================================
" Filename: autoload/calendar/constructor/day.vim
" Author: itchyny
" License: MIT License
" Last Change: 2017/05/07 22:22:26.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#constructor#day#new(instance) abort
let constructor = extend({ 'instance': a:instance }, s:constructor)
let constructor.month_constructor = calendar#constructor#month#new(constructor)
let constructor.year_constructor = calendar#constructor#year#new(constructor)
return constructor
endfunction
let s:constructor = {}
function! s:constructor.new(y, m, d) dict abort
return extend(self.instance.new(a:y, a:m, a:d), { 'constructor': self })
endfunction
" Modified Julian Day
" Reference: http://en.wikipedia.org/wiki/Julian_day
function! s:constructor.new_mjd(mjd) dict abort
return extend(extend(copy(s:instance), self.instance), { 'mjd': a:mjd, 'constructor': self })
endfunction
let s:instance = {}
function! s:div(x, y) abort
return a:x/a:y-((a:x<0)&&(a:x%a:y))
endfunction
function! s:instance.add(diff) dict abort
return self.new_mjd(self.mjd + a:diff)
endfunction
function! s:instance.add_month(diff) dict abort
let [y, m, d] = self.get_ymd()
let m += a:diff - 1
let y += s:div(m, 12)
let m -= 12 * s:div(m, 12)
let m += 1
let new_day = self.new(y, m, d)
let new_month = self.constructor.month_constructor.new(y, m)
if !new_day.is_valid()
if new_day.sub(new_month.head_day()) > 0
while !(new_day.eq_month(new_month.head_day()))
let new_day = new_day.add(-1)
endwhile
else
while !(new_day.eq_month(new_month.head_day()))
let new_day = new_day.add(1)
endwhile
endif
endif
return new_day
endfunction
function! s:instance.add_year(diff) dict abort
return self.add_month(a:diff * 12)
endfunction
function! s:instance.sub(day) dict abort
return self.mjd - a:day.mjd
endfunction
function! s:instance.week() dict abort
if has_key(self, '_week') | return self._week | endif
let m = self.mjd + 3
let self._week = m % 7 + 7 * ((m < 0) && (m % 7))
return self._week
endfunction
function! s:instance.today() dict abort
return self.new_mjd(calendar#day#today_mjd())
endfunction
function! s:instance.eq(day) dict abort
return self.mjd == a:day.mjd
endfunction
function! s:instance.eq_month(day) dict abort
return self.month().eq(a:day.month())
endfunction
function! s:instance.eq_year(day) dict abort
return self.year().eq(a:day.year())
endfunction
function! s:instance.eq_week(day) dict abort
return self.week() == a:day.week()
endfunction
function! s:instance.is_sunday() dict abort
return self.week() == 0
endfunction
function! s:instance.is_monday() dict abort
return self.week() == 1
endfunction
function! s:instance.is_tuesday() dict abort
return self.week() == 2
endfunction
function! s:instance.is_wednesday() dict abort
return self.week() == 3
endfunction
function! s:instance.is_thursday() dict abort
return self.week() == 4
endfunction
function! s:instance.is_friday() dict abort
return self.week() == 5
endfunction
function! s:instance.is_saturday() dict abort
return self.week() == 6
endfunction
function! s:instance.is_valid() dict abort
return !has_key(self, '_ymd') || self._ymd == self.get_ymd()
endfunction
function! s:instance.get_year() dict abort
return self.get_ymd()[0]
endfunction
function! s:instance.get_month() dict abort
return self.get_ymd()[1]
endfunction
function! s:instance.get_day() dict abort
return self.get_ymd()[2]
endfunction
function! s:instance.month() dict abort
if has_key(self, '_month') | return self._month | endif
let [y, m, d] = self.get_ymd()
let self._month = self.constructor.month_constructor.new(y, m)
return self._month
endfunction
function! s:instance.year() dict abort
if has_key(self, '_year') | return self._year | endif
let self._year = self.constructor.year_constructor.new(self.get_year())
return self._year
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,73 @@
" =============================================================================
" Filename: autoload/calendar/constructor/day_hybrid.vim
" Author: itchyny
" License: MIT License
" Last Change: 2017/05/07 22:07:20.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#constructor#day_hybrid#new(y, m, d) abort
let constructor = extend({ 'switch_mjd': calendar#day#gregorian#new(a:y, a:m, a:d).mjd }, s:constructor)
let constructor.switch_day = calendar#day#gregorian#new_mjd(constructor.switch_mjd)
let constructor.month_constructor = calendar#constructor#month#new(constructor)
let constructor.year_constructor = calendar#constructor#year#new(constructor)
return constructor
endfunction
let s:constructor = {}
function! s:constructor.new(y, m, d) dict abort
let mjd = calendar#day#gregorian#new(a:y, a:m, a:d).mjd
if mjd < self.switch_mjd
let mjd = calendar#day#julian#new(a:y, a:m, a:d).mjd
if mjd > self.switch_mjd
let mjd = deepcopy(self.switch_mjd)
endif
endif
let instance = self.new_mjd(mjd)
let instance._ymd = [a:y, a:m, a:d]
return instance
endfunction
function! s:constructor.new_mjd(mjd) dict abort
let instance = s:super_constructor.new_mjd(a:mjd)
let instance.constructor = self
let instance.switch_mjd = self.switch_mjd
let instance.switch_day = self.switch_day
return instance
endfunction
function! s:constructor.today() dict abort
return self.new_mjd(calendar#day#today_mjd())
endfunction
let s:instance = {}
function! s:instance.new(y, m, d) dict abort
return self.constructor.new(a:y, a:m, a:d)
endfunction
function! s:instance.new_mjd(mjd) dict abort
return self.constructor.new_mjd(a:mjd)
endfunction
function! s:instance.get_ymd() dict abort
if has_key(self, 'ymd') | return self.ymd | endif
let self.ymd = calendar#day#{self.get_calendar()}#new_mjd(self.mjd).get_ymd()
return self.ymd
endfunction
function! s:instance.is_gregorian() dict abort
return self.mjd >= self.switch_mjd
endfunction
function! s:instance.get_calendar() dict abort
return self.is_gregorian() ? 'gregorian' : 'julian'
endfunction
let s:super_constructor = calendar#constructor#day#new(s:instance)
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,155 @@
" =============================================================================
" Filename: autoload/calendar/constructor/month.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:26:32.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#constructor#month#new(day_constructor) abort
return extend({ 'day_constructor': a:day_constructor, 'cache': {} }, s:constructor)
endfunction
let s:constructor = {}
function! s:constructor.new(y, m) dict abort
let instance = copy(s:instance)
let instance.day_constructor = self.day_constructor
let instance._ym = [a:y, a:m]
let instance.constructor = self
return instance
endfunction
let s:instance = {}
function! s:instance.new(y, m) dict abort
return self.constructor.new(a:y, a:m)
endfunction
function! s:div(x, y) abort
return a:x/a:y-((a:x<0)&&(a:x%a:y))
endfunction
function! s:instance.add(diff) dict abort
let [y, m] = self.get_ym()
let m += a:diff - 1
let y += s:div(m, 12)
let m -= 12 * s:div(m, 12)
let m += 1
return self.new(y, m)
endfunction
function! s:instance.sub(month) dict abort
let [ya, ma] = self.get_ym()
let [yb, mb] = a:month.get_ym()
return (ya - yb) * 12 + (ma - mb)
endfunction
function! s:instance.eq(month) dict abort
return self.get_ym() == a:month.get_ym()
endfunction
function! s:instance.eq_month(month) dict abort
return self.eq(a:month)
endfunction
function! s:instance.eq_year(month) dict abort
return self.year().eq(a:month.year())
endfunction
function! s:instance.is_valid() dict abort
return self.head_day().is_valid() && self.last_day().is_valid()
endfunction
function! s:instance.get_ym() dict abort
if has_key(self, 'ym') | return self.ym | endif
let self.ym = self.head_day().get_ymd()[:1]
return self.ym
endfunction
function! s:instance.get_ym_string() dict abort
if has_key(self, 'ym_string') | return self.ym_string | endif
let ymd = self.head_day().get_ymd()
let self.ym_string = ymd[0] . '/' . ymd[1]
return self.ym_string
endfunction
function! s:instance.get_year() dict abort
return self.get_ym()[0]
endfunction
function! s:instance.get_month() dict abort
return self.get_ym()[1]
endfunction
function! s:instance.get_day() dict abort
return self.head_day().get_day()
endfunction
function! s:instance.head_day() dict abort
if has_key(self, '_head_day') | return self._head_day | endif
let self._head_day = self.day_constructor.new(self._ym[0], self._ym[1], 1)
if self._head_day.is_valid()
return self._head_day
else
let y = self._ym[0]
let m = self._ym[1]
let yy = self._ym[0]
let mm = self._ym[1] - 1
if mm < 1
let [yy, mm] = [yy - 1, mm + 12]
endif
let self._head_day = self.day_constructor.new(yy, mm, 1)
while self._head_day.get_year() < y || self._head_day.get_month() < m
let self._head_day = self._head_day.add(1)
endwhile
endif
return self._head_day
endfunction
function! s:instance.last_day() dict abort
if has_key(self, '_last_day') | return self._last_day | endif
let [y, m] = [self._ym[0], self._ym[1]]
let m += 1
if m > 12 | let [y, m] = [y + 1, m - 12] | endif
let self._last_day = self.new(y, m).head_day().add(-1)
return self._last_day
endfunction
function! s:instance.days() dict abort
if has_key(self, '_days') | return self._days | endif
let self._days = self.last_day().sub(self.head_day()) + 1
return self._days
endfunction
function! s:instance.get_days() dict abort
if has_key(self, '__days') | return self.__days | endif
if has_key(self.constructor.cache, self.get_ym_string())
return self.constructor.cache[self.get_ym_string()]
endif
let days = []
call add(days, self.head_day())
let l = self.last_day()
while !l.eq(days[-1])
call add(days, days[-1].add(1))
endwhile
let self.__days = days
let self.constructor.cache[self.get_ym_string()] = days
return days
endfunction
function! s:instance.day() dict abort
return self.head_day()
endfunction
function! s:instance.month() dict abort
if has_key(self, '_month') | return self._month | endif
let [y, m] = self.get_ym()
let self._month = self.new(y, m)
return self._month
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,172 @@
" =============================================================================
" Filename: autoload/calendar/constructor/view.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:26:52.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#constructor#view#new(instance) abort
return extend({ 'instance': a:instance }, s:constructor)
endfunction
let s:constructor = {}
function! s:constructor.new(source) dict abort
let instance = extend(deepcopy(s:instance), deepcopy(self.instance))
let instance.size = { 'x': 0, 'y': 0 }
let instance._size = instance.size
let instance.source = a:source
let instance._selected = 0
return instance
endfunction
let s:instance = {}
function! s:instance.set_visible(value) dict abort
let self._visible = a:value
endfunction
function! s:instance.is_visible() dict abort
sandbox return has_key(self, '_visible') ? self._visible : has_key(self.source, 'visible') ? eval(self.source.visible) : 1
endfunction
function! s:instance.on_top() dict abort
sandbox return has_key(self.source, 'on_top') ? eval(self.source.on_top) : 0
endfunction
function! s:instance.width() dict abort
return self.maxwidth()
endfunction
function! s:instance.height() dict abort
return self.maxheight()
endfunction
function! s:instance.sizex() dict abort
return self.size.x
endfunction
function! s:instance.sizey() dict abort
return self.size.y
endfunction
function! s:instance.set_size() dict abort
let self._size = copy(self.size)
let self.size.x = self.width()
let self.size.y = self.height()
if self._size != self.size && has_key(self, 'on_resize')
call self.on_resize()
endif
return self
endfunction
function! s:instance.left() dict abort
sandbox return has_key(self.source, 'left') ? eval(self.source.left) : 0
endfunction
function! s:instance.top() dict abort
sandbox return has_key(self.source, 'top') ? eval(self.source.top) : 0
endfunction
function! s:instance.maxwidth() dict abort
sandbox return has_key(self.source, 'maxwidth') ? eval(self.source.maxwidth) : calendar#util#winwidth() - 1
endfunction
function! s:instance.maxheight() dict abort
sandbox return has_key(self.source, 'maxheight') ? eval(self.source.maxheight) : calendar#util#winheight()
endfunction
function! s:instance.is_center() dict abort
return get(self.source, 'align', '') ==# 'center'
endfunction
function! s:instance.is_vcenter() dict abort
return get(self.source, 'valign', '') ==# 'center'
endfunction
function! s:instance.is_right() dict abort
return get(self.source, 'align', '') ==# 'right'
endfunction
function! s:instance.is_bottom() dict abort
return get(self.source, 'valign', '') ==# 'bottom'
endfunction
function! s:instance.is_absolute() dict abort
return get(self.source, 'position', '') ==# 'absolute'
endfunction
function! s:instance.get_top() dict abort
return max([self.top() + (self.is_vcenter() ? (self.maxheight() - self.size.y) / 2 : self.is_bottom() ? (self.maxheight() - self.size.y) : 0), 0])
endfunction
function! s:instance.get_left() dict abort
return max([self.left() + (self.is_center() ? (self.maxwidth() - self.size.x + 1) / 2 : self.is_right() ? (self.maxwidth() - self.size.x) : 0), 0])
endfunction
function! s:instance.display_point() dict abort
return 1
endfunction
function! s:instance.gather(...) dict abort
let c = self.contents()
let l = self.get_left()
let p = self.get_top() + (a:0 ? a:1 : 0)
return map(c, 'v:val.move(l, p)')
endfunction
function! s:instance.set_selected(selected) dict abort
let self._selected = a:selected
return self
endfunction
function! s:instance.is_selected() dict abort
return self._selected
endfunction
function! s:instance.set_index(index) dict abort
let self._index = a:index
endfunction
function! s:instance.get_index() dict abort
return self._index
endfunction
function! s:instance.updated() dict abort
return 1
endfunction
function! s:instance.timerange() dict abort
return ''
endfunction
function! s:instance.action(action) dict abort
return 0
endfunction
function! s:instance.oneday(day, events) dict abort
let width = self.view.inner_width
let right = has_key(a:events, 'daynum') ? a:events.daynum : ''
if has_key(a:events, 'weeknum') && width > len(right) + 6
let right = a:events.weeknum . (len(right) ? ' ' : '') . right
endif
if has_key(a:events, 'moon') && width > len(right) + 5
let right = a:events.moon . right
endif
if width > len(right) + 3 && len(right)
let le = calendar#string#strdisplaywidth(right) + 1
let right = ' ' . right
else
let le = 0
let right = ''
endif
let day = (a:day < 10 ? ' ' : '') . a:day
let holiday = get(a:events, 'holiday', '')
return calendar#string#truncate(day . ' ' . holiday, width - le) . right
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,221 @@
" =============================================================================
" Filename: autoload/calendar/constructor/view_clock.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:26:59.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#constructor#view_clock#new(instance) abort
return extend({ 'instance': a:instance }, s:constructor)
endfunction
let s:constructor = {}
function! s:constructor.new(source) dict abort
return extend(extend(s:super_constructor.new(a:source), s:instance), self.instance)
endfunction
let s:instance = {}
let s:instance.letters = []
let s:instance.prevscale = 0
let s:instance.syntax = []
let s:instance.diffs = []
let s:instance.smaller = 0
let s:instance.offsetx_start = 0
let s:instance.colnum = 1
let s:instance.winwidth = 0
let s:instance.winheight = 0
let s:instance.str = ''
let s:instance.len = 0
let s:instance._colnum = 0
function! s:instance.get_scale(...) dict abort
let colnum = a:0 ? a:1 : self.colnum
let [h, w] = [self.maxheight(), self.maxwidth()]
if self.winwidth == w && self.winheight == h && self._colnum == colnum
return self.scale
endif
let str = self.max_letter()[0]
let len = calendar#pixel#len(str) + 2 * (len(str) - 1)
let scale = 0
while w >= len * (scale + 1) * (15 + scale) / 15 + 1 &&
\ h >= 6 * (scale + 1) * self.y_height * colnum + 1
let scale += 1
endwhile
if scale > 1 && self.smaller
let scale -= 1
endif
let self.scale = scale
let self.winwidth = w
let self.winheight = h
let self._colnum = colnum
return scale
endfunction
function! s:instance.width() dict abort
let str = self.get_letter()[0]
if self.str !=# str
let self.len = calendar#pixel#len(str) + 2 * (len(str) - 1)
endif
let [h, w] = [self.maxheight(), self.maxwidth()]
if self.winwidth != w || self.winheight != h
let scale = self.get_scale()
endif
let self.winwidth = w
let self.winheight = h
let self.str = str
return self.scale ? self.len * self.scale : len(str)
endfunction
function! s:instance.height() dict abort
if self.winwidth != self.maxwidth() || self.winheight != self.maxheight()
let scale = self.get_scale()
endif
let self.one_height = self.scale ? 5 * self.scale : 1
return self.scale ? self.one_height * self.y_height : 1
endfunction
function! s:instance.gen_syn(chr, offsetx, offsety, syn) dict abort
if !len(a:chr)
return [[], 0]
endif
if !self.scale
return [[calendar#text#new(a:chr, a:offsetx, a:offsety, '')], 1]
endif
let pixel = calendar#pixel#get(a:chr)
if type(pixel) != type([])
return [[], 0]
endif
let syn = []
let max = 0
let j = 0
let scale = self.scale
let pp = ''
let above_num = 0
for p in pixel
if pp ==# p && above_num && len(syn)
let h = syn[-1].syn[0][4]
for i in range(above_num)
call syn[- 1 - i].height((h ? h : scale) + scale)
endfor
else
let max = max([max, (len(p) + 2) * scale])
let i = 0
let num = 0
while i < len(p)
let i += len(matchstr(p, '^\.*', i))
let matchlen = len(matchstr(p, '^[^.]*', i))
if matchlen
if num
call add(syn[-1].syn, [a:syn, a:offsety + j * scale, a:offsetx + i * scale, a:offsetx + i * scale + matchlen * scale, scale])
else
call add(syn, calendar#text#new(matchlen * scale, a:offsetx + i * scale, a:offsety + j * scale, a:syn).height(scale))
let num += 1
endif
endif
let i += matchlen
endwhile
let pp = p
let above_num = num
endif
let j += 1
endfor
return [syn, max]
endfunction
function! s:instance.set_contents() dict abort
let cs = self.get_letter()
let syntax = []
let diffs = []
let syn = 'NormalSpace'
let offsetx_start = 0
for j in range(len(cs))
if j >= self.y_height
break
endif
if self.prevscale == self.scale && len(self.letters) == len(cs) && self.letters[j] ==# cs[j]
let syntax_oneline = self.syntax[j]
let diffsj = self.diffs[j]
else
let syntax_oneline = []
let diffsj = []
let offsetx = len(cs[j]) ? - calendar#pixel#whitelen(cs[j][0]) * self.scale : 0
let offsetx_start = offsetx
let offsety = j * (5 + self.scale + 1)
let css = split(cs[j], '\zs')
for i in range(len(css))
if self.prevscale == self.scale && len(self.letters) == len(cs) && len(self.letters[j]) == len(css) &&
\ self.letters[j][i] ==# css[i] && diffsj == (i ? self.diffs[j][:i - 1] : []) && offsetx_start == self.offsetx_start
call add(syntax_oneline, self.syntax[j][i])
let diffx = self.diffs[j][i]
else
let [syns, diffx] = self.gen_syn(css[i], offsetx, offsety, syn)
call add(syntax_oneline, syns)
endif
let offsetx += diffx
call add(diffsj, diffx)
endfor
endif
call add(syntax, syntax_oneline)
call add(diffs, diffsj)
endfor
let self.letters = cs
let self.syntax = syntax
let self.prevscale = self.scale
let self.diffs = diffs
let self.offsetx_start = offsetx_start
let self.syn = []
let ydict = {}
let j = 0
for ss in syntax
for sss in ss
if self.scale
for ssss in sss
if has_key(ydict, ssss.y)
call extend(self.syn[ydict[ssss.y]].syn, ssss.syn)
else
call add(self.syn, deepcopy(ssss))
let ydict[ssss.y] = j
let j += 1
endif
endfor
else
call extend(self.syn, sss)
endif
endfor
endfor
endfunction
function! s:instance.on_resize() dict abort
let self.letters = []
let self.syntax = []
endfunction
function! s:instance.contents() dict abort
if self.letters != self.get_letter()
call self.set_contents()
endif
let syn = deepcopy(self.syn)
if self.is_selected() && len(self.syntax) && len(self.syntax[-1]) && len(self.syntax[-1][-1])
let cur = deepcopy(self.syntax[-1][-1][-1])
if len(cur.syn) && len(cur.syn[0]) > 3
let cur.syn[0][0] = 'Cursor'
let cur.t = 1
call cur.move(cur.syn[0][3] - cur.syn[0][2] - !!self.scale, cur.syn[0][4] ? cur.syn[0][4] - 1 : 0)
call add(syn, cur)
endif
endif
return syn
endfunction
function! s:instance.updated() dict abort
return self.letters != self.get_letter()
endfunction
let s:super_constructor = calendar#constructor#view#new(s:instance)
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,778 @@
" =============================================================================
" Filename: autoload/calendar/constructor/view_days.vim
" Author: itchyny
" License: MIT License
" Last Change: 2017/05/07 23:06:06.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#constructor#view_days#new(instance) abort
return extend({ 'instance': a:instance }, s:constructor)
endfunction
let s:constructor = {}
function! s:constructor.new(source) dict abort
return extend(extend(s:super_constructor.new(a:source), s:instance), self.instance)
endfunction
let s:instance = {}
function! s:instance.height() dict abort
return max([self.maxheight(), 6])
endfunction
function! s:instance.on_resize() dict abort
let self.frame = copy(calendar#setting#frame())
let width = calendar#string#strdisplaywidth(self.frame.vertical)
let self.view = {}
let self.view.width = (self.sizex() - width) / self.daynum / width * width
let h = max([(self.sizey() - 3) / 6, 1])
let self.view.week_count = 5
let self.view.dayheight = h < 3 ? h : max([(self.sizey() - 3) / max([self.view.week_count, 5]), 1])
let self.view.hourheight = max([(self.sizey() - self.view.dayheight) / 24, 3])
let self.view.blockmin = 60 / (self.view.hourheight - 1)
if !(self.view.width > 3 && self.view.dayheight > 1)
let self.frame = calendar#setting#get('frame_space')
let width = 1
let self.view.width = (self.sizex() - width) / self.daynum
endif
let self.frame.width = calendar#string#strdisplaywidth(self.frame.vertical)
let self.frame.strlen = len(self.frame.vertical)
let self.element = {}
let self.element.splitter = repeat(self.frame.horizontal, (self.view.width - width) / width)
let self.element.white = repeat(' ', (self.view.width - width) / width * width)
let self.element.vwhite = self.frame.vertical . self.element.white
let self.element.format = '%2d' . repeat(' ', (self.view.width - width) / width * width - 2)
let self.view.realwidth = self.view.width - width + self.frame.strlen
let self.view.inner_width = self.view.width - width
let self.view.offset = self.view.dayheight > 1 ? 3 : 1
let self.view.locale = calendar#setting#get('locale')
call self.set_day_name()
let self._cache_key = []
endfunction
function! s:instance.width() dict abort
let frame = calendar#setting#frame()
let width = calendar#string#strdisplaywidth(frame.vertical)
let w = max([(self.maxwidth() - calendar#setting#get('clock_12hour') * 7) / 8, 3])
let hh = self.height()
let h = max([(hh - 3) / 6, 1])
let h = h < 3 ? h : max([(hh - 3) / calendar#week#week_count(b:calendar.month()), 1])
if !(w > 3 && h > 1)
let width = 1
endif
let daynum = self.daynum
if daynum == 1
let views = calendar#setting#get('views')
let i = index(views, 'day_1')
if i >= 0
let days = filter([i > 0 ? views[i - 1] : '', i + 1 < len(views) ? views[i + 1] : ''], 'v:val =~# ''^day_\d$''')
if len(days)
let num = substitute(days[0], 'day_', '', '') + 0
if 1 < num && num <= 7
let daynum = num
endif
endif
endif
endif
return w * 7 / daynum / width * width * daynum + width
endfunction
function! s:instance.get_min_day() dict abort
let day = b:calendar.day()
if has_key(self, 'min_day')
if day.sub(self.min_day) < 0
let self.min_day = day
elseif day.sub(self.max_day) > 0
let self.min_day = day.add(-self.daynum + 1)
endif
else
let self.min_day = day
endif
let self.max_day = self.min_day.add(self.daynum - 1)
return self.min_day
endfunction
function! s:instance.cache_key() dict abort
if has_key(self, 'min_hour') && (self.min_hour < 0 || self.max_hour > 23)
return []
else
return copy(self.min_max_hour()) + self.get_min_day().get_ymd() + [b:calendar.day().get_month()]
\ + calendar#day#today().get_ymd() + [calendar#setting#get('frame'), calendar#setting#get('first_day')]
\ + b:calendar.event.updated() + [get(g:, 'calendar_google_event_download')]
endif
endfunction
function! s:instance.min_max_hour() dict abort
let height = self.height() - self.view.offset - self.view.dayheight
let heighthour = height / self.view.hourheight
let time = b:calendar.time()
let hour = time.hour()
if has_key(self, 'min_hour')
if hour < self.min_hour
let min = hour
elseif hour > self.max_hour
let min = self.min_hour + hour - self.max_hour
else
let min = self.min_hour
endif
else
let min = time.hour() - heighthour / 2 + 2
endif
let min = max([min, 0])
let max = min([min + heighthour - 1, 23])
let min = max([max - heighthour + 1, 0])
let max = min([min + heighthour - 1, 23])
return [min, max]
endfunction
function! s:instance.set_min_max_hour(hours) dict abort
let [self.min_hour, self.max_hour] = a:hours
endfunction
function! s:instance.get_min_max_hour() dict abort
return [self.min_hour, self.max_hour]
endfunction
function! s:instance.set_day_name() dict abort
let [h, w, ww] = [self.view.dayheight, self.view.width, self.view.realwidth]
let key = h . ',' . w . ',' . ww . ',' . calendar#setting#get('frame') . ','
\ . calendar#setting#get('locale') . ',' . calendar#week#week_index(self.get_min_day()) . ',' . calendar#setting#get('first_day')
if !has_key(self, 'day_name_cache')
let self.day_name_cache = {}
endif
if has_key(self.day_name_cache, key)
let [self.day_name_text, self.day_name_syntax] = self.day_name_cache[key]
return
endif
let day_name = copy(calendar#message#get('day_name_long'))
let maxlen = max(map(copy(day_name), 'calendar#string#strdisplaywidth(v:val)'))
if maxlen >= self.view.inner_width
let day_name = copy(calendar#message#get('day_name'))
endif
let s = repeat([''], 3)
let syntax = []
let x = self.frame.strlen
let idx = self.get_min_day().week()
for i in range(idx, idx + self.daynum - 1)
if h > 1
let s[0] .= (i > idx ? self.frame.top : self.frame.topleft) . self.element.splitter
let s[2] .= (i > idx ? self.frame.junction : self.frame.left) . self.element.splitter
endif
let name = day_name[i % 7]
let wid = calendar#string#strdisplaywidth(name)
if wid >= self.view.inner_width
let name = calendar#string#truncate(name, max([2, self.view.inner_width]))
let wid = calendar#string#strdisplaywidth(name)
endif
let len = calendar#string#strdisplaywidth(self.element.splitter)
let whiteleft = repeat(' ', (len - wid) / 2)
let whiteright = repeat(' ', len - len(whiteleft) - wid)
let weekstr = whiteleft . name . whiteright
let s[h > 1] .= self.frame.vertical . weekstr
let syn = i % 7 == 0 ? 'SundayTitle' : i % 7 == 6 ? 'SaturdayTitle' : 'DayTitle'
if len(syntax)
call add(syntax[-1].syn, [syn, h > 1, x, x + len(weekstr), 0])
else
call add(syntax, calendar#text#new(len(weekstr), x, h > 1, syn))
endif
let x += len(weekstr) + self.frame.strlen
endfor
if h > 1
let s[0] .= self.frame.topright
let s[1] .= self.frame.vertical
let s[2] .= self.frame.right
endif
let self.day_name_text = s
let self.day_name_syntax = syntax
let self.day_name_cache[key] = [s, syntax]
endfunction
function! s:get_timeevts(events, blockmin) abort
let time_events = {}
let r = range(len(a:events))
for i in r
if get(a:events[i], 'isTimeEvent') && has_key(a:events[i], 'hms') && has_key(a:events[i], 'endhms')
if a:events[i].ymd == a:events[i].endymd ||
\ (a:events[i].endhms == [0, 0, 0] &&
\ calendar#day#new(a:events[i].endymd[0], a:events[i].endymd[1], a:events[i].endymd[2]).sub(
\ calendar#day#new(a:events[i].ymd[0], a:events[i].ymd[1], a:events[i].ymd[2])
\ ) == 1
\ )
let hour = a:events[i].hms[0]
let min = a:events[i].hms[1] / a:blockmin * a:blockmin
let endhour = a:events[i].ymd == a:events[i].endymd ? a:events[i].endhms[0] : 24
let endmin = a:events[i].endhms[1]
let flg = 0
let prev = []
while (hour < endhour || hour == endhour && min < endmin) && hour <= 24
let timestr = hour . ':' . min
if !has_key(time_events, timestr)
let time_events[timestr] = []
endif
call add(time_events[timestr], [i, flg, get(a:events[i], 'syntax', '')])
let prev = time_events[timestr][-1]
let flg = 1
let min += a:blockmin
if min >= 60
let min = 0
let hour += 1
endif
endwhile
if len(prev) > 1 && prev[1]
let prev[1] = 2
endif
if len(prev) && prev[1] == 0
let prev[1] = 4
endif
endif
endif
endfor
let maxnum = 0
let prevdict = {}
let hour = 0
let min = 0
let prevret = {}
let ret = {}
while hour <= 24
let timestr = hour . ':' . min
if has_key(time_events, timestr)
let maxnum = max([maxnum, len(time_events[timestr])])
let new = {}
let minind = 0
let rr = range(len(time_events[timestr]))
for i in rr
let tvs = time_events[timestr][i]
if has_key(prevdict, tvs[0])
let new[prevdict[tvs[0]]] = deepcopy(tvs)
endif
endfor
for i in rr
let tvs = time_events[timestr][i]
if !has_key(prevdict, tvs[0])
while has_key(new, minind)
let minind += 1
endwhile
let new[minind] = deepcopy(tvs)
let prevdict[tvs[0]] = minind
endif
endfor
let minind = 0
let prevret[timestr] = []
for i in range(maxnum)
if has_key(new, i)
call add(prevret[timestr], new[i])
else
call add(prevret[timestr], [-1, 3, ''])
endif
endfor
else
let prevdict = {}
for [key, events] in items(prevret)
for event in events
call add(event, maxnum)
endfor
let ret[key] = events
endfor
let prevret = {}
let maxnum = 0
endif
let min += a:blockmin
if min >= 60
let min = 0
let hour += 1
endif
endwhile
return ret
endfunction
function! s:instance.set_contents() dict abort
if self.frame.type !=# calendar#setting#get('frame') | call self.on_resize() | endif
call self.set_day_name()
let [f, v, e] = [self.frame, self.view, self.element]
let [h, w, ww] = [v.dayheight, v.width, v.realwidth]
let height = self.height() - v.offset - h
let bottompad = (self.height() - v.offset - h) % v.hourheight + 1
let self.has_today = 0
let hh = 1 <= h - 2 ? range(1, h - 2) : []
let s = repeat([''], self.sizey())
let today = calendar#day#today()
let month = b:calendar.month()
let day = b:calendar.day()
let syntax = deepcopy(self.day_name_syntax)
for i in range(len(self.day_name_text))
let s[i] = self.day_name_text[i]
endfor
let [so, st, su, sa, tsu, tsa] = ['OtherMonth', 'Today', 'Sunday', 'Saturday', 'TodaySunday', 'TodaySaturday']
let [i, j] = [0, 0]
let days = month.get_days()
let prev_days = month.add(-1).get_days()
let next_days = month.add(1).get_days()
let wn = calendar#week#week_index(days[0])
let sub = day.sub(wn ? prev_days[-wn] : days[0])
let wnum = sub / 7
let ld = wn + len(days)
let events = b:calendar.event.get_events(day.get_year(), day.get_month())
let head = self.get_min_day().sub(wn ? prev_days[-wn] : days[0])
let range = range(head, head + self.daynum - 1)
let [self.min_hour, self.max_hour] = self.min_max_hour()
let longevt = []
let longtimeevt = []
let self.timeevent_syntax = []
let event_start_time = calendar#setting#get('event_start_time')
let event_start_time_minwidth = calendar#setting#get('event_start_time_minwidth')
let clock_12hour = calendar#setting#get('clock_12hour')
for p in range
let d = p < wn ? prev_days[-wn + p] : p < ld ? days[p - wn] : next_days[p - ld]
let evts = get(events, join(d.get_ymd(), '-'), { 'events': [] } )
let y = v.offset + h * j
let s[y] .= f.vertical
let s[y] .= self.oneday(d.get_day(), evts)
let is_today = today.eq(d)
if is_today
let self.has_today = 1
endif
let syn = is_today ? st : d.is_sunday() || get(evts, 'hasHoliday') ? su : d.is_saturday() ? sa : ''
if syn !=# ''
let l = is_today ? len(calendar#string#truncate_reverse(s[y], v.inner_width)) : 2
let syn2 = !is_today ? '' : d.is_sunday() || get(evts, 'hasHoliday') ? tsu : d.is_saturday() ? tsa : ''
let x = len(calendar#string#truncate(s[y], w * i + f.width))
if syn2 !=# ''
let x += 2
let l -= 2
endif
call add(syntax, calendar#text#new(l, x, y, syn))
if syn2 !=# ''
let l = 2
let x = len(calendar#string#truncate(s[y], w * i + f.width))
if len(syntax) && syntax[-1].y == y
call add(syntax[-1].syn, [syn2, y, x, x + l, 0])
else
call add(syntax, calendar#text#new(l, x, y, syn2))
endif
endif
endif
let z = 0
let longevtIndex = 0
for x in hh
if longevtIndex < len(longevt) && longevt[longevtIndex].viewoffset == x
let lastday = d.get_day() == longevt[longevtIndex].endymd[2] ||
\ (get(longevt[longevtIndex], 'isTimeEvent') &&
\ longevt[longevtIndex].endhms == [0, 0, 0] &&
\ calendar#day#new(longevt[longevtIndex].endymd[0], longevt[longevtIndex].endymd[1], longevt[longevtIndex].endymd[2]).sub(d) == 1
\ )
let eventtext = repeat('=', v.inner_width - lastday) . (lastday ? ']' : '')
let splitter = i ? repeat('=', f.width) : f.vertical
let s[y + x] .= splitter . eventtext
if has_key(longevt[longevtIndex], 'syntax')
let l = len(eventtext)
let syn = longevt[longevtIndex].syntax
let yy = y + x
let xx = len(s[y + x]) - l - (i ? f.width : 0)
let l = l + (i ? f.width : 0)
call add(syntax, calendar#text#new(l, xx, yy, syn))
endif
let longevtIndex += 1
else
while z < len(evts.events) && (!has_key(evts.events[z], 'summary') || evts.events[z].isHoliday || evts.events[z].isMoon || evts.events[z].isDayNum || evts.events[z].isWeekNum)
let z += 1
endwhile
if z < len(evts.events)
let is_long_event = evts.events[z].ymd != evts.events[z].endymd &&
\ (!get(evts.events[z], 'isTimeEvent') ||
\ evts.events[z].endhms != [0, 0, 0] ||
\ calendar#day#new(evts.events[z].endymd[0], evts.events[z].endymd[1], evts.events[z].endymd[2]).sub(
\ calendar#day#new(evts.events[z].ymd[0], evts.events[z].ymd[1], evts.events[z].ymd[2])
\ ) > 1
\ )
if is_long_event
let trailing = ' ' . repeat('=', v.inner_width)
call add(longevt, extend(evts.events[z], { 'viewoffset': x }))
else
let trailing = ''
endif
let starttime = event_start_time && self.view.width >= event_start_time_minwidth
\ && get(evts.events[z], 'isTimeEvent') ? evts.events[z].starttime . ' ' : ''
let eventtext = calendar#string#truncate(starttime . evts.events[z].summary . trailing, v.inner_width)
if has_key(evts.events[z], 'syntax')
let l = len(eventtext)
let xx = len(s[y + x]) + len(f.vertical)
let yy = y + x
call add(syntax, calendar#text#new(l, xx, yy, evts.events[z].syntax))
endif
let s[y + x] .= f.vertical . eventtext
let z += 1
else
let s[y + x] .= e.vwhite
endif
endif
endfor
call sort(filter(longevt, 'calendar#view#month#longevt_filter(v:val, d)'), 'calendar#view#month#sorter')
let time_events = s:get_timeevts(evts.events, v.blockmin)
for k in range(height)
if k < height - bottompad
if (k + 1) % v.hourheight
let hour = self.min_hour + k / v.hourheight
let min = (k % v.hourheight) * v.blockmin
let timestr = hour . ':' . min
if has_key(time_events, timestr) && len(time_events[timestr])
let maxnum = get(time_events[timestr][0], 3, 1)
let tevts = map(deepcopy(time_events[timestr]), 'v:val[0] >= 0 ? evts.events[v:val[0]] : {}')
let onelen = max([(v.inner_width + 2) / maxnum - f.width, f.width * 3])
let hourcontents = ''
let texts = []
let syns = []
let totallen = 0
let yy = v.offset + h + k
let ya = yy - 1
let framelen = v.inner_width / f.width * f.strlen
let xx = len(s[ya]) - framelen
for ii in range(len(tevts))
let l = maxnum > 1 ? (max([0, min([onelen, v.inner_width - totallen])]) - 1) / f.width * f.width : v.inner_width
if l >= f.width * 2
let flg = time_events[timestr][ii][1]
let border = flg == 3 ? [repeat(' ', f.width), repeat(' ', f.width)] : flg == 1 ? repeat([f.vertical], 2) : [f.bottomleft, f.bottomright]
let rep = flg == 3 || flg == 1 ? repeat(' ', f.width) : f.horizontal
if flg && flg < 4
call add(texts, border[0] . repeat(rep, l / f.width - 2) . border[1])
if flg < 3
if (k % v.hourheight) == 0 && k
let cutlen = len(s[ya][(xx):])
let leftpart = s[ya][:len(s[ya]) - cutlen - 1]
let rightpart = s[ya][len(s[ya]) - cutlen + l / f.width * f.strlen :]
let s[ya] = leftpart . f.vertical . repeat(' ', l - f.width * 2) . f.vertical . rightpart
call add(syntax, calendar#text#new(l - f.width * 2 + f.strlen * 2, xx, ya, get(tevts[ii], 'syntax', '')))
let xx += l - 2 * f.width + 2 * f.strlen + f.strlen
endif
else
let xx += l / f.width * f.strlen + f.strlen
endif
else
let eventsummary = get(tevts[ii], 'summary', '')
let smallspace = repeat(' ', f.width - 1 - (calendar#string#strdisplaywidth(eventsummary) + f.width - 1) % f.width)
let newtext = calendar#string#truncate(eventsummary . smallspace . repeat(f.horizontal, l), l - f.width) . (flg ? f.horizontal : f.topright)
call add(texts, newtext)
let xx += l / f.width * f.strlen + f.strlen
endif
call add(syns, get(tevts[ii], 'syntax', ''))
let totallen += onelen
else
let xx += l / f.width * f.strlen + f.strlen
endif
endfor
let xx = len(s[yy]) + f.strlen
let hourcontents = calendar#string#truncate(join(texts, repeat(' ', f.width)), v.inner_width)
for ii in range(len(texts))
let l = len(texts[ii])
if len(syns[ii])
call extend(time_events[timestr][ii], [l, xx, yy, syns[ii]])
call add(syntax, calendar#text#new(l, xx, yy, syns[ii]))
endif
let xx += l + f.width
endfor
else
let hourcontents = e.white
endif
let s[v.offset + h + k] .= repeat(f.vertical . hourcontents, 1)
else
let s[v.offset + h + k] .= repeat(f.vertical . e.splitter, 1)
endif
endif
endfor
call add(self.timeevent_syntax, deepcopy(time_events))
if h > 1
let frame = i ? (j + 1 == 7 ? f.bottom : f.junction) : j + 1 == 7 ? f.bottomleft : f.left
let s[y + h - 1] .= frame . e.splitter
endif
if i == 6
let [i, j] = [0, j + 1]
else
let i = i + 1
endif
endfor
for i in range(1)
for j in range(h - 1)
let s[v.offset + h * i + j] .= f.vertical
endfor
let s[v.offset + h * i + h - 1] .= (i + 1 == 7 ? f.bottomright : f.right)
endfor
let s[self.height() - bottompad] .= f.bottomleft . repeat(e.splitter . f.bottom, self.daynum - 1) . e.splitter . f.bottomright
for j in range(height)
if j < height - bottompad
let s[v.offset + h + j] .= f.vertical
endif
if !((j + 1) % v.hourheight)
let hour = self.min_hour + j / v.hourheight + 1
if clock_12hour
let postfix = hour < 12 || hour == 24 ? ' a.m.' : ' p.m.'
let hour = calendar#time#hour12(hour)
else
let postfix = ''
endif
let s[v.offset + h + j] .= printf('%2d:%02d', hour, 0) . postfix
endif
if !j
let hour = self.min_hour
if clock_12hour
let postfix = ' a.m.'
let hour = calendar#time#hour12(hour)
else
let postfix = ''
endif
let s[v.offset + h - 1] .= printf('%2d:%02d', hour, 0) . postfix
endif
endfor
let self._cache_key = self.cache_key()
let self.days = map(range(len(s)), 'calendar#text#new(s[v:val], 0, v:val, "")')
let self.syntax = syntax
let self.min_day = self.get_min_day()
endfunction
function! s:instance.contents() dict abort
if self._cache_key != self.cache_key() | call self.set_contents() | endif
let [f, v, e] = [self.frame, self.view, self.element]
let select = []
let select_over = []
let cursor = []
let now = calendar#time#now()
if self.is_selected()
for [i, hour] in self.select_index()
for h in range(v.hourheight - 1)
let y = v.offset + v.dayheight + v.hourheight * (hour - self.min_hour) + h
let x = len(calendar#string#truncate(self.days[y].s, v.width * i + f.width))
let z = len(calendar#string#truncate(self.days[y].s, v.width * (i + 1)))
let timestr = hour . ':' . (v.blockmin * h)
if has_key(self.timeevent_syntax[i], timestr)
for time_event in self.timeevent_syntax[i][timestr]
if len(time_event) == 8
call add(select_over, calendar#text#new(time_event[4], time_event[5], time_event[6], time_event[7] . 'Select'))
endif
endfor
endif
call add(select, calendar#text#new(z - x, x, y, 'Select'))
endfor
endfor
let y = v.offset + v.dayheight + v.hourheight * (hour - self.min_hour)
let x = len(calendar#string#truncate(self.days[y].s, v.width * i + f.width))
let cursor = [calendar#text#new(0, x, y, 'Cursor')]
endif
if self.has_today
let i = calendar#day#today().sub(self.get_min_day())
let h = now.minute()/ (60 / (self.view.hourheight - 1))
if self.min_hour <= now.hour() && now.hour() <= self.max_hour
let y = v.offset + v.dayheight + v.hourheight * (now.hour() - self.min_hour) + h
let x = len(calendar#string#truncate(self.days[y].s, v.width * i + f.width))
let z = len(calendar#string#truncate(self.days[y].s, v.width * (i + 1)))
let nowsyn = [calendar#text#new(z - x, x, y, 'Today')]
else
let nowsyn = []
endif
else
let nowsyn = []
endif
return deepcopy(self.days) + select + deepcopy(self.syntax) + select_over + cursor + nowsyn
endfunction
function! s:instance.select_index() dict abort
let lasti = b:calendar.day().sub(self.get_min_day())
let lasthour = b:calendar.time().hour()
if !b:calendar.visual_mode()
return [[lasti, lasthour]]
endif
let last = lasti * 24 + lasthour
let starti = b:calendar.visual_start_day().sub(self.get_min_day())
let starthour = b:calendar.visual_start_time().hour()
let start = starti * 24 + starthour
let ret = []
if b:calendar.is_visual()
for i in range(min([start, last]), max([start, last]))
let j = s:div(i, 24)
let k = i - j * 24
if [j, k] != [lasti, lasthour] && 0 <= j && j < self.daynum && self.min_hour <= k && k <= self.max_hour
call add(ret, [j, k])
endif
endfor
elseif b:calendar.is_line_visual()
for j in range(min([starti, lasti]), max([starti, lasti]))
for k in range(24)
if [j, k] != [lasti, lasthour] && 0 <= j && j < self.daynum && self.min_hour <= k && k <= self.max_hour
call add(ret, [j, k])
endif
endfor
endfor
elseif b:calendar.is_block_visual()
for j in range(min([starti, lasti]), max([starti, lasti]))
for k in range(min([starthour, lasthour]), max([starthour, lasthour]))
if [j, k] != [lasti, lasthour] && 0 <= j && j < self.daynum && self.min_hour <= k && k <= self.max_hour
call add(ret, [j, k])
endif
endfor
endfor
else
endif
call add(ret, [lasti, lasthour])
return ret
endfunction
function! s:div(x, y) abort
return a:x/a:y-((a:x<0)&&(a:x%a:y))
endfunction
function! s:instance.timerange() dict abort
let hour = b:calendar.time().hour()
if !b:calendar.visual_mode()
return printf('%d:00-%d:00 ', hour, hour + 1)
endif
let x = b:calendar.day()
let xh = b:calendar.time().hour()
let y = b:calendar.visual_start_day()
let yh = b:calendar.visual_start_time().hour()
let recurrence = ''
if b:calendar.is_line_visual()
if x.sub(y) >= 0
if x.get_year() == y.get_year()
return printf('%d/%d-%d/%d ', y.get_month(), y.get_day(), x.get_month(), x.get_day()) . recurrence
else
return printf('%d/%d/%d-%d/%d/%d ', y.get_year(), y.get_month(), y.get_day(), x.get_year(), x.get_month(), x.get_day()) . recurrence
endif
else
if x.get_year() == y.get_year()
return printf('%d/%d-%d/%d ', x.get_month(), x.get_day(), y.get_month(), y.get_day()) . recurrence
else
return printf('%d/%d/%d-%d/%d/%d ', x.get_year(), x.get_month(), x.get_day(), y.get_year(), y.get_month(), y.get_day()) . recurrence
endif
endif
elseif b:calendar.is_block_visual()
if x.sub(y) >= 0
let rec = x.sub(y) + 1
let [yh, xh] = [min([xh, yh]), max([xh, yh])]
let x = y
else
let rec = y.sub(x) + 1
let [xh, yh] = [min([xh, yh]), max([xh, yh])]
let y = x
endif
let recurrence = rec > 1 ? rec . 'days ' : ''
endif
if x.sub(y) == 0 && !len(recurrence)
return printf('%d:00 - %d:00 ', min([xh, yh]), max([xh, yh]) + 1)
elseif x.sub(y) >= 0
if x.get_year() == y.get_year()
return printf('%d/%d %d:00 - %d/%d %d:00 ', y.get_month(), y.get_day(), yh, x.get_month(), x.get_day(), xh + 1) . recurrence
else
return printf('%d/%d/%d %d:00 - %d/%d/%d %d:00 ', y.get_year(), y.get_month(), y.get_day(), yh, x.get_year(), x.get_month(), x.get_day(), xh + 1) . recurrence
endif
else
if x.get_year() == y.get_year()
return printf('%d/%d %d:00 - %d/%d %d:00 ', x.get_month(), x.get_day(), xh, y.get_month(), y.get_day(), yh + 1) . recurrence
else
return printf('%d/%d/%d %d:00 - %d/%d/%d %d:00 ', x.get_year(), x.get_month(), x.get_day(), xh, y.get_year(), y.get_month(), y.get_day(), yh + 1) . recurrence
endif
endif
endfunction
function! s:instance.action(action) dict abort
let d = b:calendar.day()
let hday = b:calendar.month().head_day()
let lday = b:calendar.month().last_day()
let hour = b:calendar.time().hour()
let wnum = d.sub(self.get_min_day())
if a:action ==# 'left'
call b:calendar.move_day(get(self, 'stopend') ? max([-v:count1, -wnum]) : -v:count1)
elseif a:action ==# 'right'
call b:calendar.move_day(get(self, 'stopend') ? min([v:count1, -wnum + self.daynum - 1]) : v:count1)
elseif index(['prev', 'next', 'space', 'add', 'subtract'], a:action) >= 0
call b:calendar.move_day(v:count1 * (index(['prev', 'subtract'], a:action) >= 0 ? -1 : 1))
elseif index(['down', 'up'], a:action) >= 0
call b:calendar.move_hour(v:count1 * (a:action ==# 'down' ? 1 : -1))
elseif index(['plus', 'minus'], a:action) >= 0
let h = v:count1 * (a:action ==# 'plus' ? 1 : -1)
while h > 23 - hour
let h = h - 24
let wnum -= self.daynum
endwhile
while h < - hour
let h = h + 24
let wnum += self.daynum
endwhile
call b:calendar.move_hour(h)
if has_key(self, 'min_day') && has_key(self, 'max_day')
if self.min_day.sub(d.add(-wnum)) > 0 || self.max_day.sub(d.add(-wnum)) < 0
let self.min_day = self.min_day.add(s:div(-wnum + self.daynum - 1, self.daynum) * self.daynum)
let self.max_day = self.max_day.add(s:div(-wnum + self.daynum - 1, self.daynum) * self.daynum)
endif
endif
call b:calendar.move_day(-wnum)
elseif index(['down_big', 'up_big'], a:action) >= 0
let diff = self.max_hour - self.min_hour
let dir = a:action ==# 'down_big' ? 1 : -1
let di = max([min([v:count1 * dir * diff * 2 / 3, 23 - hour]), - hour])
if dir > 0
let self.min_hour = self.min_hour + v:count1 * dir * diff
let self.max_hour = self.min_hour + diff
else
let self.max_hour = self.max_hour + v:count1 * dir * diff
let self.min_hour = self.max_hour - diff
endif
call b:calendar.move_hour(di)
elseif index(['down_large', 'up_large'], a:action) >= 0
let diff = self.max_hour - self.min_hour
let dir = a:action ==# 'down_large' ? 1 : -1
let di = max([min([(dir > 0 ? self.max_hour : self.min_hour) - hour + (v:count1 - 1) * dir * diff, 23 - hour]), - hour])
if dir > 0
let self.min_hour = self.min_hour + v:count1 * dir * diff
let self.max_hour = self.min_hour + diff
else
let self.max_hour = self.max_hour + v:count1 * dir * diff
let self.min_hour = self.max_hour - diff
endif
call b:calendar.move_hour(di)
elseif a:action ==# 'line_head'
call b:calendar.move_day(-wnum)
elseif a:action ==# 'line_middle'
call b:calendar.move_day(-wnum + (self.daynum - 1) / 2)
elseif a:action ==# 'line_last'
call b:calendar.move_day(self.daynum - 1 - wnum)
elseif a:action ==# 'bar'
call b:calendar.move_day(-wnum + min([v:count1 - 1, self.daynum - 1]))
elseif a:action ==# 'first_line' || a:action ==# 'first_line_head' || (a:action ==# 'last_line' && v:count)
call b:calendar.move_hour((v:count ? min([v:count1, 23]) : 0) - hour)
elseif a:action ==# 'last_line'
call b:calendar.move_hour((v:count ? max([v:count1, 23]) : 23) - hour)
elseif a:action ==# 'last_line_last'
call b:calendar.move_hour((v:count ? max([v:count1, 23]) : 23) - hour)
elseif index(['scroll_down', 'scroll_up'], a:action) >= 0
let diff = v:count1 * (a:action =~# 'down' ? 1 : -1)
let old_hours = [self.min_hour, self.max_hour]
let self.min_hour += diff
let self.max_hour += diff
let new_hours = self.min_max_hour()
if old_hours == new_hours
call b:calendar.move_hour(diff)
endif
elseif index(['scroll_top_head', 'scroll_top', 'scroll_bottom_head', 'scroll_bottom'], a:action) >= 0
let self.min_hour += 23 * (a:action =~# 'top' ? 1 : -1)
let self.max_hour += 23 * (a:action =~# 'top' ? 1 : -1)
call b:calendar.move_day(a:action =~# 'head' ? -wnum : 0)
elseif index(['scroll_center_head', 'scroll_center'], a:action) >= 0
let diff = self.max_hour - self.min_hour
let self.min_hour = hour - diff / 2 + 1
let self.max_hour = self.min_hour + diff
call b:calendar.move_day(a:action =~# 'head' ? -wnum : 0)
elseif a:action ==# 'command_enter' && mode() ==# 'c' && getcmdtype() ==# ':'
let cmd = calendar#util#getcmdline()
if cmd =~# '^\s*\d\+\s*$'
let c = max([min([matchstr(cmd, '\d\+') * 1, 23]), 0])
call b:calendar.move_hour(c - hour)
return calendar#util#update_keys()
endif
endif
endfunction
let s:super_constructor = calendar#constructor#view#new(s:instance)
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,348 @@
" =============================================================================
" Filename: autoload/calendar/constructor/view_months.vim
" Author: itchyny
" License: MIT License
" Last Change: 2017/05/07 23:07:32.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#constructor#view_months#new(instance) abort
return extend({ 'instance': a:instance }, s:constructor)
endfunction
let s:constructor = {}
function! s:constructor.new(source) dict abort
return extend(extend(s:super_constructor.new(a:source), s:instance), self.instance)
endfunction
let s:instance = {}
function! s:instance.is_full() dict abort
return self.x_months * self.y_months == 12
endfunction
function! s:instance.get_months() dict abort
if self.is_full()
return b:calendar.year().get_months()
else
let m = b:calendar.month()
let months = [m]
for i in range(self.x_months * self.y_months / 2)
call add(months, months[-1].add(1))
endfor
for i in range((self.x_months * self.y_months - 1) / 2)
call insert(months, months[0].add(-1), 0)
endfor
return months
endif
endfunction
function! s:instance.width() dict abort
let daywidth = 2
let pad = 100
while pad > daywidth * 7
let daywidth += 1
let pad = self.x_months > 1 ? max([(self.maxwidth() - daywidth * 7 * self.x_months)/2 / (self.x_months - 1), 2]) : 0
endwhile
let self.pad = pad
let self.daywidth = daywidth
return (daywidth * 7 + pad) * self.x_months - pad - self.daywidth + 2
endfunction
function! s:instance.height() dict abort
return self.y_months > 1 ? max([9, (self.maxheight()) * 4/5 / self.y_months]) * self.y_months : 9
endfunction
function! s:instance.display_point() dict abort
let w = self.maxwidth() - 2
let h = self.maxheight()
let lw = w - self.width()
let lh = (h - self.height()) * 2
return (lw >= 0 && lh >= 0) * (lw + lh + (lw - lh >= 0 ? lw - lh : - (lw - lh)) * 5)
endfunction
function! s:instance.on_resize() dict abort
let self.view = {}
let self.view.width = ((self.sizex() + self.pad + self.daywidth - 2)/ self.x_months - self.pad) / 7
let self.view.pad = self.pad
let self.view.height = self.sizey() / self.y_months
let self.view.dheight = 1
let self.view.dheight = max([1, self.view.height / 8])
let self.view.offset = self.view.dheight * 2
let self.element = {}
let self.element.pad = repeat(' ', self.view.pad)
let self.element.format = '%2d' . repeat(' ', self.view.width - 2)
let self.element.white = repeat(' ', self.view.width)
let self._today = [0, 0, 0]
let self._month = [0, 0]
let self._year = 0
call self.set_day_name()
endfunction
function! s:instance.set_day_name() dict abort
let day_name = copy(calendar#message#get('day_name'))
let [v, e] = [self.view, self.element]
let [mh, h, w] = [v.dheight, v.height, v.width]
let syntax = []
let day_names = ''
let offsetx = [0]
let index = calendar#week#first_day_index()
for i in range(index, index + 6)
let name = day_name[i % 7]
let day_names .= calendar#string#truncate(name, 2) . repeat(' ', self.view.width - 2)
call add(offsetx, len(day_names))
endfor
for j in range(self.y_months)
let y = h * j + v.offset / 2
let f = 1
let daytitles = []
for i in range(self.x_months)
call add(daytitles, calendar#text#new(len(day_names) - (self.view.width - 2), (offsetx[-1] + v.pad) * i, y, 'DayTitle'))
for k in range(index, index + 6)
let l = k % 7
let is_sunday = l == 0
let is_saturday = l == 6
if is_sunday || is_saturday
let x = (offsetx[-1] + v.pad) * i + offsetx[k - index]
let name = day_name[l]
let weekstr = calendar#string#truncate(name, 2)
let syn = is_sunday ? 'SundayTitle' : is_saturday ? 'SaturdayTitle' : ''
call daytitles[-1].over(calendar#text#new(len(weekstr), x, y, syn))
endif
endfor
endfor
for i in range(len(daytitles))
if i
call extend(syntax[-1].syn, daytitles[i].syn)
else
call add(syntax, daytitles[i])
endif
endfor
endfor
let self.day_name_texts = syntax
let self.day_names = day_names
let self.day_names_len = offsetx[-1]
let self._first_day = calendar#setting#get('first_day')
endfunction
function! s:instance.changed() dict abort
if self._today != calendar#day#today().get_ymd() || get(self, '_first_day', '') != calendar#setting#get('first_day')
return 1
elseif self.is_full()
return self._year != b:calendar.year().get_y()
else
return self._month != b:calendar.month().get_ym()
endif
endfunction
function! s:instance.set_contents() dict abort
let month_name = copy(calendar#message#get('month_name_long'))
let self.month_names_offset = []
for i in range(self.y_months)
call add(self.month_names_offset, [])
endfor
let year = b:calendar.year()
let month = b:calendar.month()
let s = repeat([''], self.sizey())
let syntax = deepcopy(self.day_name_texts)
let [v, e] = [self.view, self.element]
let [mh, h, w] = [v.dheight, v.height, v.width]
let [i, j] = [0, 0]
let today = calendar#day#today()
let self.sun_position = []
let self.sat_position = []
let self.top_syntax = []
let months = self.get_months()
let week_number = calendar#setting#get('week_number')
for m in months
if len(s[h * j])
for mj in range(h)
let s[mj + h * j] .= mj < v.offset ? e.pad : e.pad[2:]
endfor
endif
let [mi, mj] = [0, 0]
let monthname = month_name[m.get_month() - 1]
let monthnamelen = calendar#string#strdisplaywidth(monthname)
let holidays = b:calendar.event.get_holidays(m.get_year(), m.get_month())
call add(self.month_names_offset[j], len(s[mh * mj + h * j]))
if monthnamelen >= w * 6 + 2
let s[mh * mj + h * j] .= calendar#string#truncate(monthname, w * 7 - 1) . ' '
else
let whiteleft = (w * 6 + 3 - monthnamelen) / 2
let whiteright = w * 7 - monthnamelen - whiteleft
let s[mh * mj + h * j] .= repeat(' ', whiteleft) . monthname . repeat(' ', whiteright)
endif
call add(self.month_names_offset[j], len(s[mh * mj + h * j]))
let s[mh * mj + h * j + v.offset / 2] .= self.day_names
let days = m.get_days()
let prev_days = calendar#week#is_first_day(days[0]) ? [] : m.add(-1).get_days()
let next_days = calendar#week#is_last_day(days[-1]) ? [] : m.add(1).get_days()
let week_count = calendar#week#week_count(m)
let wn = calendar#week#week_index(days[0])
let ld = wn + len(days)
let sun = [-1, -1, -1]
let sat = [-1, -1, -1]
for p in range(week_count * 7)
let d = p < wn ? prev_days[-wn + p] : p < ld ? days[p - wn] : next_days[p - ld]
let x = (w * 7 + v.pad) * i + v.width * mi
let y = mh * mj + h * j + v.offset
if wn <= p && p < ld
let s[y] .= printf(e.format, d.get_day())
if today.eq(d)
for k in range(mh) " Do not use .height()
call add(self.top_syntax, calendar#text#new(2, x, y + k, 'Today'))
endfor
elseif has_key(holidays, join(d.get_ymd(), '-'))
for k in range(mh) " Do not use .height()
call add(self.top_syntax, calendar#text#new(2, x, y + k, 'Sunday'))
endfor
elseif d.is_sunday()
if sun[0] < 0 | let sun[0] = x | endif
let sun[2 - (sun[1] < 0)] = y
elseif d.is_saturday()
if sat[0] < 0 | let sat[0] = x | endif
let sat[2 - (sat[1] < 0)] = y
endif
let dd = d
else
let s[y] .= e.white
endif
if mi == 6
let [mi, mj] = [0, mj + 1]
if week_number
call add(self.top_syntax, calendar#text#new(2, len(s[y]), y, 'Comment'))
let s[y] .= printf('%2d', calendar#week#week_number(dd))
else
let s[y] .= ' '
endif
else
let mi = mi + 1
endif
endfor
if sun[0] >= 0
if sun[2] < 0 | let sun[2] = sun[1] | endif
if len(syntax) && syntax[-1].y == sun[1]
call add(syntax[-1].syn, ['Sunday', sun[1], sun[0], sun[0] + 2, sun[2] - sun[1] + mh])
elseif len(syntax) > 1 && syntax[-2].y == sun[1]
call add(syntax[-2].syn, ['Sunday', sun[1], sun[0], sun[0] + 2, sun[2] - sun[1] + mh])
else
call add(syntax, calendar#text#new(2, sun[0], sun[1], 'Sunday').height(sun[2] - sun[1] + mh))
endif
endif
if sat[0] >= 0
if sat[2] < 0 | let sat[2] = sat[1] | endif
if len(syntax) && syntax[-1].y == sat[1]
call add(syntax[-1].syn, ['Saturday', sat[1], sat[0], sat[0] + 2, sat[2] - sat[1] + mh])
elseif len(syntax) > 1 && syntax[-2].y == sat[1]
call add(syntax[-2].syn, ['Saturday', sat[1], sat[0], sat[0] + 2, sat[2] - sat[1] + mh])
else
call add(syntax, calendar#text#new(2, sat[0], sat[1], 'Saturday').height(sat[2] - sat[1] + mh))
endif
endif
call add(self.sun_position, sun)
call add(self.sat_position, sat)
for jj in range(mj, h - v.offset)
let y = mh * jj + h * j + v.offset
if y < len(s) && y < h * (j + 1)
let s[y] .= repeat(e.white, 7) . ' '
else
break
endif
endfor
if i == self.x_months - 1 | let [i, j] = [0, j + 1] | else | let i = i + 1 | endif
if j >= self.y_months | break | endif
endfor
let self._today = today.get_ymd()
let self._first_day = calendar#setting#get('first_day')
if self.is_full()
let self._year = b:calendar.year().get_y()
else
let self._month = b:calendar.month().get_ym()
endif
let self.days = map(range(len(s)), 'calendar#text#new(s[v:val], 0, v:val, "")')
let self.syntax = syntax
endfunction
function! s:instance.contents() dict abort
if get(self, '_first_day', '') != calendar#setting#get('first_day') | call self.on_resize() | endif
if self.changed() | call self.set_contents() | endif
let [v, e] = [self.view, self.element]
let [mh, h, w] = [v.dheight, v.height, v.width]
let select = []
let month = b:calendar.month()
let ij = month.sub(self.get_months()[0])
let [i, j] = [ij % self.x_months, ij / self.x_months]
let o = self.month_names_offset[j]
let sunsat = []
if self.is_selected()
for x in range(calendar#week#week_count(month) * mh + v.offset)
let l = x ? (x > 1 ? w * 7 : self.day_names_len) : o[i * 2 + 1] - o[i * 2]
let offset = x ? ((x > 1 ? w * 7 : self.day_names_len) + v.pad) * i : o[i * 2]
if x != mh
call add(select, calendar#text#new(l - (self.view.width - 2), offset, h * j + x, 'Select'))
endif
endfor
call add(select, calendar#text#new(0, o[i * 2], h * j, 'Cursor'))
let sun = self.sun_position[ij]
for j in range(sun[2] - sun[1] + mh - 1)
call add(sunsat, calendar#text#new(2, sun[0], sun[1] + j + 1, ''))
endfor
let sat = self.sat_position[ij]
for j in range(sat[2] - sat[1] + mh - 1)
call add(sunsat, calendar#text#new(2, sat[0], sat[1] + j + 1, ''))
endfor
endif
return deepcopy(self.days) + select + deepcopy(self.syntax) + sunsat + deepcopy(self.top_syntax)
endfunction
function! s:instance.action(action) dict abort
let month = b:calendar.month()
let months = self.get_months()
let ij = month.sub(months[0])
let [x, y] = [self.x_months, self.y_months]
let [i, j] = [ij % x, ij / x]
if a:action ==# 'left'
call b:calendar.move_month(self.is_full() ? max([-v:count1, - i]) : -v:count1 * y)
elseif a:action ==# 'right'
call b:calendar.move_month(self.is_full() ? min([v:count1, x - 1 - i]) : v:count1 * y)
elseif index(['prev', 'next', 'space', 'add', 'subtract'], a:action) >= 0
call b:calendar.move_month(v:count1 * (a:action ==# 'prev' || a:action ==# 'subtract' ? -1 : 1))
elseif index(['down', 'up', 'scroll_down', 'scroll_up'], a:action) >= 0
call b:calendar.move_month(v:count1 * (a:action =~# 'down' ? 1 : -1) * x)
elseif index(['plus', 'minus'], a:action) >= 0
call b:calendar.move_month(v:count1 * (a:action ==# 'plus' ? 1 : -1) * x - i)
elseif index(['down_big', 'up_big'], a:action) >= 0
call b:calendar.move_month(v:count1 * (a:action ==# 'down_big' ? 1 : -1) * (self.is_full() ? x * 2 : len(months)))
elseif index(['down_large', 'up_large'], a:action) >= 0
call b:calendar.move_year(v:count1 * (a:action ==# 'down_large' ? 1 : -1))
elseif a:action ==# 'line_head'
call b:calendar.move_month(self.is_full() ? -i : -x * y / 2)
elseif a:action ==# 'line_middle'
call b:calendar.move_month(self.is_full() ? (x - 1) / 2 - i : 0)
elseif a:action ==# 'line_last'
call b:calendar.move_month(self.is_full() ? x - 1 - i : x * y / 2)
elseif a:action ==# 'bar'
call b:calendar.move_month(min([v:count1, x]) - (self.is_full() ? i + 1 : (x + 1) / 2))
elseif a:action ==# 'first_line' || a:action ==# 'first_line_head'
call b:calendar.move_month(- ij)
elseif a:action ==# 'last_line'
call b:calendar.move_month(-month.sub(months[-x]))
elseif a:action ==# 'last_line_last'
call b:calendar.move_month(-month.sub(months[-1]))
elseif a:action ==# 'command_enter' && mode() ==# 'c' && getcmdtype() ==# ':'
let cmd = calendar#util#getcmdline()
if cmd =~# '^\s*\d\+\s*$'
let c = max([min([cmd * 1, 12]), 1])
call b:calendar.move_month(c - month.get_month())
return calendar#util#update_keys()
endif
endif
endfunction
let s:super_constructor = calendar#constructor#view#new(s:instance)
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,362 @@
" =============================================================================
" Filename: autoload/calendar/constructor/view_textbox.vim
" Author: itchyny
" License: MIT License
" Last Change: 2021/09/18 13:37:00.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#constructor#view_textbox#new(instance) abort
return extend({ 'instance': a:instance }, s:constructor)
endfunction
let s:constructor = {}
function! s:constructor.new(source) dict abort
return extend(extend(s:super_constructor.new(a:source), s:instance), self.instance)
endfunction
let s:instance = {}
let s:instance._key = []
let s:instance.__key = []
let s:instance._texts = []
let s:instance.select = 0
let s:instance.noindex = []
let s:instance._select_title = 0
let s:instance.syntax = []
let s:instance.length = 0
let s:instance._current_contents = {}
let s:instance._prev_contents = {}
let s:instance._prevprev_contents = {}
let s:instance._next_contents = {}
let s:instance._current_group_id = ''
let s:instance._nocontents = 1
function! s:instance.width() dict abort
let frame = calendar#setting#frame()
let width = calendar#string#strdisplaywidth(frame.vertical)
return self.maxwidth() / width * width + 2
endfunction
function! s:instance.contents() dict abort
if self._key == [self.is_selected(), self.select, self.sizex(), self.sizey(), get(self, 'min_index'), get(self, 'max_index')] + self.get_key()
return deepcopy(self._texts)
endif
let s = []
let frame = calendar#setting#frame()
let width = calendar#string#strdisplaywidth(frame.vertical)
let flen = len(frame.vertical)
let top = frame.topleft . repeat(frame.horizontal, (self.sizex() - 2) / width - 2) . frame.topright
let bottom = frame.bottomleft . repeat(frame.horizontal, (self.sizex() - 2) / width - 2) . frame.bottomright
let w = self.sizex() - 4 - width * 2
let sizey = self.sizey() - 1
let self.cnt = self.get_contents()
let self.length = len(self.cnt)
if len(self.cnt)
for i in range(min([len(self.cnt) - self.min_index, sizey]))
call add(s, self.cnt[self.min_index + i])
endfor
endif
if len(s) < sizey
for i in range(sizey - len(s))
call add(s, '')
endfor
else
let s = s[:sizey]
endif
call map(s, 'calendar#string#truncate(v:val, w)')
let texts = map(range(len(s)), 'calendar#text#new(" " . frame.vertical . " " . s[v:val] . " " . frame.vertical . " ", 0, v:val + 1, "")')
call insert(texts, calendar#text#new(' ' . top . ' ', 0, 0, ''), 0)
call add(texts, calendar#text#new(' ' . bottom . ' ', 0, len(s), ''))
let selsyn = ''
for [i, syn] in self.syntax
if self.min_index <= i && i + 1 < self.min_index + sizey
let len = len(s[i - self.min_index]) + 2
call add(texts, calendar#text#new(len, 1 + flen, 1 + i - self.min_index, syn))
if i == self.select
let selsyn = syn
endif
endif
endfor
if self.is_selected()
if self.min_index <= self.select && self.select < self.min_index + sizey
if self._select_line
let len = len(s[self.select - self.min_index]) + 2
call add(texts, calendar#text#new(len, 1 + flen, 1 + self.select - self.min_index, selsyn . 'Select'))
endif
endif
call add(texts, calendar#text#new(0, 1 + flen, 1 + self.select - self.min_index, 'Cursor'))
endif
let self._texts = deepcopy(texts)
let self._key = [self.is_selected(), self.select, self.sizex(), self.sizey(), get(self, 'min_index'), get(self, 'max_index')] + self.get_key()
return texts
endfunction
function! s:instance.get_key() dict abort
return []
endfunction
function! s:instance.get_contents() dict abort
if self.__key == [self.select, self.sizex(), self.sizey(), get(self, 'min_index'), get(self, 'max_index')] + self.get_key()
return self.cnt
endif
let self.noindex = []
let self.syntax = []
let cnt = []
let frame = calendar#setting#frame()
let width = calendar#string#strdisplaywidth(frame.vertical)
let cnts = self.get_raw_contents()
let w = self.sizex() - width * 2
if len(cnts)
let self._current_contents = {}
let self._prev_contents = {}
let self._prevprev_contents = {}
let self._next_contents = {}
for j in range(len(cnts))
let t = cnts[j]
if len(cnt)
if !self._select_title
call add(self.noindex, len(cnt))
endif
call add(cnt, '')
endif
if !self._select_title
call add(self.noindex, len(cnt))
endif
if len(cnt) == self.select
let self._current_contents = { 'title': t.title }
endif
call add(cnt, repeat(' ', max([(self.sizex() - 4 - width * 2 - calendar#string#strdisplaywidth(t.title)) / 2, 0])) . t.title)
if !self._select_title
call add(self.noindex, len(cnt))
endif
call add(cnt, '')
while index(self.noindex, self.select) >= 0
let self.select += 1
endwhile
if j == len(cnts) - 1
let self.select = min([self.select, len(cnt) + len(t.items) - 1])
endif
for tt in t.items
let lencnt = len(cnt)
if lencnt == self.select - 1
let self._prev_contents = deepcopy(tt)
elseif lencnt == self.select - 2
let self._prevprev_contents = deepcopy(tt)
elseif lencnt == self.select + 1
let self._next_contents = deepcopy(tt)
elseif lencnt == self.select
let self._current_contents = deepcopy(tt)
let self._current_group_id = get(t, 'id', '')
endif
if get(tt, 'status', '') ==# 'completed'
call add(self.syntax, [len(cnt), 'Comment'])
elseif has_key(tt, 'syntax')
call add(self.syntax, [len(cnt), tt.syntax])
endif
call add(cnt, get(tt, 'prefix', '') . get(tt, 'title', get(tt, 'summary', '')))
endfor
endfor
if self._nocontents && has_key(self, 'min_index') && has_key(self, 'max_index')
unlet! self.min_index self.max_index
endif
if self._current_group_id == ''
let self._current_group_id = get(cnts[0], 'id', '')
endif
let [self.min_index, self.max_index] = self.min_max_index(len(cnt))
let self._nocontents = 0
else
let [self.min_index, self.max_index] = [0, 0]
let self._nocontents = 1
let self.select = 0
let self._prev_contents = {}
let self._prevprev_contents = {}
let self._next_contents = {}
let self._current_contents = {}
let self._current_group_id = ''
endif
let self.__key = [self.select, self.sizex(), self.sizey(), get(self, 'min_index'), get(self, 'max_index')] + self.get_key()
return cnt
endfunction
function! s:instance.min_max_index(length) dict abort
let height = self.sizey() - 2
let length = max([a:length, height])
if has_key(self, 'min_index')
if self.select < self.min_index
let min = self.select
elseif self.select >= self.max_index
let min = self.min_index + self.select - self.max_index
else
let min = self.min_index
endif
else
let min = self.select - height / 2 + 2
endif
let min = max([min, 0])
let max = min([min + height - 1, length - 1])
let min = max([max - height + 1, 0])
let max = min([min + height - 1, length - 1])
return [min, max]
endfunction
function! s:instance.move_select(diff) dict abort
let self.select = max([min([self.select + a:diff, self.length - 1]), 0])
let diff = a:diff > 0 ? 1 : -1
while index(self.noindex, self.select) >= 0
if self.select < 3
let self.min_index = - self.length
let diff = 1
endif
let self.select += diff
endwhile
let self.select = max([min([self.select, self.length - 1]), 0])
let self.__updated = 1
let [self.min_index, self.max_index] = self.min_max_index(self.length)
endfunction
function! s:instance.current_contents() dict abort
return self._current_contents
endfunction
function! s:instance.prev_contents() dict abort
return self._prev_contents
endfunction
function! s:instance.prevprev_contents() dict abort
return self._prevprev_contents
endfunction
function! s:instance.next_contents() dict abort
return self._next_contents
endfunction
function! s:instance.current_group_id() dict abort
return self._current_group_id
endfunction
function! s:instance._action(action) dict abort
let hour = self.select
let self.__updated = 0
let [select, min_index, max_index] = [self.select, self.min_index, self.max_index]
if index(['down', 'up'], a:action) >= 0
call self.move_select(v:count1 * (a:action ==# 'down' ? 1 : -1))
elseif index(['down_big', 'up_big'], a:action) >= 0
let diff = self.max_index - self.min_index
let dir = a:action ==# 'down_big' ? 1 : -1
let di = max([min([v:count1 * dir * diff * 2 / 3, self.length - 1 - hour]), - hour])
if dir > 0
let self.min_index = self.min_index + v:count1 * dir * diff
let self.max_index = self.min_index + diff
else
let self.max_index = self.max_index + v:count1 * dir * diff
let self.min_index = self.max_index - diff
endif
call self.move_select(di)
elseif index(['down_large', 'up_large'], a:action) >= 0
let diff = self.max_index - self.min_index
let dir = a:action ==# 'down_large' ? 1 : -1
let di = max([min([(dir > 0 ? self.max_index : self.min_index) - hour + (v:count1 - 1) * dir * diff, self.length - 1 - hour]), - hour])
if dir > 0
let self.min_index = self.min_index + v:count1 * dir * diff
let self.max_index = self.min_index + diff
else
let self.max_index = self.max_index + v:count1 * dir * diff
let self.min_index = self.max_index - diff
endif
call self.move_select(di)
elseif a:action ==# 'first_line' || a:action ==# 'first_line_head' || (a:action ==# 'last_line' && v:count)
call self.move_select((v:count ? min([v:count1, self.length - 1]) : 0) - hour)
elseif a:action ==# 'last_line'
call self.move_select((v:count ? max([v:count1, self.length - 1]) : self.length - 1) - hour)
elseif a:action ==# 'last_line_last'
call self.move_select((v:count ? max([v:count1, self.length - 1]) : self.length - 1) - hour)
elseif index(['scroll_down', 'scroll_up'], a:action) >= 0
let diff = v:count1 * (a:action =~# 'down' ? 1 : -1)
let old_indeces = [self.min_index, self.max_index]
let self.min_index += diff
let self.max_index += diff
let new_indeces = self.min_max_index(self.length)
if old_indeces == new_indeces
call self.move_select(diff)
endif
elseif index(['scroll_top_head', 'scroll_top', 'scroll_bottom_head', 'scroll_bottom', 'scroll_center_head', 'scroll_center'], a:action) >= 0
let diff = a:action =~# 'center' ? hour - (self.max_index - self.min_index) / 2 + 1 - self.min_index : (self.length - 1) * (a:action =~# 'top' ? 1 : -1)
let self.min_index += diff
let self.max_index += diff
elseif a:action ==# 'status'
let message = get(self.current_contents(), 'title', get(self.current_contents(), 'summary', ''))
call calendar#echo#message(message)
return 1
elseif index(['yank', 'yank_line'], a:action) >= 0
call self.yank()
return 1
elseif index(['delete', 'delete_line'], a:action) >= 0
if calendar#setting#get('yank_deleting')
call self.yank()
endif
return 1
elseif a:action ==# 'enter'
let url = get(self.current_contents(), 'htmlLink', '')
if url !=# ''
call calendar#webapi#open_url(url)
endif
elseif a:action ==# 'command_enter' && mode() ==# 'c' && getcmdtype() ==# ':'
let cmd = calendar#util#getcmdline()
if cmd =~# '\v^\s*\d+\s*$'
let c = max([min([matchstr(cmd, '\d\+') * 1 - 1, self.length - 1]), 0])
let idxes = filter(range(self.length), 'index(self.noindex, v:val) < 0')
call self.move_select(get(idxes, c, get(idxes, -1, 0)) - hour)
return calendar#util#update_keys()
endif
elseif a:action ==# 'command_enter' && mode() ==# 'c' && (getcmdtype() ==# '/' || getcmdtype() ==# '?')
\ || a:action ==# 'next_match' || a:action ==# 'prev_match'
let iscmd = a:action ==# 'command_enter'
let pattern = iscmd ? getcmdline() : @/
if iscmd && getcmdtype() ==# '/' || a:action ==# 'next_match' && v:searchforward
\ || a:action ==# 'prev_match' && !v:searchforward
let indexes = range(self.select + 1 - iscmd, self.length - 1) + range(self.select + 1)
let status = '/' . pattern
else
let indexes = range(self.select - 1 + iscmd, 0, -1) + range(self.length - 1, self.select, -1)
let status = '?' . pattern
endif
let exitvalue = iscmd ? "\<C-c>:\<C-u>silent call b:calendar.update()\<CR>"
\ . ":\<C-u>silent let v:searchforward=" . (getcmdtype() ==# '/') . "\<CR>"
\ . ":\<C-u>echo " . string(status) . "\<CR>" : 0
if iscmd
let @/ = pattern
else
echo status
endif
try
for i in indexes
if self.cnt[i] =~ pattern " do not use =~# (use 'ignorecase')
call self.move_select(i - self.select)
return exitvalue
endif
endfor
catch
endtry
return exitvalue
endif
if self.__updated && [select, max_index] == [self.select, self.max_index] && (min_index == self.min_index || !min_index)
return ''
endif
endfunction
function! s:instance.yank() dict abort
let message = get(self.current_contents(), 'title', get(self.current_contents(), 'summary', ''))
call calendar#util#yank(message)
endfunction
function! s:instance.action(action) dict abort
return self._action(a:action)
endfunction
let s:super_constructor = calendar#constructor#view#new(s:instance)
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,127 @@
" =============================================================================
" Filename: autoload/calendar/constructor/view_ymd.vim
" Author: itchyny
" License: MIT License
" Last Change: 2017/07/02 08:42:35.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#constructor#view_ymd#new(instance) abort
return extend({ 'instance': a:instance }, s:constructor)
endfunction
let s:constructor = {}
function! s:constructor.new(source) dict abort
let instance = extend(extend(s:super_constructor.new(a:source), s:instance), self.instance)
let iday = index(instance.ymd, 'day')
let imonth = index(instance.ymd, 'month')
let iyear = index(instance.ymd, 'year')
let instance.select_index = iday >= 0 ? iday : imonth >= 0 ? imonth : iyear
return instance
endfunction
let s:instance = {}
function! s:instance.width() dict abort
return len(self.contents()[0].s)
endfunction
function! s:instance.height() dict abort
return 1
endfunction
function! s:sum(l) abort
let n = 0
for i in a:l
let n += i
endfor
return n
endfunction
function! s:instance.contents() dict abort
let y = b:calendar.month().get_year()
let year = y > 0 ? string(y) : (1 - y) . ' BC'
let use_month_name = calendar#setting#get('date_month_name')
let use_full_month_name = calendar#setting#get('date_full_month_name')
if use_full_month_name
let month = calendar#message#get('month_name_long')[b:calendar.month().get_month() - 1]
elseif use_month_name
let month = calendar#message#get('month_name')[b:calendar.month().get_month() - 1]
else
let month = printf('%2d', b:calendar.month().get_month())
endif
let day = printf('%2d', b:calendar.day().get_day())
let sepa = substitute(printf(' %s ', calendar#setting#get('date_separator')), '\s\+', ' ', 'g')
let texts = map(copy(self.ymd), "get({ 'year': year, 'month': month, 'day': day }, v:val)")
let t = ''
let separator = []
for i in range(len(texts))
if i
let sep = use_month_name && (self.ymd[i - 1] ==# 'month' && self.ymd[i] ==# 'day' || self.ymd[i - 1] ==# 'day' && self.ymd[i] ==# 'month') ? ' ' : sepa
else
let sep = ''
endif
call add(separator, sep)
let t .= sep . texts[i]
endfor
let text = calendar#text#new(t, 0, 0, '')
if self.is_selected()
let separatorlen = map(copy(separator), 'len(v:val)')
let length = map(copy(self.ymd), "get({ 'year': len(year), 'month': len(month), 'day': len(day) }, v:val)")
let position = map(range(len(length)), 's:sum((v:val ? length[:(v:val - 1)] : []) + (separatorlen[:(v:val)]))')
let select = calendar#text#new(length[self.select_index], position[self.select_index], 0, 'Select')
let cursor = calendar#text#new(0, length[self.select_index] + position[self.select_index], 0, 'Cursor')
return [text, select, cursor]
else
return [text]
endif
endfunction
function! s:instance.action(action) dict abort
if index(['left', 'prev', 'line_head', 'first_line', 'last_line' ], a:action) >= 0
let self.select_index = max([self.select_index - 1, 0])
elseif index(['right', 'next', 'line_last', 'last_line_last'], a:action) >= 0
let self.select_index = min([self.select_index + 1, len(self.ymd) - 1])
elseif index(['down', 'up', 'add', 'subtract', 'plus', 'minus', 'scroll_down', 'scroll_up'], a:action) >= 0
let diff = v:count1 * (index(['down', 'add', 'plus', 'scroll_down'], a:action) >= 0 ? 1 : -1)
call b:calendar['move_' . self.ymd[self.select_index]](diff)
elseif index(['down_big', 'up_big'], a:action) >= 0
let diff = v:count1 * (a:action ==# 'down_big' ? 1 : -1)
let move_big = { 'year': 10, 'month': 3, 'day': 7 }
call b:calendar['move_' . self.ymd[self.select_index]](diff * move_big[self.ymd[self.select_index]])
elseif index(['down_large', 'up_large'], a:action) >= 0
let diff = v:count1 * (a:action ==# 'down_large' ? 1 : -1)
let move_large = { 'year': 100, 'month': 6, 'day': 14 }
call b:calendar['move_' . self.ymd[self.select_index]](diff * move_large[self.ymd[self.select_index]])
elseif a:action ==# 'bar'
let self.select_index = max([min([v:count1 - 1, len(self.ymd) - 1]), 0])
elseif a:action ==# 'space'
let self.select_index = (self.select_index + 1) % len(self.ymd)
elseif a:action ==# 'command_enter' && mode() ==# 'c' && getcmdtype() ==# ':'
let cmd = calendar#util#getcmdline()
if cmd =~# '\v^\s*\d+\s*$'
let c = matchstr(cmd, '\v\d+') * 1
if self.ymd[self.select_index] ==# 'day'
let month = b:calendar.month()
let [y, m] = month.get_ym()
let c = max([min([c, month.last_day().get_day()]), month.head_day().get_day()])
call b:calendar.move_day(b:calendar.day().new(y, m, c).sub(b:calendar.day()))
elseif self.ymd[self.select_index] ==# 'month'
let month = b:calendar.month().get_month()
let c = max([min([c, 12]), 1])
call b:calendar.move_month(c - month)
elseif self.ymd[self.select_index] ==# 'year'
call b:calendar.move_year(c - b:calendar.month().get_year())
endif
return calendar#util#update_keys()
endif
endif
endfunction
let s:super_constructor = calendar#constructor#view#new(s:instance)
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,117 @@
" =============================================================================
" Filename: autoload/calendar/constructor/year.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:04.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#constructor#year#new(day_constructor) abort
return extend({ 'day_constructor': a:day_constructor, 'cache': {} }, s:constructor)
endfunction
let s:constructor = {}
function! s:constructor.new(y) dict abort
let instance = copy(s:instance)
let instance.day_constructor = self.day_constructor
let instance._y = a:y
let instance.constructor = self
return instance
endfunction
let s:instance = {}
function! s:instance.new(y) dict abort
return self.constructor.new(a:y)
endfunction
function! s:instance.add(diff) dict abort
return self.new(self.get_y() + a:diff)
endfunction
function! s:instance.sub(year) dict abort
return self.get_y() - a:year.get_y()
endfunction
function! s:instance.eq(year) dict abort
return self.get_y() == a:year.get_y()
endfunction
function! s:instance.is_valid() dict abort
return self.head_day().is_valid() && self.last_day().is_valid()
endfunction
function! s:instance.get_y() dict abort
if has_key(self, 'y') | return self.y | endif
let self.y = self.head_day().get_ymd()[0]
return self.y
endfunction
function! s:instance.get_year() dict abort
return self.get_y()
endfunction
function! s:instance.get_month() dict abort
return self.head_day().get_month()
endfunction
function! s:instance.get_day() dict abort
return self.head_day().get_day()
endfunction
function! s:instance.head_day() dict abort
if has_key(self, '_head_day') | return self._head_day | endif
let self._head_day = self.day_constructor.new(self._y, 1, 1)
return self._head_day
endfunction
function! s:instance.last_day() dict abort
if has_key(self, '_last_day') | return self._last_day | endif
let self._last_day = self.day_constructor.new(self._y + 1, 1, 1).add(-1)
return self._last_day
endfunction
function! s:instance.head_month() dict abort
if has_key(self, '_head_month') | return self._head_month | endif
let self._head_month = self.head_day().month()
return self._head_month
endfunction
function! s:instance.last_month() dict abort
if has_key(self, '_last_month') | return self._last_month | endif
let self._last_month = self.last_day().month()
return self._last_month
endfunction
function! s:instance.days() dict abort
if has_key(self, '_days') | return self._days | endif
let self._days = self.last_day().sub(self.head_day()) + 1
return self._days
endfunction
function! s:instance.get_months() dict abort
if has_key(self, '__months') | return self.__months | endif
if has_key(self.constructor.cache, self.get_y()) | return self.constructor.cache[self.get_y()] | endif
let months = []
call add(months, self.head_month())
while !self.last_month().eq(months[-1])
call add(months, months[-1].add(1))
endwhile
let self.__months = months
let self.constructor.cache[self.get_y()] = months
return months
endfunction
function! s:instance.day() dict abort
return self.head_day()
endfunction
function! s:instance.month() dict abort
return self.head_month()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,280 @@
" =============================================================================
" Filename: autoload/calendar/controller.vim
" Author: itchyny
" License: MIT License
" Last Change: 2021/09/14 13:07:41.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Calendar controller. This object is the top-level object, b:calendar.
function! calendar#controller#new() abort
let self = deepcopy(s:self)
let self.model = calendar#model#new()
let self.view = calendar#view#new()
let self.task = calendar#task#new()
let self.event = calendar#event#new()
let self.mark = calendar#mark#new()
return self
endfunction
let s:self = {}
let s:self.pos = [0, 0]
let s:self.cursor_pos = [0, 0]
let s:self.mode = ''
let s:self.action_name = ''
let s:self.defaultsyntaxnames = ['Select', 'Sunday', 'Saturday',
\ 'TodaySunday', 'TodaySaturday', 'Today',
\ 'OtherMonth', 'OtherMonthSelect', 'DayTitle', 'SundayTitle', 'SaturdayTitle',
\ 'NormalSpace', 'Comment', 'CommentSelect']
function! s:self.time() dict abort
return self.model.time()
endfunction
function! s:self.set_time(time) dict abort
return self.model.set_time(a:time)
endfunction
function! s:self.second() dict abort
return self.model.second()
endfunction
function! s:self.minute() dict abort
return self.model.minute()
endfunction
function! s:self.hour() dict abort
return self.model.hour()
endfunction
function! s:self.move_second(diff) dict abort
call self.model.move_second(a:diff)
endfunction
function! s:self.move_minute(diff) dict abort
call self.model.move_minute(a:diff)
endfunction
function! s:self.move_hour(diff) dict abort
call self.model.move_hour(a:diff)
endfunction
function! s:self.day() dict abort
return self.model.day()
endfunction
function! s:self.set_day(day) dict abort
return self.model.set_day(a:day)
endfunction
function! s:self.month() dict abort
return self.model.month()
endfunction
function! s:self.set_month() dict abort
return self.model.set_month(self.day().month())
endfunction
function! s:self.year() dict abort
return self.model.year()
endfunction
function! s:self.get_days() dict abort
return self.model.get_days()
endfunction
function! s:self.move_day(diff) dict abort
call self.model.move_day(a:diff)
endfunction
function! s:self.move_month(diff) dict abort
call self.model.move_month(a:diff)
endfunction
function! s:self.move_year(diff) dict abort
call self.model.move_year(a:diff)
endfunction
function! s:self.start_visual() dict abort
call self.model.start_visual()
endfunction
function! s:self.start_line_visual() dict abort
call self.model.start_line_visual()
endfunction
function! s:self.start_block_visual() dict abort
call self.model.start_block_visual()
endfunction
function! s:self.exit_visual() dict abort
call self.model.exit_visual()
endfunction
function! s:self.visual_mode() dict abort
return self.model.visual_mode()
endfunction
function! s:self.is_visual() dict abort
return self.model.is_visual()
endfunction
function! s:self.is_line_visual() dict abort
return self.model.is_line_visual()
endfunction
function! s:self.is_block_visual() dict abort
return self.model.is_block_visual()
endfunction
function! s:self.visual_start_day() dict abort
return self.model.visual_start_day()
endfunction
function! s:self.visual_start_time() dict abort
return self.model.visual_start_time()
endfunction
function! s:self.go(day) dict abort
call self.set_day(a:day)
call self.set_month()
call self.update()
endfunction
function! s:self.prepare() dict abort
let [self.winheight, self.winwidth] = [calendar#util#winheight(), calendar#util#winwidth()]
call calendar#mapping#new()
call calendar#autocmd#new()
call calendar#setlocal#new()
endfunction
function! s:self.update() dict abort
call self.prepare()
call self.redraw(0)
endfunction
function! s:self.update_force() dict abort
call self.prepare()
call self.redraw(1)
endfunction
function! s:self.update_force_redraw() dict abort
call self.event.clear_cache()
call self.task.clear_cache()
call self.prepare()
call self.redraw(1, 1)
endfunction
function! s:self.update_if_resized() dict abort
if self.winheight != calendar#util#winheight() || self.winwidth != calendar#util#winwidth()
call self.update_force_redraw()
endif
endfunction
function! s:self.clear() dict abort
for name in self.defaultsyntaxnames + get(b:calendar, 'syntaxnames', [])
exec 'silent! syntax clear Calendar' . name
endfor
endfunction
function! s:self.redraw(...) dict abort
if histget(':', -1) ==# 'silent call b:calendar.update()'
silent! call histdel(':', -1)
endif
let u = self.view.gather(a:0 ? a:1 : 0)
if type(u) != type([])
return
endif
call calendar#setlocal#modifiable()
silent % delete _
if a:0 > 1 && a:2
redraw
endif
call self.clear()
call setline(1, map(range(calendar#util#winheight()), 'u[v:val].s'))
let xs = {}
let names = []
for t in u
for s in t.syn
let name = s[0]
if name !=# '' && s[1] >= 0 && s[2] >= 0
if name ==# 'Cursor'
let self.pos = [s[2], s[1]]
else
if !has_key(xs, name)
let xs[name] = []
call add(names, name)
endif
call add(xs[name], s[4] ? [s[1], s[1] + s[4] + 1, s[2] + 1, s[3] + 1] : [s[1] + 1, s[2] + 1, s[3] + 1])
endif
endif
endfor
endfor
for name in names
execute 'syntax match Calendar' . name . ' /\v' . join(map(xs[name], 'len(v:val) > 3'
\.' ? "%>" . v:val[0] . "l%<" . v:val[1] . "l%" . v:val[2] . "c.*%" . v:val[3] . "c"'
\.' : "%" . v:val[0] . "l%" . v:val[1] . "c.*%" . v:val[2] . "c"'), '|') . '/'
endfor
call self.cursor()
call calendar#setlocal#nomodifiable()
endfunction
function! s:self.cursor() dict abort
let b:calendar.cursor_pos = [self.pos[1] + 1, self.pos[0] + 1]
call cursor(b:calendar.cursor_pos[0], b:calendar.cursor_pos[1])
endfunction
function! s:self.cursor_moved() dict abort
if [line('.'), col('.')] == b:calendar.cursor_pos
return
else
let [l, c] = [line('.'), col('.')]
let [pl, pc] = b:calendar.cursor_pos
let g = getline('.')
let [wp, wn, wg] = map([getline(pl)[:pc - 2], g[:c - 2], g], 'calendar#string#strdisplaywidth(v:val)')
if pl == l
call self.action(wg <= wn * 2 && wn * 2 <= wg + 3 ? 'line_middle'
\ : g[:c - 2] =~? '^\s*$' ? 'line_head'
\ : len(g) == c ? 'line_last'
\ : pc < c ? 'right'
\ : 'left')
elseif wp - wn < 2 && wp - wn > -2
call self.action(pl < l ? 'down' : 'up')
elseif l == 1 && (c > 2 && getline(1)[:c - 2] =~? '^ *$' || c <= 2)
call self.action('first_line')
elseif l == line('$') && c > 2 && getline(1)[:c - 2] =~? '^ *$'
call self.action('last_line_last')
endif
endif
endfunction
function! s:self.action(action) dict abort
let action = a:action
if index([ 'delete', 'yank', 'change' ], action) >= 0
if self.mode ==# action
let self.mode = ''
let action .= '_line'
else
let self.mode = action
return
endif
else
let self.mode = ''
endif
let self.action_name = action
let ret = self.view.action(action)
if type(ret) == type(0) && ret == 0
call self.update()
endif
return ret
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,88 @@
" =============================================================================
" Filename: autoload/calendar/countcache.vim
" Author: itchyny
" License: MIT License
" Last Change: 2020/11/19 07:40:05.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" CountCache object, caching anything with countdown.
" Caching is imporant for speeding up. However, storing everything causes the
" cache to grow bigger and bigger. For efficient caching, this CountCache object
" is used. Basically, data are stored with numbers.
" [ num, data ]
" The number refers to how many times the data is referenced to. And when saving
" to the cache file, data are saved if the data was referenced many times enough.
" When restoring the data from the cache file, all the counts are subtracted
" one, so that data will disappear if it is not referenced to for a long time.
let s:cache = calendar#cache#new('countcache')
let s:caches = []
function! calendar#countcache#new(name) abort
let self = extend(copy(s:self), { 'name': a:name })
let cache = s:cache.get(a:name)
" When restoring from the cache file, negate each count by 1.
" Also, keep the number small (50 in max) so that the number will not overflow.
let self.cache = type(cache) == type({}) ? map(cache, '[min([v:val[0] - 1, 50]), v:val[1]]') : {}
call add(s:caches, self)
return self
endfunction
let s:saveflag = {}
let s:count = 0
" Saving the cache to the cache file.
function! calendar#countcache#save() abort
if s:count < 10
let s:count += 1
return
endif
let s:count = 0
if exists('s:reltime') && has('reltime')
let time = split(split(reltimestr(reltime(s:reltime)))[0], '\.')
if time[0] < 60
return
endif
endif
for c in s:caches
if get(s:saveflag, c.name, 1)
call s:cache.save(c.name, filter(c.cache, 'v:val[0] > 29'))
let s:saveflag[c.name] = 0
endif
endfor
if has('reltime')
let s:reltime = reltime()
endif
endfunction
augroup CalendarCountCache
autocmd!
autocmd CursorHold * call calendar#countcache#save()
augroup END
let s:self = {}
" Check if the key is found in the cache.
function! s:self.has_key(k) dict abort
return has_key(self.cache, a:k)
endfunction
" Be sure to check has_key before getting the data.
function! s:self.get(k) dict abort
let self.cache[a:k][0] += 1
return self.cache[a:k][1]
endfunction
" Save a data with a key.
function! s:self.save(k, v) dict abort
let self.cache[a:k] = [ get(self.cache, a:k, [0])[0] + 1, a:v ]
let s:saveflag[self.name] = 1
return a:v
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,78 @@
" =============================================================================
" Filename: autoload/calendar/day.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:29:20.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Day object switching the calendar based on the user's setting.
function! calendar#day#new(y, m, d) abort
return calendar#day#{calendar#setting#get('calendar')}#new(a:y, a:m, a:d)
endfunction
" Day object from mjd.
function! calendar#day#new_mjd(mjd) abort
return calendar#day#{calendar#setting#get('calendar')}#new_mjd(a:mjd)
endfunction
" Today.
function! calendar#day#today() abort
return calendar#day#new_mjd(calendar#day#today_mjd())
endfunction
" Today's mjd.
function! calendar#day#today_mjd() abort
let [y, m, d] = s:ymd()
if has_key(s:, '_y') && s:_y == [y, m, d]
return s:_m
endif
let s:_y = [y, m, d]
let s:_m = calendar#day#gregorian#new(y, m, d).mjd
return s:_m
endfunction
" Today's [ year, month, day ].
if exists('*strftime')
function! s:ymd() abort
return [strftime('%Y') * 1, strftime('%m') * 1, strftime('%d') * 1]
endfunction
else
function! s:ymd() abort
return [system('date "+%Y"') * 1, system('date "+%m"') * 1, system('date "+%d"') * 1]
endfunction
endif
" Join the year, month and day using the endian, separator settings.
function! calendar#day#join_date(ymd) abort
let endian = calendar#setting#get('date_endian')
let use_month_name = calendar#setting#get('date_month_name')
let sep1 = calendar#setting#get('date_separator')
let sep2 = use_month_name ? '' : sep1
let ymd = a:ymd
if len(a:ymd) == 3
let [y, m, d] = a:ymd
let mm = use_month_name ? calendar#message#get('month_name')[m - 1] : m
if endian ==# 'big'
let ymd = [y, sep1, mm, sep2, d]
elseif endian ==# 'middle'
let ymd = [mm, sep2, d, sep1, y]
else
let ymd = [d, sep2, mm, sep1, y]
endif
elseif len(a:ymd) == 2
let [m, d] = a:ymd
let mm = use_month_name ? calendar#message#get('month_name')[m - 1] : m
if endian ==# 'big' || endian ==# 'middle'
let ymd = [mm, sep2, d]
else
let ymd = [d, sep2, mm]
endif
endif
return join(ymd, '')
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,27 @@
" =============================================================================
" Filename: autoload/calendar/day/austria.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:32.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Brixen, Salzburg and Tyrol
let s:constructor = calendar#constructor#day_hybrid#new(1583, 10, 16)
function! calendar#day#austria#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#austria#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#austria#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,27 @@
" =============================================================================
" Filename: autoload/calendar/day/austriastyria.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:34.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Carinthia and Styria
let s:constructor = calendar#constructor#day_hybrid#new(1583, 12, 25)
function! calendar#day#austriastyria#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#austriastyria#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#austriastyria#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/british.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:36.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1752, 9, 14)
function! calendar#day#british#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#british#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#british#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/bulgaria.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:37.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1916, 4, 14)
function! calendar#day#bulgaria#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#bulgaria#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#bulgaria#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/canada.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:39.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1752, 9, 14)
function! calendar#day#canada#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#canada#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#canada#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/default.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:40.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1582, 10, 15)
function! calendar#day#default#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#default#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#default#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/estonia.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:42.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1918, 2, 14)
function! calendar#day#estonia#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#estonia#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#estonia#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/france.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:44.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1582, 12, 20)
function! calendar#day#france#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#france#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#france#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/germany.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:45.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1583, 1, 11)
function! calendar#day#germany#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#germany#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#germany#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/germanyprussia.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:47.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1610, 9, 2)
function! calendar#day#germanyprussia#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#germanyprussia#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#germanyprussia#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/greece.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:49.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1923, 3, 1)
function! calendar#day#greece#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#greece#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#greece#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,75 @@
" =============================================================================
" Filename: autoload/calendar/day/gregorian.vim
" Author: itchyny
" License: MIT License
" Last Change: 2017/05/07 22:04:31.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! s:div(x, y) abort
return a:x/a:y-((a:x<0)&&(a:x%a:y))
endfunction
function! calendar#day#gregorian#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#gregorian#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#gregorian#today() abort
return s:constructor.new_mjd(calendar#day#today_mjd())
endfunction
let s:self = {}
function! s:self.new(y, m, d) dict abort
let y = a:y - (a:m < 3)
let mjd = s:div(y*1461,4)+s:div(y,400)-s:div(y,100)+((a:m+12*(a:m<3)-3)*153+2)/5+a:d-678882
return extend(self.new_mjd(mjd), { '_ymd': [a:y, a:m, a:d] })
endfunction
function! s:self.new_mjd(mjd) dict abort
return s:constructor.new_mjd(a:mjd)
endfunction
let s:_ = {}
let s:days = { '1': 31, '2': 28, '3': 31, '4': 30, '5': 31, '6': 30, '7': 31, '8': 31, '9': 30, '10': 31, '11': 30, '12': 31 }
function! s:self.get_ymd() dict abort
if has_key(self, 'ymd') | return self.ymd | endif
let _ = self.mjd
if has_key(s:_, _) | return s:_[_] | endif
if has_key(s:_, _ - 1) && s:_[_ - 1][2] < s:days[s:_[_ - 1][1]]
let p = s:_[_ - 1]
let s:_[_] = [p[0], p[1], p[2] + 1]
return s:_[_]
endif
let a = _ + 2432045
let b = s:div(4 * a + 3, 146097)
let c = a - s:div(146097 * b, 4)
let d = (4 * c + 3) / 1461
let e = c - (1461 * d) / 4
let m = (5 * e + 2) / 153
let day = e - (153 * m + 2) / 5 + 1
let month = m + 3 - 12 * (m / 10)
let year = 100 * b + d - 4800 + m / 10
let self.ymd = [year, month, day]
let s:_[_] = self.ymd
return self.ymd
endfunction
function! s:self.is_gregorian() dict abort
return 1
endfunction
function! s:self.get_calendar() dict abort
return 'gregorian'
endfunction
let s:constructor = calendar#constructor#day#new(s:self)
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/holland.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:56.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1583, 1, 1)
function! calendar#day#holland#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#holland#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#holland#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/hungary.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:57.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1587, 11, 1)
function! calendar#day#hungary#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#hungary#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#hungary#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/italy.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:28:59.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1582, 10, 15)
function! calendar#day#italy#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#italy#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#italy#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,30 @@
" =============================================================================
" Filename: autoload/calendar/day/japan.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:29:01.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" TODO: In Japan, The calendar before switching to Gregorian's calendar was
" not Julian's. It was a lunisolar calendar. Therefore, the day before 1873/1/1
" was 1872/12/3, not 1872/12/19. For more infomation, see:
" http://en.wikipedia.org/wiki/Tenp%C5%8D_calendar
let s:constructor = calendar#constructor#day_hybrid#new(1873, 1, 1)
function! calendar#day#japan#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#japan#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#japan#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,66 @@
" =============================================================================
" Filename: autoload/calendar/day/julian.vim
" Author: itchyny
" License: MIT License
" Last Change: 2017/05/07 22:12:02.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! s:div(x, y) abort
return a:x/a:y-((a:x<0)&&(a:x%a:y))
endfunction
function! calendar#day#julian#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#julian#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#julian#today() abort
return s:constructor.new_mjd(calendar#day#today_mjd())
endfunction
let s:self = {}
function! s:self.new(y, m, d) dict abort
let y = a:y - (a:m < 3)
let mjd = s:div(y*1461,4)+((a:m+12*(a:m<3)-3)*153+2)/5+a:d-678884
return extend(self.new_mjd(mjd), { '_ymd': [a:y, a:m, a:d] })
endfunction
function! s:self.new_mjd(mjd) dict abort
return s:constructor.new_mjd(a:mjd)
endfunction
let s:_ = {}
function! s:self.get_ymd() dict abort
if has_key(self, 'ymd') | return self.ymd | endif
if has_key(s:_, self.mjd) | return s:_[self.mjd] | endif
let c = self.mjd + 678883
let d = s:div(4 * c + 3, 1461)
let e = c - s:div(1461 * d, 4)
let m = (5 * e + 2) / 153
let day = e - (153 * m + 2) / 5 + 1
let month = m + 3 - 12 * (m / 10)
let year = d + m / 10
let self.ymd = [year, month, day]
let s:_[self.mjd] = self.ymd
return self.ymd
endfunction
function! s:self.is_gregorian() dict abort
return 0
endfunction
function! s:self.get_calendar() dict abort
return 'julian'
endfunction
let s:constructor = calendar#constructor#day#new(s:self)
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/poland.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:29:08.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1582, 10, 15)
function! calendar#day#poland#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#poland#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#poland#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/portugal.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:29:09.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1582, 10, 15)
function! calendar#day#portugal#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#portugal#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#portugal#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/russia.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:29:11.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1918, 2, 14)
function! calendar#day#russia#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#russia#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#russia#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/spain.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:29:12.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1582, 10, 15)
function! calendar#day#spain#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#spain#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#spain#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/turkey.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:29:14.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1927, 1, 1)
function! calendar#day#turkey#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#turkey#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#turkey#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,26 @@
" =============================================================================
" Filename: autoload/calendar/day/us.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:29:16.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:constructor = calendar#constructor#day_hybrid#new(1752, 9, 14)
function! calendar#day#us#new(y, m, d) abort
return s:constructor.new(a:y, a:m, a:d)
endfunction
function! calendar#day#us#new_mjd(mjd) abort
return s:constructor.new_mjd(a:mjd)
endfunction
function! calendar#day#us#today() abort
return s:constructor.today()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,52 @@
" =============================================================================
" Filename: autoload/calendar/echo.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:29:23.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Echo messages.
function! calendar#echo#echo(msg) abort
echo a:msg
endfunction
function! calendar#echo#message(msg) abort
call calendar#echo#message_raw(calendar#setting#get('message_prefix') . a:msg)
endfunction
function! calendar#echo#message_raw(msg) abort
redraw
echo ''
for msg in split(a:msg, '\n')
echo msg
endfor
endfunction
function! calendar#echo#error(msg) abort
call calendar#echo#error_raw(calendar#setting#get('message_prefix') . a:msg)
endfunction
function! calendar#echo#error_raw(msg) abort
redraw
echo ''
echohl ErrorMsg
for msg in split(a:msg, '\n')
echo msg
endfor
echohl None
endfunction
function! calendar#echo#normal_message(name) abort
call calendar#echo#message(calendar#message#get(a:name))
endfunction
function! calendar#echo#error_message(name) abort
call calendar#echo#error(calendar#message#get(a:name))
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,136 @@
" =============================================================================
" Filename: autoload/calendar/event.vim
" Author: itchyny
" License: MIT License
" Last Change: 2020/10/17 01:37:16.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Event controller.
" This object handles both local and Google Calendar.
function! calendar#event#new() abort
let self = deepcopy(s:self)
if calendar#setting#get('google_calendar')
let self.event_source_name = 'google'
else
let self.event_source_name = 'local'
endif
let self.event_source = calendar#event#{self.event_source_name}#new()
return self
endfunction
let s:self = {}
let s:self.__events = {}
let s:self._holidays = {}
let s:self._updated = 0
function! s:self.updated() dict abort
if self._updated > 0
let self._updated -= 1
endif
return [self._updated]
endfunction
function! s:self.get_events_one_month(year, month, ...) dict abort
let events = self.event_source.get_events_one_month(a:year, a:month, a:0 && a:1)
if self.event_source_name !=# 'google'
let holiday = self.get_holidays(a:year, a:month)
for day in keys(holiday)
if len(holiday[day].events)
if !has_key(events, day)
let events[day] = { 'events': [] }
endif
let events[day].hasHoliday = 1
call extend(events[day].events, holiday[day].events)
let events[day].holiday = holiday[day].events[-1].summary
endif
endfor
endif
return events
endfunction
function! s:self.clear_cache() dict abort
let self.__events = {}
let self._holidays = {}
let self._updated = 10
call self.event_source.clear_cache()
endfunction
function! s:self.get_events(year, month) dict abort
let key = a:year . '-' . a:month
if self._updated > 0
let self._updated -= 1
endif
if has_key(self.__events, key) && (!calendar#setting#get('google_calendar') || get(g:, 'calendar_google_event_download', 1) <= 0) && !self._updated
return self.__events[key]
endif
let events = self.get_events_one_month(a:year, a:month, 1)
let [year, month] = calendar#day#new(a:year, a:month, 1).month().add(1).get_ym()
call extend(events, self.get_events_one_month(year, month, 0))
let [year, month] = calendar#day#new(a:year, a:month, 1).month().add(-1).get_ym()
call extend(events, self.get_events_one_month(year, month, 0))
let self.__events[key] = events
return self.__events[key]
endfunction
function! s:self.get_holidays(year, month) dict abort
let key = a:year . '-' . a:month
if has_key(self._holidays, key) && (!calendar#setting#get('google_calendar') || get(g:, 'calendar_google_event_download', 1) <= 0)
return self._holidays[key]
endif
let self._holidays[key] = calendar#google#calendar#getHolidays(a:year, a:month)
return self._holidays[key]
endfunction
function! s:self.update(calendarId, eventId, title, year, month, ...) dict abort
let self._updated = 10
return self.event_source.update(a:calendarId, a:eventId, a:title, a:year, a:month, a:0 ? a:1 : {})
endfunction
function! s:self.insert(calendarId, title, start, end, year, month, ...) dict abort
let self._updated = 10
return self.event_source.insert(a:calendarId, a:title, a:start, a:end, a:year, a:month, a:0 ? a:1 : {})
endfunction
function! s:self.move(calendarId, eventId, destination, year, month) dict abort
let self._updated = 10
return self.event_source.move(a:calendarId, a:eventId, a:destination, a:year, a:month)
endfunction
function! s:self.delete(calendarId, eventId, year, month) dict abort
let self._updated = 10
return self.event_source.delete(a:calendarId, a:eventId, a:year, a:month)
endfunction
function! s:self.createCalendar() dict abort
let self._updated = 10
return self.event_source.createCalendar()
endfunction
function! s:self.calendarList() dict abort
return self.event_source.calendarList()
endfunction
function! s:self.calendarCandidates() dict abort
let calendars = self.event_source.calendarList()
let calendar_candidates = calendar#setting#get('calendar_candidates')
if type(calendar_candidates) ==# type('') || type(calendar_candidates) ==# type([])
let cs = []
for pattern in type(calendar_candidates) ==# type('') ?
\ split(calendar_candidates, ', *') : calendar_candidates
for c in calendars
if c.summary =~# pattern
call add(cs, c)
endif
endfor
endfor
let calendars = cs
endif
return calendars
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,68 @@
" =============================================================================
" Filename: autoload/calendar/event/google.vim
" Author: itchyny
" License: MIT License
" Last Change: 2017/05/23 22:01:14.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#event#google#new() abort
return deepcopy(s:self)
endfunction
let s:self = {}
let s:self._key = {}
let s:self._events = {}
function! s:self.get_events_one_month(year, month, ...) dict abort
let key = a:year . '-' . a:month
if has_key(self._key, key) && has_key(self._events, key) && get(g:, 'calendar_google_event_download', 1) <= 0 && self._events[key] != {}
if a:0 && a:1
call calendar#google#calendar#getEventsInitial(a:year, a:month)
endif
return self._events[key]
endif
if has_key(self._key, key)
unlet self._key[key]
endif
if has_key(g:, 'calendar_google_event_download')
if get(g:, 'calendar_google_event_download') > 1
let g:calendar_google_event_download -= 1
endif
endif
let self._events[key] = calendar#google#calendar#getEvents(a:year, a:month, a:0 && a:1)
let self._key[key] = 1
return self._events[key]
endfunction
function! s:self.update(calendarId, eventId, title, year, month, ...) dict abort
call calendar#google#calendar#update(a:calendarId, a:eventId, a:title, a:year, a:month, a:0 ? a:1 : {})
endfunction
function! s:self.insert(calendarId, title, start, end, year, month, ...) dict abort
call calendar#google#calendar#insert(a:calendarId, a:title, a:start, a:end, a:year, a:month, a:0 ? a:1 : {})
endfunction
function! s:self.move(calendarId, eventId, destination, year, month) dict abort
call calendar#google#calendar#move(a:calendarId, a:eventId, a:destination, a:year, a:month)
endfunction
function! s:self.delete(calendarId, eventId, year, month) dict abort
call calendar#google#calendar#delete(a:calendarId, a:eventId, a:year, a:month)
endfunction
function! s:self.calendarList() dict abort
return calendar#google#calendar#getMyCalendarList()
endfunction
function! s:self.createCalendar() dict abort
endfunction
function! s:self.clear_cache() dict abort
call calendar#google#calendar#clearCache()
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,250 @@
" =============================================================================
" Filename: autoload/calendar/event/local.vim
" Author: itchyny
" License: MIT License
" Last Change: 2021/01/30 16:44:33.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
function! calendar#event#local#new() abort
return deepcopy(s:self)
endfunction
let s:cache = calendar#cache#new('local')
let s:event_cache = s:cache.new('event')
let s:self = {}
let s:self._key = {}
let s:self._events = {}
function! s:self.get_events_one_month(year, month, ...) dict abort
let events = {}
let calendarList = self.calendarList()
let [y, m] = [printf('%04d', a:year), printf('%02d', a:month)]
let clock_12hour = calendar#setting#get('clock_12hour')
for calendar in calendarList
let syn = calendar#color#new_syntax(get(calendar, 'id', ''), get(calendar, 'foregroundColor', ''), get(calendar, 'backgroundColor'))
unlet! c
let c = s:event_cache.new(calendar.id).new(y).new(m).get('0')
if type(c) != type({}) || type(get(c, 'items')) != type([])
continue
endif
for itm in c.items
if !(has_key(itm, 'start') && (has_key(itm.start, 'date') || has_key(itm.start, 'dateTime'))
\ && has_key(itm, 'end') && (has_key(itm.end, 'date') || has_key(itm.end, 'dateTime')))
continue
endif
let isTimeEvent = (!has_key(itm.start, 'date')) && has_key(itm.start, 'dateTime') && (!has_key(itm.end, 'date')) && has_key(itm.end, 'dateTime')
let ymd = calendar#time#datetime(get(itm.start, 'date', get(itm.start, 'dateTime', '')))
let endymd = calendar#time#datetime(get(itm.end, 'date', get(itm.end, 'dateTime', '')))
if len(ymd) != 6 || len(endymd) != 6
continue
endif
let date = join(ymd[:2], '-')
if has_key(itm.end, 'date')
let endymd = ymd[:2] == [endymd[0], endymd[1], endymd[2] - 1] ? ymd : calendar#day#new(endymd[0], endymd[1], endymd[2]).add(-1).get_ymd() + endymd[3:]
endif
if clock_12hour
let start_postfix = ymd[3] < 12 || ymd[3] == 24 ? 'am' : 'pm'
let end_postfix = endymd[3] < 12 || endymd[3] == 24 ? 'am' : 'pm'
let starttime = ymd[5] ?
\ printf('%d:%02d:%02d%s', calendar#time#hour12(ymd[3]), ymd[4], ymd[5], start_postfix ==# end_postfix ? '' : start_postfix) :
\ printf('%d:%02d%s', calendar#time#hour12(ymd[3]), ymd[4], start_postfix ==# end_postfix ? '' : start_postfix)
let endtime = endymd[5] ?
\ printf('%d:%02d:%02d%s', calendar#time#hour12(endymd[3]), endymd[4], endymd[5], end_postfix) :
\ printf('%d:%02d%s', calendar#time#hour12(endymd[3]), endymd[4], end_postfix)
else
let starttime = ymd[5] ? printf('%d:%02d:%02d', ymd[3], ymd[4], ymd[5]) : printf('%d:%02d', ymd[3], ymd[4])
let endtime = endymd[5] ? printf('%d:%02d:%02d', endymd[3], endymd[4], endymd[5]) : printf('%d:%02d', endymd[3], endymd[4])
endif
if !has_key(events, date)
let events[date] = { 'events': [] }
endif
call add(events[date].events, extend(itm,
\ { 'calendarId': calendar.id
\ , 'calendarSummary': calendar.summary
\ , 'syntax': syn
\ , 'isTimeEvent': isTimeEvent
\ , 'isHoliday': 0
\ , 'isMoon': 0
\ , 'isDayNum': 0
\ , 'isWeekNum': 0
\ , 'starttime': starttime
\ , 'endtime': endtime
\ , 'ymdnum': (((ymd[0] * 100 + ymd[1]) * 100) + ymd[2])
\ , 'hms': ymd[3:]
\ , 'sec': isTimeEvent ? ((ymd[3] * 60) + ymd[4]) * 60 + ymd[5]
\ : get(itm, 'summary', '') =~# '\v^\d\d?:\d\d(:\d\d)?\s+' ? s:extract_time_sec(itm.summary) : 0
\ , 'ymd': ymd[:2]
\ , 'endhms': endymd[3:]
\ , 'endymd': endymd[:2] }))
endfor
endfor
for date in keys(events)
call sort(events[date].events, function('s:events_sorter'))
endfor
return events
endfunction
function! s:extract_time_sec(summary) abort
let xs = matchlist(a:summary, '\v^(\d\d?):(\d\d)%(:(\d\d))?')
return ((xs[1] * 60) + xs[2]) * 60 + xs[3]
endfunction
function! s:events_sorter(x, y) abort
return a:x.calendarId ==# a:y.calendarId
\ ? (a:x.sec == a:y.sec
\ ? (get(a:x, 'summary', '') > get(a:y, 'summary', '') ? 1 : -1)
\ : a:x.sec > a:y.sec ? 1 : -1) : 0
endfunction
function! s:self.update(calendarId, eventId, title, year, month, ...) dict abort
let calendarList = self.calendarList()
let [y, m] = [printf('%04d', a:year), printf('%02d', a:month)]
for calendar in calendarList
if calendar.id ==# a:calendarId
let c = s:event_cache.new(calendar.id).new(y).new(m).get('0')
let cnt = type(c) == type({}) && has_key(c, 'items') && type(c.items) == type([]) ? c : { 'items': [] }
for i in range(len(cnt.items))
if cnt.items[i].id ==# a:eventId
let cnt.items[i].summary = a:title
call extend(cnt.items[i], a:0 ? a:1 : {})
call s:event_cache.new(calendar.id).new(y).new(m).save('0', cnt)
return
endif
endfor
endif
endfor
endfunction
function! s:self.insert(calendarId, title, start, end, year, month, ...) dict abort
let calendarList = self.calendarList()
let [y, m] = [printf('%04d', a:year), printf('%02d', a:month)]
if a:start =~# '\v^\d+[-/]\d+[-/]\d+'
let ymd = map(split(matchstr(a:start, '\v^\d+[-/]\d+[-/]\d+'), '[-/]'), 'v:val + 0')
let [y, m] = [printf('%04d', ymd[0]), printf('%02d', ymd[1])]
elseif a:start =~# '\v^\d+[-/]\d+'
let md = map(split(matchstr(a:start, '\v^\d+[-/]\d+'), '[-/]'), 'v:val + 0')
let m = printf('%04d', md[0])
endif
for calendar in calendarList
if calendar.id ==# a:calendarId
let c = s:event_cache.new(calendar.id).new(y).new(m).get('0')
let cnt = type(c) == type({}) && has_key(c, 'items') && type(c.items) == type([]) ? c : { 'items': [] }
call add(cnt.items,
\ { 'id': calendar#util#id()
\ , 'summary': a:title
\ , 'start': a:start =~# '\vT\d+' ? { 'dateTime': a:start } : { 'date': a:start }
\ , 'end': a:end =~# '\vT\d+' ? { 'dateTime': a:end } : { 'date': a:end }
\ })
call s:event_cache.new(calendar.id).new(y).new(m).save('0', cnt)
return
endif
endfor
endfunction
function! s:self.move(calendarId, eventId, destination, year, month) dict abort
let calendarList = self.calendarList()
let [y, m] = [printf('%04d', a:year), printf('%02d', a:month)]
let event = {}
for calendar in calendarList
if calendar.id ==# a:calendarId
let c = s:event_cache.new(calendar.id).new(y).new(m).get('0')
let cnt = type(c) == type({}) && has_key(c, 'items') && type(c.items) == type([]) ? c : { 'items': [] }
for i in range(len(cnt.items))
if cnt.items[i].id ==# a:eventId
let event = deepcopy(cnt.items[i])
call remove(cnt.items, i)
call s:event_cache.new(calendar.id).new(y).new(m).save('0', cnt)
break
endif
endfor
endif
endfor
for calendar in calendarList
if calendar.id ==# a:destination
let c = s:event_cache.new(calendar.id).new(y).new(m).get('0')
let cnt = type(c) == type({}) && has_key(c, 'items') && type(c.items) == type([]) ? c : { 'items': [] }
call add(cnt.items,
\ { 'id': calendar#util#id()
\ , 'summary': event.summary
\ , 'start': event.start
\ , 'end': event.end
\ })
call s:event_cache.new(calendar.id).new(y).new(m).save('0', cnt)
return
endif
endfor
endfunction
function! s:self.delete(calendarId, eventId, year, month) dict abort
let calendarList = self.calendarList()
let [y, m] = [printf('%04d', a:year), printf('%02d', a:month)]
for calendar in calendarList
if calendar.id ==# a:calendarId
let c = s:event_cache.new(calendar.id).new(y).new(m).get('0')
let cnt = type(c) == type({}) && has_key(c, 'items') && type(c.items) == type([]) ? c : { 'items': [] }
for i in range(len(cnt.items))
if cnt.items[i].id ==# a:eventId
call remove(cnt.items, i)
call s:event_cache.new(calendar.id).new(y).new(m).save('0', cnt)
return
endif
endfor
endif
endfor
endfunction
function! s:self.calendarList() dict abort
if has_key(self, '_calendarList')
return self._calendarList
endif
let self._calendarList = []
let cnt = s:cache.get('calendarList')
if type(cnt) == type({}) && has_key(cnt, 'items') && type(cnt.items) == type([])
let self._calendarList = filter(cnt.items, 'has_key(v:val, "id") && has_key(v:val, "summary")')
endif
return self._calendarList
endfunction
function! s:self.createCalendar() dict abort
let cnt = s:cache.get('calendarList')
if type(cnt) == type({}) && has_key(cnt, 'items') && type(cnt.items) == type([])
let c = cnt
else
let c = { 'items': [] }
endif
redraw
let calendarTitle = input(calendar#message#get('input_calendar_name'))
if len(calendarTitle)
let colors = []
for itm in c.items
if has_key(itm, 'backgroundColor')
call add(colors, itm.backgroundColor)
endif
endfor
let newcolors = filter(calendar#color#colors(), 'index(colors, v:val) >= 0')
if len(newcolors) == 0
let newcolors = calendar#color#colors()
endif
call add(c.items,
\ { 'id': calendar#util#id()
\ , 'summary': calendarTitle
\ , 'backgroundColor': newcolors[0]
\ , 'foregroundColor': '#000000'
\ })
call s:cache.save('calendarList', c)
if has_key(self, '_calendarList')
unlet! self._calendarList
endif
endif
endfunction
function! s:self.clear_cache() dict abort
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,618 @@
" =============================================================================
" Filename: autoload/calendar/google/calendar.vim
" Author: itchyny
" License: MIT License
" Last Change: 2020/11/19 07:40:32.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:cache = calendar#cache#new('google')
let s:event_cache = s:cache.new('event')
let g:calendar_google_event_download = 0
let g:calendar_google_event_downloading = {}
let g:calendar_google_event_downloading_list = 0
function! calendar#google#calendar#get_url(type) abort
return 'https://www.googleapis.com/calendar/v3/' . a:type
endfunction
function! calendar#google#calendar#getCalendarList() abort
let calendarList = s:cache.get('calendarList')
if (!g:calendar_google_event_downloading_list) && (type(calendarList) != type({}) ||
\ calendar#timestamp#update('google_calendarlist', 24 * 60 * 60))
let g:calendar_google_event_downloading_list = 1
call calendar#google#client#get_async(s:newid(['calendarList', 0]),
\ 'calendar#google#calendar#getCalendarList_response',
\ calendar#google#calendar#get_url('users/me/calendarList'))
endif
return type(calendarList) == type({}) ? calendarList : {}
endfunction
function! calendar#google#calendar#getCalendarList_response(id, response) abort
let [_calendarlist, err; rest] = s:getdata(a:id)
if a:response.status =~# '^2'
let cnt = calendar#webapi#decode(a:response.content)
let content = type(cnt) == type({}) ? cnt : {}
if has_key(content, 'items') && type(content.items) == type([])
let content.items = filter(deepcopy(content.items), 'get(v:val, "accessRole", "") ==# "owner"')
\ + filter(deepcopy(content.items), 'get(v:val, "accessRole", "") !=# "owner"')
call s:cache.save('calendarList', content)
let g:calendar_google_event_downloading_list = 0
let g:calendar_google_event_download = 3
silent! let b:calendar.event._updated = 3
silent! call b:calendar.update()
endif
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#get_async(s:newid(['calendarList', err + 1]),
\ 'calendar#google#calendar#getCalendarList_response',
\ calendar#google#calendar#get_url('users/me/calendarList'))
endif
endif
endfunction
function! calendar#google#calendar#getMyCalendarList() abort
let calendarList = calendar#google#calendar#getCalendarList()
let validCalendar = filter(get(deepcopy(calendarList), 'items', []), 'type(v:val) == type({}) && has_key(v:val, "summary") && has_key(v:val, "id")')
return filter(validCalendar, 'get(v:val, "selected") && (get(v:val, "accessRole", "") ==# "owner" || (get(v:val, "summary", "") !=# "Phases of the Moon") && get(v:val, "id", "") !~# "holiday@")')
endfunction
function! calendar#google#calendar#getColors() abort
let colors = s:cache.get('colors')
if calendar#timestamp#update('google_calendarcolor', 7 * 24 * 60 * 60)
call calendar#google#client#get_async(s:newid(['calendarColor', 0]),
\ 'calendar#google#calendar#getColors_response',
\ calendar#google#calendar#get_url('colors'))
endif
return type(colors) == type({}) ? colors : {}
endfunction
function! calendar#google#calendar#getColors_response(id, response) abort
let [_calendarlist, err; rest] = s:getdata(a:id)
let colors = s:cache.get('colors')
if a:response.status =~# '^2'
let cnt = calendar#webapi#decode(a:response.content)
let content = type(cnt) == type({}) ? cnt : {}
if has_key(content, 'event') && type(content.event) == type({})
call s:cache.save('colors', content)
silent! call b:calendar.update()
endif
endif
endfunction
function! calendar#google#calendar#getEventSummary(year, month) abort
let calendarList = calendar#google#calendar#getCalendarList()
let events = []
if has_key(calendarList, 'items') && type(calendarList.items) == type([]) && len(calendarList.items)
let [y, m] = [printf('%04d', a:year), printf('%02d', a:month)]
for item in calendarList.items
unlet! cnt
if get(item, 'selected')
let cnt = s:event_cache.new(item.id).new(y).new(m).get('information')
if type(cnt) == type({}) && has_key(cnt, 'summary')
call add(events, cnt)
else
call calendar#google#calendar#downloadEvents(a:year, a:month)
break
endif
endif
endfor
endif
return events
endfunction
function! calendar#google#calendar#initialDownload(year, month, index) abort
let myCalendarList = calendar#google#calendar#getMyCalendarList()
let key = join([a:year, a:month], '/')
if a:index < len(myCalendarList) && get(s:initial_download, key, 2) < 2
call calendar#async#new(printf('calendar#google#calendar#downloadEvents(%d, %d, "%s", %d)', a:year, a:month, myCalendarList[a:index].id, a:index))
endif
endfunction
let s:initial_download = {}
let s:event_download = {}
function! calendar#google#calendar#getEventsInitial(year, month) abort
let myCalendarList = calendar#google#calendar#getMyCalendarList()
let events = {}
let key = join([a:year, a:month], '/')
if !get(s:initial_download, key)
let s:initial_download[key] = 1
if len(myCalendarList) && calendar#timestamp#update(printf('google_calendar_%04d%02d', a:year, a:month), 30 * 60)
call calendar#async#new(printf('calendar#google#calendar#initialDownload(%d, %d, 0)', a:year, a:month))
endif
endif
endfunction
function! calendar#google#calendar#clearCache() abort
let s:initial_download = {}
let s:event_download = {}
unlet! g:calendar_google_event_download
call calendar#timestamp#clear()
endfunction
" The optional argument: Forcing initial download. s:initial_download is used to check.
function! calendar#google#calendar#getEvents(year, month, ...) abort
let s:is_dark = calendar#color#is_dark()
let calendarList = calendar#google#calendar#getCalendarList()
let colors = get(calendar#google#calendar#getColors(), 'event', {})
let events = {}
let key = join([a:year, a:month], '/')
if a:0 && a:1
call calendar#google#calendar#getEventsInitial(a:year, a:month)
endif
if type(get(calendarList, 'items')) != type([])
return events
endif
let [y, m] = [printf('%04d', a:year), printf('%02d', a:month)]
let clock_12hour = calendar#setting#get('clock_12hour')
for item in calendarList.items
if !get(item, 'selected')
continue
endif
let isHoliday = item.id =~# 'holiday@group.v.calendar.google.com'
let isMoon = item.summary ==# 'Phases of the Moon' && &enc ==# 'utf-8' && &fenc ==# 'utf-8'
let isDayNum = item.summary ==# 'Day of the Year'
let isWeekNum = item.summary ==# 'Week Numbers'
let calendarsyn = calendar#color#new_syntax(get(item, 'id', ''), get(item, 'foregroundColor', ''), get(item, 'backgroundColor', ''))
unlet! cnt
let cnt = s:event_cache.new(item.id).new(y).new(m).get('information')
if type(cnt) == type({}) && has_key(cnt, 'summary')
let index = 0
while 1
unlet! c
let c = s:event_cache.new(item.id).new(y).new(m).get(index)
if type(c) != type({})
break
endif
let index += 1
if type(get(c, 'items')) != type([])
continue
endif
for itm in c.items
if !(has_key(itm, 'start') && (has_key(itm.start, 'date') || has_key(itm.start, 'dateTime'))
\ && has_key(itm, 'end') && (has_key(itm.end, 'date') || has_key(itm.end, 'dateTime')))
continue
endif
if has_key(itm, 'colorId')
let foregroundColor = get(get(colors, itm.colorId, {}), 'foreground', get(item, 'foregroundColor', ''))
let backgroundColor = get(get(colors, itm.colorId, {}), 'background', get(item, 'backgroundColor', ''))
let syn = calendar#color#new_syntax(get(itm, 'id', ''), foregroundColor, backgroundColor)
else
let syn = calendarsyn
endif
let ymd = calendar#time#datetime(get(itm.start, 'date', get(itm.start, 'dateTime', '')))
let endymd = calendar#time#datetime(get(itm.end, 'date', get(itm.end, 'dateTime', '')))
let isTimeEvent = (!has_key(itm.start, 'date')) && has_key(itm.start, 'dateTime') && (!has_key(itm.end, 'date')) && has_key(itm.end, 'dateTime')
if len(ymd) != 6 || len(endymd) != 6 || [a:year, a:month] != [ymd[0], ymd[1]]
continue
endif
let date = join(ymd[:2], '-')
if has_key(itm.end, 'date')
let endymd = ymd[:2] == [endymd[0], endymd[1], endymd[2] - 1] ? ymd : calendar#day#new(endymd[0], endymd[1], endymd[2]).add(-1).get_ymd() + endymd[3:]
endif
if clock_12hour
let start_postfix = ymd[3] < 12 || ymd[3] == 24 ? 'am' : 'pm'
let end_postfix = endymd[3] < 12 || endymd[3] == 24 ? 'am' : 'pm'
let starttime = ymd[5] ?
\ printf('%d:%02d:%02d%s', calendar#time#hour12(ymd[3]), ymd[4], ymd[5], start_postfix ==# end_postfix ? '' : start_postfix) :
\ printf('%d:%02d%s', calendar#time#hour12(ymd[3]), ymd[4], start_postfix ==# end_postfix ? '' : start_postfix)
let endtime = endymd[5] ?
\ printf('%d:%02d:%02d%s', calendar#time#hour12(endymd[3]), endymd[4], endymd[5], end_postfix) :
\ printf('%d:%02d%s', calendar#time#hour12(endymd[3]), endymd[4], end_postfix)
else
let starttime = ymd[5] ? printf('%d:%02d:%02d', ymd[3], ymd[4], ymd[5]) : printf('%d:%02d', ymd[3], ymd[4])
let endtime = endymd[5] ? printf('%d:%02d:%02d', endymd[3], endymd[4], endymd[5]) : printf('%d:%02d', endymd[3], endymd[4])
endif
if !has_key(events, date)
let events[date] = { 'events': [] }
endif
call add(events[date].events,
\ extend(itm,
\ { 'calendarId': item.id
\ , 'calendarSummary': item.summary
\ , 'syntax': syn
\ , 'isTimeEvent': isTimeEvent
\ , 'isHoliday': isHoliday
\ , 'isMoon': isMoon
\ , 'isDayNum': isDayNum
\ , 'isWeekNum': isWeekNum
\ , 'starttime': starttime
\ , 'endtime': endtime
\ , 'ymdnum': (((ymd[0] * 100 + ymd[1]) * 100) + ymd[2])
\ , 'hms': ymd[3:]
\ , 'sec': isTimeEvent ? ((ymd[3] * 60) + ymd[4]) * 60 + ymd[5]
\ : get(itm, 'summary', '') =~# '\v^\d\d?:\d\d(:\d\d)?\s+' ? s:extract_time_sec(itm.summary) : 0
\ , 'ymd': ymd[:2]
\ , 'endhms': endymd[3:]
\ , 'endymd': endymd[:2] }))
if isHoliday
let events[date].holiday = events[date].events[-1].summary
let events[date].hasHoliday = 1
endif
if isMoon
call s:moon_event(events[date])
endif
if isDayNum
let events[date].daynum = matchstr(events[date].events[-1].summary, '\d\+')
endif
if isWeekNum
let events[date].weeknum = matchstr(events[date].events[-1].summary, '\d\+')
endif
endfor
endwhile
elseif !get(s:event_download, key)
let s:event_download[key] = 1
call calendar#google#calendar#downloadEvents(a:year, a:month)
break
endif
endfor
for date in keys(events)
call sort(events[date].events, function('calendar#google#calendar#sorter'))
endfor
return events
endfunction
function! s:extract_time_sec(summary) abort
let xs = matchlist(a:summary, '\v^(\d\d?):(\d\d)%(:(\d\d))?')
return ((xs[1] * 60) + xs[2]) * 60 + xs[3]
endfunction
function! calendar#google#calendar#sorter(x, y) abort
return a:x.calendarId ==# a:y.calendarId
\ ? (a:x.sec == a:y.sec
\ ? (get(a:x, 'summary', '') > get(a:y, 'summary', '') ? 1 : -1)
\ : a:x.sec > a:y.sec ? 1 : -1) : 0
endfunction
function! s:moon_event(events) abort
let s = a:events.events[-1].summary
let m = s =~# '^New moon' ? (s:is_dark ? "\u25cb" : "\u25cf")
\ : s =~# '^First quarter' ? (s:is_dark ? "\u25d1" : "\u25d0")
\ : s =~# '^Full moon' ? (s:is_dark ? "\u25cf" : "\u25cb")
\ : s =~# '^Last quarter' ? (s:is_dark ? "\u25d0" : "\u25d1")
\ : ''
let a:events.moon = calendar#string#truncate(m, 2)
if m !=# ''
let a:events.events[-1].summary = a:events.moon . ' ' . a:events.events[-1].summary
endif
endfunction
function! calendar#google#calendar#getHolidays(year, month) abort
let _calendarList = s:cache.get('calendarList')
let calendarList = type(_calendarList) == type({}) ? _calendarList : {}
let events = {}
if type(get(calendarList, 'items')) != type([])
return events
endif
let [y, m] = [printf('%04d', a:year), printf('%02d', a:month)]
for item in calendarList.items
if !get(item, 'selected') || item.id !~# 'holiday@group.v.calendar.google.com'
continue
endif
unlet! cnt
let cnt = s:event_cache.new(item.id).new(y).new(m).get('information')
if type(cnt) != type({}) || !has_key(cnt, 'summary')
continue
endif
let index = 0
while 1
unlet! c
let c = s:event_cache.new(item.id).new(y).new(m).get(index)
if type(c) != type({})
break
endif
let index += 1
if type(get(c, 'items')) != type([])
continue
endif
for itm in c.items
if !(has_key(itm, 'start') && (has_key(itm.start, 'date') || has_key(itm.start, 'dateTime'))
\ && has_key(itm, 'end') && (has_key(itm.end, 'date') || has_key(itm.end, 'dateTime')))
continue
endif
let date = has_key(itm.start, 'date') ? itm.start.date
\ : has_key(itm.start, 'dateTime') ? matchstr(itm.start.dateTime, '\d\+-\d\+-\d\+') : ''
let ymd = map(split(date, '-'), 'v:val + 0')
let enddate = has_key(itm.end, 'date') ? itm.end.date : has_key(itm.end, 'dateTime') ? matchstr(itm.end.dateTime, '\d\+-\d\+-\d\+') : ''
let endymd = map(split(enddate, '-'), 'v:val + 0')
if len(ymd) != 3 || len(endymd) != 3
continue
endif
let date = join(ymd, '-')
if has_key(itm.end, 'date')
let endymd = calendar#day#new(endymd[0], endymd[1], endymd[2]).add(-1).get_ymd()
endif
if !has_key(events, date)
let events[date] = { 'events': [], 'hasHoliday': 1 }
endif
call add(events[date].events,
\ extend(itm,
\ { 'calendarId': item.id
\ , 'calendarSummary': item.summary
\ , 'holiday': get(itm, 'summary', '')
\ , 'isHoliday': 1
\ , 'isMoon': 0
\ , 'isDayNum': 0
\ , 'isWeekNum': 0
\ , 'starttime': ''
\ , 'endtime': ''
\ , 'ymdnum': (((ymd[0] * 100 + ymd[1]) * 100) + ymd[2])
\ , 'hms': [ 0, 0, 0 ]
\ , 'ymd': ymd
\ , 'endhms': [ 0, 0, 0 ]
\ , 'endymd': endymd }))
endfor
endwhile
endfor
return events
endfunction
" The optional argument is:
" The first argument: Specify the calendar id. If this argument is given,
" the only one calendar is downloaded.
" The second argument: Initial download. See calendar#google#calendar#initialDownload.
function! calendar#google#calendar#downloadEvents(year, month, ...) abort
let calendarList = calendar#google#calendar#getCalendarList()
let key = join([a:year, a:month], '/')
if a:0 < 1
let s:initial_download[key] = 2
endif
let month = a:month + 1
let year = a:year
if month > 12
let [year, month] = [year + 1, month - 12]
endif
let [timemin, timemax] = [printf('%04d-%02d-01T00:00:00Z', a:year, a:month), printf('%04d-%02d-01T00:00:00Z', year, month)]
if has_key(g:calendar_google_event_downloading, timemin)
let g:calendar_google_event_downloading[timemin] = 1
endif
if has_key(calendarList, 'items') && type(calendarList.items) == type([]) && len(calendarList.items)
let [y, m] = [printf('%04d', a:year), printf('%02d', a:month)]
let j = 0
while j < len(calendarList.items)
let item = calendarList.items[j]
if !get(item, 'selected') || a:0 && item.id !=# a:1
let j += 1
continue
endif
unlet! cnt
let cnt = s:event_cache.new(item.id).new(y).new(m).get('information')
if type(cnt) != type({}) || !has_key(cnt, 'summary') || a:0
let opt = { 'timeMin': timemin, 'timeMax': timemax, 'singleEvents': 'true' }
call calendar#google#client#get_async(s:newid(['download', 0, 0, 0, timemin, timemax, y, m, item.id]),
\ 'calendar#google#calendar#response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(item.id) . '/events'), opt)
break
endif
let j += 1
endwhile
if a:0 > 1
call calendar#async#new(printf('calendar#google#calendar#initialDownload(%d, %d, %d)', a:year, a:month, a:2 + 1))
endif
endif
endfunction
function! calendar#google#calendar#response(id, response) abort
let calendarList = calendar#google#calendar#getCalendarList()
let [_download, err, j, i, timemin, timemax, year, month, id; rest] = s:getdata(a:id)
let opt = { 'timeMin': timemin, 'timeMax': timemax, 'singleEvents': 'true' }
if a:response.status =~# '^2'
let cnt = calendar#webapi#decode(a:response.content)
let content = type(cnt) == type({}) ? cnt : {}
if has_key(content, 'items')
call s:event_cache.new(id).new(year).new(month).save(i, content)
if i == 0
call remove(content, 'items')
call s:event_cache.new(id).new(year).new(month).save('information', content)
endif
if has_key(content, 'nextPageToken')
let opt = extend(opt, { 'pageToken': content.nextPageToken })
call calendar#google#client#get_async(s:newid(['download', err, j, i + 1, timemin, timemax, year, month, id]),
\ 'calendar#google#calendar#response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(id) . '/events'), opt)
else
let k = i + 1
while filereadable(s:event_cache.new(id).new(year).new(month).path(k))
silent! call s:event_cache.new(id).new(year).new(month).delete(k)
let k += 1
endwhile
let g:calendar_google_event_download = 2
let j += 1
while j < len(calendarList.items)
let item = calendarList.items[j]
if !get(item, 'selected')
let j += 1
continue
endif
unlet! cnt
let cnt = s:event_cache.new(item.id).new(year).new(month).get('information')
if type(cnt) != type({}) || !has_key(cnt, 'summary')
call calendar#google#client#get_async(s:newid(['download', 0, j, 0, timemin, timemax, year, month, item.id]),
\ 'calendar#google#calendar#response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(item.id) . '/events'), opt)
break
endif
let j += 1
endwhile
if j == len(calendarList.items)
let g:calendar_google_event_download = 3
silent! let b:calendar.event._updated = 5
silent! call b:calendar.update()
endif
endif
endif
elseif a:response.status == 401 || a:response.status == 404
if i == 0 && err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#get_async(s:newid(['download', err + 1, j, i, timemin, timemax, year, month, id]),
\ 'calendar#google#calendar#response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(id) . '/events'), opt)
else
call calendar#google#client#get_async_use_api_key(s:newid(['download', err + 1, j, 0, timemin, timemax, year, month, id]),
\ 'calendar#google#calendar#response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(id) . '/events'), opt)
endif
endif
endfunction
function! calendar#google#calendar#update(calendarId, eventId, title, year, month, ...) abort
let opt = a:0 ? a:1 : {}
if has_key(opt, 'start')
call s:set_timezone(a:calendarId, opt.start)
endif
if has_key(opt, 'end')
call s:set_timezone(a:calendarId, opt.end)
endif
let location = matchstr(a:title, '\%( at \)\@<=.\+$')
let opt = extend(opt, len(location) ? { 'location': location } : {})
call calendar#google#client#patch_async(s:newid(['update', 0, a:year, a:month, a:calendarId, a:eventId, a:title, opt]),
\ 'calendar#google#calendar#update_response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(a:calendarId) . '/events/' . a:eventId),
\ { 'calendarId': a:calendarId, 'eventId': a:eventId },
\ extend({ 'id': a:eventId, 'summary': a:title }, opt))
endfunction
function! calendar#google#calendar#update_response(id, response) abort
let [_update, err, year, month, calendarId, eventId, title, opt; rest] = s:getdata(a:id)
if a:response.status =~# '^2'
call calendar#google#calendar#downloadEvents(year, month, calendarId)
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#patch_async(s:newid(['update', 1, year, month, calendarId, eventId, title, opt]),
\ 'calendar#google#calendar#update_response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(calendarId) . '/events/' . eventId),
\ { 'calendarId': calendarId, 'eventId': eventId },
\ extend({ 'id': eventId, 'summary': title }, opt))
else
call calendar#webapi#echo_error(a:response)
endif
else
call calendar#webapi#echo_error(a:response)
endif
endfunction
function! calendar#google#calendar#insert(calendarId, title, start, end, year, month, ...) abort
let start = a:start =~# 'T\d' && len(a:start) > 10 ? { 'dateTime': a:start } : { 'date': a:start }
let end = a:end =~# 'T\d' && len(a:end) > 10 ? { 'dateTime': a:end } : { 'date': a:end }
let location = matchstr(a:title, '\%( at \)\@<=.\+$')
let opt = len(location) ? { 'location': location } : {}
let recurrence = a:0 ? a:1 : {}
if has_key(recurrence, 'week') || has_key(recurrence, 'day')
call extend(opt, { 'recurrence': [ 'RRULE:' . (
\ has_key(recurrence, 'week') ? ('FREQ=WEEKLY;COUNT=' . recurrence.week) :
\ has_key(recurrence, 'day') ? ('FREQ=DAILY;COUNT=' . recurrence.day) :
\ '') ] })
endif
call s:set_timezone(a:calendarId, start)
call s:set_timezone(a:calendarId, end)
call calendar#google#client#post_async(s:newid(['insert', 0, a:year, a:month, a:calendarId, start, end, a:title, opt]),
\ 'calendar#google#calendar#insert_response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(a:calendarId) . '/events'),
\ { 'calendarId': a:calendarId },
\ extend({ 'summary': a:title, 'start': start, 'end': end, 'transparency': 'transparent' }, opt))
endfunction
function! calendar#google#calendar#insert_response(id, response) abort
let [_insert, err, year, month, calendarId, start, end, title, opt; rest] = s:getdata(a:id)
if a:response.status =~# '^2'
call calendar#google#calendar#downloadEvents(year, month, calendarId)
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#post_async(s:newid(['insert', 1, year, month, calendarId, start, end, title, opt]),
\ 'calendar#google#calendar#insert_response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(calendarId) . '/events'),
\ { 'calendarId': calendarId },
\ extend({ 'summary': title, 'start': start, 'end': end, 'transparency': 'transparent' }, opt))
endif
else
call calendar#webapi#echo_error(a:response)
endif
endfunction
function! calendar#google#calendar#move(calendarId, eventId, destination, year, month) abort
call calendar#google#client#post_async(s:newid(['move', 0, a:year, a:month, a:calendarId, a:eventId, a:destination]),
\ 'calendar#google#calendar#move_response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(a:calendarId) . '/events/' . a:eventId . '/move'),
\ { 'destination': a:destination }, {})
endfunction
function! calendar#google#calendar#move_response(id, response) abort
let [_move, err, year, month, calendarId, eventId, destination; rest] = s:getdata(a:id)
if a:response.status =~# '^2'
call calendar#google#calendar#downloadEvents(year, month, calendarId)
call calendar#google#calendar#downloadEvents(year, month, destination)
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#patch_async(s:newid(['move', 1, year, month, calendarId, eventId, destination]),
\ 'calendar#google#calendar#move_response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(calendarId) . '/events/' . eventId . '/move'),
\ { 'destination': destination }, {})
else
call calendar#webapi#echo_error(a:response)
endif
else
call calendar#webapi#echo_error(a:response)
endif
endfunction
function! calendar#google#calendar#delete(calendarId, eventId, year, month) abort
call calendar#google#client#delete_async(s:newid(['delete', 0, a:year, a:month, a:calendarId, a:eventId]),
\ 'calendar#google#calendar#delete_response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(a:calendarId) . '/events/' . a:eventId),
\ { 'calendarId': a:calendarId, 'eventId': a:eventId }, {})
endfunction
function! calendar#google#calendar#delete_response(id, response) abort
let [_delete, err, year, month, calendarId, eventId; rest] = s:getdata(a:id)
if a:response.status =~# '^2' || a:response.status ==# '410'
call calendar#google#calendar#downloadEvents(year, month, calendarId)
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#delete_async(s:newid(['delete', 1, year, month, calendarId, eventId]),
\ 'calendar#google#calendar#delete_response',
\ calendar#google#calendar#get_url('calendars/' . s:event_cache.escape(calendarId) . '/events/' . eventId),
\ { 'calendarId': calendarId, 'eventId': eventId })
else
call calendar#webapi#echo_error(a:response)
endif
else
call calendar#webapi#echo_error(a:response)
endif
endfunction
function! s:set_timezone(calendarId, obj) abort
let timezone = calendar#setting#get('time_zone')
if has_key(a:obj, 'dateTime')
let a:obj.dateTime .= timezone
else
let a:obj.timeZone = timezone
endif
if has_key(a:obj, 'dateTime')
let a:obj.date = function('calendar#webapi#null')
elseif has_key(a:obj, 'date')
let a:obj.dateTime = function('calendar#webapi#null')
endif
endfunction
let s:id_data = {}
function! s:newid(data) abort
let id = join([ 'google', 'calendar', a:data[0] ], '_') . '_' . calendar#util#id()
let s:id_data[id] = a:data
return id
endfunction
function! s:getdata(id) abort
return s:id_data[a:id]
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,196 @@
" =============================================================================
" Filename: autoload/calendar/google/client.vim
" Author: itchyny
" License: MIT License
" Last Change: 2020/11/30 20:02:44.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:cache = calendar#cache#new('google')
let s:auth_url = 'https://accounts.google.com/o/oauth2/auth'
let s:token_url = 'https://accounts.google.com/o/oauth2/token'
function! s:client() abort
return extend(deepcopy(calendar#setting#get('google_client')), { 'response_type': 'code' })
endfunction
function! s:get_url() abort
let client = s:client()
let param = {}
for x in ['client_id', 'redirect_uri', 'scope', 'response_type']
if has_key(client, x)
let param[x] = client[x]
endif
endfor
return s:auth_url . '?' . calendar#webapi#encodeURI(param)
endfunction
function! calendar#google#client#access_token() abort
let cache = s:cache.get('access_token')
if type(cache) != type({}) || type(cache) == type({}) && !has_key(cache, 'access_token')
call calendar#google#client#initialize_access_token()
let cache = s:cache.get('access_token')
if type(cache) != type({}) || type(cache) == type({}) && !has_key(cache, 'access_token')
return 1
endif
let content = cache
else
let content = cache
endif
return content.access_token
endfunction
function! calendar#google#client#initialize_access_token() abort
let client = s:client()
let url = s:get_url()
call calendar#webapi#open_url(url)
try
let code = input(printf(calendar#message#get('access_url_input_code'), url) . "\n" . calendar#message#get('input_code'))
catch
return
endtry
if code !=# ''
let response = calendar#webapi#post_nojson(s:token_url, {}, {
\ 'client_id': client.client_id,
\ 'client_secret': client.client_secret,
\ 'code': code,
\ 'redirect_uri': client.redirect_uri,
\ 'grant_type': 'authorization_code'})
let content = calendar#webapi#decode(response.content)
if calendar#google#client#access_token_response(response, content)
return
endif
else
return
endif
let g:calendar_google_event_downloading_list = 0
let g:calendar_google_event_download = 3
silent! let b:calendar.event._updated = 3
endfunction
function! calendar#google#client#refresh_token() abort
let client = s:client()
let cache = s:cache.get('refresh_token')
if type(cache) == type({}) && has_key(cache, 'refresh_token') && type(cache.refresh_token) == type('')
let response = calendar#webapi#post_nojson(s:token_url, {}, {
\ 'client_id': client.client_id,
\ 'client_secret': client.client_secret,
\ 'refresh_token': cache.refresh_token,
\ 'grant_type': 'refresh_token'})
let content = calendar#webapi#decode(response.content)
if calendar#google#client#access_token_response(response, content)
return 1
endif
return content.access_token
else
return 1
endif
endfunction
function! calendar#google#client#access_token_response(response, content) abort
if a:response.status == 200
if !has_key(a:content, 'access_token')
call calendar#echo#error_message('google_access_token_fail')
return 1
else
call s:cache.save('access_token', a:content)
if has_key(a:content, 'refresh_token') && type(a:content.refresh_token) == type('')
call s:cache.save('refresh_token', { 'refresh_token': a:content.refresh_token })
endif
endif
else
call calendar#echo#error_message('google_access_token_fail')
return 1
endif
endfunction
function! calendar#google#client#get(url, ...) abort
return s:request('get', a:url, a:0 ? a:1 : {}, a:0 > 1 ? a:2 : {})
endfunction
function! calendar#google#client#put(url, ...) abort
return s:request('put', a:url, a:0 ? a:1 : {}, a:0 > 1 ? a:2 : {})
endfunction
function! calendar#google#client#post(url, ...) abort
return s:request('post', a:url, a:0 ? a:1 : {}, a:0 > 1 ? a:2 : {})
endfunction
function! calendar#google#client#delete(url, ...) abort
return s:request('delete', a:url, a:0 ? a:1 : {}, a:0 > 1 ? a:2 : {})
endfunction
function! s:request(method, url, param, body) abort
let client = s:client()
let access_token = calendar#google#client#access_token()
if type(access_token) != type('')
return 1
endif
let param = extend(a:param, { 'oauth_token': access_token })
let response = calendar#webapi#{a:method}(a:url, param, a:body)
if response.status == 200
return calendar#webapi#decode(response.content)
elseif response.status == 401
unlet! access_token
let access_token = calendar#google#client#refresh_token()
if type(access_token) != type('')
return 1
endif
let param = extend(a:param, { 'oauth_token': access_token })
let response = calendar#webapi#{a:method}(a:url, param, a:body)
if response.status == 200
return calendar#webapi#decode(response.content)
endif
endif
return 1
endfunction
function! calendar#google#client#get_async(id, cb, url, ...) abort
call s:request_async(a:id, a:cb, 'get', a:url, a:0 ? a:1 : {}, a:0 > 1 ? a:2 : {})
endfunction
function! calendar#google#client#delete_async(id, cb, url, ...) abort
call s:request_async(a:id, a:cb, 'delete', a:url, a:0 ? a:1 : {}, a:0 > 1 ? a:2 : {})
endfunction
function! calendar#google#client#put_async(id, cb, url, ...) abort
call s:request_async(a:id, a:cb, 'put', a:url, a:0 ? a:1 : {}, a:0 > 1 ? a:2 : {})
endfunction
function! calendar#google#client#patch_async(id, cb, url, ...) abort
call s:request_async(a:id, a:cb, 'patch', a:url, a:0 ? a:1 : {}, a:0 > 1 ? a:2 : {})
endfunction
function! calendar#google#client#post_async(id, cb, url, ...) abort
call s:request_async(a:id, a:cb, 'post', a:url, a:0 ? a:1 : {}, a:0 > 1 ? a:2 : {})
endfunction
function! s:request_async(id, cb, method, url, param, body) abort
let access_token = calendar#google#client#access_token()
if type(access_token) != type('')
return 1
endif
let param = extend(a:param, { 'oauth_token': access_token })
call calendar#webapi#{a:method}_async(a:id, a:cb, a:url, param, a:body)
endfunction
function! calendar#google#client#get_async_use_api_key(id, cb, url, ...) abort
call s:request_async_use_api_key(a:id, a:cb, 'get', a:url, a:0 ? a:1 : {}, a:0 > 1 ? a:2 : {})
endfunction
function! calendar#google#client#post_async_use_api_key(id, cb, url, ...) abort
call s:request_async_use_api_key(a:id, a:cb, 'post', a:url, a:0 ? a:1 : {}, a:0 > 1 ? a:2 : {})
endfunction
function! s:request_async_use_api_key(id, cb, method, url, param, body) abort
let client = s:client()
let param = extend(a:param, { 'key': client.api_key })
call calendar#webapi#{a:method}_async(a:id, a:cb, a:url, param, a:body)
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,440 @@
" =============================================================================
" Filename: autoload/calendar/google/task.vim
" Author: itchyny
" License: MIT License
" Last Change: 2021/09/18 13:24:16.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
let s:cache = calendar#cache#new('google')
let s:task_cache = s:cache.new('task')
function! calendar#google#task#get_url(type) abort
return 'https://www.googleapis.com/tasks/v1/' . a:type
endfunction
function! calendar#google#task#getTaskList() abort
let taskList = s:cache.get('taskList')
if type(taskList) != type({}) || calendar#timestamp#update('google_tasklist', 7 * 24 * 60 * 60)
call calendar#google#client#get_async(s:newid(['taskList', 0]),
\ 'calendar#google#task#getTaskList_response',
\ calendar#google#task#get_url('users/@me/lists'))
if type(taskList) != type({})
return {}
endif
endif
return taskList
endfunction
function! calendar#google#task#getTaskList_response(id, response) abort
let [_tasklist, err; rest] = s:getdata(a:id)
if a:response.status =~# '^2'
let cnt = calendar#webapi#decode(a:response.content)
let content = type(cnt) == type({}) ? cnt : {}
if has_key(content, 'items') && type(content.items) == type([])
call s:cache.save('taskList', content)
silent! let b:calendar.task._updated = 1
silent! call b:calendar.update()
endif
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#get_async(s:newid(['taskList', err + 1]),
\ 'calendar#google#task#getTaskList_response',
\ calendar#google#task#get_url('users/@me/lists'))
endif
endif
endfunction
function! calendar#google#task#getTasks() abort
if calendar#timestamp#update('google_task', 30 * 60)
call calendar#async#new('calendar#google#task#downloadTasks(1)')
endif
let allTaskList = []
let taskList = calendar#google#task#getTaskList()
if has_key(taskList, 'items') && type(taskList.items) == type([])
for tasklist in taskList.items
call add(allTaskList, tasklist)
let allTaskList[-1].items = []
unlet! cnt
let cnt = s:task_cache.new(tasklist.id).get('information')
if type(cnt) == type({}) && cnt != {}
let i = 0
let allTaskList[-1].etag = cnt.etag
let items = []
while type(cnt) == type({})
unlet! cnt
let cnt = s:task_cache.new(tasklist.id).get(i)
if type(cnt) == type({}) && cnt != {} && has_key(cnt, 'items') && type(cnt.items) == type([])
call extend(items, cnt.items)
endif
let i += 1
endwhile
for item in items
if has_key(item, 'due') && item.due =~# '\v\d+-\d+-\d+T'
let [y, m, d] = map(split(substitute(substitute(item.due, 'T.*', '', ''), '\s', '', 'g'), '[-/]'), 'substitute(v:val, "^0", "", "") + 0')
let item.title = calendar#day#join_date([y, m, d]) . ' ' . get(item, 'title', '')
call remove(item, 'due')
endif
if has_key(item, 'notes') && item.notes !=# ''
let item.title = get(item, 'title', '') . ' note: ' . get(item, 'notes', '')
endif
endfor
call sort(items, function('calendar#google#task#sorter'))
let i = 0
while i < len(items)
if !has_key(items[i], 'parent')
break
endif
let j = i + 1
let items[i].prefix = ' +- '
while j < len(items)
if items[j].id ==# items[i].parent
while j < len(items) - 1
if get(items[j + 1], 'parent', '') ==# items[i].parent
let items[j + 1].prefix = ' |- '
let j += 1
else
break
endif
endwhile
call insert(items, items[i], j + 1)
call remove(items, i)
let i -= 1
break
endif
let j += 1
endwhile
let i += 1
endwhile
let allTaskList[-1].items = items
else
call calendar#google#task#downloadTasks()
endif
endfor
endif
return allTaskList
endfunction
function! calendar#google#task#sorter(x, y) abort
return has_key(a:x, 'parent') != has_key(a:y, 'parent')
\ ? (has_key(a:x, 'parent') ? -1 : 1)
\ : a:x.position ==# a:y.position
\ ? (a:x.updated > a:y.updated ? 1 : -1)
\ : a:x.position > a:y.position ? 1 : -1
endfunction
" Optional argument: Force download.
function! calendar#google#task#downloadTasks(...) abort
let taskList = calendar#google#task#getTaskList()
if has_key(taskList, 'items') && type(taskList.items) == type([]) && len(taskList.items)
let j = 0
while j < len(taskList.items)
let item = taskList.items[j]
unlet! cnt
let cnt = s:task_cache.new(item.id).get('information')
if type(cnt) != type({}) || cnt == {} || get(a:000, 0) && (a:0 <= 1 || item.id ==# get(a:000, 1, ''))
let opt = { 'tasklist': item.id, 'maxResults': 100 }
call calendar#google#client#get_async(s:newid(['download', 0, j, 0, item.id, a:000]),
\ 'calendar#google#task#response',
\ calendar#google#task#get_url('lists/' . item.id . '/tasks'), opt)
break
endif
let j += 1
endwhile
if j == len(taskList.items)
silent! let b:calendar.task._updated = 1
silent! call b:calendar.update()
endif
endif
endfunction
function! calendar#google#task#response(id, response) abort
let taskList = calendar#google#task#getTaskList()
let [_download, err, j, i, id, force; rest] = s:getdata(a:id)
let opt = { 'tasklist': id }
if a:response.status =~# '^2'
let cnt = calendar#webapi#decode(a:response.content)
let content = type(cnt) == type({}) ? cnt : {}
if has_key(content, 'items')
call s:task_cache.new(id).save(i, content)
if i == 0
call remove(content, 'items')
call s:task_cache.new(id).save('information', content)
endif
if has_key(content, 'nextPageToken')
let opt = extend(opt, { 'pageToken': content.nextPageToken })
call calendar#google#client#get_async(s:newid(['download', err, j, i + 1, id, force]),
\ 'calendar#google#task#response',
\ calendar#google#task#get_url('lists/' . id . '/tasks'), opt)
else
let k = i + 1
while filereadable(s:task_cache.new(id).path(k))
silent! call s:task_cache.new(id).delete(k)
let k += 1
endwhile
let j += 1
while j < len(taskList.items)
let item = taskList.items[j]
unlet! cnt
let cnt = s:task_cache.new(item.id).get('information')
let opt = { 'tasklist': item.id, 'maxResults': 100 }
if type(cnt) != type({}) || cnt == {} || get(force, 0) && (len(force) <= 1 || item.id ==# get(force, 1, ''))
call calendar#google#client#get_async(s:newid(['download', 0, j, 0, item.id, force]),
\ 'calendar#google#task#response',
\ calendar#google#task#get_url('lists/' . item.id . '/tasks'), opt)
break
endif
let j += 1
endwhile
if j == len(taskList.items)
silent! let b:calendar.task._updated = 1
silent! call b:calendar.update()
endif
endif
elseif i == 0 && has_key(content, 'etag')
let k = 0
while filereadable(s:task_cache.new(id).path(k))
silent! call s:task_cache.new(id).delete(k)
let k += 1
endwhile
if k > 0
silent! let b:calendar.task._updated = 1
silent! call b:calendar.update()
endif
endif
elseif a:response.status == 401
if i == 0 && err == 0
let opt = { 'tasklist': id }
call calendar#google#client#refresh_token()
call calendar#google#client#get_async(s:newid(['download', err + 1, j, i, id, force]),
\ 'calendar#google#task#response',
\ calendar#google#task#get_url('lists/' . id . '/tasks'), opt)
endif
endif
endfunction
function! calendar#google#task#insert(id, previous, parent, title, ...) abort
let opt = { 'tasklist': a:id }
if a:previous !=# ''
let opt.previous = a:previous
endif
if a:parent !=# ''
let opt.parent = a:parent
endif
let due = ''
if a:0
let due = get(a:1, 'due', '')
if due !=# ''
let due = due . (due =~# 'Z$' ? '' : 'Z')
endif
endif
let note = ''
if a:title =~# ' note: '
let note = matchstr(a:title, ' note: .*$')
let title = a:title[:(len(a:title) - len(note)) - 1]
let note = substitute(note, ' note:\s*', '', '')
else
let note = ''
let title = a:title
endif
call calendar#google#client#post_async(s:newid(['insert', 0, a:id, title, note, due, opt]),
\ 'calendar#google#task#insert_response',
\ calendar#google#task#get_url('lists/' . a:id . '/tasks'),
\ opt, extend({ 'title': title, 'notes': note }, due ==# '' ? {} : { 'due': due ==# '-1Z' ? function('calendar#webapi#null') : due }))
endfunction
function! calendar#google#task#insert_response(id, response) abort
let [_insert, err, id, title, note, due, opt; rest] = s:getdata(a:id)
if a:response.status =~# '^2'
call calendar#google#task#downloadTasks(1, id)
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#post_async(s:newid(['insert', 1, id, title, note, due, opt]),
\ 'calendar#google#task#insert_response',
\ calendar#google#task#get_url('lists/' . id . '/tasks'),
\ opt, extend({ 'title': title, 'notes': note }, due ==# '' ? {} : { 'due': due ==# '-1Z' ? function('calendar#webapi#null') : due }))
endif
endif
endfunction
function! calendar#google#task#move(id, taskid, previous, parent) abort
let opt = { 'tasklist': a:id }
if a:previous !=# ''
let opt.previous = a:previous
endif
if a:parent !=# ''
let opt.parent = a:parent
endif
call calendar#google#client#post_async(s:newid(['move', 0, a:id, a:taskid, opt]),
\ 'calendar#google#task#move_response',
\ calendar#google#task#get_url('lists/' . a:id . '/tasks/' . a:taskid . '/move'),
\ opt, {})
endfunction
function! calendar#google#task#move_response(id, response) abort
let [_move, err, id, taskid, opt; rest] = s:getdata(a:id)
if a:response.status =~# '^2'
call calendar#google#task#downloadTasks(1, id)
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#post_async(s:newid(['move', 1, id, taskid, opt]),
\ 'calendar#google#task#move_response',
\ calendar#google#task#get_url('lists/' . id . '/tasks/' . taskid . '/move'),
\ opt, {})
endif
endif
endfunction
function! calendar#google#task#clear_completed(id) abort
call calendar#google#client#post_async(s:newid(['clear_completed', 0, a:id]),
\ 'calendar#google#task#clear_completed_response',
\ calendar#google#task#get_url('lists/' . a:id . '/clear'),
\ { 'tasklist': a:id })
endfunction
function! calendar#google#task#clear_completed_response(id, response) abort
let [_clear_completed, err, id; rest] = s:getdata(a:id)
if a:response.status =~# '^2'
call calendar#google#task#downloadTasks(1, id)
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#post_async(s:newid(['clear_completed', 1, id]),
\ 'calendar#google#task#clear_completed_response',
\ calendar#google#task#get_url('lists/' . id . '/clear'),
\ { 'tasklist': id })
endif
endif
endfunction
function! calendar#google#task#update(id, taskid, title, ...) abort
let due = ''
if a:0
let due = get(a:1, 'due', '')
if due !=# ''
let due = due . (due =~# 'Z$' ? '' : 'Z')
endif
endif
let note = ''
if a:title =~# ' note: '
let note = matchstr(a:title, ' note: .*$')
let title = a:title[:(len(a:title) - len(note)) - 1]
let note = substitute(note, ' note:\s*', '', '')
else
let note = ''
let title = a:title
endif
call calendar#google#client#put_async(s:newid(['update', 0, a:id, a:taskid, title, note, due]),
\ 'calendar#google#task#update_response',
\ calendar#google#task#get_url('lists/' . a:id . '/tasks/' . a:taskid),
\ { 'tasklist': a:id, 'task': a:taskid },
\ extend({ 'id': a:taskid, 'title': title, 'notes': note }, due ==# '' ? {} : { 'due': due ==# '-1Z' ? function('calendar#webapi#null') : due }))
endfunction
function! calendar#google#task#update_response(id, response) abort
let [_update, err, id, taskid, title, note, due; rest] = s:getdata(a:id)
if a:response.status =~# '^2'
call calendar#google#task#downloadTasks(1, id)
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#put_async(s:newid(['update', 1, id, taskid, title, note, due]),
\ 'calendar#google#task#update_response',
\ calendar#google#task#get_url('lists/' . id . '/tasks/' . taskid),
\ { 'tasklist': id, 'task': taskid },
\ extend({ 'id': taskid, 'title': title, 'notes': note }, due ==# '' ? {} : { 'due': due ==# '-1Z' ? function('calendar#webapi#null') : due }))
endif
endif
endfunction
function! calendar#google#task#complete(id, taskid) abort
call calendar#google#client#patch_async(s:newid(['complete', 0, a:id, a:taskid]),
\ 'calendar#google#task#complete_response',
\ calendar#google#task#get_url('lists/' . a:id . '/tasks/' . a:taskid),
\ { 'tasklist': a:id, 'task': a:taskid },
\ { 'id': a:taskid, 'status': 'completed' })
endfunction
function! calendar#google#task#complete_response(id, response) abort
let [_complete, err, id, taskid; rest] = s:getdata(a:id)
if a:response.status =~# '^2'
call calendar#google#task#downloadTasks(1, id)
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#patch_async(s:newid(['complete', 1, id, taskid]),
\ 'calendar#google#task#complete_response',
\ calendar#google#task#get_url('lists/' . id . '/tasks/' . taskid),
\ { 'tasklist': id, 'task': taskid },
\ { 'id': taskid, 'status': 'completed' })
endif
endif
endfunction
function! calendar#google#task#uncomplete(id, taskid) abort
call calendar#google#client#patch_async(s:newid(['uncomplete', 0, a:id, a:taskid]),
\ 'calendar#google#task#uncomplete_response',
\ calendar#google#task#get_url('lists/' . a:id . '/tasks/' . a:taskid),
\ { 'tasklist': a:id, 'task': a:taskid },
\ { 'id': a:taskid, 'status': 'needsAction' })
endfunction
function! calendar#google#task#uncomplete_response(id, response) abort
let [_uncomplete, err, id, taskid; rest] = s:getdata(a:id)
if a:response.status =~# '^2'
call calendar#google#task#downloadTasks(1, id)
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#patch_async(s:newid(['uncomplete', 1, id, taskid]),
\ 'calendar#google#task#uncomplete_response',
\ calendar#google#task#get_url('lists/' . id . '/tasks/' . taskid),
\ { 'tasklist': id, 'task': taskid },
\ { 'id': taskid, 'status': 'needsAction' })
endif
endif
endfunction
function! calendar#google#task#delete(id, taskid) abort
call calendar#google#client#delete_async(s:newid(['delete', 0, a:id, a:taskid]),
\ 'calendar#google#task#delete_response',
\ calendar#google#task#get_url('lists/' . a:id . '/tasks/' . a:taskid),
\ { 'tasklist': a:id, 'task': a:taskid },
\ { 'id': a:taskid })
endfunction
function! calendar#google#task#delete_response(id, response) abort
let [_delete, err, id, taskid; rest] = s:getdata(a:id)
if a:response.status =~# '^2'
call calendar#google#task#downloadTasks(1, id)
elseif a:response.status == 401
if err == 0
call calendar#google#client#refresh_token()
call calendar#google#client#delete_async(s:newid(['delete', 1, id, taskid]),
\ 'calendar#google#task#delete_response',
\ calendar#google#task#get_url('lists/' . id . '/tasks/' . taskid),
\ { 'tasklist': id, 'task': taskid },
\ { 'id': taskid })
endif
endif
endfunction
let s:id_data = {}
function! s:newid(data) abort
let id = join([ 'google', 'task', a:data[0] ], '_') . '_' . calendar#util#id()
let s:id_data[id] = a:data
return id
endfunction
function! s:getdata(id) abort
return s:id_data[a:id]
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,243 @@
" =============================================================================
" Filename: autoload/calendar/mapping.vim
" Author: itchyny
" License: MIT License
" Last Change: 2019/08/07 21:21:45.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Setting mappings in the calendar buffer.
function! calendar#mapping#new() abort
let save_cpo = &cpo
set cpo&vim
if has_key(get(b:, 'calendar', {}), 'view')
let v = b:calendar.view
if maparg('<ESC>', 'n') !=# '<Plug>(calendar_escape)'
if v.help_visible() || v.event_visible() || v.task_visible() || b:calendar.visual_mode()
if v:version > 703
nmap <buffer><nowait> <ESC> <Plug>(calendar_escape)
else
nmap <buffer> <ESC> <Plug>(calendar_escape)
endif
endif
else
if !(v.help_visible() || v.event_visible() || v.task_visible() || b:calendar.visual_mode())
nunmap <buffer> <ESC>
endif
endif
endif
if &l:filetype ==# 'calendar'
let &cpo = save_cpo
return
endif
" normal mode mapping
let actions = ['left', 'right', 'down', 'up', 'prev', 'next', 'move_down', 'move_up', 'move_event',
\ 'down_big', 'up_big', 'down_large', 'up_large',
\ 'line_head', 'line_middle', 'line_last', 'bar',
\ 'first_line', 'last_line', 'first_line_head', 'last_line_last', 'space',
\ 'scroll_down', 'scroll_up', 'scroll_top_head', 'scroll_top',
\ 'scroll_center_head', 'scroll_center', 'scroll_bottom_head', 'scroll_bottom',
\ 'add', 'subtract', 'status', 'plus', 'minus', 'task', 'event', 'close_task', 'close_event',
\ 'delete', 'delete_line', 'yank', 'yank_line', 'change', 'change_line',
\ 'undo', 'undo_line', 'tab', 'shift_tab', 'next_match', 'prev_match',
\ 'today', 'enter', 'view_left', 'view_right', 'redraw', 'clear', 'help', 'hide', 'exit',
\ 'visual', 'visual_line', 'visual_block', 'exit_visual',
\ 'start_insert', 'start_insert_append', 'start_insert_head', 'start_insert_last',
\ 'start_insert_prev_line', 'start_insert_next_line', 'start_insert_quick',
\ ]
for action in actions
exec printf("nnoremap <buffer><silent> <Plug>(calendar_%s) :<C-u>call b:calendar.action('%s')<CR>", action, action)
endfor
" escape
nmap <buffer><silent><expr> <Plug>(calendar_escape)
\ b:calendar.view.help_visible() ? "\<Plug>(calendar_help)" :
\ b:calendar.view.event_visible() ? "\<Plug>(calendar_event)" :
\ b:calendar.visual_mode() ? "\<Plug>(calendar_exit_visual)" :
\ b:calendar.view.task_visible() ? "\<Plug>(calendar_task)" :
\ ""
" mark
let marks = map(range(97, 97 + 25), 'nr2char(v:val)')
for mark in marks
exec printf("nmap <buffer><silent> m%s :<C-u>call b:calendar.mark.set('%s')<CR>", mark, mark)
exec printf("nmap <buffer><silent> `%s :<C-u>call b:calendar.mark.get('%s')<CR>", mark, mark)
exec printf("nmap <buffer><silent> '%s :<C-u>call b:calendar.mark.get('%s')<CR>", mark, mark)
exec printf("nmap <buffer><silent> g`%s :<C-u>call b:calendar.mark.get('%s')<CR>", mark, mark)
exec printf("nmap <buffer><silent> g'%s :<C-u>call b:calendar.mark.get('%s')<CR>", mark, mark)
endfor
for mark in ['`', "'"]
exec printf("nmap <buffer><silent> %s%s :<C-u>call b:calendar.mark.get('%s')<CR>", mark, mark, mark ==# "'" ? mark . mark : mark)
endfor
" command line mapping
cnoremap <buffer><silent><expr> <Plug>(calendar_command_enter) b:calendar.action('command_enter')
" move neighborhood
nmap <buffer> h <Plug>(calendar_left)
nmap <buffer> l <Plug>(calendar_right)
nmap <buffer> j <Plug>(calendar_down)
nmap <buffer> k <Plug>(calendar_up)
nmap <buffer> <Left> <Plug>(calendar_left)
nmap <buffer> <Right> <Plug>(calendar_right)
nmap <buffer> <Down> <Plug>(calendar_down)
nmap <buffer> <Up> <Plug>(calendar_up)
nmap <buffer> <BS> h
nmap <buffer> <C-h> h
nmap <buffer> gh h
nmap <buffer> gl l
nmap <buffer> gj j
nmap <buffer> gk k
nmap <buffer> g<Left> <Left>
nmap <buffer> g<Right> <Right>
nmap <buffer> g<Down> <Down>
nmap <buffer> g<Up> <Up>
nmap <buffer> <S-Down> <Down>
nmap <buffer> <S-Up> <Up>
nmap <buffer> <C-n> <Plug>(calendar_down)
nmap <buffer> <C-p> <Plug>(calendar_up)
nmap <buffer> <C-j> <Plug>(calendar_move_down)
nmap <buffer> <C-k> <Plug>(calendar_move_up)
nmap <buffer> <C-S-Down> <Plug>(calendar_move_down)
nmap <buffer> <C-S-Up> <Plug>(calendar_move_up)
nmap <buffer> M <Plug>(calendar_move_event)
nmap <buffer> w <Plug>(calendar_next)
nmap <buffer> W w
nmap <buffer> e w
nmap <buffer> <S-Right> w
nmap <buffer> <C-Right> w
nmap <buffer> b <Plug>(calendar_prev)
nmap <buffer> B b
nmap <buffer> ge b
nmap <buffer> gE b
nmap <buffer> <S-Left> b
nmap <buffer> <C-Left> b
" move page
nmap <buffer> <C-d> <Plug>(calendar_down_big)
nmap <buffer> <C-u> <Plug>(calendar_up_big)
nmap <buffer> <C-f> <Plug>(calendar_down_large)
nmap <buffer> <C-b> <Plug>(calendar_up_large)
nmap <buffer> <PageDown> <C-f>
nmap <buffer> <PageUp> <C-b>
" move column
nmap <buffer> 0 <Plug>(calendar_line_head)
nmap <buffer> ^ 0
nmap <buffer> g0 0
nmap <buffer> <Home> 0
nmap <buffer> g<Home> 0
nmap <buffer> g^ ^
nmap <buffer> gm <Plug>(calendar_line_middle)
nmap <buffer> $ <Plug>(calendar_line_last)
nmap <buffer> g$ $
nmap <buffer> g_ $
nmap <buffer> <End> $
nmap <buffer> g<End> $
nmap <buffer> gg <Plug>(calendar_first_line)
nmap <buffer> <C-Home> gg
nmap <buffer> ( <Plug>(calendar_first_line)
nmap <buffer> { (
nmap <buffer> [[ (
nmap <buffer> [] [[
nmap <buffer> G <Plug>(calendar_last_line)
nmap <buffer> ) <Plug>(calendar_last_line)
nmap <buffer> } )
nmap <buffer> ]] )
nmap <buffer> ][ ]]
nmap <buffer> <C-End> <Plug>(calendar_last_line_last)
nmap <buffer> <Bar> <Plug>(calendar_bar)
" scroll
nmap <buffer> <C-e> <Plug>(calendar_scroll_down)
nmap <buffer> <C-y> <Plug>(calendar_scroll_up)
nmap <buffer> z<CR> <Plug>(calendar_scroll_top_head)
nmap <buffer> zt <Plug>(calendar_scroll_top)
nmap <buffer> z. <Plug>(calendar_scroll_center_head)
nmap <buffer> zz <Plug>(calendar_scroll_center)
nmap <buffer> z- <Plug>(calendar_scroll_bottom_head)
nmap <buffer> zb <Plug>(calendar_scroll_bottom)
" delete
nmap <buffer> d <Plug>(calendar_delete)
nmap <buffer> D <Plug>(calendar_delete_line)
" yank
nmap <buffer> y <Plug>(calendar_yank)
nmap <buffer> Y <Plug>(calendar_yank_line)
" change
nmap <buffer> c <Plug>(calendar_change)
nmap <buffer> C <Plug>(calendar_change_line)
" utility
nmap <buffer> <Undo> <Plug>(calendar_undo)
nmap <buffer> u <Plug>(calendar_undo)
nmap <buffer> U <Plug>(calendar_undo_line)
nmap <buffer> <TAB> <Plug>(calendar_tab)
nmap <buffer> <S-Tab> <Plug>(calendar_shift_tab)
nmap <buffer> n <Plug>(calendar_next_match)
nmap <buffer> N <Plug>(calendar_prev_match)
nmap <buffer> t <Plug>(calendar_today)
nmap <buffer> <CR> <Plug>(calendar_enter)
nmap <buffer> <C-a> <Plug>(calendar_add)
nmap <buffer> <C-x> <Plug>(calendar_subtract)
nmap <buffer> <C-g> <Plug>(calendar_status)
nmap <buffer> + <Plug>(calendar_plus)
nmap <buffer> - <Plug>(calendar_minus)
nmap <buffer> T <Plug>(calendar_task)
nmap <buffer> E <Plug>(calendar_event)
nmap <buffer> < <Plug>(calendar_view_left)
nmap <buffer> > <Plug>(calendar_view_right)
nmap <buffer> <Space> <Plug>(calendar_space)
nmap <buffer> <C-l> <Plug>(calendar_redraw)
nmap <buffer> <C-r> <Plug>(calendar_redraw)
nmap <buffer> L <Plug>(calendar_clear)
nmap <buffer> ? <Plug>(calendar_help)
nmap <buffer> q <Plug>(calendar_hide)
nmap <buffer> Q <Plug>(calendar_exit)
" nop
nmap <buffer> H <Nop>
nmap <buffer> J <Nop>
nmap <buffer> p <Nop>
nmap <buffer> P <Nop>
nmap <buffer> r <Nop>
nmap <buffer> R <Nop>
nmap <buffer> ~ <Nop>
" insert mode
nmap <buffer> i <Plug>(calendar_start_insert)
nmap <buffer> a <Plug>(calendar_start_insert_append)
nmap <buffer> I <Plug>(calendar_start_insert_head)
nmap <buffer> A <Plug>(calendar_start_insert_last)
nmap <buffer> O <Plug>(calendar_start_insert_prev_line)
nmap <buffer> o <Plug>(calendar_start_insert_next_line)
" visual mode
nmap <buffer> v <Plug>(calendar_visual)
nmap <buffer> V <Plug>(calendar_visual_line)
nmap <buffer> <C-v> <Plug>(calendar_visual_block)
nmap <buffer> gh v
nmap <buffer> gH V
nmap <buffer> g<C-h> <C-v>
" command line
cmap <buffer> <CR> <Plug>(calendar_command_enter)
" mouse wheel
map <buffer> <ScrollWheelUp> <Plug>(calendar_prev)
map <buffer> <ScrollWheelDown> <Plug>(calendar_next)
let &cpo = save_cpo
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,56 @@
" =============================================================================
" Filename: autoload/calendar/mark.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:30:36.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Mark controller.
function! calendar#mark#new() abort
return extend(copy(s:self), { 'mark': {} })
endfunction
let s:self = {}
function! s:self.set(mark) dict abort
let self.mark[a:mark] = copy(b:calendar.day().get_ymd()) + copy(b:calendar.time().get_hms())
let self.mark["'"] = self.mark[a:mark]
endfunction
function! s:self.get(mark) dict abort
let mark = a:mark ==# '`' ? "'" : a:mark
if has_key(self.mark, mark)
let m = self.mark[mark]
call b:calendar.set_time(b:calendar.time().new(m[3], m[4], m[5]))
call b:calendar.go(b:calendar.day().new(m[0], m[1], m[2]))
else
call calendar#echo#message(calendar#message#get('mark_not_set') . mark)
endif
endfunction
function! s:self.showmarks() dict abort
let marks = ['mark year month day hour minute second']
let format = '%s %6d %4d %4d %4d %4d %4d'
for [k, m] in items(self.mark)
call add(marks, printf(format, k, m[0], m[1], m[2], m[3], m[4], m[5]))
endfor
call add(marks, calendar#message#get('hit_any_key'))
call calendar#echo#echo(join(marks, "\n"))
call getchar()
endfunction
function! s:self.delmarks(...) dict abort
if a:0
if has_key(self.mark, a:1)
unlet self.mark[a:1]
endif
else
let self.mark = {}
endif
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,43 @@
" =============================================================================
" Filename: autoload/calendar/message.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:30:41.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Getting the message based on the locale setting.
" The message files are found in message/.
function! calendar#message#get(type) abort
let locale = calendar#setting#get('locale')
try
let message = calendar#message#{locale}#get()
catch
if len(locale) > 1
try
let message = calendar#message#{locale[:1]}#get()
catch
let message = calendar#message#default#get()
endtry
else
let message = calendar#message#default#get()
endif
finally
if has_key(message, a:type)
return message[a:type]
else
let message = calendar#message#default#get()
if has_key(message, a:type)
return message[a:type]
else
let message = calendar#message#en#get()
return message[a:type]
endif
endif
endtry
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,35 @@
" =============================================================================
" Filename: autoload/calendar/message/default.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:30:38.
" =============================================================================
scriptencoding utf-8
let s:save_cpo = &cpo
set cpo&vim
function! calendar#message#default#get() abort
return extend(s:english_message, s:message())
endfunction
let s:english_message = deepcopy(calendar#message#en#get())
if exists('*strftime')
function! s:message() abort
let message = {}
let message.day_name = map(range(3, 9), "strftime('%a', 60 * 60 * (24 * v:val + 10))")
let message.day_name_long = map(range(3, 9), "strftime('%A', 60 * 60 * (24 * v:val + 10))")
let message.month_name = map(range(12), "strftime('%b', 60 * 60 * 24 * (32 * v:val + 5))")
let message.month_name_long = map(range(12), "strftime('%B', 60 * 60 * 24 * (32 * v:val + 5))")
return message
endfunction
else
function! s:message() abort
return {}
endfunction
endif
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,107 @@
" =============================================================================
" Filename: autoload/calendar/message/en.vim
" Author: itchyny
" License: MIT License
" Last Change: 2016/05/09 08:07:17.
" =============================================================================
scriptencoding utf-8
let s:save_cpo = &cpo
set cpo&vim
function! calendar#message#en#get() abort
return s:message
endfunction
let s:message = {}
let s:message.day_name = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]
let s:message.day_name_long = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ]
let s:message.month_name = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
let s:message.month_name_long = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]
let s:message.today = 'today'
let s:message.multiple_argument = 'There are multiple possible arguments'
let s:message.mkdir_fail = 'Could not create the directory for cache files'
let s:message.cache_file_unwritable = 'The cache file is not writable'
let s:message.cache_write_fail = 'Could not write the cache file'
let s:message.access_url_input_code = 'Access %s and paste the code'
let s:message.google_access_token_fail = 'Fail in authorization to Google'
let s:message.delete_event = 'Delete the event? (cannot be undone) y/N: '
let s:message.delete_task = 'Delete the task? (cannot be undone) y/N: '
let s:message.clear_completed_task = 'Clear all the completed tasks? (cannot be undone) y/N: '
let s:message.curl_wget_not_found = 'curl and wget not found'
let s:message.mark_not_set = 'Mark not set: '
let s:message.start_date_time = 'Starting date and time: '
let s:message.end_date_time = 'Ending date and time: '
let s:message.input_calendar_index = 'Input the index of the calendar: '
let s:message.input_calendar_name = 'Input the name of a new calendar: '
let s:message.hit_any_key = '[Hit any key]'
let s:message.input_code = 'CODE: '
let s:message.input_task = 'TASK: '
let s:message.input_event = 'EVENT: '
let s:message.help = {
\ 'title': calendar#util#name() . ' help',
\ 'message': join([" This is a calendar application for Vim. ",
\ "This calendar provides many views. Press the < and > keys. ",
\ "There are year view, month view, week view, days view, day view and clock view.\n",
\ " This calendar supports to download calendars from Google Calendar and show the events. ",
\ "Add the following configuration to your vimrc file.\n",
\ " let g:calendar_google_calendar = 1\n",
\ "On starting the calendar, it will start authorization. ",
\ "Press the E key to view and edit the events of the selected day. ",
\ "Moreover, you can also download tasks from Google Task with the following configuration.\n",
\ " let g:calendar_google_task = 1\n",
\ "In order to see tasks, press the T key. You can edit and create tasks in the task window.\n",
\ " For more information, open the help file with the following command.\n",
\ " :help calendar\n",
\ ], ''),
\ 'credit': join([" Name: " . calendar#util#name(),
\ " Version: " . calendar#util#version(),
\ " Author: " . calendar#util#author(),
\ " License: " . calendar#util#license(),
\ " Repository: " . calendar#util#repository(),
\ " Bug tracker: " . calendar#util#issue(),
\ ], "\n"),
\ 'view_left': 'Left view',
\ 'view_right': 'Right view',
\ 'today': 'Go to today',
\ 'task': 'Toggle task window',
\ 'event': 'Toggle event window',
\ 'delete_line': 'Delete the event / Complete the task',
\ 'clear': 'Clear completed tasks',
\ 'undo_line': 'Uncomplete the task',
\ 'help': 'Toggle this help',
\ 'exit': 'Exit',
\ }
let s:message.task = {
\ 'title': 'Task list',
\ }
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,113 @@
" =============================================================================
" Filename: autoload/calendar/message/ja.vim
" Author: itchyny
" License: MIT License
" Last Change: 2016/05/09 08:06:55.
" =============================================================================
scriptencoding utf-8
let s:save_cpo = &cpo
set cpo&vim
function! calendar#message#ja#get() abort
return s:message
endfunction
let s:message = {}
let s:message.day_name = [ '日', '月', '火', '水', '木', '金', '土' ]
let s:message.day_name_long = [ '日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日' ]
let s:message.month_name = [ '1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月' ]
let s:message.month_name_long = s:message.month_name
let s:message.today = '今日'
let s:message.multiple_argument = '複数の引数候補があります'
let s:message.mkdir_fail = 'キャッシュ用のディレクトリーの作成に失敗しました'
let s:message.cache_file_unwritable = 'キャッシュファイルの書き込みが許されていません'
let s:message.cache_write_fail = 'キャッシュファイルの書き込みに失敗しました'
let s:message.access_url_input_code = '%s にアクセスして、コードを入力して下さい'
let s:message.google_access_token_fail = 'Googleへの認証に失敗しました'
let s:message.delete_event = 'イベントを削除しますか? (この操作は元に戻せません) y/N: '
let s:message.delete_task = 'タスクを削除しますか? (この操作は元に戻せません) y/N: '
let s:message.clear_completed_task = '完了したタスクを全て削除しますか? (この操作は元に戻せません) y/N: '
let s:message.curl_wget_not_found = 'curl または wget が必要です'
let s:message.mark_not_set = 'マークが設定されていません: '
let s:message.start_date_time = '開始日時: '
let s:message.end_date_time = '終了日時: '
let s:message.input_calendar_index = 'カレンダーの番号を指定して下さい: '
let s:message.input_calendar_name = '新しいカレンダーの名前を入力して下さい: '
let s:message.hit_any_key = '[キーを押して下さい]'
let s:message.input_code = 'コード: '
let s:message.input_task = 'タスク: '
let s:message.input_event = 'イベント: '
let s:message.help = {
\ 'title': calendar#util#name() . ' ヘルプ',
\ 'message': join([" Vimで動くカレンダーアプリケーションです。",
\ "このカレンダーは、様々なビューを備えています。< と > を押してみてください。",
\ "一年のビュー、一か月ビュー、週間ビュー、数日ビュー、一日ビュー、そして時計ビューがあります。\n",
\ " また、Google Calendarからカレンダーをダウンロードし、表示することも出来ます。",
\ "次の設定をvimrcに書いて下さい。\n",
\ " let g:calendar_google_calendar = 1\n",
\ "カレンダーを起動すると、認証が始まります。",
\ "選択した日のイベント一覧を表示したり、編集したりするには、Eを押して下さい。",
\ "また、次の設定を書くとGoogle Taskからあなたのタスクをダウンロードすることも出来ます。\n",
\ " let g:calendar_google_task = 1\n",
\ "タスクを表示するには、Tを押して下さい。",
\ "その画面で、タスクを編集したり新しく作成したりすることも出来ます。\n",
\ " 更に詳細な事は、アプリケーションのヘルプファイルを参照して下さい。\n",
\ " :help calendar\n",
\ ], ''),
\ 'credit': join([" アプリケーション名: " . calendar#util#name(),
\ " バージョン: " . calendar#util#version(),
\ " 作者: " . calendar#util#author(),
\ " ライセンス: " . calendar#util#license(),
\ " リポジトリ: " . calendar#util#repository(),
\ " バグ報告: " . calendar#util#issue(),
\ ], "\n"),
\ 'Credit': 'クレジット',
\ 'Mapping': 'マッピング',
\ 'View': 'ビュー',
\ 'Utility': 'ユーティリティー',
\ 'view_left': '左のビュー',
\ 'view_right': '右のビュー',
\ 'today': '今日',
\ 'Event window / Task window': 'イベントウィンドウ / タスクウィンドウ',
\ 'task': 'タスクウィンドウを表示/非表示',
\ 'event': 'イベントウィンドウを表示/非表示',
\ 'delete_line': 'イベントを削除 / 選択中のタスクを完了状態にする',
\ 'clear': '完了したタスクを全て削除する',
\ 'undo_line': '完了状態にしたタスクを未完にする',
\ 'help': 'このヘルプを表示/非表示',
\ 'exit': 'カレンダーを終了する',
\ }
let s:message.task = {
\ 'title': 'タスク',
\ }
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,156 @@
" =============================================================================
" Filename: autoload/calendar/model.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:31:06.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Model object
" This object keeps time, day and month.
function! calendar#model#new() abort
return copy(s:self)
endfunction
let s:self = {}
function! s:self.time() dict abort
return self._time
endfunction
function! s:self.set_time(time) dict abort
let self._time = a:time
return self
endfunction
function! s:self.second() dict abort
return self._time.second()
endfunction
function! s:self.minute() dict abort
return self._time.minute()
endfunction
function! s:self.hour() dict abort
return self._time.hour()
endfunction
function! s:self.move_second(diff) dict abort
let [d, new_time] = self.time().add_second(a:diff)
call self.set_time(new_time)
call self.move_day(d)
endfunction
function! s:self.move_minute(diff) dict abort
let [d, new_time] = self.time().add_minute(a:diff)
call self.set_time(new_time)
call self.move_day(d)
endfunction
function! s:self.move_hour(diff) dict abort
let [d, new_time] = self.time().add_hour(a:diff)
call self.set_time(new_time)
call self.move_day(d)
endfunction
function! s:self.day() dict abort
return self._day
endfunction
function! s:self.set_day(day) dict abort
let self._day = a:day
return self
endfunction
function! s:self.month() dict abort
return self._month
endfunction
function! s:self.set_month(month) dict abort
let self._month = a:month
return self
endfunction
function! s:self.set_month_from_day() dict abort
return self.set_month(self.day().month())
endfunction
function! s:self.year() dict abort
return self._day.year()
endfunction
function! s:self.get_days() dict abort
return self.month().get_days()
endfunction
function! s:self.move_day(diff) dict abort
let new_day = self.day().add(a:diff)
call self.set_day(new_day)
if !self.month().eq(new_day.month())
call self.set_month_from_day()
endif
endfunction
function! s:self.move_month(diff) dict abort
call self.set_day(self.day().add_month(a:diff))
call self.set_month_from_day()
endfunction
function! s:self.move_year(diff) dict abort
call self.set_day(self.day().add_year(a:diff))
call self.set_month_from_day()
endfunction
function! s:self._start_visual(mode) dict abort
if self.visual_mode() == 0
let self._visual_start_day = deepcopy(self._day)
let self._visual_start_time = deepcopy(self._time)
endif
let self._visual = get(self, '_visual') == a:mode ? 0 : a:mode
endfunction
function! s:self.start_visual() dict abort
call self._start_visual(1)
endfunction
function! s:self.start_line_visual() dict abort
call self._start_visual(2)
endfunction
function! s:self.start_block_visual() dict abort
call self._start_visual(3)
endfunction
function! s:self.exit_visual() dict abort
let self._visual = 0
return self
endfunction
function! s:self.visual_mode() dict abort
return get(self, '_visual')
endfunction
function! s:self.is_visual() dict abort
return get(self, '_visual') == 1
endfunction
function! s:self.is_line_visual() dict abort
return get(self, '_visual') == 2
endfunction
function! s:self.is_block_visual() dict abort
return get(self, '_visual') == 3
endfunction
function! s:self.visual_start_day() dict abort
return get(self, '_visual_start_day', self._day)
endfunction
function! s:self.visual_start_time() dict abort
return get(self, '_visual_start_time', self._time)
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,64 @@
" =============================================================================
" Filename: autoload/calendar/pixel.vim
" Author: itchyny
" License: MIT License
" Last Change: 2015/03/29 06:31:09.
" =============================================================================
let s:save_cpo = &cpo
set cpo&vim
" Load the pixel files on demand.
" The pixel data are saved in files under pixel/.
" For example, the character code of 'F' is 70 so the pixel data is pixel/70.
" chr: character to get the pixel of
" returns: pixel data in an array
let s:pixel = { ' ': [ '..', '..', '..', '..', '..'] }
let s:dir = expand('<sfile>:p:h') . '/pixel/'
function! calendar#pixel#get(chr) abort
if a:chr ==# ''
return repeat([''], 5)
endif
if has_key(s:pixel, a:chr)
return type(s:pixel[a:chr]) == type([]) ? s:pixel[a:chr] : s:pixel[' ']
endif
let path = s:dir . char2nr(a:chr)
if filereadable(path)
let s:pixel[a:chr] = readfile(path)
else
let s:pixel[a:chr] = 0
endif
return get(s:pixel, a:chr, s:pixel[' '])
endfunction
function! calendar#pixel#len(chr) abort
let len = 0
for c in split(a:chr, '\zs')
unlet! px
let px = calendar#pixel#get(c)
if type(px) == type([])
let len += len(px[0])
endif
endfor
if len(a:chr)
let len -= calendar#pixel#whitelen(a:chr[0])
let len -= calendar#pixel#whitelen(a:chr[len(a:chr) - 1], '\.*$')
endif
return len
endfunction
function! calendar#pixel#whitelen(chr, ...) abort
let pat = a:0 ? a:1 : '^\.*'
let px = calendar#pixel#get(a:chr)
if type(px) != type([])
return 0
endif
let min = 100
for str in px
let min = min([min, len(matchstr(str, pat))])
endfor
return min
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo

View File

@ -0,0 +1,5 @@
...%%
...%%
.%%%%
%%.%%
.%%%%

View File

@ -0,0 +1,5 @@
.....
.%%%.
%%.%%
%%%..
.%%%%

View File

@ -0,0 +1,5 @@
..%%.
.%%..
%%%%%
.%%..
.%%..

View File

@ -0,0 +1,5 @@
.%%%.
%%.%%
.%%%%
...%%
.%%%.

View File

@ -0,0 +1,5 @@
%%...
%%...
%%%%.
%%.%%
%%.%%

View File

@ -0,0 +1,5 @@
..
%%
..
%%
%%

View File

@ -0,0 +1,5 @@
...%%
.....
...%%
%%.%%
.%%%.

View File

@ -0,0 +1,5 @@
%%...
%%...
%%.%%
%%%%.
%%.%%

View File

@ -0,0 +1,5 @@
%%%.
.%%.
.%%.
.%%.
.%%%

View File

@ -0,0 +1,5 @@
........
........
%%%%%%%.
%%.%%.%%
%%.%%.%%

View File

@ -0,0 +1,5 @@
.....
.....
%%%%.
%%.%%
%%.%%

View File

@ -0,0 +1,5 @@
.....
.....
.%%%.
%%.%%
.%%%.

View File

@ -0,0 +1,5 @@
%%%%.
%%.%%
%%%%.
%%...
%%...

View File

@ -0,0 +1,5 @@
.%%%%
%%.%%
.%%%%
...%%
...%%

View File

@ -0,0 +1,5 @@
.....
%%.%%
%%%%.
%%...
%%...

View File

@ -0,0 +1,5 @@
.%%%%
%%...
%%%%%
...%%
%%%%.

View File

@ -0,0 +1,5 @@
....
.%%.
%%%%
.%%.
.%%%

View File

@ -0,0 +1,5 @@
.....
.....
%%.%%
%%.%%
.%%%%

View File

@ -0,0 +1,5 @@
......
......
%%..%%
.%%%%.
..%%..

View File

@ -0,0 +1,5 @@
..........
..........
%%..%%..%%
.%%%%%%%%.
..%%..%%..

View File

@ -0,0 +1,5 @@
.....
.....
%%.%%
.%%%.
%%.%%

View File

@ -0,0 +1,5 @@
......
%%..%%
.%%%%.
..%%..
.%%...

View File

@ -0,0 +1,5 @@
.....
.....
%%%%%
.%%%.
%%%%%

View File

@ -0,0 +1,5 @@
.%%%
.%%.
%%%.
.%%.
.%%%

View File

@ -0,0 +1,5 @@
%%
%%
%%
%%
%%

View File

@ -0,0 +1,5 @@
%%%.
.%%.
.%%%
.%%.
%%%.

View File

@ -0,0 +1,5 @@
.......
.......
.%%%.%%
%%.%%%.
.......

View File

@ -0,0 +1,5 @@
%%
%%
%%
..
%%

View File

@ -0,0 +1,5 @@
.%%.%%
%%.%%.
......
......
......

View File

@ -0,0 +1,5 @@
.%%.%%.
%%%%%%%
.%%.%%.
%%%%%%%
.%%.%%.

View File

@ -0,0 +1,6 @@
.%%%%%
%.%%..
%%%%%%
..%%.%
%%%%%.

View File

@ -0,0 +1,5 @@
....%%
%%.%%.
..%%..
.%%.%%
%%....

View File

@ -0,0 +1,5 @@
..%%%..
.%%....
.%%%...
%%...%%
.%%%%%.

View File

@ -0,0 +1,5 @@
.%%
%%.
...
...
...

View File

@ -0,0 +1,5 @@
.%%
%%.
%%.
%%.
.%%

View File

@ -0,0 +1,5 @@
%%..
.%%.
.%%.
.%%.
%%..

Some files were not shown because too many files have changed in this diff Show More