diff --git a/denops/aider/aiderCommand.ts b/denops/aider/aiderCommand.ts index ecbc779..3d121c2 100644 --- a/denops/aider/aiderCommand.ts +++ b/denops/aider/aiderCommand.ts @@ -3,58 +3,58 @@ import * as v from "https://deno.land/x/denops_std@v6.4.0/variable/mod.ts"; import { ensure, is } from "https://deno.land/x/unknownutil@v3.17.0/mod.ts"; import * as fn from "https://deno.land/x/denops_std@v6.4.0/function/mod.ts"; -export const aiderCommand = { - async debug(denops: Denops): Promise { - await denops.cmd("b#"); - }, - - async run(denops: Denops): Promise { - const aiderCommand = ensure( - await v.g.get(denops, "aider_command"), - is.String, - ); - await denops.cmd(`terminal ${aiderCommand}`); - }, - /** - * Aiderをバックグラウンドで実行します。 - * 新しいバッファを作成し、Aiderコマンドをターミナルで実行した後、 - * 前のバッファに戻ります。 - * @param {Denops} denops - Denopsインスタンス - * @returns {Promise} - */ - async silentRun(denops: Denops): Promise { - await denops.cmd("enew"); - - const aiderCommand = ensure( - await v.g.get(denops, "aider_command"), - is.String, - ); - await denops.cmd(`terminal ${aiderCommand}`); - - await denops.cmd("b#"); - - await denops.cmd("echo 'Aider is running in the background.'"); - }, - /** - * Aiderバッファにメッセージを送信します。 - * @param {Denops} denops - Denops instance - * @param {number} jobId - The job id to send the message to - * @param {string} prompt - The prompt to send - * @returns {Promise} - */ - async sendPrompt( - denops: Denops, - jobId: number, - prompt: string, - ): Promise { - await v.r.set(denops, "q", prompt); - await fn.feedkeys(denops, "G"); - await fn.feedkeys(denops, '"qp'); - await denops.call("chansend", jobId, "\n"); - }, - - async exit(denops: Denops, jobId: number, bufnr: number): Promise { - await denops.call("chansend", jobId, "/exit\n"); - await denops.cmd(`bdelete! ${bufnr}`); - }, -}; +export async function debug(denops: Denops): Promise { + await denops.cmd("b#"); +} + +export async function run(denops: Denops): Promise { + const aiderCommand = ensure( + await v.g.get(denops, "aider_command"), + is.String, + ); + await denops.cmd(`terminal ${aiderCommand}`); +} + +/** + * Aiderをバックグラウンドで実行します。 + * 新しいバッファを作成し、Aiderコマンドをターミナルで実行した後、 + * 前のバッファに戻ります。 + * @param {Denops} denops - Denopsインスタンス + * @returns {Promise} + */ +export async function silentRun(denops: Denops): Promise { + await denops.cmd("enew"); + + const aiderCommand = ensure( + await v.g.get(denops, "aider_command"), + is.String, + ); + await denops.cmd(`terminal ${aiderCommand}`); + + await denops.cmd("b#"); + + await denops.cmd("echo 'Aider is running in the background.'"); +} + +/** + * Aiderバッファにメッセージを送信します。 + * @param {Denops} denops - Denops instance + * @param {number} jobId - The job id to send the message to + * @param {string} prompt - The prompt to send + * @returns {Promise} + */ +export async function sendPrompt( + denops: Denops, + jobId: number, + prompt: string, +): Promise { + await v.r.set(denops, "q", prompt); + await fn.feedkeys(denops, "G"); + await fn.feedkeys(denops, '"qp'); + await denops.call("chansend", jobId, "\n"); +} + +export async function exit(denops: Denops, jobId: number, bufnr: number): Promise { + await denops.call("chansend", jobId, "/exit\n"); + await denops.cmd(`bdelete! ${bufnr}`); +} diff --git a/denops/aider/buffer.ts b/denops/aider/buffer.ts index 5668832..a7ae481 100644 --- a/denops/aider/buffer.ts +++ b/denops/aider/buffer.ts @@ -14,7 +14,7 @@ import { getBufferName, } from "./utils.ts"; import { feedkeys } from "https://deno.land/x/denops_std@v6.4.0/function/mod.ts"; -import { aiderCommand } from "./aiderCommand.ts"; +import * as aiderCommand from "./aiderCommand.ts"; /** * Enum representing different buffer layout options. @@ -28,207 +28,211 @@ export type BufferLayout = typeof bufferLayouts[number]; * vsplit: vertical split * floating: floating window */ -export const buffer = { - async getOpenBufferType(denops: Denops): Promise { - return maybe( - await v.g.get(denops, "aider_buffer_open_type"), - is.LiteralOneOf(bufferLayouts), - ) ?? "floating"; - }, - async exitAiderBuffer(denops: Denops): Promise { - const buffer = await identifyAiderBuffer(denops); - if (buffer === undefined) { - return; - } - const { job_id, bufnr } = buffer; - aiderCommand.exit(denops, job_id, bufnr); - }, - - /** - * Opens an Aider buffer. - * If an Aider buffer is already open, it opens that buffer. - * If no Aider buffer is open, it creates a new buffer and opens it. - * The way the buffer is opened depends on the value of openBufferType. - * If openBufferType is "split" or "vsplit", the buffer is opened in a split. - * Otherwise, the buffer is opened in a floating window. - * - * @param {Denops} denops - The Denops instance. - * @param {BufferLayout} openBufferType - The type of buffer to open. - * @returns {Promise} - * @throws {Error} If openBufferType is an invalid value. - */ - async openAiderBuffer( - denops: Denops, - openBufferType: BufferLayout, - ): Promise { - const aiderBufnr = await getAiderBufferNr(denops); - if (aiderBufnr && openBufferType === "floating") { - await openFloatingWindow(denops, aiderBufnr); +export async function getOpenBufferType(denops: Denops): Promise { + return maybe( + await v.g.get(denops, "aider_buffer_open_type"), + is.LiteralOneOf(bufferLayouts), + ) ?? "floating"; +} + +export async function exitAiderBuffer(denops: Denops): Promise { + const buffer = await identifyAiderBuffer(denops); + if (buffer === undefined) { + return; + } + const { job_id, bufnr } = buffer; + aiderCommand.exit(denops, job_id, bufnr); +} + +/** + * Opens an Aider buffer. + * If an Aider buffer is already open, it opens that buffer. + * If no Aider buffer is open, it creates a new buffer and opens it. + * The way the buffer is opened depends on the value of openBufferType. + * If openBufferType is "split" or "vsplit", the buffer is opened in a split. + * Otherwise, the buffer is opened in a floating window. + * + * @param {Denops} denops - The Denops instance. + * @param {BufferLayout} openBufferType - The type of buffer to open. + * @returns {Promise} + * @throws {Error} If openBufferType is an invalid value. + */ +export async function openAiderBuffer( + denops: Denops, + openBufferType: BufferLayout, +): Promise { + const aiderBufnr = await getAiderBufferNr(denops); + if (aiderBufnr && openBufferType === "floating") { + await openFloatingWindow(denops, aiderBufnr); + await emit(denops, "User", "AiderOpen"); + return true; + } + + if (openBufferType === "split" || openBufferType === "vsplit") { + if (aiderBufnr === undefined) { + await denops.cmd(openBufferType); await emit(denops, "User", "AiderOpen"); - return true; + } else { + await openSplitWindow(denops); } + return; + } - if (openBufferType === "split" || openBufferType === "vsplit") { - if (aiderBufnr === undefined) { - await denops.cmd(openBufferType); - await emit(denops, "User", "AiderOpen"); - } else { - await buffer.openSplitWindow(denops); - } - return; - } + const bufnr = ensure( + await n.nvim_create_buf(denops, false, true), + is.Number, + ); - const bufnr = ensure( - await n.nvim_create_buf(denops, false, true), - is.Number, - ); + await openFloatingWindow(denops, bufnr); - await openFloatingWindow(denops, bufnr); + await emit(denops, "User", "AiderOpen"); + return; +} - await emit(denops, "User", "AiderOpen"); +export async function sendPromptWithInput( + denops: Denops, + input: string, +): Promise { + const bufnr = await getAiderBufferNr(denops); + if (bufnr === undefined) { + await denops.cmd("echo 'Aider is not running'"); + await denops.cmd("AiderRun"); + return; + } + + const openBufferType = await getOpenBufferType(denops); + + if (openBufferType === "floating") { + await openAiderBuffer(denops, openBufferType); + await sendPromptFromFloatingWindow(denops, input); return; - }, + } - async sendPromptWithInput(denops: Denops, input: string): Promise { + await sendPromptFromSplitWindow(denops, input); +} + +export async function sendPromptByBuffer( + denops: Denops, + openBufferType: BufferLayout, +): Promise { + const bufferContent = ensure( + await denops.call("getbufline", "%", 1, "$"), + is.ArrayOf(is.String), + ).join("\n"); + + await denops.cmd("bdelete!"); + + if (openBufferType === "floating") { + await sendPromptFromFloatingWindow(denops, bufferContent); + } else { + await sendPromptFromSplitWindow(denops, bufferContent); + } + + await emit(denops, "User", "AiderOpen"); + return; +} + +export async function openFloatingWindowWithSelectedCode( + denops: Denops, + start: unknown, + end: unknown, + openBufferType: BufferLayout, +): Promise { + const words = ensure( + await denops.call("getline", start, end), + is.ArrayOf(is.String), + ); + if (openBufferType !== "floating") { const bufnr = await getAiderBufferNr(denops); if (bufnr === undefined) { await denops.cmd("echo 'Aider is not running'"); await denops.cmd("AiderRun"); return; } + } - const openBufferType = await buffer.getOpenBufferType(denops); - - if (openBufferType === "floating") { - await buffer.openAiderBuffer(denops, openBufferType); - await sendPromptFromFloatingWindow(denops, input); - return; - } - - await sendPromptFromSplitWindow(denops, input); - }, - async sendPromptByBuffer( - denops: Denops, - openBufferType: BufferLayout, - ): Promise { - const bufferContent = ensure( - await denops.call("getbufline", "%", 1, "$"), - is.ArrayOf(is.String), - ).join("\n"); - - await denops.cmd("bdelete!"); - - if (openBufferType === "floating") { - await sendPromptFromFloatingWindow(denops, bufferContent); - } else { - await sendPromptFromSplitWindow(denops, bufferContent); - } - - await emit(denops, "User", "AiderOpen"); - return; - }, - async openFloatingWindowWithSelectedCode( - denops: Denops, - start: unknown, - end: unknown, - openBufferType: BufferLayout, - ): Promise { - const words = ensure( - await denops.call("getline", start, end), - is.ArrayOf(is.String), - ); - if (openBufferType !== "floating") { - const bufnr = await getAiderBufferNr(denops); - if (bufnr === undefined) { - await denops.cmd("echo 'Aider is not running'"); - await denops.cmd("AiderRun"); - return; - } - } - - const filetype = ensure( - await fn.getbufvar(denops, "%", "&filetype"), - is.String, - ); - words.unshift("```" + filetype); - words.push("```"); + const filetype = ensure( + await fn.getbufvar(denops, "%", "&filetype"), + is.String, + ); + words.unshift("```" + filetype); + words.push("```"); - const bufnr = ensure( - await n.nvim_create_buf(denops, false, true), - is.Number, - ); - await openFloatingWindow( - denops, - bufnr, - ); + const bufnr = ensure( + await n.nvim_create_buf(denops, false, true), + is.Number, + ); + await openFloatingWindow( + denops, + bufnr, + ); - await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, words); - await n.nvim_buf_set_lines(denops, bufnr, 0, 1, true, []); - await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, [""]); + await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, words); + await n.nvim_buf_set_lines(denops, bufnr, 0, 1, true, []); + await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, [""]); - const additionalPrompt = await getAdditionalPrompt(denops); - if (additionalPrompt) { - await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, ["# rule"]); - await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, additionalPrompt); - await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, [""]); - } - await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, ["# prompt"]); + const additionalPrompt = await getAdditionalPrompt(denops); + if (additionalPrompt) { + await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, ["# rule"]); + await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, additionalPrompt); await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, [""]); - await feedkeys(denops, "Gi"); + } + await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, ["# prompt"]); + await n.nvim_buf_set_lines(denops, bufnr, -1, -1, true, [""]); + await feedkeys(denops, "Gi"); - await n.nvim_buf_set_keymap(denops, bufnr, "n", "q", "close!", { + await n.nvim_buf_set_keymap(denops, bufnr, "n", "q", "close!", { + silent: true, + }); + await n.nvim_buf_set_keymap( + denops, + bufnr, + "n", + "", + "AiderSendPrompt", + { silent: true, - }); - await n.nvim_buf_set_keymap( - denops, - bufnr, - "n", - "", - "AiderSendPrompt", - { - silent: true, - }, - ); - }, - /** - * バッファがAiderバッファかどうかを確認します。 - * @param {Denops} denops - Denopsインスタンス - * @param {number} bufnr - バッファ番号 - * @returns {Promise} - */ - async checkIfAiderBuffer( - denops: Denops, - bufnr: number, - ): Promise { - // aiderバッファの場合 `term://{path}//{pid}:aider --4o --no-auto-commits` のような名前になっている - const name = await getBufferName(denops, bufnr); - const splitted = name.split(" "); - return splitted[0].endsWith("aider"); - }, - - /** - * バッファがターミナルバッファかどうかを確認します。 - * @param {Denops} denops - Denopsインスタンス - * @param {number} bufnr - バッファ番号 - * @returns {Promise} - */ - async checkIfTerminalBuffer( - denops: Denops, - bufnr: number, - ): Promise { - const buftype = await fn.getbufvar(denops, bufnr, "&buftype"); - return buftype === "terminal"; - }, - - /** - * スプリットウィンドウを開く - * - * @param {Denops} denops - Denopsインスタンス - */ - async openSplitWindow(denops: Denops): Promise { - await denops.cmd(await buffer.getOpenBufferType(denops)); - }, -}; + }, + ); +} +/** + * バッファがAiderバッファかどうかを確認します。 + * @param {Denops} denops - Denopsインスタンス + * @param {number} bufnr - バッファ番号 + * @returns {Promise} + */ +export async function checkIfAiderBuffer( + denops: Denops, + bufnr: number, +): Promise { + // aiderバッファの場合 `term://{path}//{pid}:aider --4o --no-auto-commits` のような名前になっている + const name = await getBufferName(denops, bufnr); + const splitted = name.split(" "); + return splitted[0].endsWith("aider"); +} + +/** + * バッファがターミナルバッファかどうかを確認します。 + * @param {Denops} denops - Denopsインスタンス + * @param {number} bufnr - バッファ番号 + * @returns {Promise} + */ +export async function checkIfTerminalBuffer( + denops: Denops, + bufnr: number, +): Promise { + const buftype = await fn.getbufvar(denops, bufnr, "&buftype"); + return buftype === "terminal"; +} + +/** + * スプリットウィンドウを開く + * + * @param {Denops} denops - Denopsインスタンス + */ +export async function openSplitWindow(denops: Denops): Promise { + await denops.cmd(await getOpenBufferType(denops)); +} /** * 開いているウィンドウの中からAiderバッファを識別し、そのジョブID、ウィンドウ番号、バッファ番号を返します。 @@ -242,7 +246,7 @@ async function identifyAiderBuffer( for (let i = 1; i <= win_count; i++) { const bufnr = ensure(await fn.winbufnr(denops, i), is.Number); - if (await buffer.checkIfAiderBuffer(denops, bufnr)) { + if (await checkIfAiderBuffer(denops, bufnr)) { const job_id = ensure( await fn.getbufvar(denops, bufnr, "&channel"), is.Number, diff --git a/denops/aider/main.ts b/denops/aider/main.ts index 062ab52..a82e5fc 100644 --- a/denops/aider/main.ts +++ b/denops/aider/main.ts @@ -1,7 +1,8 @@ import { Denops } from "https://deno.land/x/denops_std@v6.4.0/mod.ts"; import * as fn from "https://deno.land/x/denops_std@v6.4.0/function/mod.ts"; -import { aiderCommand } from "./aiderCommand.ts"; -import { buffer, BufferLayout } from "./buffer.ts"; +import * as aiderCommand from "./aiderCommand.ts"; +import * as buffer from "./buffer.ts"; +import { BufferLayout } from "./buffer.ts"; import { getAiderBufferNr, getCurrentFilePath } from "./utils.ts"; /** diff --git a/denops/aider/utils.ts b/denops/aider/utils.ts index a0bb30f..af26a9d 100644 --- a/denops/aider/utils.ts +++ b/denops/aider/utils.ts @@ -6,7 +6,7 @@ import { maybe, } from "https://deno.land/x/unknownutil@v3.17.0/mod.ts"; import * as v from "https://deno.land/x/denops_std@v6.4.0/variable/mod.ts"; -import { buffer } from "./buffer.ts"; +import * as buffer from "./buffer.ts"; /** * Gets the additional prompt from vim global variable "aider_additional_prompt".