micro/runtime/plugins/comment/comment.lua
Dmytro Maluka 85afb6eb87 Use StoreVisualX() all over the code
Since we already have the StoreVisualX() helper, use it all over the
place instead of setting LastVisualX directly.

This will allow us to add more logic to StoreVisualX() add let this
extra logic apply everywhere automatically.
2024-10-13 17:46:34 +02:00

213 lines
6.4 KiB
Lua

VERSION = "1.0.0"
local util = import("micro/util")
local config = import("micro/config")
local buffer = import("micro/buffer")
local ft = {}
ft["apacheconf"] = "# %s"
ft["batch"] = ":: %s"
ft["c"] = "// %s"
ft["c++"] = "// %s"
ft["cmake"] = "# %s"
ft["conf"] = "# %s"
ft["crystal"] = "# %s"
ft["css"] = "/* %s */"
ft["d"] = "// %s"
ft["dart"] = "// %s"
ft["dockerfile"] = "# %s"
ft["elm"] = "-- %s"
ft["fish"] = "# %s"
ft["gdscript"] = "# %s"
ft["glsl"] = "// %s"
ft["go"] = "// %s"
ft["haskell"] = "-- %s"
ft["html"] = "<!-- %s -->"
ft["ini"] = "; %s"
ft["java"] = "// %s"
ft["javascript"] = "// %s"
ft["jinja2"] = "{# %s #}"
ft["json"] = "// %s"
ft["julia"] = "# %s"
ft["kotlin"] = "// %s"
ft["lua"] = "-- %s"
ft["markdown"] = "<!-- %s -->"
ft["nginx"] = "# %s"
ft["nim"] = "# %s"
ft["objc"] = "// %s"
ft["ocaml"] = "(* %s *)"
ft["pascal"] = "{ %s }"
ft["perl"] = "# %s"
ft["php"] = "// %s"
ft["pony"] = "// %s"
ft["powershell"] = "# %s"
ft["proto"] = "// %s"
ft["python"] = "# %s"
ft["python3"] = "# %s"
ft["ruby"] = "# %s"
ft["rust"] = "// %s"
ft["scala"] = "// %s"
ft["shell"] = "# %s"
ft["sql"] = "-- %s"
ft["swift"] = "// %s"
ft["tex"] = "% %s"
ft["toml"] = "# %s"
ft["twig"] = "{# %s #}"
ft["v"] = "// %s"
ft["xml"] = "<!-- %s -->"
ft["yaml"] = "# %s"
ft["zig"] = "// %s"
ft["zscript"] = "// %s"
ft["zsh"] = "# %s"
local last_ft
function updateCommentType(buf)
if buf.Settings["commenttype"] == nil or (last_ft ~= buf.Settings["filetype"] and last_ft ~= nil) then
if ft[buf.Settings["filetype"]] ~= nil then
buf:SetOptionNative("commenttype", ft[buf.Settings["filetype"]])
else
buf:SetOptionNative("commenttype", "# %s")
end
last_ft = buf.Settings["filetype"]
end
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
end
function commentLine(bp, lineN, indentLen)
updateCommentType(bp.Buf)
local line = bp.Buf:Line(lineN)
local commentType = bp.Buf.Settings["commenttype"]
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["commenttype"]
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)
local allComments = true
for line = startLine, endLine do
if not isCommented(bp, line, commentRegex) then
allComments = false
break
end
end
-- 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
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
if allComments then
uncommentLine(bp, line, commentRegex)
else
commentLine(bp, line, indentMin)
end
end
end
function comment(bp, args)
updateCommentType(bp.Buf)
local commentType = bp.Buf.Settings["commenttype"]
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
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
end
toggleCommentSelection(bp, bp.Cursor.CurSelection[1].Y, endLine, commentRegex)
end
else
toggleCommentLine(bp, bp.Cursor.Y, commentRegex)
end
end
function string.starts(String,Start)
return string.sub(String,1,string.len(Start))==Start
end
function init()
config.MakeCommand("comment", comment, config.NoComplete)
config.TryBindKey("Alt-/", "lua:comment.comment", false)
config.TryBindKey("CtrlUnderscore", "lua:comment.comment", false)
config.AddRuntimeFile("comment", config.RTHelp, "help/comment.md")
end