summaryrefslogtreecommitdiff
path: root/support/texlab/tests/integration/lsp/fixture.rs
blob: 17eb65992361e56301e72b681119907a6190b100 (plain)
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
use std::collections::BTreeMap;

use anyhow::Result;
use lsp_types::{Position, Range, TextDocumentIdentifier, TextDocumentPositionParams};
use rustc_hash::FxHashMap;

use crate::lsp::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(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) -> Result<TextDocumentPositionParams> {
        let text_document = TextDocumentIdentifier::new(server.uri(self.name)?);
        Ok(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
}