Skip to content

Instantly share code, notes, and snippets.

@jstaursky
Last active January 22, 2022 23:08
Show Gist options
  • Save jstaursky/ee5bf5fd41273717f18292bed099fb1b to your computer and use it in GitHub Desktop.
Save jstaursky/ee5bf5fd41273717f18292bed099fb1b to your computer and use it in GitHub Desktop.
// REQUIRES libuv
#include <assert.h>
#include <iostream>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <uv.h>
#include <string>
#include <string.h>
#include <atomic>
#define create_cursor_mover(anscii) [](uv_buf_t* dst) -> void { \
std::string s{anscii}; \
dst->base = new char[s.length() + 1]; \
dst->len = s.length() + 1; \
memcpy(dst->base, s.c_str(), dst->len); \
}
// ascii control codes.
#define UP "\033[1A"
#define DOWN "\033[1B"
#define LEFT "\033[1D"
#define RIGHT "\033[1C"
auto move_cursor_up = create_cursor_mover (UP);
auto move_cursor_down = create_cursor_mover (DOWN);
auto move_cursor_left = create_cursor_mover (LEFT);
auto move_cursor_right = create_cursor_mover (RIGHT);
std::atomic<bool> end(false);
uv_loop_t* loop;
uv_tty_t tty;
uv_tty_t tty_out;
uv_signal_t sigterm;
uv_write_t write_req;
uv_buf_t write_buf = { .base = NULL, .len = 0 };
uint64_t start = uv_hrtime() / 1e9;
void stop()
{
int stop_ret = uv_read_stop ((uv_stream_t*)&tty);
int sigstop_ret = uv_signal_stop (&sigterm);
}
void writer_cleanup (uv_write_t* req, int status)
{
delete[] write_buf.base;
write_buf.base = nullptr;
write_buf.len = 0;
}
void reader_preconf (uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
{
buf->base = new char[suggested_size];
buf->len = suggested_size;
}
void reader_cb (uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
{
if (nread < 0) {
end = true;
goto cleanup;
}
for (ssize_t i = 0; i < nread; i++) {
switch (buf->base[i]) {
case 'h':
move_cursor_left (&write_buf);
break;
case 'j':
move_cursor_down (&write_buf);
break;
case 'k':
move_cursor_up (&write_buf);
break;
case 'l':
move_cursor_right (&write_buf);
break;
default:
break;
}
// ctrl-c
if (buf->base[i] == (0xf & 'c')) {
end = true;
}
}
// Commit write_buf edits to tty.
uv_write (&write_req, (uv_stream_t*)&tty_out, &write_buf, 1, &writer_cleanup);
cleanup:
if (buf->base && buf->len > 0)
delete[] buf->base;
if (end.load())
stop();
}
void signal_cb (uv_signal_t* sig, int signum)
{
stop();
}
void walk_and_close_cb (uv_handle_t* handle, void* arg)
{
if (!uv_is_closing (handle)) {
uv_close (handle, NULL);
}
}
void print_counter (void* arg)
{
while(!end.load()) {
uint64_t count = (uv_hrtime() / 1e9) - start;
printf("%ld\n", count);
uv_sleep(1000);
}
}
int main (int argc, char *argv[])
{
loop = uv_default_loop();
uv_tty_init (loop, &tty, fileno (stdin), 0);
uv_tty_init (loop, &tty_out, fileno (stdout), 0);
uv_signal_init (loop, &sigterm);
uv_tty_set_mode (&tty, UV_TTY_MODE_RAW);
uv_read_start ((uv_stream_t*)&tty, &reader_preconf, &reader_cb);
uv_signal_start (&sigterm, signal_cb, SIGTERM);
uv_thread_t tid;
uv_thread_create(&tid, print_counter, nullptr);
uv_run (loop, UV_RUN_DEFAULT);
uv_tty_reset_mode();
uv_walk (loop, &walk_and_close_cb, NULL);
uv_run (loop, UV_RUN_DEFAULT);
uv_thread_join(&tid);
uv_loop_close (loop);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment