From bafb0ff36cc17b5740829db4bca1c0d64fc18a71 Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Tue, 10 Sep 2024 23:07:06 +0900 Subject: [PATCH 1/7] emit on openAiderBuffer --- denops/aider/buffer.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/denops/aider/buffer.ts b/denops/aider/buffer.ts index b7d9e4a..6785600 100644 --- a/denops/aider/buffer.ts +++ b/denops/aider/buffer.ts @@ -1,5 +1,6 @@ import { Denops } from "https://deno.land/x/denops_std@v6.4.0/mod.ts"; import * as v from "https://deno.land/x/denops_std@v6.4.0/variable/mod.ts"; +import { emit } from "https://deno.land/x/denops_std@v6.5.1/autocmd/mod.ts"; import * as n from "https://deno.land/x/denops_std@v6.4.0/function/nvim/mod.ts"; import * as fn from "https://deno.land/x/denops_std@v6.4.0/function/mod.ts"; import { @@ -133,11 +134,13 @@ export const buffer = { const aiderBufnr = await getAiderBufferNr(denops); if (aiderBufnr) { await buffer.openFloatingWindow(denops, aiderBufnr); + await emit(denops, "User", "AiderOpen"); return true; } if (openBufferType === "split" || openBufferType === "vsplit") { await denops.cmd(openBufferType); + await emit(denops, "User", "AiderOpen"); return; } @@ -151,6 +154,7 @@ export const buffer = { bufnr, ); + await emit(denops, "User", "AiderOpen"); return; }, From cedbd36406076490bc5572ba93c93549f3468b08 Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Tue, 10 Sep 2024 23:29:28 +0900 Subject: [PATCH 2/7] refactor: hide internal functions in buffer.ts --- denops/aider/aiderCommand.ts | 4 +- denops/aider/buffer.ts | 334 +++++++++++++++++------------------ denops/aider/utils.ts | 4 +- 3 files changed, 170 insertions(+), 172 deletions(-) diff --git a/denops/aider/aiderCommand.ts b/denops/aider/aiderCommand.ts index f6dddce..cf612af 100644 --- a/denops/aider/aiderCommand.ts +++ b/denops/aider/aiderCommand.ts @@ -3,7 +3,7 @@ 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"; import { getAiderBufferNr, getCurrentFilePath } from "./utils.ts"; -import { buffer, checkIfTerminalBuffer } from "./buffer.ts"; +import { buffer } from "./buffer.ts"; export const aiderCommand = { async debug(denops: Denops): Promise { @@ -51,7 +51,7 @@ export const aiderCommand = { if (await getAiderBufferNr(denops) === undefined) { await aiderCommand.silentRun(denops); } - if (await checkIfTerminalBuffer(denops, bufnr)) { + if (await buffer.checkIfTerminalBuffer(denops, bufnr)) { return; } const currentFile = await getCurrentFilePath(denops); diff --git a/denops/aider/buffer.ts b/denops/aider/buffer.ts index 6785600..031162e 100644 --- a/denops/aider/buffer.ts +++ b/denops/aider/buffer.ts @@ -28,92 +28,19 @@ export type BufferLayout = typeof bufferLayouts[number]; * floating: floating window */ export const buffer = { - async exitAiderBuffer(denops: Denops): Promise { - await identifyAiderBuffer(denops, async (job_id, _winnr, bufnr) => { - await denops.call("chansend", job_id, "/exit\n"); - await denops.cmd(`bdelete! ${bufnr}`); - }); - }, async getOpenBufferType(denops: Denops): Promise { return maybe( await v.g.get(denops, "aider_buffer_open_type"), is.LiteralOneOf(bufferLayouts), ) ?? "floating"; }, - - /** - * Opens a floating window for the specified buffer. - * The floating window is positioned at the center of the terminal. - * - * @param {Denops} denops - The Denops instance. - * @param {number} bufnr - The buffer number. - * @returns {Promise} - */ - async openFloatingWindow( - denops: Denops, - bufnr: number, - ): Promise { - const terminal_width = Math.floor( - ensure(await n.nvim_get_option(denops, "columns"), is.Number), - ); - const terminal_height = Math.floor( - ensure(await n.nvim_get_option(denops, "lines"), is.Number), - ); - const floatWinHeight = ensure( - await v.g.get(denops, "aider_floatwin_height"), - is.Number, - ); - const floatWinWidth = ensure( - await v.g.get(denops, "aider_floatwin_width"), - is.Number, - ); - - const row = Math.floor((terminal_height - floatWinHeight) / 2); - const col = Math.floor((terminal_width - floatWinWidth) / 2); - - await n.nvim_open_win(denops, bufnr, true, { - title: - "| normal mode > qq: quit, terminal mode > : quit | visual mode > : send prompt |", - relative: "editor", - border: "double", - width: floatWinWidth, - height: floatWinHeight, - row: row, - col: col, + async exitAiderBuffer(denops: Denops): Promise { + await identifyAiderBuffer(denops, async (job_id, _winnr, bufnr) => { + await denops.call("chansend", job_id, "/exit\n"); + await denops.cmd(`bdelete! ${bufnr}`); }); - await n.nvim_buf_set_keymap( - denops, - bufnr, - "t", - "", - "close!", - { - silent: true, - }, - ); - await n.nvim_buf_set_keymap( - denops, - bufnr, - "n", - "q", - "close!", - { - silent: true, - }, - ); - await n.nvim_buf_set_keymap( - denops, - bufnr, - "n", - "", - "close!", - { - silent: true, - }, - ); - - await denops.cmd("set nonumber"); }, + /** * Opens an Aider buffer. * If an Aider buffer is already open, it opens that buffer. @@ -133,7 +60,7 @@ export const buffer = { ): Promise { const aiderBufnr = await getAiderBufferNr(denops); if (aiderBufnr) { - await buffer.openFloatingWindow(denops, aiderBufnr); + await openFloatingWindow(denops, aiderBufnr); await emit(denops, "User", "AiderOpen"); return true; } @@ -149,7 +76,7 @@ export const buffer = { is.Number, ); - await buffer.openFloatingWindow( + await openFloatingWindow( denops, bufnr, ); @@ -158,67 +85,6 @@ export const buffer = { return; }, - async sendPromptFromFloatingWindow(denops: Denops): Promise { - const bufnr = await getAiderBufferNr(denops); - if (bufnr === undefined) { - return; - } - await buffer.openFloatingWindow(denops, bufnr); - - await feedkeys(denops, "G"); - await feedkeys(denops, '"qp'); - - const jobId = ensure( - await fn.getbufvar(denops, bufnr, "&channel"), - is.Number, - ); - - await denops.call("chansend", jobId, "\n"); - }, - - /** - * スプリットウィンドウからプロンプトを送信する非同期関数 - * - * この関数は以下の操作を行います: - * 1. ターミナルバッファを識別 - * 2. 現在のバッファを閉じる - * 3. ターミナルウィンドウに移動 - * 4. カーソルを最後に移動 - * 5. レジスタ 'q' の内容を貼り付け - * 6. Enter キーを送信 - * 7. 元のウィンドウに戻る - * - * @param {Denops} denops - Denopsインスタンス - */ - async sendPromptFromSplitWindow(denops: Denops): Promise { - await identifyAiderBuffer(denops, async (job_id, winnr, _bufnr) => { - await denops.cmd(`bdelete!`); - if (await v.g.get(denops, "aider_buffer_open_type") !== "floating") { - await denops.cmd(`${winnr}wincmd w`); - } else { - const totalWindows = ensure( - await denops.call("winnr", "$"), - is.Number, - ); - - for (let winnr = 1; winnr <= totalWindows; winnr++) { - const bufnr = await denops.call("winbufnr", winnr); - - const buftype = await denops.call("getbufvar", bufnr, "&buftype"); - - if (buftype === "terminal") { - await denops.cmd(`${winnr}wincmd w`); - break; - } - } - } - await feedkeys(denops, "G"); - await feedkeys(denops, '"qp'); - await denops.call("chansend", job_id, "\n"); - await denops.cmd("wincmd p"); - }); - }, - async sendPromptWithInput(denops: Denops): Promise { const bufnr = await getAiderBufferNr(denops); if (bufnr === undefined) { @@ -227,12 +93,12 @@ export const buffer = { return; } - await buffer.openFloatingWindow(denops, bufnr); - const openBufferType = await buffer.getOpenBufferType(denops); + await buffer.openAiderBuffer(denops, openBufferType); + openBufferType === "floating" - ? await buffer.sendPromptFromFloatingWindow(denops) - : await buffer.sendPromptFromSplitWindow(denops); + ? await sendPromptFromFloatingWindow(denops) + : await sendPromptFromSplitWindow(denops); }, async sendPrompt( denops: Denops, @@ -243,8 +109,8 @@ export const buffer = { await denops.cmd("bdelete!"); openBufferType === "floating" - ? buffer.sendPromptFromFloatingWindow(denops) - : buffer.sendPromptFromSplitWindow(denops); + ? sendPromptFromFloatingWindow(denops) + : sendPromptFromSplitWindow(denops); return; }, @@ -278,7 +144,7 @@ export const buffer = { await n.nvim_create_buf(denops, false, true), is.Number, ); - await buffer.openFloatingWindow( + await openFloatingWindow( denops, bufnr, ); @@ -316,6 +182,35 @@ export const buffer = { }, ); }, + /** + * バッファが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"; + }, }; /** @@ -336,7 +231,7 @@ async function identifyAiderBuffer( for (let i = 1; i <= win_count; i++) { const bufnr = ensure(await fn.winbufnr(denops, i), is.Number); - if (await checkIfAiderBuffer(denops, bufnr)) { + if (await buffer.checkIfAiderBuffer(denops, bufnr)) { const job_id = ensure( await fn.getbufvar(denops, bufnr, "&channel"), is.Number, @@ -349,31 +244,134 @@ async function identifyAiderBuffer( } /** - * バッファがAiderバッファかどうかを確認します。 - * @param {Denops} denops - Denopsインスタンス - * @param {number} bufnr - バッファ番号 - * @returns {Promise} + * Opens a floating window for the specified buffer. + * The floating window is positioned at the center of the terminal. + * + * @param {Denops} denops - The Denops instance. + * @param {number} bufnr - The buffer number. + * @returns {Promise} */ -export async function checkIfAiderBuffer( +async function openFloatingWindow( 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"); +): Promise { + const terminal_width = Math.floor( + ensure(await n.nvim_get_option(denops, "columns"), is.Number), + ); + const terminal_height = Math.floor( + ensure(await n.nvim_get_option(denops, "lines"), is.Number), + ); + const floatWinHeight = ensure( + await v.g.get(denops, "aider_floatwin_height"), + is.Number, + ); + const floatWinWidth = ensure( + await v.g.get(denops, "aider_floatwin_width"), + is.Number, + ); + + const row = Math.floor((terminal_height - floatWinHeight) / 2); + const col = Math.floor((terminal_width - floatWinWidth) / 2); + + await n.nvim_open_win(denops, bufnr, true, { + title: + "| normal mode > qq: quit, terminal mode > : quit | visual mode > : send prompt |", + relative: "editor", + border: "double", + width: floatWinWidth, + height: floatWinHeight, + row: row, + col: col, + }); + await n.nvim_buf_set_keymap( + denops, + bufnr, + "t", + "", + "close!", + { + silent: true, + }, + ); + await n.nvim_buf_set_keymap( + denops, + bufnr, + "n", + "q", + "close!", + { + silent: true, + }, + ); + await n.nvim_buf_set_keymap( + denops, + bufnr, + "n", + "", + "close!", + { + silent: true, + }, + ); + + await denops.cmd("set nonumber"); } +async function sendPromptFromFloatingWindow(denops: Denops): Promise { + const bufnr = await getAiderBufferNr(denops); + if (bufnr === undefined) { + return; + } + await openFloatingWindow(denops, bufnr); + await feedkeys(denops, "G"); + await feedkeys(denops, '"qp'); + + const jobId = ensure( + await fn.getbufvar(denops, bufnr, "&channel"), + is.Number, + ); + + await denops.call("chansend", jobId, "\n"); +} /** - * バッファがターミナルバッファかどうかを確認します。 + * スプリットウィンドウからプロンプトを送信する非同期関数 + * + * この関数は以下の操作を行います: + * 1. ターミナルバッファを識別 + * 2. 現在のバッファを閉じる + * 3. ターミナルウィンドウに移動 + * 4. カーソルを最後に移動 + * 5. レジスタ 'q' の内容を貼り付け + * 6. Enter キーを送信 + * 7. 元のウィンドウに戻る + * * @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"; +async function sendPromptFromSplitWindow(denops: Denops): Promise { + await identifyAiderBuffer(denops, async (job_id, winnr, _bufnr) => { + await denops.cmd(`bdelete!`); + if (await v.g.get(denops, "aider_buffer_open_type") !== "floating") { + await denops.cmd(`${winnr}wincmd w`); + } else { + const totalWindows = ensure( + await denops.call("winnr", "$"), + is.Number, + ); + + for (let winnr = 1; winnr <= totalWindows; winnr++) { + const bufnr = await denops.call("winbufnr", winnr); + + const buftype = await denops.call("getbufvar", bufnr, "&buftype"); + + if (buftype === "terminal") { + await denops.cmd(`${winnr}wincmd w`); + break; + } + } + } + await feedkeys(denops, "G"); + await feedkeys(denops, '"qp'); + await denops.call("chansend", job_id, "\n"); + await denops.cmd("wincmd p"); + }); } diff --git a/denops/aider/utils.ts b/denops/aider/utils.ts index 626e62c..5bd3cf0 100644 --- a/denops/aider/utils.ts +++ b/denops/aider/utils.ts @@ -2,7 +2,7 @@ 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 { ensure, is } 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 { checkIfAiderBuffer } from "./buffer.ts"; +import { buffer } from "./buffer.ts"; /** * Gets the additional prompt from vim global variable "aider_additional_prompt". @@ -58,7 +58,7 @@ export async function getAiderBufferNr( for (let i = 1; i <= buf_count; i++) { const bufnr = ensure(await fn.bufnr(denops, i), is.Number); - if (await checkIfAiderBuffer(denops, bufnr)) { + if (await buffer.checkIfAiderBuffer(denops, bufnr)) { return bufnr; } } From 7499f14b9e0631b5871c3f908ac8a1806efd2740 Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Tue, 10 Sep 2024 23:40:43 +0900 Subject: [PATCH 3/7] emit on sendPrompt --- denops/aider/buffer.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/denops/aider/buffer.ts b/denops/aider/buffer.ts index 031162e..7260b33 100644 --- a/denops/aider/buffer.ts +++ b/denops/aider/buffer.ts @@ -112,6 +112,7 @@ export const buffer = { ? sendPromptFromFloatingWindow(denops) : sendPromptFromSplitWindow(denops); + await emit("User", "AiderOpen"); return; }, async openFloatingWindowWithSelectedCode( From b1bbb03bf418a8cdb5dd4d06cd48e63bae76db8c Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Tue, 10 Sep 2024 23:43:13 +0900 Subject: [PATCH 4/7] add autocmd key setting on README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 0521d55..c34cb7f 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,16 @@ nnoremap ai :AiderAddIgnoreCurrentFile nnoremap aI :AiderOpenIgnore nnoremap ah :AiderHide vmap av :AiderVisualTextWithPrompt +augroup AiderOpenGroup + autocmd! + autocmd User AiderOpen call s:AiderOpenHandler() +augroup END + +function! s:AiderOpenHandler() abort + " Set key mappings for the buffer + execute 'tnoremap ' + execute 'nnoremap :AiderHide' +endfunction ``` ## Usage From 3b07135b2acf69ca14334da177b3bfd9dd15e7b9 Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Tue, 10 Sep 2024 23:46:57 +0900 Subject: [PATCH 5/7] remove default keymap for closing floating window --- denops/aider/buffer.ts | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/denops/aider/buffer.ts b/denops/aider/buffer.ts index 7260b33..23f39d8 100644 --- a/denops/aider/buffer.ts +++ b/denops/aider/buffer.ts @@ -275,8 +275,6 @@ async function openFloatingWindow( const col = Math.floor((terminal_width - floatWinWidth) / 2); await n.nvim_open_win(denops, bufnr, true, { - title: - "| normal mode > qq: quit, terminal mode > : quit | visual mode > : send prompt |", relative: "editor", border: "double", width: floatWinWidth, @@ -284,36 +282,6 @@ async function openFloatingWindow( row: row, col: col, }); - await n.nvim_buf_set_keymap( - denops, - bufnr, - "t", - "", - "close!", - { - silent: true, - }, - ); - await n.nvim_buf_set_keymap( - denops, - bufnr, - "n", - "q", - "close!", - { - silent: true, - }, - ); - await n.nvim_buf_set_keymap( - denops, - bufnr, - "n", - "", - "close!", - { - silent: true, - }, - ); await denops.cmd("set nonumber"); } From 2fd59ec6c727e9f01c4bfef5241dd82a6676a091 Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Tue, 10 Sep 2024 23:54:29 +0900 Subject: [PATCH 6/7] add lua settings to README.md --- README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/README.md b/README.md index c34cb7f..efade5f 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Minimal helper plugin for aider with neovim. ## Settings +### vimscript Please add the following settings to your vimrc or init.vim. ```vim @@ -44,6 +45,36 @@ function! s:AiderOpenHandler() abort endfunction ``` +### lua (lazy.nvim) +Please add the following settings to your lazy settings. + +```lua +{ "nekowasabi/aider.vim" + , dependencies = "vim-denops/denops.vim" + , config = function() + vim.g.aider_command = 'aider --no-auto-commits' + vim.g.aider_buffer_open_type = 'floating' + vim.g.aider_floatwin_width = 100 + vim.g.aider_floatwin_height = 20 + vim.api.nvim_set_keymap('n', 'ar', ':AiderRun', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('n', 'aa', ':AiderAddCurrentFile', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('n', 'aw', ':AiderAddWeb', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('n', 'ask', ':AiderAsk ', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('n', 'ase', ':AiderSendPrompt ', { noremap = true, silent = true }) + + vim.api.nvim_create_autocmd('User', + { + pattern = 'AiderOpen', + callback = + function(args) + vim.keymap.set('t', '', '', { buffer = args.buf }) + vim.keymap.set('n', '', 'AiderHide', { buffer = args.buf }) + end + }) + end + } +``` + ## Usage To use aider.vim, you can run the following commands within Vim or Neovim: From 9b71324efbe8f691dc8eeda1116f2e70e4659ca0 Mon Sep 17 00:00:00 2001 From: tsukimizake Date: Wed, 11 Sep 2024 00:04:01 +0900 Subject: [PATCH 7/7] same keymap as the vimscript version on lua --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index efade5f..8d65f8b 100644 --- a/README.md +++ b/README.md @@ -56,11 +56,6 @@ Please add the following settings to your lazy settings. vim.g.aider_buffer_open_type = 'floating' vim.g.aider_floatwin_width = 100 vim.g.aider_floatwin_height = 20 - vim.api.nvim_set_keymap('n', 'ar', ':AiderRun', { noremap = true, silent = true }) - vim.api.nvim_set_keymap('n', 'aa', ':AiderAddCurrentFile', { noremap = true, silent = true }) - vim.api.nvim_set_keymap('n', 'aw', ':AiderAddWeb', { noremap = true, silent = true }) - vim.api.nvim_set_keymap('n', 'ask', ':AiderAsk ', { noremap = true, silent = true }) - vim.api.nvim_set_keymap('n', 'ase', ':AiderSendPrompt ', { noremap = true, silent = true }) vim.api.nvim_create_autocmd('User', { @@ -71,6 +66,14 @@ Please add the following settings to your lazy settings. vim.keymap.set('n', '', 'AiderHide', { buffer = args.buf }) end }) + vim.api.nvim_set_keymap('n', 'ar', ':AiderRun', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('n', 'aa', ':AiderAddCurrentFile', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('n', 'aw', ':AiderAddWeb', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('n', 'ax', ':AiderExit', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('n', 'ai', ':AiderAddIgnoreCurrentFile', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('n', 'aI', ':AiderOpenIgnore', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('n', 'ah', ':AiderHide', { noremap = true, silent = true }) + vim.api.nvim_set_keymap('v', 'av', ':AiderVisualTextWithPrompt', { noremap = true, silent = true }) end } ```