aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/line/mode.h53
-rw-r--r--module-test/line_test.cc14
-rw-r--r--src/line/mode.cc130
3 files changed, 146 insertions, 51 deletions
diff --git a/include/line/mode.h b/include/line/mode.h
index 8811e66..2baad81 100644
--- a/include/line/mode.h
+++ b/include/line/mode.h
@@ -1,59 +1,28 @@
#pragma once
-#include <unistd.h>
#include <termios.h>
-#include <stdlib.h>
+#include <string>
using namespace std; // TODO: remove
namespace ov4
{
-inline termios attr;
-
-void disable_raw()
-{
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr);
-}
-
-void enable_raw()
+struct T_position
{
- termios attr_raw;
- tcgetattr(STDIN_FILENO, &attr);
- tcgetattr(STDIN_FILENO, &attr_raw);
-
- // LOCAL
+ int row;
+ int col;
+};
- // disable
- // echo
- // canonical
- // signal
- // disable post-input processing, aka control-V
- attr_raw.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN);
-
- // INPUT
-
- // disable
- // software flow control, aka control-S/Q
- // \n and \r conversion
- attr_raw.c_iflag &= ~(IXON | ICRNL);
-
- // OUTPUT
+inline termios attr;
- // disable
- // post-output processing
- attr_raw.c_oflag &= ~(OPOST);
+void disable_raw();
+void enable_raw();
- // misc
- attr_raw.c_iflag &= ~(BRKINT | INPCK | ISTRIP);
- attr_raw.c_cflag |= ~(CS8);
+void clear_below();
- atexit(disable_raw);
+std::string readline();
- // TCSAFLUSH
- // the change shall occur after all output written to fildes is transmitted
- // and all input so far received but not read shall be discarded before the change is made
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr_raw);
-}
+T_position get_cursor_position();
}
diff --git a/module-test/line_test.cc b/module-test/line_test.cc
index 7bc16df..d71d088 100644
--- a/module-test/line_test.cc
+++ b/module-test/line_test.cc
@@ -2,6 +2,7 @@
* test line editor
$ g++ \
module-test/line_test.cc \
+ src/line/mode.cc \
-std=c++26 -Iinclude -Ithird_party/magic_enum/include \
-O0 -ggdb3 -fno-omit-frame-pointer -fno-inline -D_GLIBCXX_ASSERTIONS \
-o module-test/line_test.out
@@ -11,6 +12,7 @@
#include <iostream>
#include <print>
+#include <unistd.h>
#include "line/mode.h"
@@ -20,14 +22,8 @@ using namespace ov4;
int main()
{
enable_raw();
- char c;
- while (read(STDIN_FILENO, &c, 1) == 1)
- {
- if (c == 'q') break;
- if (iscntrl(c))
- print("control: {}\r\n", static_cast<unsigned char>(c));
- else
- print("entered: {}\r\n", c);
- }
+ string s = readline();
+ disable_raw();
+ cout << s << endl;
return 0;
}
diff --git a/src/line/mode.cc b/src/line/mode.cc
new file mode 100644
index 0000000..83eda67
--- /dev/null
+++ b/src/line/mode.cc
@@ -0,0 +1,130 @@
+#include "line/mode.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <iostream>
+#include <print>
+
+using namespace std;
+
+namespace ov4
+{
+
+void disable_raw()
+{
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr);
+}
+
+void enable_raw()
+{
+ termios attr_raw;
+ tcgetattr(STDIN_FILENO, &attr);
+ tcgetattr(STDIN_FILENO, &attr_raw);
+
+ // LOCAL
+
+ // disable
+ // echo
+ // canonical
+ // signal
+ // disable post-input processing, aka control-V
+ attr_raw.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN);
+
+ // INPUT
+
+ // disable
+ // software flow control, aka control-S/Q
+ // \n and \r conversion
+ attr_raw.c_iflag &= ~(IXON | ICRNL);
+
+ // OUTPUT
+
+ // disable
+ // post-output processing
+ attr_raw.c_oflag &= ~(OPOST);
+
+ // misc
+ attr_raw.c_iflag &= ~(BRKINT | INPCK | ISTRIP);
+ attr_raw.c_cflag |= ~(CS8);
+
+ atexit(disable_raw);
+
+ // TCSAFLUSH
+ // the change shall occur after all output written to fildes is transmitted
+ // and all input so far received but not read shall be discarded before the change is made
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr_raw);
+}
+
+void clear_below()
+{
+ print("\x1b[0J");
+}
+
+string readline()
+{
+ string buffer;
+ char c;
+ while (read(STDIN_FILENO, &c, 1) == 1)
+ {
+ if (c == 'Q') break;
+ else if (c == 'C')
+ {
+ clear_below();
+ }
+ else if (c == 'R')
+ {
+ get_cursor_position();
+ }
+ else if (iscntrl(c))
+ {
+ print("control: {}\r\n", static_cast<unsigned char>(c));
+ fflush(stdout);
+ if (c == 13) // \n
+ {
+ //print("line: {}\r\n", buffer);
+ return buffer;
+ }
+ }
+ else
+ {
+ print("{}", c);
+ buffer += c;
+ fflush(stdout);
+ }
+ }
+ return buffer;
+}
+
+T_position get_cursor_position()
+{
+ char c;
+ string buffer;
+ T_position pos;
+ int row, col;
+ tcflush(STDIN_FILENO, TCIFLUSH);
+ cout << "\x1b[6n" << flush;
+ while (read(STDIN_FILENO, &c, 1) == 1)
+ {
+ if (c == 'R') break;
+ buffer += c;
+ }
+ if (buffer.size() <= 2 || buffer[0] != '\x1b' || buffer[1] != '[')
+ {
+ pos.row = -1;
+ pos.col = -1;
+ return pos;
+ }
+ if ((sscanf(buffer.c_str(), "\x1b[%d;%d", &row, &col)) != 2)
+ {
+ pos.row = -1;
+ pos.col = -1;
+ return pos;
+ }
+ pos.row = row;
+ pos.col = col;
+ print("row {}, col {}\r\n", row, col);
+ fflush(stdout);
+ return pos;
+}
+
+}