Clean up REPL a bit by moving InputWindow to special class.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2021-01-05 00:13:42 +01:00
parent 5c086ee066
commit f328762cd8
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
2 changed files with 198 additions and 155 deletions

177
repl/InputWindow.hpp Normal file
View File

@ -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

View File

@ -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();