Skip to content

feat: Auto calculate commentstring #62

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

Merged
merged 13 commits into from
Nov 20, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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
25 changes: 14 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,19 @@ local ft = require('Comment.ft')
-- set both line and block commentstring
ft.set('javascript', {'//%s', '/*%s*/'})

-- set line, block and override commentstring
-- for particular treesitter nodes
ft.set("javascript", {
"// %s",
"/*%s*/",
jsx_fragment = { "{/* %s */}" },
jsx_element = { "{/* %s */}" },
jsx_attribute = { "// %s" },
jsx_expression = { "// %s", "/*%s*/" },
call_expression = { "// %s", "/*%s*/" },
statement_block = { "// %s" },
})

-- Just set only line comment
ft.set('yaml', '#%s')

Expand Down Expand Up @@ -412,6 +425,7 @@ The following object is provided as an argument to `pre_hook` and `post_hook` fu
```lua
---Comment context
---@class Ctx
---@field lang string: The name of the language where the cursor is
---@field ctype CType
---@field cmode CMode
---@field cmotion CMotion
Expand Down Expand Up @@ -442,17 +456,6 @@ There are multiple ways to contribute reporting/fixing bugs, feature requests. Y
- Live upto the expectation of `tcomment`
- Basic INSERT mode mappings
- Doc comment i.e `/**%s*/` (js), `///%s` (rust)

- Inbuilt context commentstring using treesitter

```lua
{
pre_hook = function()
return require('Comment.ts').commentstring()
end
}
```

- Header comment

```lua
Expand Down
22 changes: 7 additions & 15 deletions lua/Comment/comment.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
local Ctx = require('Comment.ctx')
local U = require('Comment.utils')

local A = vim.api
Expand All @@ -7,24 +8,17 @@ local C = {
config = nil,
}

---Comment context
---@class Ctx
---@field ctype CType
---@field cmode CMode
---@field cmotion CMotion

---Comments the current line
function C.comment()
local line = A.nvim_get_current_line()

local pattern = U.get_pattern(C.config.ignore)
if not U.ignore(line, pattern) then
---@type Ctx
local ctx = {
local ctx = Ctx:new({
cmode = U.cmode.comment,
cmotion = U.cmotion.line,
ctype = U.ctype.line,
}
})

local padding, _ = U.get_padding(C.config.padding)
local lcs, rcs = U.parse_cstr(C.config, ctx)
Expand All @@ -39,12 +33,11 @@ function C.uncomment()

local pattern = U.get_pattern(C.config.ignore)
if not U.ignore(line, pattern) then
---@type Ctx
local ctx = {
local ctx = Ctx:new({
cmode = U.cmode.uncomment,
cmotion = U.cmotion.line,
ctype = U.ctype.line,
}
})

local lcs, rcs = U.parse_cstr(C.config, ctx)
local _, pp = U.get_padding(C.config.padding)
Expand All @@ -64,12 +57,11 @@ function C.toggle()

local pattern = U.get_pattern(C.config.ignore)
if not U.ignore(line, pattern) then
---@type Ctx
local ctx = {
local ctx = Ctx:new({
cmode = U.cmode.toggle,
cmotion = U.cmotion.line,
ctype = U.ctype.line,
}
})

local lcs, rcs = U.parse_cstr(C.config, ctx)
local lcs_esc, rcs_esc = U.escape(lcs), U.escape(rcs)
Expand Down
26 changes: 26 additions & 0 deletions lua/Comment/ctx.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
local ts = require('Comment.ts')

--- Comment context
---@class Ctx
---@field lang string: The name of the language where the cursor is
---@field node table: The containing node of where the cursor is
---@field ctype CType
---@field cmode CMode
---@field cmotion CMotion
local Ctx = {}

--- Create a new Ctx
---@return Ctx
function Ctx:new(opts)
assert(opts.cmode, 'Must have a cmode')
assert(opts.cmotion, 'Must have a cmotion')
assert(opts.ctype, 'Must have a ctype')

opts.lang = ts.get_lang(opts)
opts.node = ts.get_node(opts)
opts.node_type = opts.node and opts.node:type()

return setmetatable(opts, self)
end

return Ctx
11 changes: 5 additions & 6 deletions lua/Comment/extra.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local U = require('Comment.utils')
local Ctx = require('Comment.ctx')
local A = vim.api

local E = {}
Expand All @@ -7,12 +8,11 @@ local E = {}
---@param ctype CType
---@param cfg Config
local function ins_on_line(count, ctype, cfg)
---@type Ctx
local ctx = {
local ctx = Ctx:new({
cmode = U.cmode.comment,
cmotion = U.cmotion.line,
ctype = ctype,
}
})

local pos = A.nvim_win_get_cursor(0)
local srow, scol = pos[1] + count, pos[2]
Expand Down Expand Up @@ -50,12 +50,11 @@ end
---@param ctype CType
---@param cfg Config
function E.norm_A(ctype, cfg)
---@type Ctx
local ctx = {
local ctx = Ctx:new({
cmode = U.cmode.comment,
cmotion = U.cmotion.line,
ctype = ctype,
}
})

local pos = A.nvim_win_get_cursor(0)
local line = A.nvim_get_current_line()
Expand Down
43 changes: 39 additions & 4 deletions lua/Comment/ft.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ local M = {
latex = '%%s',
}

local javascript_special_nodes = {
comment = { M.cxx_l, M.cxx_b },
jsx_attribute = { M.cxx_l, M.cxx_b },
jsx_element = { '{/* %s */}', '{/* %s */}' },
jsx_fragment = { '{/* %s */}', '{/* %s */}' },
jsx_opening_element = { M.cxx_l, M.cxx_b },
call_expression = { M.cxx_l, M.cxx_b },
statement_block = { M.cxx_l, M.cxx_b },
}

---Lang table that contains commentstring (linewise/blockwise) for mutliple filetypes
---@type table { filetype = { linewise, blockwise } }
local L = {
Expand All @@ -28,8 +38,8 @@ local L = {
html = { M.html_b, M.html_b },
idris = { M.dash, M.haskell_b },
java = { M.cxx_l, M.cxx_b },
javascript = { M.cxx_l, M.cxx_b },
javascriptreact = { M.cxx_l, M.cxx_b },
javascript = vim.tbl_deep_extend('keep', { M.cxx_l, M.cxx_b }, javascript_special_nodes),
javascriptreact = vim.tbl_deep_extend('keep', { M.cxx_l, M.cxx_b }, javascript_special_nodes),
julia = { M.hash, '#=%s=#' },
lidris = { M.dash, M.haskell_b },
lua = { M.dash, '--[[%s--]]' },
Expand All @@ -47,8 +57,8 @@ local L = {
terraform = { M.hash, M.cxx_b },
tex = { M.latex },
toml = { M.hash },
typescript = { M.cxx_l, M.cxx_b },
typescriptreact = { M.cxx_l, M.cxx_b },
typescript = vim.tbl_deep_extend('keep', { M.cxx_l, M.cxx_b }, javascript_special_nodes),
typescriptreact = vim.tbl_deep_extend('keep', { M.cxx_l, M.cxx_b }, javascript_special_nodes),
vim = { '"%s' },
xml = { M.html_b, M.html_b },
yaml = { M.hash },
Expand All @@ -60,10 +70,35 @@ return setmetatable({}, {
set = function(k, v)
L[k] = type(v) == 'string' and { v } or v
end,

get = function(lang, ctype)
local l = L[lang]
return l and l[ctype]
end,

lang = function(lang)
return L[lang]
end,

calculate = function(ctx)
P(ctx)
local lang = L[ctx.lang]
if not lang then
return
end

if not ctx.node then
return lang[ctx.ctype] or lang[1]
end

local config = lang[ctx.node:type()]
if not config then
return lang[ctx.ctype] or lang[1]
end

-- TODO: Dunno if this is any good or not.
return config[ctx.ctype] or config[1]
end,
},
__newindex = function(this, k, v)
this.set(k, v)
Expand Down
11 changes: 5 additions & 6 deletions lua/Comment/opfunc.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
local Ctx = require('Comment.ctx')
local U = require('Comment.utils')
local A = vim.api

Expand Down Expand Up @@ -48,12 +49,11 @@ function O.opfunc(cfg, vmode, cmode, ctype, cmotion)
local partial_block = cmotion == U.cmotion.char or cmotion == U.cmotion.v
local block_x = partial_block and same_line

---@type Ctx
local ctx = {
local ctx = Ctx:new({
cmode = cmode,
cmotion = cmotion,
ctype = block_x and U.ctype.block or ctype,
}
})

local lcs, rcs = U.parse_cstr(cfg, ctx)

Expand Down Expand Up @@ -252,12 +252,11 @@ end
---Example: `10gl` will comment 10 lines
---@param cfg Config
function O.count(cfg)
---@type Ctx
local ctx = {
local ctx = Ctx:new({
cmode = U.cmode.toggle,
cmotion = U.cmotion.line,
ctype = U.ctype.line,
}
})
local lcs, rcs = U.parse_cstr(cfg, ctx)
local srow, erow, lines = U.get_count_lines(vim.v.count)
ctx.cmode = O.linewise({
Expand Down
109 changes: 109 additions & 0 deletions lua/Comment/ts.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
local ft = require('Comment.ft')
local U = require('Comment.utils')

local ts = {}

local get_cursor_line_non_whitespace_col_location = function()
local cursor = vim.api.nvim_win_get_cursor(0)
local first_non_whitespace_col = vim.fn.match(vim.fn.getline('.'), '\\S')

return {
cursor[1] - 1,
first_non_whitespace_col,
}
end

--- Get the tree associated with the current comment
---@param ctx Ctx
local get_current_tree = function(ctx, bufnr, range)
if bufnr and not range then
error('If you pass bufnr, you must pass a range as well')
end

bufnr = bufnr or vim.api.nvim_get_current_buf()
local ok, langtree = pcall(vim.treesitter.get_parser, bufnr)

if not ok then
return nil
end

if not range then
local cursor
if ctx.cmotion == U.cmotion.line then
cursor = get_cursor_line_non_whitespace_col_location()
elseif ctx.cmotion == U.cmotion.V then
local region = { U.get_region('V') }
cursor = { region[1] - 1, region[2] }
elseif ctx.cmotion == U.cmotion.v then
local region = { U.get_region('v') }
cursor = { region[1] - 1, region[2] }
else
-- ctx.cmotion == U.cmotion.char
cursor = vim.api.nvim_win_get_cursor(0)
end

range = {
cursor[1] - 1,
cursor[2],
cursor[1] - 1,
cursor[2],
}
end

return langtree:language_for_range(range), range
end

--- Get the current language for bufnr and range
---@param ctx Ctx: The current content
---@param bufnr number: The bufnr
---@param range table: See ranges for treesitter
function ts.get_lang(ctx, bufnr, range)
local current_tree = get_current_tree(ctx, bufnr, range)
if not current_tree then
return
end

return current_tree:lang()
end

--- Get corresponding node to the context
---@param ctx Ctx: The current content
---@param bufnr number: The buffer you are interested in. Generally nil
---@param in_range table: The range you are interested in. Generally nil
function ts.get_node(ctx, bufnr, in_range)
local current_tree, range = get_current_tree(ctx, bufnr, in_range)
if not current_tree then
return
end

local lang = current_tree:lang()

local config = ft.lang(lang)
if not config then
return
end

-- Short circuit if this ft doesn't have magical embedded languages
-- inside of itself that randomly change just based on where you are
-- in a syntax tree, instead of like, having the same rules everywhere.
if vim.tbl_islist(config) then
return nil
end

local root = current_tree:trees()[1]:root()
local contained = root:named_descendant_for_range(unpack(range))

local original = contained
while contained and contained:type() and not config[contained:type()] do
contained = contained:parent()
end

-- Hmmm, might want this back, not sure yet.
-- if not contained then
-- return original
-- end

return contained
end

return ts
Loading