summaryrefslogtreecommitdiff
path: root/.config/micro/plug/snippets/snippets.lua
diff options
context:
space:
mode:
Diffstat (limited to '.config/micro/plug/snippets/snippets.lua')
-rw-r--r--.config/micro/plug/snippets/snippets.lua586
1 files changed, 0 insertions, 586 deletions
diff --git a/.config/micro/plug/snippets/snippets.lua b/.config/micro/plug/snippets/snippets.lua
deleted file mode 100644
index d5d71b3..0000000
--- a/.config/micro/plug/snippets/snippets.lua
+++ /dev/null
@@ -1,586 +0,0 @@
-VERSION = "0.2.0"
-
-local micro = import("micro")
-local buffer = import("micro/buffer")
-local config = import("micro/config")
-local util = import("micro/util")
-
-local debugflag = true
-local curFileType = ""
-local snippets = {}
-local currentSnippet = nil
-local RTSnippets = config.NewRTFiletype()
-
-local Location = {}
-Location.__index = Location
-
-local Snippet = {}
-Snippet.__index = Snippet
-
--- Snippets
--- --> Snippet
--- --> Location
-
-function Location.new(idx, ph, snippet)
- debug1("Location.new(idx, ph, snip) idx = " , idx)
- --debugt("Location.new(idx, ph, snip) ph = ", ph)
- --debugt("Location.new(idx, ph, snippet) snippet = ", snippet)
-
- local self = setmetatable({}, Location)
- self.idx = idx
- self.ph = ph
- self.snippet = snippet
- return self
-end
-
--- offset of the location relative to the snippet start
-function Location.offset(self)
- debug("Location.offset(self)")
- local add = 0
- for i = 1, #self.snippet.locations do
- local loc = self.snippet.locations[i]
- debug1("loc = ",loc)
- if loc == self then
- break
- end
-
- local val = loc.ph.value
- micro.Log("VAL", val)
- if val then
- add = add + val:len()
- end
- end
- return self.idx+add
-end
-
-function Location.startPos(self)
- --debugt("Location.startPos(self) = ",self)
- local loc = self.snippet.startPos
- return loc:Move(self:offset(), self.snippet.view.buf)
-end
-
--- returns the length of the location (but at least 1)
-function Location.len(self)
- debug("Location.len(self)")
- local len = 0
- if self.ph.value then
- len = self.ph.value:len()
- end
- if len <= 0 then
- len = 1
- end
- return len
-end
-
-function Location.endPos(self)
- debug("Location.endPos(self)")
- local start = self:startPos()
- micro.Log("ENDPOS", self.ph.value)
- return start:Move(self:len(), self.snippet.view.buf)
-end
-
--- check if the given loc is within the location
-function Location.isWithin(self, loc)
- debug("Location.isWithin(self, loc)")
- return loc:GreaterEqual(self:startPos()) and loc:LessEqual(self:endPos())
-end
-
-function Location.focus(self)
- debug("Location.focus(self)")
- local view = self.snippet.view
- local startP = self:startPos():Move(-1, view.Buf)
- local endP = self:endPos():Move(-1, view.Buf)
- micro.Log(startP, endP)
-
- if view.Cursor:LessThan(startP) then
- while view.Cursor:LessThan(startP) do
- view.Cursor:Right()
- end
- elseif view.Cursor:GreaterEqual(endP) then
- while view.Cursor:GreaterEqual(endP) do
- view.Cursor:Left()
- end
- end
-
- if self.ph.value:len() > 0 then
- view.Cursor:SetSelectionStart(startP)
- view.Cursor:SetSelectionEnd(endP)
- else
- view.Cursor:ResetSelection()
- end
-end
-
-function Location.handleInput(self, ev)
- debug("Location.handleInput(self, ev)")
- if ev.EventType == 1 then
- -- TextInput
- if util.String(ev.Deltas[1].Text) == "\n" then
- Accept()
- return false
- else
- local offset = 1
- local sp = self:startPos()
- while sp:LessEqual(-ev.Deltas[1].Start) do
- sp = sp:Move(1, self.snippet.view.Buf)
- offset = offset + 1
- end
-
- self.snippet:remove()
- local v = self.ph.value
- if v == nil then
- v = ""
- end
-
- self.ph.value = v:sub(0, offset-1) .. util.String(ev.Deltas[1].Text) .. v:sub(offset)
- self.snippet:insert()
- return true
- end
- elseif ev.EventType == -1 then
- -- TextRemove
- local offset = 1
- local sp = self:startPos()
- while sp:LessEqual(-ev.Deltas[1].Start) do
- sp = sp:Move(1, self.snippet.view.Buf)
- offset = offset + 1
- end
-
- if ev.Deltas[1].Start.Y ~= ev.Deltas[1].End.Y then
- return false
- end
-
- self.snippet:remove()
-
- local v = self.ph.value
- if v == nil then
- v = ""
- end
-
- local len = ev.Deltas[1].End.X - ev.Deltas[1].Start.X
-
- self.ph.value = v:sub(0, offset-1) .. v:sub(offset+len)
- self.snippet:insert()
- return true
- end
-
- return false
-end
-
--- new snippet
-function Snippet.new()
- debug("Snippet.new()")
- local self = setmetatable({}, Snippet)
- self.code = ""
- return self
-end
-
--- add line of code to snippet
-function Snippet.AddCodeLine(self, line)
- --debugt("Snippet.AddCodeLine(self,line) self = " , self)
- debug1("Snippet.AddCodeLine(self, line) line = " , line)
- if self.code ~= "" then
- self.code = self.code .. "\n"
- end
- self.code = self.code .. line
-end
-
-function Snippet.Prepare(self)
- debug("Snippet.Prepare(self)")
- if not self.placeholders then
- self.placeholders = {}
- self.locations = {}
- local count = 0
- local pattern = "${(%d+):?([^}]*)}"
- while true do
- local num, value = self.code:match(pattern)
- if not num then
- break
- end
- count = count+1
- num = tonumber(num)
- local idx = self.code:find(pattern)
- self.code = self.code:gsub(pattern, "", 1)
- micro.Log("IDX", idx, self.code)
-
- local placeHolders = self.placeholders[num]
- if not placeHolders then
- placeHolders = {num = num}
- self.placeholders[#self.placeholders+1] = placeHolders
- end
- self.locations[#self.locations+1] = Location.new(idx, placeHolders, self)
- debug1("location total = ",#self.locations)
- if value then
- placeHolders.value = value
- end
- end
- end
-end
-
-function Snippet.clone(self)
- debug("Snippet.clone(self)")
- local result = Snippet.new()
- result:AddCodeLine(self.code)
- result:Prepare()
- return result
-end
-
-function Snippet.str(self)
- debug("Snippet.str(self)")
- local res = self.code
- for i = #self.locations, 1, -1 do
- local loc = self.locations[i]
- res = res:sub(0, loc.idx-1) .. loc.ph.value .. res:sub(loc.idx)
- end
- return res
-end
-
-function Snippet.findLocation(self, loc)
- debug1("Snippet.findLocation(self, loc) loc = ",loc)
- for i = 1, #self.locations do
- if self.locations[i]:isWithin(loc) then
- return self.locations[i]
- end
- end
- return nil
-end
-
-function Snippet.remove(self)
- debug("Snippet.remove(self)")
- local endPos = self.startPos:Move(self:str():len(), self.view.Buf)
- self.modText = true
- self.view.Cursor:SetSelectionStart(self.startPos)
- self.view.Cursor:SetSelectionEnd(endPos)
- self.view.Cursor:DeleteSelection()
- self.view.Cursor:ResetSelection()
- self.modText = false
-end
-
-function Snippet.insert(self)
- debug("Snippet.insert(self)")
- self.modText = true
- self.view.Buf:insert(self.startPos, self:str())
- self.modText = false
-end
-
-function Snippet.focusNext(self)
- debug("Snippet.focusNext(self)")
- if self.focused == nil then
- self.focused = 0
- else
- self.focused = (self.focused + 1) % #self.placeholders
- end
-
- local ph = self.placeholders[self.focused+1]
-
- for i = 1, #self.locations do
- if self.locations[i].ph == ph then
- self.locations[i]:focus()
- return
- end
- end
-end
-
-local function CursorWord(bp)
- debug1("CursorWord(bp)",bp)
- local c = bp.Cursor
- local x = c.X-1 -- start one rune before the cursor
- local result = ""
- while x >= 0 do
- local r = util.RuneStr(c:RuneUnder(x))
- if (r == " ") then -- IsWordChar(r) then
- break
- else
- result = r .. result
- end
- x = x-1
- end
-
- return result
-end
-
-local function ReadSnippets(filetype)
- debug1("ReadSnippets(filetype)",filetype)
- local snippets = {}
- local allSnippetFiles = config.ListRuntimeFiles(RTSnippets)
- local exists = false
-
- for i = 1, #allSnippetFiles do
- if allSnippetFiles[i] == filetype then
- exists = true
- break
- end
- end
-
- if not exists then
- micro.InfoBar():Error("No snippets file for \""..filetype.."\"")
- return snippets
- end
-
- local snippetFile = config.ReadRuntimeFile(RTSnippets, filetype)
-
- local curSnip = nil
- local lineNo = 0
- for line in string.gmatch(snippetFile, "(.-)\r?\n") do
- lineNo = lineNo + 1
- if string.match(line,"^#") then
- -- comment
- elseif line:match("^snippet") then
- curSnip = Snippet.new()
- for snipName in line:gmatch("%s(.+)") do -- %s space .+ one or more non-empty sequence
- snippets[snipName] = curSnip
- end
- else
- local codeLine = line:match("^\t(.*)$")
- if codeLine ~= nil then
- curSnip:AddCodeLine(codeLine)
- elseif line ~= "" then
- micro.InfoBar():Error("Invalid snippets file (Line #"..tostring(lineNo)..")")
- end
- end
- end
- debugt("ReadSnippets(filetype) snippets = ",snippets)
- return snippets
-end
-
--- Check filetype and load snippets
--- Return true is snippets loaded for filetype
--- Return false if no snippets loaded
-local function EnsureSnippets(bp)
- debug("EnsureSnippets()")
- local filetype = bp.Buf.Settings["filetype"]
- if curFileType ~= filetype then
- snippets = ReadSnippets(filetype)
- curFileType = filetype
- end
- if next(snippets) == nil then
- return false
- end
- return true
-end
-
-function onBeforeTextEvent(sb, ev)
- debug1("onBeforeTextEvent(ev)",ev)
- if currentSnippet ~= nil and currentSnippet.view.Buf.SharedBuffer == sb then
- if currentSnippet.modText then
- -- text event from the snippet. simply ignore it...
- return true
- end
-
- local locStart = nil
- local locEnd = nil
-
- if ev.Deltas[1].Start ~= nil and currentSnippet ~= nil then
- locStart = currentSnippet:findLocation(ev.Deltas[1].Start:Move(1, currentSnippet.view.Buf))
- locEnd = currentSnippet:findLocation(ev.Deltas[1].End)
- end
- if locStart ~= nil and ((locStart == locEnd) or (ev.Deltas[1].End.Y==0 and ev.Deltas[1].End.X==0)) then
- if locStart:handleInput(ev) then
- currentSnippet.view.Cursor:Goto(-ev.C)
- return false
- end
- end
- Accept()
- end
-
- return true
-
-end
-
--- Insert snippet if found.
--- Pass in the name of the snippet to be inserted by command mode
--- No name passed in then it will check the text left of the cursor
-function Insert(bp, args)
- local snippetName = nil
- if args ~= nil and #args > 0 then
- snippetName = args[1]
- end
- debug1("Insert(snippetName)",snippetName)
-
- local c = bp.Cursor
- local buf = bp.Buf
- local xy = buffer.Loc(c.X, c.Y)
- -- check if a snippet name was passed in
- local noArg = false
- if not snippetName then
- snippetName = CursorWord(bp)
- noArg = true
- end
- -- check filetype and load snippets
- local result = EnsureSnippets(bp)
- -- if no snippets return early
- if (result == false) then return end
-
- -- curSn cloned into currentSnippet if snippet found
- local curSn = snippets[snippetName]
- if curSn then
- currentSnippet = curSn:clone()
- currentSnippet.view = bp
- -- remove snippet keyword from micro buffer before inserting snippet
- if noArg then
- currentSnippet.startPos = xy:Move(-snippetName:len(), buf)
-
- currentSnippet.modText = true
-
- c:SetSelectionStart(currentSnippet.startPos)
- c:SetSelectionEnd(xy)
- c:DeleteSelection()
- c:ResetSelection()
-
- currentSnippet.modText = false
- else
- -- no need to remove snippet keyword from buffer as run from command mode
- currentSnippet.startPos = xy
- end
- -- insert snippet to micro buffer
- currentSnippet:insert()
- micro.InfoBar():Message("Snippet Inserted \""..snippetName.."\"")
-
- -- Placeholders
- if #currentSnippet.placeholders == 0 then
- local pos = currentSnippet.startPos:Move(currentSnippet:str():len(), bp.Buf)
- while bp.Cursor:LessThan(pos) do
- bp.Cursor:Right()
- end
- while bp.Cursor:GreaterThan(pos) do
- bp.Cursor:Left()
- end
- else
- currentSnippet:focusNext()
- end
- else
- -- Snippet not found
- micro.InfoBar():Message("Unknown snippet \""..snippetName.."\"")
- end
-end
-
-function Next()
- debug("Next()")
- if currentSnippet then
- currentSnippet:focusNext()
- end
-end
-
-function Accept()
- debug("Accept()")
- currentSnippet = nil
-end
-
-function Cancel()
- debug("Cancel()")
- if currentSnippet then
- currentSnippet:remove()
- Accept()
- end
-end
-
-
-local function StartsWith(String,Start)
- debug1("StartsWith(String,Start) String ",String)
- debug1("StartsWith(String,Start) start ",start)
- String = String:upper()
- Start = Start:upper()
- return string.sub(String,1,string.len(Start))==Start
-end
-
--- Used for auto complete in the command prompt
-function findSnippet(input)
- debug1("findSnippet(input)",input)
- local result = {}
- -- TODO: pass bp
- EnsureSnippets()
-
- for name,v in pairs(snippets) do
- if StartsWith(name, input) then
- table.insert(result, name)
- end
- end
- return result
-end
-
--- Debug functions below
--- debug1 is for logging functionName and 1 argument passed
-function debug1(functionName, argument)
- if debugflag == false then return end
- if argument == nil then
- micro.Log("snippets-plugin -> function " .. functionName .. " = nil")
- elseif argument == "" then
- micro.Log("snippets-plugin -> function " .. functionName .. " = empty string")
- else micro.Log("snippets-plugin -> function " .. functionName .. " = " .. tostring(argument))
- end
-end
-
--- debug is for logging functionName only
-function debug(functionName)
- if debugflag == false then return end
- micro.Log("snippets-plugin -> function " .. functionName)
-end
-
--- debug is for logging functionName and table
-function debugt(functionName,tablepassed)
- if debugflag == false then return end
- micro.Log("snippets-plugin -> function " .. functionName )
- tprint(tablepassed)
--- if (tablepassed == nil) then return end
--- for key,value in pairs(tablepassed) do
--- micro.Log("key - " .. tostring(key) .. "value = " .. tostring(value[1]) )
--- end
-end
-
--- dump table
-function dump(o)
- if type(o) == 'table' then
- local s = '{ '
- for k,v in pairs(o) do
- if type(k) ~= 'number' then k = '"'..k..'"' end
- s = s .. '['..k..'] = ' .. dump(v) .. ','
- end
- return s .. '} '
- else
- return tostring(o)
- end
- end
-
- function tprint (tbl, indent)
- if not indent then indent = 0 end
- for k, v in pairs(tbl) do
- formatting = string.rep(" ", indent) .. k .. ": "
- if type(v) == "table" then
- micro.Log(formatting .. "Table ->")
- tprint(v, indent+1)
- elseif type(v) == nil then
- micro.Log(formatting .. " nil")
- else
- micro.Log(formatting .. tostring(v))
- end
- end
- end
-
- function checkTableisEmpty(myTable)
- if next(myTable) == nil then
- -- myTable is empty
- end
-end
-
-function tablePrint(tbl)
- for index = 1, #tbl do
- micro.Log(tostring(index) .. " = " .. tostring(tbl[index]))
- end
-end
-
-function init()
- -- Insert a snippet
- config.MakeCommand("snippetinsert", Insert, config.NoComplete)
- -- Mark next placeholder
- config.MakeCommand("snippetnext", Next, config.NoComplete)
- -- Cancel current snippet (removes the text)
- config.MakeCommand("snippetcancel", Cancel, config.NoComplete)
- -- Acceptes snipped editing
- config.MakeCommand("snippetaccept", Accept, config.NoComplete)
-
- config.AddRuntimeFile("snippets", config.RTHelp, "help/snippets.md")
- config.AddRuntimeFilesFromDirectory("snippets", RTSnippets, "snippets", "*.snippets")
-
- config.TryBindKey("Alt-w", "lua:snippets.Next", false)
- config.TryBindKey("Alt-a", "lua:snippets.Accept", false)
- config.TryBindKey("Alt-s", "lua:snippets.Insert", false)
- config.TryBindKey("Alt-d", "lua:snippets.Cancel", false)
-end