diff options
| -rw-r--r-- | buffer.c | 5 | ||||
| -rw-r--r-- | chat.h | 1 | ||||
| -rw-r--r-- | ui.c | 206 | 
3 files changed, 53 insertions, 159 deletions
@@ -178,6 +178,11 @@ int bufferPush(  	return flow(&buffer->hard, cols, soft);  } +int bufferBlank(struct Buffer *buffer) { +	struct Line blank = { .heat = Cold, .str = "" }; +	return flow(&buffer->hard, 1, &blank); +} +  void bufferReflow(struct Buffer *buffer, int cols) {  	buffer->hard.len = 0;  	for (size_t i = 0; i < BufferCap; ++i) { @@ -291,6 +291,7 @@ int bufferPush(  	struct Buffer *buffer, int cols,  	enum Heat heat, time_t time, const char *str  ); +int bufferBlank(struct Buffer *buffer);  void bufferReflow(struct Buffer *buffer, int cols);  enum Edit { @@ -59,7 +59,6 @@  enum {  	StatusLines = 1, -	WindowLines = 1024,  	MarkerLines = 1,  	SplitLines = 5,  	InputLines = 1, @@ -71,12 +70,11 @@ enum {  #define MAIN_LINES (LINES - StatusLines - InputLines)  static WINDOW *status; -static WINDOW *marker; +static WINDOW *main;  static WINDOW *input;  struct Window {  	uint id; -	WINDOW *pad;  	int scroll;  	bool mark;  	bool mute; @@ -136,10 +134,6 @@ static uint windowFor(uint id) {  	if (!window) err(EX_OSERR, "malloc");  	window->id = id; -	window->pad = newpad(WindowLines, COLS); -	if (!window->pad) err(EX_OSERR, "newpad"); -	scrollok(window->pad, true); -	wmove(window->pad, WindowLines - 1, 0);  	window->mark = true;  	window->ignore = true;  	window->buffer = bufferAlloc(); @@ -149,7 +143,6 @@ static uint windowFor(uint id) {  static void windowFree(struct Window *window) {  	bufferFree(window->buffer); -	delwin(window->pad);  	free(window);  } @@ -275,11 +268,8 @@ void uiInit(void) {  	status = newwin(StatusLines, COLS, 0, 0);  	if (!status) err(EX_OSERR, "newwin"); -	marker = newwin( -		MarkerLines, COLS, -		LINES - InputLines - SplitLines - MarkerLines, 0 -	); -	wbkgd(marker, ACS_BULLET); +	main = newwin(MAIN_LINES, COLS, StatusLines, 0); +	if (!main) err(EX_OSERR, "newwin");  	input = newpad(InputLines, InputCols);  	if (!input) err(EX_OSERR, "newpad"); @@ -299,30 +289,7 @@ static char prevTitle[sizeof(title)];  void uiDraw(void) {  	if (hidden) return;  	wnoutrefresh(status); -	const struct Window *window = windows.ptrs[windows.show]; -	if (!window->scroll) { -		pnoutrefresh( -			window->pad, -			WindowLines - MAIN_LINES, 0, -			StatusLines, 0, -			BOTTOM - InputLines, RIGHT -		); -	} else { -		pnoutrefresh( -			window->pad, -			WindowLines - window->scroll - MAIN_LINES + MarkerLines, 0, -			StatusLines, 0, -			BOTTOM - InputLines - SplitLines - MarkerLines, RIGHT -		); -		touchwin(marker); -		wnoutrefresh(marker); -		pnoutrefresh( -			window->pad, -			WindowLines - SplitLines, 0, -			LINES - InputLines - SplitLines, 0, -			BOTTOM - InputLines, RIGHT -		); -	} +	wnoutrefresh(main);  	int y, x;  	getyx(input, y, x);  	pnoutrefresh( @@ -383,12 +350,12 @@ static short stylePair(struct Style style) {  	return colorPair(Colors[style.fg], Colors[style.bg]);  } -static void statusAdd(const char *str) { +static void styleAdd(WINDOW *win, const char *str) {  	struct Style style = StyleDefault;  	while (*str) {  		size_t len = styleParse(&style, &str); -		wattr_set(status, styleAttr(style), stylePair(style), NULL); -		waddnstr(status, str, len); +		wattr_set(win, styleAttr(style), stylePair(style), NULL); +		waddnstr(win, str, len);  		str += len;  	}  } @@ -431,7 +398,7 @@ static void statusUpdate(void) {  		if (window->scroll) {  			catf(&cat, "~%d ", window->scroll);  		} -		statusAdd(buf); +		styleAdd(status, buf);  	}  	wclrtoeol(status); @@ -480,14 +447,35 @@ void uiHide(void) {  	endwin();  } +static void windowUpdate(void) { +	struct Window *window = windows.ptrs[windows.show]; + +	int y = MAIN_LINES - 1; +	for (size_t i = BufferCap - 1 - window->scroll; i < BufferCap; --i) { +		const struct Line *line = bufferHard(window->buffer, i); +		if (!line) continue; +		if (line->heat < Cold && window->ignore) continue; +		wmove(main, y, 0); +		styleAdd(main, line->str); +		wclrtoeol(main); +		if (!y--) break; +	} + +	while (y >= 0) { +		wmove(main, y--, 0); +		wclrtoeol(main); +	} +} +  static void windowScroll(struct Window *window, int n) {  	mark(window);  	window->scroll += n; -	if (window->scroll > WindowLines - MAIN_LINES) { -		window->scroll = WindowLines - MAIN_LINES; +	if (window->scroll > BufferCap - MAIN_LINES) { +		window->scroll = BufferCap - MAIN_LINES;  	}  	if (window->scroll < 0) window->scroll = 0;  	unmark(window); +	windowUpdate();  }  static void windowScrollPage(struct Window *window, int n) { @@ -499,72 +487,6 @@ static void windowScrollUnread(struct Window *window) {  	windowScroll(window, window->unreadHard - MAIN_LINES);  } -static int wordWidth(const char *str) { -	size_t len = strcspn(str, " \t"); -	int width = 0; -	while (len) { -		wchar_t wc; -		int n = mbtowc(&wc, str, len); -		if (n < 1) return width + len; -		width += (iswprint(wc) ? wcwidth(wc) : 0); -		str += n; -		len -= n; -	} -	return width; -} - -// XXX: ncurses likes to render zero-width characters as spaces... -static int waddnstrnzw(WINDOW *win, const char *str, int len) { -	wchar_t wc; -	while (len) { -		int n = mbtowc(&wc, str, len); -		if (n < 1) return waddnstr(win, str, len); -		if (wcwidth(wc)) waddnstr(win, str, n); -		str += n; -		len -= n; -	} -	return OK; -} - -static int wordWrap(WINDOW *win, const char *str) { -	int y, x, width; -	getmaxyx(win, y, width); -	waddch(win, '\n'); - -	int lines = 1; -	int align = 0; -	struct Style style = StyleDefault; -	while (*str) { -		char ch = *str; -		if (ch == ' ' || ch == '\t') { -			getyx(win, y, x); -			const char *word = &str[strspn(str, " \t")]; -			if (width - x - 1 <= wordWidth(word)) { -				lines += 1 + (align + wordWidth(word)) / width; -				waddch(win, '\n'); -				getyx(win, y, x); -				wmove(win, y, align); -				str = word; -			} else { -				waddch(win, (align ? ch : ' ')); -				str++; -			} -		} -		if (ch == '\t' && !align) { -			getyx(win, y, align); -		} - -		size_t len = styleParse(&style, &str); -		size_t ws = strcspn(str, " \t"); -		if (ws < len) len = ws; - -		wattr_set(win, styleAttr(style), stylePair(style), NULL); -		waddnstrnzw(win, str, len); -		str += len; -	} -	return lines; -} -  struct Util uiNotifyUtil;  static void notify(uint id, const char *str) {  	if (!uiNotifyUtil.argc) return; @@ -596,23 +518,21 @@ static void notify(uint id, const char *str) {  void uiWrite(uint id, enum Heat heat, const time_t *src, const char *str) {  	struct Window *window = windows.ptrs[windowFor(id)];  	time_t ts = (src ? *src : time(NULL)); -	bufferPush(window->buffer, COLS, heat, ts, str); + +	int lines = bufferPush(window->buffer, COLS, heat, ts, str);  	if (heat < Cold && window->ignore) return; -	int lines = 0;  	if (!window->unreadSoft++) window->unreadHard = 0;  	if (window->mark && heat > Cold) {  		if (!window->unreadWarm++) { -			lines++; -			waddch(window->pad, '\n'); +			lines += bufferBlank(window->buffer);  		}  		if (heat > window->heat) window->heat = heat;  		statusUpdate();  	} - -	lines += wordWrap(window->pad, str);  	window->unreadHard += lines;  	if (window->scroll) windowScroll(window, lines); +	windowUpdate();  	if (window->mark && heat > Warm) {  		beep(); @@ -632,45 +552,13 @@ void uiFormat(  	uiWrite(id, heat, time, buf);  } -static void reflow(struct Window *window) { -	werase(window->pad); -	wmove(window->pad, 0, 0); - -	int flowed = 0; -	window->unreadHard = 0; -	for (size_t i = 0; i < BufferCap; ++i) { -		const struct Line *line = bufferSoft(window->buffer, i); -		if (!line) continue; -		if (line->heat < Cold && window->ignore) continue; -		int lines = 0; -		if (i == (size_t)(BufferCap - window->unreadSoft)) { -			waddch(window->pad, '\n'); -			lines++; -		} -		lines += wordWrap(window->pad, line->str); -		if (i >= (size_t)(BufferCap - window->unreadSoft)) { -			window->unreadHard += lines; -		} -		flowed += lines; -	} - -	if (flowed < WindowLines) { -		wscrl(window->pad, -(WindowLines - 1 - flowed)); -		wmove(window->pad, WindowLines - 1, RIGHT); -	} -} -  static void resize(void) { -	mvwin(marker, LINES - InputLines - SplitLines - MarkerLines, 0); -	int height, width; -	getmaxyx(windows.ptrs[0]->pad, height, width); -	if (width == COLS) return; +	statusUpdate(); +	wresize(main, MAIN_LINES, COLS);  	for (uint num = 0; num < windows.len; ++num) { -		wresize(windows.ptrs[num]->pad, WindowLines, COLS); -		reflow(windows.ptrs[num]); +		bufferReflow(windows.ptrs[num]->buffer, COLS);  	} -	(void)height; -	statusUpdate(); +	windowUpdate();  }  static void bufferList(const struct Buffer *buffer) { @@ -793,12 +681,12 @@ static void inputUpdate(void) {  }  static void windowShow(uint num) { -	touchwin(windows.ptrs[num]->pad);  	windows.swap = windows.show;  	windows.show = num;  	windows.user = num;  	mark(windows.ptrs[windows.swap]);  	unmark(windows.ptrs[windows.show]); +	windowUpdate();  	inputUpdate();  } @@ -830,6 +718,7 @@ static void windowClose(uint num) {  		windows.swap = windows.show;  	} else if (windows.show > num) {  		windows.show--; +		windowUpdate();  	}  	statusUpdate();  } @@ -844,7 +733,7 @@ void uiCloseNum(uint num) {  static void toggleIgnore(struct Window *window) {  	window->ignore ^= true; -	reflow(window); +	windowUpdate();  	statusUpdate();  } @@ -889,8 +778,8 @@ static void keyCode(int code) {  		break; case KeyMetaMinus: toggleIgnore(window);  		break; case KeyMetaSlash: windowShow(windows.swap); -		break; case KeyMetaGt: windowScroll(window, -WindowLines); -		break; case KeyMetaLt: windowScroll(window, +WindowLines); +		break; case KeyMetaGt: windowScroll(window, -BufferCap); +		break; case KeyMetaLt: windowScroll(window, +BufferCap);  		break; case KeyMeta0 ... KeyMeta9: uiShowNum(code - KeyMeta0);  		break; case KeyMetaA: showAuto(); @@ -898,7 +787,7 @@ static void keyCode(int code) {  		break; case KeyMetaD: edit(id, EditDeleteNextWord, 0);  		break; case KeyMetaF: edit(id, EditNextWord, 0);  		break; case KeyMetaL: bufferList(window->buffer); -		break; case KeyMetaM: waddch(window->pad, '\n'); +		break; case KeyMetaM: bufferBlank(window->buffer); windowUpdate();  		break; case KeyMetaQ: edit(id, EditCollapse, 0);  		break; case KeyMetaU: windowScrollUnread(window);  		break; case KeyMetaV: windowScrollPage(window, +1); @@ -913,8 +802,8 @@ static void keyCode(int code) {  		break; case KEY_NPAGE: windowScrollPage(window, -1);  		break; case KEY_PPAGE: windowScrollPage(window, +1);  		break; case KEY_RIGHT: edit(id, EditNext, 0); -		break; case KEY_SEND: windowScroll(window, -WindowLines); -		break; case KEY_SHOME: windowScroll(window, +WindowLines); +		break; case KEY_SEND: windowScroll(window, -BufferCap); +		break; case KEY_SHOME: windowScroll(window, +BufferCap);  		break; case KEY_UP: windowScroll(window, +1);  	}  } @@ -1095,7 +984,6 @@ void uiLoad(const char *name) {  			readString(file, &buf, &cap);  			bufferPush(window->buffer, COLS, heat, time, buf);  		} -		reflow(window);  	}  	free(buf);  | 
