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
|
use std::collections::BTreeMap;
use lsp_types::{Position, Range, TextDocumentIdentifier, TextDocumentPositionParams};
use rustc_hash::FxHashMap;
use super::client::Client;
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
enum Line<'a> {
File(&'a str, &'a str),
Plain(&'a str),
Range(u32, u32, std::ops::Range<usize>),
Cursor(usize),
Empty,
}
fn parse_line(line: &str) -> Line {
if let Some(name) = line.strip_prefix("%TEX ") {
Line::File(name, "latex")
} else if let Some(name) = line.strip_prefix("%BIB ") {
Line::File(name, "bibtex")
} else if let Some(name) = line.strip_prefix("%LOG ") {
Line::File(name, "log")
} else if let Some(text) = line.strip_prefix("%SRC ") {
Line::Plain(text)
} else if let Some(text) = line.strip_prefix("%CUR ") {
let position = text.find('^').unwrap();
Line::Cursor(position)
} else if line.is_empty() {
Line::Empty
} else {
let key1 = line[1..2].parse().unwrap();
let key2 = line[3..4].parse().unwrap();
let line = &line[5..];
let range = line
.find('^')
.map_or(0..0, |start| start..(line.rfind('^').unwrap() + 1));
Line::Range(key1, key2, range)
}
}
#[derive(Debug, Default)]
pub struct FileRange<'a> {
pub name: &'a str,
pub range: Range,
}
#[derive(Debug, Default)]
pub struct File<'a> {
pub name: &'a str,
pub lang: &'a str,
pub text: String,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub struct FileCursor<'a> {
pub name: &'a str,
pub position: Position,
}
impl<'a> FileCursor<'a> {
pub fn into_params(self, server: &Client) -> TextDocumentPositionParams {
let text_document = TextDocumentIdentifier::new(server.uri(self.name));
TextDocumentPositionParams {
text_document,
position: self.position,
}
}
}
#[derive(Debug, Default)]
pub struct Fixture<'a> {
pub files: Vec<File<'a>>,
pub cursor: Option<FileCursor<'a>>,
pub ranges: BTreeMap<u32, FxHashMap<u32, FileRange<'a>>>,
}
pub fn parse(input: &str) -> Fixture {
let mut fixture = Fixture::default();
let mut file = File::default();
let mut file_line_index = 0;
for line in input.lines().map(parse_line) {
match line {
Line::File(name, lang) => {
if !file.name.is_empty() {
fixture.files.push(file);
file = File::default();
}
file.name = name;
file.lang = lang;
file_line_index = 0;
}
Line::Plain(line) => {
file.text.push_str(line);
file.text.push('\n');
file_line_index += 1;
}
Line::Range(key1, key2, range) => {
let line = file_line_index - 1;
let start = Position::new(line, range.start.try_into().unwrap());
let end = Position::new(line, range.end.try_into().unwrap());
let range = Range::new(start, end);
fixture.ranges.entry(key1).or_default().insert(
key2,
FileRange {
name: file.name,
range,
},
);
}
Line::Cursor(position) => {
fixture.cursor = Some(FileCursor {
name: file.name,
position: Position::new(file_line_index - 1, position.try_into().unwrap()),
});
}
Line::Empty => {}
};
}
fixture.files.push(file);
fixture
}
|