From 0979d74ee1c06a0234baad2e55d9f35d1cafadde Mon Sep 17 00:00:00 2001 From: Trevor Facer Date: Fri, 8 Aug 2025 08:04:22 -0600 Subject: [PATCH 1/7] chore: Default model choice to gpt-5 --- lua/explain-it/config.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/explain-it/config.lua b/lua/explain-it/config.lua index 0a221f3..e513440 100644 --- a/lua/explain-it/config.lua +++ b/lua/explain-it/config.lua @@ -8,7 +8,7 @@ M.options = { debug = false, max_notification_width = 200, max_retries = 3, - openai_chat_model = "gpt-4o", + openai_chat_model = "gpt-5", openai_completion_model = "text-davinci-003", output_directory = "/tmp/explain_it_output", split_responses = true, From 342ab04b930fe744a3e3a245ed4c72c4919552b1 Mon Sep 17 00:00:00 2001 From: Trevor Facer Date: Thu, 14 Aug 2025 08:59:06 -0600 Subject: [PATCH 2/7] docs: Generate latest docs --- doc/explain-it.txt | 94 +++++++++++++++++++++++++--------------------- doc/tags | 1 + 2 files changed, 52 insertions(+), 43 deletions(-) diff --git a/doc/explain-it.txt b/doc/explain-it.txt index fdff890..2491a7b 100644 --- a/doc/explain-it.txt +++ b/doc/explain-it.txt @@ -3,7 +3,7 @@ *ExplainIt.setup()* `ExplainIt.setup`({opts}) Sets up plugin with user-provided options -Parameters~ +Parameters ~ {opts} `(any)` ------------------------------------------------------------------------------ @@ -12,14 +12,14 @@ Parameters~ Core function for preparing requests to external services. Based on input, will either pull the contents of the full buffer into a variable or just the visually selected text, then call call_chat_gpt with it. -Parameters~ +Parameters ~ {opts} `(any)` ------------------------------------------------------------------------------ *ExplainIt.call_chat_gpt()* `ExplainIt.call_chat_gpt`({opts}) Takes prepared input text and calls either the chat or the completion api on the chat-gpt module -Parameters~ +Parameters ~ {opts} `(any)` @@ -28,14 +28,14 @@ Parameters~ *M.options* `M.options` Plugin default config values: -> +>lua M.options = { append_current_buffer = false, -- Prints useful logs about what event are triggered, and reasons actions are executed. debug = false, max_notification_width = 200, max_retries = 3, - openai_chat_model = "gpt-3.5-turbo-16k-0613", + openai_chat_model = "gpt-5", openai_completion_model = "text-davinci-003", output_directory = "/tmp/explain_it_output", split_responses = true, @@ -49,14 +49,13 @@ Plugin default config values: } < - ------------------------------------------------------------------------------ *M.setup()* `M.setup`({options}) -Parameters~ +Parameters ~ {options} `(table)` Module config table. See |M.options|. -Usage~ +Usage ~ `require("explain-it").setup()` (add `{}` with your |M.options| table) @@ -66,18 +65,18 @@ Usage~ `M.make_system_call`({command}) Makes a call into the underlying operating system and reads the response -Parameters~ +Parameters ~ {command} `(string)` the command to run -Return~ +Return ~ `(string|nil)` result result of the command ------------------------------------------------------------------------------ *M.make_system_call_with_retry()* `M.make_system_call_with_retry`({command}) Wrapper around make_system_call that will retry failed requests -Parameters~ +Parameters ~ {command} `(string)` -Return~ +Return ~ `(table|lsp.ResponseError)` ------------------------------------------------------------------------------ @@ -92,17 +91,26 @@ Creates a temporary file on the operating system *M.notify_response()* `M.notify_response`({ai_response}) response using notify -Parameters~ -{ai_response} AIResponse -Return~ +Parameters ~ +{ai_response} `(AIResponse)` +Return ~ +`(nil)` + +------------------------------------------------------------------------------ + *M.append_buffer_response()* + `M.append_buffer_response`({ai_response}) +response using notify +Parameters ~ +{ai_response} `(AIResponse)` +Return ~ `(nil)` ============================================================================== ------------------------------------------------------------------------------ -Class~ +Class ~ {AIResponse} -Fields~ +Fields ~ {question} `(string)` {input} `(string)` {response} `(string)` @@ -124,57 +132,57 @@ commands *M.parse_response()* `M.parse_response`({response_json}, {split}) Formats a response string to extract the chat-gpt response (or error) from the API response. Includes logic to be API agnostic for either the completion or the chat API -Parameters~ +Parameters ~ {response_json} `(table)` {split} `(boolean)` -Return~ +Return ~ `(string)` ------------------------------------------------------------------------------ *M.get_filetype()* `M.get_filetype`() Uses vim api to get filetype of current buffer -Return~ +Return ~ `(string)` ------------------------------------------------------------------------------ *M.get_question()* `M.get_question`({question}) Returns default question based on filetype of buffer -Parameters~ +Parameters ~ {question} `(string|nil)` -Return~ +Return ~ `(string)` ------------------------------------------------------------------------------ *M.get_formatted_command()* `M.get_formatted_command`({escaped_input}, {question}, {command_type}) Uses a local command and replaces placeholder text with the ChatGPT API Key from an env var and placeholder text with the prompt -Parameters~ +Parameters ~ {escaped_input} `(string)` {question} `(string)` -{command_type} commands -Return~ +{command_type} `(commands)` +Return ~ `(string)` ------------------------------------------------------------------------------ *M.call_gpt()* `M.call_gpt`({escaped_input}, {optional_question}, {prompt_type}) Formats input in order to make an API call to ChatGPT, makes the API call, writes the prompt and response to a file, then returns the response -Parameters~ +Parameters ~ {escaped_input} `(any)` {optional_question} `(any)` {prompt_type} `(any)` -Return~ -AIResponse +Return ~ +`(AIResponse)` ------------------------------------------------------------------------------ *M.write_ai_response_to_file()* `M.write_ai_response_to_file`({ai_response}) Writes the prompt and response to a file so that Chat-GPT responses can be persisted -Parameters~ -{ai_response} AIResponse -Return~ +Parameters ~ +{ai_response} `(AIResponse)` +Return ~ `(string)` @@ -185,21 +193,21 @@ Return~ Yank current visual selection into the 'v' register Note that this makes no effort to preserve this register Credit: tjdevries -Return~ +Return ~ `(string)` ------------------------------------------------------------------------------ *M.get_buffer_lines()* `M.get_buffer_lines`() Get all lines in current buffer -Return~ +Return ~ `(string)` ------------------------------------------------------------------------------ *M.append_buffer_lines()* `M.append_buffer_lines`({bufnr}, {content}) content to buffer -Parameters~ +Parameters ~ {bufnr} `(number)` {content} `(string)` @@ -209,18 +217,18 @@ Parameters~ *M.escape()* `M.escape`({input}) Escapes characters so that they can be included in a JSON body -Parameters~ +Parameters ~ {input} `(any)` -Return~ +Return ~ `(string)` ------------------------------------------------------------------------------ *M.get_escaped_string()* `M.get_escaped_string`({input}) Escapes a string value or all string values on an input table -Parameters~ -{input} `(string|{)` [string]: string } -Return~ +Parameters ~ +{input} `(string|{ [string]: string })` +Return ~ `(string)` @@ -229,18 +237,18 @@ Return~ *M.format_string_with_line_breaks()* `M.format_string_with_line_breaks`({str}) Takes a string of variable length as input, then formats the string by splitting it into words and inserting line breaks to ensure that each line is no longer than the max_width as defined in global settings -Parameters~ +Parameters ~ {str} `(string)` -Return~ +Return ~ `(string)` ------------------------------------------------------------------------------ *M.truncate_string()* `M.truncate_string`({str}, {len}) Takes a string as input and returns a truncated version of the string if it is longer than 77 characters. The truncated version includes an ellipsis ("...") at the end. If the string is 77 characters or shorter, the function simply returns the original string. The code also includes comments that describe the function's input and output parameters. Finally, the code returns the module "M". -Parameters~ +Parameters ~ {str} `(string)` -Return~ +Return ~ `(string)` diff --git a/doc/tags b/doc/tags index 9ab852e..ee295dc 100644 --- a/doc/tags +++ b/doc/tags @@ -3,6 +3,7 @@ ExplainIt.call_chat_gpt() explain-it.txt /*ExplainIt.call_chat_gpt()* ExplainIt.explain_it() explain-it.txt /*ExplainIt.explain_it()* ExplainIt.setup() explain-it.txt /*ExplainIt.setup()* M.append_buffer_lines() explain-it.txt /*M.append_buffer_lines()* +M.append_buffer_response() explain-it.txt /*M.append_buffer_response()* M.call_gpt() explain-it.txt /*M.call_gpt()* M.escape() explain-it.txt /*M.escape()* M.format_string_with_line_breaks() explain-it.txt /*M.format_string_with_line_breaks()* From e2ef7b5936d80602079de5e0ebf6e9747a3fd5af Mon Sep 17 00:00:00 2001 From: Trevor Facer Date: Thu, 14 Aug 2025 12:08:38 -0600 Subject: [PATCH 3/7] build: Modernize GHA workflow --- .github/workflows/main.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index aec98d4..afd1019 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,7 +7,7 @@ on: types: [opened, synchronize] concurrency: - group: github.head_ref + group: ${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: @@ -54,25 +54,25 @@ jobs: matrix: include: - id: Neovim Nightly - os: ubuntu-20.04 + os: ubuntu-latest url: https://github.com/neovim/neovim/releases/download/nightly/nvim-linux64.tar.gz manager: sudo apt-get packages: -y ripgrep - id: Neovim 0.9 - os: ubuntu-20.04 + os: ubuntu-latest url: https://github.com/neovim/neovim/releases/download/v0.9.0/nvim-linux64.tar.gz manager: sudo apt-get packages: -y ripgrep - id: Neovim 0.8 - os: ubuntu-20.04 + os: ubuntu-latest url: https://github.com/neovim/neovim/releases/download/v0.8.0/nvim-linux64.tar.gz manager: sudo apt-get packages: -y ripgrep steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: date +%F > todays-date - name: Restore from todays cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: _neovim key: ${{ runner.os }}-${{ matrix.url }}-${{ hashFiles('todays-date') }} From 3c9de04300f2d39e5b059220fa00d9b965dba9f2 Mon Sep 17 00:00:00 2001 From: Trevor Facer Date: Fri, 15 Aug 2025 11:30:25 -0600 Subject: [PATCH 4/7] test: Fix failing tests --- lua/tests/handlers/response_spec.lua | 20 ++++++++++++++++---- lua/tests/init_spec.lua | 2 ++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lua/tests/handlers/response_spec.lua b/lua/tests/handlers/response_spec.lua index e8a3f5d..235d800 100644 --- a/lua/tests/handlers/response_spec.lua +++ b/lua/tests/handlers/response_spec.lua @@ -1,13 +1,25 @@ local stub = require "luassert.stub" + +-- Clear loaded modules to ensure we can mock properly +package.loaded["notify"] = nil +package.loaded["explain-it.handlers.response"] = nil + +-- Create stub for notify +local notify_stub = stub() +package.loaded["notify"] = notify_stub + local response_handler = require "explain-it.handlers.response" -local notify = require "notify" + describe("notify", function() before_each(function() - stub(notify, "notify") require("explain-it").setup { token_limit = 2000, } end) + + after_each(function() + notify_stub:clear() + end) it("should notify response", function() local ai_response = { @@ -25,11 +37,11 @@ describe("notify", function() Nice to meet you John ]] response_handler.notify_response(ai_response) - assert.stub(notify.notify).was_called_with(expected_notification, nil, nil) + assert.stub(notify_stub).was_called_with(expected_notification) end) it("should not notify response if ai_response is nil", function() response_handler.notify_response(nil) - assert.stub(notify.notify).was_not_called() + assert.stub(notify_stub).was_not_called() end) end) diff --git a/lua/tests/init_spec.lua b/lua/tests/init_spec.lua index 2d24a2d..e115076 100644 --- a/lua/tests/init_spec.lua +++ b/lua/tests/init_spec.lua @@ -40,6 +40,7 @@ describe("ExplainIt", function() custom_prompt = false, text = "escaped string", is_visual = false, + output_to_buffer = false, } end) @@ -52,6 +53,7 @@ describe("ExplainIt", function() custom_prompt = false, text = "escaped string", is_visual = true, + output_to_buffer = false, } end) From 6ceb4cebda482647a2aac40ca9f20ed94d39545e Mon Sep 17 00:00:00 2001 From: Trevor Facer Date: Tue, 19 Aug 2025 06:56:21 -0600 Subject: [PATCH 5/7] lint: Fix linting of test file --- lua/tests/handlers/response_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/tests/handlers/response_spec.lua b/lua/tests/handlers/response_spec.lua index 235d800..e32fe90 100644 --- a/lua/tests/handlers/response_spec.lua +++ b/lua/tests/handlers/response_spec.lua @@ -16,7 +16,7 @@ describe("notify", function() token_limit = 2000, } end) - + after_each(function() notify_stub:clear() end) From 397d82378980bc7cdec515982663e6655c936f6c Mon Sep 17 00:00:00 2001 From: Trevor Facer Date: Tue, 19 Aug 2025 07:08:58 -0600 Subject: [PATCH 6/7] build: Use correct build for neovim nightly --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index afd1019..5114d66 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -55,7 +55,7 @@ jobs: include: - id: Neovim Nightly os: ubuntu-latest - url: https://github.com/neovim/neovim/releases/download/nightly/nvim-linux64.tar.gz + url: https://github.com/neovim/neovim/releases/download/nightly/nvim-linux-x86_64.tar.gz manager: sudo apt-get packages: -y ripgrep - id: Neovim 0.9 From 436afa9a0d234918a658328983a14787193a464b Mon Sep 17 00:00:00 2001 From: Trevor Facer Date: Tue, 19 Aug 2025 07:12:17 -0600 Subject: [PATCH 7/7] build: Use neovim stable and 0.10.4 for CI/CD tests --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5114d66..e8bc378 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -58,14 +58,14 @@ jobs: url: https://github.com/neovim/neovim/releases/download/nightly/nvim-linux-x86_64.tar.gz manager: sudo apt-get packages: -y ripgrep - - id: Neovim 0.9 + - id: Neovim 0.10.4 os: ubuntu-latest - url: https://github.com/neovim/neovim/releases/download/v0.9.0/nvim-linux64.tar.gz + url: https://github.com/neovim/neovim/releases/download/v0.10.4/nvim-linux-x86_64.tar.gz manager: sudo apt-get packages: -y ripgrep - - id: Neovim 0.8 + - id: Neovim Stable os: ubuntu-latest - url: https://github.com/neovim/neovim/releases/download/v0.8.0/nvim-linux64.tar.gz + url: https://github.com/neovim/neovim/releases/download/stable/nvim-linux-x86_64.tar.gz manager: sudo apt-get packages: -y ripgrep steps: