Skip to content

Commit 48109de

Browse files
refactor parse_multiple & related functions into _quarto.modules.typst.css
1 parent f0202ec commit 48109de

File tree

2 files changed

+135
-121
lines changed

2 files changed

+135
-121
lines changed

src/resources/filters/modules/typst_css.lua

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,12 +533,136 @@ local function translate_length(csslen, warnings)
533533
return length and output_length(length, warnings)
534534
end
535535

536+
-- only a few of these map to typst, again seems simplest to parse anyway
537+
local border_styles = {
538+
'none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset', 'inherit', 'initial', 'revert', 'revert-layer', 'unset'
539+
}
540+
541+
function parse_multiple(s, limit, callback)
542+
local start = 0
543+
local count = 0
544+
repeat
545+
start = callback(s, start)
546+
-- not really necessary with string:find
547+
-- as evidenced that s.sub also works
548+
while s:sub(start, start) == ' ' do
549+
start = start + 1
550+
end
551+
count = count + 1
552+
until count >=limit or start >= #s
553+
end
554+
555+
local border_width_keywords = {
556+
thin = '1px',
557+
medium = '3px',
558+
thick = '5px'
559+
}
560+
561+
local function translate_border_width(v, warnings)
562+
v = border_width_keywords[v] or v
563+
local thickness = translate_length(v, warnings)
564+
return thickness == '0pt' and 'delete' or thickness
565+
end
566+
567+
local function quote(s)
568+
return '"' .. s .. '"'
569+
end
570+
571+
local function translate_border_style(v, _warnings)
572+
local dash
573+
if v == 'none' then
574+
return 'delete'
575+
elseif tcontains({'dotted', 'dashed'}, v) then
576+
return quote(v)
577+
end
578+
return nil
579+
end
580+
581+
local function translate_border_color(v, warnings)
582+
return output_color(parse_color(v, warnings), nil, warnings)
583+
end
584+
585+
-- border shorthand
586+
-- https://developer.mozilla.org/en-US/docs/Web/CSS/border
587+
local function translate_border(v, warnings)
588+
-- not sure why the default style that works is not the same one specified
589+
local width = 'medium'
590+
local style = 'solid' -- css specifies none
591+
local paint = 'black' -- css specifies currentcolor
592+
parse_multiple(v, 3, function(s, start)
593+
local fbeg, fend = s:find('%w+%b()', start)
594+
if fbeg then
595+
local paint2 = translate_border_color(s:sub(fbeg, fend), warnings)
596+
if paint2 then
597+
paint = paint2
598+
end
599+
return fend + 1
600+
else
601+
fbeg, fend = s:find('%S+', start)
602+
local term = v:sub(fbeg, fend)
603+
if tcontains(border_styles, term) then
604+
style = term
605+
else
606+
if parse_length_unit(term) or border_width_keywords[term] then
607+
width = term
608+
else
609+
local paint2 = translate_border_color(term, warnings)
610+
if paint2 then
611+
paint = paint2
612+
else
613+
output_warning(warnings, 'invalid border shorthand ' .. term)
614+
end
615+
end
616+
end
617+
return fend + 1
618+
end
619+
end)
620+
return {
621+
thickness = translate_border_width(width, warnings),
622+
dash = translate_border_style(style, warnings),
623+
paint = paint
624+
}
625+
end
626+
627+
local function consume_width(s, start, warnings)
628+
fbeg, fend = s:find('%S+', start)
629+
local term = s:sub(fbeg, fend)
630+
local thickness = translate_border_width(term, warnings)
631+
return thickness, fend + 1
632+
end
633+
634+
local function consume_style(s, start, warnings)
635+
fbeg, fend = s:find('%S+', start)
636+
local term = s:sub(fbeg, fend)
637+
local dash = translate_border_style(term, warnings)
638+
return dash, fend + 1
639+
end
640+
641+
local function consume_color(s, start, warnings)
642+
local fbeg, fend = s:find('%w+%b()', start)
643+
if not fbeg then
644+
fbeg, fend = s:find('%S+', start)
645+
end
646+
if not fbeg then return nil end
647+
local paint = translate_border_color(s:sub(fbeg, fend), warnings)
648+
return paint, fend + 1
649+
end
650+
651+
536652
return {
537653
parse_color = parse_color,
538654
parse_opacity = parse_opacity,
539655
output_color = output_color,
540656
parse_length_unit = parse_length_unit,
541657
parse_length = parse_length,
542658
output_length = output_length,
543-
translate_length = translate_length
659+
translate_length = translate_length,
660+
parse_multiple = parse_multiple,
661+
translate_border = translate_border,
662+
translate_border_width = translate_border_width,
663+
translate_border_style = translate_border_style,
664+
translate_border_color = translate_border_color,
665+
consume_width = consume_width,
666+
consume_style = consume_style,
667+
consume_color = consume_color
544668
}

src/resources/filters/quarto-post/typst-css-property-processing.lua

Lines changed: 10 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,6 @@ function render_typst_css_property_processing()
100100

101101
local border_sides = {'left', 'top', 'right', 'bottom'}
102102
local border_properties = {'width', 'style', 'color'}
103-
local border_width_keywords = {
104-
thin = '1px',
105-
medium = '3px',
106-
thick = '5px'
107-
}
108-
109103
local function all_equal(seq)
110104
local a = seq[1]
111105
for i = 2, #seq do
@@ -116,135 +110,31 @@ function render_typst_css_property_processing()
116110
return true
117111
end
118112

119-
local function translate_border_width(v)
120-
v = border_width_keywords[v] or v
121-
local thickness = _quarto.format.typst.css.translate_length(v, _warnings)
122-
return thickness == '0pt' and 'delete' or thickness
123-
end
124-
125-
local function translate_border_style(v)
126-
local dash
127-
if v == 'none' then
128-
return 'delete'
129-
elseif tcontains({'dotted', 'dashed'}, v) then
130-
return quote(v)
131-
end
132-
return nil
133-
end
134-
135-
local function translate_border_color(v)
136-
return _quarto.format.typst.css.output_color(_quarto.modules.typst.css.parse_color(v, _warnings), nil, _warnings)
137-
end
138113

139114
local border_translators = {
140115
width = {
141116
prop = 'thickness',
142-
fn = translate_border_width
117+
fn = _quarto.modules.typst.css.translate_border_width
143118
},
144119
style = {
145120
prop = 'dash',
146-
fn = translate_border_style
121+
fn = _quarto.modules.typst.css.translate_border_style
147122
},
148123
color = {
149124
prop = 'paint',
150-
fn = translate_border_color
125+
fn = _quarto.modules.typst.css.translate_border_color
151126
}
152127
}
153128

154-
-- only a few of these map to typst, again seems simplest to parse anyway
155-
local border_styles = {
156-
'none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset', 'inherit', 'initial', 'revert', 'revert-layer', 'unset'
157-
}
158-
159-
function parse_multiple(s, limit, callback)
160-
local start = 0
161-
local count = 0
162-
repeat
163-
start = callback(s, start)
164-
-- not really necessary with string:find
165-
-- as evidenced that s.sub also works
166-
while s:sub(start, start) == ' ' do
167-
start = start + 1
168-
end
169-
count = count + 1
170-
until count >=limit or start >= #s
171-
end
172-
173-
-- border shorthand
174-
-- https://developer.mozilla.org/en-US/docs/Web/CSS/border
175-
local function translate_border(v)
176-
-- not sure why the default style that works is not the same one specified
177-
local width = 'medium'
178-
local style = 'solid' -- css specifies none
179-
local paint = 'black' -- css specifies currentcolor
180-
parse_multiple(v, 3, function(s, start)
181-
local fbeg, fend = s:find('%w+%b()', start)
182-
if fbeg then
183-
local paint2 = translate_border_color(s:sub(fbeg, fend))
184-
if paint2 then
185-
paint = paint2
186-
end
187-
return fend + 1
188-
else
189-
fbeg, fend = s:find('%S+', start)
190-
local term = v:sub(fbeg, fend)
191-
if tcontains(border_styles, term) then
192-
style = term
193-
else
194-
if _quarto.format.typst.css.parse_length_unit(term) or border_width_keywords[term] then
195-
width = term
196-
else
197-
local paint2 = translate_border_color(term)
198-
if paint2 then
199-
paint = paint2
200-
else
201-
_warnings:insert('invalid border shorthand ' .. term)
202-
end
203-
end
204-
end
205-
return fend + 1
206-
end
207-
end)
208-
return {
209-
thickness = translate_border_width(width),
210-
dash = translate_border_style(style),
211-
paint = paint
212-
}
213-
end
214-
215-
local function consume_width(s, start)
216-
fbeg, fend = s:find('%S+', start)
217-
local term = s:sub(fbeg, fend)
218-
local thickness = translate_border_width(term)
219-
return thickness, fend + 1
220-
end
221-
222-
local function consume_style(s, start)
223-
fbeg, fend = s:find('%S+', start)
224-
local term = s:sub(fbeg, fend)
225-
local dash = translate_border_style(term)
226-
return dash, fend + 1
227-
end
228-
229-
local function consume_color(s, start)
230-
local fbeg, fend = s:find('%w+%b()', start)
231-
if not fbeg then
232-
fbeg, fend = s:find('%S+', start)
233-
end
234-
if not fbeg then return nil end
235-
local paint = translate_border_color(s:sub(fbeg, fend))
236-
return paint, fend + 1
237-
end
238-
239129
local border_consumers = {
240-
width = consume_width,
241-
style = consume_style,
242-
color = consume_color,
130+
width = _quarto.modules.typst.css.consume_width,
131+
style = _quarto.modules.typst.css.consume_style,
132+
color = _quarto.modules.typst.css.consume_color,
243133
}
244134
local function handle_border(k, v, borders)
245135
local _, ndash = k:gsub('-', '')
246136
if ndash == 0 then
247-
local border = translate_border(v)
137+
local border = _quarto.modules.typst.css.translate_border(v, _warnings)
248138
for _, side in ipairs(border_sides) do
249139
borders[side] = borders[side] or {}
250140
for k2, v2 in pairs(border) do
@@ -255,13 +145,13 @@ function render_typst_css_property_processing()
255145
local part = k:match('^border--(%a+)')
256146
if tcontains(border_sides, part) then
257147
borders[part] = borders[part] or {}
258-
local border = translate_border(v)
148+
local border = _quarto.modules.typst.css.translate_border(v, _warnings)
259149
for k2, v2 in pairs(border) do
260150
borders[part][k2] = v2
261151
end
262152
elseif tcontains(border_properties, part) then
263153
local items = {}
264-
parse_multiple(v, 4, function(s, start)
154+
_quarto.modules.typst.css.parse_multiple(v, 4, function(s, start)
265155
local item, newstart = border_consumers[part](s, start)
266156
table.insert(items, item)
267157
return newstart
@@ -304,7 +194,7 @@ function render_typst_css_property_processing()
304194
if tcontains(border_sides, side) and tcontains(border_properties, prop) then
305195
borders[side] = borders[side] or {}
306196
local tr = border_translators[prop]
307-
borders[side][tr.prop] = tr.fn(v)
197+
borders[side][tr.prop] = tr.fn(v, _warnings)
308198
else
309199
_warnings:insert('invalid 3-item border key ' .. k)
310200
end

0 commit comments

Comments
 (0)