Factor out line editing to edit.c
parent
b66c8abf70
commit
eac0f83efa
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@ CFLAGS += -Wall -Wextra -Wpedantic
|
||||||
CFLAGS += -I/usr/local/include
|
CFLAGS += -I/usr/local/include
|
||||||
LDFLAGS += -L/usr/local/lib
|
LDFLAGS += -L/usr/local/lib
|
||||||
LDLIBS = -lcursesw -ltls
|
LDLIBS = -lcursesw -ltls
|
||||||
OBJS = chat.o handle.o input.o irc.o pls.o tab.o ui.o
|
OBJS = chat.o edit.o handle.o input.o irc.o pls.o tab.o ui.o
|
||||||
|
|
||||||
all: tags chat
|
all: tags chat
|
||||||
|
|
||||||
|
|
3
README
3
README
|
@ -4,7 +4,8 @@ This software targets FreeBSD and requires LibreSSL.
|
||||||
|
|
||||||
chat.h Shared state and function prototypes
|
chat.h Shared state and function prototypes
|
||||||
chat.c Command line parsing and poll loop
|
chat.c Command line parsing and poll loop
|
||||||
ui.c Curses UI, mIRC formatting, line editing
|
ui.c Curses UI and mIRC formatting
|
||||||
|
edit.c Line editing
|
||||||
irc.c TLS client connection
|
irc.c TLS client connection
|
||||||
input.c Input command handling
|
input.c Input command handling
|
||||||
handle.c Incoming command handling
|
handle.c Incoming command handling
|
||||||
|
|
14
chat.h
14
chat.h
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
|
@ -31,6 +32,15 @@ struct {
|
||||||
char *chan;
|
char *chan;
|
||||||
} chat;
|
} chat;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IRC_BOLD = 002,
|
||||||
|
IRC_COLOR = 003,
|
||||||
|
IRC_REVERSE = 026,
|
||||||
|
IRC_RESET = 017,
|
||||||
|
IRC_ITALIC = 035,
|
||||||
|
IRC_UNDERLINE = 037,
|
||||||
|
};
|
||||||
|
|
||||||
int ircConnect(const char *host, const char *port, const char *webPass);
|
int ircConnect(const char *host, const char *port, const char *webPass);
|
||||||
void ircRead(void);
|
void ircRead(void);
|
||||||
void ircWrite(const char *ptr, size_t len);
|
void ircWrite(const char *ptr, size_t len);
|
||||||
|
@ -58,6 +68,10 @@ void uiFmt(const wchar_t *format, ...);
|
||||||
} while(0)
|
} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const wchar_t *editHead(void);
|
||||||
|
const wchar_t *editTail(void);
|
||||||
|
bool edit(bool meta, bool ctrl, wchar_t ch);
|
||||||
|
|
||||||
void handle(char *line);
|
void handle(char *line);
|
||||||
void input(char *line);
|
void input(char *line);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,193 @@
|
||||||
|
/* Copyright (C) 2018 Curtis McEnroe <june@causal.agency>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sysexits.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <wctype.h>
|
||||||
|
|
||||||
|
#include "chat.h"
|
||||||
|
|
||||||
|
enum { BUF_LEN = 512 };
|
||||||
|
static struct {
|
||||||
|
wchar_t buf[BUF_LEN];
|
||||||
|
wchar_t *ptr;
|
||||||
|
wchar_t *end;
|
||||||
|
wchar_t *tab;
|
||||||
|
} line = {
|
||||||
|
.ptr = line.buf,
|
||||||
|
.end = line.buf,
|
||||||
|
};
|
||||||
|
|
||||||
|
static wchar_t tail;
|
||||||
|
const wchar_t *editHead(void) {
|
||||||
|
tail = *line.ptr;
|
||||||
|
*line.ptr = L'\0';
|
||||||
|
return line.buf;
|
||||||
|
}
|
||||||
|
const wchar_t *editTail(void) {
|
||||||
|
*line.ptr = tail;
|
||||||
|
*line.end = L'\0';
|
||||||
|
return line.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void left(void) {
|
||||||
|
if (line.ptr > line.buf) line.ptr--;
|
||||||
|
}
|
||||||
|
static void right(void) {
|
||||||
|
if (line.ptr < line.end) line.ptr++;
|
||||||
|
}
|
||||||
|
static void home(void) {
|
||||||
|
line.ptr = line.buf;
|
||||||
|
}
|
||||||
|
static void end(void) {
|
||||||
|
line.ptr = line.end;
|
||||||
|
}
|
||||||
|
static void kill(void) {
|
||||||
|
line.end = line.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void backspace(void) {
|
||||||
|
if (line.ptr == line.buf) return;
|
||||||
|
if (line.ptr != line.end) {
|
||||||
|
wmemmove(line.ptr - 1, line.ptr, line.end - line.ptr);
|
||||||
|
}
|
||||||
|
line.ptr--;
|
||||||
|
line.end--;
|
||||||
|
}
|
||||||
|
static void delete(void) {
|
||||||
|
if (line.ptr == line.end) return;
|
||||||
|
right();
|
||||||
|
backspace();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert(wchar_t ch) {
|
||||||
|
if (line.end == &line.buf[BUF_LEN - 1]) return;
|
||||||
|
if (line.ptr != line.end) {
|
||||||
|
wmemmove(line.ptr + 1, line.ptr, line.end - line.ptr);
|
||||||
|
}
|
||||||
|
*line.ptr++ = ch;
|
||||||
|
line.end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enter(void) {
|
||||||
|
if (line.end == line.buf) return;
|
||||||
|
*line.end = L'\0';
|
||||||
|
char *str = awcstombs(line.buf);
|
||||||
|
if (!str) err(EX_DATAERR, "awcstombs");
|
||||||
|
input(str);
|
||||||
|
free(str);
|
||||||
|
line.ptr = line.buf;
|
||||||
|
line.end = line.buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *prefix;
|
||||||
|
static void complete(void) {
|
||||||
|
if (!line.tab) {
|
||||||
|
editHead();
|
||||||
|
line.tab = wcsrchr(line.buf, L' ');
|
||||||
|
line.tab = (line.tab ? &line.tab[1] : line.buf);
|
||||||
|
prefix = awcstombs(line.tab);
|
||||||
|
if (!prefix) err(EX_DATAERR, "awcstombs");
|
||||||
|
editTail();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *next = tabNext(prefix);
|
||||||
|
if (!next) return;
|
||||||
|
|
||||||
|
wchar_t *wcs = ambstowcs(next);
|
||||||
|
if (!wcs) err(EX_DATAERR, "ambstowcs");
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
for (; wcs[i] && line.ptr > &line.tab[i]; ++i) {
|
||||||
|
line.tab[i] = wcs[i];
|
||||||
|
}
|
||||||
|
while (line.ptr > &line.tab[i]) {
|
||||||
|
backspace();
|
||||||
|
}
|
||||||
|
for (; wcs[i]; ++i) {
|
||||||
|
insert(wcs[i]);
|
||||||
|
}
|
||||||
|
free(wcs);
|
||||||
|
|
||||||
|
size_t pos = line.tab - line.buf;
|
||||||
|
if (!pos) {
|
||||||
|
insert(L':');
|
||||||
|
} else if (pos >= 2) {
|
||||||
|
if (line.buf[pos - 2] == L':' || line.buf[pos - 2] == L',') {
|
||||||
|
line.buf[pos - 2] = L',';
|
||||||
|
insert(L':');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
insert(L' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void accept(void) {
|
||||||
|
if (!line.tab) return;
|
||||||
|
line.tab = NULL;
|
||||||
|
free(prefix);
|
||||||
|
tabAccept();
|
||||||
|
}
|
||||||
|
static void reject(void) {
|
||||||
|
if (!line.tab) return;
|
||||||
|
line.tab = NULL;
|
||||||
|
free(prefix);
|
||||||
|
tabReject();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool editMeta(wchar_t ch) {
|
||||||
|
(void)ch;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool editCtrl(wchar_t ch) {
|
||||||
|
switch (ch) {
|
||||||
|
break; case L'B': reject(); left();
|
||||||
|
break; case L'F': reject(); right();
|
||||||
|
break; case L'A': reject(); home();
|
||||||
|
break; case L'E': reject(); end();
|
||||||
|
break; case L'D': reject(); delete();
|
||||||
|
break; case L'K': reject(); kill();
|
||||||
|
|
||||||
|
break; case L'C': accept(); insert(IRC_COLOR);
|
||||||
|
break; case L'N': accept(); insert(IRC_RESET);
|
||||||
|
break; case L'O': accept(); insert(IRC_BOLD);
|
||||||
|
break; case L'R': accept(); insert(IRC_COLOR);
|
||||||
|
break; case L'T': accept(); insert(IRC_ITALIC);
|
||||||
|
break; case L'V': accept(); insert(IRC_REVERSE);
|
||||||
|
|
||||||
|
break; default: return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool edit(bool meta, bool ctrl, wchar_t ch) {
|
||||||
|
if (meta) return editMeta(ch);
|
||||||
|
if (ctrl) return editCtrl(ch);
|
||||||
|
switch (ch) {
|
||||||
|
break; case L'\t': complete();
|
||||||
|
break; case L'\b': reject(); backspace();
|
||||||
|
break; case L'\n': accept(); enter();
|
||||||
|
break; default: {
|
||||||
|
if (!iswprint(ch)) return false;
|
||||||
|
accept();
|
||||||
|
insert(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
2
pls.c
2
pls.c
|
@ -20,6 +20,8 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#include "chat.h"
|
||||||
|
|
||||||
wchar_t *ambstowcs(const char *src) {
|
wchar_t *ambstowcs(const char *src) {
|
||||||
size_t len = mbsrtowcs(NULL, &src, 0, NULL);
|
size_t len = mbsrtowcs(NULL, &src, 0, NULL);
|
||||||
if (len == (size_t)-1) return NULL;
|
if (len == (size_t)-1) return NULL;
|
||||||
|
|
6
tab.c
6
tab.c
|
@ -34,7 +34,7 @@ static void prepend(struct Entry *entry) {
|
||||||
head = entry;
|
head = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove(struct Entry *entry) {
|
static void unlink(struct Entry *entry) {
|
||||||
if (entry->prev) entry->prev->next = entry->next;
|
if (entry->prev) entry->prev->next = entry->next;
|
||||||
if (entry->next) entry->next->prev = entry->prev;
|
if (entry->next) entry->next->prev = entry->prev;
|
||||||
if (head == entry) head = entry->next;
|
if (head == entry) head = entry->next;
|
||||||
|
@ -42,7 +42,7 @@ static void remove(struct Entry *entry) {
|
||||||
|
|
||||||
static void touch(struct Entry *entry) {
|
static void touch(struct Entry *entry) {
|
||||||
if (head == entry) return;
|
if (head == entry) return;
|
||||||
remove(entry);
|
unlink(entry);
|
||||||
prepend(entry);
|
prepend(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ static struct Entry *match;
|
||||||
void tabRemove(const char *word) {
|
void tabRemove(const char *word) {
|
||||||
for (struct Entry *entry = head; entry; entry = entry->next) {
|
for (struct Entry *entry = head; entry; entry = entry->next) {
|
||||||
if (strcmp(entry->word, word)) continue;
|
if (strcmp(entry->word, word)) continue;
|
||||||
remove(entry);
|
unlink(entry);
|
||||||
if (match == entry) match = entry->next;
|
if (match == entry) match = entry->next;
|
||||||
free(entry->word);
|
free(entry->word);
|
||||||
free(entry);
|
free(entry);
|
||||||
|
|
211
ui.c
211
ui.c
|
@ -35,6 +35,7 @@
|
||||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
|
||||||
#define CTRL(c) ((c) & 037)
|
#define CTRL(c) ((c) & 037)
|
||||||
|
#define UNCTRL(c) ((c) + '@')
|
||||||
|
|
||||||
#ifndef A_ITALIC
|
#ifndef A_ITALIC
|
||||||
#define A_ITALIC A_NORMAL
|
#define A_ITALIC A_NORMAL
|
||||||
|
@ -235,14 +236,6 @@ static void wordWrap(WINDOW *win, const wchar_t *str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
|
||||||
IRC_BOLD = 0x02,
|
|
||||||
IRC_COLOR = 0x03,
|
|
||||||
IRC_REVERSE = 0x16,
|
|
||||||
IRC_RESET = 0x0F,
|
|
||||||
IRC_ITALIC = 0x1D,
|
|
||||||
IRC_UNDERLINE = 0x1F,
|
|
||||||
};
|
|
||||||
static const wchar_t IRC_CODES[] = {
|
static const wchar_t IRC_CODES[] = {
|
||||||
L' ',
|
L' ',
|
||||||
IRC_BOLD,
|
IRC_BOLD,
|
||||||
|
@ -324,199 +317,71 @@ static void logDown(void) {
|
||||||
ui.scroll = MIN(ui.scroll + logHeight() / 2, LOG_LINES);
|
ui.scroll = MIN(ui.scroll + logHeight() / 2, LOG_LINES);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum { BUF_LEN = 512 };
|
static bool keyChar(wint_t ch) {
|
||||||
static struct {
|
|
||||||
wchar_t buf[BUF_LEN];
|
|
||||||
wchar_t *ptr;
|
|
||||||
wchar_t *end;
|
|
||||||
} line = { .ptr = line.buf, .end = line.buf };
|
|
||||||
|
|
||||||
static void left(void) {
|
|
||||||
if (line.ptr > line.buf) line.ptr--;
|
|
||||||
}
|
|
||||||
static void right(void) {
|
|
||||||
if (line.ptr < line.end) line.ptr++;
|
|
||||||
}
|
|
||||||
static void home(void) {
|
|
||||||
line.ptr = line.buf;
|
|
||||||
}
|
|
||||||
static void end(void) {
|
|
||||||
line.ptr = line.end;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void kill(void) {
|
|
||||||
line.end = line.ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void insert(wchar_t ch) {
|
|
||||||
if (line.end == &line.buf[BUF_LEN - 1]) return;
|
|
||||||
if (line.ptr != line.end) {
|
|
||||||
wmemmove(line.ptr + 1, line.ptr, line.end - line.ptr);
|
|
||||||
}
|
|
||||||
*line.ptr++ = ch;
|
|
||||||
line.end++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void backspace(void) {
|
|
||||||
if (line.ptr == line.buf) return;
|
|
||||||
if (line.ptr != line.end) {
|
|
||||||
wmemmove(line.ptr - 1, line.ptr, line.end - line.ptr);
|
|
||||||
}
|
|
||||||
line.ptr--;
|
|
||||||
line.end--;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void delete(void) {
|
|
||||||
if (line.ptr == line.end) return;
|
|
||||||
right();
|
|
||||||
backspace();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void enter(void) {
|
|
||||||
if (line.end == line.buf) return;
|
|
||||||
*line.end = L'\0';
|
|
||||||
char *str = awcstombs(line.buf);
|
|
||||||
if (!str) err(EX_DATAERR, "awcstombs");
|
|
||||||
input(str);
|
|
||||||
free(str);
|
|
||||||
line.ptr = line.buf;
|
|
||||||
line.end = line.buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct {
|
|
||||||
wchar_t *word;
|
|
||||||
char *prefix;
|
|
||||||
} tab;
|
|
||||||
|
|
||||||
static void accept(void) {
|
|
||||||
if (!tab.word) return;
|
|
||||||
tab.word = NULL;
|
|
||||||
free(tab.prefix);
|
|
||||||
tabAccept();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reject(void) {
|
|
||||||
if (!tab.word) return;
|
|
||||||
tab.word = NULL;
|
|
||||||
free(tab.prefix);
|
|
||||||
tabReject();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void complete(void) {
|
|
||||||
if (!tab.word) {
|
|
||||||
wchar_t ch = *line.ptr;
|
|
||||||
*line.ptr = L'\0';
|
|
||||||
tab.word = wcsrchr(line.buf, L' ');
|
|
||||||
tab.word = (tab.word ? &tab.word[1] : line.buf);
|
|
||||||
tab.prefix = awcstombs(tab.word);
|
|
||||||
if (!tab.prefix) err(EX_DATAERR, "awcstombs");
|
|
||||||
*line.ptr = ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *complete = tabNext(tab.prefix);
|
|
||||||
if (!complete) {
|
|
||||||
reject();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t *wcs = ambstowcs(complete);
|
|
||||||
if (!wcs) err(EX_DATAERR, "ambstowcs");
|
|
||||||
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; wcs[i] && line.ptr > &tab.word[i]; ++i) {
|
|
||||||
tab.word[i] = wcs[i];
|
|
||||||
}
|
|
||||||
while (line.ptr > &tab.word[i]) {
|
|
||||||
backspace();
|
|
||||||
}
|
|
||||||
for (; wcs[i]; ++i) {
|
|
||||||
insert(wcs[i]);
|
|
||||||
}
|
|
||||||
free(wcs);
|
|
||||||
|
|
||||||
if (tab.word == line.buf) insert(L':');
|
|
||||||
insert(L' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
static void keyChar(wint_t ch) {
|
|
||||||
static bool esc, csi;
|
static bool esc, csi;
|
||||||
|
bool update = false;
|
||||||
if (csi) {
|
|
||||||
csi = false;
|
|
||||||
if (ch == L'O') logMark();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
csi = (esc && ch == L'[');
|
|
||||||
esc = (ch == L'\33');
|
|
||||||
if (csi) return;
|
|
||||||
|
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
break; case CTRL('L'): uiRedraw();
|
break; case CTRL('L'): uiRedraw();
|
||||||
break; case CTRL('B'): reject(); left();
|
break; case CTRL('['): esc = true; return false;
|
||||||
break; case CTRL('F'): reject(); right();
|
break; case L'\b': update = edit(esc, false, L'\b');
|
||||||
break; case CTRL('A'): reject(); home();
|
break; case L'\177': update = edit(esc, false, L'\b');
|
||||||
break; case CTRL('E'): reject(); end();
|
break; case L'\t': update = edit(esc, false, L'\t');
|
||||||
break; case CTRL('D'): reject(); delete();
|
break; case L'\n': update = edit(esc, false, L'\n');
|
||||||
break; case CTRL('K'): reject(); kill();
|
|
||||||
break; case L'\b': reject(); backspace();
|
|
||||||
break; case L'\177': reject(); backspace();
|
|
||||||
break; case L'\t': complete();
|
|
||||||
break; case L'\n': accept(); enter();
|
|
||||||
break; case CTRL('C'): accept(); insert(IRC_COLOR);
|
|
||||||
break; case CTRL('N'): accept(); insert(IRC_RESET);
|
|
||||||
break; case CTRL('O'): accept(); insert(IRC_BOLD);
|
|
||||||
break; case CTRL('R'): accept(); insert(IRC_COLOR);
|
|
||||||
break; case CTRL('T'): accept(); insert(IRC_ITALIC);
|
|
||||||
break; case CTRL('U'): accept(); insert(IRC_UNDERLINE);
|
|
||||||
break; case CTRL('V'): accept(); insert(IRC_REVERSE);
|
|
||||||
break; default: {
|
break; default: {
|
||||||
if (iswprint(ch)) {
|
if (esc && ch == L'[') {
|
||||||
accept();
|
csi = true;
|
||||||
insert(ch);
|
return false;
|
||||||
|
} else if (csi) {
|
||||||
|
if (ch == L'O') logMark();
|
||||||
|
} else if (iswcntrl(ch)) {
|
||||||
|
update = edit(esc, true, UNCTRL(ch));
|
||||||
|
} else {
|
||||||
|
update = edit(esc, false, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
esc = false;
|
||||||
|
csi = false;
|
||||||
|
return update;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyCode(wint_t ch) {
|
static bool keyCode(wint_t ch) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
break; case KEY_RESIZE: uiResize();
|
break; case KEY_RESIZE: uiResize();
|
||||||
break; case KEY_PPAGE: logUp();
|
break; case KEY_PPAGE: logUp();
|
||||||
break; case KEY_NPAGE: logDown();
|
break; case KEY_NPAGE: logDown();
|
||||||
break; case KEY_LEFT: left();
|
break; case KEY_LEFT: return edit(false, true, 'B');
|
||||||
break; case KEY_RIGHT: right();
|
break; case KEY_RIGHT: return edit(false, true, 'F');
|
||||||
break; case KEY_HOME: home();
|
break; case KEY_HOME: return edit(false, true, 'A');
|
||||||
break; case KEY_END: end();
|
break; case KEY_END: return edit(false, true, 'E');
|
||||||
break; case KEY_BACKSPACE: backspace();
|
break; case KEY_DC: return edit(false, true, 'D');
|
||||||
break; case KEY_DC: delete();
|
break; case KEY_BACKSPACE: return edit(false, false, '\b');
|
||||||
break; case KEY_ENTER: enter();
|
break; case KEY_ENTER: return edit(false, false, '\n');
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiRead(void) {
|
void uiRead(void) {
|
||||||
|
bool update = false;
|
||||||
int ret;
|
int ret;
|
||||||
wint_t ch;
|
wint_t ch;
|
||||||
while (ERR != (ret = wget_wch(ui.input, &ch))) {
|
while (ERR != (ret = wget_wch(ui.input, &ch))) {
|
||||||
if (ret == KEY_CODE_YES) {
|
if (ret == KEY_CODE_YES) {
|
||||||
keyCode(ch);
|
update |= keyCode(ch);
|
||||||
} else {
|
} else {
|
||||||
keyChar(ch);
|
update |= keyChar(ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!update) return;
|
||||||
|
|
||||||
wmove(ui.input, 1, 0);
|
wmove(ui.input, 1, 0);
|
||||||
|
addIRC(ui.input, editHead());
|
||||||
|
|
||||||
ch = *line.ptr;
|
int y, x;
|
||||||
*line.ptr = L'\0';
|
getyx(ui.input, y, x);
|
||||||
addIRC(ui.input, line.buf);
|
|
||||||
*line.ptr = ch;
|
|
||||||
|
|
||||||
int _, x;
|
addIRC(ui.input, editTail());
|
||||||
getyx(ui.input, _, x);
|
|
||||||
|
|
||||||
*line.end = L'\0';
|
|
||||||
addIRC(ui.input, line.ptr);
|
|
||||||
|
|
||||||
wclrtoeol(ui.input);
|
wclrtoeol(ui.input);
|
||||||
wmove(ui.input, 1, x);
|
wmove(ui.input, y, x);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue