Skip to content

feat: support edits from Cody #220

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 179 additions & 0 deletions lua/sg/cody/protocol.lua
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,183 @@ proto.document = {
end,
}

---@class cody.TextDocumentEditParams
---@field uri string
---@field edits cody.TextEdit[]
---@field options? { undoStopBefore: boolean, undoStopAfter: boolean }

---@alias cody.TextEdit cody.ReplaceTextEdit | cody.InsertTextEdit | cody.DeleteTextEdit

---@class cody.ReplaceTextEdit
---@field type 'replace'
---@field range cody.Range
---@field value string
---unsupported field metadata? vscode.WorkspaceEditEntryMetadata

---@class cody.InsertTextEdit
---@field type 'insert'
---@field position cody.Position
---@field value string
---unsupported metadata?: vscode.WorkspaceEditEntryMetadata

---@class cody.DeleteTextEdit
---@field type 'delete'
---@field range cody.Range
---unsupported metadata? vscode.WorkspaceEditEntryMetadata

--- Apply a single text edit to a buffer
---@param bufnr number
---@param edit cody.TextEdit
proto.apply_text_edit = function(bufnr, edit)
if edit.type == "replace" then
local replace = edit ---@as cody.ReplaceTextEdit

local range = replace.range
local start = range.start
local finish = range["end"]

vim.api.nvim_buf_set_text(
bufnr,
start.line,
start.character,
finish.line,
finish.character,
vim.split(replace.value, "\n")
)
elseif edit.type == "insert" then
local insert = edit ---@as cody.InsertTextEdit

local line = insert.position.line
local character = insert.position.character
vim.api.nvim_buf_set_text(
bufnr,
line,
character,
line,
character,
vim.split(insert.value, "\n")
)
elseif edit.type == "delete" then
local delete = edit ---@as cody.DeleteTextEdit
local range = delete.range
local start = range.start
local finish = range["end"]

vim.api.nvim_buf_set_text(bufnr, start.line, start.character, finish.line, finish.character, {})
else
error("Unknown edit type: " .. edit.type)
end
end

--- Handle text document edits
---@param _ any
---@param params cody.TextDocumentEditParams
proto.handle_text_document_edit = function(_, params)
local bufnr = vim.uri_to_bufnr(params.uri)
for _, edit in ipairs(params.edits) do
proto.apply_text_edit(bufnr, edit)
end

return true
end

---@class cody.UntitledTextDocument
---@field uri string
---@field content? string
---@field language? string

--- Open an untitled document
---@param _ any
---@param params cody.UntitledTextDocument
proto.handle_text_document_open_untitled_document = function(_, params)
vim.cmd.edit(params.uri)
if params.content then
vim.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(params.content, "\n"))
end
end

---@class cody.WorkspaceEditParams
---@field operations cody.WorkspaceEditOperation[]
---@field metadata? cody.vscode.WorkspaceEditMetadata

---@alias cody.WorkspaceEditOperation cody.CreateFileOperation | cody.RenameFileOperation | cody.DeleteFileOperation | cody.EditFileOperation

---@class cody.WriteFileOptions
---@field overwrite? boolean
---@field ignoreIfExists? boolean

---@class cody.CreateFileOperation
---@field type 'create-file'
---@field uri string
---@field options? cody.WriteFileOptions
---@field textContents string
---@field metadata? cody.vscode.WorkspaceEditEntryMetadata

---@class cody.RenameFileOperation
---@field type 'rename-file'
---@field oldUri string
---@field newUri string
---@field options? cody.WriteFileOptions
---@field metadata? cody.vscode.WorkspaceEditEntryMetadata

---@class cody.DeleteFileOperation
---@field type 'delete-file'
---@field uri string
---@field deleteOptions? { recursive: boolean, ignoreIfNotExists: boolean }
---@field metadata? cody.vscode.WorkspaceEditEntryMetadata

---@class cody.EditFileOperation
---@field type 'edit-file'
---@field uri string
---@field edits cody.TextEdit[]

---@class cody.vscode.WorkspaceEditMetadata
---@field isRefactoring? boolean

---@class cody.vscode.WorkspaceEditEntryMetadata
---@field needsConfirmation boolean
---@field label string
---@field description? string

--- Handle a workspace edit
---@param _ any
---@param params cody.WorkspaceEditParams
proto.handle_workspace_edit = function(_, params)
for _, operation in ipairs(params.operations) do
print("operation: ", vim.inspect(operation))
if operation.type == "create-file" then
local create = operation ---@as cody.CreateFileOperation
--- uri string
--- options? cody.WriteFileOptions
--- textContents string
--- metadata? cody.vscode.WorkspaceEditEntryMetadata

local filename = vim.uri_to_fname(create.uri)

-- TODO: create.options -> flags
local flags = nil
vim.fn.writefile(vim.split(create.textContents, "\n"), filename, flags)
elseif operation.type == "rename-file" then
local rename = operation ---@as cody.RenameFileOperation

-- TODO: handle options
vim.fn.rename(vim.uri_to_fname(rename.oldUri), vim.uri_to_fname(rename.newUri))
elseif operation.type == "delete-file" then
local delete = operation ---@as cody.DeleteFileOperation

-- TODO: delete.deleteOptions
vim.fn.delete(vim.uri_to_fname(delete.uri))
elseif operation.type == "edit-file" then
local edit = operation ---@as cody.EditFileOperation

local bufnr = vim.uri_to_bufnr(edit.uri)
for _, text_edit in ipairs(edit.edits) do
proto.apply_text_edit(bufnr, text_edit)
end
else
error("Unknown workspace edit operation: " .. operation.type)
end
end
end

return proto
30 changes: 23 additions & 7 deletions lua/sg/cody/rpc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -143,20 +143,36 @@ M.start = function(opts, callback)
notification_callback(noti)
end
end,

["editTaskState/didChange"] = function(...)
require("sg.cody.rpc.edit_task").did_change(...)
end,
}

local server_handlers = {
["webview/create"] = function(_, params)
vim.notify(string.format("WEBVIEW CREATE: %s", vim.inspect(params)))
end,

["showQuickPick"] = function(_, params)
return function(respond)
vim.ui.select(params, nil, function(selected)
respond(selected)
end)
end
end,
-- TODO: Don't think we ever merged this
-- ["showQuickPick"] = function(_, params)
-- return function(respond)
-- vim.ui.select(params, nil, function(selected)
-- respond(selected)
-- end)
-- end
-- end,

-- 'textDocument/edit': [TextDocumentEditParams, boolean]
["textDocument/edit"] = protocol.handle_text_document_edit,

-- 'textDocument/openUntitledDocument': [UntitledTextDocument, boolean]
["textDocument/openUntitledDocument"] = protocol.handle_open_untitled_document,

-- 'textDocument/show': [{ uri: string; options?: vscode.TextDocumentShowOptions }, boolean]

-- 'workspace/edit': [WorkspaceEditParams, boolean]
["workspace/edit"] = protocol.handle_workspace_edit,
}

-- Clear old information before restarting the client
Expand Down
36 changes: 36 additions & 0 deletions lua/sg/cody/rpc/edit_task.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
local M = {}

local tasks = {}

---@enum cody.CodyTaskState
local cody_task_state = {
idle = 1,
working = 2,
inserting = 3,
applying = 4,
formatting = 5,
applied = 6,
finished = 7,
error = 8,
pending = 9,
}

---@class cody.CodyError
---@field message string
---@field cause? cody.CodyError
---@field stack? string

---@class cody.EditTask
---@field id string
---@field state cody.CodyTaskState
---@field error? cody.CodyError

---comment
---@param task_state any
M.did_change = function(task_state)
print("editTaskState/didChange", vim.inspect(task_state))
end

-- editCommands/test

return M
4 changes: 2 additions & 2 deletions lua/sg/log.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ end

local logger = require("plenary.log").new {
plugin = "sg",
level = "warn",
use_console = false,
level = "info",
use_console = true,
info_level = 3,
}

Expand Down
6 changes: 3 additions & 3 deletions lua/sg/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ local M = {}
---@field content string?
---@field selection cody.Range?

---@class CodyPosition
---@class cody.Position
---@field line number
--- 0-indexed
---@field character number
--- 0-indexed

---@class cody.Range
---@field start CodyPosition
---@field end CodyPosition
---@field start cody.Position
---@field end cody.Position

---@class cody.URI
---@field authority string
Expand Down
6 changes: 6 additions & 0 deletions scratch/edit-test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
local rpc = require "sg.cody.rpc"

rpc.request("editCommands/test", nil, function(err, data)
print "hello?"
print(vim.inspect { err = err, data = data })
end)