Skip to main content

accepted/
buffer_mode.rs

1use crate::buffer::Buffer;
2use crate::core::CoreBuffer;
3use crate::draw;
4use crate::mode::{Mode, Normal, Transition, TransitionReturn};
5use futures::future::{FutureExt, LocalBoxFuture};
6
7pub struct BufferMode<'a, B: CoreBuffer> {
8    pub buf: Buffer<'a, B>,
9    mode: Box<dyn Mode<B>>,
10    is_recording: bool,
11    dot_macro: Vec<termion::event::Event>,
12    recording_macro: Vec<termion::event::Event>,
13}
14
15pub enum TabOperation {
16    Nothing,
17    Close,
18    NewTab,
19    ChangeTab(usize),
20    StartRmate,
21}
22
23impl<'a, B: CoreBuffer> BufferMode<'a, B> {
24    pub fn new(buf: Buffer<'a, B>) -> Self {
25        Self {
26            buf,
27            mode: Box::new(Normal::default()),
28            is_recording: false,
29            dot_macro: Vec::new(),
30            recording_macro: Vec::new(),
31        }
32    }
33
34    pub fn event(&mut self, event: termion::event::Event) -> LocalBoxFuture<'_, TabOperation> {
35        async move {
36            if self.is_recording {
37                self.recording_macro.push(event.clone());
38            }
39            match self.mode.event(&mut self.buf, event.clone()).await {
40                Transition::Exit => {
41                    return TabOperation::Close;
42                }
43                Transition::Trans(mut t) => {
44                    t.init(&mut self.buf);
45                    self.mode = t;
46                }
47                Transition::DoMacro => {
48                    for event in self.dot_macro.clone() {
49                        self.event(event).await;
50                    }
51                }
52                Transition::Return(TransitionReturn {
53                    message,
54                    is_commit_dot_macro,
55                }) => {
56                    if self.is_recording && !self.recording_macro.is_empty() && is_commit_dot_macro
57                    {
58                        std::mem::swap(&mut self.dot_macro, &mut self.recording_macro);
59                        self.recording_macro.clear();
60                    }
61                    self.is_recording = false;
62                    let mut t = if let Some(s) = message {
63                        Box::new(Normal::with_message(s))
64                    } else {
65                        Box::new(Normal::default())
66                    };
67                    t.init(&mut self.buf);
68                    self.mode = t;
69                }
70                Transition::RecordMacro(mut t) => {
71                    self.is_recording = true;
72                    self.recording_macro.clear();
73                    self.recording_macro.push(event);
74                    t.init(&mut self.buf);
75                    self.mode = t;
76                }
77                Transition::CreateNewTab => {
78                    self.mode = Box::new(Normal::default());
79                    return TabOperation::NewTab;
80                }
81                Transition::ChangeTab(i) => {
82                    self.mode = Box::new(Normal::default());
83                    return TabOperation::ChangeTab(i);
84                }
85                Transition::StartRmate => {
86                    self.mode = Box::new(Normal::default());
87                    return TabOperation::StartRmate;
88                }
89                Transition::Nothing => {}
90            }
91            TabOperation::Nothing
92        }
93        .boxed_local()
94    }
95
96    pub fn draw(&mut self, view: draw::TermView) -> draw::CursorState {
97        self.mode.draw(&mut self.buf, view)
98    }
99
100    /// This method should be called every frame
101    pub fn background_task_duration(&mut self, duration: std::time::Duration) {
102        self.buf.extend_cache_duration(duration);
103    }
104}