local SpecFormatter = {} local utils = {} function SpecFormatter.init( us ) utils = us end function trim( s ) return ( s:gsub( "^%s*(.-)%s*$", "%1" ) ) end local function rawpairs( t ) return next, t, nil end -- The code this is based off of is here: -- https://swarm.workshop.perforce.com/files/guest/jason_gibson/misc/spec_printer.pl -- -- Note that this function expects the forms to be as the server produces -- them, not as processed by another trigger/Extension. function SpecFormatter.Format( type, formFile, keepComments ) local form = "" local body = {} local inBody = false local bodyKey = "View" -- Everything but protections. local space = 0 local plusminus = 0 local quote_len = 0 local spaces = { 1, 0, 2, 0, 3, 0, 4, 0 } function protectBody( line ) -- A comment is not formatted. if string.find( line, "^%s+##" ) then table.insert( body, line ) return end local _, _, pp, put, pu, pip, ppa = string.find( line, "^%s(%S*) (%S*) (%S*) (%S*) (.*)" ) if string.len( pp ) > spaces[ 1 ] then spaces[ 1 ] = string.len( pp ) end if string.len( put ) > spaces[ 2 ] then spaces[ 2 ] = string.len( put ) end if string.len( pu ) > spaces[ 3 ] then spaces[ 3 ] = string.len( pu ) end if string.len( pip ) > spaces[ 4 ] then spaces[ 4 ] = string.len( pip ) end table.insert( body, line ) end function viewBody( line ) local tline = trim( line ) -- todo: should be utils.trim local _, _, lhs, rhs = string.find( tline, "(.*) (\"?//.*)" ) local len = string.len( lhs ) if len > space then space = len end local quote = 0 if string.match( tline, "^\"[%+-&]" ) then quote = 2 elseif string.match( tline, "^[%+-&]" ) or string.match( tline, "^\"" ) then quote = 1 end if quote > quote_len then quote_len = quote end table.insert( body, { ["line"] = tline, ["quote"] = quote } ) end if type == "protect" then bodyKey = "Protections" end for line in io.lines( formFile ) do line = line .. "\n" if string.match( line, "^#" ) and keepComments then form = form .. line goto continue end if not inBody then form = form .. line end if string.match( line, "^" .. bodyKey .. ":" ) then inBody = true goto continue end if inBody then if type == "protect" then protectBody( line ) else viewBody( line ) end else assert( "how?" ) end ::continue:: end function formatProtect() for i, line in ipairs( body ) do if string.find( line, "^%s+##" ) then form = form .. line .. "\n" goto next end form = form .. "\t" local _, _, pp, put, pu, pip, ppa = string.find( line, "^%s(%S*) (%S*) (%S*) (%S*) (.*)" ) form = form .. string.rep( " ", 1 + spaces[ 1 ] - string.len( pp ) ) .. pp form = form .. string.rep( " ", 1 + spaces[ 2 ] - string.len( put ) ) .. put form = form .. string.rep( " ", 1 + spaces[ 3 ] - string.len( pu ) ) .. pu form = form .. string.rep( " ", 1 + spaces[ 4 ] - string.len( pip ) ) .. pip local quote = 0 if string.match( ppa, "^\"[%+-&]" ) then quote = 2 elseif string.match( ppa, "^[%+-&]" ) or string.match( line, "^\"" ) then quote = 1 end form = form .. " " .. string.rep( " ", 2 - quote ) .. ppa .. "\n" form = form .. "\n" ::next:: end end function formatView() for i, t in ipairs( body ) do local line = t[ "line" ] local quote = t[ "quote" ] local tbl = {} local _, _, lhs, rhs = string.find( line, "(.*) (\"?//.*)" ) local ql = quote_len - quote local sp1 = "" if quote_len > 0 then sp1 = sp1 .. string.rep( " ", ql - #sp1 ) end local sp2 = "" local lhsQ = 0 if string.match( rhs, "^\"" ) then lhsQ = ql else lhsQ = ql - 1 end sp2 = sp2 .. string.rep( " ", space - lhsQ - string.len( lhs ) + 3) form = form .. "\t" .. sp1 .. lhs .. sp2 .. rhs .. "\n" ::continue:: end end if type == "protect" then formatProtect() else formatView() end utils.writeFile( formFile, form ) return true, "no message" end return SpecFormatter