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) cursor_pos_--;
294 while (cursor_pos_ > 0 && std::isspace(current_line_[cursor_pos_])) {
295 cursor_pos_--;
296 }
297 while (cursor_pos_ > 0 && !std::isspace(current_line_[cursor_pos_ - 1])) {
298 cursor_pos_--;
299 }
300}
301
305
309
310// Editing implementations
312 if (cursor_pos_ < static_cast<int>(current_line_.length())) {
313 undo_stack_.push_back(current_line_);
314 current_line_.erase(cursor_pos_, 1);
315 }
316}
317
319 undo_stack_.push_back(current_line_);
321 current_line_.clear();
322 cursor_pos_ = 0;
323}
324
328
330 if (!yank_buffer_.empty()) {
331 undo_stack_.push_back(current_line_);
333 }
334}
335
337 if (!yank_buffer_.empty()) {
338 undo_stack_.push_back(current_line_);
339 if (cursor_pos_ < static_cast<int>(current_line_.length())) {
340 cursor_pos_++;
341 }
343 cursor_pos_ += yank_buffer_.length() - 1;
344 }
345}
346
348 if (!undo_stack_.empty()) {
349 redo_stack_.push_back(current_line_);
350 current_line_ = undo_stack_.back();
351 undo_stack_.pop_back();
352 cursor_pos_ = std::min(cursor_pos_, static_cast<int>(current_line_.length()));
353 }
354}
355
357 if (!redo_stack_.empty()) {
358 undo_stack_.push_back(current_line_);
359 current_line_ = redo_stack_.back();
360 redo_stack_.pop_back();
361 cursor_pos_ = std::min(cursor_pos_, static_cast<int>(current_line_.length()));
362 }
363}
364
366 undo_stack_.push_back(current_line_);
367 current_line_.insert(cursor_pos_, 1, c);
368 cursor_pos_++;
369}
370
372 if (cursor_pos_ > 0) {
373 undo_stack_.push_back(current_line_);
374 current_line_.erase(cursor_pos_ - 1, 1);
375 cursor_pos_--;
376 }
377}
378
380 DeleteChar();
381}
382
386 if (!autocomplete_options_.empty()) {
387 // Simple implementation: insert first suggestion
388 std::string completion = autocomplete_options_[0];
389 undo_stack_.push_back(current_line_);
390 current_line_ = completion;
391 cursor_pos_ = completion.length();
392 }
393 }
394}
395
396// History navigation
398 if (history_.empty()) return;
399
400 if (history_index_ == -1) {
401 history_index_ = history_.size() - 1;
402 } else if (history_index_ > 0) {
404 }
405
407 cursor_pos_ = current_line_.length();
408}
409
411 if (history_.empty() || history_index_ == -1) return;
412
413 if (history_index_ < static_cast<int>(history_.size()) - 1) {
416 } else {
417 history_index_ = -1;
418 current_line_.clear();
419 }
420
421 cursor_pos_ = current_line_.length();
422}
423
424void VimMode::Render() const {
425 // Clear line and redraw
426 std::cout << CLEAR_LINE;
427
428 // Show mode indicator
429 if (mode_ == VimModeType::INSERT) {
430 std::cout << "-- INSERT -- ";
431 } else if (mode_ == VimModeType::NORMAL) {
432 std::cout << "-- NORMAL -- ";
433 } else if (mode_ == VimModeType::COMMAND_LINE) {
434 std::cout << ":";
435 }
436
437 // Show prompt and line
438 std::cout << current_line_;
439
440 // Move cursor to correct position
441 int display_offset = (mode_ == VimModeType::INSERT ? 13 : 13); // Length of "-- INSERT -- "
442 std::cout << "\r";
443 for (int i = 0; i < display_offset + cursor_pos_; ++i) {
444 std::cout << "\033[C"; // Move cursor right
445 }
446
447 std::cout.flush();
448}
449
450} // namespace agent
451} // namespace cli
452} // namespace yaze
std::vector< std::string > redo_stack_
Definition vim_mode.h:138
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:146
std::vector< std::string > history_
Definition vim_mode.h:133
void Render() const
Render the current line with syntax highlighting.
Definition vim_mode.cc:424
std::string current_line_
Definition vim_mode.h:129
void AddToHistory(const std::string &line)
Add line to history.
Definition vim_mode.cc:88
std::function< std::vector< std::string >(const std::string &)> autocomplete_callback_
Definition vim_mode.h:144
std::vector< std::string > undo_stack_
Definition vim_mode.h:137
VimModeType
Vim editing modes.
Definition vim_mode.h:16
Main namespace for the application.