sl_liner/
editor_rules.rs

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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! Provides [DefaultEditorRules] for editor behaviors with custom override function.
//! See [NewlineRule] and [WordDivideRule], the traits that compose editor behaviors.
use crate::Buffer;

/// When the client inputs the newline character, '\n', the Editor can decide to *not* evalute the
/// newline if the provided implementation of this trait returns false. Default prevents evaluate
/// if the last non whitespace character is a backslash.
pub trait NewlineRule {
    fn evaluate_on_newline(&self, buf: &Buffer) -> bool {
        last_non_ws_char_was_not_backslash(buf)
    }
}

/// Default NewlineRule implementation.
pub fn last_non_ws_char_was_not_backslash(buf: &Buffer) -> bool {
    let mut found_backslash = false;
    for x in buf.range_graphemes_all().rev() {
        if x == " " {
            continue;
        } else if x == "\\" {
            found_backslash = true;
            break;
        } else {
            break;
        }
    }
    // if the last non-whitespace character was not a backslash then we can evaluate the line, as
    // backslash is the user's way of indicating intent to insert a new line
    !found_backslash
}

/// When the Editor is trying to place the term cursor it needs to know how to divide the words to
/// determine its [CursorPosition] state.
pub trait WordDivideRule {
    fn divide_words(&self, buf: &Buffer) -> Vec<(usize, usize)> {
        divide_words_by_space(buf)
    }
}

/// Default WordDivideRule implementation.
pub fn divide_words_by_space(buf: &Buffer) -> Vec<(usize, usize)> {
    let mut res = Vec::new();

    let mut word_start = None;
    let mut just_had_backslash = false;

    let buf_vec = buf.range_graphemes_all();
    for (i, c) in buf_vec.enumerate() {
        if c == "\\" {
            just_had_backslash = true;
            continue;
        }

        if let Some(start) = word_start {
            if c == " " && !just_had_backslash {
                res.push((start, i));
                word_start = None;
            }
        } else if c != " " {
            word_start = Some(i);
        }

        just_had_backslash = false;
    }

    if let Some(start) = word_start {
        res.push((start, buf.num_graphemes()));
    }

    res
}

/// Trait that implements all editor rule behaviors, a mechanism to allow modification of the
/// library's behavior at runtime.
pub trait EditorRules
where
    Self: WordDivideRule + NewlineRule,
{
}

/// Provides default editor behavior and provides custom override function.
pub struct DefaultEditorRules<T, U>
where
    T: WordDivideRule,
    U: NewlineRule,
{
    word_divider_rule: T,
    newline_rule: U,
}

impl Default for DefaultEditorRules<DefaultWordDivideRule, DefaultNewlineRule> {
    fn default() -> Self {
        Self::new()
    }
}

impl DefaultEditorRules<DefaultWordDivideRule, DefaultNewlineRule> {
    pub fn new() -> Self {
        DefaultEditorRules {
            word_divider_rule: DefaultWordDivideRule {},
            newline_rule: DefaultNewlineRule {},
        }
    }
}

impl<T, U> EditorRules for DefaultEditorRules<T, U>
where
    T: WordDivideRule,
    U: NewlineRule,
{
}

impl<T, U> DefaultEditorRules<T, U>
where
    T: WordDivideRule,
    U: NewlineRule,
{
    pub fn custom(t: T, u: U) -> Self {
        DefaultEditorRules {
            word_divider_rule: t,
            newline_rule: u,
        }
    }
}

/// Struct with default newline behavior
pub struct DefaultNewlineRule;
impl NewlineRule for DefaultNewlineRule {}

/// Struct with default word divide behavior
pub struct DefaultWordDivideRule;
impl WordDivideRule for DefaultWordDivideRule {}

impl<T, U> NewlineRule for DefaultEditorRules<T, U>
where
    T: WordDivideRule,
    U: NewlineRule,
{
    fn evaluate_on_newline(&self, buf: &Buffer) -> bool {
        self.newline_rule.evaluate_on_newline(buf)
    }
}

impl<T, U> WordDivideRule for DefaultEditorRules<T, U>
where
    T: WordDivideRule,
    U: NewlineRule,
{
    fn divide_words(&self, buf: &Buffer) -> Vec<(usize, usize)> {
        self.word_divider_rule.divide_words(buf)
    }
}