Skip to content

Commit

Permalink
fix(visual): Fix syncing vscode selection to nvim (#1647)
Browse files Browse the repository at this point in the history
Handle CJK characters
  • Loading branch information
xiyaowong committed Nov 22, 2023
1 parent ef81aec commit 8d2a14a
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 17 deletions.
27 changes: 27 additions & 0 deletions runtime/lua/vscode-neovim/internal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,31 @@ function M.get_selections(win)
end
end

---@param buf integer
---@param anchor lsp.Position
---@param active lsp.Position
function M.start_visual(buf, anchor, active)
if buf ~= api.nvim_get_current_buf() then
return
end

if util.compare_position(anchor, active) == 1 then
anchor.character = math.max(0, anchor.character - 1)
else
active.character = math.max(0, active.character - 1)
end

local anchor_line = anchor.line + 1
local active_line = active.line + 1
local anchor_line_text = util.get_line(buf, anchor.line)
local active_line_text = util.get_line(buf, active.line)
local anchor_col = vim.str_byteindex(anchor_line_text, anchor.character, true)
local active_col = vim.str_byteindex(active_line_text, active.character, true)

local v = fn.visualmode(1)
api.nvim_buf_set_mark(buf, "<", anchor_line, anchor_col, {})
api.nvim_buf_set_mark(buf, ">", active_line, active_col, {})
api.nvim_feedkeys((v == "V" or v == "\x16") and "gvv" or "gv", "n", false)
end

return M
43 changes: 43 additions & 0 deletions runtime/lua/vscode-neovim/util.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
local M = {}

local api = vim.api

function M.is_visual_mode()
local mode = vim.api.nvim_get_mode().mode
return mode == "v" or mode == "V" or mode == "\x16"
Expand All @@ -19,4 +21,45 @@ function M.get_char_at(line, byte_col, buf)
end
end

--- Gets the zero-indexed lines from the given buffer.
---
---@param bufnr integer bufnr to get the lines from
---@param rows integer[] zero-indexed line numbers
---@return table<integer, string> a table mapping rows to lines
function M.get_lines(bufnr, rows)
rows = type(rows) == "table" and rows or { rows }

local lines = {}
for _, row in ipairs(rows) do
lines[row] = (api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { "" })[1]
end
return lines
end

--- Gets the zero-indexed line from the given buffer.
---
---@param bufnr integer
---@param row integer zero-indexed line number
---@return string the line at row in filename
function M.get_line(bufnr, row)
return M.get_lines(bufnr, { row })[row]
end

--- Compare two positions
---@param a lsp.Position
---@param b lsp.Position
---@return -1|0|1 -1 if a < b, 0 if a == b, 1 if a > b
function M.compare_position(a, b)
if a.line > b.line then
return 1
end
if a.line == b.line and a.character > b.character then
return 1
end
if a.line == b.line and a.character == b.character then
return 0
end
return -1
end

return M
26 changes: 9 additions & 17 deletions src/cursor_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,32 +388,24 @@ export class CursorManager implements Disposable {
}

private async updateNeovimVisualSelection(editor: TextEditor, selection: Selection): Promise<void> {
if (this.main.modeManager.isInsertMode) return;
const winId = this.main.bufferManager.getWinIdForTextEditor(editor);
if (!winId) return;
const bufId = this.main.bufferManager.getBufferIdForTextDocument(editor.document);
if (!bufId) return;
const neovimCursorPos = this.neovimCursorPosition.get(editor);
if (neovimCursorPos && neovimCursorPos.isEqual(selection)) {
if (neovimCursorPos?.isEqual(selection)) {
logger.debug(`Skipping event since neovim has same visual pos`);
return;
}
let anchor = selection.anchor;
let active = selection.active;
// compensate for vscode selection containing last character
if (anchor.isBeforeOrEqual(active)) {
active = new Position(active.line, Math.max(active.character - 1, 0));
} else {
anchor = new Position(anchor.line, Math.max(anchor.character - 1, 0));
}
if (this.main.modeManager.isInsertMode) return;
logger.debug(
`Starting visual mode from: [${anchor.line}, ${anchor.character}] to [${active.line}, ${active.character}]`,
const anchor = selection.anchor;
const active = selection.active;
await actions.lua(
"start_visual",
bufId,
{ line: anchor.line, character: anchor.character },
{ line: active.line, character: active.character },
);
const visualmode = await this.client.call("visualmode", [1]);
await this.client.call("nvim_buf_set_mark", [bufId, "<", anchor.line + 1, anchor.character, {}]);
await this.client.call("nvim_buf_set_mark", [bufId, ">", active.line + 1, active.character, {}]);
await this.client.input(visualmode === "V" || visualmode === "\x16" ? "gvv" : "gv");
await this.client.call("winrestview", [{ curswant: active.character }]);
}

private triggerMovementFunctions = (editor: TextEditor, pos: Position): void => {
Expand Down

0 comments on commit 8d2a14a

Please sign in to comment.