Clean up REPL a bit by moving InputWindow to special class.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
5c086ee066
commit
f328762cd8
|
@ -0,0 +1,177 @@
|
|||
#ifndef MALACHSCRIPT_INPUTWINDOW_HPP
|
||||
#define MALACHSCRIPT_INPUTWINDOW_HPP
|
||||
#include <ncurses.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace MalachScriptRepl {
|
||||
class InputWindow {
|
||||
private:
|
||||
WINDOW* _window;
|
||||
|
||||
std::vector<std::u8string> _lines = {u8""};
|
||||
int _row = 0;
|
||||
int _col = 0;
|
||||
int _rightPos = 0;
|
||||
[[maybe_unused]] int _scroll = 0;
|
||||
|
||||
std::function<void(const std::vector<std::u8string>&)> _onChange;
|
||||
|
||||
public:
|
||||
InputWindow(int height, int width, int y, int x) {
|
||||
_window = newwin(height, width, y, x);
|
||||
keypad(_window, true);
|
||||
}
|
||||
|
||||
inline void RegisterOnChange(std::function<void(const std::vector<std::u8string>&)> listener) {
|
||||
_onChange = listener;
|
||||
}
|
||||
|
||||
inline void Refresh() { wrefresh(_window); }
|
||||
inline void Clear() { wclear(_window); }
|
||||
|
||||
[[nodiscard]] inline int GetInput() const { return wgetch(_window); }
|
||||
inline std::pair<int, int> GetCursorPosition() {
|
||||
int row, col;
|
||||
getyx(_window, row, col);
|
||||
return std::pair<int, int>(row, col);
|
||||
}
|
||||
|
||||
inline void MoveCursorPosition(int row, int col) { wmove(_window, row, col); }
|
||||
|
||||
inline void MoveCursorLeft() {
|
||||
if (_col > 0) {
|
||||
wmove(_window, _row, --_col);
|
||||
_rightPos = _col;
|
||||
}
|
||||
}
|
||||
|
||||
inline void MoveCursorRight() {
|
||||
auto& line = _lines[_row];
|
||||
if (_col < (int)line.size()) {
|
||||
wmove(_window, _row, ++_col);
|
||||
_rightPos = _col;
|
||||
}
|
||||
}
|
||||
|
||||
inline void MoveCursorUp() {
|
||||
if (_row > 0) {
|
||||
_col = _rightPos;
|
||||
if (_col > (int)_lines[_row - 1].size()) {
|
||||
_col = (int)_lines[_row - 1].size();
|
||||
}
|
||||
wmove(_window, --_row, _col);
|
||||
}
|
||||
}
|
||||
|
||||
inline void MoveCursorDown() {
|
||||
if (_row < (int)_lines.size() - 1) {
|
||||
_col = _rightPos;
|
||||
if (_col > (int)_lines[_row + 1].size()) {
|
||||
_col = (int)_lines[_row + 1].size();
|
||||
}
|
||||
wmove(_window, ++_row, _col);
|
||||
}
|
||||
}
|
||||
|
||||
inline void Backspace() {
|
||||
if (_col > 0) {
|
||||
mvwdelch(_window, _row, --_col);
|
||||
auto& line = _lines[_row];
|
||||
line = line.erase(_col, 1);
|
||||
_onChange(_lines);
|
||||
}
|
||||
}
|
||||
|
||||
inline void Return() {
|
||||
_lines.insert(_lines.begin() + _row + 1, u8"");
|
||||
_row++;
|
||||
_col = 0;
|
||||
for (size_t i = _row - 1; i < _lines.size(); i++) {
|
||||
wmove(_window, i, 0);
|
||||
wclrtoeol(_window);
|
||||
waddstr(_window, (char*)_lines[i].c_str());
|
||||
}
|
||||
wmove(_window, _row, _col);
|
||||
}
|
||||
inline void Tab() {
|
||||
wmove(_window, _row, 0);
|
||||
wclrtoeol(_window);
|
||||
auto& line = _lines[_row];
|
||||
if ((int)line.length() <= _col) {
|
||||
line += u8" ";
|
||||
} else {
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
line.insert(line.begin() + _col, u8' ');
|
||||
}
|
||||
}
|
||||
waddstr(_window, (char*)line.c_str());
|
||||
_col += 4;
|
||||
_rightPos = _col;
|
||||
wmove(_window, _row, _col);
|
||||
_onChange(_lines);
|
||||
}
|
||||
|
||||
inline void GoToEndOfLine() {
|
||||
_col = _lines[_row].size();
|
||||
_rightPos = _col;
|
||||
wmove(_window, _row, _col);
|
||||
}
|
||||
inline void GoToStartOfLine() {
|
||||
_col = _lines[_row].size();
|
||||
_rightPos = _col;
|
||||
wmove(_window, _row, _col);
|
||||
}
|
||||
|
||||
inline void Input(int c) {
|
||||
wmove(_window, _row, 0);
|
||||
auto& line = _lines[_row];
|
||||
if ((int)line.length() <= _col) {
|
||||
line += (char8_t)c;
|
||||
} else {
|
||||
line.insert(line.begin() + _col, c);
|
||||
}
|
||||
waddstr(_window, (char*)line.c_str());
|
||||
_col++;
|
||||
_rightPos = _col;
|
||||
wmove(_window, _row, _col);
|
||||
_onChange(_lines);
|
||||
}
|
||||
|
||||
inline void SetScriptWithDiagnostics(const std::u8string& script,
|
||||
const MalachScript::Diagnostics::Diagnostic* diag) {
|
||||
auto yx = GetCursorPosition();
|
||||
|
||||
Clear();
|
||||
|
||||
if (diag != nullptr) {
|
||||
auto start = diag->GetSpan().GetStart();
|
||||
auto end = diag->GetSpan().GetEnd() + 1;
|
||||
if (end > script.size()) {
|
||||
end = script.size();
|
||||
if (start == end && start > 0) {
|
||||
start--;
|
||||
}
|
||||
}
|
||||
|
||||
waddnstr(_window, (char*)script.c_str(), start);
|
||||
wattron(_window, COLOR_PAIR(1));
|
||||
waddnstr(_window, (char*)script.substr(start).data(), end - start);
|
||||
wattroff(_window, COLOR_PAIR(1));
|
||||
waddnstr(_window, (char*)script.substr(end).data(), script.size() - end);
|
||||
|
||||
if (start >= script.size() - 1) {
|
||||
wattron(_window, COLOR_PAIR(1));
|
||||
waddch(_window, ' ');
|
||||
wattroff(_window, COLOR_PAIR(1));
|
||||
}
|
||||
} else {
|
||||
waddstr(_window, (char*)script.c_str());
|
||||
}
|
||||
MoveCursorPosition(yx.first, yx.second);
|
||||
Refresh();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MALACHSCRIPT_INPUTWINDOW_HPP
|
176
repl/main.cpp
176
repl/main.cpp
|
@ -3,49 +3,10 @@
|
|||
#include "../src/Parser/Lexer/Lexer.hpp"
|
||||
#include "../src/Parser/Parser.hpp"
|
||||
#include "../src/Parser/Statements/ParsedStatementStringifier.hpp"
|
||||
|
||||
void UpdateScriptWithParseInfo(WINDOW* inputWindow, const std::u8string& script,
|
||||
const MalachScript::Diagnostics::Diagnostic* diag,
|
||||
[[maybe_unused]] const MalachScript::Parser::LexToken* firstToken) {
|
||||
std::stringstream ss((char*)script.c_str());
|
||||
|
||||
int col;
|
||||
int row;
|
||||
getyx(inputWindow, row, col);
|
||||
wclear(inputWindow);
|
||||
|
||||
if (diag != nullptr) {
|
||||
auto start = diag->GetSpan().GetStart();
|
||||
auto end = diag->GetSpan().GetEnd() + 1;
|
||||
if (end > script.size()) {
|
||||
end = script.size();
|
||||
if (start == end && start > 0) {
|
||||
start--;
|
||||
}
|
||||
}
|
||||
|
||||
waddnstr(inputWindow, (char*)script.c_str(), start);
|
||||
wattron(inputWindow, COLOR_PAIR(1));
|
||||
waddnstr(inputWindow, (char*)script.substr(start).data(), end - start);
|
||||
wattroff(inputWindow, COLOR_PAIR(1));
|
||||
waddnstr(inputWindow, (char*)script.substr(end).data(), script.size() - end);
|
||||
|
||||
if (start >= script.size() - 1) {
|
||||
wattron(inputWindow, COLOR_PAIR(1));
|
||||
waddch(inputWindow, ' ');
|
||||
wattroff(inputWindow, COLOR_PAIR(1));
|
||||
}
|
||||
} else {
|
||||
waddstr(inputWindow, (char*)script.c_str());
|
||||
}
|
||||
|
||||
wmove(inputWindow, row, col);
|
||||
|
||||
wrefresh(inputWindow);
|
||||
}
|
||||
#include "InputWindow.hpp"
|
||||
|
||||
void ParseAndUpdate(const std::vector<std::u8string> lines, WINDOW* diagnosticsWindow, WINDOW* parsedWindow,
|
||||
WINDOW* inputWindow) {
|
||||
MalachScriptRepl::InputWindow& inputWindow) {
|
||||
std::u8string script;
|
||||
for (const auto& line : lines) {
|
||||
script += line;
|
||||
|
@ -89,7 +50,7 @@ void ParseAndUpdate(const std::vector<std::u8string> lines, WINDOW* diagnosticsW
|
|||
}
|
||||
wrefresh(parsedWindow);
|
||||
|
||||
UpdateScriptWithParseInfo(inputWindow, script, diag, firstToken);
|
||||
inputWindow.SetScriptWithDiagnostics(script, diag);
|
||||
delete parsedResult;
|
||||
}
|
||||
|
||||
|
@ -121,134 +82,39 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char* argv[]) {
|
|||
|
||||
wrefresh(stdscr);
|
||||
|
||||
auto* inputWindow = newwin(inputFieldSize, maxX - 3, 1, 2);
|
||||
keypad(inputWindow, true);
|
||||
|
||||
auto* diagnosticsWindow = newwin(25, (maxX - 4) / 2, 32, 2);
|
||||
[[maybe_unused]] auto* diagnosticsWindow = newwin(25, (maxX - 4) / 2, 32, 2);
|
||||
|
||||
auto* parsedResultWindow = newwin(25, (maxX - 4) / 2 - 2, 32, (maxX - 4) / 2 + 4);
|
||||
wrefresh(parsedResultWindow);
|
||||
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
|
||||
// Special handler so we can keep the column
|
||||
int rightPos = 0;
|
||||
|
||||
std::vector<std::u8string> lines = {u8""};
|
||||
auto inputWindow = MalachScriptRepl::InputWindow(inputFieldSize, maxX - 3, 1, 2);
|
||||
inputWindow.RegisterOnChange(
|
||||
[diagnosticsWindow, parsedResultWindow, &inputWindow](const std::vector<std::u8string>& lines) {
|
||||
ParseAndUpdate(lines, diagnosticsWindow, parsedResultWindow, inputWindow);
|
||||
});
|
||||
|
||||
int c;
|
||||
bool running = true;
|
||||
while (running) {
|
||||
c = wgetch(inputWindow);
|
||||
c = inputWindow.GetInput();
|
||||
switch (c) {
|
||||
case 27: running = false; break;
|
||||
|
||||
case KEY_LEFT: {
|
||||
if (col > 0) {
|
||||
wmove(inputWindow, row, --col);
|
||||
rightPos = col;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KEY_RIGHT: {
|
||||
auto& line = lines[row];
|
||||
if (col < (int)line.size()) {
|
||||
wmove(inputWindow, row, ++col);
|
||||
rightPos = col;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KEY_UP:
|
||||
if (row > 0) {
|
||||
col = rightPos;
|
||||
if (col > (int)lines[row - 1].size()) {
|
||||
col = (int)lines[row - 1].size();
|
||||
}
|
||||
wmove(inputWindow, --row, col);
|
||||
}
|
||||
|
||||
wrefresh(stdscr);
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
if (row < (int)lines.size() - 1) {
|
||||
col = rightPos;
|
||||
if (col > (int)lines[row + 1].size()) {
|
||||
col = (int)lines[row + 1].size();
|
||||
}
|
||||
wmove(inputWindow, ++row, col);
|
||||
}
|
||||
break;
|
||||
case KEY_LEFT: inputWindow.MoveCursorLeft(); break;
|
||||
case KEY_RIGHT: inputWindow.MoveCursorRight(); break;
|
||||
case KEY_UP: inputWindow.MoveCursorUp(); break;
|
||||
case KEY_DOWN: inputWindow.MoveCursorDown(); break;
|
||||
case KEY_BACKSPACE:
|
||||
case 127:
|
||||
if (col > 0) {
|
||||
mvwdelch(inputWindow, row, --col);
|
||||
auto& line = lines[row];
|
||||
line = line.erase(col, 1);
|
||||
ParseAndUpdate(lines, diagnosticsWindow, parsedResultWindow, inputWindow);
|
||||
}
|
||||
break;
|
||||
case 127: inputWindow.Backspace(); break;
|
||||
case 10:
|
||||
case KEY_ENTER:
|
||||
lines.insert(lines.begin() + row + 1, u8"");
|
||||
row++;
|
||||
col = 0;
|
||||
for (size_t i = row - 1; i < lines.size(); i++) {
|
||||
wmove(inputWindow, i, 0);
|
||||
wclrtoeol(inputWindow);
|
||||
waddstr(inputWindow, (char*)lines[i].c_str());
|
||||
}
|
||||
wmove(inputWindow, row, col);
|
||||
|
||||
break;
|
||||
case KEY_ENTER: inputWindow.Return(); break;
|
||||
case 9:
|
||||
case KEY_STAB: {
|
||||
wmove(inputWindow, row, 0);
|
||||
wclrtoeol(inputWindow);
|
||||
auto& line = lines[row];
|
||||
if ((int)line.length() <= col) {
|
||||
line += u8" ";
|
||||
} else {
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
line.insert(line.begin() + col, u8' ');
|
||||
}
|
||||
}
|
||||
waddstr(inputWindow, (char*)line.c_str());
|
||||
col += 4;
|
||||
rightPos = col;
|
||||
wmove(inputWindow, row, col);
|
||||
ParseAndUpdate(lines, diagnosticsWindow, parsedResultWindow, inputWindow);
|
||||
break;
|
||||
}
|
||||
case KEY_END: {
|
||||
col = lines[row].size();
|
||||
rightPos = col;
|
||||
wmove(inputWindow, row, col);
|
||||
break;
|
||||
}
|
||||
case KEY_HOME: {
|
||||
col = 0;
|
||||
rightPos = col;
|
||||
wmove(inputWindow, row, col);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
wmove(inputWindow, row, 0);
|
||||
auto& line = lines[row];
|
||||
if ((int)line.length() <= col) {
|
||||
line += (char8_t)c;
|
||||
} else {
|
||||
line.insert(line.begin() + col, c);
|
||||
}
|
||||
waddstr(inputWindow, (char*)line.c_str());
|
||||
col++;
|
||||
rightPos = col;
|
||||
wmove(inputWindow, row, col);
|
||||
ParseAndUpdate(lines, diagnosticsWindow, parsedResultWindow, inputWindow);
|
||||
break;
|
||||
}
|
||||
case KEY_STAB: inputWindow.Tab(); break;
|
||||
case KEY_END: inputWindow.GoToEndOfLine(); break;
|
||||
case KEY_HOME: inputWindow.GoToStartOfLine(); break;
|
||||
default: inputWindow.Input(c); break;
|
||||
}
|
||||
wrefresh(inputWindow);
|
||||
inputWindow.Refresh();
|
||||
}
|
||||
endwin();
|
||||
|
||||
|
|
Loading…
Reference in New Issue