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

feat(mail): use bundle vim-mail

This commit is contained in:
Shidong Wang 2021-10-23 15:34:04 +08:00
parent b74dd23e4d
commit fa43ef2043
No known key found for this signature in database
GPG Key ID: 41BB7053E835C848
12 changed files with 471 additions and 12 deletions

View File

@ -6,9 +6,24 @@
" License: GPLv3
"=============================================================================
""
" @section mail, layers-mail
" @parentsection layers
" The `mail` layer provides basic function to connected to mail server.
"
" @subsection layer options
"
" 1. `ssh_port`: set the port of mail server
"
" @subsection key bindings
" >
" Key Bingding Description
" SPC a m open mail client
" <
function! SpaceVim#layers#mail#plugins() abort
return [
\ ['vim-mail/vim-mail',{ 'merged' : 0, 'loadconf' : 1}],
\ [g:_spacevim_root_dir . 'bundle/vim-mail', {'merged' : 0, 'loadconf' : 1}],
\ ]
endfunction

1
bundle/vim-mail/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
tags

13
bundle/vim-mail/README.md Normal file
View File

@ -0,0 +1,13 @@
# vim-mail[WIP]
manager mail in vim
[![](https://spacevim.org/img/build-with-SpaceVim.svg)](https://spacevim.org)
## screenshort
![Mail list](https://user-images.githubusercontent.com/13142418/31721165-3b8d93f6-b44b-11e7-8be4-f62180c4f762.png)
## usage
- `call mail#client#open()`: open vim-mail windows

View File

@ -0,0 +1,37 @@
function! mail#new()
let f = tempname() . '/new_email'
exe 'edit ' . f
setf mail
call setline(1, s:build_header())
normal! G
endfunction
let s:headers = {
\ 'From' : 'From: "' . g:mail_sending_name . '" <' . g:mail_sending_address . '>',
\ 'Reply-To' : 'Reply-To: "' . g:mail_sending_name . '" <' . g:mail_sending_address . '>',
\ }
function! s:build_header(...) abort
let header = []
call add(header, s:headers['From'])
call add(header, 'Subject:')
call add(header, 'Data:' . strftime("%c"))
call add(header, 'To:')
call add(header, s:headers['Reply-To'])
call add(header, '')
return header
endfunction
function! mail#list() abort
endfunction
" number of unseen message in INBOX
function! mail#statusline()
return mail#client#unseen()
endfunction

View File

@ -0,0 +1,111 @@
let s:job_id = 0
let s:job_noop_timer = ''
let s:JOB = SpaceVim#api#import('job')
function! mail#client#connect(ip, port)
let argv = ['telnet', a:ip, a:port]
let s:job_id = s:JOB.start(argv,
\ {
\ 'on_stdout' : function('s:on_stdout'),
\ 'on_stderr' : function('s:on_stderr'),
\ 'on_exit' : function('s:on_exit'),
\ }
\ )
endfunction
" Wed, 06 Sep 2017 02:55:41 +0000 ===> 2017-09-06
let s:__months = {
\ 'Sep' : 9,
\ }
function! s:convert(date) abort
let info = split(a:date, ' ')
let year = info[3]
let m = get(s:__months, info[2], 00)
let day = len(info[1]) == 1 ? '0' . info[1] : info[1]
return join([year, m, day], '-')
endfunction
function! s:noop(id) abort
call mail#client#send(mail#command#noop())
endfunction
let s:_mail_id = -1
let s:_mail_date = ''
let s:_mail_from = ''
let s:_mail_subject = ''
let s:mail_unseen = 0
function! s:parser(data) abort
if type(a:data) == 3
for data in a:data
call mail#client#logger#info('STDOUT: ' . data)
if data =~ '^\* \d\+ FETCH '
let s:_mail_id = matchstr(data, '\d\+')
elseif data =~ '^From: '
let s:_mail_from = substitute(data, '^From: ', '', 'g')
let s:_mail_from .= repeat(' ', 50 - len(s:_mail_from))
elseif data =~ '^Date: '
let s:_mail_date = s:convert(substitute(data, '^Date: ', '', 'g'))
elseif data =~ '^Subject: '
let s:_mail_subject = substitute(data, '^Subject: ', '', 'g')
call mail#client#mailbox#updatedir(s:_mail_id, s:_mail_from, s:_mail_date, s:_mail_subject, mail#client#win#currentDir())
elseif data =~ '* STATUS INBOX'
let s:mail_unseen = matchstr(data, '\d\+')
endif
endfor
else
echom a:data
endif
endfunction
function! s:on_stdout(id, data, event) abort
call s:parser(a:data)
endfunction
function! s:on_stderr(id, data, event) abort
for data in a:data
call mail#client#logger#error('STDERR: ' . data)
endfor
endfunction
function! s:on_exit(id, data, event) abort
call s:parser(a:data)
let s:job_id = 0
if !empty(s:job_noop_timer)
call timer_stop(s:job_noop_timer)
let s:job_noop_timer = ''
endif
endfunction
function! mail#client#send(command)
call mail#client#logger#info('Send command: ' . a:command)
call s:JOB.send(s:job_id, a:command)
endfunction
function! mail#client#open()
if s:job_id == 0
let username = input('USERNAME: ')
let password = input('PASSWORD: ')
if !empty(username) && !empty(password)
call mail#client#connect('imap.163.com', 143)
call mail#client#send(mail#command#login(username, password))
call mail#client#send(mail#command#select(mail#client#win#currentDir()))
call mail#client#send(mail#command#fetch('1:15', 'BODY[HEADER.FIELDS ("DATE" "FROM" "SUBJECT")]'))
call mail#client#send(mail#command#status('INBOX', '["RECENT"]'))
let s:job_noop_timer = timer_start(20000, function('s:noop'), {'repeat' : -1})
endif
endif
call mail#client#win#open()
endfunction
function! mail#client#unseen()
return s:mail_unseen
endfunction

View File

@ -0,0 +1,28 @@
let s:LOGGER = SpaceVim#api#import('logger')
let g:wsd = keys(s:LOGGER)
call s:LOGGER.set_name('vim-mail')
call s:LOGGER.set_level(1)
let s:LOGGER.silent = 0
function! mail#client#logger#info(msg)
call s:LOGGER.info(a:msg)
endfunction
function! mail#client#logger#error(msg)
call s:LOGGER.error(a:msg)
endfunction
function! mail#client#logger#warn(msg)
call s:LOGGER.warn(a:msg)
endfunction
function! mail#client#logger#view()
call s:LOGGER.view()
endfunction

View File

@ -0,0 +1,41 @@
let s:mail_box = {}
function! mail#client#mailbox#get(dir)
return get(s:mail_box, a:dir, {})
endfunction
function! mail#client#mailbox#updatedir(id, from, data, subject, dir)
if !has_key(s:mail_box, a:dir)
call extend(s:mail_box, {a:dir :
\ { a:id :
\ {
\ 'from' : a:from,
\ 'subject' : a:subject,
\ 'data' : a:data,
\ },
\ },
\ }
\ )
else
if !has_key(s:mail_box[a:dir], a:id)
call extend(s:mail_box[a:dir],
\ { a:id :
\ {
\ 'from' : a:from,
\ 'subject' : a:subject,
\ 'data' : a:data,
\ },
\ },
\ )
else
call extend(s:mail_box[a:dir][a:id],
\ {
\ 'from' : a:from,
\ 'subject' : a:subject,
\ 'data' : a:data,
\ },
\ )
endif
endif
endfunction

View File

@ -0,0 +1,50 @@
" load APIs
"
let s:BUFFER = SpaceVim#api#import('vim#buffer')
let s:bufnr = 0
let s:win_name = 'home'
let s:win_dir = 'INBOX'
let s:win_unseen = {}
function! mail#client#win#open()
if s:bufnr == 0
split __VIM_MAIL__
let s:bufnr = bufnr('%')
setlocal buftype=nofile nobuflisted nolist noswapfile nowrap cursorline nospell nomodifiable nowrap norelativenumber number
nnoremap <silent><buffer> <F5> :call <SID>refresh()<Cr>
setfiletype VimMailClient
else
split
exe 'b' . s:bufnr
endif
call s:refresh()
endfunction
function! mail#client#win#currentDir()
return s:win_dir
endfunction
function! s:refresh() abort
let mails = mail#client#mailbox#get(s:win_dir)
let lines = ['DATA FROM SUBJECT']
for id in keys(mails)
call add(lines, mails[id]['data'] . ' ' . mails[id]['from'] . ' ' . mails[id]['subject'])
endfor
call setbufvar(s:bufnr, '&modifiable', 1)
call s:BUFFER.buf_set_lines(s:bufnr, 0, len(lines), 0, lines)
call setbufvar(s:bufnr, '&modifiable', 0)
endfunction
function! mail#client#win#status() abort
return {
\ 'dir' : s:win_dir,
\ 'unseen' : get(s:win_unseen, 's:win_dir', 0),
\ }
endfunction

View File

@ -0,0 +1,35 @@
" http://blog.csdn.net/thundercumt/article/details/51742115
" http://blog.csdn.net/shanghaojiabohetang/article/details/74486196
" LOGIN
" LIST
" SELECT
let s:PASSWORD = SpaceVim#api#import('password')
let s:cmd_prefix = s:PASSWORD.generate_simple(5)
function! mail#command#login(username, password)
return join([s:cmd_prefix, 'LOGIN', a:username, a:password], ' ')
endfunction
function! mail#command#list(dir, patten)
return join([s:cmd_prefix, 'LIST', a:dir, a:patten], ' ')
endfunction
" msg should be a list like ['MESSAGES', 'UNSEEN', 'RECENT']
function! mail#command#status(dir, msg)
endfunction
function! mail#command#select(dir)
return join([s:cmd_prefix, 'SELECT', a:dir], ' ')
endfunction
" A FETCH 1:4 BODY[HEADER.FIELDS ("DATA" "FROM" "SUBJECT")]
function! mail#command#fetch(id, data)
return join([s:cmd_prefix, 'FETCH', a:id, a:data], ' ')
endfunction
function! mail#command#noop()
return join([s:cmd_prefix, 'NOOP'], ' ')
endfunction

View File

@ -0,0 +1,17 @@
"=============================================================================
" mail.vim --- mail manager for vim
" Copyright (c) 2016-2017 Shidong Wang & Contributors
" Author: Shidong Wang < wsdjeg at 163.com >
" URL: https://github.com/vim-mail/vim-mail
" License: MIT license
"=============================================================================
let g:mail_command = 'telnet'
let g:mail_method = 'imap'
let g:mail_sending_name = 'Shidong Wang'
let g:mail_sending_address = 'wsdjeg@163.com'
let g:mail_logger_silent = 0
if !exists('g:mail_directory')
let g:mail_directory = expand('~/.vim-mail/')
endif

View File

@ -0,0 +1,94 @@
"=============================================================================
" mail.vim --- mail syntax file for vim
" Copyright (c) 2016-2017 Shidong Wang & Contributors
" Author: Shidong Wang < wsdjeg at 163.com >
" URL: https://github.com/vim-mail/vim-mail
" License: MIT license
"=============================================================================
" Quit when a syntax file was already loaded
if exists("b:current_syntax")
finish
endif
" The mail header is recognized starting with a "keyword:" line and ending
" with an empty line or other line that can't be in the header. All lines of
" the header are highlighted. Headers of quoted messages (quoted with >) are
" also highlighted.
" Syntax clusters
syn cluster mailHeaderFields contains=mailHeaderKey,mailSubject,mailHeaderEmail,@mailLinks
syn cluster mailLinks contains=mailURL,mailEmail
syn cluster mailQuoteExps contains=mailQuoteExp1,mailQuoteExp2,mailQuoteExp3,mailQuoteExp4,mailQuoteExp5,mailQuoteExp6
syn case match
" For "From " matching case is required. The "From " is not matched in quoted
" emails
syn region mailHeader contains=@mailHeaderFields start="^From " skip="^\s" end="\v^[-A-Za-z0-9]*([^-A-Za-z0-9:]|$)"me=s-1
syn match mailHeaderKey contained contains=mailEmail "^From\s.*$"
syn case ignore
" Nothing else depends on case. Headers in properly quoted (with "> " or ">")
" emails are matched
syn region mailHeader contains=@mailHeaderFields,@mailQuoteExps start="^\z(\(> \?\)*\)\v(newsgroups|from|((in-)?reply-)?to|b?cc|subject|return-path|received|date|replied):" skip="^\z1\s" end="\v^\z1[-a-z0-9]*([^-a-z0-9:]|$)"me=s-1 end="\v^\z1@!"me=s-1 end="\v^\z1(\> ?)+"me=s-1
syn region mailHeaderKey contained contains=mailHeaderEmail,mailEmail,@mailQuoteExps start="\v(^(\> ?)*)@<=(to|b?cc):" skip=",$" end="$"
syn match mailHeaderKey contained contains=mailHeaderEmail,mailEmail "\v(^(\> ?)*)@<=(from|reply-to):.*$"
syn match mailHeaderKey contained "\v(^(\> ?)*)@<=date:"
syn match mailSubject contained "\v(^(\> ?)*)@<=subject:.*$"
" Anything in the header between < and > is an email address
syn match mailHeaderEmail contained "<.\{-}>"
" Mail Signatures. (Begin with "--", end with change in quote level)
syn region mailSignature contains=@mailLinks,@mailQuoteExps start="^\z(\(> \?\)*\)-- *$" end="^\z1$" end="^\z1\@!"me=s-1 end="^\z1\(> \?\)\+"me=s-1
" URLs start with a known protocol or www,web,w3.
syn match mailURL `\v<(((https?|ftp|gopher)://|(mailto|file|news):)[^' <>"]+|(www|web|w3)[a-z0-9_-]*\.[a-z0-9._-]+\.[^' <>"]+)[a-z0-9/]`
syn match mailEmail "\v[_=a-z\./+0-9-]+\@[a-z0-9._-]+\a{2}"
" Make sure quote markers in regions (header / signature) have correct color
syn match mailQuoteExp1 contained "\v^(\> ?)"
syn match mailQuoteExp2 contained "\v^(\> ?){2}"
syn match mailQuoteExp3 contained "\v^(\> ?){3}"
syn match mailQuoteExp4 contained "\v^(\> ?){4}"
syn match mailQuoteExp5 contained "\v^(\> ?){5}"
syn match mailQuoteExp6 contained "\v^(\> ?){6}"
" Even and odd quoted lines. order is imporant here!
syn match mailQuoted1 contains=mailHeader,@mailLinks,mailSignature "^\([a-z]\+>\|[]|}>]\).*$"
syn match mailQuoted2 contains=mailHeader,@mailLinks,mailSignature "^\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{2}.*$"
syn match mailQuoted3 contains=mailHeader,@mailLinks,mailSignature "^\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{3}.*$"
syn match mailQuoted4 contains=mailHeader,@mailLinks,mailSignature "^\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{4}.*$"
syn match mailQuoted5 contains=mailHeader,@mailLinks,mailSignature "^\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{5}.*$"
syn match mailQuoted6 contains=mailHeader,@mailLinks,mailSignature "^\(\([a-z]\+>\|[]|}>]\)[ \t]*\)\{6}.*$"
" Need to sync on the header. Assume we can do that within 30 lines
if exists("b:mail_minlines")
exec "syn sync minlines=" . b:mail_minlines
else
syn sync minlines=30 " All syntax groups are short
endif
" Define the default highlighting.
hi def link mailHeader Statement
hi def link mailHeaderKey Type
hi def link mailSignature PreProc
hi def link mailHeaderEmail mailEmail
hi def link mailEmail Special
hi def link mailURL String
hi def link mailSubject LineNR
hi def link mailQuoted1 Comment
hi def link mailQuoted3 mailQuoted1
hi def link mailQuoted5 mailQuoted1
hi def link mailQuoted2 Identifier
hi def link mailQuoted4 mailQuoted2
hi def link mailQuoted6 mailQuoted2
hi def link mailQuoteExp1 mailQuoted1
hi def link mailQuoteExp2 mailQuoted2
hi def link mailQuoteExp3 mailQuoted3
hi def link mailQuoteExp4 mailQuoted4
hi def link mailQuoteExp5 mailQuoted5
hi def link mailQuoteExp6 mailQuoted6
let b:current_syntax = "mail"

View File

@ -191,17 +191,18 @@ CONTENTS *SpaceVim-contents*
105. lang#zig.................................|SpaceVim-layers-lang-zig|
106. language server protocol......................|SpaceVim-layers-lsp|
107. leaderf...................................|SpaceVim-layers-leaderf|
108. operator.................................|SpaceVim-layers-operator|
109. shell.......................................|SpaceVim-layers-shell|
110. ssh...........................................|SpaceVim-layers-ssh|
111. test.........................................|SpaceVim-layers-test|
112. tmux.........................................|SpaceVim-layers-tmux|
113. tools#dash.............................|SpaceVim-layers-tools-dash|
114. tools#mpv...............................|SpaceVim-layers-tools-mpv|
115. tools#zeal.............................|SpaceVim-layers-tools-zeal|
116. treesitter.............................|SpaceVim-layers-treesitter|
117. ui.............................................|SpaceVim-layers-ui|
118. unite.......................................|SpaceVim-layers-unite|
108. mail.........................................|SpaceVim-layers-mail|
109. operator.................................|SpaceVim-layers-operator|
110. shell.......................................|SpaceVim-layers-shell|
111. ssh...........................................|SpaceVim-layers-ssh|
112. test.........................................|SpaceVim-layers-test|
113. tmux.........................................|SpaceVim-layers-tmux|
114. tools#dash.............................|SpaceVim-layers-tools-dash|
115. tools#mpv...............................|SpaceVim-layers-tools-mpv|
116. tools#zeal.............................|SpaceVim-layers-tools-zeal|
117. treesitter.............................|SpaceVim-layers-treesitter|
118. ui.............................................|SpaceVim-layers-ui|
119. unite.......................................|SpaceVim-layers-unite|
7. Usage....................................................|SpaceVim-usage|
1. buffers-and-files..................|SpaceVim-usage-buffers-and-files|
2. custom_plugins........................|SpaceVim-usage-custom_plugins|
@ -4620,6 +4621,22 @@ The following key bindings will be enabled when this layer is loaded:
<Leader> f r Resumes Unite window
<
==============================================================================
MAIL *SpaceVim-layers-mail*
The `mail` layer provides basic function to connected to mail server.
LAYER OPTIONS
1. `ssh_port`: set the port of mail server
KEY BINDINGS
>
Key Bingding Description
SPC a m open mail client
<
==============================================================================
OPERATOR *SpaceVim-layers-operator*