Skip to content
Open
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
117 changes: 56 additions & 61 deletions runtime/plugins/comment/comment.lua
Original file line number Diff line number Diff line change
Expand Up @@ -84,77 +84,33 @@ end
function isCommented(bp, lineN, commentRegex)
local line = bp.Buf:Line(lineN)
local regex = commentRegex:gsub("%s+", "%s*")
if string.match(line, regex) then
return true
end
return false
return string.match(line, regex)
end

function commentLine(bp, lineN, indentLen)
updateCommentType(bp.Buf)

local line = bp.Buf:Line(lineN)
local commentType = bp.Buf.Settings["comment.type"]
Copy link
Collaborator

@JoeKar JoeKar Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of merging the master branch into the PR branch it is more preferred to rebase the PR branch against the actual upstream master.
This allows us to extract a clean set of patches, which can be applied easily.

This also helps to cleanup the PR's history.

local sel = -bp.Cursor.CurSelection
local curpos = -bp.Cursor.Loc
local index = string.find(commentType, "%%s") - 1
local indent = string.sub(line, 1, indentLen)
local trimmedLine = string.sub(line, indentLen + 1)
trimmedLine = trimmedLine:gsub("%%", "%%%%")
local commentedLine = commentType:gsub("%%s", trimmedLine)
bp.Buf:Replace(buffer.Loc(0, lineN), buffer.Loc(#line, lineN), indent .. commentedLine)
if bp.Cursor:HasSelection() then
bp.Cursor.CurSelection[1].Y = sel[1].Y
bp.Cursor.CurSelection[2].Y = sel[2].Y
bp.Cursor.CurSelection[1].X = sel[1].X
bp.Cursor.CurSelection[2].X = sel[2].X
else
bp.Cursor.X = curpos.X + index
bp.Cursor.Y = curpos.Y
end
bp.Cursor:Relocate()
bp.Cursor:StoreVisualX()
end

function uncommentLine(bp, lineN, commentRegex)
updateCommentType(bp.Buf)

local line = bp.Buf:Line(lineN)
local commentType = bp.Buf.Settings["comment.type"]
local sel = -bp.Cursor.CurSelection
local curpos = -bp.Cursor.Loc
local index = string.find(commentType, "%%s") - 1
if not string.match(line, commentRegex) then
commentRegex = commentRegex:gsub("%s+", "%s*")
end
if string.match(line, commentRegex) then
uncommentedLine = string.match(line, commentRegex)
bp.Buf:Replace(buffer.Loc(0, lineN), buffer.Loc(#line, lineN), util.GetLeadingWhitespace(line) .. uncommentedLine)
if bp.Cursor:HasSelection() then
bp.Cursor.CurSelection[1].Y = sel[1].Y
bp.Cursor.CurSelection[2].Y = sel[2].Y
bp.Cursor.CurSelection[1].X = sel[1].X
bp.Cursor.CurSelection[2].X = sel[2].X
else
bp.Cursor.X = curpos.X - index
bp.Cursor.Y = curpos.Y
end
end
bp.Cursor:Relocate()
bp.Cursor:StoreVisualX()
end

function toggleCommentLine(bp, lineN, commentRegex)
if isCommented(bp, lineN, commentRegex) then
uncommentLine(bp, lineN, commentRegex)
else
commentLine(bp, lineN, #util.GetLeadingWhitespace(bp.Buf:Line(lineN)))
end
end

function toggleCommentSelection(bp, startLine, endLine, commentRegex)
function toggleCommentSelection(bp, lines, commentRegex)
local allComments = true
for line = startLine, endLine do
for line,_ in pairs(lines) do
if not isCommented(bp, line, commentRegex) then
allComments = false
break
Expand All @@ -164,21 +120,22 @@ function toggleCommentSelection(bp, startLine, endLine, commentRegex)
-- NOTE: we assume that the indentation is either tabs only or spaces only
local indentMin = -1
if not allComments then
for line = startLine, endLine do
for line,_ in pairs(lines) do
local indentLen = #util.GetLeadingWhitespace(bp.Buf:Line(line))
if indentMin == -1 or indentLen < indentMin then
indentMin = indentLen
end
end
end

for line = startLine, endLine do
for line,_ in pairs(lines) do
if allComments then
uncommentLine(bp, line, commentRegex)
else
commentLine(bp, line, indentMin)
end
end
return not allComments
end

function comment(bp, args)
Expand All @@ -187,22 +144,60 @@ function comment(bp, args)
local commentType = bp.Buf.Settings["comment.type"]
local commentRegex = "^%s*" .. commentType:gsub("%%","%%%%"):gsub("%$","%$"):gsub("%)","%)"):gsub("%(","%("):gsub("%?","%?"):gsub("%*", "%*"):gsub("%-", "%-"):gsub("%.", "%."):gsub("%+", "%+"):gsub("%]", "%]"):gsub("%[", "%["):gsub("%%%%s", "(.*)")

if bp.Cursor:HasSelection() then
if bp.Cursor.CurSelection[1]:GreaterThan(-bp.Cursor.CurSelection[2]) then
local endLine = bp.Cursor.CurSelection[1].Y
if bp.Cursor.CurSelection[1].X == 0 then
endLine = endLine - 1
local lines = {}
local curData = {}
-- gather cursor data and lines to (un)comment
for i = 1,#bp.Buf:getCursors() do
local cursor = bp.Buf:getCursor(i-1)
local hasSelection = cursor:HasSelection()
local excludedEnd = nil
if hasSelection then
local startSel = 1
local endSel = 2
if cursor.CurSelection[startSel]:GreaterThan(-cursor.CurSelection[endSel]) then
startSel = 2
endSel = 1
end
local fromLineNo = cursor.CurSelection[startSel].Y
local toLineNo = cursor.CurSelection[endSel].Y

-- don't indent the line after when selection ends in a newline
if cursor.CurSelection[endSel].X == 0 then
excludedEnd = endSel
toLineNo = toLineNo - 1
end

for lineN = fromLineNo,toLineNo do
lines[lineN] = true
end
toggleCommentSelection(bp, bp.Cursor.CurSelection[2].Y, endLine, commentRegex)
else
local endLine = bp.Cursor.CurSelection[2].Y
if bp.Cursor.CurSelection[2].X == 0 then
endLine = endLine - 1
lines[cursor.Y] = true
end
table.insert(curData, {
sel = -cursor.CurSelection,
curpos = -cursor.Loc,
cursor = cursor,
hasSelection = hasSelection,
excludedEnd = excludedEnd,
})
end
-- (un)comment selected lines
local commented = toggleCommentSelection(bp, lines, commentRegex)
-- restore cursors
local displacement = (string.find(commentType, "%%s") - 1) * (commented and 1 or -1)
for i=1,#curData do
local cursor = curData[i].cursor
if curData[i].hasSelection then
for j=1,2 do
cursor.CurSelection[j].Y = curData[i].sel[j].Y
cursor.CurSelection[j].X = curData[i].sel[j].X + (j == curData[i].excludedEnd and 0 or displacement)
end
toggleCommentSelection(bp, bp.Cursor.CurSelection[1].Y, endLine, commentRegex)
else
cursor.Y = curData[i].curpos.Y
cursor.X = curData[i].curpos.X + displacement
end
else
toggleCommentLine(bp, bp.Cursor.Y, commentRegex)
cursor:Relocate()
cursor:StoreVisualX()
end
end

Expand Down
4 changes: 2 additions & 2 deletions runtime/plugins/comment/help/comment.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ the binding:
> comment
```

If you have a selection, the plugin will comment all the lines
selected.
If you have a selection of text, or multiple cursors, the plugin
will comment all the selected lines.

The comment type will be auto detected based on the filetype,
but it is only available for certain filetypes:
Expand Down