1
0
Fork 0
mirror of https://gitlab.com/sortix/sortix.git synced 2023-02-13 20:55:38 -05:00

Switch sh to termios.

This commit is contained in:
Jonas 'Sortie' Termansen 2016-04-23 13:16:55 +02:00
parent 1a3b3f6deb
commit 88337bc046
5 changed files with 180 additions and 112 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen.
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -17,15 +17,13 @@
* Read a line from the terminal.
*/
#include <sys/keycodes.h>
#include <sys/termmode.h>
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>
@ -33,6 +31,8 @@
#include "editline.h"
#include "showline.h"
#define CONTROL(x) (((x) - 64) & 127)
void edit_line_show(struct edit_line* edit_state)
{
size_t line_length = 0;
@ -270,31 +270,31 @@ void edit_line_type_codepoint(struct edit_line* edit_state, wchar_t wc)
assert(edit_state->line_used <= edit_state->line_length);
}
void line_edit_type_home(struct edit_line* edit_state)
void edit_line_type_home(struct edit_line* edit_state)
{
edit_state->line_offset = 0;
}
void line_edit_type_left(struct edit_line* edit_state)
void edit_line_type_left(struct edit_line* edit_state)
{
if ( edit_state->line_offset == 0 )
return;
edit_state->line_offset--;
}
void line_edit_type_right(struct edit_line* edit_state)
void edit_line_type_right(struct edit_line* edit_state)
{
if ( edit_state->line_offset == edit_state->line_used )
return;
edit_state->line_offset++;
}
void line_edit_type_end(struct edit_line* edit_state)
void edit_line_type_end(struct edit_line* edit_state)
{
edit_state->line_offset = edit_state->line_used;
}
void line_edit_type_backspace(struct edit_line* edit_state)
void edit_line_type_backspace(struct edit_line* edit_state)
{
if ( edit_state->line_offset == 0 )
return;
@ -304,7 +304,7 @@ void line_edit_type_backspace(struct edit_line* edit_state)
edit_state->line[i] = edit_state->line[i+1];
}
void line_edit_type_previous_word(struct edit_line* edit_state)
void edit_line_type_previous_word(struct edit_line* edit_state)
{
while ( edit_state->line_offset &&
iswspace(edit_state->line[edit_state->line_offset-1]) )
@ -314,7 +314,7 @@ void line_edit_type_previous_word(struct edit_line* edit_state)
edit_state->line_offset--;
}
void line_edit_type_next_word(struct edit_line* edit_state)
void edit_line_type_next_word(struct edit_line* edit_state)
{
while ( edit_state->line_offset != edit_state->line_used &&
iswspace(edit_state->line[edit_state->line_offset]) )
@ -324,7 +324,7 @@ void line_edit_type_next_word(struct edit_line* edit_state)
edit_state->line_offset++;
}
void line_edit_type_delete(struct edit_line* edit_state)
void edit_line_type_delete(struct edit_line* edit_state)
{
if ( edit_state->line_offset == edit_state->line_used )
return;
@ -333,10 +333,10 @@ void line_edit_type_delete(struct edit_line* edit_state)
edit_state->line[i] = edit_state->line[i+1];
}
void line_edit_type_eof_or_delete(struct edit_line* edit_state)
void edit_line_type_eof_or_delete(struct edit_line* edit_state)
{
if ( edit_state->line_used )
return line_edit_type_delete(edit_state);
return edit_line_type_delete(edit_state);
edit_state->editing = false;
edit_state->eof_condition = true;
if ( edit_state->trap_eof_opportunity )
@ -353,13 +353,13 @@ void edit_line_type_interrupt(struct edit_line* edit_state)
void edit_line_type_kill_after(struct edit_line* edit_state)
{
while ( edit_state->line_offset < edit_state->line_used )
line_edit_type_delete(edit_state);
edit_line_type_delete(edit_state);
}
void edit_line_type_kill_before(struct edit_line* edit_state)
{
while ( edit_state->line_offset )
line_edit_type_backspace(edit_state);
edit_line_type_backspace(edit_state);
}
void edit_line_type_clear(struct edit_line* edit_state)
@ -371,10 +371,10 @@ void edit_line_type_delete_word_before(struct edit_line* edit_state)
{
while ( edit_state->line_offset &&
iswspace(edit_state->line[edit_state->line_offset-1]) )
line_edit_type_backspace(edit_state);
edit_line_type_backspace(edit_state);
while ( edit_state->line_offset &&
!iswspace(edit_state->line[edit_state->line_offset-1]) )
line_edit_type_backspace(edit_state);
edit_line_type_backspace(edit_state);
}
int edit_line_completion_sort(const void* a_ptr, const void* b_ptr)
@ -495,74 +495,6 @@ void edit_line_type_complete(struct edit_line* edit_state)
free(partial);
}
void edit_line_kbkey(struct edit_line* edit_state, int kbkey)
{
if ( kbkey != KBKEY_TAB && kbkey != -KBKEY_TAB )
edit_state->double_tab = false;
if ( edit_state->left_control || edit_state->right_control )
{
switch ( kbkey )
{
case KBKEY_LEFT: line_edit_type_previous_word(edit_state); return;
case KBKEY_RIGHT: line_edit_type_next_word(edit_state); return;
};
}
switch ( kbkey )
{
case KBKEY_HOME: line_edit_type_home(edit_state); return;
case KBKEY_LEFT: line_edit_type_left(edit_state); return;
case KBKEY_RIGHT: line_edit_type_right(edit_state); return;
case KBKEY_UP: edit_line_type_history_prev(edit_state); return;
case KBKEY_DOWN: edit_line_type_history_next(edit_state); return;
case KBKEY_END: line_edit_type_end(edit_state); return;
case KBKEY_BKSPC: line_edit_type_backspace(edit_state); return;
case KBKEY_DELETE: line_edit_type_delete(edit_state); return;
case KBKEY_TAB: edit_line_type_complete(edit_state); return;
case -KBKEY_LCTRL: edit_state->left_control = false; return;
case +KBKEY_LCTRL: edit_state->left_control = true; return;
case -KBKEY_RCTRL: edit_state->right_control = false; return;
case +KBKEY_RCTRL: edit_state->right_control = true; return;
};
}
void edit_line_codepoint(struct edit_line* edit_state, wchar_t wc)
{
if ( (edit_state->left_control || edit_state->right_control) &&
((L'a' <= wc && wc <= L'z') || (L'A' <= wc && wc <= L'Z')) )
{
if ( wc == L'a' || wc == L'A' )
line_edit_type_home(edit_state);
if ( wc == L'b' || wc == L'B' )
line_edit_type_left(edit_state);
if ( wc == L'c' || wc == L'C' )
edit_line_type_interrupt(edit_state);
if ( wc == L'd' || wc == L'D' )
line_edit_type_eof_or_delete(edit_state);
if ( wc == L'e' || wc == L'E' )
line_edit_type_end(edit_state);
if ( wc == L'f' || wc == L'F' )
line_edit_type_right(edit_state);
if ( wc == L'k' || wc == L'K' )
edit_line_type_kill_after(edit_state);
if ( wc == L'l' || wc == L'L' )
show_line_clear(&edit_state->show_state);
if ( wc == L'u' || wc == L'U' )
edit_line_type_kill_before(edit_state);
if ( wc == L'w' || wc == L'W' )
edit_line_type_delete_word_before(edit_state);
return;
}
if ( wc == L'\b' || wc == 127 )
return;
if ( wc == L'\t' )
return;
edit_line_type_codepoint(edit_state, wc);
}
void edit_line(struct edit_line* edit_state)
{
edit_state->editing = true;
@ -578,27 +510,140 @@ void edit_line(struct edit_line* edit_state)
edit_state->history_offset = edit_state->history_used;
edit_state->history_target = edit_state->history_used;
settermmode(edit_state->in_fd, TERMMODE_KBKEY | TERMMODE_UNICODE);
struct termios old_tio, tio;
tcgetattr(edit_state->in_fd, &old_tio);
memcpy(&tio, &old_tio, sizeof(tio));
tio.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN);
#if defined(__sortix__)
tio.c_lflag &= ~(ISORTIX_KBKEY | ISORTIX_CHARS_DISABLE |
ISORTIX_32BIT | ISORTIX_NONBLOCK | ISORTIX_TERMMODE);
#endif
tcsetattr(edit_state->in_fd, TCSANOW, &tio);
show_line_begin(&edit_state->show_state, edit_state->out_fd);
int escape = 0;
unsigned int params[16];
size_t param_index = 0;
mbstate_t ps = { 0 };
while ( edit_state->editing )
{
edit_line_show(edit_state);
uint32_t codepoint;
if ( read(0, &codepoint, sizeof(codepoint)) != sizeof(codepoint) )
char c;
if ( read(0, &c, sizeof(c)) != sizeof(c) )
{
edit_state->eof_condition = true;
edit_state->abort_editing = true;
break;
}
int kbkey;
if ( (kbkey = KBKEY_DECODE(codepoint)) )
edit_line_kbkey(edit_state, kbkey);
if ( c != '\t' )
edit_state->double_tab = false;
if ( escape )
{
if ( c == '[' )
{
escape = 2;
}
else if ( escape == 1 && c == 'O' )
{
escape = 3;
}
else if ( '0' <= c && c <= '9' )
{
params[param_index] *= 10;
params[param_index] += c - '0';
}
else if ( c == ';' )
{
if ( param_index < 16 )
++param_index;
}
else if ( 64 <= c && c <= 126 )
{
for ( size_t i = 0; i < 16; i++ )
if ( params[i] == 0 )
params[i] = 1;
switch ( c )
{
case 'A': edit_line_type_history_prev(edit_state); break;
case 'B': edit_line_type_history_next(edit_state); break;
case 'C':
if ( (params[1] - 1) & (1 << 2) ) /* control */
edit_line_type_next_word(edit_state);
else
edit_line_type_right(edit_state);
break;
case 'D':
if ( (params[1] - 1) & (1 << 2) ) /* control */
edit_line_type_previous_word(edit_state);
else
edit_line_type_left(edit_state);
break;
case 'F': edit_line_type_end(edit_state); break;
case 'H': edit_line_type_home(edit_state); break;
case 'R':
{
unsigned int r = params[0] - 1;
unsigned int c = params[1] - 1;
show_line_wincurpos(&edit_state->show_state, r, c);
edit_line_show(edit_state);
} break;
case '~':
if ( params[0] == 3 )
edit_line_type_delete(edit_state);
break;
}
escape = 0;
}
}
else if ( c == CONTROL('A') )
edit_line_type_home(edit_state);
else if ( c == CONTROL('B') )
edit_line_type_left(edit_state);
else if ( c == CONTROL('C') )
edit_line_type_interrupt(edit_state);
else if ( c == CONTROL('D') )
edit_line_type_eof_or_delete(edit_state);
else if ( c == CONTROL('E') )
edit_line_type_end(edit_state);
else if ( c == CONTROL('F') )
edit_line_type_right(edit_state);
else if ( c == CONTROL('I') )
edit_line_type_complete(edit_state);
else if ( c == CONTROL('K') )
edit_line_type_kill_after(edit_state);
else if ( c == CONTROL('L') )
show_line_clear(&edit_state->show_state);
else if ( c == CONTROL('U') )
edit_line_type_kill_before(edit_state);
else if ( c == CONTROL('W') )
edit_line_type_delete_word_before(edit_state);
else if ( c == CONTROL('[') )
{
param_index = 0;
memset(params, 0, sizeof(params));
escape = 1;
}
else if ( c == 127 )
edit_line_type_backspace(edit_state);
else
edit_line_codepoint(edit_state, (wchar_t) codepoint);
{
wchar_t wc;
size_t amount = mbrtowc(&wc, &c, 1, &ps);
if ( amount == (size_t) -2 )
continue;
if ( amount == (size_t) -1 )
wc = 0xFFFD; /* REPLACEMENT CHARACTER */
if ( amount == 0 )
continue;
edit_line_type_codepoint(edit_state, wc);
}
}
if ( edit_state->abort_editing )
@ -609,5 +654,5 @@ void edit_line(struct edit_line* edit_state)
show_line_finish(&edit_state->show_state);
}
settermmode(edit_state->in_fd, TERMMODE_NORMAL);
tcsetattr(edit_state->in_fd, TCSANOW, &old_tio);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen.
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -65,15 +65,15 @@ void edit_line_type_history_save_current(struct edit_line* edit_state);
void edit_line_type_history_prev(struct edit_line* edit_state);
void edit_line_type_history_next(struct edit_line* edit_state);
void edit_line_type_codepoint(struct edit_line* edit_state, wchar_t wc);
void line_edit_type_home(struct edit_line* edit_state);
void line_edit_type_left(struct edit_line* edit_state);
void line_edit_type_right(struct edit_line* edit_state);
void line_edit_type_end(struct edit_line* edit_state);
void line_edit_type_backspace(struct edit_line* edit_state);
void line_edit_type_previous_word(struct edit_line* edit_state);
void line_edit_type_next_word(struct edit_line* edit_state);
void line_edit_type_delete(struct edit_line* edit_state);
void line_edit_type_eof_or_delete(struct edit_line* edit_state);
void edit_line_type_home(struct edit_line* edit_state);
void edit_line_type_left(struct edit_line* edit_state);
void edit_line_type_right(struct edit_line* edit_state);
void edit_line_type_end(struct edit_line* edit_state);
void edit_line_type_backspace(struct edit_line* edit_state);
void edit_line_type_previous_word(struct edit_line* edit_state);
void edit_line_type_next_word(struct edit_line* edit_state);
void edit_line_type_delete(struct edit_line* edit_state);
void edit_line_type_eof_or_delete(struct edit_line* edit_state);
void edit_line_type_interrupt(struct edit_line* edit_state);
void edit_line_type_kill_after(struct edit_line* edit_state);
void edit_line_type_kill_before(struct edit_line* edit_state);
@ -81,8 +81,6 @@ void edit_line_type_clear(struct edit_line* edit_state);
void edit_line_type_delete_word_before(struct edit_line* edit_state);
int edit_line_completion_sort(const void* a_ptr, const void* b_ptr);
void edit_line_type_complete(struct edit_line* edit_state);
void edit_line_kbkey(struct edit_line* edit_state, int kbkey);
void edit_line_codepoint(struct edit_line* edit_state, wchar_t wc);
void edit_line(struct edit_line* edit_state);
#endif

View file

@ -17,6 +17,7 @@
* Command language interpreter.
*/
#include <sys/stat.h>
#include <sys/wait.h>
#include <assert.h>
@ -1005,9 +1006,9 @@ struct execute_result execute(char** tokens,
if ( !strcmp(type, "<") )
fd = open(target, O_RDONLY | O_CLOEXEC);
else if ( !strcmp(type, ">") )
fd = open(target, O_WRONLY | O_CREATE | O_TRUNC | O_CLOEXEC, 0666);
fd = open(target, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0666);
else if ( !strcmp(type, ">>") )
fd = open(target, O_WRONLY | O_CREATE | O_APPEND | O_CLOEXEC, 0666);
fd = open(target, O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, 0666);
if ( fd < 0 )
{

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen.
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -82,9 +82,26 @@ void show_line_begin(struct show_line* show_state, int out_fd)
show_state->out_fd = out_fd;
show_state->current_line = NULL;
show_state->current_cursor = 0;
tcgetwincurpos(out_fd, &show_state->wcp_start);
show_state->wcp_current = show_state->wcp_start;
tcgetwinsize(show_state->out_fd, &show_state->ws);
if ( tcgetwincurpos(out_fd, &show_state->wcp_start) == 0 )
show_state->wcp_current = show_state->wcp_start;
else
{
dprintf(show_state->out_fd, "\e[6n");
show_state->wcp_pending = true;
}
}
void show_line_wincurpos(struct show_line* show_state,
unsigned int r,
unsigned int c)
{
if ( !show_state->wcp_pending )
return;
show_state->wcp_start.wcp_row = r;
show_state->wcp_start.wcp_col = c;
show_state->wcp_current = show_state->wcp_start;
show_state->wcp_pending = false;
}
bool show_line_is_weird(const char* line)
@ -270,6 +287,9 @@ bool show_line_optimized(struct show_line* show_state, const char* line, size_t
void show_line(struct show_line* show_state, const char* line, size_t cursor)
{
if ( show_state->wcp_pending )
return;
// TODO: We don't currently invalidate on SIGWINCH.
struct winsize ws;
tcgetwinsize(show_state->out_fd, &ws);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen.
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -38,6 +38,7 @@ struct show_line
char* current_line;
size_t current_cursor;
bool invalidated;
bool wcp_pending;
};
struct wincurpos predict_cursor(struct cursor_predict* cursor_predict,
@ -49,6 +50,9 @@ bool predict_will_scroll(struct cursor_predict cursor_predict,
struct winsize ws,
wchar_t c);
void show_line_begin(struct show_line* show_state, int out_fd);
void show_line_wincurpos(struct show_line* show_state,
unsigned int r,
unsigned int c);
bool show_line_is_weird(const char* line);
void show_line_change_cursor(struct show_line* show_state, struct wincurpos wcp);
bool show_line_optimized(struct show_line* show_state, const char* line, size_t cursor);