A simple CPU rendered GUI IDE experience.
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
use std::ops::Range;

use helix_core::snippets::parser::SnippetElement;

#[derive(
    Debug, Clone, serde_derive::Serialize, serde_derive::Deserialize,
)]
pub struct Snippet {
    pub stops: Vec<(Stop, StopP)>,
    pub last: Option<StopP>,
    pub index: usize,
}

#[derive(
    Debug,
    Clone,
    PartialEq,
    Eq,
    serde_derive::Serialize,
    serde_derive::Deserialize,
)]
pub enum StopP {
    Just(usize),
    Range(Range<usize>),
}
impl StopP {
    pub fn r(&self) -> Range<usize> {
        match self {
            Self::Just(x) => *x..*x,
            Self::Range(range) => range.clone(),
        }
    }
    pub fn manipulate(&mut self, mut f: impl FnMut(usize) -> usize) {
        match self {
            Self::Just(x) => *x = f(*x),
            Self::Range(range) => {
                range.start = f(range.start);
                range.end = f(range.end);
            }
        }
    }
}

impl Snippet {
    pub fn parse(x: &str, at: usize) -> Option<(Self, String)> {
        let value = helix_core::snippets::parser::parse(x).ok()?;

        let mut stops = vec![];
        let mut cursor = 0;
        let mut o = String::default();
        // snippets may request multiple cursors; i dont support multiple cursors yet
        for value in value.into_iter() {
            Self::apply(value, &mut stops, &mut cursor, &mut o);
        }
        stops.sort_by_key(|x| x.0);
        stops.iter_mut().for_each(|x| x.1.manipulate(|x| x + at));
        let last = stops.try_remove(0);
        Some((Snippet { last: last.map(|x| x.1), stops, index: 0 }, o))
    }
    pub fn manipulate(&mut self, f: impl FnMut(usize) -> usize + Clone) {
        self.stops.iter_mut().for_each(|x| x.1.manipulate(f.clone()));
        self.last.as_mut().map(|x| x.manipulate(f));
    }
    pub fn next(&mut self) -> Option<StopP> {
        self.stops.get(self.index).map(|x| {
            self.index += 1;
            x.1.clone()
        })
    }
    pub fn list(&self) -> impl Iterator<Item = StopP> {
        self.stops
            .iter()
            .skip(self.index)
            .map(|x| &x.1)
            .chain(self.last.iter())
            .cloned()
    }

    pub fn apply(
        x: SnippetElement,
        stops: &mut Vec<(Stop, StopP)>,
        cursor: &mut usize,
        text: &mut String,
    ) {
        match x {
            SnippetElement::Tabstop { tabstop, transform: None } =>
                stops.push((tabstop, StopP::Just(*cursor))),
            SnippetElement::Placeholder { tabstop, value } => {
                let start = *cursor;
                for value in value {
                    Self::apply(value, stops, cursor, text)
                }
                stops.push((tabstop, StopP::Range(start..*cursor)))
            }
            SnippetElement::Choice { tabstop, choices } => {
                let start = *cursor;
                text.push_str(&choices[0]);
                *cursor += choices[0].chars().count();
                stops.push((tabstop, StopP::Range(start..*cursor)))
            }
            SnippetElement::Text(x) => {
                text.push_str(&x);
                *cursor += x.chars().count();
            }
            _ => unimplemented!(),
        }
    }
}
pub type Stop = usize;