Skip to content
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

Apply #194

Merged
merged 10 commits into from
Jan 30, 2025
Merged

Apply #194

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
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![Tabnine Chat Support](https://github.com/codota/tabnine-nvim/blob/master/chat/ticker.png)](#tabnine-chat---beta)
[![Tabnine Chat Support](https://github.com/codota/tabnine-nvim/blob/master/chat/ticker.png)](#tabnine-chat)

# tabnine-nvim
Tabnine client for Neovim
Expand All @@ -14,7 +14,7 @@ Tabnine client for Neovim
- [Windows](#windows)
- [Activate (mandatory)](#activate-mandatory)
- [Activate Tabnine Pro](#activate-tabnine-pro)
- [Tabnine Chat - BETA](#tabnine-chat---beta)
- [Tabnine Chat](#tabnine-chat)
- [Commands](#commands)
- [Tabnine Chat commands](#tabnine-chat-commands)
- [`<Tab>` and `nvim-cmp`](#tab-and-nvim-cmp)
Expand Down Expand Up @@ -184,12 +184,16 @@ $ pacman -S --needed gtk3 glib2 webkit2gtk-4.1 libsoup3
- `:TabnineToggle` - to toggle enable/disable
- `:TabnineChat` - to launch Tabnine chat
- `:TabnineLoginWithAuthToken` - to log in using auth token (for headless environments, where no browser is available)
- `:TabnineAccept` - accept apply changes
- `:TabnineReject` - reject apply changes

### Tabnine Chat commands
- `:TabnineChat` - to open Tabnine Chat
- `:TabnineFix` - to fix the function in scope
- `:TabnineTest` - to generate tests for function in scope
- `:TabnineExplain` - to explain the function in scope
- `:TabnineAccept` - accept apply changes
- `:TabnineReject` - reject apply changes

## `<Tab>` and `nvim-cmp`

Expand Down
267 changes: 133 additions & 134 deletions chat/index.html

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions chat/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ fn main() -> wry::Result<()> {
.with_window_icon(Some(ICON.clone()))
.build(&event_loop)?;
let webview = WebViewBuilder::new(window)?
.with_devtools(true)
.with_custom_protocol("wry".into(), |request| {
let path = request.uri().path();
// Read the file content from file path
Expand Down Expand Up @@ -91,6 +92,7 @@ fn main() -> wry::Result<()> {
let _ = writeln!(lock, "{req}");
})
.with_url(BASE_URL)?
//.with_url("http://localhost:3000")?
.build()?;

let proxy = event_loop.create_proxy();
Expand Down
5 changes: 5 additions & 0 deletions doc/tabnine.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ Enable Tabnine
Toggle enable/disable
:TabnineToggle

Accept Apply Changes
:TabnineAccept

Reject Apply Changes
:TabnineReject
==============================================================================
CONFIGURATION *tabnine-nvim-configuration*

Expand Down
1 change: 0 additions & 1 deletion lua/tabnine/auto_commands.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ function M.setup()
ctermfg = config.get_config().suggestion_color.cterm,
})

-- For chat
api.nvim_set_hl(0, consts.tabnine_codelens_hl_group, {
fg = config.get_config().codelens_color.gui,
ctermfg = config.get_config().codelens_color.cterm,
Expand Down
130 changes: 130 additions & 0 deletions lua/tabnine/chat/apply.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
local api = vim.api
local M = {}
local original_window

local function create_floating_window(width_percentage, height_percentage, col_offset)
local width = math.floor(vim.o.columns * width_percentage)
local height = math.floor(vim.o.lines * height_percentage)
local row = math.floor((vim.o.lines - height) / 2)
local col = math.floor((vim.o.columns - width) / 2) + col_offset

local opts = {
relative = "editor",
width = width,
height = height,
row = row,
col = col,
style = "minimal",
border = "rounded",
}

return api.nvim_open_win(0, true, opts)
end

M.open = function(diff)
original_window = api.nvim_get_current_win()
if diff.comparableCode then
local current_filetype = vim.bo.filetype

-- Create two floating windows side by side
local left_win = create_floating_window(0.4, 0.8, -math.floor(vim.o.columns * 0.2))
local right_win = create_floating_window(0.4, 0.8, math.floor(vim.o.columns * 0.2))

-- Create buffers for comparable and new code
local comparable_buf = api.nvim_create_buf(false, true)
local new_buf = api.nvim_create_buf(false, true)

-- Set content and options for comparable code buffer
api.nvim_buf_set_lines(comparable_buf, 0, -1, false, vim.split(diff.comparableCode, "\n"))
api.nvim_buf_set_option(comparable_buf, "filetype", current_filetype)
api.nvim_buf_set_option(comparable_buf, "modifiable", false)

-- Set content and options for new code buffer
api.nvim_buf_set_lines(new_buf, 0, -1, false, vim.split(diff.newCode, "\n"))
api.nvim_buf_set_option(new_buf, "filetype", current_filetype)
api.nvim_buf_set_option(new_buf, "modifiable", false)

-- Set buffers to respective windows
api.nvim_win_set_buf(left_win, comparable_buf)
api.nvim_win_set_buf(right_win, new_buf)

-- Enable diff mode for both windows
api.nvim_win_call(left_win, function()
vim.cmd("diffthis")
end)
api.nvim_win_call(right_win, function()
vim.cmd("diffthis")
end)

-- Store window IDs
M.comparable_win = left_win
M.new_win = right_win
end
end

M.accept = function()
if
M.new_win
and M.comparable_win
and api.nvim_win_is_valid(M.new_win)
and api.nvim_win_is_valid(M.comparable_win)
then
local new_code_buf = api.nvim_win_get_buf(M.new_win)
local comparable_code_buf = api.nvim_win_get_buf(M.comparable_win)

-- Get the content of the new code buffer
local new_code = api.nvim_buf_get_lines(new_code_buf, 0, -1, false)

-- Get the content of the comparable code buffer
local comparable_code = api.nvim_buf_get_lines(comparable_code_buf, 0, -1, false)

-- Switch to the original window
api.nvim_set_current_win(original_window)
local original_buf = api.nvim_get_current_buf()
local original_lines = api.nvim_buf_get_lines(original_buf, 0, -1, false)

-- Find the start and end positions of the comparable code in the original buffer
local start_line, end_line
for i, line in ipairs(original_lines) do
if line == comparable_code[1] then
start_line = i - 1
end_line = start_line + #comparable_code - 1
if vim.deep_equal(vim.list_slice(original_lines, start_line + 1, end_line + 1), comparable_code) then
break
end
end
end

if start_line and end_line then
-- Replace only the comparable code portion with the new code
api.nvim_buf_set_lines(original_buf, start_line, end_line + 1, false, new_code)
end

-- Close the diff windows
M.close()
end
end

M.close = function()
if M.comparable_win and api.nvim_win_is_valid(M.comparable_win) then api.nvim_win_close(M.comparable_win, true) end
if M.new_win and api.nvim_win_is_valid(M.new_win) then api.nvim_win_close(M.new_win, true) end
M.comparable_win = nil
M.new_win = nil
end

M.reject = function()
if
M.new_win
and M.comparable_win
and api.nvim_win_is_valid(M.new_win)
and api.nvim_win_is_valid(M.comparable_win)
then
-- Switch back to the original window
api.nvim_set_current_win(original_window)

-- Close the diff windows
M.close()
end
end

return M
2 changes: 2 additions & 0 deletions lua/tabnine/chat/binary.lua
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ function ChatBinary:start()
id = message.id,
payload = payload,
})
end, function(error)
self:post_message({ id = message.id, error = error })
end)
else
self:post_message({ id = message.id, error = "not_implemented" })
Expand Down
44 changes: 35 additions & 9 deletions lua/tabnine/chat/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ local fn = vim.fn
local tabnine_binary = require("tabnine.binary")
local utils = require("tabnine.utils")
local api = vim.api
local apply = require("tabnine.chat.apply")
local config = require("tabnine.config")
local lsp = require("tabnine.lsp")

Expand Down Expand Up @@ -140,9 +141,17 @@ local function register_events(on_init)
})
end)
end)
chat_binary:register_event("insert_at_cursor", function(message, _)
chat_binary:register_event("insert_at_cursor", function(message, answer)
local lines = utils.str_to_lines(message.code)

if message.diff then
apply.open(message.diff)
answer({})
return
end

api.nvim_buf_set_text(0, fn.line("v") - 1, fn.col("v") - 1, fn.line(".") - 1, fn.col(".") - 1, lines)
answer({})
end)

chat_binary:register_event("get_basic_context", function(_, answer)
Expand All @@ -168,7 +177,7 @@ local function register_events(on_init)
type = "Editor",
fileCode = file_code,
path = api.nvim_buf_get_name(0),
currentLineIndex = api.nvim_win_get_cursor(0)[1],
currentLineIndex = api.nvim_win_get_cursor(0)[1] - 1,
}
elseif contextType == "Diagnostics" then
return {
Expand Down Expand Up @@ -242,18 +251,35 @@ local function register_events(on_init)
end)
end)

chat_binary:register_event("navigate_to_location", function(request, answer)
vim.cmd("e " .. request.path)
answer({})
chat_binary:register_event("navigate_to_location", function(request, answer, error)
if fn.filereadable(request.path) == 1 then
local current_buffer_path = vim.fn.expand("%:p")
local requested_path = fn.fnamemodify(request.path, ":p")

if current_buffer_path ~= requested_path then
vim.cmd("new " .. fn.fnameescape(request.path))
else
vim.cmd("buffer " .. fn.bufnr(request.path))
end

answer({})
else
error("File not found")
end
end)

chat_binary:register_event("create_new_file", function(request, answer)
vim.fn.writefile({ "" }, request.path)
fn.writefile({ "" }, request.path)
answer({})
end)

chat_binary:register_event("get_file_content", function(request, answer)
local file_content = utils.lines_to_str(vim.fn.readfile(request.filePath))
answer({ content = file_content })
chat_binary:register_event("get_file_content", function(request, answer, error)
if vim.fn.filereadable(request.filePath) == 1 then
local file_content = utils.lines_to_str(vim.fn.readfile(request.filePath))
answer({ content = file_content })
else
error("File not found")
end
end)

chat_binary:register_event("browse_folder", function(_, answer)
Expand Down
3 changes: 3 additions & 0 deletions lua/tabnine/chat/user_commands.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
local M = {}
local api = vim.api
local apply = require("tabnine.chat.apply")
local chat = require("tabnine.chat")
local codelens = require("tabnine.chat.codelens")

Expand All @@ -19,6 +20,8 @@ function M.setup()
api.nvim_create_user_command("TabnineFix", function()
codelens.run_under_cursor("/fix-code")
end, {})
api.nvim_create_user_command("TabnineAccept", apply.accept, {})
api.nvim_create_user_command("TabnineReject", apply.reject, {})
end

return M
Loading