diff options
Diffstat (limited to 'src/extensions/string.lua')
| -rw-r--r-- | src/extensions/string.lua | 86 |
1 files changed, 85 insertions, 1 deletions
diff --git a/src/extensions/string.lua b/src/extensions/string.lua index 247d31a..5cbb4ec 100644 --- a/src/extensions/string.lua +++ b/src/extensions/string.lua @@ -1,3 +1,7 @@ +function string:starts_with(s) + return self:sub(1, #s) == s +end + function string:flag_name() if self:sub(1, 2) ~= "--" then return nil @@ -16,11 +20,91 @@ function string:split(sep) return splits end +-- NOTE: This function is for certain not complete and not very efficient +-- but for now it works good enough to proceed with development. +-- We might need to rewrite this function in the future if it is a bottleneck. +function string:split_into_template_blocks() + local splits = { { kind = 'text', content = '' } } + local stack = {} + local current = self + + local matching = { + ["{"] = "}", + ["["] = "]", + ["("] = ")", + } + + while #current > 0 do + local add = true + if #stack == 0 and current:starts_with("@{") then + current = current:sub(2, #current) + stack[#stack + 1] = "}" + splits[#splits + 1] = { kind = 'code', content = '' } + add = false + elseif #stack > 0 and ( + current:starts_with('"') or + current:starts_with("'") or + current:starts_with('[[') + ) then + local string_end = current:starts_with('"') and '"' or (current:starts_with("'") and "'" or ']]') + splits[#splits].content = splits[#splits].content .. current:sub(1, 1) + current = current:sub(2) + + while #current > 0 do + if current:starts_with('\\') then + splits[#splits].content = splits[#splits].content .. current:sub(1, 1) + current = current:sub(2) + elseif current:starts_with(string_end) then + break + end + splits[#splits].content = splits[#splits].content .. current:sub(1, 1) + current = current:sub(2) + end + + elseif #stack > 0 and current:starts_with("--") then + local comment_end = current:starts_with('--[[') and ']]' or '\n' + splits[#splits].content = splits[#splits].content .. current:sub(1, (current:find(comment_end) + #comment_end) or #current + 1) + current = current:sub((current:find(comment_end) + #comment_end) or #current + 1) + add = false + elseif #stack > 0 then + local start = current:sub(1, 1) + local closing = matching[start] + + if start == stack[#stack] then + stack[#stack] = nil + + if #stack == 0 then + current = current:sub(2, #current) + splits[#splits + 1] = { kind = 'text', content = '' } + end + elseif closing then + stack[#stack + 1] = closing + end + end + + if add then + splits[#splits].content = splits[#splits].content .. current:sub(1, 1) + end + current = current:sub(2) + end + + return splits +end + return { tests = { function() local path = 'some/path/here' - assert.equals({ 'some', 'path', 'here' }, path.split("/")) + assert.equals({ 'some', 'path', 'here' }, path:split("/")) end, + function() + local f = Path:new("example/test.py"):open("r") + local raw = f:read("*all") + f:close() + + for _, value in ipairs(raw:split_into_template_blocks()) do + print(require('inspect')(value)) + end + end } } |