diff --git a/README.md b/README.md index a3e8481..e3af2b6 100644 --- a/README.md +++ b/README.md @@ -31,12 +31,13 @@ For detailed optimization work, you can see my blog (written in Chinese): [https ## Brief introduction -This plugin now have four parts +This plugin now have five parts 1. chunk 1. indent 1. line_num 1. blank +1. scope One picture to understand what these mods do @@ -73,6 +74,20 @@ One picture to understand what these mods do image +### scope + +Highlight the current scope (function, class, or block) the cursor is in by setting a background highlight on all lines in that scope. Uses treesitter to find the enclosing scope node. + +To enable: +```lua +require('hlchunk').setup({ + scope = { + enable = true, + style = { { bg = "#3a3a5c" } }, + }, +}) +``` + ## Requirements neovim version `>= 0.10.0` @@ -119,6 +134,7 @@ The specific configuration methods for each mod can be found in their respective - [indent](./docs/en/indent.md) - [line_num](./docs/en/line_num.md) - [blank](./docs/en/blank.md) +- [scope](#scope) You can config the whole plugin by using setup function: diff --git a/lua/hlchunk/mods/scope/init.lua b/lua/hlchunk/mods/scope/init.lua new file mode 100644 index 0000000..4aabac1 --- /dev/null +++ b/lua/hlchunk/mods/scope/init.lua @@ -0,0 +1,85 @@ +local BaseMod = require("hlchunk.mods.base_mod") +local ScopeConf = require("hlchunk.mods.scope.scope_conf") +local chunkHelper = require("hlchunk.utils.chunkHelper") +local class = require("hlchunk.utils.class") + +local api = vim.api +local CHUNK_RANGE_RET = chunkHelper.CHUNK_RANGE_RET + +---@class HlChunk.ScopeMetaInfo : HlChunk.MetaInfo + +local constructor = function(self, conf, meta) + local default_meta = { + name = "scope", + augroup_name = "hlchunk_scope", + hl_base_name = "HLScope", + ns_id = api.nvim_create_namespace("scope"), + } + + BaseMod.init(self, conf, meta) + self.meta = vim.tbl_deep_extend("force", default_meta, meta or {}) + self.conf = ScopeConf(conf) +end + +---@class HlChunk.ScopeMod : HlChunk.BaseMod +---@field conf HlChunk.ScopeConf +---@field meta HlChunk.ScopeMetaInfo +---@field render fun(self: HlChunk.ScopeMod, range: HlChunk.Scope) +---@overload fun(conf?: HlChunk.UserScopeConf, meta?: HlChunk.MetaInfo): HlChunk.ScopeMod +local ScopeMod = class(BaseMod, constructor) + +function ScopeMod:render(range) + if not self:shouldRender(range.bufnr) then + return + end + + local hl_name = self.meta.hl_name_list[1] + if not hl_name then + return + end + + local bufnr = range.bufnr + local ns_id = self.meta.ns_id + local priority = self.conf.priority + + for i = range.start, range.finish do + api.nvim_buf_set_extmark(bufnr, ns_id, i, 0, { + end_row = i + 1, + end_col = 0, + hl_group = hl_name, + priority = priority, + }) + end +end + +function ScopeMod:createAutocmd() + BaseMod.createAutocmd(self) + + api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, { + group = self.meta.augroup_name, + callback = function(event) + local bufnr = event.buf + if not self:shouldRender(bufnr) then + return + end + local winnr = api.nvim_get_current_win() + local pos = api.nvim_win_get_cursor(winnr) + local retcode, cur_scope_range = chunkHelper.get_chunk_range({ + pos = { bufnr = bufnr, row = pos[1] - 1, col = pos[2] }, + use_treesitter = self.conf.use_treesitter, + }) + self:clear({ bufnr = bufnr, start = 0, finish = api.nvim_buf_line_count(bufnr) }) + if retcode ~= CHUNK_RANGE_RET.OK then + if retcode == CHUNK_RANGE_RET.NO_TS then + self:notify("[hlchunk.scope]: no parser for " .. vim.bo[bufnr].ft, nil, { once = true }) + elseif retcode == CHUNK_RANGE_RET.NO_CHUNK then + self:notify("[hlchunk.scope]: no scope node found at cursor", nil, { once = true }) + end + return + end + self:render(cur_scope_range) + end, + }) +end + +return ScopeMod diff --git a/lua/hlchunk/mods/scope/scope_conf.lua b/lua/hlchunk/mods/scope/scope_conf.lua new file mode 100644 index 0000000..2ffdc41 --- /dev/null +++ b/lua/hlchunk/mods/scope/scope_conf.lua @@ -0,0 +1,26 @@ +local class = require("hlchunk.utils.class") +local BaseConf = require("hlchunk.mods.base_mod.base_conf") + +---@class HlChunk.UserScopeConf : HlChunk.UserBaseConf +---@field use_treesitter? boolean + +---@class HlChunk.ScopeConf : HlChunk.BaseConf +---@field use_treesitter boolean +---@overload fun(conf?: table): HlChunk.ScopeConf +local ScopeConf = class(BaseConf, function(self, conf) + local default_conf = { + enable = false, + priority = 10, + style = { + { bg = "#3a3a5c" }, + }, + use_treesitter = true, + } + conf = vim.tbl_deep_extend("force", default_conf, conf or {}) --[[@as HlChunk.ScopeConf]] + BaseConf.init(self, conf) + + self.priority = conf.priority + self.use_treesitter = conf.use_treesitter +end) + +return ScopeConf