ParaDocs/src/editor_hard.cpp
PoliEcho dded22125c
Some checks failed
build_test / build (push) Failing after 2m49s
add hard editor
2025-06-02 20:26:58 +02:00

190 lines
5.0 KiB
C++

#include <ncurses.h>
#include <cstddef>
#include <cstdint>
#include <nlohmann/json.hpp>
#include <nlohmann/json_fwd.hpp>
#include <sstream>
#include <string>
#include <vector>
#include "strings.h"
using nlohmann::json;
void save_document(std::string& text, std::vector<std::string>& lines) {
text = "";
for (const std::string& line : lines) {
text.append(line);
text.append("\n");
}
}
void editor_hard(std::string& text) {
uint16_t cursor_x = 0;
uint16_t cursor_y = 0;
std::vector<std::string> lines;
char mode = 'n';
uint16_t window_height, window_width;
mode = 'n';
noecho();
curs_set(1);
cbreak();
keypad(stdscr, TRUE);
getmaxyx(stdscr, window_height, window_width);
// Parse the multi-line string into individual lines
lines.clear();
std::stringstream ss(text);
std::string line;
while (std::getline(ss, line)) {
lines.push_back(line);
}
// Ensure at least one empty line exists
if (lines.empty()) {
lines.push_back("");
}
while (true) {
clear();
// Draw text lines
for (size_t i = 0; i < window_height - 1 && i < lines.size(); i++) {
mvprintw(i, 0, "%s", lines[i].c_str());
}
// Draw status line
std::string status = "Mode: " + std::string(1, mode);
mvprintw(window_height - 1, 0, "%s", status.c_str());
move(cursor_y, cursor_x);
refresh();
{
int ch = getch();
switch (mode) {
case 'n': // Normal mode
switch (ch) {
case 'h':
if (cursor_x > 0) {
cursor_x--;
}
break;
case 'j':
if (cursor_y < lines.size() - 1) {
cursor_y++;
if (cursor_x > lines[cursor_y].length()) {
cursor_x = lines[cursor_y].length();
}
}
break;
case 'k':
if (cursor_y > 0) {
cursor_y--;
if (cursor_x > lines[cursor_y].length()) {
cursor_x = lines[cursor_y].length();
}
}
break;
case 'l':
if (cursor_x < lines[cursor_y].length()) {
cursor_x++;
}
break;
case 'i':
case 'a':
mode = 'i';
break;
case 'x':
if (cursor_x < lines[cursor_y].length()) {
lines[cursor_y].erase(cursor_x, 1);
}
break;
case ':': {
// Enter command mode
std::string command = "";
int cmd_ch;
// Show command prompt
mvprintw(window_height - 1, 0, ":%s", command.c_str());
clrtoeol();
refresh();
while ((cmd_ch = getch()) != '\n' && cmd_ch != '\r') {
if (cmd_ch == 27) { // ESC - cancel command
break;
} else if (cmd_ch == KEY_BACKSPACE || cmd_ch == 127) {
if (!command.empty()) {
command.pop_back();
}
} else if (cmd_ch >= 32 && cmd_ch <= 126) {
command += static_cast<char>(cmd_ch);
}
mvprintw(window_height - 1, 0, ":%s", command.c_str());
clrtoeol();
refresh();
}
// Execute command
if (cmd_ch != 27) { // If not cancelled
switch (hash_djb2a(command)) {
case "q"_sh:
return;
break;
case "w"_sh:
save_document(text, lines);
break;
case "wq"_sh:
case "x"_sh:
save_document(text, lines);
return;
break;
case "q!"_sh:
return;
break;
}
}
} break;
}
break;
case 'i': // Insert mode
switch (ch) {
case 27: // ESC
mode = 'n';
if (cursor_x > 0)
cursor_x--;
break;
case KEY_BACKSPACE:
case 127:
if (mode == 'i' && cursor_x > 0) {
lines[cursor_y].erase(cursor_x - 1, 1);
cursor_x--;
}
break;
case '\n':
case '\r': {
// Insert new line
std::string new_line = lines[cursor_y].substr(cursor_x);
lines[cursor_y] = lines[cursor_y].substr(0, cursor_x);
lines.insert(lines.begin() + cursor_y + 1, new_line);
cursor_y++;
cursor_x = 0;
break;
}
default:
if (ch >= 32 && ch <= 126) {
if (mode == 'i') {
lines[cursor_y].insert(cursor_x, 1, ch);
cursor_x++;
}
}
break;
}
break;
}
}
}
}