2022-09-04 10:25:18 +00:00
-- This file is part of Reno desktop.
--
-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
-- Various utilitiy parsers
local parsers = { }
local function split_strings ( text )
2023-07-03 16:53:52 +00:00
-- probably the cleanest function to split by strings i've written to date
2022-09-04 10:25:18 +00:00
local split = { }
while text : find ( " \" " ) do
local strstart = text : find ( " \" " )
while text : sub ( strstart - 1 , strstart - 1 ) == " \\ " do
strstart = text : find ( " \" " , strstart + 1 )
end
local strend = text : find ( " \" " , strstart + 1 )
while text : sub ( strend - 1 , strend - 1 ) == " \\ " do
strend = text : find ( " \" " , strend + 1 )
end
if not strend then
return nil , " String not closed at " .. strstart
end
local before_string = text : sub ( 1 , strstart - 1 )
local string = text : sub ( strstart , strend ) : gsub ( " \\ \" " , " \" " )
text = text : sub ( strend + 1 , - 1 )
table.insert ( split , before_string )
table.insert ( split , string )
end
table.insert ( split , text )
return split
end
2022-09-16 18:42:50 +00:00
parsers.fast_split_yaml = function ( cfgtext )
-- Fast yaml splitter - incomplete parsing, only first layer is parsed
-- Used within timers to find objects while decreasing CPU usage
local items = { }
local replacements = 1
cfgtext = cfgtext : gsub ( " ^%s* " , " " )
while replacements > 0 do
cfgtext , replacements = cfgtext : gsub ( " ^(.- \n )(%S+) " , function ( struct , n )
table.insert ( items , struct )
return " " .. n
end )
end
table.insert ( items , cfgtext )
return items
end
parsers.yaml_pseudo = function ( cfgtext )
-- Somewhat yaml-like structure used by pactl
local struct = { }
local lines = { }
cfgtext : gsub ( " (%s*)([^ \n ]*) " , function ( spacing , line )
table.insert ( lines ,
{
spacing : len ( ) ,
-- key
line : match ( " ^([^:=]-)%s*[:=] " ) or line ,
-- value
line : match ( " :%s*(.-)%s*$ " ) or
line : match ( " =%s*(.-)%s*$ " )
}
)
end )
local history = { struct }
local spacing_width = 0
for k , v in pairs ( lines ) do
if v [ 1 ] > spacing_width then
history [ # history ] [ lines [ k - 1 ] [ 2 ] ] = {
[ lines [ k - 1 ] [ 2 ] ] = lines [ k - 1 ] [ 3 ]
}
history [ # history + 1 ] = history [ # history ] [ lines [ k - 1 ] [ 2 ] ]
elseif v [ 1 ] < spacing_width then
history [ # history ] = nil
end
if v [ 3 ] and v [ 3 ] : match ( " ^%s* \" .* \" %s*$ " ) then
history [ # history ] [ v [ 2 ] ] = v [ 3 ] : match ( " ^%s* \" (.*) \" %s*$ " )
else
history [ # history ] [ v [ 2 ] ] = v [ 3 ]
end
spacing_width = v [ 1 ]
end
return struct
end
2023-07-03 16:53:52 +00:00
local function quotestrip ( txt )
if ( txt : sub ( 1 , 1 ) : match ( " [' \" ] " ) )
and ( txt : sub ( - 1 , - 1 ) == txt : sub ( 1 , 1 ) ) then
return txt : sub ( 2 , - 2 )
else
return txt
end
end
2022-09-04 10:25:18 +00:00
parsers.conf = function ( cfgtext )
2022-09-16 18:42:50 +00:00
-- Conf style parser (not exactly TOML)
2022-09-04 10:25:18 +00:00
cfgtext = cfgtext : gsub ( " #[^ \n ]* " , " " )
local split_by_strings , err = split_strings ( cfgtext )
2023-07-03 16:53:52 +00:00
if not split_by_strings then error ( err ) end
local full_split = { { } }
local current_line = full_split [ 1 ]
-- tokenizer
for _ , v in pairs ( split_by_strings ) do
v = v : match ( " ^[ \t ]*(.*)[ \t ]*$ " )
if ( not ( v == " " ) ) then
if not v : match ( " ^ \" .* \" $ " ) then
v : gsub ( " [^ \t ]+ " , function ( text )
while text : match ( " \n " ) do
local before , after = text : match ( " ([^ \n ]*) \n (.*) " )
if before ~= " " then
table.insert ( current_line , before )
end
if # current_line > 0 then
table.insert ( full_split , { } )
current_line = full_split [ # full_split ]
end
text = after
end
if text ~= " " then
table.insert ( current_line , text )
end
end )
else
table.insert ( current_line , v )
end
end
2022-09-04 10:25:18 +00:00
end
2023-07-03 16:53:52 +00:00
table.remove ( full_split , # full_split )
2022-09-04 10:25:18 +00:00
local struct = { global = { } }
local block = " global "
2023-07-03 16:53:52 +00:00
-- parser
for _ , line in pairs ( full_split ) do
if line [ 1 ] and line [ 1 ] : match ( " ^%[[^%]]+%]$ " ) then -- block
block = line [ 1 ] : match ( " ^%[([^%]]+)%]$ " )
struct [ block ] = { }
elseif # line == 3 then -- assignment
if ( line [ 3 ] : sub ( 1 , 1 ) : match ( " [' \" ] " ) ) -- string
and ( line [ 3 ] : sub ( - 1 , - 1 ) == line [ 3 ] : sub ( 1 , 1 ) ) then
struct [ block ] [ quotestrip ( line [ 1 ] ) ] = quotestrip ( line [ 3 ] )
elseif line [ 3 ] : match ( " ^%d+$ " ) then -- number
struct [ block ] [ quotestrip ( line [ 1 ] ) ] = tonumber ( line [ 3 ] )
elseif ( line [ 3 ] == " true " ) or ( line [ 3 ] == " false " ) then -- boolean
struct [ block ] [ quotestrip ( line [ 1 ] ) ] = ( line [ 3 ] == " true " )
else
error ( " Invalid assignment expression: " .. line [ 3 ] )
end
else -- invalid
local textline = " "
for _ , v in pairs ( line ) do
textline = textline .. v .. " "
end
error ( " Invalid config expression: " .. textline : sub ( 1 , - 2 ) )
2022-09-04 10:25:18 +00:00
end
end
return struct
end
return parsers