summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ui.c234
1 files changed, 139 insertions, 95 deletions
diff --git a/ui.c b/ui.c
index 7cfb417..8b3c1eb 100644
--- a/ui.c
+++ b/ui.c
@@ -37,7 +37,7 @@
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 
-#define CTRL(c)   ((c) & 037)
+#define CTRL(c)   ((c) ^ 0100)
 
 static void colorInit(void) {
 	start_color();
@@ -105,9 +105,7 @@ static void viewRemove(struct View *view) {
 	views.tags[view->tag.id] = NULL;
 }
 
-static const int LOG_LINES   = 256;
-static const int TOPIC_COLS  = 512;
-static const int INPUT_COLS  = 512;
+static const int LOG_LINES = 256;
 
 static int logHeight(const struct View *view) {
 	return LINES - (view->topic ? 2 : 0) - 2;
@@ -141,6 +139,13 @@ static struct View *viewTag(struct Tag tag) {
 	return view;
 }
 
+static void viewResize(void) {
+	for (struct View *view = views.head; view; view = view->next) {
+		wresize(view->log, LOG_LINES, COLS);
+		wmove(view->log, lastLogLine(), lastCol());
+	}
+}
+
 static void viewClose(struct View *view) {
 	viewRemove(view);
 	if (view->topic) delwin(view->topic);
@@ -157,61 +162,29 @@ static void viewUnmark(struct View *view) {
 	view->mark = false;
 }
 
+static const int COLS_MAX = 512;
+
 static struct {
 	bool hide;
 	struct View *view;
+	WINDOW *status;
 	WINDOW *input;
 } ui;
 
-void uiHide(void) {
-	ui.hide = true;
-	termMode(TERM_FOCUS, false);
-	endwin();
-}
-
 static void uiShow(void) {
 	ui.hide = false;
 	termMode(TERM_FOCUS, true);
 }
 
-void uiInit(void) {
-	setlocale(LC_CTYPE, "");
-	initscr();
-	cbreak();
-	noecho();
-
-	colorInit();
-	termInit();
-
-	ui.input = newpad(2, INPUT_COLS);
-	mvwhline(ui.input, 0, 0, ACS_HLINE, INPUT_COLS);
-	wmove(ui.input, 1, 0);
-	keypad(ui.input, true);
-	nodelay(ui.input, true);
-
-	ui.view = viewTag(TAG_STATUS);
-	termTitle(TAG_STATUS.name);
-
-	uiShow();
-}
-
-void uiExit(void) {
-	uiHide();
-	printf(
-		"This program is AGPLv3 free software!\n"
-		"The source is available at <" SOURCE_URL ">.\n"
-	);
-}
-
-static void uiResize(void) {
-	for (struct View *view = views.head; view; view = view->next) {
-		wresize(view->log, LOG_LINES, COLS);
-		wmove(view->log, lastLogLine(), lastCol());
-	}
+void uiHide(void) {
+	ui.hide = true;
+	termMode(TERM_FOCUS, false);
+	endwin();
 }
 
 void uiDraw(void) {
 	if (ui.hide) return;
+
 	if (ui.view->topic) {
 		pnoutrefresh(
 			ui.view->topic,
@@ -220,20 +193,31 @@ void uiDraw(void) {
 			1, lastCol()
 		);
 	}
+
 	pnoutrefresh(
 		ui.view->log,
 		ui.view->scroll - logHeight(ui.view), 0,
 		(ui.view->topic ? 2 : 0), 0,
 		lastLine() - 2, lastCol()
 	);
+
 	int _, x;
+	getyx(ui.status, _, x);
+	pnoutrefresh(
+		ui.status,
+		0, MAX(0, x - lastCol() - 1),
+		lastLine() - 1, 0,
+		lastLine() - 1, lastCol()
+	);
+
 	getyx(ui.input, _, x);
 	pnoutrefresh(
 		ui.input,
 		0, MAX(0, x - lastCol() + 3),
-		lastLine() - 1, 0,
+		lastLine(), 0,
 		lastLine(), lastCol()
 	);
+
 	doupdate();
 }
 
@@ -241,52 +225,6 @@ static void uiRedraw(void) {
 	clearok(curscr, true);
 }
 
-static void uiView(struct View *view) {
-	termTitle(view->tag.name);
-	if (view->topic) touchwin(view->topic);
-	touchwin(view->log);
-	viewMark(ui.view);
-	viewUnmark(view);
-	ui.view = view;
-}
-
-static void uiClose(struct View *view) {
-	if (ui.view == view) {
-		if (view->next) {
-			uiView(view->next);
-		} else if (view->prev) {
-			uiView(view->prev);
-		} else {
-			return;
-		}
-	}
-	viewClose(view);
-}
-
-void uiViewTag(struct Tag tag) {
-	uiView(viewTag(tag));
-}
-
-void uiCloseTag(struct Tag tag) {
-	uiClose(viewTag(tag));
-}
-
-void uiViewNum(int num) {
-	if (num < 0) {
-		for (struct View *view = views.tail; view; view = view->prev) {
-			if (++num) continue;
-			uiView(view);
-			break;
-		}
-	} else {
-		for (struct View *view = views.head; view; view = view->next) {
-			if (num--) continue;
-			uiView(view);
-			break;
-		}
-	}
-}
-
 static const short IRC_COLORS[] = {
 	[IRC_WHITE]       = 8 + COLOR_WHITE,
 	[IRC_BLACK]       = 0 + COLOR_BLACK,
@@ -381,11 +319,88 @@ static void addIRC(WINDOW *win, const wchar_t *str) {
 	}
 }
 
+static void uiStatus(void) {
+	mvwhline(ui.status, 0, 0, ACS_HLINE, COLS);
+	mvwaddch(ui.status, 0, COLS, ACS_RTEE);
+
+	int num = 0;
+	int count = 0;
+	for (const struct View *view = views.head; view; view = view->next, ++num) {
+		if (!view->unread) continue;
+		bool status = (view->tag.id == TAG_STATUS.id);
+
+		int unread;
+		wchar_t *str;
+		int len = aswprintf(
+			&str, L",\3%02d%d\3%s%s%n(%d)",
+			(view->hot ? IRC_YELLOW : IRC_WHITE), num,
+			&status[":"], (status ? "" : view->tag.name),
+			&unread, view->unread
+		);
+		if (len < 0) err(EX_OSERR, "aswprintf");
+		if (view->unread == 1) str[unread] = L'\0';
+
+		addIRC(ui.status, count ? str : &str[1]);
+		free(str);
+		count++;
+	}
+
+	waddch(ui.status, count ? ACS_LTEE : '\b');
+	waddch(ui.status, ACS_HLINE);
+}
+
+static void uiView(struct View *view) {
+	termTitle(view->tag.name);
+	if (view->topic) touchwin(view->topic);
+	touchwin(view->log);
+	viewMark(ui.view);
+	viewUnmark(view);
+	ui.view = view;
+	uiStatus();
+}
+
+static void uiClose(struct View *view) {
+	if (ui.view == view) {
+		if (view->next) {
+			uiView(view->next);
+		} else if (view->prev) {
+			uiView(view->prev);
+		} else {
+			return;
+		}
+	}
+	viewClose(view);
+}
+
+void uiViewTag(struct Tag tag) {
+	uiView(viewTag(tag));
+}
+
+void uiCloseTag(struct Tag tag) {
+	uiClose(viewTag(tag));
+}
+
+void uiViewNum(int num) {
+	if (num < 0) {
+		for (struct View *view = views.tail; view; view = view->prev) {
+			if (++num) continue;
+			uiView(view);
+			break;
+		}
+	} else {
+		for (struct View *view = views.head; view; view = view->next) {
+			if (num--) continue;
+			uiView(view);
+			break;
+		}
+	}
+}
+
 void uiTopic(struct Tag tag, const char *topic) {
 	struct View *view = viewTag(tag);
 	if (!view->topic) {
-		view->topic = newpad(2, TOPIC_COLS);
-		mvwhline(view->topic, 1, 0, ACS_HLINE, TOPIC_COLS);
+		view->topic = newpad(2, COLS_MAX);
+		mvwhline(view->topic, 1, 0, ACS_HLINE, COLS_MAX);
 	}
 	wchar_t *wcs = ambstowcs(topic);
 	if (!wcs) err(EX_DATAERR, "ambstowcs");
@@ -404,6 +419,7 @@ void uiLog(struct Tag tag, enum UIHeat heat, const wchar_t *line) {
 			view->hot = true;
 			beep(); // TODO: Notification.
 		}
+		uiStatus();
 	}
 	addIRC(view->log, line);
 }
@@ -419,6 +435,34 @@ void uiFmt(struct Tag tag, enum UIHeat heat, const wchar_t *format, ...) {
 	free(wcs);
 }
 
+void uiInit(void) {
+	setlocale(LC_CTYPE, "");
+	initscr();
+	cbreak();
+	noecho();
+
+	colorInit();
+	termInit();
+
+	ui.status = newpad(1, COLS_MAX);
+	ui.input = newpad(1, COLS_MAX);
+	keypad(ui.input, true);
+	nodelay(ui.input, true);
+
+	ui.view = viewTag(TAG_STATUS);
+	uiViewTag(TAG_STATUS);
+	uiStatus();
+	uiShow();
+}
+
+void uiExit(void) {
+	uiHide();
+	printf(
+		"This program is AGPLv3 free software!\n"
+		"The source is available at <" SOURCE_URL ">.\n"
+	);
+}
+
 static void logScrollUp(int lines) {
 	int height = logHeight(ui.view);
 	if (ui.view->scroll == height) return;
@@ -505,7 +549,7 @@ static bool keyChar(wchar_t ch) {
 
 static bool keyCode(wchar_t ch) {
 	switch (ch) {
-		break; case KEY_RESIZE:    uiResize(); return false;
+		break; case KEY_RESIZE:    viewResize(); return false;
 		break; case KEY_SLEFT:     logScrollUp(1); return false;
 		break; case KEY_SRIGHT:    logScrollDown(1); return false;
 		break; case KEY_PPAGE:     logPageUp(); return false;
@@ -537,7 +581,7 @@ void uiRead(void) {
 	if (!update) return;
 
 	int y, x;
-	wmove(ui.input, 1, 0);
+	wmove(ui.input, 0, 0);
 	addIRC(ui.input, editHead());
 	getyx(ui.input, y, x);
 	addIRC(ui.input, editTail());
Git commands. Signed-off-by: John Keeping <john@keeping.me.uk> 2014-01-12cache: don't leave cache_slot fields uninitializedJohn Keeping Valgrind says: ==18344== Conditional jump or move depends on uninitialised value(s) ==18344== at 0x406C83: open_slot (cache.c:63) ==18344== by 0x407478: cache_ls (cache.c:403) ==18344== by 0x404C9A: process_request (cgit.c:639) ==18344== by 0x406BD2: fill_slot (cache.c:190) ==18344== by 0x4071A0: cache_process (cache.c:284) ==18344== by 0x404461: main (cgit.c:952) ==18344== Uninitialised value was created by a stack allocation ==18344== at 0x40738B: cache_ls (cache.c:375) This is caused by the keylen field being used to calculate whether or not a slot is matched. We never then check the value of this and the length of data read depends on the key length read from the file so this isn't dangerous, but it's nice to avoid branching based on uninitialized data. Signed-off-by: John Keeping <john@keeping.me.uk> 2014-01-10filter: split filter functions into their own fileJason A. Donenfeld A first step for more interesting things. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> 2014-01-10filter: make exit status localJason A. Donenfeld It's only used in one place, and not useful to have around since close_filter will die() if exit_status isn't what it expects, anyway. So this is best as just a local variable instead of as part of the struct. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> 2014-01-10parsing: fix header typoJason A. Donenfeld 2014-01-10cgit.c: Fix comment on bit mask hackLukas Fleischer * Formatting and spelling fixes. * A bit mask with the size of one byte only allows for storing 8 (not 255!) different flags. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de> 2014-01-10cgit.c: Use "else" for mutually exclusive branchesLukas Fleischer When parsing command line arguments, no pair of command line options can ever match simultaneously. Use "else if" blocks to reflect this. This change improves both readability and speed. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de> 2014-01-10ui-snapshot.c: Do not reinvent suffixcmp()Lukas Fleischer Use suffixcmp() from Git instead of reimplementing it. This is a preparation for moving to ends_with() in Git 1.8.6. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de> 2014-01-10Refactor cgit_parse_snapshots_mask()Lukas Fleischer Use Git string lists instead of str{spn,cspn,ncmp}() magic. This significantly improves readability. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de> 2014-01-10Disallow use of undocumented snapshot delimitersLukas Fleischer Since the introduction of selective snapshot format configuration in dc3c9b5 (allow selective enabling of snapshots, 2007-07-21), we allowed seven different delimiters for snapshot formats, while the documentation has always been clear about spaces being the only valid delimiter: The value is a space-separated list of zero or more of the values "tar", "tar.gz", "tar.bz2", "tar.xz" and "zip". Supporting the undocumented delimiters makes the code unnecessarily complex. Remove them. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de> 2014-01-10Replace most uses of strncmp() with prefixcmp()Lukas Fleischer This is a preparation for replacing all prefix checks with either strip_prefix() or starts_with() when Git 1.8.6 is released. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de> 2014-01-09README: Fix dependenciesLukas Fleischer * Remove the dependency on Git (which can be obtained automatically when building, using either the Git submodule or `make get-git`). * Use proper upstream names of dependencies. Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de> 2014-01-08README: Spelling and formatting fixesLukas Fleischer * Several small spelling and capitalization fixes. * Use consistent and better-looking formatting that is compatible with AsciiDoc (and partly compatible with RST). Signed-off-by: Lukas Fleischer <cgit@cryptocrack.de> 2014-01-08Fix UTF-8 with syntax-highlighting.pyPřemysl Janouch Previously the script tried to encode output from Pygments with the ASCII codec, which failed. Signed-off-by: Přemysl Janouch <p.janouch@gmail.com> 2014-01-08Add a suggestion to the manpagePřemysl Janouch So that people wishing to use "enable-http-clone" don't have to find out the correct settings on their own. Signed-off-by: Přemysl Janouch <p.janouch@gmail.com> 2014-01-08Fix the example configurationPřemysl Janouch "enable-git-clone" doesn't exist, replaced with "enable-http-clone". Signed-off-by: Přemysl Janouch <p.janouch@gmail.com> 2014-01-08Fix about-formatting.shPřemysl Janouch dash failed to parse the script. Signed-off-by: Přemysl Janouch <p.janouch@gmail.com> 2014-01-08Fix some spelling errorsPřemysl Janouch Signed-off-by: Přemysl Janouch <p.janouch@gmail.com> 2014-01-08filters: highlight.sh: add css comments for highlight 2.6 and 3.8Ferry Huberts