diff --git a/autoload/traqvim/message.vim b/autoload/traqvim/message.vim index 1867dc0..117da67 100644 --- a/autoload/traqvim/message.vim +++ b/autoload/traqvim/message.vim @@ -13,6 +13,26 @@ function traqvim#message#get_message() abort return traqvim#message#get_message_buf(curline, bufnr("%")) endfunction +function traqvim#message#get_message_quote() abort + let curline = line(".") + let message = traqvim#message#get_message_buf(curline, bufnr("%")) + let quote = message->get("quote", []) + if empty(quote) + return {} + endif + let quotePos = copy(message)->get("position")->get("quote", []) + if empty(quotePos) + return {} + endif + let relativePos = curline - message.position["start"] + silent let quotePos->filter({ _, v -> v.start <= relativePos && relativePos <= v.end }) + if len(quotePos) == 0 + return {} + else + return quote[quotePos[0]->get("index")] + endif +endfunction + function traqvim#message#message_prev() abort let cur = traqvim#message#get_message() if empty(cur) @@ -44,7 +64,8 @@ function traqvim#message#goto_message() abort if empty(message) return endif - call denops#request('traqvim', 'timelineMessage', [message]) + let quote = traqvim#message#get_message_quote() + call denops#request('traqvim', 'timelineMessage', [quote != #{} ? quote : message]) endfunction function traqvim#message#registerYankMessageLink() abort diff --git a/autoload/traqvim/view.vim b/autoload/traqvim/view.vim index 25b4c98..e3f688c 100644 --- a/autoload/traqvim/view.vim +++ b/autoload/traqvim/view.vim @@ -1,39 +1,67 @@ " バッファ変数の情報を元に描画する関数郡 " Message { user : {id, name, displayName}, content, createdAt } -function! traqvim#view#make_message_body(message, width) abort +" return { +" body: string[], +" position: { +" quote: { +" index: number, +" start: number, +" end: number +" }[] +" } +" } +function traqvim#view#make_message_body(message, width) abort let createdAt = denops#request('traqvim', 'convertDate', [a:message["createdAt"]]) let header = [ a:message["user"]["displayName"] . " @" . a:message["user"]["name"] . " " . createdAt, "" ] let rows = split(a:message["content"], "\n") - let quote = [] + let quotes = [] + let quotePos = [] if a:message->has_key("quote") if type(a:message["quote"]) == type([]) for q in a:message["quote"] let createdAt = denops#request('traqvim', 'convertDate', [q["createdAt"]]) - let quote += [ "", ">"] + let quote = [] + let quote += [ ">" ] let quote += [ "\t". q["user"]["displayName"] . " @" . q["user"]["name"] . " " . createdAt, "" ] let quote += map(split(q["content"], "\n"), { _, v -> "\t" . v }) let quote += [ "", "<"] + let quotes += [ quote ] + let quotePos += [#{ + \ index: len(quotes) - 1, + \ start: len(header) + len(rows) + copy(quotes)->flatten()->len() - len(quote) + 1, + \ end: len(header) + len(rows) + copy(quotes)->flatten()->len() + \}] endfor endif endif let footer = [ "", repeat("─", a:width - 2) ] " 2はsigncolumnの分 - let messageBody = header + rows + quote + footer - return messageBody + let messageBody = header + rows + quotes->flatten() + footer + return #{ body: messageBody, position: #{ quote: quotePos }} endfunction function traqvim#view#update_message_position(timeline, key, value) abort if a:key == 0 let start = 1 - let body = traqvim#view#make_message_body(a:value, winwidth(bufwinid("%"))) - let end = start + len(body) - 1 - let a:value.position = #{ index: 0, start: start, end: end } + let mes = traqvim#view#make_message_body(a:value, winwidth(bufwinid("%"))) + let end = start + len(mes.body) - 1 + let a:value.position = #{ + \ index: 0, + \ start: start, + \ end: end, + \ quote: mes.position["quote"] + \} else let prev = a:timeline[a:key - 1] let start = prev.position["end"] + 1 - let body = traqvim#view#make_message_body(a:value, winwidth(bufwinid("%"))) - let end = start + len(body) - 1 - let a:value.position = #{ index: a:key, start: start, end: end } + let mes = traqvim#view#make_message_body(a:value, winwidth(bufwinid("%"))) + let end = start + len(mes.body) - 1 + let a:value.position = #{ + \ index: a:key, + \ start: start, + \ end: end, + \ quote: mes.position["quote"] + \} endif return a:value endfunction @@ -46,11 +74,16 @@ function traqvim#view#draw_timeline(bufNum) abort let winnr = bufwinid(a:bufNum) let width = winwidth(winnr) for message in getbufvar(a:bufNum, "channelTimeline") - let body = traqvim#view#make_message_body(message, width) - let end = start + len(body) - 1 + let mes = traqvim#view#make_message_body(message, width) + let end = start + len(mes.body) - 1 " 一度に全部描画するから、positionをここで設定する - let message.position = #{ index: index, start: start, end: end } - call setbufline(a:bufNum, start, body) + let message.position = #{ + \ index: index, + \ start: start, + \ end: end, + \ quote: mes.position["quote"] + \} + call setbufline(a:bufNum, start, mes.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) @@ -91,9 +124,9 @@ function traqvim#view#draw_forward_messages(bufNum, messages) abort let winnr = bufwinid(a:bufNum) let width = winwidth(winnr) for message in a:messages - let body = traqvim#view#make_message_body(message, width) - let end = start + len(body) - 1 - call appendbufline(a:bufNum, start - 1, body) + let mes = traqvim#view#make_message_body(message, width) + let end = start + len(mes.body) - 1 + call appendbufline(a:bufNum, start - 1, mes.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) @@ -115,9 +148,9 @@ function traqvim#view#draw_back_messages(bufNum, messages) abort let width = winwidth(winnr) " appendbufline()を使用する for message in a:messages - let body = traqvim#view#make_message_body(message, width) - let end = start + len(body) - 1 - call appendbufline(a:bufNum, start - 1, body) + let mes = traqvim#view#make_message_body(message, width) + let end = start + len(mes.body) - 1 + call appendbufline(a:bufNum, start - 1, mes.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) @@ -167,9 +200,9 @@ function traqvim#view#draw_insert_message(bufNum, message) abort endif let winnr = bufwinid(a:bufNum) let width = winwidth(winnr) - let body = traqvim#view#make_message_body(a:message, width) - let end = start + len(body) - 1 - call appendbufline(a:bufNum, start - 1, body) + let mes = traqvim#view#make_message_body(a:message, width) + let end = start + len(mes.body) - 1 + call appendbufline(a:bufNum, start - 1, mes.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) diff --git a/denops/@ddu-kinds/channel.ts b/denops/@ddu-kinds/channel.ts index 2dcb36d..e531f85 100644 --- a/denops/@ddu-kinds/channel.ts +++ b/denops/@ddu-kinds/channel.ts @@ -90,8 +90,20 @@ export class Kind extends dduVim.BaseKind { message, args.previewContext.width, ); - assert(ret, is.ArrayOf(is.String)); - return ret; + assert( + ret, + is.ObjectOf({ + body: is.ArrayOf(is.String), + position: is.OptionalOf(is.ObjectOf({ + quote: is.ArrayOf(is.ObjectOf({ + index: is.Number, + start: is.Number, + end: is.Number, + })), + })), + }), + ); + return ret.body; }), ); const timelinePreview: string[] = timelinePreviewArray.flat(); diff --git a/denops/traqvim/type.d.ts b/denops/traqvim/type.d.ts index 4d00bb8..b498167 100644 --- a/denops/traqvim/type.d.ts +++ b/denops/traqvim/type.d.ts @@ -14,6 +14,12 @@ export interface Message extends traq.Message { index: number; start: number; end: number; + // 相対位置の方がメッセージの位置変更に簡単に対応できそう + quote?: { + index: number; + start: number; + end: number; + }[]; }; quote?: Message[]; } diff --git a/denops/traqvim/type_check.ts b/denops/traqvim/type_check.ts index 74585af..d2431ac 100644 --- a/denops/traqvim/type_check.ts +++ b/denops/traqvim/type_check.ts @@ -64,6 +64,11 @@ export const isMessage: Predicate = is.ObjectOf({ index: is.Number, start: is.Number, end: is.Number, + quote: is.OptionalOf(is.ArrayOf(is.ObjectOf({ + index: is.Number, + start: is.Number, + end: is.Number, + }))), })), // quote?: Message[]; quote: is.OptionalOf(is.ArrayOf((x: unknown): x is Message => isMessage(x))),