mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-05 17:15:12 +00:00
import vim plugin
This commit is contained in:
parent
cbc74916a9
commit
e23e363e0a
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
/target
|
/target
|
||||||
|
/vim/doc/tags
|
||||||
|
|
125
vim/README.md
Normal file
125
vim/README.md
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
# 📫 Himalaya.vim
|
||||||
|
|
||||||
|
Vim plugin for [Himalaya](https://github.com/soywod/himalaya) CLI email client.
|
||||||
|
|
||||||
|
![image](https://user-images.githubusercontent.com/10437171/104848096-aee51000-58e3-11eb-8d99-bcfab5ca28ba.png)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
* [Motivation](#motivation)
|
||||||
|
* [Installation](#installation)
|
||||||
|
* [Usage](#usage)
|
||||||
|
* [List messages view](#list-messages-view)
|
||||||
|
* [Read message view](#read-message-view)
|
||||||
|
* [Write message view](#write-message-view)
|
||||||
|
* [License](https://github.com/soywod/himalaya.vim/blob/master/LICENSE)
|
||||||
|
* [Credits](#credits)
|
||||||
|
|
||||||
|
## Motivation
|
||||||
|
|
||||||
|
Bringing emails to the terminal is a pain. The mainstream TUI, (neo)mutt, takes
|
||||||
|
time to configure. The default mapping is not intuitive when coming from the
|
||||||
|
Vim environment. It is even scary to use at the beginning, since you are
|
||||||
|
dealing with sensitive data!
|
||||||
|
|
||||||
|
The aim of Himalaya is to extract the email logic into a simple (yet solid) CLI
|
||||||
|
API that can be used either directly from the terminal or UIs. It gives users
|
||||||
|
more flexibility.
|
||||||
|
|
||||||
|
This Vim plugin is a TUI implementation for Himalaya CLI.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
First you need to install and configure the [himalaya
|
||||||
|
CLI](https://github.com/soywod/himalaya#installation). Then you can install
|
||||||
|
this plugin with your favorite plugin manager. For eg with
|
||||||
|
[vim-plug](https://github.com/junegunn/vim-plug) add to your `.vimrc`:
|
||||||
|
|
||||||
|
```viml
|
||||||
|
Plug "soywod/himalaya.vim"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then:
|
||||||
|
|
||||||
|
```viml
|
||||||
|
:PlugInstall
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### List messages view
|
||||||
|
|
||||||
|
```vim
|
||||||
|
:Himalaya
|
||||||
|
```
|
||||||
|
|
||||||
|
![gif](https://user-images.githubusercontent.com/10437171/110707014-f9ef1580-81f8-11eb-93ad-233010733ca3.gif)
|
||||||
|
|
||||||
|
| Function | Default binding |
|
||||||
|
| --- | --- |
|
||||||
|
| Change the current mbox | `gm` |
|
||||||
|
| Show previous page | `gp` |
|
||||||
|
| Show next page | `gn` |
|
||||||
|
| Read focused msg | `<Enter>` |
|
||||||
|
| Write a new msg | `gw` |
|
||||||
|
| Reply to the focused msg | `gr` |
|
||||||
|
| Reply all to the focused msg | `gR` |
|
||||||
|
| Forward the focused message | `gf` |
|
||||||
|
| Download all focused msg attachments | `ga` |
|
||||||
|
|
||||||
|
They can be customized:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
nmap gm <plug>(himalaya-mbox-input)
|
||||||
|
nmap gp <plug>(himalaya-mbox-prev-page)
|
||||||
|
nmap gn <plug>(himalaya-mbox-next-page)
|
||||||
|
nmap <cr> <plug>(himalaya-msg-read)
|
||||||
|
nmap gw <plug>(himalaya-msg-write)
|
||||||
|
nmap gr <plug>(himalaya-msg-reply)
|
||||||
|
nmap gR <plug>(himalaya-msg-reply-all)
|
||||||
|
nmap gf <plug>(himalaya-msg-forward)
|
||||||
|
nmap ga <plug>(himalaya-msg-attachments)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Read message view
|
||||||
|
|
||||||
|
![gif](https://user-images.githubusercontent.com/10437171/110708073-7b937300-81fa-11eb-9f4c-5472cea22e21.gif)
|
||||||
|
|
||||||
|
| Function | Default binding |
|
||||||
|
| --- | --- |
|
||||||
|
| Write a new msg | `gw` |
|
||||||
|
| Reply to the msg | `gr` |
|
||||||
|
| Reply all to the msg | `gR` |
|
||||||
|
| Forward the message | `gf` |
|
||||||
|
| Download all msg attachments | `ga` |
|
||||||
|
|
||||||
|
They can be customized:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
nmap gw <plug>(himalaya-msg-write)
|
||||||
|
nmap gr <plug>(himalaya-msg-reply)
|
||||||
|
nmap gR <plug>(himalaya-msg-reply-all)
|
||||||
|
nmap gf <plug>(himalaya-msg-forward)
|
||||||
|
nmap ga <plug>(himalaya-msg-attachments)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Write message view
|
||||||
|
|
||||||
|
![gif](https://user-images.githubusercontent.com/10437171/110708795-84387900-81fb-11eb-8f8a-f7e7862e816d.gif)
|
||||||
|
|
||||||
|
When you exit this special buffer, you will be prompted 4 choices:
|
||||||
|
|
||||||
|
- `Send`: sends the message
|
||||||
|
- `Draft`: saves the message into the `Drafts` mailbox
|
||||||
|
- `Quit`: quits the buffer without saving
|
||||||
|
- `Cancel`: goes back to the message edition
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
- [IMAP RFC3501](https://tools.ietf.org/html/rfc3501)
|
||||||
|
- [Iris](https://github.com/soywod/iris.vim), the himalaya predecessor
|
||||||
|
- [isync](https://isync.sourceforge.io/), an email synchronizer for offline usage
|
||||||
|
- [NeoMutt](https://neomutt.org/), an email terminal user interface
|
||||||
|
- [Alpine](http://alpine.x10host.com/alpine/alpine-info/), an other email terminal user interface
|
||||||
|
- [mutt-wizard](https://github.com/LukeSmithxyz/mutt-wizard), a tool over NeoMutt and isync
|
||||||
|
- [rust-imap](https://github.com/jonhoo/rust-imap), a rust IMAP lib
|
57
vim/autoload/himalaya/mbox.vim
Normal file
57
vim/autoload/himalaya/mbox.vim
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
let s:print_info = function("himalaya#utils#print_msg")
|
||||||
|
let s:print_err = function("himalaya#utils#print_err")
|
||||||
|
let s:cli = function("himalaya#shared#cli")
|
||||||
|
|
||||||
|
" Pagination
|
||||||
|
|
||||||
|
let s:curr_page = 0
|
||||||
|
function! himalaya#mbox#curr_page()
|
||||||
|
return s:curr_page
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#mbox#prev_page()
|
||||||
|
let s:curr_page = max([0, s:curr_page - 1])
|
||||||
|
call himalaya#msg#list()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#mbox#next_page()
|
||||||
|
let s:curr_page = s:curr_page + 1
|
||||||
|
call himalaya#msg#list()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Mailbox
|
||||||
|
|
||||||
|
let s:curr_mbox = "INBOX"
|
||||||
|
function! himalaya#mbox#curr_mbox()
|
||||||
|
return s:curr_mbox
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#mbox#input()
|
||||||
|
try
|
||||||
|
call s:print_info("Fetching mailboxes…")
|
||||||
|
|
||||||
|
let mboxes = map(s:cli("mailboxes", []), "v:val.name")
|
||||||
|
|
||||||
|
" if &rtp =~ "fzf.vim"
|
||||||
|
" call fzf#run({
|
||||||
|
" \"source": mboxes,
|
||||||
|
" \"sink": function("himalaya#mbox#post_input"),
|
||||||
|
" \"down": "25%",
|
||||||
|
" \})
|
||||||
|
" else
|
||||||
|
let choice = map(copy(mboxes), "printf('%s (%d)', v:val, v:key)")
|
||||||
|
redraw | echo
|
||||||
|
let choice = input(join(choice, ", ") . ": ")
|
||||||
|
redraw | echo
|
||||||
|
call himalaya#mbox#post_input(mboxes[choice])
|
||||||
|
" endif
|
||||||
|
catch
|
||||||
|
call s:print_err(v:exception)
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#mbox#post_input(mbox)
|
||||||
|
let s:curr_mbox = a:mbox
|
||||||
|
let s:curr_page = 0
|
||||||
|
call himalaya#msg#list()
|
||||||
|
endfunction
|
107
vim/autoload/himalaya/mbx.vim
Normal file
107
vim/autoload/himalaya/mbx.vim
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
let s:trim = function("himalaya#utils#trim")
|
||||||
|
let s:print_err = function("himalaya#utils#print_err")
|
||||||
|
let s:print_info = function("himalaya#utils#print_msg")
|
||||||
|
|
||||||
|
let s:buff_name = "Himalaya"
|
||||||
|
|
||||||
|
" Exec utils
|
||||||
|
|
||||||
|
function! s:exec(cmd, args)
|
||||||
|
let cmd = call("printf", [a:cmd] + a:args)
|
||||||
|
let res = system(cmd)
|
||||||
|
|
||||||
|
try
|
||||||
|
return eval(res)
|
||||||
|
catch
|
||||||
|
throw res
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Render utils
|
||||||
|
|
||||||
|
function! s:render(type, lines)
|
||||||
|
let s:max_widths = s:get_max_widths(a:lines, s:config[a:type].columns)
|
||||||
|
let header = [s:render_line(s:config.labels, s:max_widths, a:type)]
|
||||||
|
let line = map(copy(a:lines), "s:render_line(v:val, s:max_widths, a:type)")
|
||||||
|
|
||||||
|
return header + line
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:render_line(line, max_widths, type)
|
||||||
|
return "|" . join(map(
|
||||||
|
\copy(s:config[a:type].columns),
|
||||||
|
\"s:render_cell(a:line[v:val], a:max_widths[v:key])",
|
||||||
|
\), "")
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:render_cell(cell, max_width)
|
||||||
|
let cell_width = strdisplaywidth(a:cell[:a:max_width])
|
||||||
|
return a:cell[:a:max_width] . repeat(" ", a:max_width - cell_width) . " |"
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:get_max_widths(msgs, columns)
|
||||||
|
let max_widths = map(copy(a:columns), "strlen(s:config.labels[v:val])")
|
||||||
|
|
||||||
|
for msg in a:msgs
|
||||||
|
let widths = map(copy(a:columns), "strlen(msg[v:val])")
|
||||||
|
call map(max_widths, "max([widths[v:key], v:val])")
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return max_widths
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" List
|
||||||
|
|
||||||
|
let s:config = {
|
||||||
|
\"list": {
|
||||||
|
\"columns": ["delim", "name", "attributes"],
|
||||||
|
\},
|
||||||
|
\"labels": {
|
||||||
|
\"delim": "DELIM",
|
||||||
|
\"name": "NAME",
|
||||||
|
\"attributes": "ATTRIBUTES",
|
||||||
|
\},
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! himalaya#mbx#format_for_list(mbx)
|
||||||
|
let mbx = copy(a:mbx)
|
||||||
|
let mbx.attributes = join(mbx.attributes, ", ")
|
||||||
|
return mbx
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:get_focused_mbx()
|
||||||
|
try
|
||||||
|
return s:trim(split(getline("."), "|")[1])
|
||||||
|
catch
|
||||||
|
throw "mailbox not found"
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#mbx#list()
|
||||||
|
try
|
||||||
|
call s:print_info("Fetching mailboxes…")
|
||||||
|
|
||||||
|
let prev_pos = getpos(".")
|
||||||
|
let mbxs = s:exec("himalaya --output json mailboxes", [])
|
||||||
|
let mbxs = map(copy(mbxs), 'himalaya#mbx#format_for_list(v:val)')
|
||||||
|
|
||||||
|
silent! bwipeout "Mailboxes"
|
||||||
|
silent! edit Mailboxes
|
||||||
|
|
||||||
|
call append(0, s:render("list", mbxs))
|
||||||
|
execute "$d"
|
||||||
|
|
||||||
|
call setpos(".", prev_pos)
|
||||||
|
setlocal filetype=himalaya-mbx-list
|
||||||
|
let &modified = 0
|
||||||
|
|
||||||
|
call s:print_info("Done!")
|
||||||
|
catch
|
||||||
|
call s:print_err(v:exception)
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#mbx#select()
|
||||||
|
let mbx = s:get_focused_mbx()
|
||||||
|
call himalaya#msg#list(mbx)
|
||||||
|
endfunction
|
241
vim/autoload/himalaya/msg.vim
Normal file
241
vim/autoload/himalaya/msg.vim
Normal file
|
@ -0,0 +1,241 @@
|
||||||
|
let s:print_info = function("himalaya#utils#print_msg")
|
||||||
|
let s:print_err = function("himalaya#utils#print_err")
|
||||||
|
let s:trim = function("himalaya#utils#trim")
|
||||||
|
let s:cli = function("himalaya#shared#cli")
|
||||||
|
|
||||||
|
let s:msg_id = 0
|
||||||
|
let s:draft = ""
|
||||||
|
|
||||||
|
" Message
|
||||||
|
|
||||||
|
function! s:format_msg_for_list(msg)
|
||||||
|
let msg = copy(a:msg)
|
||||||
|
|
||||||
|
let flag_unseen = index(msg.flags, "Seen") == -1 ? "🟓" : " "
|
||||||
|
let flag_replied = index(msg.flags, "Answered") == -1 ? " " : "↩"
|
||||||
|
let flag_flagged = index(msg.flags, "Flagged") == -1 ? " " : "!"
|
||||||
|
let msg.flags = printf("%s%s%s", flag_unseen, flag_replied, flag_flagged)
|
||||||
|
|
||||||
|
return msg
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#msg#list()
|
||||||
|
try
|
||||||
|
let mbox = himalaya#mbox#curr_mbox()
|
||||||
|
let page = himalaya#mbox#curr_page()
|
||||||
|
|
||||||
|
call s:print_info(printf("Fetching %s messages…", tolower(mbox)))
|
||||||
|
let msgs = s:cli("--mailbox %s list --page %d", [shellescape(mbox), page])
|
||||||
|
let msgs = map(copy(msgs), "s:format_msg_for_list(v:val)")
|
||||||
|
call s:print_info("Done!")
|
||||||
|
|
||||||
|
let buftype = stridx(bufname("%"), "Himalaya messages") == 0 ? "file" : "edit"
|
||||||
|
execute printf("silent! %s Himalaya messages [%s] [page %d]", buftype, tolower(mbox), page + 1)
|
||||||
|
setlocal modifiable
|
||||||
|
execute "%d"
|
||||||
|
call append(0, s:render("list", msgs))
|
||||||
|
execute "$d"
|
||||||
|
setlocal filetype=himalaya-msg-list
|
||||||
|
let &modified = 0
|
||||||
|
execute 0
|
||||||
|
catch
|
||||||
|
call s:print_err(v:exception)
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#msg#read()
|
||||||
|
try
|
||||||
|
let s:msg_id = s:get_focused_msg_id()
|
||||||
|
let mbox = himalaya#mbox#curr_mbox()
|
||||||
|
|
||||||
|
call s:print_info(printf("Fetching message %d…", s:msg_id))
|
||||||
|
let msg = s:cli("read %d --mailbox %s", [s:msg_id, shellescape(mbox)])
|
||||||
|
call s:print_info("Done!")
|
||||||
|
|
||||||
|
let attachment = msg.hasAttachment ? " []" : ""
|
||||||
|
execute printf("silent! edit Himalaya read message [%d]%s", s:msg_id, attachment)
|
||||||
|
setlocal modifiable
|
||||||
|
execute "%d"
|
||||||
|
call append(0, split(substitute(msg.content, "\r", "", "g"), "\n"))
|
||||||
|
execute "$d"
|
||||||
|
setlocal filetype=himalaya-msg-read
|
||||||
|
let &modified = 0
|
||||||
|
execute 0
|
||||||
|
catch
|
||||||
|
call s:print_err(v:exception)
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#msg#write()
|
||||||
|
try
|
||||||
|
call s:print_info("Fetching new template…")
|
||||||
|
let msg = s:cli("template new", [])
|
||||||
|
call s:print_info("Done!")
|
||||||
|
|
||||||
|
silent! edit Himalaya write
|
||||||
|
call append(0, split(substitute(msg.template, "\r", "", "g"), "\n"))
|
||||||
|
execute "$d"
|
||||||
|
setlocal filetype=himalaya-msg-write
|
||||||
|
let &modified = 0
|
||||||
|
execute 0
|
||||||
|
catch
|
||||||
|
call s:print_err(v:exception)
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#msg#reply()
|
||||||
|
try
|
||||||
|
let mbox = himalaya#mbox#curr_mbox()
|
||||||
|
let msg_id = stridx(bufname("%"), "Himalaya messages") == 0 ? s:get_focused_msg_id() : s:msg_id
|
||||||
|
|
||||||
|
call s:print_info("Fetching reply template…")
|
||||||
|
let msg = s:cli("template reply %d --mailbox %s", [msg_id, shellescape(mbox)])
|
||||||
|
call s:print_info("Done!")
|
||||||
|
|
||||||
|
execute printf("silent! edit Himalaya reply [%d]", msg_id)
|
||||||
|
call append(0, split(substitute(msg.template, "\r", "", "g"), "\n"))
|
||||||
|
execute "$d"
|
||||||
|
setlocal filetype=himalaya-msg-write
|
||||||
|
let &modified = 0
|
||||||
|
execute 0
|
||||||
|
catch
|
||||||
|
call s:print_err(v:exception)
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#msg#reply_all()
|
||||||
|
try
|
||||||
|
let mbox = himalaya#mbox#curr_mbox()
|
||||||
|
let msg_id = stridx(bufname("%"), "Himalaya messages") == 0 ? s:get_focused_msg_id() : s:msg_id
|
||||||
|
|
||||||
|
call s:print_info("Fetching reply all template…")
|
||||||
|
let msg = s:cli("template reply %d --mailbox %s --all", [msg_id, shellescape(mbox)])
|
||||||
|
call s:print_info("Done!")
|
||||||
|
|
||||||
|
execute printf("silent! edit Himalaya reply all [%d]", msg_id)
|
||||||
|
call append(0, split(substitute(msg.template, "\r", "", "g"), "\n"))
|
||||||
|
execute "$d"
|
||||||
|
setlocal filetype=himalaya-msg-write
|
||||||
|
let &modified = 0
|
||||||
|
execute 0
|
||||||
|
catch
|
||||||
|
call s:print_err(v:exception)
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#msg#forward()
|
||||||
|
try
|
||||||
|
let mbox = himalaya#mbox#curr_mbox()
|
||||||
|
let msg_id = stridx(bufname("%"), "Himalaya messages") == 0 ? s:get_focused_msg_id() : s:msg_id
|
||||||
|
|
||||||
|
call s:print_info("Fetching forward template…")
|
||||||
|
let msg = s:cli("template forward %d --mailbox %s", [msg_id, shellescape(mbox)])
|
||||||
|
call s:print_info("Done!")
|
||||||
|
|
||||||
|
execute printf("silent! edit Himalaya forward [%d]", msg_id)
|
||||||
|
call append(0, split(substitute(msg.template, "\r", "", "g"), "\n"))
|
||||||
|
execute "$d"
|
||||||
|
setlocal filetype=himalaya-msg-write
|
||||||
|
let &modified = 0
|
||||||
|
execute 0
|
||||||
|
catch
|
||||||
|
call s:print_err(v:exception)
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#msg#draft_save()
|
||||||
|
let s:draft = join(getline(1, "$"), "\r\n")
|
||||||
|
call s:print_info("Draft saved!")
|
||||||
|
let &modified = 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#msg#draft_handle()
|
||||||
|
while 1
|
||||||
|
let choice = input("(s)end, (d)raft, (q)uit or (c)ancel? ")
|
||||||
|
let choice = tolower(choice)[0]
|
||||||
|
redraw | echo
|
||||||
|
|
||||||
|
if choice == "s"
|
||||||
|
call s:print_info("Sending message…")
|
||||||
|
call s:cli("send -- %s", [shellescape(s:draft)])
|
||||||
|
call s:print_info("Done!")
|
||||||
|
return
|
||||||
|
elseif choice == "d"
|
||||||
|
call s:print_info("Saving draft…")
|
||||||
|
call s:cli("save --mailbox Drafts -- %s", [shellescape(s:draft)])
|
||||||
|
call s:print_info("Done!")
|
||||||
|
return
|
||||||
|
elseif choice == "q"
|
||||||
|
return
|
||||||
|
elseif choice == "c"
|
||||||
|
throw "Action canceled"
|
||||||
|
endif
|
||||||
|
endwhile
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#msg#attachments()
|
||||||
|
try
|
||||||
|
let mbox = himalaya#mbox#curr_mbox()
|
||||||
|
let msg_id = stridx(bufname("%"), "Himalaya messages") == 0 ? s:get_focused_msg_id() : s:msg_id
|
||||||
|
|
||||||
|
call s:print_info("Downloading attachments…")
|
||||||
|
let msg = s:cli("attachments %d --mailbox %s", [msg_id, shellescape(mbox)])
|
||||||
|
call s:print_info("Done!")
|
||||||
|
catch
|
||||||
|
call s:print_err(v:exception)
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Render utils
|
||||||
|
|
||||||
|
let s:config = {
|
||||||
|
\"list": {
|
||||||
|
\"columns": ["uid", "flags", "subject", "sender", "date"],
|
||||||
|
\},
|
||||||
|
\"labels": {
|
||||||
|
\"uid": "UID",
|
||||||
|
\"flags": "FLAGS",
|
||||||
|
\"subject": "SUBJECT",
|
||||||
|
\"sender": "SENDER",
|
||||||
|
\"date": "DATE",
|
||||||
|
\},
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! s:render(type, lines)
|
||||||
|
let s:max_widths = s:get_max_widths(a:lines, s:config[a:type].columns)
|
||||||
|
let header = [s:render_line(s:config.labels, s:max_widths, a:type)]
|
||||||
|
let line = map(copy(a:lines), "s:render_line(v:val, s:max_widths, a:type)")
|
||||||
|
|
||||||
|
return header + line
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:render_line(line, max_widths, type)
|
||||||
|
return "|" . join(map(
|
||||||
|
\copy(s:config[a:type].columns),
|
||||||
|
\"s:render_cell(a:line[v:val], a:max_widths[v:key])",
|
||||||
|
\), "")
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:render_cell(cell, max_width)
|
||||||
|
let cell_width = strdisplaywidth(a:cell[:a:max_width])
|
||||||
|
return a:cell[:a:max_width] . repeat(" ", a:max_width - cell_width) . " |"
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:get_max_widths(msgs, columns)
|
||||||
|
let max_widths = map(copy(a:columns), "strlen(s:config.labels[v:val])")
|
||||||
|
|
||||||
|
for msg in a:msgs
|
||||||
|
let widths = map(copy(a:columns), "strlen(msg[v:val])")
|
||||||
|
call map(max_widths, "max([widths[v:key], v:val])")
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return max_widths
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:get_focused_msg_id()
|
||||||
|
try
|
||||||
|
return s:trim(split(getline("."), "|")[0])
|
||||||
|
catch
|
||||||
|
throw "message not found"
|
||||||
|
endtry
|
||||||
|
endfunction
|
28
vim/autoload/himalaya/shared.vim
Normal file
28
vim/autoload/himalaya/shared.vim
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
function! himalaya#shared#define_bindings(bindings)
|
||||||
|
for [mode, key, name] in a:bindings
|
||||||
|
let plug = substitute(name, "[#_]", "-", "g")
|
||||||
|
let plug = printf("<plug>(himalaya-%s)", plug)
|
||||||
|
execute printf("%snoremap <silent>%s :call himalaya#%s()<cr>", mode, plug, name)
|
||||||
|
|
||||||
|
if !hasmapto(plug, mode)
|
||||||
|
execute printf("%smap <nowait><buffer>%s %s", mode, key, plug)
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#shared#cli(cmd, args)
|
||||||
|
let cmd = call("printf", ["himalaya --output json " . a:cmd] + a:args)
|
||||||
|
let res = system(cmd)
|
||||||
|
|
||||||
|
if !empty(res)
|
||||||
|
try
|
||||||
|
return eval(res)
|
||||||
|
catch
|
||||||
|
throw res
|
||||||
|
endtry
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#shared#thread_fold(lnum)
|
||||||
|
return getline(a:lnum)[0] == ">"
|
||||||
|
endfunction
|
238
vim/autoload/himalaya/ui.vim
Normal file
238
vim/autoload/himalaya/ui.vim
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
let s:compose = function('himalaya#utils#compose')
|
||||||
|
let s:trim = function('himalaya#utils#trim')
|
||||||
|
let s:print_msg = function('himalaya#utils#print_msg')
|
||||||
|
let s:print_err = function('himalaya#utils#print_err')
|
||||||
|
|
||||||
|
let s:max_widths = []
|
||||||
|
let s:buff_name = 'Himalaya'
|
||||||
|
let s:msgs = []
|
||||||
|
|
||||||
|
let s:config = {
|
||||||
|
\'list': {
|
||||||
|
\'columns': ['uid', 'subject', 'sender', 'date'],
|
||||||
|
\},
|
||||||
|
\'labels': {
|
||||||
|
\'uid': 'ID',
|
||||||
|
\'subject': 'SUBJECT',
|
||||||
|
\'sender': 'SENDER',
|
||||||
|
\'date': 'DATE',
|
||||||
|
\},
|
||||||
|
\}
|
||||||
|
|
||||||
|
function! himalaya#ui#list()
|
||||||
|
try
|
||||||
|
let prev_pos = getpos('.')
|
||||||
|
let s:msgs = himalaya#msg#list()
|
||||||
|
let lines = map(copy(s:msgs), 'himalaya#msg#format_for_list(v:val)')
|
||||||
|
|
||||||
|
redir => buf_list | silent! ls | redir END
|
||||||
|
execute 'silent! edit ' . s:buff_name
|
||||||
|
|
||||||
|
if match(buf_list, '"Himalaya') > -1
|
||||||
|
execute '0,$d'
|
||||||
|
endif
|
||||||
|
|
||||||
|
call append(0, s:render('list', lines))
|
||||||
|
execute '$d'
|
||||||
|
call setpos('.', prev_pos)
|
||||||
|
setlocal filetype=himalaya-list
|
||||||
|
let &modified = 0
|
||||||
|
echo
|
||||||
|
catch
|
||||||
|
call s:print_err(v:exception)
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Cell management
|
||||||
|
|
||||||
|
function! himalaya#ui#select_next_cell()
|
||||||
|
normal! f|l
|
||||||
|
|
||||||
|
if col('.') == col('$') - 1
|
||||||
|
if line('.') == line('$')
|
||||||
|
normal! T|
|
||||||
|
else
|
||||||
|
normal! j0l
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#ui#select_prev_cell()
|
||||||
|
if col('.') == 2 && line('.') > 2
|
||||||
|
normal! k$T|
|
||||||
|
else
|
||||||
|
normal! 2T|
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#ui#delete_in_cell()
|
||||||
|
execute printf('normal! %sdt|', col('.') == 1 ? '' : 'T|')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#ui#change_in_cell()
|
||||||
|
call himalaya#ui#delete_in_cell()
|
||||||
|
startinsert
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#ui#visual_in_cell()
|
||||||
|
execute printf('normal! %svt|', col('.') == 1 ? '' : 'T|')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Parse utils
|
||||||
|
|
||||||
|
function! himalaya#ui#parse_buffer()
|
||||||
|
" try
|
||||||
|
" let lines = filter(getline(2, "$"), "!empty(s:trim(v:val))")
|
||||||
|
" let prev_msgs = copy(s:msgs)
|
||||||
|
" let next_msgs = map(lines, "s:parse_buffer_line(v:key, v:val)")
|
||||||
|
" let msgs_to_add = filter(copy(next_msgs), "empty(v:val.id)")
|
||||||
|
" let msgs_to_edit = []
|
||||||
|
" let msgs_to_do = []
|
||||||
|
" let msgs = []
|
||||||
|
|
||||||
|
" for prev_msg in prev_msgs
|
||||||
|
" let next_msg = filter(copy(next_msgs), "v:val.id == prev_msg.id")
|
||||||
|
|
||||||
|
" if empty(next_msg)
|
||||||
|
" let msgs_to_do += [prev_msg.id]
|
||||||
|
" elseif prev_msg.desc != next_msg[0].desc || prev_msg.project != next_msg[0].project || prev_msg.due.approx != next_msg[0].due
|
||||||
|
" let msgs_to_edit += [next_msg[0]]
|
||||||
|
" endif
|
||||||
|
" endfor
|
||||||
|
|
||||||
|
" for msg in msgs_to_add | let msgs += [himalaya#msg#add(msg)] | endfor
|
||||||
|
" for msg in msgs_to_edit | let msgs += [himalaya#msg#edit(msg)] | endfor
|
||||||
|
" for id in msgs_to_do | let msgs += [himalaya#msg#do(id)] | endfor
|
||||||
|
|
||||||
|
" call himalaya#ui#list()
|
||||||
|
" let &modified = 0
|
||||||
|
" for msg in msgs | call s:print_msg(msg) | endfor
|
||||||
|
" catch
|
||||||
|
" call s:print_err(v:exception)
|
||||||
|
" endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:parse_buffer_line(index, line)
|
||||||
|
if match(a:line, '^|[0-9a-f\-]\{-} *|.* *|.\{-} *|.\{-} *|.\{-} *|$') != -1
|
||||||
|
let cells = split(a:line, "|")
|
||||||
|
let id = s:trim(cells[0])
|
||||||
|
let desc = s:trim(join(cells[1:-4], ""))
|
||||||
|
let project = s:trim(cells[-3])
|
||||||
|
let due = s:trim(cells[-1])
|
||||||
|
|
||||||
|
return {
|
||||||
|
\"id": id,
|
||||||
|
\"desc": desc,
|
||||||
|
\"project": project,
|
||||||
|
\"due": due,
|
||||||
|
\}
|
||||||
|
else
|
||||||
|
let [desc, project, due] = s:parse_args(s:trim(a:line))
|
||||||
|
|
||||||
|
return {
|
||||||
|
\"id": "",
|
||||||
|
\"desc": desc,
|
||||||
|
\"project": project,
|
||||||
|
\"due": due,
|
||||||
|
\}
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:uniq_by_id(a, b)
|
||||||
|
if a:a.id > a:b.id | return 1
|
||||||
|
elseif a:a.id < a:b.id | return -1
|
||||||
|
else | return 0 | endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:parse_args(args)
|
||||||
|
let args = split(a:args, ' ')
|
||||||
|
|
||||||
|
let idx = 0
|
||||||
|
let desc = []
|
||||||
|
let project = ""
|
||||||
|
let due = ""
|
||||||
|
|
||||||
|
while idx < len(args)
|
||||||
|
let arg = args[idx]
|
||||||
|
|
||||||
|
if arg == "-p" || arg == "--project"
|
||||||
|
let project = get(args, idx + 1, "")
|
||||||
|
let idx = idx + 1
|
||||||
|
elseif arg == "-d" || arg == "--due"
|
||||||
|
let due = get(args, idx + 1, "")
|
||||||
|
let idx = idx + 1
|
||||||
|
else
|
||||||
|
call add(desc, arg)
|
||||||
|
endif
|
||||||
|
|
||||||
|
let idx = idx + 1
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
return [join(desc, ' '), project, due]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" ------------------------------------------------------------------ # Renders #
|
||||||
|
|
||||||
|
function! s:render(type, lines)
|
||||||
|
let s:max_widths = s:get_max_widths(a:lines, s:config[a:type].columns)
|
||||||
|
let header = [s:render_line(s:config.labels, s:max_widths, a:type)]
|
||||||
|
let line = map(copy(a:lines), 's:render_line(v:val, s:max_widths, a:type)')
|
||||||
|
|
||||||
|
return header + line
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:render_line(line, max_widths, type)
|
||||||
|
return '|' . join(map(
|
||||||
|
\copy(s:config[a:type].columns),
|
||||||
|
\'s:render_cell(a:line[v:val], a:max_widths[v:key])',
|
||||||
|
\), '')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:render_cell(cell, max_width)
|
||||||
|
let cell_width = strdisplaywidth(a:cell[:a:max_width])
|
||||||
|
return a:cell[:a:max_width] . repeat(' ', a:max_width - cell_width) . ' |'
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" -------------------------------------------------------------------- # Utils #
|
||||||
|
|
||||||
|
function! s:get_max_widths(msgs, columns)
|
||||||
|
let max_widths = map(copy(a:columns), 'strlen(s:config.labels[v:val])')
|
||||||
|
|
||||||
|
for msg in a:msgs
|
||||||
|
let widths = map(copy(a:columns), 'strlen(msg[v:val])')
|
||||||
|
call map(max_widths, 'max([widths[v:key], v:val])')
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return max_widths
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:get_focused_msg_id()
|
||||||
|
try
|
||||||
|
return s:trim(split(getline("."), "|")[0])
|
||||||
|
catch
|
||||||
|
throw "msg not found"
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:refresh_buff_name()
|
||||||
|
let buff_name = 'Himalaya'
|
||||||
|
|
||||||
|
if !g:himalaya_hide_done
|
||||||
|
let buff_name .= '*'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if len(g:himalaya_context) > 0
|
||||||
|
let tags = map(copy(g:himalaya_context), 'printf(" +%s", v:val)')
|
||||||
|
let buff_name .= join(tags, '')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if buff_name != s:buff_name
|
||||||
|
execute 'silent! enew'
|
||||||
|
execute 'silent! bwipeout ' . s:buff_name
|
||||||
|
let s:buff_name = buff_name
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:exists_in(list, item)
|
||||||
|
return index(a:list, a:item) > -1
|
||||||
|
endfunction
|
87
vim/autoload/himalaya/utils.vim
Normal file
87
vim/autoload/himalaya/utils.vim
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
" ------------------------------------------------------------------ # Compose #
|
||||||
|
|
||||||
|
function! himalaya#utils#compose(...)
|
||||||
|
let funcs = map(reverse(copy(a:000)), 'function(v:val)')
|
||||||
|
return function('s:compose', [funcs])
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:compose(funcs, arg)
|
||||||
|
let data = a:arg
|
||||||
|
|
||||||
|
for Func in a:funcs
|
||||||
|
let data = Func(data)
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return data
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" --------------------------------------------------------------------- # Trim #
|
||||||
|
|
||||||
|
function! himalaya#utils#trim(str)
|
||||||
|
return himalaya#utils#compose('s:trim_left', 's:trim_right')(a:str)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:trim_left(str)
|
||||||
|
return substitute(a:str, '^\s*', '', 'g')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:trim_right(str)
|
||||||
|
return substitute(a:str, '\s*$', '', 'g')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" ------------------------------------------------------------------- # Assign #
|
||||||
|
|
||||||
|
function! himalaya#utils#assign(...)
|
||||||
|
let overrides = copy(a:000)
|
||||||
|
let base = remove(overrides, 0)
|
||||||
|
|
||||||
|
for override in overrides
|
||||||
|
for [key, val] in items(override)
|
||||||
|
let base[key] = val
|
||||||
|
unlet key val
|
||||||
|
endfor
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return base
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" ---------------------------------------------------------------------- # Sum #
|
||||||
|
|
||||||
|
function! himalaya#utils#sum(array)
|
||||||
|
let total = 0
|
||||||
|
|
||||||
|
for item in a:array
|
||||||
|
let total += item
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return total
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" ----------------------------------------------------------- # Match one item #
|
||||||
|
|
||||||
|
function! himalaya#utils#match_one(list_src, list_dest)
|
||||||
|
if empty(a:list_dest)
|
||||||
|
return 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
for item in a:list_src
|
||||||
|
if index(a:list_dest, item) > -1 | return 1 | endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
" --------------------------------------------------------------------- # Logs #
|
||||||
|
|
||||||
|
function! himalaya#utils#print_msg(msg)
|
||||||
|
echohl None
|
||||||
|
echom a:msg
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! himalaya#utils#print_err(err)
|
||||||
|
redraw
|
||||||
|
echohl ErrorMsg
|
||||||
|
echom a:err
|
||||||
|
echohl None
|
||||||
|
endfunction
|
149
vim/doc/himalaya.txt
Normal file
149
vim/doc/himalaya.txt
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
*himalaya.txt* - ⏱ Minimalist task & time manager.
|
||||||
|
|
||||||
|
_/ _/ _/ _/ _/_/_/_/ _/_/ _/_/_/
|
||||||
|
_/ _/ _/_/ _/ _/ _/ _/ _/
|
||||||
|
_/ _/ _/ _/ _/ _/_/_/ _/ _/ _/ _/_/
|
||||||
|
_/ _/ _/ _/_/ _/ _/ _/ _/ _/
|
||||||
|
_/_/ _/ _/ _/ _/_/ _/_/_/
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
TABLE OF CONTENTS *himalaya-contents*
|
||||||
|
|
||||||
|
Requirements .......................................... |himalaya-requirements|
|
||||||
|
Usage ........................................................ |himalaya-usage|
|
||||||
|
Mappings ................................................. |himalaya-mappings|
|
||||||
|
License .................................................... |himalaya-license|
|
||||||
|
Contributing .......................................... |himalaya-contributing|
|
||||||
|
Changelog ................................................ |himalaya-changelog|
|
||||||
|
Credits .................................................... |himalaya-credits|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
REQUIREMENTS *himalaya-requirements*
|
||||||
|
|
||||||
|
- Vim or Neovim
|
||||||
|
- Himalaya CLI {1}
|
||||||
|
https://github.com/soywod/himalaya#installation {1}
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
USAGE *himalaya-usage*
|
||||||
|
|
||||||
|
It is recommanded to first read the Himalaya CLI documentation {1} to understand
|
||||||
|
the concept.
|
||||||
|
|
||||||
|
To list tasks:
|
||||||
|
>
|
||||||
|
:Himalaya
|
||||||
|
<
|
||||||
|
Then you can manage tasks using Vim mapping. The table will automatically
|
||||||
|
readjust on buffer save (`:w`). See https://github.com/soywod/himalaya.vim.
|
||||||
|
|
||||||
|
https://github.com/soywod/himalaya#readme {1}
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
MAPPINGS *himalaya-mappings*
|
||||||
|
|
||||||
|
Here the default mappings:
|
||||||
|
|
||||||
|
List done tasks gd
|
||||||
|
List deleted tasks gD
|
||||||
|
Toggle task <CR>
|
||||||
|
Show task infos {K}
|
||||||
|
Set context {gc}
|
||||||
|
Show worktime {gw}
|
||||||
|
Jump to the next cell <C-n>
|
||||||
|
Jump to the prev cell <C-p>
|
||||||
|
Delete in cell {dic}
|
||||||
|
Change in cell {cic}
|
||||||
|
Visual in cell {vic}
|
||||||
|
|
||||||
|
You can customize them:
|
||||||
|
>
|
||||||
|
nmap gd <plug>(himalaya-list-done)
|
||||||
|
nmap gD <plug>(himalaya-list-deleted)
|
||||||
|
nmap <cr> <plug>(himalaya-toggle)
|
||||||
|
nmap K <plug>(himalaya-info)
|
||||||
|
nmap gc <plug>(himalaya-context)
|
||||||
|
nmap gw <plug>(himalaya-worktime)
|
||||||
|
nmap <c-n> <plug>(himalaya-next-cell)
|
||||||
|
nmap <c-p> <plug>(himalaya-prev-cell)
|
||||||
|
nmap dic <plug>(himalaya-delete-in-cell)
|
||||||
|
nmap cic <plug>(himalaya-change-in-cell)
|
||||||
|
nmap vic <plug>(himalaya-visual-in-cell)
|
||||||
|
<
|
||||||
|
==============================================================================
|
||||||
|
LICENSE *himalaya-license*
|
||||||
|
|
||||||
|
Copyright © 2019-2020 Clément DOUIN <clement.douin@posteo.net>
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer in the documentation and/or other materials provided
|
||||||
|
with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of Author name here nor the names of other
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
CONTRIBUTING *himalaya-contributing*
|
||||||
|
|
||||||
|
Report any bugs here: https://github.com/soywod/himalaya.vim/issues
|
||||||
|
Feel free to submit pull requests: https://github.com/soywod/himalaya.vim/pulls
|
||||||
|
|
||||||
|
1) Git commit messages follow the `Angular Convention` {1}, but contain only a
|
||||||
|
subject.
|
||||||
|
>
|
||||||
|
- Use imperative, present tense: “change” not “changed” nor “changes”
|
||||||
|
- Don't capitalize first letter
|
||||||
|
- No dot (.) at the end
|
||||||
|
<
|
||||||
|
2) Vim code should be as clean as possible, variables and functions use the
|
||||||
|
snake case convention. A line should never contain more than `80` characters.
|
||||||
|
|
||||||
|
3) Tests should be added for each new functionality. Be sure to run tests
|
||||||
|
before proposing a pull request.
|
||||||
|
|
||||||
|
https://gist.github.com/stephenparish/9941e89d80e2bc58a153 {1}
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
CHANGELOG *himalaya-changelog*
|
||||||
|
|
||||||
|
See https://github.com/soywod/himalaya.vim/blob/master/CHANGELOG.md.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
CREDITS *himalaya-credits*
|
||||||
|
|
||||||
|
- Taskwarrior, a task manager {1}
|
||||||
|
- Timewarrior, a time tracker {2}
|
||||||
|
- vim-taskwarrior, a Taskwarrior wrapper for vim {3}
|
||||||
|
- vimwiki, for the idea of managing tasks inside a buffer {4}
|
||||||
|
- Kronos, the Himalaya predecessor {5}
|
||||||
|
|
||||||
|
https://taskwarrior.org {1}
|
||||||
|
https://taskwarrior.org/docs/timewarrior {2}
|
||||||
|
https://github.com/blindFS/vim-taskwarrior {3}
|
||||||
|
https://github.com/vimwiki/vimwiki {4}
|
||||||
|
https://github.com/soywod/kronos.vim {5}
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
vim:tw=78:ts=4:ft=help:norl:
|
21
vim/ftplugin/himalaya-msg-list.vim
Normal file
21
vim/ftplugin/himalaya-msg-list.vim
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
setlocal buftype=nofile
|
||||||
|
setlocal cursorline
|
||||||
|
setlocal nomodifiable
|
||||||
|
setlocal nowrap
|
||||||
|
setlocal startofline
|
||||||
|
|
||||||
|
nnoremap <buffer><silent>q :bwipeout<cr>
|
||||||
|
nnoremap <buffer><silent><cr> :bwipeout<cr>
|
||||||
|
nnoremap <buffer><silent><esc> :bwipeout<cr>
|
||||||
|
|
||||||
|
call himalaya#shared#define_bindings([
|
||||||
|
\["n", "gm" , "mbox#input" ],
|
||||||
|
\["n", "gp" , "mbox#prev_page" ],
|
||||||
|
\["n", "gn" , "mbox#next_page" ],
|
||||||
|
\["n", "<cr>", "msg#read" ],
|
||||||
|
\["n", "gw" , "msg#write" ],
|
||||||
|
\["n", "gr" , "msg#reply" ],
|
||||||
|
\["n", "gR" , "msg#reply_all" ],
|
||||||
|
\["n", "gf" , "msg#forward" ],
|
||||||
|
\["n", "ga" , "msg#attachments"],
|
||||||
|
\])
|
18
vim/ftplugin/himalaya-msg-read.vim
Normal file
18
vim/ftplugin/himalaya-msg-read.vim
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
setlocal bufhidden=wipe
|
||||||
|
setlocal buftype=nofile
|
||||||
|
setlocal cursorline
|
||||||
|
setlocal foldexpr=himalaya#shared#thread_fold(v:lnum)
|
||||||
|
setlocal foldlevel=0
|
||||||
|
setlocal foldlevelstart=0
|
||||||
|
setlocal foldmethod=expr
|
||||||
|
setlocal nomodifiable
|
||||||
|
setlocal nowrap
|
||||||
|
setlocal startofline
|
||||||
|
|
||||||
|
call himalaya#shared#define_bindings([
|
||||||
|
\["n", "gw", "msg#write" ],
|
||||||
|
\["n", "gr", "msg#reply" ],
|
||||||
|
\["n", "gR", "msg#reply_all" ],
|
||||||
|
\["n", "gf", "msg#forward" ],
|
||||||
|
\["n", "ga", "msg#attachments"],
|
||||||
|
\])
|
13
vim/ftplugin/himalaya-msg-write.vim
Normal file
13
vim/ftplugin/himalaya-msg-write.vim
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
setlocal cursorline
|
||||||
|
setlocal foldexpr=himalaya#shared#thread_fold(v:lnum)
|
||||||
|
setlocal foldlevel=0
|
||||||
|
setlocal foldlevelstart=0
|
||||||
|
setlocal foldmethod=expr
|
||||||
|
setlocal nowrap
|
||||||
|
setlocal startofline
|
||||||
|
|
||||||
|
augroup himalaya
|
||||||
|
autocmd! * <buffer>
|
||||||
|
autocmd BufWriteCmd <buffer> call himalaya#msg#draft_save()
|
||||||
|
autocmd BufUnload <buffer> call himalaya#msg#draft_handle()
|
||||||
|
augroup end
|
11
vim/plugin/himalaya.vim
Normal file
11
vim/plugin/himalaya.vim
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
if exists("g:himalaya_loaded")
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
let g:himalaya_loaded = 1
|
||||||
|
|
||||||
|
if !executable("himalaya")
|
||||||
|
throw "Himalaya CLI not found, see https://github.com/soywod/himalaya#installation"
|
||||||
|
endif
|
||||||
|
|
||||||
|
command! Himalaya call himalaya#msg#list()
|
24
vim/syntax/himalaya-msg-list.vim
Normal file
24
vim/syntax/himalaya-msg-list.vim
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
if exists("b:current_syntax")
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
syntax match hya_sep /|/
|
||||||
|
syntax match hya_uid /^|.\{-}|/ contains=hya_sep
|
||||||
|
syntax match hya_flags /^|.\{-}|.\{-}|/ contains=hya_uid,hya_sep
|
||||||
|
syntax match hya_subject /^|.\{-}|.\{-}|.\{-}|/ contains=hya_uid,hya_flags,hya_sep
|
||||||
|
syntax match hya_sender /^|.\{-}|.\{-}|.\{-}|.\{-}|/ contains=hya_uid,hya_flags,hya_subject,hya_sep
|
||||||
|
syntax match hya_date /^|.\{-}|.\{-}|.\{-}|.\{-}|.\{-}|/ contains=hya_uid,hya_flags,hya_subject,hya_sender,hya_sep
|
||||||
|
syntax match hya_head /.*\%1l/ contains=hya_sep
|
||||||
|
syntax match hya_unseen /^|.\{-}|🟓.*$/ contains=hya_sep
|
||||||
|
|
||||||
|
highlight default link hya_sep VertSplit
|
||||||
|
highlight default link hya_uid Identifier
|
||||||
|
highlight default link hya_flags Special
|
||||||
|
highlight default link hya_subject String
|
||||||
|
highlight default link hya_sender Structure
|
||||||
|
highlight default link hya_date Constant
|
||||||
|
|
||||||
|
highlight hya_head term=bold,underline cterm=bold,underline gui=bold,underline
|
||||||
|
highlight hya_unseen term=bold cterm=bold gui=bold
|
||||||
|
|
||||||
|
let b:current_syntax = "himalaya-msg-list"
|
Loading…
Reference in a new issue