Hi all, I wonder if it anybody sees a possible way to do this in typst:
The code below defines a nested dictionary and a function creates a copy in which all the children inherit (concatenates in this case) the default value (so that it only needs to be changed once in the source dictionary for all the elements)
#let dict = (
key1: (
default: "1",
subkey1: "hello",
subkey2: "world"
),
key2: "other"
)
#let create-main-inherited-dict(dict, main-key: "default") = {
let result = (:)
for (key, value) in dict {
if type(value) == dictionary and main-key in value {
// If value is a dictionary with a main key
let main-value = value.at(main-key)
let new-nested = (:)
// Add the main value as the direct value for this key
new-nested.insert(main-key, main-value)
// Process all other keys (excluding the main key)
for (subkey, subvalue) in value {
if subkey != main-key {
// Concatenate main value with subkey value
new-nested.insert(subkey, str(main-value) + str(subvalue))
}
}
result.insert(key, new-nested)
} else {
// If value is not a dictionary or doesn't have main key, keep as is
result.insert(key, value)
}
}
result
}
#let c = create-main-inherited-dict(dict)
Paragraph #c.key1.subkey1 and then #c.key1
The result is the intended one for the #c.key1.subkey1 (''1hello") but I would like that #c.key1 does return #c.key1.default (“1”). I guess this is difficult unless there would be way to define a default value with a special key in typst.
Is there such thing? or anybody sees a workaround that still calls in the text a dictionary (to benefit from the built-in autocompletion in the app)?
Do I understand correctly that when displaying dictionaries in your document, you want them to show the value associated with "default"
if it is defined, otherwise the whole dictionary? There probably is a way of doing this “automatically” using very hacky show rules, but I’d advice against this.
Instead, consider passing the dictionary to a function that returns what you want it to return:
#let get-value-or-default(item) = {
if type(item) == dictionary and "default" in item.keys() {
return item.default
}
return item
}
Paragraph #get-value-or-default(c.key1.subkey1) and then #get-value-or-default(c.key1). But c itself does not have default so it returns the whole dictionary: #get-value-or-default(c)
1 Like
Hi. The closest that exists is Symbol Type – Typst Documentation, but that is only for single Unicode characters.
Actually, @bluss mentioned symbolx – Typst Universe, and you can use that instead.
#import "@preview/symbolx:0.1.0": symbol, symbolx-rule
#let create-main-inherited-dict(dict, prefix: none, main-key: "default") = {
let result = (:)
for (key, value) in dict {
if type(value) != dictionary {
result.insert(key, prefix + value)
continue
}
assert(
main-key in value,
message: "Dictionaries without main key are not allowed",
)
let main-value = value.at(main-key)
let new-nested = (:)
assert(
type(main-value) != dictionary,
message: "Main key can't have dictionary value",
)
new-nested.insert(main-key, main-value)
let dict = value
_ = dict.remove(main-key)
new-nested += create-main-inherited-dict(
dict,
prefix: main-value,
main-key: main-key,
)
result.insert(key, new-nested)
}
result
}
#let create-symbol-from-dict(dict, main-key: "default") = {
let args = ()
if main-key in dict {
args.push(value)
_ = dict.remove(main-key)
} else {
args.push(sym.zws)
}
for (key, value) in dict {
if type(value) != dictionary {
args.push((key, value))
continue
}
for (subkey, subvalue) in value {
if subkey == main-key {
args.push((key, subvalue))
continue
}
args.push((key + "." + subkey, subvalue))
}
}
symbol(..args)
}
#let dict = (
key1: (
default: "1",
subkey1: "hello",
subkey2: "world",
),
key2: "other",
)
#let inherited-dict = create-main-inherited-dict(dict)
#let (map, c) = create-symbol-from-dict(inherited-dict)
#show: symbolx-rule(map)
Paragraph #c.key1.subkey1 and then #c.key1
(#c) (#c.key1) (#c.key1.subkey1) (#c.key1.subkey2) (#c.key2)

I made the first function recursive to be usable for any structure, but the second one isn’t, because it’s harder to create the arguments for symbol
, but is probably possible. You also probably can merge them.