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
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
#![allow(unused_parens, unused_variables, dead_code)]

use Default::default;
use NamedKey::*;
use lsp_types::*;
use regex::Regex;
use winit::event::MouseButton;
use winit::keyboard::{Key, NamedKey, SmolStr};

use crate::commands::Commands;
use crate::edi::handle2;
use crate::lsp::{AQErr, Rq, RqS};
use crate::sym::{Symbols, SymbolsList};
use crate::text::TextArea;
use crate::{
    BoolRequest, CLICKING, InputRequest, act, alt, ctrl, handle, shift,
};

impl Default for State {
    fn default() -> Self {
        Self::Default
    }
}
#[derive(Debug, Copy, Clone)]
pub enum Direction {
    Above,
    Below,
}
#[derive(Debug, Copy, Clone)]
pub enum LR {
    Left,
    Right,
}
rust_fsm::state_machine! {
#[derive(Debug)]
pub(crate) State => #[derive(Debug)] pub(crate) Action => #[derive(Debug)] pub(crate) Do

Dead => K(Key => _) => Dead,
Default => {
    K(Key::Character(x) if x == "s" && ctrl()) => Save [Save],
    K(Key::Character(x) if x == "q" && ctrl()) => Dead [Quit],
    K(Key::Character(x) if x == "v" && ctrl()) => _ [Paste],
    K(Key::Character(x) if x == "z" && ctrl()) => _ [Undo],
    K(Key::Character(x) if x == "y" && ctrl()) => _ [Redo],
    K(Key::Character(x) if x == "f" && ctrl()) => Procure((default(), InputRequest::Search)),
    K(Key::Character(x) if x == "o" && ctrl()) => Procure((default(), InputRequest::OpenFile)),
    K(Key::Character(x) if x == "c" && ctrl()) => _,
    K(Key::Character(x) if x == "l" && ctrl()) => _ [Symbols],
    K(Key::Character(x) if x == "." && ctrl()) => _ [CodeAction],
    K(Key::Character(x) if x == "0" && ctrl()) => _ [MatchingBrace],
    K(Key::Character(x) if x == "`" && ctrl()) => _ [SpawnTerminal],
    K(Key::Character(y) if y == "/" && ctrl()) => Default [Comment(State => State::Default)],
    K(Key::Character(x) if x == "p" && ctrl()) => Command(Commands => Commands::default()),
    K(Key::Named(F1)) => Procure((default(), InputRequest::RenameSymbol)),
    K(Key::Named(k @ (ArrowUp | ArrowDown)) if alt()) => _ [InsertCursor(Direction => {
        if k == ArrowUp {Direction::Above} else { Direction::Below }
    })],
    K(Key::Named(ArrowUp | ArrowLeft | ArrowDown | ArrowRight | Home | End) if shift()) => Selection [StartSelection],
    M(MouseButton::Left if shift()) => Selection [StartSelection],
    M(MouseButton::Left if alt()) => _ [InsertCursorAtMouse],
    M(MouseButton::Left if ctrl()) => _ [GoToDefinition],
    M(MouseButton::Left) => _ [MoveCursor],
    K(Key::Character(x) if x == "-" && ctrl()) => _ [NavBack],
    K(Key::Character(x) if x == "=" && ctrl()) => _ [NavBack],
    M(MouseButton::Back) => _ [NavBack],
    M(MouseButton::Forward) => _ [NavForward],
    C(((usize, usize)) => .. if unsafe { CLICKING }) => Selection [StartSelection],
    Changed => RequestBoolean(BoolRequest => BoolRequest::ReloadFile),
    K(Key::Named(Escape)) => _ [Escape],
    C(_) => _ [Hover],
    K(_) => _ [Edit],
    M(_) => _,
},
Command(_) => K(Key::Named(Escape)) => Default,
Command(t) => K(Key::Named(Enter)) => Default [ProcessCommand(Commands => t)],
Command(mut t) => K(Key::Named(Tab) if shift()) => Command({ t.back();t }),
Command(mut t) => K(Key::Named(Tab)) => Command({ t.next(); t }),
Command(mut t) => K(k) => Command({ handle2(&k, &mut t.tedit, None); t }),
Command(t) => C(_) => _,
Command(t) => K(_) => _,
Symbols(Rq { result: Some(_x), request: _rq }) => {
    K(Key::Named(Tab) if shift()) => _ [SymbolsSelectNext],
    K(Key::Named(ArrowDown)) => _ [SymbolsSelectNext],
    K(Key::Named(ArrowUp | Tab)) => _ [SymbolsSelectPrev],
    K(Key::Named(Enter)) => _ [SymbolsSelect],
    K(Key::Named(Escape)) => Default,
},
Symbols(Rq::<Symbols, Option<SymbolsList>, (), AQErr> => _rq) => {
    K(Key::Character(x) if x == "d" && ctrl()) => _ [SwitchType], // crahs cond methinks
    K(Key::Named(Escape)) => Default,
    K(_) => _ [SymbolsHandleKey],
    C(_) => _,
    M(_) => _,
},
CodeAction(Rq { result : Some(_x), request }) => {
    K(Key::Named(Tab) if shift()) => _ [CASelectPrev],
    K(Key::Named(ArrowDown | Tab)) => _ [CASelectNext],
    K(Key::Named(ArrowUp)) => _ [CASelectPrev],
    K(Key::Named(Enter | ArrowRight)) => _ [CASelectRight],
    K(Key::Named(ArrowLeft)) => _ [CASelectLeft],
},
CodeAction(RqS<act::CodeActions, lsp_request!("textDocument/codeAction")> => rq) => {
    K(Key::Named(Escape)) => Default,
    C(_) => _,
    M(_) => _,
    K(_) => _,
},
Selection => {
    K(Key::Named(ArrowUp | ArrowLeft | ArrowDown | ArrowRight | Home | End) if shift()) => Selection [UpdateSelection],
    M(MouseButton::Left if shift()) => Selection [ExtendSelectionToMouse],
}, // note: it does in fact fall through. this syntax is not an arm, merely shorthand.
Selection => {
    C(_ if unsafe { CLICKING }) => _ [ExtendSelectionToMouse],
    C(_) => _,
    M(MouseButton => MouseButton::Left) => Default [MoveCursor],
    K(Key::Named(Backspace)) => Default [Delete],
    K(Key::Character(y) if y == "x" && ctrl()) => Default [Cut],
    K(Key::Character(y) if y == "c" && ctrl()) => Default [Copy],
    K(Key::Character(y) if y == "/" && ctrl()) => Default [Comment(State::Selection)],
    M(_) => _,

    K(Key::Character(y) if !ctrl()) => Default [Insert(SmolStr => y)],
    K(Key::Named(ArrowLeft)) => Default [SetCursor(LR => LR::Left)],
    K(Key::Named(ArrowRight)) => Default [SetCursor(LR::Right)],
    K(_) => Default [Edit],
},
Save => {
    RequireFilename => Procure((TextArea, InputRequest) => (default(), InputRequest::SaveFile)),
    Saved => Default,
},
Procure((_, _)) => K(Key::Named(Escape)) => Default,
Procure((t, InputRequest::Search)) => K(Key::Named(Enter)) => Default [StartSearch(String => t.rope.to_string())],
Procure((t, InputRequest::SaveFile)) => K(Key::Named(Enter)) => Default [SaveTo(String => t.rope.to_string())],
Procure((t, InputRequest::OpenFile)) => K(Key::Named(Enter)) => Default [OpenFile(String => t.rope.to_string())],
Procure((t, InputRequest::RenameSymbol)) => K(Key::Named(Enter)) => Default [RenameSymbol(String => t.rope.to_string())],
Procure((t, a)) => K(k) => Procure((handle(k, t), a)),
Procure((t, a)) => C(_) => Procure((t, a)),
RequestBoolean(t) => {
    K(Key::Character(x) if x == "y") => Default [Boolean((BoolRequest, bool) => (t, true))],
    K(Key::Character(x) if x == "n") => Default [Boolean((t, false))],
    K(Key::Named(Escape)) => Default [Boolean((t, false))],
    K(_) => RequestBoolean(t),
    C(_) => _,
    Changed => _,
    M(_) => _,
},
Search((x, y, m)) => {
    M(MouseButton::Left) => Default [MoveCursor],
    C(_) => Search((x, y, m)),
    K(Key::Named(Enter) if shift()) => Search((x, y.checked_sub(1).unwrap_or(m-1), m)) [SearchChanged],
    K(Key::Named(Enter)) => Search((Regex, usize, usize) => (x,   (y+ 1) % m, m)) [SearchChanged],
    K(_) => Default [Reinsert],
}
}