yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
vim_mode.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cctype>
5#include <iostream>
6
7#ifdef _WIN32
8#include <conio.h>
9#else
10#include <termios.h>
11#include <unistd.h>
12#endif
13
14namespace yaze {
15namespace cli {
16namespace agent {
17
18namespace {
19
20// Key codes for special keys
21constexpr int KEY_ESC = 27;
22constexpr int KEY_ENTER = 10;
23constexpr int KEY_BACKSPACE = 127;
24constexpr int KEY_CTRL_P = 16;
25constexpr int KEY_CTRL_N = 14;
26constexpr int KEY_TAB = 9;
27
28// Terminal control sequences
29const char* CLEAR_LINE = "\033[2K\r";
30const char* MOVE_CURSOR_HOME = "\r";
31const char* SAVE_CURSOR = "\033[s";
32const char* RESTORE_CURSOR = "\033[u";
33
34#ifndef _WIN32
35// Set terminal to raw mode (character-by-character input)
36void SetRawMode(bool enable) {
37 static struct termios orig_termios;
38 static bool has_orig = false;
39
40 if (enable) {
41 if (!has_orig) {
42 tcgetattr(STDIN_FILENO, &orig_termios);
43 has_orig = true;
44 }
45
46 struct termios raw = orig_termios;
47 raw.c_lflag &= ~(ECHO | ICANON); // Disable echo and canonical mode
48 raw.c_cc[VMIN] = 1; // Read at least 1 character
49 raw.c_cc[VTIME] = 0; // No timeout
50 tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
51 } else {
52 if (has_orig) {
53 tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
54 }
55 }
56}
57#endif
58
59} // namespace
60
62#ifndef _WIN32
63 SetRawMode(true);
64#endif
65}
66
67std::string VimMode::GetModeString() const {
68 switch (mode_) {
70 return "NORMAL";
72 return "INSERT";
74 return "VISUAL";
76 return "COMMAND";
77 }
78 return "UNKNOWN";
79}
80
82 current_line_.clear();
83 cursor_pos_ = 0;
84 line_complete_ = false;
85 redo_stack_.clear();
86}
87
88void VimMode::AddToHistory(const std::string& line) {
89 if (!line.empty()) {
90 history_.push_back(line);
91 history_index_ = -1; // Reset to no history selection
92 }
93}
94
95bool VimMode::ProcessKey(int ch) {
96 line_complete_ = false;
97
98 switch (mode_) {
101 break;
104 break;
106 // Visual mode not yet implemented
108 break;
110 // Command line mode not yet implemented
111 if (ch == KEY_ESC) {
113 }
114 break;
115 }
116
117 return line_complete_;
118}
119
121 if (new_mode != mode_) {
122 mode_ = new_mode;
123 Render(); // Redraw with new mode indicator
124 }
125}
126
128 switch (ch) {
129 // Enter insert mode
130 case 'i':
132 break;
133 case 'a':
134 MoveRight();
136 break;
137 case 'o':
138 // Insert new line below (just append and go to insert mode)
141 break;
142 case 'O':
143 // Insert new line above (go to beginning and insert mode)
146 break;
147
148 // Movement
149 case 'h':
150 MoveLeft();
151 break;
152 case 'l':
153 MoveRight();
154 break;
155 case 'w':
157 break;
158 case 'b':
160 break;
161 case '0':
163 break;
164 case '$':
166 break;
167
168 // Editing
169 case 'x':
170 DeleteChar();
171 break;
172 case 'd':
173 // Simple implementation: dd deletes line
174 {
175 int next_ch;
176#ifdef _WIN32
177 next_ch = _getch();
178#else
179 read(STDIN_FILENO, &next_ch, 1);
180#endif
181 if (next_ch == 'd') {
182 DeleteLine();
183 }
184 }
185 break;
186 case 'y':
187 // yy yanks line
188 {
189 int next_ch;
190#ifdef _WIN32
191 next_ch = _getch();
192#else
193 read(STDIN_FILENO, &next_ch, 1);
194#endif
195 if (next_ch == 'y') {
196 YankLine();
197 }
198 }
199 break;
200 case 'p':
201 PasteAfter();
202 break;
203 case 'P':
204 PasteBefore();
205 break;
206 case 'u':
207 Undo();
208 break;
209 case KEY_CTRL_P:
210 case 'k':
211 HistoryPrev();
212 break;
213 case KEY_CTRL_N:
214 case 'j':
215 HistoryNext();
216 break;
217
218 // Accept line (Enter in normal mode)
219 case KEY_ENTER:
220 line_complete_ = true;
221 break;
222
223 // Command mode
224 case ':':
226 break;
227 }
228
229 Render();
230}
231
233 switch (ch) {
234 case KEY_ESC:
236 if (cursor_pos_ > 0) {
237 cursor_pos_--; // Vim moves cursor left on ESC
238 }
239 break;
240 case KEY_ENTER:
241 line_complete_ = true;
242 break;
243 case KEY_BACKSPACE:
244 case 8: // Ctrl+H
245 Backspace();
246 break;
247 case KEY_TAB:
248 Complete();
249 break;
250 case KEY_CTRL_P:
251 HistoryPrev();
252 break;
253 case KEY_CTRL_N:
254 HistoryNext();
255 break;
256 default:
257 if (ch >= 32 && ch < 127) { // Printable ASCII
258 InsertChar(static_cast<char>(ch));
259 }
260 break;
261 }
262
263 if (!line_complete_) {
264 Render();
265 }
266}
267
268// Movement implementations
270 if (cursor_pos_ > 0) {
271 cursor_pos_--;
272 }
273}
274
276 if (cursor_pos_ < static_cast<int>(current_line_.length())) {
277 cursor_pos_++;
278 }
279}
280
282 while (cursor_pos_ < static_cast<int>(current_line_.length()) &&
283 !std::isspace(current_line_[cursor_pos_])) {
284 cursor_pos_++;
285 }
286 while (cursor_pos_ < static_cast<int>(current_line_.length()) &&
287 std::isspace(current_line_[cursor_pos_])) {
288 cursor_pos_++;
289 }
290}
291
293 if (cursor_pos_ > 0)
294 cursor_pos_--;
295 while (cursor_pos_ > 0 && std::isspace(current_line_[cursor_pos_])) {
296 cursor_pos_--;
297 }
298 while (cursor_pos_ > 0 && !std::isspace(current_line_[cursor_pos_ - 1])) {
299 cursor_pos_--;
300 }
301}
302
306
310
311// Editing implementations
313 if (cursor_pos_ < static_cast<int>(current_line_.length())) {
314 undo_stack_.push_back(current_line_);
315 current_line_.erase(cursor_pos_, 1);
316 }
317}
318
320 undo_stack_.push_back(current_line_);
322 current_line_.clear();
323 cursor_pos_ = 0;
324}
325
329
331 if (!yank_buffer_.empty()) {
332 undo_stack_.push_back(current_line_);
334 }
335}
336
338 if (!yank_buffer_.empty()) {
339 undo_stack_.push_back(current_line_);
340 if (cursor_pos_ < static_cast<int>(current_line_.length())) {
341 cursor_pos_++;
342 }
344 cursor_pos_ += yank_buffer_.length() - 1;
345 }
346}
347
349 if (!undo_stack_.empty()) {
350 redo_stack_.push_back(current_line_);
351 current_line_ = undo_stack_.back();
352 undo_stack_.pop_back();
354 std::min(cursor_pos_, static_cast<int>(current_line_.length()));
355 }
356}
357
359 if (!redo_stack_.empty()) {
360 undo_stack_.push_back(current_line_);
361 current_line_ = redo_stack_.back();
362 redo_stack_.pop_back();
364 std::min(cursor_pos_, static_cast<int>(current_line_.length()));
365 }
366}
367
369 undo_stack_.push_back(current_line_);
370 current_line_.insert(cursor_pos_, 1, c);
371 cursor_pos_++;
372}
373
375 if (cursor_pos_ > 0) {
376 undo_stack_.push_back(current_line_);
377 current_line_.erase(cursor_pos_ - 1, 1);
378 cursor_pos_--;
379 }
380}
381
383 DeleteChar();
384}
385
389 if (!autocomplete_options_.empty()) {
390 // Simple implementation: insert first suggestion
391 std::string completion = autocomplete_options_[0];
392 undo_stack_.push_back(current_line_);
393 current_line_ = completion;
394 cursor_pos_ = completion.length();
395 }
396 }
397}
398
399// History navigation
401 if (history_.empty())
402 return;
403
404 if (history_index_ == -1) {
405 history_index_ = history_.size() - 1;
406 } else if (history_index_ > 0) {
408 }
409
411 cursor_pos_ = current_line_.length();
412}
413
415 if (history_.empty() || history_index_ == -1)
416 return;
417
418 if (history_index_ < static_cast<int>(history_.size()) - 1) {
421 } else {
422 history_index_ = -1;
423 current_line_.clear();
424 }
425
426 cursor_pos_ = current_line_.length();
427}
428
429void VimMode::Render() const {
430 // Clear line and redraw
431 std::cout << CLEAR_LINE;
432
433 // Show mode indicator
434 if (mode_ == VimModeType::INSERT) {
435 std::cout << "-- INSERT -- ";
436 } else if (mode_ == VimModeType::NORMAL) {
437 std::cout << "-- NORMAL -- ";
438 } else if (mode_ == VimModeType::COMMAND_LINE) {
439 std::cout << ":";
440 }
441
442 // Show prompt and line
443 std::cout << current_line_;
444
445 // Move cursor to correct position
446 int display_offset =
447 (mode_ == VimModeType::INSERT ? 13 : 13); // Length of "-- INSERT -- "
448 std::cout << "\r";
449 for (int i = 0; i < display_offset + cursor_pos_; ++i) {
450 std::cout << "\033[C"; // Move cursor right
451 }
452
453 std::cout.flush();
454}
455
456} // namespace agent
457} // namespace cli
458} // namespace yaze
std::function< std::vector< std::string >(const std::string &) autocomplete_callback_)
Definition vim_mode.h:147
std::vector< std::string > redo_stack_
Definition vim_mode.h:140
void HandleInsertMode(int ch)
Definition vim_mode.cc:232
void SwitchMode(VimModeType new_mode)
Definition vim_mode.cc:120
bool ProcessKey(int ch)
Process a key press.
Definition vim_mode.cc:95
void HandleNormalMode(int ch)
Definition vim_mode.cc:127
void Reset()
Reset for new line.
Definition vim_mode.cc:81
std::string GetModeString() const
Get mode string for display.
Definition vim_mode.cc:67
std::vector< std::string > autocomplete_options_
Definition vim_mode.h:149
std::vector< std::string > history_
Definition vim_mode.h:135
void Render() const
Render the current line with syntax highlighting.
Definition vim_mode.cc:429
std::string current_line_
Definition vim_mode.h:131
void AddToHistory(const std::string &line)
Add line to history.
Definition vim_mode.cc:88
std::vector< std::string > undo_stack_
Definition vim_mode.h:139
VimModeType
Vim editing modes.
Definition vim_mode.h:16