From 954a9e127ac2c4c0389304f2c66799d92b4b87a4 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch 
Date: Fri, 17 Apr 2015 21:29:18 +0200
Subject: degesch: more user command handling
It's become obvious that I really, really need to finish printing
to buffer first, as I keep adding new TODO comments.
---
 degesch.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 109 insertions(+), 11 deletions(-)
diff --git a/degesch.c b/degesch.c
index c5debdb..1f960ba 100644
--- a/degesch.c
+++ b/degesch.c
@@ -282,6 +282,7 @@ struct app_context
 	struct buffer *buffers;             ///< All our buffers in order
 	struct buffer *buffers_tail;        ///< The tail of our buffers
 
+	// XXX: when we go multiserver, there will be collisions
 	struct str_map buffers_by_name;     ///< Excludes GLOBAL and SERVER
 	struct buffer *global_buffer;       ///< The global buffer
 	struct buffer *server_buffer;       ///< The server buffer
@@ -822,6 +823,8 @@ buffer_remove (struct app_context *ctx, struct buffer *buffer)
 {
 	hard_assert (buffer != ctx->current_buffer);
 
+	// TODO: part from the channel if needed
+
 	// rl_clear_history, being the only way I know of to get rid of the complete
 	// history including attached data, is a pretty recent addition.  *sigh*
 #if RL_READLINE_VERSION >= 0x0603
@@ -1524,16 +1527,107 @@ irc_process_message (const struct irc_message *msg,
 
 // --- User input handling -----------------------------------------------------
 
-static void handle_command_help (struct app_context *, const char *);
+static void handle_command_help (struct app_context *, char *);
+
+/// Cuts the longest non-whitespace portion of text and advances the pointer
+static char *
+cut_word (char **s)
+{
+	char *start = *s;
+	size_t word_len = strcspn (*s, " \t");
+	char *end = start + word_len;
+	*s = end + strspn (end, " \t");
+	*end = '\0';
+	return start;
+}
+
+static bool
+try_handle_buffer_goto (struct app_context *ctx, const char *word)
+{
+	unsigned long n;
+	if (!xstrtoul (&n, word, 10))
+		return false;
+
+	if (n > INT_MAX || !buffer_goto (ctx, n))
+	{
+		// TODO: print a "no such buffer" error message
+	}
+	return true;
+}
+
+static struct buffer *
+try_decode_buffer (struct app_context *ctx, const char *word)
+{
+	unsigned long n;
+	struct buffer *buffer = NULL;
+	if (xstrtoul (&n, word, 10) && n <= INT_MAX)
+		buffer = buffer_at_index (ctx, n);
+	if (!buffer)
+		buffer = str_map_find (&ctx->buffers_by_name, word);
+	// TODO: decode the global and server buffers, partial matches
+	return buffer;
+}
 
 static void
-handle_command_buffer (struct app_context *ctx, const char *arguments)
+handle_command_buffer (struct app_context *ctx, char *arguments)
 {
-	// TODO: parse the arguments
+	char *action = cut_word (&arguments);
+	if (try_handle_buffer_goto (ctx, action))
+		return;
+
+	struct buffer *buffer = NULL;
+
+	// XXX: also build a prefix map?
+	// TODO: some subcommand to print N last lines from the buffer
+	if (!strcasecmp_ascii (action, "list"))
+	{
+		// TODO: print a list of "%d: %s", index, name
+	}
+	else if (!strcasecmp_ascii (action, "clear"))
+	{
+		// TODO
+	}
+	else if (!strcasecmp_ascii (action, "move"))
+	{
+		// TODO: unlink the buffer and link it back at index;
+		//   we will probably need to extend liberty for this
+	}
+	else if (!strcasecmp_ascii (action, "close"))
+	{
+		const char *which = NULL;
+		if (!*arguments)
+			buffer = ctx->current_buffer;
+		else
+			buffer = try_decode_buffer (ctx, (which = cut_word (&arguments)));
+
+		if (!buffer)
+		{
+			// TODO: print a "no such buffer: %s" message
+			return;
+		}
+		if (buffer == ctx->global_buffer)
+		{
+			// TODO: print a "can't close the global buffer" message
+			return;
+		}
+		if (buffer == ctx->server_buffer)
+		{
+			// TODO: print a "can't close the server buffer" message
+			return;
+		}
+
+		if (buffer == ctx->current_buffer)
+			buffer_activate (ctx, buffer_next (ctx, 1));
+		buffer_remove (ctx, buffer);
+	}
+	else
+	{
+		// TODO: show usage (or do something else?)
+	}
 }
 
 static void
-handle_command_quit (struct app_context *ctx, const char *arguments)
+handle_command_quit (struct app_context *ctx, char *arguments)
 {
 	if (ctx->irc_fd != -1)
 	{
@@ -1548,7 +1642,7 @@ handle_command_quit (struct app_context *ctx, const char *arguments)
 static struct command_handler
 {
 	char *name;
-	void (*handler) (struct app_context *ctx, const char *arguments);
+	void (*handler) (struct app_context *ctx, char *arguments);
 	// TODO: probably also a usage string
 }
 g_command_handlers[] =
@@ -1586,7 +1680,7 @@ g_command_handlers[] =
 };
 
 static void
-handle_command_help (struct app_context *ctx, const char *arguments)
+handle_command_help (struct app_context *ctx, char *arguments)
 {
 	// TODO: show a list of all user commands
 }
@@ -1637,13 +1731,17 @@ process_user_command (struct app_context *ctx, char *command)
 		initialized = true;
 	}
 
-	// TODO: cut a single word (strtok_r()?)
-	// TODO: if it's a number, switch to the given buffer
+	char *name = cut_word (&command);
+	if (try_handle_buffer_goto (ctx, name))
+		return;
 
-	struct command_handler *handler = str_map_find (&partial, command);
+	struct command_handler *handler = str_map_find (&partial, name);
 	if (handler)
-		// FIXME: pass arguments correctly
-		handler->handler (ctx, "");
+		handler->handler (ctx, command);
+	else
+	{
+		// TODO: print a "no such command" error message
+	}
 }
 
 static void
-- 
cgit v1.2.3-70-g09d2