///|
fn href_spec() -> FunctionSpec {
FunctionSpec::make(
["\\href"],
2,
arg_types=[UrlArg, OriginalArg],
allowed_in_text=true,
handler=href_handler,
)
}
///|
fn url_spec() -> FunctionSpec {
FunctionSpec::make(
["\\url"],
1,
arg_types=[UrlArg],
allowed_in_text=true,
handler=url_handler,
)
}
///|
fn href_argument(
args : Array[ParseNode],
index : Int,
func_name : String,
) -> String raise ParseFailure {
guard require_function_arg(args, index, func_name) is Url(url~, ..) else {
raise InternalInvariant(message="Expected URL argument for " + func_name)
}
url
}
///|
fn href_handler(
context : FunctionContext,
args : Array[ParseNode],
_ : Array[ParseNode?],
) -> ParseNode raise ParseFailure {
let href = href_argument(args, 0, context.func_name)
let body = require_function_arg(args, 1, context.func_name)
if (context.is_trusted)(UrlTrust(command="\\href", url=href, protocol=None)) {
Href(mode=context.mode, href~, body=ord_argument(body))
} else {
body
}
}
///|
fn url_handler(
context : FunctionContext,
args : Array[ParseNode],
_ : Array[ParseNode?],
) -> ParseNode raise ParseFailure {
let href = href_argument(args, 0, context.func_name)
let chars = href
.to_array()
.map(char => {
TextOrd(
mode=Text,
loc=None,
text=if char == '~' {
"\\textasciitilde"
} else {
String::from_array([char])
},
)
})
let body = ParseNode::Text(mode=context.mode, font="\\texttt", body=chars)
if (context.is_trusted)(UrlTrust(command="\\url", url=href, protocol=None)) {
Href(mode=context.mode, href~, body=ord_argument(body))
} else {
body
}
}