Skip to content
This repository has been archived by the owner on Jul 22, 2023. It is now read-only.

Commit

Permalink
Merge pull request #10 from jameshiew/robustness
Browse files Browse the repository at this point in the history
v0.2.1
  • Loading branch information
jameshiew authored Sep 14, 2021
2 parents 50baf13 + 488f784 commit 817b40c
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 12 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

## [0.2.1] - 2021-09-14

### Changed
* Disable requesting compressed HTTP responses on Windows as possibly it is less likely to be supported by Windows' `curl`s

### Fixed
* Send an appropriate Vim notification in more cases when `curl` terminates with nonzero exit code, rather than raising a plenary.path error
* Prevent logspam when OpenAI returns a non-200 HTTP status that was caused by a timer not being closed properly

## [0.2.0] - 2021-09-14

### Changed
Expand All @@ -15,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed
* Using a default keymap in a buffer should work first time rather than just deselecting the current visual selection ([#2](https://github.com/jameshiew/nvim-magic/issues/2))
* OpenAI API key should no longer leak in an error message when `curl` times out, rather a generic request timed out error message is shown

## [0.1.0] - 2021-09-13

Expand Down
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# nvim-magic
[![Pipeline Status](https://gitlab.com/jameshiew/nvim-magic/badges/master/pipeline.svg)](https://gitlab.com/jameshiew/nvim-magic/-/pipelines)

A pluggable framework for integrating AI code assistance into Neovim. The goals are to make using AI code assistance unobtrusive, and to make it easy to create and share new flows that use AI code assistance.
A pluggable framework for integrating AI code assistance into Neovim. The goals are to make using AI code assistance unobtrusive, and to make it easy to create and share new flows that use AI code assistance. Go to [quickstart](#quickstart) for how to install.

## Features

Expand All @@ -28,6 +28,13 @@ A pluggable framework for integrating AI code assistance into Neovim. The goals

## Quickstart

### Prerequisites

* Neovim (v0.5+)
* `curl`

### Installation

At the moment, only a backend for [OpenAI](https://beta.openai.com/) is implemented, which is bundled in this repo and used by default. Your API key should be made available to your Neovim session in an environment variable `OPENAI_API_KEY`. See [docs/openai.md](docs/openai.md) for more details.

```shell
Expand All @@ -43,7 +50,7 @@ use({
config = function()
require('nvim-magic').setup()
end,
tag = 'v0.2.0', -- recommended to pin to a tag and update manually as there may be breaking changes
tag = 'v0.2.1', -- recommended to pin to a tag and update manually as there may be breaking changes
requires = {
'nvim-lua/plenary.nvim',
'MunifTanjim/nui.nvim'
Expand Down
1 change: 0 additions & 1 deletion docs/openai.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,3 @@ Be aware of the following:

Since the API key is passed as an environment variable to Neovim, it could be exposed to other processes. It will be visible if the environment of the Neovim process is inspected using something like `htop`, for example.

The error message echoed in Neovim when a completion request times out includes the API key, as it is passed to the underlying `curl` command on the command line.
27 changes: 23 additions & 4 deletions lua/nvim-magic-openai/curl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ local P = require('plenary.path')

local DEFAULT_TIMEOUT = 10000 -- milliseconds

local function is_windows()
return P.path.sep == '\\'
end

local function default_compressed()
return not is_windows() -- it may be more common on Windows for curl to be installed without compression support
end

-- Utils ----------------------------------------------------
-------------------------------------------------------------

Expand Down Expand Up @@ -101,7 +109,7 @@ util.gen_dump_path = function()
local v = (l == 'x') and math.random(0, 0xf) or math.random(0, 0xb)
return string.format('%x', v)
end)
if P.path.sep == '\\' then
if is_windows() then
path = string.format('%s\\AppData\\Local\\Temp\\plenary_curl_%s.headers', os.getenv('USERPROFILE'), id)
else
path = '/tmp/plenary_curl_' .. id .. '.headers'
Expand Down Expand Up @@ -264,6 +272,13 @@ local curl_job = function(args, dump_path, callback)
command = 'curl',
args = args,
on_exit = function(j, code)
if code ~= 0 then
callback(
nil,
'curl exited with code=' .. tostring(code) .. ' stderr=' .. vim.inspect(j:stderr_result())
)
return
end
local output = parse.response(j:result(), dump_path, code)
callback(output)
end,
Expand All @@ -272,7 +287,7 @@ end

local request = function(specs)
local args, opts = parse.request(vim.tbl_extend('force', {
compressed = true,
compressed = default_compressed(),
dry_run = false,
dump = util.gen_dump_path(),
}, specs))
Expand All @@ -283,10 +298,14 @@ local request = function(specs)

local response
local cb
local errmsg
if opts.callback then
cb = opts.callback
else
cb = function(output)
cb = function(output, error_msg)
if error_msg then
errmsg = error_msg
end
response = output
end
end
Expand All @@ -295,7 +314,7 @@ local request = function(specs)

if opts.return_job then
return job, function()
return response
return response, errmsg
end
end

Expand Down
15 changes: 10 additions & 5 deletions lua/nvim-magic-openai/http.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,34 +40,39 @@ function ClientMethods:post(api_endpoint, json_body, api_key, success, fail)
0,
interval_ms,
vim.schedule_wrap(function()
local res = res_fn()
local res, errmsg = res_fn()
if errmsg then
timer:close()
fail('error: ' .. errmsg)
return
end
if res then
local res_filename = id .. '-response.json'
local res_json = vim.fn.json_encode(res)
self.cache:save(res_filename, res_json)

assert(type(res.exit) == 'number')
if res.exit ~= 0 then
fail('curl call failed with exit code ' .. tostring(res.exit))
timer:close()
fail('curl call failed exit_code=' .. tostring(res.exit))
return
end

if res.status ~= 200 then
fail('non-200 HTTP status = see ' .. res_json .. ' for raw response')
timer:close()
fail('non-200 HTTP status response=' .. res_json)
return
end

success(res.body)
timer:close()
success(res.body)
return
end

elapsed_ms = elapsed_ms + interval_ms
if elapsed_ms > DEFAULT_TIMEOUT_MILLI then
fail('timed out after ' + tostring(DEFAULT_TIMEOUT_MILLI) + ' milliseconds')
timer:close()
fail('timed out after milliseconds=' .. tostring(DEFAULT_TIMEOUT_MILLI))
return
end
end)
Expand Down

0 comments on commit 817b40c

Please sign in to comment.