cortav  Check-in [0c6a784678]

Overview
Comment:add --version -V flag
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 0c6a7846785c6aa3dbf9875546d9c41d78c1f7a7632473672727214618c9fb06
User & Date: lexi on 2021-12-21 05:04:57
Other Links: manifest | tags
Context
2021-12-22
10:19
add extension mechanism, move toc to extensions, update docs, fix bugs check-in: 330e1ecfdb user: lexi tags: trunk
2021-12-21
05:04
add --version -V flag check-in: 0c6a784678 user: lexi tags: trunk
03:26
fix embarassing typobug check-in: d5e8521d30 user: lexi tags: trunk
Changes

Modified cli.lua from [37b0a0a8ee] to [bdd85f20a4].

     2      2   local ss = require 'sirsem'
     3      3   
     4      4   local default_mode = {
     5      5   	['render:format'] = 'html';
     6      6   	['html:gen-styles'] = true;
     7      7   }
     8      8   
     9         -local function
    10         -kmap(fn, list)
    11         -	local new = {}
    12         -	for k, v in pairs(list) do
    13         -		local nk,nv = fn(k,v)
    14         -		new[nk or k] = nv or v
    15         -	end
    16         -	return new
    17         -end
    18         -
    19         -local function
    20         -kfilter(list, fn)
    21         -	local new = {}
    22         -	for k, v in pairs(list) do
    23         -		if fn(k,v) then new[k] = v end
    24         -	end
    25         -	return new
    26         -end
    27         -
    28      9   local function
    29     10   main(input, output, log, mode, suggestions, vars)
    30     11   	local doc = ct.parse(input.stream, input.src, mode)
    31     12   	input.stream:close()
    32     13   	if mode['parse:show-tree'] then
    33     14   		log:write(dump(doc))
    34     15   	end
................................................................................
    43     24   		error 'what output format should i translate the input to?'
    44     25   	end
    45     26   	if mode['render:format'] == 'none' then return 0 end
    46     27   	if not ct.render[mode['render:format']] then
    47     28   		ct.exns.unimpl('output format “%s” unsupported', mode['render:format']):throw()
    48     29   	end
    49     30   	
    50         -	local render_opts = kmap(function(k,v)
           31  +	local render_opts = ss.kmap(function(k,v)
    51     32   		return k:sub(2+#mode['render:format'])
    52         -	end, kfilter(mode, function(m)
           33  +	end, ss.kfilter(mode, function(m)
    53     34   		return ss.str.begins(m, mode['render:format']..':')
    54     35   	end))
    55     36   
    56     37   	doc.vars = vars
    57     38   	
    58     39   	-- this is kind of gross but the context object belongs to the parser,
    59     40   	-- not the renderer, so that's not a suitable place for this information
................................................................................
   136    117   		mode = function(key,value) mode[checkmodekey(key)] = value end;
   137    118   		['mode-set'] = function(key) mode[checkmodekey(key)] = true end;
   138    119   		['mode-clear'] = function(key) mode[checkmodekey(key)] = false end;
   139    120   
   140    121   		['mode-weak'] = function(key,value) suggestions[checkmodekey(key)] = value end;
   141    122   		['mode-set-weak'] = function(key) suggestions[checkmodekey(key)] = true end;
   142    123   		['mode-clear-weak'] = function(key) suggestions[checkmodekey(key)] = false end;
          124  +
          125  +		['version'] = function()
          126  +			outp:write(ct.info:about())
          127  +			if next(ct.ext.loaded) then
          128  +				outp:write('\nactive extensions:\n')
          129  +				for k,v in pairs(ct.ext.loaded) do
          130  +					outp:write(string.format(' * %s', v.id ..
          131  +						(v.version and (' ' .. v.version:string()) or '')))
          132  +					if v.desc then
          133  +						outp:write(string.format(': %s', v.desc))
          134  +						if v.contributors then
          135  +							outp:write(string.format(' [%s]', table.concat(
          136  +								ss.map(function(ctr)
          137  +									return ctr.name or ctr.handle
          138  +								end, v.contributors), ', ')))
          139  +						end
          140  +					else
          141  +						outp:write'\n'
          142  +					end
          143  +				end
          144  +			end
          145  +			os.exit(0)
          146  +		end
   143    147   	}
   144    148   
   145    149   	local args = {}
   146    150   	local keepParsing = true
   147    151   	do local i = 1 while i <= #arg do local v = arg[i]
   148    152   		local execLongOpt = function(longopt)
   149    153   			if not onswitch[longopt] then
   150    154   				ct.exns.cli('switch --%s unrecognized', longopt):throw()
   151    155   			end
   152    156   			local nargs = optnparams(longopt)
   153    157   
   154    158   			if nargs > 1 then
   155    159   				if i + nargs > #arg then
   156         -					ct.exns.cli('not enough arguments for switch --%s (%u expected)', longopt, nargs):throw()
          160  +					ct.exns.cli('not enough arguments for switch --%s (%s expected)', longopt, nargs):throw()
   157    161   				end
   158    162   				local nt = {}
   159    163   				for j = i+1, i+nargs do
   160    164   					table.insert(nt, arg[j])
   161    165   				end
   162         -				onswitch[longopt](table.unpack(nt))
          166  +				print('onsw')
   163    167   			elseif nargs == 1 then
   164    168   				onswitch[longopt](arg[i+1])
          169  +			else
          170  +				onswitch[longopt]()
   165    171   			end
   166    172   			i = i + nargs
   167    173   		end
   168    174   		if v == '--' then
   169    175   			keepParsing = false
   170    176   		else
   171    177   			local longopt = v:match '^%-%-(.+)$'
................................................................................
   173    179   				execLongOpt(longopt)
   174    180   			else
   175    181   				if keepParsing and v:sub(1,1) == '-' then
   176    182   					for c,p in ss.str.enc.utf8.each(v:sub(2)) do
   177    183   						if optmap[c] then
   178    184   							execLongOpt(optmap[c])
   179    185   						else
   180         -							ct.exns.cli('switch -%i unrecognized', c):throw()
          186  +							ct.exns.cli('switch -%s unrecognized', c):throw()
   181    187   						end
   182    188   					end
   183    189   				else
   184    190   					table.insert(args, v)
   185    191   				end
   186    192   			end
   187    193   

Modified cortav.lua from [70cf5fbd0d] to [7d896a453b].

     8      8   local startswith = ss.str.begins
     9      9   local eachcode = ss.str.enc.utf8.each
    10     10   local dump = ss.dump
    11     11   local declare = ss.declare
    12     12   
    13     13   -- make this module available to require() when linked into a lua bytecode program with luac
    14     14   local ct = ss.namespace 'cortav'
           15  +ct.info = {
           16  +	version = ss.version {0,1; 'devel'};
           17  +	package_name = 'cortav';
           18  +	contributors = {
           19  +		{ name = 'lexi hale', handle = 'velartrill';
           20  +		  mail = 'lexi@hale.su', homepage = 'https://hale.su' };
           21  +	};
           22  +	ident_string = function(i)
           23  +		return string.format('%s %s', i.package_name, i.version)
           24  +	end;
           25  +	credits = function(i)
           26  +		local all = ss.copy(i.contributors)
           27  +		for i,who in pairs(all) do
           28  +			who.role = who.role or 'core functionality'
           29  +		end
           30  +		for name,ext in pairs(ct.ext.loaded) do
           31  +			if ext.contributors then
           32  +				for _,c in pairs(ext.contributors) do
           33  +					local ofs, ref = ss.find(all, function(a)
           34  +						return a.handle == c.handle
           35  +					end)
           36  +					if ofs then
           37  +						ref.role = string.format('%s; %s extension', ref.role, name)
           38  +					else
           39  +						local c = ss.clone(ext.author)
           40  +						c.role = name .. ' extension'
           41  +					end
           42  +				end
           43  +			end
           44  +		end
           45  +		return all
           46  +	end;
           47  +	credits_ascii = function(contributors)
           48  +		local body = ''
           49  +		for _, c in pairs(contributors) do
           50  +			local str
           51  +			if c.handle then
           52  +				str = string.format('%s “%s” <%s>', c.name, c.handle, c.mail)
           53  +			else
           54  +				str = string.format('%s <%s>', c.name, c.mail)
           55  +			end
           56  +			if c.homepage then
           57  +				str = string.format('%s (%s)', str, c.homepage)
           58  +			end
           59  +			if c.role then
           60  +				str = string.format('%s: %s', str, c.role)
           61  +			end
           62  +			body = body .. string.format(' ~ %s\n', str)
           63  +		end
           64  +		return body
           65  +	end;
           66  +	about = function(i)
           67  +		return i:ident_string() .. '\n' ..
           68  +		       i.credits_ascii(i:credits())
           69  +	end;
           70  +}
           71  +
           72  +
    15     73   ct.render = {}
    16     74   
    17     75   ct.exns = {
    18     76   	tx = ss.exnkind('translation error', function(msg,...)
    19     77   		return string.format("(%s:%u) "..msg, ...)
    20     78   	end);
    21     79   	io = ss.exnkind('IO error', function(msg, ...)

Modified ext/toc.lua from [a3dcc0807f] to [ed743c91e7].

     1      1   local ct = require 'cortav'
     2      2   local ss = require 'sirsem'
     3      3   
     4      4   ct.ext.install {
     5      5   	id = 'toc';
     6      6   	desc = 'provides a table of contents for HTML renderer plus generic fallback';
            7  +	version = ss.version {0,1; 'devel'};
            8  +	contributors = {{name='lexi hale', handle='velartrill', mail='lexi@hale.su', homepage='https://hale.su'}};
     7      9   	directive = function(words)
     8     10   
     9     11   	end;
    10     12   }

Modified sirsem.lua from [a1f6282434] to [8f6ee343ec].

    35     35   function ss.filter(list, fn)
    36     36   	local new = {}
    37     37   	for i, v in ipairs(list) do
    38     38   		if fn(v,i) then table.insert(new, v) end
    39     39   	end
    40     40   	return new
    41     41   end
           42  +function ss.kmap(fn, list)
           43  +	local new = {}
           44  +	for k, v in pairs(list) do
           45  +		local nk,nv = fn(k,v)
           46  +		new[nk or k] = nv or v
           47  +	end
           48  +	return new
           49  +end
           50  +
           51  +function ss.kfilter(list, fn)
           52  +	local new = {}
           53  +	for k, v in pairs(list) do
           54  +		if fn(k,v) then new[k] = v end
           55  +	end
           56  +	return new
           57  +end
           58  +
           59  +function ss.find(tbl, pred, ...)
           60  +	pred = pred or function(a,b)
           61  +		return a == b
           62  +	end
           63  +	for k,v in pairs(tbl) do
           64  +		if pred(v,k,...) then return k,v end
           65  +	end
           66  +	return nil
           67  +end
           68  +
           69  +function ss.clone(tbl) -- performs a shallow copy
           70  +	if tbl.clone then return tbl:clone() end
           71  +	local new = {}
           72  +	for k,v in pairs(tbl) do
           73  +		new[k] = v
           74  +	end
           75  +	return new
           76  +end
           77  +
           78  +function ss.copy(tbl) -- performs a deep copy
           79  +	local new = {}
           80  +	for k,v in pairs(tbl) do
           81  +		if type(v) == 'table' then
           82  +			if v.clone then
           83  +				new[k] = v:clone() -- this may or may not do a deep copy!
           84  +			else
           85  +				new[k] = ss.copy(v)
           86  +			end
           87  +		else
           88  +			new[k] = v
           89  +		end
           90  +	end
           91  +	return new
           92  +end
           93  +
           94  +function ss.delegate(tbl,tpl) -- returns a table that looks up keys it lacks from
           95  +                              -- tbl (lightweight alternative to shallow copies)
           96  +	tpl = tpl or {}
           97  +	return setmetatable({}, {__index=tbl})
           98  +end
    42     99   
    43    100   ss.str = {}
    44    101   
    45    102   function ss.str.begins(str, pfx)
    46    103   	return string.sub(str, 1, #pfx) == pfx
    47    104   end
    48    105   
................................................................................
   268    325   				ss.str.exn('out of place token “%s”', stop):throw()
   269    326   			end
   270    327   		end
   271    328   	end
   272    329   
   273    330   	ss.str.exn('token “%s” expected before end of line', stop):throw()
   274    331   end
          332  +
          333  +ss.version = ss.declare {
          334  +	name = 'version';
          335  +	mk = function(tbl) return tbl end;
          336  +	fns = {
          337  +		pre = function(self,other) end;
          338  +		post = function(self,other) end;
          339  +		string = function(self) return tostring(self) end;		
          340  +	};
          341  +	cast = {
          342  +		string = function(vers)
          343  +			if not(next(vers)) then return '0.0' end
          344  +			local str = ''
          345  +			for _,v in pairs(vers) do
          346  +				if type(v) == 'string' then
          347  +					if str ~= '' then str = str .. '-' end
          348  +					str = str .. v
          349  +				else
          350  +					if str ~= '' then str = str .. '.' end
          351  +					str = str .. tostring(v)
          352  +				end
          353  +			end
          354  +			return str
          355  +		end
          356  +	};
          357  +}
          358  +
          359  +function ss.classinstance(o)
          360  +	local g = getmetatable(o)
          361  +	if not o then return nil end
          362  +	local mm = getmetatable(g)
          363  +	if not o then return nil end
          364  +	if mm.__name == 'class' then
          365  +		return g
          366  +	else
          367  +		return nil
          368  +	end
          369  +end
          370  +