|
@@ -1,18 +1,16 @@
|
|
|
#include "core/ReadLine.h"
|
|
|
|
|
|
#include <ctype.h>
|
|
|
-#include <errno.h>
|
|
|
#include <stdatomic.h>
|
|
|
#include <stdint.h>
|
|
|
#include <stdio.h>
|
|
|
#include <string.h>
|
|
|
-#include <termios.h>
|
|
|
-#include <unistd.h>
|
|
|
|
|
|
#include "ErrorSimulator.h"
|
|
|
#include "core/Logger.h"
|
|
|
#include "core/Queue.h"
|
|
|
#include "core/Thread.h"
|
|
|
+#include "core/Unicode.h"
|
|
|
|
|
|
static constexpr size_t HISTORY_LENGTH = 10;
|
|
|
static constexpr size_t CONSOLE_BUFFER_SIZE = 256;
|
|
@@ -28,7 +26,6 @@ QUEUE_SOURCE(ConsoleLine, CL)
|
|
|
static atomic_bool running = true;
|
|
|
static thrd_t readThread = {0};
|
|
|
|
|
|
-static struct termios original;
|
|
|
static QueueCL buffer = {0};
|
|
|
static ConsoleLine currentBuffer = {0};
|
|
|
static size_t move = 0;
|
|
@@ -40,35 +37,20 @@ static size_t historyOffset = 0;
|
|
|
static size_t historyIndex = 0;
|
|
|
static size_t historyLength = 0;
|
|
|
|
|
|
-static void getAttributes(struct termios* t) {
|
|
|
- if(tcgetattr(STDIN_FILENO, t)) {
|
|
|
- LOG_WARNING("cannot get terminal attributes");
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void restoreAttributes() {
|
|
|
- if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &original)) {
|
|
|
- LOG_WARNING("cannot restore terminal attributes: %s", strerror(errno));
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static char readChar() {
|
|
|
- char c = 0;
|
|
|
- ssize_t bytes = read(STDIN_FILENO, &c, 1);
|
|
|
- return bytes <= 0 ? '\0' : c;
|
|
|
-}
|
|
|
-
|
|
|
-static void addChar(char c) {
|
|
|
- if(currentBuffer.length >= CONSOLE_BUFFER_SIZE - 1) {
|
|
|
- return;
|
|
|
- }
|
|
|
- for(size_t i = 0; i < move; i++) {
|
|
|
- currentBuffer.data[currentBuffer.length - i] =
|
|
|
- currentBuffer.data[currentBuffer.length - i - 1];
|
|
|
+static void addChar(u64 c) {
|
|
|
+ UTF8 u = convertUnicodeToUTF8((u32)c);
|
|
|
+ for(u32 k = 0; k < u.length; k++) {
|
|
|
+ if(currentBuffer.length >= CONSOLE_BUFFER_SIZE - 1) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for(size_t i = 0; i < move; i++) {
|
|
|
+ currentBuffer.data[currentBuffer.length - i] =
|
|
|
+ currentBuffer.data[currentBuffer.length - i - 1];
|
|
|
+ }
|
|
|
+ currentBuffer.length++;
|
|
|
+ currentBuffer.data[currentBuffer.length - move - 1] = (char)u.data[k];
|
|
|
+ currentBuffer.data[currentBuffer.length] = '\0';
|
|
|
}
|
|
|
- currentBuffer.length++;
|
|
|
- currentBuffer.data[currentBuffer.length - move - 1] = c;
|
|
|
- currentBuffer.data[currentBuffer.length] = '\0';
|
|
|
}
|
|
|
|
|
|
static void print(const char* s) {
|
|
@@ -79,10 +61,10 @@ static void refreshLine(const char* prefix) {
|
|
|
print(prefix);
|
|
|
print(currentBuffer.data);
|
|
|
if(cursorMove > 0) {
|
|
|
- printf("\33[%zuD", cursorMove);
|
|
|
+ moveCursorLeft((int)cursorMove);
|
|
|
}
|
|
|
fflush(stdout);
|
|
|
- print("\33[2K\r");
|
|
|
+ clearTerminalLine();
|
|
|
}
|
|
|
|
|
|
static bool clear() {
|
|
@@ -122,16 +104,12 @@ static void addLine() {
|
|
|
clear();
|
|
|
}
|
|
|
|
|
|
-static char isUTF8Part(char c) {
|
|
|
- return ((uint8_t)c & 0xC0) == 0x80;
|
|
|
-}
|
|
|
-
|
|
|
static bool removeChar() {
|
|
|
size_t pos = currentBuffer.length - move;
|
|
|
if(pos > 0) {
|
|
|
size_t l = 1;
|
|
|
while(pos - l >= 0) {
|
|
|
- if(!isUTF8Part(currentBuffer.data[pos - l])) {
|
|
|
+ if(!isUTF8Remainder((u8)currentBuffer.data[pos - l])) {
|
|
|
break;
|
|
|
}
|
|
|
l++;
|
|
@@ -144,7 +122,7 @@ static bool removeChar() {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-static bool handleControlKey(char c) {
|
|
|
+static bool handleControlKey(u64 c) {
|
|
|
switch(c) {
|
|
|
case 3: return clear();
|
|
|
case 10:
|
|
@@ -184,7 +162,7 @@ static char getMoved() {
|
|
|
static void handleLeftArrow() {
|
|
|
if(move < currentBuffer.length) {
|
|
|
move++;
|
|
|
- while(move < currentBuffer.length && isUTF8Part(getMoved())) {
|
|
|
+ while(move < currentBuffer.length && isUTF8Remainder((u8)getMoved())) {
|
|
|
move++;
|
|
|
}
|
|
|
cursorMove++;
|
|
@@ -194,38 +172,31 @@ static void handleLeftArrow() {
|
|
|
static void handleRightArrow() {
|
|
|
if(move > 0) {
|
|
|
move--;
|
|
|
- while(move > 0 && isUTF8Part(getMoved())) {
|
|
|
+ while(move > 0 && isUTF8Remainder((u8)getMoved())) {
|
|
|
move--;
|
|
|
}
|
|
|
cursorMove--;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void readEscapeSequence() {
|
|
|
- if(readChar() != '[') {
|
|
|
- return;
|
|
|
- }
|
|
|
- switch(readChar()) {
|
|
|
- case 'A': handleUpArrow(); break;
|
|
|
- case 'B': handleDownArrow(); break;
|
|
|
- case 'C': handleRightArrow(); break;
|
|
|
- case 'D': handleLeftArrow(); break;
|
|
|
- case '3':
|
|
|
- if(readChar() == '~' && move > 0) {
|
|
|
- handleRightArrow();
|
|
|
- removeChar();
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static void handleChars() {
|
|
|
while(true) {
|
|
|
- char c = readChar();
|
|
|
+ u64 c = getRawChar();
|
|
|
if(c == 0) {
|
|
|
break;
|
|
|
- } else if(c == 27) {
|
|
|
- readEscapeSequence();
|
|
|
+ } else if(c == TERMINAL_KEY_ARROW_UP) {
|
|
|
+ handleUpArrow();
|
|
|
+ } else if(c == TERMINAL_KEY_ARROW_DOWN) {
|
|
|
+ handleDownArrow();
|
|
|
+ } else if(c == TERMINAL_KEY_ARROW_RIGHT) {
|
|
|
+ handleRightArrow();
|
|
|
+ } else if(c == TERMINAL_KEY_ARROW_LEFT) {
|
|
|
+ handleLeftArrow();
|
|
|
+ } else if(c == TERMINAL_KEY_DELETE) {
|
|
|
+ if(move > 0) {
|
|
|
+ handleRightArrow();
|
|
|
+ removeChar();
|
|
|
+ }
|
|
|
} else if(iscntrl(c)) {
|
|
|
if(handleControlKey(c)) {
|
|
|
addLine();
|
|
@@ -249,18 +220,9 @@ static int loop(void* data) {
|
|
|
}
|
|
|
|
|
|
bool startReadLine(void) {
|
|
|
- // https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html
|
|
|
- getAttributes(&original);
|
|
|
- struct termios raw = original;
|
|
|
- raw.c_iflag &= ~(tcflag_t)(ICRNL | IXON);
|
|
|
- raw.c_lflag &= ~(tcflag_t)(ECHO | ICANON | IEXTEN | ISIG);
|
|
|
- raw.c_cc[VMIN] = 0;
|
|
|
- raw.c_cc[VTIME] = 0;
|
|
|
-
|
|
|
- if(tcsetattr(STDIN_FILENO, TCSANOW, &raw)) {
|
|
|
+ if(enterRawTerminal()) {
|
|
|
LOG_WARNING("cannot set terminal attributes");
|
|
|
}
|
|
|
-
|
|
|
initQueueCL(&buffer, 10);
|
|
|
atomic_store(&running, true);
|
|
|
if(MUTEX_INIT_FAIL || mtx_init(&bufferMutex, mtx_plain) != thrd_success) {
|
|
@@ -292,7 +254,9 @@ bool readLine(char* buffer_, size_t n) {
|
|
|
void stopReadLine() {
|
|
|
atomic_store(&running, false);
|
|
|
joinThreadSafe(&readThread);
|
|
|
- restoreAttributes();
|
|
|
+ if(leaveRawTerminal()) {
|
|
|
+ LOG_WARNING("cannot restore terminal attributes");
|
|
|
+ }
|
|
|
destroyQueueCL(&buffer);
|
|
|
mtx_destroy(&bufferMutex);
|
|
|
}
|