tangled
alpha
login
or
join now
ngp.computer
/
tsk
A file-based task manager
0
fork
atom
overview
issues
pulls
pipelines
FIX: multiple styles on one line breaking rendering
ngp.computer
1 year ago
ce6d639b
95700381
+77
-52
4 changed files
expand all
collapse all
unified
split
Cargo.lock
Cargo.toml
src
main.rs
task.rs
+1
-1
Cargo.lock
···
582
582
583
583
[[package]]
584
584
name = "tsk"
585
585
-
version = "0.2.1"
585
585
+
version = "0.2.2"
586
586
dependencies = [
587
587
"clap",
588
588
"clap_complete",
+1
-1
Cargo.toml
···
1
1
[package]
2
2
name = "tsk"
3
3
-
version = "0.2.1"
3
3
+
version = "0.2.2"
4
4
edition = "2021"
5
5
publish = true
6
6
+14
-7
src/main.rs
···
96
96
/// Shows raw file attributes for the file
97
97
#[arg(short = 'x', default_value_t = false)]
98
98
show_attrs: bool,
99
99
+
100
100
+
#[arg(short = 'R', default_value_t = false)]
101
101
+
raw: bool,
99
102
/// The [TSK-]ID of the task to display
100
103
#[command(flatten)]
101
104
task_id: TaskId,
···
232
235
Commands::Swap => command_swap(dir),
233
236
Commands::Show {
234
237
task_id,
238
238
+
raw,
235
239
show_attrs,
236
236
-
} => command_show(dir, task_id, show_attrs),
240
240
+
} => command_show(dir, task_id, show_attrs, raw),
237
241
Commands::Follow {
238
242
task_id,
239
243
link_index,
···
385
389
Workspace::from_path(dir)?.deprioritize(task_id.into())
386
390
}
387
391
388
388
-
fn command_show(dir: PathBuf, task_id: TaskId, show_attrs: bool) -> Result<()> {
392
392
+
fn command_show(dir: PathBuf, task_id: TaskId, show_attrs: bool, raw: bool) -> Result<()> {
389
393
let task = Workspace::from_path(dir)?.task(task_id.into())?;
390
394
// YAML front-matter style. YAML is gross, but it's what everyone uses!
391
395
if show_attrs && !task.attributes.is_empty() {
···
395
399
}
396
400
println!("---");
397
401
}
398
398
-
if let Some(styled_task) = task::parse(&task.to_string()) {
399
399
-
writeln!(io::stdout(), "{}", styled_task.content)?;
400
400
-
} else {
401
401
-
println!("{task}");
402
402
+
match task::parse(&task.to_string()) {
403
403
+
Some(styled_task) if !raw => {
404
404
+
writeln!(io::stdout(), "{}", styled_task.content)?;
405
405
+
}
406
406
+
_ => {
407
407
+
println!("{task}");
408
408
+
}
402
409
}
403
410
Ok(())
404
411
}
···
421
428
if edit {
422
429
command_edit(dir, taskid)
423
430
} else {
424
424
-
command_show(dir, taskid, false)
431
431
+
command_show(dir, taskid, false, false)
425
432
}
426
433
}
427
434
}
+61
-43
src/task.rs
···
9
9
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
10
10
enum ParserState {
11
11
// Started by ` =`, terminated by `=
12
12
-
Highlight(usize),
12
12
+
Highlight(usize, usize),
13
13
// Started by ` [`, terminated by `](`
14
14
-
Linktext(usize),
14
14
+
Linktext(usize, usize),
15
15
// Started by `](`, terminated by `) `, must immedately follow a Linktext
16
16
-
Link(usize),
17
17
-
RawLink(usize),
16
16
+
Link(usize, usize),
17
17
+
RawLink(usize, usize),
18
18
// Started by ` [[`, terminated by `]] `
19
19
-
InternalLink(usize),
19
19
+
InternalLink(usize, usize),
20
20
// Started by ` *`, terminated by `* `
21
21
-
Italics(usize),
21
21
+
Italics(usize, usize),
22
22
// Started by ` !`, termianted by `!`
23
23
-
Bold(usize),
23
23
+
Bold(usize, usize),
24
24
// Started by ` _`, terminated by `_ `
25
25
-
Underline(usize),
25
25
+
Underline(usize, usize),
26
26
// Started by ` -`, terminated by `- `
27
27
-
Strikethrough(usize),
27
27
+
Strikethrough(usize, usize),
28
28
29
29
// TODO: implement these.
30
30
// Started by `_ `, terminated by `_`
···
37
37
// `\n` and followed by a `\n`
38
38
BlockEnd(usize),
39
39
// Started by ` ``, terminated by `` ` or `\n`
40
40
-
InlineBlock(usize),
40
40
+
InlineBlock(usize, usize),
41
41
// Started by `^\w+>`, terminated by `\n`
42
42
Blockquote(usize),
43
43
}
···
64
64
let state_last = state.last().cloned();
65
65
match stream.next() {
66
66
// there will always be an op code in the stack
67
67
-
Some((_, c)) => {
67
67
+
Some((char_pos, c)) => {
68
68
out.push(c);
69
69
let end = out.len() - 1;
70
70
match (last, c, state_last) {
71
71
('[', '[', _) => {
72
72
-
state.push(InternalLink(end));
72
72
+
state.push(InternalLink(end, char_pos));
73
73
}
74
74
-
(']', ']', Some(InternalLink(il))) => {
74
74
+
(']', ']', Some(InternalLink(il, s_pos))) => {
75
75
state.pop();
76
76
-
let contents = out.get(il + 1..out.len() - 2)?;
76
76
+
let contents = s.get(s_pos + 1..char_pos - 1)?;
77
77
if let Ok(id) = Id::from_str(&contents) {
78
78
let linktext = format!(
79
79
"{}{}",
···
87
87
}
88
88
}
89
89
(' ' | '\r' | '\n', '[', _) => {
90
90
-
state.push(Linktext(end));
90
90
+
state.push(Linktext(end, char_pos));
91
91
}
92
92
-
(']', '(', Some(Linktext(_))) => {
93
93
-
state.push(Link(end));
92
92
+
(']', '(', Some(Linktext(_, _))) => {
93
93
+
state.push(Link(end, char_pos));
94
94
}
95
95
-
(')', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(Link(_))) => {
96
96
-
let linkpos = if let Link(lp) = state.pop().unwrap() {
95
95
+
(')', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(Link(_, _))) => {
96
96
+
// TODO: this needs to be updated to use `s` instead of `out` for position
97
97
+
// parsing
98
98
+
let linkpos = if let Link(lp, _) = state.pop().unwrap() {
97
99
lp
98
100
} else {
99
101
// remove the linktext state, it is always present.
100
102
state.pop();
101
103
continue;
102
104
};
103
103
-
let linktextpos = if let Linktext(lt) = state.pop().unwrap() {
105
105
+
let linktextpos = if let Linktext(lt, _) = state.pop().unwrap() {
104
106
lt
105
107
} else {
106
108
continue;
···
116
118
out.replace_range(linktextpos..end, &linktext);
117
119
}
118
120
}
119
119
-
('>', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(RawLink(hl))) => {
121
121
+
('>', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(RawLink(hl, s_pos)))
122
122
+
if s_pos != char_pos - 1 =>
123
123
+
{
120
124
state.pop();
121
121
-
let link = out.get(hl + 1..out.len() - 2)?;
125
125
+
let link = s.get(s_pos + 1..char_pos - 1)?;
122
126
if let Ok(url) = Url::parse(link) {
123
127
let linktext =
124
128
format!("{}{}", link.blue(), super_num(links.len() + 1).purple());
···
127
131
}
128
132
}
129
133
(' ' | '\r' | '\n', '<', _) => {
130
130
-
state.push(RawLink(end));
134
134
+
state.push(RawLink(end, char_pos));
131
135
}
132
132
-
('=', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(Highlight(hl))) => {
136
136
+
('=', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(Highlight(hl, s_pos)))
137
137
+
if s_pos != char_pos - 1 =>
138
138
+
{
133
139
state.pop();
134
140
out.replace_range(
135
141
hl..end,
136
136
-
&out.get(hl + 1..out.len() - 2)?.reversed().to_string(),
142
142
+
&s.get(s_pos + 1..char_pos - 1)?.reversed().to_string(),
137
143
);
138
144
}
139
145
(' ' | '\r' | '\n', '=', _) => {
140
140
-
state.push(Highlight(end));
146
146
+
state.push(Highlight(end, char_pos));
141
147
}
142
148
(' ' | '\r' | '\n', '*', _) => {
143
143
-
state.push(Italics(end));
149
149
+
state.push(Italics(end, char_pos));
144
150
}
145
145
-
('*', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(Italics(il))) => {
151
151
+
('*', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(Italics(il, s_pos)))
152
152
+
if s_pos != char_pos - 1 =>
153
153
+
{
146
154
state.pop();
147
155
out.replace_range(
148
156
il..end,
149
149
-
&out.get(il + 1..out.len() - 2)?.italic().to_string(),
157
157
+
&s.get(s_pos + 1..char_pos - 1)?.italic().to_string(),
150
158
);
151
159
}
152
160
(' ' | '\r' | '\n', '!', _) => {
153
153
-
state.push(Bold(end));
161
161
+
state.push(Bold(end, char_pos));
154
162
}
155
155
-
('!', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(Bold(il))) => {
163
163
+
('!', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(Bold(il, s_pos)))
164
164
+
if s_pos != char_pos - 1 =>
165
165
+
{
156
166
state.pop();
157
157
-
out.replace_range(il..end, &out.get(il + 1..end - 1)?.bold().to_string());
167
167
+
out.replace_range(
168
168
+
il..end,
169
169
+
&s.get(s_pos + 1..char_pos - 1)?.bold().to_string(),
170
170
+
);
158
171
}
159
172
(' ' | '\r' | '\n', '_', _) => {
160
160
-
state.push(Underline(end));
173
173
+
state.push(Underline(end, char_pos));
161
174
}
162
162
-
('_', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(Underline(il))) => {
175
175
+
('_', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(Underline(il, s_pos)))
176
176
+
if s_pos != char_pos - 1 =>
177
177
+
{
163
178
state.pop();
164
179
out.replace_range(
165
180
il..end,
166
166
-
&out.get(il + 1..end - 1)?.underline().to_string(),
181
181
+
&s.get(s_pos + 1..char_pos - 1)?.underline().to_string(),
167
182
);
168
183
}
169
184
(' ' | '\r' | '\n', '~', _) => {
170
170
-
state.push(Strikethrough(end));
185
185
+
state.push(Strikethrough(end, char_pos));
171
186
}
172
172
-
('~', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(Strikethrough(il))) => {
187
187
+
('~', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(Strikethrough(il, s_pos)))
188
188
+
if s_pos != char_pos - 1 =>
189
189
+
{
173
190
state.pop();
174
191
out.replace_range(
175
192
il..end,
176
176
-
&out.get(il + 1..end - 1)?.strikethrough().to_string(),
193
193
+
&s.get(s_pos + 1..char_pos - 1)?.strikethrough().to_string(),
177
194
);
178
195
}
179
179
-
('`', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(InlineBlock(hl))) => {
180
180
-
state.pop();
196
196
+
('`', ' ' | '\n' | '\r' | '.' | '!' | '?', Some(InlineBlock(hl, s_pos)))
197
197
+
if s_pos != char_pos - 1 =>
198
198
+
{
181
199
out.replace_range(
182
200
hl..end,
183
183
-
&out.get(hl + 1..out.len() - 1)?.green().to_string(),
201
201
+
&s.get(s_pos + 1..char_pos - 1)?.green().to_string(),
184
202
);
185
203
}
186
186
-
(' ' | '\r' | '\n', '`', _) => {
187
187
-
state.push(InlineBlock(end));
204
204
+
(' ' | '\n' | '\r' | '.' | '!' | '?', '`', _) => {
205
205
+
state.push(InlineBlock(end, char_pos));
188
206
}
189
207
_ => (),
190
208
}