├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── autoload
├── ctrlp
│ └── slackmemo.vim
└── slackmemo.vim
├── doc
└── slackmemo-vim.txt
└── plugin
└── slackmemo.vim
/.gitignore:
--------------------------------------------------------------------------------
1 | doc/tags
2 | .cache
3 | .cache2
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 0.2.1
2 |
3 | * Replace `channels.xxx` with `conversations.xxx`, Thanks [cympfh](https://github.com/cympfh) !
4 |
5 |
6 | ## 0.2.0
7 |
8 | * Fix refetch list errors.
9 | * Fix versioning. (Should made it 0.2.0 when added `:SlackMemoSearch`.)
10 |
11 |
12 | ## 0.1.3
13 |
14 | * Fix typo...
15 |
16 |
17 | ## 0.1.2
18 |
19 | * Add `:SlackMemoSearch` method. Thanks [@h-michael](https://github.com/h-michael) !.
20 |
21 |
22 | ## 0.1.1
23 |
24 | * Fix url formating decode
25 | - `` => `http://hoge.com/fuga/`
26 | * Fix deletion memo bugs. (ref: [issue-#1](https://github.com/tsuyoshiwada/slack-memo-vim/issues/1))
27 |
28 |
29 | ## 0.1.0
30 |
31 | * Support CtrlP lists.
32 |
33 |
34 | ## 0.0.2
35 |
36 | * Fix error when buffer with same name already exists.
37 |
38 |
39 | ## 0.0.1
40 |
41 | * First release.
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2016 by tsuyoshiwada.
2 | modification, are permitted provided that the following conditions are met:
3 |
4 | 1. Redistributions of source code must retain the above copyright notice,
5 | this list of conditions and the following disclaimer.
6 | 2. Redistributions in binary form must reproduce the above copyright notice,
7 | this list of conditions and the following disclaimer in the documentation
8 | and/or other materials provided with the distribution.
9 |
10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
11 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
12 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
14 | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
15 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
19 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
20 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
21 | OF THE POSSIBILITY OF SUCH DAMAGE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | slack-memo.vim
2 | ==============
3 |
4 | Simple memo manager with Vim using Slack.
5 |
6 |
7 | ## Screenshots
8 |
9 | 
10 |
11 |
12 | ## Usage
13 |
14 | Post a memo on Slack.
15 |
16 | ```vim
17 | :SlackMemoPost
18 | ```
19 |
20 | List memos on Slack.
21 |
22 | ```vim
23 | :SlackMemoList
24 | ```
25 |
26 | List memos on Slack with CtrlP.
27 |
28 | ```vim
29 | :SlackMemoCtrlP
30 | ```
31 |
32 | List search result memos on Slack
33 | ```vim
34 | :SlackMemoSearch search query
35 | ```
36 |
37 |
38 | ### Keymaps in the memo list
39 |
40 | The following keymaps are available in the buffer of the memo list. It does not work with CtrlP.
41 |
42 | | key | description |
43 | |:---------------|:------------------------|
44 | | `Enter` or `o` | Open memo on cursor. |
45 | | `Esc` or `q` | Close memo list window. |
46 | | `d` | Delete memo on cursor. |
47 | | `y` | Yank memo on cursor. |
48 | | `r` | Update list window. |
49 |
50 | You can udpate it by saving memo opened in buffer.
51 |
52 |
53 | ## Install
54 |
55 | It's easy to install using plugin manager.
56 | Depending on your plugin manager, please add the following to `.vimrc`.
57 |
58 | ### Install with [dein](https://github.com/Shougo/dein.vim)
59 |
60 | ```vim
61 | call dein#add('tsuyoshiwada/slack-memo-vim', {'depends': 'mattn/webapi-vim'})
62 | ```
63 |
64 | ### Install with [NeoBundle](https://github.com/Shougo/neobundle.vim)
65 |
66 | ```vim
67 | NeoBundle 'tsuyoshiwada/slack-memo-vim', {'depends': 'mattn/webapi-vim'}
68 | ```
69 |
70 |
71 |
72 | ## Requirements
73 |
74 | * `curl` command.
75 | * [mattn/webapi-vim](https://github.com/mattn/webapi-vim).
76 |
77 |
78 |
79 | ## Setup
80 |
81 | You need a token to use [Slack Web API](https://api.slack.com/web).
82 | Please set your token on `g:slack_memo_token`. and set channel Id in `g:slack_memo_channel`.
83 |
84 | ```vim
85 | let g:slack_memo_token = ''
86 | let g:slack_memo_channel = ''
87 | ```
88 |
89 | If you do not know the Id right away, you can easily check with the [channel.list](https://api.slack.com/methods/channels.list/test) tester.
90 |
91 | Setup is complete!
92 |
93 |
94 |
95 | ## Tips
96 |
97 | ### Example keymap
98 |
99 | You can post / list easily with the following keymap.
100 |
101 | ```vim
102 | nnoremap smp :SlackMemoPost
103 | nnoremap sml :SlackMemoList
104 | ```
105 |
106 | ### GFM TODO list
107 |
108 | Support GFM TODO list. Posting following memo will be displayed with emoji on Slack.
109 |
110 | ```markdown
111 | * [x] Done1
112 | * [x] Done2
113 | * [ ] TODO...
114 | ```
115 |
116 |
117 |
118 | ## Contributing
119 |
120 | ### Reporting issue
121 |
122 | * [Welcome issue!](https://github.com/tsuyoshiwada/slack-memo-vim/issues)
123 |
124 | ### Contributing to code
125 |
126 | * Fork it.
127 | * Commit your changes and give your commit message.
128 | * Push to your fork on GitHub.
129 | * Open a Pull Request.
130 |
131 |
132 | ## Credit
133 |
134 | * [Slack](https://slack.com/).
135 | * Inspired by [gist-vim](https://github.com/mattn/gist-vim).
136 |
137 |
138 |
139 | ## License
140 |
141 | See the [LICENSE](https://raw.githubusercontent.com/tsuyoshiwada/slack-memo-vim/master/LICENSE).
142 |
143 |
144 |
145 | ## TODO
146 |
147 | * [x] Support [CtrlP](https://github.com/ctrlpvim/ctrlp.vim).
148 | * [ ] Support sort list.
149 | * [ ] Support vertical split list window.
150 | * [ ] Support open memo in new tab.
151 | * [ ] Delete multiple memos.
152 | * [ ] List more than 1000 memos.
153 |
154 |
--------------------------------------------------------------------------------
/autoload/ctrlp/slackmemo.vim:
--------------------------------------------------------------------------------
1 | "=============================================================================
2 | " File: slack-memo.vim
3 | " Version: 0.2.1
4 | " Author: tsuyoshiwada
5 | " WebPage: http://github.com/tsuyoshiwada/slack-memo-vim
6 | " License: BSD
7 |
8 | if exists('g:loaded_ctrlp_slackmemo') && g:loaded_ctrlp_slackmemo
9 | finish
10 | endif
11 | let g:loaded_ctrlp_slackmemo = 1
12 |
13 |
14 | let s:slackmemo_var = {
15 | \ 'init': 'ctrlp#slackmemo#init()',
16 | \ 'accept': 'ctrlp#slackmemo#accept',
17 | \ 'exit': 'ctrlp#slackmemo#exit()',
18 | \ 'lname': 'slackmemo',
19 | \ 'sname': 'slackmemo',
20 | \ 'type': 'path',
21 | \ 'sort': 0
22 | \ }
23 |
24 | if exists('g:ctrlp_ext_vars') && !empty(g:ctrlp_ext_vars)
25 | let g:ctrlp_ext_vars = add(g:ctrlp_ext_vars, s:slackmemo_var)
26 | else
27 | let g:ctrlp_ext_vars = [s:slackmemo_var]
28 | endif
29 |
30 |
31 | function! s:format_memo(memo) abort
32 | let ts = a:memo.ts
33 | let datetime = strftime("%Y-%m-%d", substitute(ts, '^\(\d\+\)\.\d\+$', '\1', 'g'))
34 | let title = split(a:memo.text, '\n')[0]
35 | let title = substitute(title, ' ', ' ', 'g')
36 | return printf('[%s](%s): %s', ts, datetime, title)
37 | endfunction
38 |
39 |
40 | function! ctrlp#slackmemo#init()
41 | let res = slackmemo#fetch()
42 | if !res.ok
43 | return ""
44 | endif
45 |
46 | let s:list = res.messages
47 | let s:messages = map(deepcopy(s:list), 's:format_memo(v:val)')
48 | return s:messages
49 | endfunction
50 |
51 |
52 | function! ctrlp#slackmemo#accept(mode, str)
53 | let ts = matchlist(filter(deepcopy(s:messages), 'v:val ==# a:str')[0], '^\[\(\d\+\.\d\+\)\]')[1]
54 | let memo = filter(deepcopy(s:list), 'slackmemo#compareMemoWithTS(v:val, "'.slackmemo#escapeTS(ts).'", 0)')[0]
55 |
56 | call ctrlp#exit()
57 | redraw!
58 | call slackmemo#open(memo)
59 | endfunction
60 |
61 |
62 | function! ctrlp#slackmemo#exit()
63 | if exists('s:list')
64 | unlet! s:list
65 | endif
66 |
67 | if exists('s:messages')
68 | unlet! s:messages
69 | endif
70 | endfunction
71 |
72 |
73 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars)
74 | function! ctrlp#slackmemo#id()
75 | return s:id
76 | endfunction
77 |
--------------------------------------------------------------------------------
/autoload/slackmemo.vim:
--------------------------------------------------------------------------------
1 | "=============================================================================
2 | " File: slack-memo.vim
3 | " Version: 0.2.1
4 | " Author: tsuyoshiwada
5 | " WebPage: http://github.com/tsuyoshiwada/slack-memo-vim
6 | " License: BSD
7 |
8 | let s:save_cpo = &cpoptions
9 | set cpoptions&vim
10 |
11 |
12 | if !executable('curl')
13 | echohl ErrorMsg | echomsg 'SlackMemo: require ''curl'' command' | echohl None
14 | finish
15 | endif
16 |
17 |
18 | if globpath(&rtp, 'autoload/webapi/http.vim') ==# ''
19 | echohl ErrorMsg | echomsg 'SlackMemo: require ''webapi'', install https://github.com/mattn/webapi-vim' | echohl None
20 | finish
21 | else
22 | call webapi#json#true()
23 | endif
24 |
25 |
26 | if !exists('g:slack_memo_token')
27 | echohl ErrorMsg | echomsg 'SlackMemo: You have not configured a token. Read '':help slack-memo-setup''.' | echohl None
28 | finish
29 | endif
30 |
31 |
32 | if !exists('g:slack_memo_channel')
33 | echohl ErrorMsg | echomsg 'SlackMemo: You have not configured a channel id. Read '':help slack-memo-setup''.' | echohl None
34 | finish
35 | endif
36 |
37 |
38 | function! s:setGlobalOptDefault(opt, val)
39 | if !exists('g:' . a:opt)
40 | let g:{a:opt} = a:val
41 | endif
42 | endfunction
43 |
44 | call s:setGlobalOptDefault('slack_memo_bot_username', 'Vim (bot)')
45 | call s:setGlobalOptDefault('slack_memo_bot_icon_url', '')
46 | call s:setGlobalOptDefault('slack_memo_bot_icon_emoji', '')
47 | call s:setGlobalOptDefault('slack_memo_list_count', 1000)
48 |
49 |
50 | let s:bufprefix = 'slackmemo' . (has('unix') ? ':' : '_')
51 | let s:listbufname = s:bufprefix.'-list'
52 | let s:slackapi = 'https://slack.com/api'
53 |
54 |
55 | " Utilities
56 | function! s:format_memo(memo) abort
57 | let ts = a:memo.ts
58 | let datetime = strftime("%Y-%m-%d %H:%M:%S", substitute(ts, '^\(\d\+\)\.\d\+$', '\1', 'g'))
59 | let title = split(a:memo.text, '\n')[0]
60 | let title = substitute(title, ' ', ' ', 'g')
61 | return printf('memo: %s [%s] %s', ts, datetime, title)
62 | endfunction
63 |
64 |
65 | function! slackmemo#compareMemoWithTS(memo, ts, cond)
66 | return a:cond == 0 ? a:memo.ts == a:ts : a:memo.ts != a:ts
67 | endfunction
68 |
69 |
70 | function! s:decode_memo_text(text)
71 | let text = a:text
72 | let text = join(map(split(text, "\n"), 's:encode_memo_line(v:val)'), "\n")
73 | return text
74 | endfunction
75 |
76 | function! s:encode_memo_line(line)
77 | let line = a:line
78 |
79 | " GFM - Checkbox
80 | if match(line, '[\*\-] \[ \]') > -1
81 | let line = substitute(line, '\([\*\-]\) \[ \]', '\1 :white_large_square: ', '')
82 | elseif match(line, '[\*\-] \[x\]') > -1
83 | let line = substitute(line, '\([\*\-]\) \[x\]', '\1 :ballot_box_with_check: ', '')
84 | endif
85 |
86 | return line
87 | endfunction
88 |
89 |
90 | function! s:decode_memo_line(line)
91 | let line = a:line
92 |
93 | " GFM - Checkbox
94 | if match(line, '[\*\-] :white_large_square: ') > -1
95 | let line = substitute(line, '\([\*\-]\) :white_large_square: ', '\1 [ ]', '')
96 | elseif match(line, '[\*\-] :ballot_box_with_check: ') > -1
97 | let line = substitute(line, '\([\*\-]\) :ballot_box_with_check: ', '\1 [x]', '')
98 | endif
99 |
100 | " URL
101 | if match(line, '') > -1
102 | let line = substitute(line, '<\(https\?:\/\/\S\+\)>', '\1', 'g')
103 | endif
104 |
105 | return line
106 | endfunction
107 |
108 |
109 | " SlackMemo
110 | function! slackmemo#escapeTS(ts)
111 | return substitute(a:ts, '\.', '\\.', 'g')
112 | endfunction
113 |
114 |
115 | function! slackmemo#decodeMemo(memo)
116 | let text = webapi#html#decodeEntityReference(a:memo.text)
117 | let text = join(map(split(text, "\n"), 's:decode_memo_line(v:val)'), "\n")
118 | let a:memo.text = text
119 | return a:memo
120 | endfunction
121 |
122 |
123 | function! slackmemo#fetch() abort
124 | let res = webapi#http#get(s:slackapi . '/conversations.history', {
125 | \ 'token': g:slack_memo_token,
126 | \ 'channel': g:slack_memo_channel,
127 | \ 'count': g:slack_memo_list_count
128 | \ })
129 | let res = webapi#json#decode(res.content)
130 |
131 | if res.ok
132 | let messages = map(copy(res.messages), 'slackmemo#decodeMemo(v:val)')
133 | let messages = filter(res.messages, '!empty(v:val.text)')
134 | let res.messages = messages
135 | endif
136 |
137 | return res
138 | endfunction
139 |
140 |
141 | function! slackmemo#list(mode) abort
142 | redraw | echon 'Listing slack memo... '
143 |
144 | let res = slackmemo#fetch()
145 |
146 | if !res.ok
147 | redraw | echon 'Bad request...'
148 | return
149 | endif
150 |
151 | if a:mode == "CtrlP"
152 | if globpath(&rtp, 'autoload/ctrlp.vim') ==# ''
153 | echohl ErrorMsg | echomsg 'SlackMemo: require ''CtrlP'', install https://github.com/ctrlpvim/ctrlp.vim' | echohl None
154 | return
155 | endif
156 | call ctrlp#init(ctrlp#slackmemo#id())
157 |
158 | else
159 | call s:SlackMemoListOpen()
160 | let oldpos = getpos('.')
161 | let b:messages = res.messages
162 | call s:SlackMemoListRender()
163 | call cursor(oldpos[1], oldpos[2])
164 | endif
165 | endfunction
166 |
167 |
168 | function! slackmemo#search(mode, ...) abort
169 | let query = join(a:000, ' ')
170 | let res = slackmemo#chnnel_name()
171 |
172 | if !res.ok
173 | redraw | echon 'Invalid channel id...'
174 | return
175 | endif
176 |
177 | let res = slackmemo#search_messages(res.channel.name, query)
178 | call s:SlackMemoListOpen()
179 | let oldpos = getpos('.')
180 | let b:messages = slackmemo#matches2memos(res.messages.matches)
181 | call s:SlackMemoListRender()
182 | call cursor(oldpos[1], oldpos[2])
183 | endfunction
184 |
185 |
186 | function! slackmemo#search_messages(channel_name, query) abort
187 | let query = 'in:' . a:channel_name . ' ' . a:query
188 |
189 | let res = webapi#http#get(s:slackapi . '/search.messages', {
190 | \ 'token': g:slack_memo_token,
191 | \ 'query': query,
192 | \ 'count': g:slack_memo_list_count
193 | \ })
194 | let res = webapi#json#decode(res.content)
195 |
196 | if res.ok
197 | let matches = map(copy(res.messages.matches), 'slackmemo#decodeMemo(v:val)')
198 | let messages = filter(res.messages.matches, '!empty(v:val.text)')
199 | let res.messages.matches = matches
200 | endif
201 |
202 | return res
203 | endfunction
204 |
205 |
206 | function! slackmemo#chnnel_name()
207 | let res = webapi#http#get(s:slackapi . '/conversations.info', {
208 | \ 'token': g:slack_memo_token,
209 | \ 'channel': g:slack_memo_channel
210 | \ })
211 | let res = webapi#json#decode(res.content)
212 |
213 | return res
214 | endfunction
215 |
216 |
217 | function! slackmemo#matches2memos(matches) abort
218 | let messages = []
219 | for m in a:matches
220 | let message = {
221 | \ 'type': m.type,
222 | \ 'ts': m.ts,
223 | \ 'user': m.user,
224 | \ 'text': m.text
225 | \ }
226 | call add(messages, message)
227 | endfor
228 | return messages
229 | endfunction
230 |
231 |
232 | function! slackmemo#post() abort
233 | let text = join(getline(0, '$'), "\n")
234 |
235 | if text == ''
236 | redraw | echon 'Post failed, current buffer is empty!'
237 | return
238 | endif
239 |
240 | redraw | echon 'Posting memo... '
241 |
242 | let res = webapi#http#post(s:slackapi . '/chat.postMessage', {
243 | \ 'token': g:slack_memo_token,
244 | \ 'channel': g:slack_memo_channel,
245 | \ 'text': s:decode_memo_text(text),
246 | \ 'username': g:slack_memo_bot_username,
247 | \ 'icon_url': g:slack_memo_bot_icon_url,
248 | \ 'icon_emoji': g:slack_memo_bot_icon_emoji
249 | \ })
250 | let res = webapi#json#decode(res.content)
251 |
252 | if !res.ok
253 | redraw | echon 'Post failed...'
254 | return
255 | endif
256 |
257 | let b:slackmemo = {
258 | \ 'ts': res.ts
259 | \ }
260 |
261 | silent exec 'noautocmd file' s:bufprefix.b:slackmemo.ts.'.md'
262 | call s:SlackMemoCurrentBufferToEditable()
263 | call s:SlackMemoAppend(res.message)
264 |
265 | redraw | echon 'Done !!'
266 | endfunction
267 |
268 |
269 | function! slackmemo#open(memo)
270 | let bufname = s:bufprefix . a:memo.ts . '.md'
271 | let winnum = bufwinnr(bufnr(bufname))
272 |
273 | if winnum != -1
274 | if winnum != bufwinnr('%')
275 | exe winnum 'wincmd w'
276 | endif
277 | setlocal modifiable
278 | else
279 | for bufnr in range(1, bufnr('$'))
280 | if bufname == bufname(bufnr)
281 | silent exe 'bw!' bufnr
282 | endif
283 | endfor
284 |
285 | exec 'silent noautocmd rightbelow new'
286 | bw!
287 |
288 | setlocal noswapfile
289 | silent exec 'noautocmd file' bufname
290 | endif
291 |
292 | filetype detect
293 | silent %d _
294 |
295 | call setline(1, split(a:memo.text, "\n"))
296 | call s:SlackMemoCurrentBufferToEditable()
297 | endfunction
298 |
299 |
300 | function! s:SlackMemoListWinnr()
301 | return bufwinnr(bufnr(s:listbufname))
302 | endfunction
303 |
304 |
305 | function! s:SlackMemoListOpen()
306 | let winnum = s:SlackMemoListWinnr()
307 | if winnum != -1
308 | if winnum != bufwinnr('%')
309 | exe winnum 'wincmd w'
310 | endif
311 | else
312 | exec 'silent noautocmd split' s:listbufname
313 | endif
314 | endfunction
315 |
316 |
317 | function! s:SlackMemoListClose()
318 | let winnum = bufwinnr(bufnr(s:listbufname))
319 | if winnum != -1
320 | if winnum != bufwinnr('%')
321 | exe winnum 'wincmd w'
322 | bw!
323 | endif
324 | endif
325 | endfunction
326 |
327 |
328 | function! s:SlackMemoListRender()
329 | if exists('b:messages')
330 | let messages = deepcopy(b:messages)
331 | else
332 | let messages = []
333 | endif
334 |
335 | setlocal modifiable
336 | silent %d _
337 |
338 | let lines = map(messages, 's:format_memo(v:val)')
339 | call setline(1, split(join(lines, "\n"), "\n"))
340 | sort! n /\%2c/
341 |
342 | syntax match SpecialKey /^memo: /he=e-1
343 | syntax match Title /^memo: \S\+/hs=s+5 contains=ALL
344 | syntax match Type /\[\d\{4}-\d\{2}-\d\{2} \d\{2}:\d\{2}:\d\{2}\]/ contains=ALL
345 |
346 | setlocal buftype=nofile bufhidden=hide noswapfile
347 | setlocal cursorline
348 | setlocal nomodified
349 | setlocal nomodifiable
350 | nohlsearch
351 |
352 | nnoremap :call SlackMemoListAction(0)
353 | nnoremap o :call SlackMemoListAction(0)
354 | nnoremap d :call SlackMemoListAction(1)
355 | nnoremap y :call SlackMemoListAction(2)
356 | nnoremap r :call SlackMemoListAction(3)
357 | nnoremap :bw
358 | nnoremap q :bw
359 |
360 | redraw | echo ''
361 | endfunction
362 |
363 |
364 | function! s:SlackMemoAppend(memo)
365 | let winnum = s:SlackMemoListWinnr()
366 | if winnum < 0
367 | return
368 | endif
369 |
370 | let currentwinnum = bufwinnr(bufnr(bufname('%')))
371 |
372 | call s:SlackMemoListOpen()
373 | let view = winsaveview()
374 | let b:messages = getbufvar('%', 'messages')
375 | call add(b:messages, a:memo)
376 | setlocal modifiable
377 | call append(0, s:format_memo(a:memo))
378 | setlocal nomodifiable
379 | call winrestview(view)
380 |
381 | exe currentwinnum 'wincmd w'
382 | endfunction
383 |
384 |
385 | function! s:SlackMemoCurrentBufferToEditable()
386 | setlocal buftype=acwrite bufhidden=hide noswapfile
387 | setlocal nomodified
388 | doau StdinReadPost,BufRead,BufReadPost
389 |
390 | augroup SlackMemoWrite
391 | autocmd! BufWriteCmd call s:SlackMemoWrite(expand(""))
392 | augroup END
393 | endfunction
394 |
395 |
396 | function! s:SlackMemoListAction(mode)
397 | let line = getline('.')
398 | let ts = matchstr(line, '^memo:\s*\zs\(\d\+\.\d\+\)\ze\.*')
399 |
400 | if a:mode == 0
401 | call s:SlackMemoOpen(ts)
402 | call s:SlackMemoListClose()
403 |
404 | elseif a:mode == 1
405 | if confirm('Really force delete memo?', "&Yes\n&No", 2) == 1
406 | call s:SlackMemoDelete(ts)
407 | endif
408 |
409 | elseif a:mode == 2
410 | let memo = s:GetSlackMemoByTS(ts)
411 | let @" = memo.text
412 | let @* = memo.text
413 | redraw | echon 'Yanked!'
414 |
415 | elseif a:mode == 3
416 | call slackmemo#list("default")
417 | endif
418 | endfunction
419 |
420 |
421 | function! s:GetSlackMemoByTS(ts)
422 | if !exists('b:messages')
423 | return 0
424 | endif
425 |
426 | let messages = deepcopy(b:messages)
427 | let messages = filter(messages, 'slackmemo#compareMemoWithTS(v:val, "'.slackmemo#escapeTS(a:ts).'", 0)')
428 | return len(messages) > -1 ? messages[0] : 0
429 | endfunction
430 |
431 |
432 | function! s:SlackMemoOpen(ts)
433 | let memo = s:GetSlackMemoByTS(a:ts)
434 | call slackmemo#open(memo)
435 | endfunction
436 |
437 |
438 | function! s:SlackMemoWrite(fname) abort
439 | let text = join(getline(0, '$'), "\n")
440 | let bufname = bufname('%')
441 | let bufnamemx = '^' . s:bufprefix .'\(\d\+\.\d\+\)\.md$'
442 | let ts = ''
443 |
444 | if bufname =~# bufnamemx
445 | let ts = matchlist(bufname, bufnamemx)[1]
446 | elseif exists('b:slackmemo') && has_key(b:slackmemo, 'ts')
447 | let ts = b:slackmemo['ts']
448 | endif
449 |
450 | if ts != ''
451 | call s:SlackMemoUpdate(ts, text)
452 | endif
453 | endfunction
454 |
455 |
456 | function! s:SlackMemoUpdate(ts, text)
457 | redraw | echon 'Updating memo...'
458 |
459 | let res = webapi#http#post(s:slackapi . '/chat.update', {
460 | \ 'token': g:slack_memo_token,
461 | \ 'channel': g:slack_memo_channel,
462 | \ 'ts': a:ts,
463 | \ 'text': s:decode_memo_text(a:text)
464 | \ })
465 | let res = webapi#json#decode(res.content)
466 |
467 | if !res.ok
468 | redraw
469 | echomsg 'Bad request...'
470 | return
471 | endif
472 |
473 | let winnum = s:SlackMemoListWinnr()
474 | if winnum > -1
475 | let currentwinnum = bufwinnr(bufnr(bufname('%')))
476 |
477 | call s:SlackMemoListOpen()
478 | let line = s:format_memo(res)
479 | let view = winsaveview()
480 | setlocal modifiable
481 | normal! gg
482 | if search('memo: '.a:ts)
483 | call setline('.', line)
484 | endif
485 | setlocal nomodifiable
486 | call winrestview(view)
487 |
488 | exe currentwinnum 'wincmd w'
489 | endif
490 |
491 | setlocal nomodified
492 | redraw | echon 'Updated!'
493 | endfunction
494 |
495 |
496 | function! s:SlackMemoDelete(ts) abort
497 | redraw | echon 'Deleting memo...'
498 |
499 | let res = webapi#http#post(s:slackapi . '/chat.delete', {
500 | \ 'token': g:slack_memo_token,
501 | \ 'channel': g:slack_memo_channel,
502 | \ 'ts': a:ts
503 | \ })
504 | let res = webapi#json#decode(res.content)
505 |
506 | if !res.ok
507 | redraw
508 | echomsg 'Bad request...'
509 | return
510 | endif
511 |
512 | let view = winsaveview()
513 | setlocal modifiable
514 | normal! gg
515 | if search('memo: '.a:ts)
516 | exe ':normal! dd'
517 | endif
518 | setlocal nomodifiable
519 | call winrestview(view)
520 |
521 | if exists('b:slackmemo')
522 | unlet b:slackmemo
523 | endif
524 |
525 | redraw | echon 'Deleted!!'
526 | endfunction
527 |
528 |
529 |
530 |
531 | let &cpo = s:save_cpo
532 | unlet s:save_cpo
533 |
--------------------------------------------------------------------------------
/doc/slackmemo-vim.txt:
--------------------------------------------------------------------------------
1 | *slackmemo-vim.txt* Simple memo manager with Vim using Slack.
2 |
3 | Version: 0.2.1
4 | Author: tsuyoshiwada
5 |
6 | ==============================================================================
7 | CONTENTS *slack-memo-contents*
8 |
9 | 1. Usage |slack-memo-usage|
10 | 2. Install |slack-memo-install|
11 | 3. Requirements |slack-memo-requirements|
12 | 4. Setup |slack-memo-setup|
13 | 5. Variables |slack-memo-variables|
14 | 6. License |slack-memo-license|
15 | 7. Tips |slack-memo-tips|
16 |
17 | ==============================================================================
18 | USAGE *slack-memo-usage*
19 |
20 | - Post a memo on Slack. >
21 |
22 | :SlackMemoPost
23 | <
24 | - List memos on Slack. >
25 |
26 | :SlackMemoList
27 | <
28 | - Keymaps in the memo list.
29 |
30 | Key Description ~
31 | Open memo on cursor.
32 | o Same as above...
33 | Close memo on cursor.
34 | q Same as above...
35 | d Delete memo on cursor.
36 | y Yank memo on cursor.
37 | r Update list window.
38 |
39 | - Update a memo on Slack.
40 | You can update the gist with the {:w} command within the memo buffer.
41 |
42 | - List memos on Slack with CtrlP. >
43 |
44 | :SlackMemoCtrlP
45 | <
46 | - List search result memos on Slack. >
47 |
48 | :SlackMemoSearch search query parameters
49 |
50 | ==============================================================================
51 | INSTALL *slack-memo-install*
52 |
53 | It's easy to install using plugin manager.
54 | Depending on your plugin manager, please add the following to .vimrc.
55 |
56 | - Install with dein. (https://github.com/Shougo/dein.vim) >
57 |
58 | call dein#add('tsuyoshiwada/slack-memo-vim', {
59 | \ 'depends': 'mattn/webapi-vim'
60 | \ })
61 | <
62 | - Install with NeoBundle. (https://github.com/Shougo/neobundle.vim) >
63 |
64 | NeoBundle 'tsuyoshiwada/slack-memo-vim', {
65 | \ 'depends': 'mattn/webapi-vim'
66 | \ }
67 | <
68 | You need to install webapi-vim also:
69 | http://www.vim.org/scripts/script.php?script_id=4019
70 |
71 | If you want to use latest one:
72 | https://github.com/mattn/webapi-vim
73 |
74 | ==============================================================================
75 | REQUIREMENTS *slack-memo-requirements*
76 |
77 | - curl command (http://curl.haxx.se/)
78 | - webapi-vim (https://github.com/mattn/webapi-vim)
79 |
80 | ==============================================================================
81 | SETUP *slack-memo-setup*
82 |
83 | You need a token to use Slack Web API. (https://api.slack.com/web)
84 | Please set your token on |g:slack_memo_token|.
85 | >
86 | let g:slack_memo_token = ''
87 | <
88 | Please set channel ID in |g:slack_memo_channel|.
89 | If you do not know the ID right away,
90 | you can easily check with the channel.list tester.
91 | (https://api.slack.com/methods/channels.list/test)
92 | >
93 | let g:slack_memo_channel = ''
94 | <
95 | Setup is complete!
96 |
97 | ==============================================================================
98 | VARIABLES *slack-memo-variables*
99 |
100 | g:slack_memo_token *g:slack_memo_token*
101 | Please specify the token for Slack Web API.
102 | Refer to Slack for acquisition method. (https://api.slack.com/web)
103 |
104 | Required.
105 |
106 | g:slack_memo_channel *g:slack_memo_channel*
107 | Please specify channel ID with string.
108 |
109 | Required.
110 |
111 | g:slack_memo_bot_username *g:slack_memo_bot_username*
112 | Please specify the name of the user who posts the memo.
113 |
114 | Default value is 'Vim (bot)'.
115 |
116 | g:slack_memo_bot_icon_url *g:slack_memo_bot_icon_url*
117 | Please specify the user icon.
118 |
119 | Default value is ''.
120 |
121 | g:slack_memo_bot_icon_emoji *g:slack_memo_bot_icon_emoji*
122 | Please specify the user emoji.
123 | Default value is ''.
124 |
125 | g:slack_memo_list_count *g:slack_memo_list_count*
126 | Please specify length to display in list of memos.
127 | NOTE: between 1 and 1000.
128 |
129 | Default value is 1000.
130 |
131 | ==============================================================================
132 | LICENSE *slack-memo-license*
133 |
134 | Copyright 2016 by tsuyoshiwada.
135 | modification, are permitted provided that the following conditions are met:
136 |
137 | 1. Redistributions of source code must retain the above copyright notice,
138 | this list of conditions and the following disclaimer.
139 | 2. Redistributions in binary form must reproduce the above copyright notice,
140 | this list of conditions and the following disclaimer in the documentation
141 | and/or other materials provided with the distribution.
142 |
143 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
144 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
145 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
146 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
147 | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
148 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
149 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
150 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
151 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
152 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
153 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
154 | OF THE POSSIBILITY OF SUCH DAMAGE.
155 |
156 | ==============================================================================
157 | TIPS *slack-memo-tips*
158 |
159 | You can post / list easily with the following keymap.
160 | >
161 | nnoremap smp :SlackMemoPost
162 | nnoremap sml :SlackMemoList
163 | <
164 | Support GFM TODO list.
165 | Posting following memo will be displayed with emoji on Slack.
166 | >
167 | * [x] Done1
168 | * [x] Done2
169 | * [ ] TODO...
170 | <
171 |
172 | vim:tw=78:ts=8:ft=help:norl:ai:et
173 |
--------------------------------------------------------------------------------
/plugin/slackmemo.vim:
--------------------------------------------------------------------------------
1 | "=============================================================================
2 | " File: slack-memo.vim
3 | " Version: 0.2.1
4 | " Author: tsuyoshiwada
5 | " WebPage: http://github.com/tsuyoshiwada/slack-memo-vim
6 | " License: BSD
7 |
8 | if &compatible || (exists('g:loaded_slackmemo_vim') && g:loaded_slackmemo_vim)
9 | finish
10 | endif
11 | let g:loaded_slackmemo_vim = 1
12 |
13 | command! -nargs=0 SlackMemoPost :call slackmemo#post()
14 | command! -nargs=0 SlackMemoList :call slackmemo#list('default')
15 | command! -nargs=0 SlackMemoCtrlP :call slackmemo#list('CtrlP')
16 | command! -nargs=* SlackMemoSearch :call slackmemo#search('default', )
17 |
--------------------------------------------------------------------------------