Skip to content

Commit

Permalink
perf: add ml_get_buf, ml_get_buf_len and skipwhite
Browse files Browse the repository at this point in the history
  • Loading branch information
shellRaining committed Jun 9, 2024
1 parent 48bbc13 commit c579e2a
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 46 deletions.
1 change: 0 additions & 1 deletion lua/hlchunk/mods/chunk/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,6 @@ function ChunkMod:createAutocmd()
end
debounce_render_cb(event)
end

api.nvim_create_autocmd({ "CursorMovedI", "CursorMoved" }, {
group = self.meta.augroup_name,
callback = debounce_render_cb_with_pre_hook,
Expand Down
11 changes: 1 addition & 10 deletions lua/hlchunk/mods/indent/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,7 @@ function IndentMod:renderLine(bufnr, index, blankLen)
local style = self.meta.hl_name_list[(i - 1 + shadow_char_num) % #self.meta.hl_name_list + 1]
row_opts.virt_text = { { char, style } }
row_opts.virt_text_win_col = offset + (i - 1) * self.meta.shiftwidth

-- when use treesitter, without this judge, when paste code will over render
-- if row_opts.virt_text_win_col < 0 or row_opts.virt_text_win_col >= fn.indent(index) then
-- vim.notify(tostring(index))
-- -- if the len of the line is 0, and have leftcol, we should draw it indent by context
-- if api.nvim_buf_get_lines(bufnr, index - 1, index, false)[1] ~= "" then
-- return
-- end
-- end
api.nvim_buf_set_extmark(bufnr, self.meta.ns_id, index - 1, 0, row_opts)
api.nvim_buf_set_extmark(bufnr, self.meta.ns_id, index, 0, row_opts)
end
end

Expand Down
61 changes: 52 additions & 9 deletions lua/hlchunk/utils/cFunc.lua
Original file line number Diff line number Diff line change
@@ -1,27 +1,70 @@
local ffi = require("ffi")

ffi.cdef([[
typedef struct {} Error;
typedef struct file_buffer buf_T;
typedef int32_t linenr_T;
buf_T *find_buffer_by_handle(int buffer, Error *err);
int get_indent_buf(buf_T *buf, linenr_T lnum);
int get_sw_value(buf_T *buf);
typedef struct {} Error;
typedef int colnr_T;
typedef struct file_buffer buf_T;
typedef int32_t linenr_T;
buf_T *find_buffer_by_handle(int buffer, Error *err);
int get_indent_buf(buf_T *buf, linenr_T lnum); // fn.indent
int get_sw_value(buf_T *buf); // fn.shiftwidth
char *ml_get_buf(buf_T *buf, linenr_T lnum); // fn.getbufline
colnr_T ml_get_buf_len(buf_T *buf, linenr_T lnum); // #fn.getbufline
// string utils
char *skipwhite(const char *p);
]])
local C = ffi.C

local M = {}

---@param bufnr number
---@param row number 0-index
function M.get_indent(bufnr, row)
---@param lnum number 0-index
---@return number
function M.get_indent(bufnr, lnum)
local line_cnt = vim.api.nvim_buf_line_count(bufnr)
if lnum >= line_cnt then
return -1
end
local handler = C.find_buffer_by_handle(bufnr, ffi.new("Error"))
return C.get_indent_buf(handler, row + 1)
return C.get_indent_buf(handler, lnum + 1)
end

function M.get_sw(bufnr)
local handler = C.find_buffer_by_handle(bufnr, ffi.new("Error"))
return C.get_sw_value(handler)
end

---@param bufnr number
---@param lnum number 0-index
---@return string
function M.get_line(bufnr, lnum)
local line_cnt = vim.api.nvim_buf_line_count(bufnr)
if lnum >= line_cnt then
return ""
end
local handler = C.find_buffer_by_handle(bufnr, ffi.new("Error"))
return C.ml_get_buf(handler, lnum + 1)
end

---@param bufnr number
---@param lnum number 0-index
---@return number
function M.get_line_len(bufnr, lnum)
local line_cnt = vim.api.nvim_buf_line_count(bufnr)
if lnum >= line_cnt then
return 0
end
local handler = C.find_buffer_by_handle(bufnr, ffi.new("Error"))
return C.ml_get_buf_len(handler, lnum + 1)
end

---return the first non-white character in the string, or '' if the string is empty or contains only white characters
---@param s string
---@return string
function M.skipwhite(s)
local c = ffi.string(C.skipwhite(s), 1)
return c == "\0" and "" or c
end

return M
46 changes: 20 additions & 26 deletions lua/hlchunk/utils/indentHelper.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@ local fn = vim.fn
local cFunc = require("hlchunk.utils.cFunc")

-- get the virtual indent of the given line
---@param rows_indent table<number, number>
---@param line number
---@param bufnr number
---@param lnum number 0-indexed
---@return number
local function get_virt_indent(rows_indent, line)
local cur = line + 1
while rows_indent[cur] do
if rows_indent[cur] == 0 then
break
elseif rows_indent[cur] > 0 then
return rows_indent[cur]
local function get_virt_indent(bufnr, lnum)
local line_cnt = vim.api.nvim_buf_line_count(bufnr)
for i = lnum + 1, line_cnt do
local line = cFunc.get_line(bufnr, i)
if cFunc.skipwhite(line) ~= "" then
return cFunc.get_indent(bufnr, i)
end
cur = cur + 1
end
return -1
end
Expand Down Expand Up @@ -43,38 +41,34 @@ indentHelper.ROWS_INDENT_RETCODE = {
}

local function get_rows_indent_by_context(range)
local begRow = range.start + 1
local endRow = range.finish + 1

local rows_indent = {}
local bufnr = range.bufnr

for i = endRow, begRow, -1 do
rows_indent[i] = cFunc.get_indent(range.bufnr, i - 1)
if rows_indent[i] == 0 and #fn.getline(i) == 0 then
rows_indent[i] = get_virt_indent(rows_indent, i) or -1
for i = range.finish, range.start, -1 do
rows_indent[i] = cFunc.get_indent(bufnr, i)
if rows_indent[i] == 0 and cFunc.get_line_len(bufnr, i) == 0 then
rows_indent[i] = get_virt_indent(bufnr, i)
end
end

return indentHelper.ROWS_INDENT_RETCODE.OK, rows_indent
end

local function get_rows_indent_by_treesitter(range)
local begRow = range.start + 1
local endRow = range.finish + 1

local rows_indent = {}
local ts_indent_status, ts_indent = pcall(require, "nvim-treesitter.indent")
if not ts_indent_status then
return indentHelper.ROWS_INDENT_RETCODE.NO_TS, {}
end

for i = endRow, begRow, -1 do
rows_indent[i] = vim.api.nvim_buf_call(range.bufnr, function()
local indent = ts_indent.get_indent(i)
local bufnr = range.bufnr
for i = range.start, range.finish, -1 do
rows_indent[i] = vim.api.nvim_buf_call(bufnr, function()
local indent = ts_indent.get_indent(i + 1)
if indent == -1 then
indent = fn.indent(i)
if indent == 0 and #fn.getline(i) == 0 then
indent = get_virt_indent(rows_indent, i) or -1
indent = fn.indent(i + 1)
if indent == 0 and cFunc.get_line_len(bufnr, i) == 0 then
indent = get_virt_indent(bufnr, i)
end
end
---@diagnostic disable-next-line: redundant-return-value
Expand Down
17 changes: 17 additions & 0 deletions test/features/cFunc_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
local assert = require("luassert")
local cFunc = require("hlchunk.utils.cFunc")

describe("cFunc", function()
it("skipwhite", function()
local str

str = " abc"
assert.equals(cFunc.skipwhite(str), "a")
str = " "
assert.equals(cFunc.skipwhite(str), "")
str = ""
assert.equals(cFunc.skipwhite(str), "")
str = "abc"
assert.equals(cFunc.skipwhite(str), "a")
end)
end)

0 comments on commit c579e2a

Please sign in to comment.