From 22d38600d0edbb35029b3076c14e0e119dbf3dd2 Mon Sep 17 00:00:00 2001
From: Ryan Dwyer <ryandwyer1@gmail.com>
Date: Mon, 14 May 2018 22:47:10 +1000
Subject: Implement marks

---
 sway/commands/mark.c   | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++
 sway/commands/unmark.c | 32 ++++++++++++++++++++++++
 2 files changed, 100 insertions(+)
 create mode 100644 sway/commands/mark.c
 create mode 100644 sway/commands/unmark.c

(limited to 'sway/commands')

diff --git a/sway/commands/mark.c b/sway/commands/mark.c
new file mode 100644
index 00000000..782e8ab9
--- /dev/null
+++ b/sway/commands/mark.c
@@ -0,0 +1,68 @@
+#define _POSIX_C_SOURCE 200809L
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/tree/view.h"
+#include "list.h"
+#include "log.h"
+#include "stringop.h"
+
+// mark foo                      Same as mark --replace foo
+// mark --add foo                Add this mark to view's list
+// mark --replace foo            Replace view's marks with this single one
+// mark --add --toggle foo       Toggle current mark and persist other marks
+// mark --replace --toggle foo   Toggle current mark and remove other marks
+
+struct cmd_results *cmd_mark(int argc, char **argv) {
+	struct cmd_results *error = NULL;
+	if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) {
+		return error;
+	}
+	struct sway_container *container =
+		config->handler_context.current_container;
+	if (container->type != C_VIEW) {
+		return cmd_results_new(CMD_INVALID, "mark",
+				"Only views can have marks");
+	}
+	struct sway_view *view = container->sway_view;
+
+	bool add = false, toggle = false;
+	while (argc > 0 && strncmp(*argv, "--", 2) == 0) {
+		if (strcmp(*argv, "--add") == 0) {
+			add = true;
+		} else if (strcmp(*argv, "--replace") == 0) {
+			add = false;
+		} else if (strcmp(*argv, "--toggle") == 0) {
+			toggle = true;
+		} else {
+			return cmd_results_new(CMD_INVALID, "mark",
+					"Unrecognized argument '%s'", *argv);
+		}
+		++argv;
+		--argc;
+	}
+
+	if (!argc) {
+		return cmd_results_new(CMD_INVALID, "mark",
+				"Expected '[--add|--replace] [--toggle] <identifier>'");
+	}
+
+	char *mark = join_args(argv, argc);
+	bool had_mark = view_has_mark(view, mark);
+
+	if (!add) {
+		// Replacing
+		view_clear_marks(view);
+	}
+
+	view_find_and_unmark(mark);
+
+	if (!toggle || (toggle && !had_mark)) {
+		list_add(view->marks, strdup(mark));
+	}
+
+	free(mark);
+	view_execute_criteria(view);
+
+	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c
new file mode 100644
index 00000000..a7d39432
--- /dev/null
+++ b/sway/commands/unmark.c
@@ -0,0 +1,32 @@
+#define _POSIX_C_SOURCE 200809L
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/tree/view.h"
+#include "list.h"
+#include "log.h"
+#include "stringop.h"
+
+struct cmd_results *cmd_unmark(int argc, char **argv) {
+	if (argc == 0) {
+		// Remove all marks from the current container
+		struct sway_container *container =
+			config->handler_context.current_container;
+		if (container->type != C_VIEW) {
+			return cmd_results_new(CMD_INVALID, "unmark",
+					"Only views can have marks");
+		}
+		view_clear_marks(container->sway_view);
+	} else {
+		// Remove a single mark from whichever container has it
+		char *mark = join_args(argv, argc);
+		if (!view_find_and_unmark(mark)) {
+			free(mark);
+			return cmd_results_new(CMD_INVALID, "unmark",
+					"No view exists with that mark");
+		}
+		free(mark);
+	}
+
+	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
-- 
cgit v1.2.3


From 4d1edfcba90854bd7f37ecb1b36fe4f05c37dda3 Mon Sep 17 00:00:00 2001
From: Ryan Dwyer <ryandwyer1@gmail.com>
Date: Tue, 15 May 2018 11:24:16 +1000
Subject: Change unmark implemention to match i3's

---
 include/sway/config.h  |  1 +
 sway/commands.c        |  6 +++---
 sway/commands/mark.c   |  2 +-
 sway/commands/unmark.c | 49 ++++++++++++++++++++++++++++++++++++++-----------
 4 files changed, 43 insertions(+), 15 deletions(-)

(limited to 'sway/commands')

diff --git a/include/sway/config.h b/include/sway/config.h
index f77c3b50..33f52156 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -368,6 +368,7 @@ struct sway_config {
 		struct seat_config *seat_config;
 		struct sway_seat *seat;
 		struct sway_container *current_container;
+		bool using_criteria;
 	} handler_context;
 };
 
diff --git a/sway/commands.c b/sway/commands.c
index 31d241a8..9b6d6459 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -302,7 +302,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
 	head = exec;
 	do {
 		// Extract criteria (valid for this command list only).
-		bool has_criteria = false;
+		config->handler_context.using_criteria = false;
 		if (*head == '[') {
 			char *error = NULL;
 			struct criteria *criteria = criteria_parse(head, &error);
@@ -315,7 +315,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
 			views = criteria_get_views(criteria);
 			head += strlen(criteria->raw);
 			criteria_destroy(criteria);
-			has_criteria = true;
+			config->handler_context.using_criteria = true;
 			// Skip leading whitespace
 			head += strspn(head, whitespace);
 		}
@@ -352,7 +352,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
 				goto cleanup;
 			}
 
-			if (!has_criteria) {
+			if (!config->handler_context.using_criteria) {
 				// without criteria, the command acts upon the focused
 				// container
 				config->handler_context.current_container =
diff --git a/sway/commands/mark.c b/sway/commands/mark.c
index 782e8ab9..b131f2f3 100644
--- a/sway/commands/mark.c
+++ b/sway/commands/mark.c
@@ -57,7 +57,7 @@ struct cmd_results *cmd_mark(int argc, char **argv) {
 
 	view_find_and_unmark(mark);
 
-	if (!toggle || (toggle && !had_mark)) {
+	if (!toggle || !had_mark) {
 		list_add(view->marks, strdup(mark));
 	}
 
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c
index a7d39432..ea2a5709 100644
--- a/sway/commands/unmark.c
+++ b/sway/commands/unmark.c
@@ -7,26 +7,53 @@
 #include "log.h"
 #include "stringop.h"
 
+static void remove_all_marks_iterator(struct sway_container *con, void *data) {
+	if (con->type == C_VIEW) {
+		view_clear_marks(con->sway_view);
+	}
+}
+
+// unmark                  Remove all marks from all views
+// unmark foo              Remove single mark from whichever view has it
+// [criteria] unmark       Remove all marks from matched view
+// [criteria] unmark foo   Remove single mark from matched view
+
 struct cmd_results *cmd_unmark(int argc, char **argv) {
-	if (argc == 0) {
-		// Remove all marks from the current container
+	// Determine the view
+	struct sway_view *view = NULL;
+	if (config->handler_context.using_criteria) {
 		struct sway_container *container =
 			config->handler_context.current_container;
 		if (container->type != C_VIEW) {
 			return cmd_results_new(CMD_INVALID, "unmark",
 					"Only views can have marks");
 		}
-		view_clear_marks(container->sway_view);
-	} else {
-		// Remove a single mark from whichever container has it
-		char *mark = join_args(argv, argc);
-		if (!view_find_and_unmark(mark)) {
-			free(mark);
-			return cmd_results_new(CMD_INVALID, "unmark",
-					"No view exists with that mark");
+		view = container->sway_view;
+	}
+
+	// Determine the mark
+	char *mark = NULL;
+	if (argc > 0) {
+		mark = join_args(argv, argc);
+	}
+
+	if (view && mark) {
+		// Remove the mark from the given view
+		if (view_has_mark(view, mark)) {
+			view_find_and_unmark(mark);
 		}
-		free(mark);
+	} else if (view && !mark) {
+		// Clear all marks from the given view
+		view_clear_marks(view);
+	} else if (!view && mark) {
+		// Remove mark from whichever view has it
+		view_find_and_unmark(mark);
+	} else {
+		// Remove all marks from all views
+		container_for_each_descendant_dfs(&root_container,
+				remove_all_marks_iterator, NULL);
 	}
+	free(mark);
 
 	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
 }
-- 
cgit v1.2.3