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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
use crate::{
    buffer::BufferHandle,
    buffer_view::{BufferView, BufferViewCollection},
    client::{ClientManager, TargetClient},
    cursor::Cursor,
    editor::Editor,
};

pub enum NavigationDirection {
    Forward,
    Backward,
}

#[derive(Clone, Copy)]
struct NavigationHistorySnapshot {
    buffer_handle: BufferHandle,
    cursor_range: (usize, usize),
}

enum NavigationState {
    IterIndex(usize),
    Insert,
}

pub struct NavigationHistory {
    cursors: Vec<Cursor>,
    snapshots: Vec<NavigationHistorySnapshot>,
    state: NavigationState,
}

impl NavigationHistory {
    pub fn save_client_snapshot(
        clients: &mut ClientManager,
        target: TargetClient,
        buffer_views: &BufferViewCollection,
    ) {
        let client = match clients.get_mut(target) {
            Some(client) => client,
            None => return,
        };
        let view_handle = match client.buffer_view_handle() {
            Some(handle) => handle,
            None => return,
        };
        let buffer_view = match buffer_views.get(view_handle) {
            Some(view) => view,
            None => return,
        };

        client.navigation_history.add_snapshot(buffer_view);
    }

    fn add_snapshot(&mut self, buffer_view: &BufferView) {
        let buffer_handle = buffer_view.buffer_handle;
        let cursors = &buffer_view.cursors[..];

        if let NavigationState::IterIndex(index) = self.state {
            self.snapshots.truncate(index);
        }
        self.state = NavigationState::Insert;

        if let Some(last) = self.snapshots.last() {
            if last.buffer_handle == buffer_handle {
                let same_cursors = cursors
                    .iter()
                    .zip(self.cursors[last.cursor_range.0..last.cursor_range.1].iter())
                    .all(|(a, b)| *a == *b);
                if same_cursors {
                    return;
                }
            }
        }

        let cursors_start_index = self.cursors.len();
        for c in cursors {
            self.cursors.push(*c);
        }

        self.snapshots.push(NavigationHistorySnapshot {
            buffer_handle,
            cursor_range: (cursors_start_index, self.cursors.len()),
        });
    }

    pub fn move_in_history(
        editor: &mut Editor,
        clients: &mut ClientManager,
        target: TargetClient,
        direction: NavigationDirection,
    ) {
        let client = match clients.get_mut(target) {
            Some(client) => client,
            None => return,
        };

        let current_buffer_view_handle = client.buffer_view_handle();

        let history = &mut client.navigation_history;
        let mut history_index = match history.state {
            NavigationState::IterIndex(index) => index,
            NavigationState::Insert => history.snapshots.len(),
        };

        let snapshot = match direction {
            NavigationDirection::Forward => {
                if history_index + 1 >= history.snapshots.len() {
                    return;
                }

                history_index += 1;
                let snapshot = history.snapshots[history_index];
                snapshot
            }
            NavigationDirection::Backward => {
                if history_index == 0 {
                    return;
                }

                if history_index == history.snapshots.len() {
                    if let Some(buffer_view) =
                        current_buffer_view_handle.and_then(|h| editor.buffer_views.get(h))
                    {
                        history.add_snapshot(buffer_view)
                    }
                }

                history_index -= 1;
                history.snapshots[history_index]
            }
        };

        history.state = NavigationState::IterIndex(history_index);

        let view_handle = editor
            .buffer_views
            .buffer_view_handle_from_buffer_handle(target, snapshot.buffer_handle);
        let mut cursors = match editor.buffer_views.get_mut(view_handle) {
            Some(view) => view.cursors.mut_guard(),
            None => return,
        };
        cursors.clear();
        for cursor in history.cursors[snapshot.cursor_range.0..snapshot.cursor_range.1].iter() {
            cursors.add(*cursor);
        }
        drop(cursors);

        clients.set_buffer_view_handle(editor, target, Some(view_handle));
    }

    pub fn remove_snapshots_with_buffer_handle(&mut self, buffer_handle: BufferHandle) {
        for i in (0..self.snapshots.len()).rev() {
            let snapshot = self.snapshots[i];
            if snapshot.buffer_handle == buffer_handle {
                self.cursors
                    .drain(snapshot.cursor_range.0..snapshot.cursor_range.1);
                self.snapshots.remove(i);

                let cursor_range_len = snapshot.cursor_range.1 - snapshot.cursor_range.0;
                for s in &mut self.snapshots[i..] {
                    if s.cursor_range.0 >= snapshot.cursor_range.1 {
                        s.cursor_range.0 -= cursor_range_len;
                        s.cursor_range.1 -= cursor_range_len;
                    }
                }

                if let NavigationState::IterIndex(index) = &mut self.state {
                    if i <= *index && *index > 0 {
                        *index -= 1;
                    }
                }
            }
        }
    }
}

impl Default for NavigationHistory {
    fn default() -> Self {
        Self {
            cursors: Vec::default(),
            snapshots: Vec::default(),
            state: NavigationState::IterIndex(0),
        }
    }
}