diff --git a/autoload/helper.vim b/autoload/helper.vim index a957e9c..706aa4a 100644 --- a/autoload/helper.vim +++ b/autoload/helper.vim @@ -4,4 +4,5 @@ function! helper#define_highlight() abort highlight! VtraQScreenName ctermfg=lightmagenta guifg=lightmagenta cterm=bold highlight! link VtraQQuote Comment highlight! link VtraQMessage Keyword + highlight! link VtraQPin Keyword endfunction diff --git a/autoload/traqvim.vim b/autoload/traqvim.vim index 842ad4a..51cee8e 100644 --- a/autoload/traqvim.vim +++ b/autoload/traqvim.vim @@ -17,6 +17,7 @@ endfunction function! traqvim#draw_timeline(bufNum) abort call setbufvar(a:bufNum, "&modifiable", 1) + call sign_unplace("VtraQ", #{ buffer: a:bufNum }) let index = 0 let start = 1 let winnr = bufwinid(a:bufNum) @@ -27,6 +28,12 @@ function! traqvim#draw_timeline(bufNum) abort " 一度に全部描画するから、positionをここで設定する let message.position = #{ index: index, start: start, end: end } call setbufline(a:bufNum, start, body) + if message->get('pinned') + call sign_place(0, "VtraQ", "pin", a:bufNum, #{ lnum: start, priority: 10 }) + for i in range(start + 1, end - 1) + call sign_place(0, "VtraQ", "pin_long", a:bufNum, #{ lnum: i, priority: 10 }) + endfor + endif let start = end + 1 let index = index + 1 endfor @@ -34,6 +41,35 @@ function! traqvim#draw_timeline(bufNum) abort call setbufvar(a:bufNum, "&modifiable", 0) endfunction +function traqvim#draw_message_pin(bufNum, message) abort + call setbufvar(a:bufNum, "&modifiable", 1) + let start = a:message.position["start"] + let end = a:message.position["end"] + if a:message->get('pinned') + call sign_place(0, "VtraQ", "pin", a:bufNum, #{ lnum: start, priority: 10 }) + for i in range(start + 1, end - 1) + call sign_place(0, "VtraQ", "pin_long", a:bufNum, #{ lnum: i, priority: 10 }) + endfor + else + " unplaceはbufferとidしか指定できない + let pin_signs = sign_getplaced(a:bufNum, #{ group: "VtraQ", lnum: start }) + \ ->filter({ _, v -> v->get('bufnr') == a:bufNum }) + \ ->get(0) + call sign_unplace( + \"VtraQ", + \#{ buffer: a:bufNum, id: pin_signs->get('signs')->get(0)->get('id') }) + for i in range(start + 1, end - 1) + let pin_long_signs = sign_getplaced(a:bufNum, #{ group: "VtraQ", lnum: i }) + \ ->filter({ _, v -> v->get('bufnr') == a:bufNum }) + \ ->get(0) + call sign_unplace( + \"VtraQ", + \#{ buffer: a:bufNum, id: pin_long_signs->get('signs')->get(0)->get('id') }) + endfor + endif + call setbufvar(a:bufNum, "&modifiable", 0) +endfunction + function! traqvim#draw_forward_messages(bufNum, messages) abort call setbufvar(a:bufNum, "&modifiable", 1) " startをバッファの最下値にする @@ -44,6 +80,12 @@ function! traqvim#draw_forward_messages(bufNum, messages) abort let body = traqvim#make_message_body(message, width) let end = start + len(body) - 1 call appendbufline(a:bufNum, start - 1, body) + if message->get('pinned') + call sign_place(0, "VtraQ", "pin", a:bufNum, #{ lnum: start, priority: 10 }) + for i in range(start + 1, end - 1) + call sign_place(0, "VtraQ", "pin_long", a:bufNum, #{ lnum: i, priority: 10 }) + endfor + endif let start = end + 1 endfor " この関数を呼ばれる前に追加分が既にバッファ変数に登録されてる @@ -62,6 +104,12 @@ function! traqvim#draw_back_messages(bufNum, messages) abort let body = traqvim#make_message_body(message, width) let end = start + len(body) - 1 call appendbufline(a:bufNum, start - 1, body) + if message->get('pinned') + call sign_place(0, "VtraQ", "pin", a:bufNum, #{ lnum: start, priority: 10 }) + for i in range(start + 1, end - 1) + call sign_place(0, "VtraQ", "pin_long", a:bufNum, #{ lnum: i, priority: 10 }) + endfor + endif let start = end + 1 endfor " 既存のメッセージのpositionを更新する @@ -74,6 +122,12 @@ function traqvim#draw_delete_message(bufNum, message) abort call setbufvar(a:bufNum, "&modifiable", 1) let start = a:message.position["start"] let end = a:message.position["end"] + if a:message->get('pinned') + call sign_unplace("VtraQ", #{ buffer: a:bufNum, lnum: start }) + for i in range(start + 1, end - 1) + call sign_unplace("VtraQ", #{ buffer: a:bufNum, lnum: i }) + endfor + endif call deletebufline(a:bufNum, start, end) " 既存のメッセージのpositionを更新する " この関数を呼ばれる前に削除分が既にバッファ変数から削除されてる @@ -102,6 +156,12 @@ function traqvim#draw_insert_message(bufNum, message) abort let body = traqvim#make_message_body(a:message, width) let end = start + len(body) - 1 call appendbufline(a:bufNum, start - 1, body) + if a:message->get('pinned') + call sign_place(0, "VtraQ", "pin", a:bufNum, #{ lnum: start, priority: 10 }) + for i in range(start + 1, end - 1) + call sign_place(0, "VtraQ", "pin_long", a:bufNum, #{ lnum: i, priority: 10 }) + endfor + endif " 既存のメッセージのpositionを更新する call map(timeline, function("traqvim#update_message_position", [timeline])) call setbufvar(a:bufNum, "&modifiable", 0) @@ -158,7 +218,7 @@ function! traqvim#make_message_body(message, width) abort endfor endif endif - let footer = [ "", repeat("─", a:width) ] + let footer = [ "", repeat("─", a:width - 2) ] " 2はsigncolumnの分 let messageBody = header + rows + quote + footer return messageBody endfunction @@ -255,6 +315,27 @@ function traqvim#deleteMessage(t) abort call denops#request('traqvim', 'messageDelete', [bufnr(), messageStart]) endfunction +function traqvim#registerTogglePin() abort + let &opfunc = function('traqvim#togglePin') + return 'g@' +endfunction + +function traqvim#togglePin(t) abort + if a:t != 'line' + return + endif + let messageStart = traqvim#get_message_buf(line("'["), bufnr('%')) + let messageEnd = traqvim#get_message_buf(line("']"), bufnr('%')) + if messageStart->get('id') != messageEnd->get('id') + return + endif + if messageStart->get('pinned') + call denops#request('traqvim', 'removePin', [bufnr(), messageStart]) + else + call denops#request('traqvim', 'createPin', [bufnr(), messageStart]) + endif +endfunction + function traqvim#message_motion() abort let position = traqvim#get_message()->get('position') call cursor(position->get('start'), 1) diff --git a/denops/traqvim/action.ts b/denops/traqvim/action.ts index a2c0c80..f30f0ad 100644 --- a/denops/traqvim/action.ts +++ b/denops/traqvim/action.ts @@ -4,8 +4,10 @@ import { activity, channelMessageOptions, channelTimeline, + createPin, deleteMessage, editMessage, + removePin, } from "./model.ts"; export const actionOpenChannel = async ( @@ -184,3 +186,63 @@ export const actionYankMessageMarkdown = async ( await fn.setreg(denops, '"', message.content); await helper.echo(denops, "Yanked message markdown"); }; + +export const actionCreatePin = async ( + denops: Denops, + message: Message, + bufNum: number, +): Promise => { + try { + await createPin(message.id); + } catch (e) { + console.error(e); + return; + } + // 既存メッセージの取得 + const timeline = await vars.buffers.get(denops, "channelTimeline"); + ensureArray(timeline); + message.pinned = true; + // ピン留めしたものをセット + await vars.buffers.set( + denops, + "channelTimeline", + timeline.map((m) => { + if (m.id === message.id) { + return message; + } else { + return m; + } + }), + ); + await denops.call("traqvim#draw_message_pin", bufNum, message); +}; + +export const actionRemovePin = async ( + denops: Denops, + message: Message, + bufNum: number, +): Promise => { + try { + await removePin(message.id); + } catch (e) { + console.error(e); + return; + } + // 既存メッセージの取得 + const timeline = await vars.buffers.get(denops, "channelTimeline"); + ensureArray(timeline); + message.pinned = false; + // ピン留め解除したものをセット + await vars.buffers.set( + denops, + "channelTimeline", + timeline.map((m) => { + if (m.id === message.id) { + return message; + } else { + return m; + } + }), + ); + await denops.call("traqvim#draw_message_pin", bufNum, message); +}; diff --git a/denops/traqvim/main.ts b/denops/traqvim/main.ts index 5cc600d..a4f3086 100644 --- a/denops/traqvim/main.ts +++ b/denops/traqvim/main.ts @@ -18,11 +18,13 @@ import { } from "./deps.ts"; import { actionBackChannelMessage, + actionCreatePin, actionDeleteMessage, actionEditMessage, actionForwardChannelMessage, actionOpenActivity, actionOpenChannel, + actionRemovePin, actionYankMessageLink, actionYankMessageMarkdown, } from "./action.ts"; @@ -337,5 +339,21 @@ export async function main(denops: Denops) { await denops.cmd(":bdelete"); return; }, + async createPin( + bufNum: unknown, + message: unknown, + ): Promise { + ensureNumber(bufNum); + await actionCreatePin(denops, message as Message, bufNum); + return; + }, + async removePin( + bufNum: unknown, + message: unknown, + ): Promise { + ensureNumber(bufNum); + await actionRemovePin(denops, message as Message, bufNum); + return; + }, }; } diff --git a/denops/traqvim/model.ts b/denops/traqvim/model.ts index 8a2c290..de97a66 100644 --- a/denops/traqvim/model.ts +++ b/denops/traqvim/model.ts @@ -291,3 +291,23 @@ export const editMessage = async ( console.error(e); } }; + +export const createPin = async ( + messageId: string, +): Promise => { + try { + await api.api.createPin(messageId); + } catch (e) { + console.error(e); + } +}; + +export const removePin = async ( + messageId: string, +): Promise => { + try { + await api.api.removePin(messageId); + } catch (e) { + console.error(e); + } +}; diff --git a/ftplugin/traqvim.vim b/ftplugin/traqvim.vim index edc6d65..66b6967 100644 --- a/ftplugin/traqvim.vim +++ b/ftplugin/traqvim.vim @@ -1,7 +1,13 @@ setlocal noswapfile -setlocal signcolumn=no +setlocal signcolumn=yes setlocal nolist + +" TODO: nerd font導入してるかの確認とかしたいな +" call sign_define("pin", #{ text: "📌"}) +call sign_define("pin", #{ text: "󰐃", texthl: "VtraQPin"}) "f0403 ← nerd font導入後、これに対応してるらしい +call sign_define("pin_long", #{ text: "│" , texthl: "VtraQPin"}) + nnoremap (traqvim-next) \ call traqvim#message_next() nnoremap (traqvim-prev) @@ -13,6 +19,8 @@ nnoremap (traqvim-yank-message-markdown-operator) \ traqvim#registerYankMessageMarkdown() nnoremap (traqvim-delete-message-operator) \ traqvim#registerDeleteMessage() +nnoremap (traqvim-toggle-pin-operator) + \ traqvim#registerTogglePin() onoremap (traqvim-message-motion) \ :call traqvim#message_motion() @@ -29,6 +37,9 @@ nmap Y nmap d \ (traqvim-delete-message-operator) +nmap p + \ (traqvim-toggle-pin-operator) + command! -buffer -nargs=0 TraqYankMessageLink \ call denops#request('traqvim', 'yankMessageLink', [traqvim#get_message()]) command! -buffer -nargs=0 TraqYankMessageMarkdown diff --git a/plugin/traqvim.vim b/plugin/traqvim.vim index 9585a73..169a161 100644 --- a/plugin/traqvim.vim +++ b/plugin/traqvim.vim @@ -29,6 +29,10 @@ command! TraqMessageDelete call denops#request('traqvim', 'messageDelete', [bufn command! TraqMessageEdit call denops#request('traqvim', 'messageEditOpen', [bufnr(), traqvim#get_message()]) " messageの編集を適用 command! TraqMessageEditApply call denops#request('traqvim', 'messageEdit', [getbufvar(bufname("%"), "editSourceBuffer"), getbufvar(bufname("%"), "message"), getline(1, '$')]) +" pinを作成 +command! TraqCreatePin call denops#request('traqvim', 'createPin', [bufnr(), traqvim#get_message()]) +" pinを削除 +command! TraqRemovePin call denops#request('traqvim', 'removePin', [bufnr(), traqvim#get_message()]) call helper#define_highlight()