1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use super::prelude::*;
use crate::tree::{AnchorTarget, LinkLabel, LinkLocation, LinkType};
use crate::url::is_url;
pub const RULE_LINK_SINGLE: Rule = Rule {
name: "link-single",
position: LineRequirement::Any,
try_consume_fn: link,
};
pub const RULE_LINK_SINGLE_NEW_TAB: Rule = Rule {
name: "link-single-new-tab",
position: LineRequirement::Any,
try_consume_fn: link_new_tab,
};
fn link<'p, 'r, 't>(parser: &'p mut Parser<'r, 't>) -> ParseResult<'r, 't, Elements<'t>> {
debug!("Trying to create a single-bracket link (regular)");
check_step(parser, Token::LeftBracket)?;
try_consume_link(parser, RULE_LINK_SINGLE, None)
}
fn link_new_tab<'p, 'r, 't>(
parser: &'p mut Parser<'r, 't>,
) -> ParseResult<'r, 't, Elements<'t>> {
debug!("Trying to create a single-bracket link (new tab)");
check_step(parser, Token::LeftBracketStar)?;
try_consume_link(parser, RULE_LINK_SINGLE_NEW_TAB, Some(AnchorTarget::NewTab))
}
fn try_consume_link<'p, 'r, 't>(
parser: &'p mut Parser<'r, 't>,
rule: Rule,
target: Option<AnchorTarget>,
) -> ParseResult<'r, 't, Elements<'t>> {
info!(
"Trying to create a single-bracket link (target {})",
match target {
Some(target) => target.name(),
None => "<none>",
},
);
let url = collect_text(
parser,
rule,
&[ParseCondition::current(Token::Whitespace)],
&[
ParseCondition::current(Token::RightBracket),
ParseCondition::current(Token::ParagraphBreak),
ParseCondition::current(Token::LineBreak),
],
None,
)?;
if !url_valid(url) {
return Err(parser.make_warn(ParseWarningKind::InvalidUrl));
}
debug!("Retrieved URL '{url}' for link, now fetching label");
let label = collect_text(
parser,
rule,
&[ParseCondition::current(Token::RightBracket)],
&[
ParseCondition::current(Token::ParagraphBreak),
ParseCondition::current(Token::LineBreak),
],
None,
)?;
debug!("Retrieved label for link, now build element (label '{label}')");
let label = label.trim();
let element = Element::Link {
ltype: LinkType::Direct,
link: LinkLocation::Url(cow!(url)),
label: LinkLabel::Text(cow!(label)),
target,
};
ok!(element)
}
fn url_valid(url: &str) -> bool {
if url.is_empty() {
return false;
}
if url.starts_with('/') {
return true;
}
if is_url(url) {
return true;
}
false
}