Overview
Comment: | enable command line control of process |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
a651687c24ddf516f1cad1483cf7b9cf |
User & Date: | lexi on 2021-12-18 13:03:40 |
Other Links: | manifest | tags |
Context
2021-12-19
| ||
05:25 | further develop html renderer and document it, many doc fixes, fix misc bugs check-in: 2e37b523b5 user: lexi tags: trunk | |
2021-12-18
| ||
13:03 | enable command line control of process check-in: a651687c24 user: lexi tags: trunk | |
05:24 | initial commit check-in: 5e07b52c57 user: lexi tags: trunk | |
Changes
Modified cortav.lua from [fc129ed31b] to [f20a833e35].
150 150 fns = { 151 151 throw = function(me) error(me) end; 152 152 } 153 153 } 154 154 ct.exnkind = declare { 155 155 ident = 'exn-kind'; 156 156 mk = function(desc, report) 157 - return { desc = desc, report = report } 157 + return { 158 + desc = desc; 159 + report = report or function(msg,...) 160 + return string.format(msg,...) 161 + end; 162 + } 158 163 end; 159 164 call = function(me, ...) 160 165 return ct.exn(me, ...) 161 166 end; 162 167 } 163 168 164 169 ct.exns = { 165 170 tx = ct.exnkind('translation error', function(msg,...) 166 171 return string.format("(%s:%u) "..msg, ...) 167 - end) 172 + end); 173 + io = ct.exnkind('IO error', function(msg, ...) 174 + return string.format("<%s %s> "..msg, ...) 175 + end); 176 + cli = ct.exnkind 'command line parse error'; 177 + mode = ct.exnkind('bad mode', function(msg, ...) 178 + return string.format("mode “%s” "..msg, ...) 179 + end); 168 180 } 169 181 170 182 ct.ctx = declare { 171 183 mk = function(src) return {src = src} end; 172 184 ident = 'context'; 173 185 cast = { 174 186 string = function(me) ................................................................................ 390 402 end 391 403 392 404 local span_renderers = {} 393 405 local function htmlSpan(spans, block, sec) 394 406 local text = {} 395 407 for k,v in pairs(spans) do 396 408 if type(v) == 'string' then 397 - table.insert(text,(v:gsub('[<>&]', 409 + table.insert(text,(v:gsub('[<>&"]', 398 410 function(x) 399 - return string.format('&#%02u', string.byte(x)) 411 + return string.format('&#%02u;', string.byte(x)) 400 412 end))) 401 413 else 402 414 table.insert(text, span_renderers[v.kind](v, block, sec)) 403 415 end 404 416 end 405 417 return table.concat(text) 406 418 end 407 419 408 420 function span_renderers.format(sp) 409 421 local tags = { strong = 'strong', emph = 'em', strike = 'del', insert = 'ins', literal = 'code' } 410 - if sp.style == 'literal' then 422 + if sp.style == 'literal' and not opts['fossil-uv'] then 411 423 stylesNeeded.code = true 412 424 end 413 425 if sp.style == 'del' or sp.style == 'ins' then 414 426 stylesNeeded.editors_markup = true 415 427 end 416 428 return tag(tags[sp.style],nil,htmlSpan(sp.spans)) 417 429 end ................................................................................ 677 689 678 690 local styles = {} 679 691 for k in pairs(stylesNeeded) do 680 692 table.insert(styles, (stylesets[k]:gsub('%s+',' '))) 681 693 end 682 694 683 695 local head = {} 696 + local styletag = '' 697 + if opts['link-css'] then 698 + local css = opts['link-css'] 699 + if type(css) ~= 'string' then ct.exns.mode('must be a string', 'html:link-css'):throw() end 700 + styletag = styletag .. elt('link',{rel='stylesheet',type='text/css',href=opts['link-css']}) 701 + end 684 702 if next(styles) then 685 - table.insert(head, tag('style',{type='text/css'},table.concat(styles))) 703 + if opts['gen-styles'] then 704 + styletag = styletag .. tag('style',{type='text/css'},table.concat(styles)) 705 + end 706 + table.insert(head, styletag) 686 707 end 687 708 688 - if opts.snippet then 689 - return body 709 + if opts['fossil-uv'] then 710 + return tag('div',{class='fossil-doc',['data-title']=doctitle},styletag .. body) 711 + elseif opts.snippet then 712 + return styletag .. body 690 713 else 691 714 return dr.htmlDoc(doctitle, next(head) and table.concat(head), body) 692 715 end 693 716 end 694 717 695 718 local function 696 719 startswith(str, pfx) ................................................................................ 929 952 if a1 == ':' and a2 ~= ':' then 930 953 align = 'left' 931 954 elseif a1 == ':' and a2 == ':' then 932 955 align = 'center' 933 956 elseif a1 ~= ':' and a2 == ':' then 934 957 align = 'right' 935 958 end 959 + text = text:match '^%s*(.-)%s*$' 936 960 table.insert(row, { 937 961 spans = ct.parse_span(text, c); 938 962 align = align; 939 963 header = header; 940 964 }) 941 965 end 942 966 if #c.sec.blocks > 1 and c.sec.blocks[#c.sec.blocks].kind == 'table' then ................................................................................ 1100 1124 end 1101 1125 end 1102 1126 1103 1127 return ctx.doc 1104 1128 end 1105 1129 1106 1130 local default_mode = { 1107 - format = 'html'; 1131 + ['render:format'] = 'html'; 1132 + ['html:gen-styles'] = true; 1108 1133 } 1134 + 1135 +local function filter(list, fn) 1136 + local new = {} 1137 + for i, v in ipairs(list) do 1138 + if fn(v,i) then table.insert(new, v) end 1139 + end 1140 + return new 1141 +end 1142 + 1143 +local function kmap(fn, list) 1144 + local new = {} 1145 + for k, v in pairs(list) do 1146 + local nk,nv = fn(k,v) 1147 + new[nk or k] = nv or v 1148 + end 1149 + return new 1150 +end 1151 +local function kfilter(list, fn) 1152 + local new = {} 1153 + for k, v in pairs(list) do 1154 + if fn(k,v) then new[k] = v end 1155 + end 1156 + return new 1157 +end 1109 1158 1110 1159 local function main(input, output, log, mode, vars) 1111 1160 local doc = ct.parse(input.stream, input.src) 1112 1161 input.stream:close() 1113 - if mode['show-tree'] then 1162 + if mode['parse:show-tree'] then 1114 1163 log:write(dump(doc)) 1115 1164 end 1116 1165 1117 - if not mode.format then 1166 + if not mode['render:format'] then 1118 1167 error 'what output format should i translate the input to?' 1119 1168 end 1120 - if not ct.render[mode.format] then 1121 - error(string.format('output format “%s” unsupported', mode.format)) 1169 + if not ct.render[mode['render:format']] then 1170 + error(string.format('output format “%s” unsupported', mode['render:format'])) 1122 1171 end 1123 1172 1124 - output:write(ct.render[mode.format](doc, {})) 1173 + local render_opts = kmap(function(k,v) 1174 + return k:sub(2+#mode['render:format']) 1175 + end, kfilter(mode, function(m) 1176 + return startswith(m, mode['render:format']..':') 1177 + end)) 1178 + 1179 + output:write(ct.render[mode['render:format']](doc, render_opts)) 1125 1180 end 1126 1181 1127 1182 local inp,outp,log = io.stdin, io.stdout, io.stderr 1128 1183 1129 1184 local function entry_cli() 1130 1185 local mode, vars, input = default_mode, {}, { 1131 1186 stream = inp; 1132 1187 src = { 1133 1188 file = '(stdin)'; 1134 1189 } 1135 1190 } 1136 1191 1137 - if arg[1] and arg[1] ~= '' then 1192 + local optnparams = function(o) 1193 + local param_opts = { 1194 + out = 1; 1195 + log = 1; 1196 + define = 2; -- key value 1197 + ['mode-set'] = 1; 1198 + ['mode-clear'] = 1; 1199 + mode = 2; 1200 + } 1201 + return param_opts[o] or 0 1202 + end 1203 + 1204 + local optmap = { 1205 + o = 'out'; 1206 + l = 'log'; 1207 + d = 'define'; 1208 + V = 'version'; 1209 + h = 'help'; 1210 + y = 'mode-set', n = 'mode-clear'; 1211 + m = 'mode'; 1212 + } 1213 + 1214 + local checkmodekey = function(key) 1215 + if not key:match '[^:]+:.+' then 1216 + ct.exns.cli('invalid mode key %s', key):throw() 1217 + end 1218 + return key 1219 + end 1220 + local onswitch = { 1221 + out = function(file) 1222 + local nf = io.open(file,'wb') 1223 + if nf then outp:close() outp = nf else 1224 + ct.exns.io('could not open output file for writing', 'open',file):throw() 1225 + end 1226 + end; 1227 + log = function(file) 1228 + local nf = io.open(file,'wb') 1229 + if nf then log:close() log = nf else 1230 + ct.exns.io('could not open log file for writing', 'open',file):throw() 1231 + end 1232 + end; 1233 + define = function(key,value) 1234 + -- set context key 1235 + end; 1236 + mode = function(key,value) mode[checkmodekey(key)] = value end; 1237 + ['mode-set'] = function(key) mode[checkmodekey(key)] = true end; 1238 + ['mode-clear'] = function(key) mode[checkmodekey(key)] = false end; 1239 + } 1240 + 1241 + local args = {} 1242 + local keepParsing = true 1243 + do local i = 1 while i <= #arg do local v = arg[i] 1244 + local execLongOpt = function(longopt) 1245 + if not onswitch[longopt] then 1246 + ct.exns.cli('switch --%s unrecognized', longopt):throw() 1247 + end 1248 + local nargs = optnparams(longopt) 1249 + 1250 + if nargs > 1 then 1251 + if i + nargs > #arg then 1252 + ct.exns.cli('not enough arguments for switch --%s (%u expected)', longopt, nargs):throw() 1253 + end 1254 + local nt = {} 1255 + for j = i+1, i+nargs do 1256 + table.insert(nt, arg[j]) 1257 + end 1258 + onswitch[longopt](table.unpack(nt)) 1259 + elseif nargs == 1 then 1260 + onswitch[longopt](arg[i+1]) 1261 + end 1262 + i = i + nargs 1263 + end 1264 + if v == '--' then 1265 + keepParsing = false 1266 + else 1267 + local longopt = v:match '^%-%-(.+)$' 1268 + if keepParsing and longopt then 1269 + execLongOpt(longopt) 1270 + else 1271 + if keepParsing and v:sub(1,1) == '-' then 1272 + for c,p in eachcode(v:sub(2)) do 1273 + if optmap[c] then 1274 + execLongOpt(optmap[c]) 1275 + else 1276 + ct.exns.cli('switch -%i unrecognized', c):throw() 1277 + end 1278 + end 1279 + else 1280 + table.insert(args, v) 1281 + end 1282 + end 1283 + 1284 + end 1285 + i = i + 1 end end 1286 + 1287 + if args[1] and args[1] ~= '' then 1138 1288 local file = io.open(arg[1], "rb") 1139 - if not file then error('unable to load file ' .. arg[1]) end 1289 + if not file then error('unable to load file ' .. args[1]) end 1140 1290 input.stream = file 1141 - input.src.file = arg[1] 1291 + input.src.file = args[1] 1142 1292 end 1143 1293 1144 1294 main(input, outp, log, mode, vars) 1145 1295 end 1146 1296 1147 1297 -- local ok, e = pcall(entry_cli) 1148 1298 local ok, e = true, entry_cli()