[gnome-todo] todo-txt: add support for list background color
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-todo] todo-txt: add support for list background color
- Date: Thu, 14 Jun 2018 02:02:50 +0000 (UTC)
commit a6787314bf7fcd3a6e9d6a287557fcb85959c1b5
Author: Rohit Kaushik <kaushikrohit325 gmail com>
Date: Thu May 24 17:10:53 2018 +0530
todo-txt: add support for list background color
plugins/todo-txt/gtd-provider-todo-txt.c | 176 +++++++++++++++++++++++++++----
plugins/todo-txt/gtd-todo-txt-parser.c | 166 +++++++++++++++++++++--------
plugins/todo-txt/gtd-todo-txt-parser.h | 12 ++-
3 files changed, 288 insertions(+), 66 deletions(-)
---
diff --git a/plugins/todo-txt/gtd-provider-todo-txt.c b/plugins/todo-txt/gtd-provider-todo-txt.c
index 0dcb5ac..a1ac591 100644
--- a/plugins/todo-txt/gtd-provider-todo-txt.c
+++ b/plugins/todo-txt/gtd-provider-todo-txt.c
@@ -74,6 +74,9 @@ enum
LAST_PROP
};
+typedef gboolean (*GtdLineParserFunc) (GtdProviderTodoTxt *self,
+ const gchar *line,
+ GError **error);
/*
* Auxiliary methods
@@ -128,11 +131,27 @@ print_task (GString *output,
g_string_append (output, "\n");
}
+static gchar*
+rgba_to_hex (GdkRGBA *color)
+{
+ g_autofree gchar *color_str = NULL;
+ gint r;
+ gint g;
+ gint b;
+
+ color_str = gdk_rgba_to_string (color);
+ sscanf (color_str, "rgb(%d,%d,%d)", &r, &g, &b);
+
+ return g_strdup_printf ("#%02x%02x%02x", r, g, b);
+}
+
static void
update_source (GtdProviderTodoTxt *self)
{
g_autofree gchar *output_path = NULL;
g_autoptr (GString) contents = NULL;
+ g_autoptr (GString) color_line = NULL;
+ g_autoptr (GString) list_line = NULL;
g_autoptr (GError) error = NULL;
GtdTaskList *list;
guint i;
@@ -140,6 +159,8 @@ update_source (GtdProviderTodoTxt *self)
GTD_ENTRY;
contents = g_string_new ("");
+ color_line = g_string_new ("");
+ list_line = g_string_new ("");
/* Save the tasks first */
for (i = 0; i < self->cache->len; i++)
@@ -155,24 +176,40 @@ update_source (GtdProviderTodoTxt *self)
print_task (contents, l->data);
}
- /* Then the task lists */
+ /* Initialize lists & colors custom lines */
+ g_string_append_printf (list_line, "h:1 Lists ");
+ g_string_append_printf (color_line, "h:1 Colors ");
+
+ /* Then the task lists and color */
for (i = 0; i < self->cache->len; i++)
{
g_autofree gchar *color_str = NULL;
g_autoptr (GdkRGBA) color = NULL;
+ const gchar *list_name;
list = g_ptr_array_index (self->cache, i);
-
- /* Print the list as the first line */
+ list_name = gtd_task_list_get_name (list);
color = gtd_task_list_get_color (list);
- color_str = gdk_rgba_to_string (color);
+ color_str = rgba_to_hex (color);
+
+ g_string_append_printf (list_line, "@%s", list_name);
+ g_string_append_printf (color_line, "%s:%s", list_name, color_str);
- g_string_append_printf (contents,
- "h:1 @%s color:%s\n",
- gtd_task_list_get_name (list),
- color_str);
+ if (i < self->cache->len - 1)
+ {
+ g_string_append (list_line, " ");
+ g_string_append (color_line, " ");
+ }
}
+ /* Append newline to end of custom lines */
+ g_string_append (list_line, "\n");
+ g_string_append (color_line, "\n");
+
+ /* Finally add custom lines to todo.txt content */
+ g_string_append (contents, list_line->str);
+ g_string_append (contents, color_line->str);
+
output_path = g_file_get_path (self->source_file);
g_file_set_contents (output_path, contents->str, contents->len, &error);
@@ -200,18 +237,31 @@ add_task_list (GtdProviderTodoTxt *self,
self->task_lists = g_list_append (self->task_lists, list);
}
-static void
-parse_task_list (GtdProviderTodoTxt *self,
- const gchar *line)
+static gboolean
+parse_lists_line (GtdProviderTodoTxt *self,
+ const gchar *line,
+ GError **error)
{
- g_autoptr (GtdTaskList) list = NULL;
+ g_autoptr (GPtrArray) lists = NULL;
+ guint i;
- list = gtd_todo_txt_parser_parse_task_list (GTD_PROVIDER (self), line);
+ lists = gtd_todo_txt_parser_parse_task_lists (GTD_PROVIDER (self), line, error);
- if (!list)
- return;
+ if (!lists)
+ return FALSE;
+
+ for (i = 0; i < lists->len; i++)
+ add_task_list (self, g_ptr_array_index (lists, i));
- add_task_list (self, g_steal_pointer (&list));
+ return TRUE;
+}
+
+static gboolean
+parse_list_colors_line (GtdProviderTodoTxt *self,
+ const gchar *line,
+ GError **error)
+{
+ return gtd_todo_txt_parser_parse_task_list_color (self->lists, line, error);
}
static void
@@ -254,13 +304,54 @@ parse_task (GtdProviderTodoTxt *self,
self->task_counter++;
}
+struct
+{
+ GtdTodoTxtLineType type;
+ const gchar *identifier;
+ GtdLineParserFunc parse;
+} custom_lines_vtable[] =
+{
+ { GTD_TODO_TXT_LINE_TYPE_TASKLIST, "Lists", parse_lists_line },
+ { GTD_TODO_TXT_LINE_TYPE_LIST_COLORS, "Colors", parse_list_colors_line }
+};
+
+static GPtrArray*
+remove_irrelevant_lines (GStrv lines)
+{
+ g_autoptr (GPtrArray) l = NULL;
+ guint len;
+ guint i;
+
+ len = g_strv_length (lines);
+ l = g_ptr_array_new ();
+
+ for (i = 0; i < len; i++)
+ {
+ gchar *line;
+
+ line = lines[i];
+
+ g_strstrip (line);
+
+ if (!line || g_str_equal (line, "") || g_str_equal (line, "\n"))
+ continue;
+
+ g_ptr_array_add (l, lines[i]);
+ }
+
+ return g_steal_pointer (&l);
+}
+
static void
reload_tasks (GtdProviderTodoTxt *self)
{
g_autofree gchar *input_path = NULL;
g_autofree gchar *file_contents = NULL;
g_autoptr (GError) error = NULL;
+ g_autoptr (GPtrArray) valid_lines = NULL;
g_auto (GStrv) lines = NULL;
+ guint vtable_len;
+ guint n_lines;
guint i;
GTD_ENTRY;
@@ -279,14 +370,53 @@ reload_tasks (GtdProviderTodoTxt *self)
self->task_counter = 0;
+ if (g_str_equal (file_contents, ""))
+ return;
+
lines = g_strsplit (file_contents, "\n", -1);
+ valid_lines = remove_irrelevant_lines (lines);
+ n_lines = valid_lines->len;
+ vtable_len = G_N_ELEMENTS (custom_lines_vtable);
+
+ /* First parse the custom lines at the end of todo.txt */
- for (i = 0; lines && lines[i]; i++)
+ for (i = 0; i < vtable_len; i++)
+ {
+ GtdTodoTxtLineType line_type;
+ const gchar *line;
+
+ if (n_lines < vtable_len)
+ break;
+
+ line = g_ptr_array_index(valid_lines, n_lines - vtable_len + i);
+
+ line_type = gtd_todo_txt_parser_get_line_type (line, &error);
+
+ if (error)
+ {
+ g_warning ("Error parsing custom line %d: %s", n_lines - vtable_len + i, error->message);
+ g_clear_error (&error);
+ continue;
+ }
+
+ if (custom_lines_vtable[i].type == line_type)
+ custom_lines_vtable[i].parse (self, line, &error);
+
+ if (error)
+ {
+ g_warning ("Error parsing custom line %d: %s", n_lines - vtable_len + i, error->message);
+ g_clear_error (&error);
+ continue;
+ }
+ }
+
+ /* Then regular task lines */
+ for (i = 0; i < n_lines - vtable_len; i++)
{
GtdTodoTxtLineType line_type;
gchar *line;
- line = lines[i];
+ line = g_ptr_array_index (valid_lines, i);
/* Last element of the array is NULL */
if (!line || line[0] == '\0')
@@ -308,12 +438,20 @@ reload_tasks (GtdProviderTodoTxt *self)
switch (line_type)
{
case GTD_TODO_TXT_LINE_TYPE_TASKLIST:
- parse_task_list (self, line);
break;
case GTD_TODO_TXT_LINE_TYPE_TASK:
parse_task (self, line);
break;
+
+ case GTD_TODO_TXT_LINE_TYPE_LIST_COLORS:
+ break;
+
+ case GTD_TODO_TXT_LINE_TYPE_UNKNOWN:
+ break;
+
+ default:
+ break;
}
}
diff --git a/plugins/todo-txt/gtd-todo-txt-parser.c b/plugins/todo-txt/gtd-todo-txt-parser.c
index 5e1db05..6ba1ff0 100644
--- a/plugins/todo-txt/gtd-todo-txt-parser.c
+++ b/plugins/todo-txt/gtd-todo-txt-parser.c
@@ -197,12 +197,13 @@ parse_token_id (const gchar *token,
}
static GStrv
-tokenize_line (const gchar *line)
+tokenize_line (const gchar *line,
+ const gchar *delimiter)
{
GStrv tokens = NULL;
gsize i;
- tokens = g_strsplit (line, " ", -1);
+ tokens = g_strsplit (line, delimiter, -1);
for (i = 0; tokens && tokens[i]; i++)
g_strstrip (tokens[i]);
@@ -235,7 +236,7 @@ gtd_todo_txt_parser_parse_task (GtdProvider *provider,
state.in_description = FALSE;
task = GTD_TASK (gtd_provider_todo_txt_generate_task (GTD_PROVIDER_TODO_TXT (provider)));
- tokens = tokenize_line (line);
+ tokens = tokenize_line (line, " ");
for (i = 0; tokens && tokens[i]; i++)
{
@@ -304,73 +305,142 @@ gtd_todo_txt_parser_parse_task (GtdProvider *provider,
}
/**
- * gtd_todo_txt_parser_parse_task_list:
+ * gtd_todo_txt_parser_parse_task_lists:
* provider: the @GtdProvider of the new tasklist
* @line: the tasklist line to be parsed
*
- * Parses a @GtdTaskList from @line. If there is a 'color:' token,
- * it is taken into account.
+ * Parses a list of @GtdTaskList from @line.
*
- * Returns: (transfer full)(nullable): A @GtdTaskList
+ * Returns: (transfer full)(nullable): A @GPtrArray
*/
-GtdTaskList*
-gtd_todo_txt_parser_parse_task_list (GtdProvider *provider,
- const gchar *line)
+GPtrArray*
+gtd_todo_txt_parser_parse_task_lists (GtdProvider *provider,
+ const gchar *line,
+ GError **error)
{
- g_autoptr (GtdTaskList) new_list = NULL;
- g_autoptr (GString) list_name = NULL;
- g_autofree gchar *color = NULL;
- g_auto (GStrv) tokens = NULL;
+ g_auto (GStrv) lists = NULL;
+ g_autoptr (GPtrArray) l = NULL;
guint i;
- tokens = tokenize_line (line);
- list_name = g_string_new (NULL);
+ l = g_ptr_array_new ();
+ lists = tokenize_line (line + strlen ("h:1 Lists "), " ");
GTD_TRACE_MSG ("Parsing tasklist from line '%s'", line);
- for (i = 0; tokens && tokens[i]; i++)
+ for (i = 0; lists && lists[i]; i++)
{
- const gchar *token = tokens[i];
+ g_autoptr (GtdTaskList) new_list = NULL;
+ g_autoptr (GString) list_name = NULL;
+ g_autofree gchar *color = NULL;
+ g_auto (GStrv) tokens = NULL;
+ const gchar *token = lists[i];
if (!token)
break;
- /* Color */
- if (g_str_has_prefix (token, "color:"))
- {
- color = g_strdup (token + strlen ("color:"));
- continue;
- }
+ list_name = g_string_new (NULL);
+ g_string_append_printf (list_name, "%s ", token[0] == '@' ? token + 1 : token);
- /* Hidden token */
- if (g_str_has_prefix (token, "h:1"))
+ if (list_name->len == 0)
continue;
- /* Title */
- g_string_append_printf (list_name, "%s ", token[0] == '@' ? token + 1 : token);
+ g_strstrip (list_name->str);
+
+ new_list = g_object_new (GTD_TYPE_TASK_LIST,
+ "provider", provider,
+ "name", list_name->str,
+ "is-removable", TRUE,
+ NULL);
+
+ g_ptr_array_add (l, g_steal_pointer (&new_list));
}
- if (list_name->len == 0)
- return NULL;
+ return g_steal_pointer (&l);
+}
- g_strstrip (list_name->str);
+/**
+ * gtd_todo_txt_parser_parse_task_list_color:
+ * map: the @GHashTable of task lists
+ * @line: the tasklist line to be parsed
+ *
+ * Parses colors from line and set the corresponding
+ * list color.
+ *
+ * Returns: %TRUE if color line was parsed without error,
+ * %FALSE otherwise.
+ */
+gboolean
+gtd_todo_txt_parser_parse_task_list_color (GHashTable *name_to_tasklist,
+ const gchar *line,
+ GError **error)
+{
+ g_auto (GStrv) lists = NULL;
+ guint tokens_len_after_split = 2;
+ guint i;
- new_list = g_object_new (GTD_TYPE_TASK_LIST,
- "provider", provider,
- "name", list_name->str,
- "is-removable", TRUE,
- NULL);
+ lists = tokenize_line (line + strlen ("h:1 Colors "), " ");
- if (color)
+ GTD_TRACE_MSG ("Parsing colors from line '%s'", line);
+
+ for (i = 0; lists && lists[i]; i++)
{
- GdkRGBA rgba;
+ gchar *list_name = NULL;
+ gchar *color = NULL;
+ g_auto (GStrv) tokens = NULL;
+ const gchar *list = lists[i];
+ GtdTaskList *task_list;
- gdk_rgba_parse (&rgba, color);
+ if (!list)
+ break;
- gtd_task_list_set_color (new_list, &rgba);
- }
+ tokens = tokenize_line (list, ":");
- return g_steal_pointer (&new_list);
+ if (g_strv_length (tokens) != tokens_len_after_split)
+ {
+ g_set_error (error,
+ GTD_TODO_TXT_PARSER_ERROR,
+ GTD_TODO_TXT_PARSER_INVALID_LINE,
+ "Invalid list found in color line");
+
+ GTD_RETURN (FALSE);
+ }
+
+ list_name = tokens[0];
+ color = tokens[1];
+
+ g_strstrip (list_name);
+ g_strstrip (color);
+
+ task_list = g_hash_table_lookup (name_to_tasklist, list_name);
+
+ if (!task_list)
+ {
+ g_set_error (error,
+ GTD_TODO_TXT_PARSER_ERROR,
+ GTD_TODO_TXT_PARSER_INVALID_LINE,
+ "Invalid list found in color line");
+
+ GTD_RETURN (FALSE);
+ }
+
+ if (color && g_strcmp0 (color, "") != 0 && g_strcmp0 (color, "null") != 0)
+ {
+ GdkRGBA rgba;
+
+ if (!gdk_rgba_parse (&rgba, color))
+ {
+ g_set_error (error,
+ GTD_TODO_TXT_PARSER_ERROR,
+ GTD_TODO_TXT_PARSER_INVALID_COLOR_HEX,
+ "Invalid color found");
+
+ GTD_RETURN (FALSE);
+ }
+
+ gtd_task_list_set_color (task_list, &rgba);
+ }
+ }
+ return TRUE;
}
/**
@@ -387,7 +457,7 @@ gtd_todo_txt_parser_get_line_type (const gchar *line,
GError **error)
{
GtdTodoTxtLineType line_type;
- g_auto (GStrv) tokens;
+ g_auto (GStrv) tokens = NULL;
GtdTodoTxtParserState state;
gboolean task_list_name_tk;
Token token_id;
@@ -395,9 +465,15 @@ gtd_todo_txt_parser_get_line_type (const gchar *line,
GTD_ENTRY;
- tokens = tokenize_line (line);
+ if (g_str_has_prefix (line, "h:1 Lists"))
+ return GTD_TODO_TXT_LINE_TYPE_TASKLIST;
+
+ if (g_str_has_prefix (line, "h:1 Colors"))
+ return GTD_TODO_TXT_LINE_TYPE_LIST_COLORS;
+
+ tokens = tokenize_line (line, " ");
state.last_token = TOKEN_START;
- line_type = GTD_TODO_TXT_LINE_TYPE_TASKLIST;
+ line_type = GTD_TODO_TXT_LINE_TYPE_UNKNOWN;
task_list_name_tk = FALSE;
for (i = 0; tokens && tokens[i]; i++)
diff --git a/plugins/todo-txt/gtd-todo-txt-parser.h b/plugins/todo-txt/gtd-todo-txt-parser.h
index be758aa..b94fd07 100644
--- a/plugins/todo-txt/gtd-todo-txt-parser.h
+++ b/plugins/todo-txt/gtd-todo-txt-parser.h
@@ -29,6 +29,7 @@ G_BEGIN_DECLS
typedef enum
{
GTD_TODO_TXT_PARSER_INVALID_DUE_DATE,
+ GTD_TODO_TXT_PARSER_INVALID_COLOR_HEX,
GTD_TODO_TXT_PARSER_INVALID_LINE,
GTD_TODO_TXT_PARSER_UNSUPPORTED_TOKEN,
GTD_TODO_TXT_PARSER_WRONG_LINE_TYPE,
@@ -38,6 +39,8 @@ typedef enum
{
GTD_TODO_TXT_LINE_TYPE_TASKLIST,
GTD_TODO_TXT_LINE_TYPE_TASK,
+ GTD_TODO_TXT_LINE_TYPE_LIST_COLORS,
+ GTD_TODO_TXT_LINE_TYPE_UNKNOWN
} GtdTodoTxtLineType;
#define GTD_TODO_TXT_PARSER_ERROR (gtd_todo_txt_parser_error_quark ())
@@ -47,13 +50,18 @@ GQuark gtd_todo_txt_parser_error_quark (void);
GtdTodoTxtLineType gtd_todo_txt_parser_get_line_type (const gchar *line,
GError **error);
-GtdTaskList* gtd_todo_txt_parser_parse_task_list (GtdProvider *provider,
- const gchar *line);
+GPtrArray* gtd_todo_txt_parser_parse_task_lists (GtdProvider *provider,
+ const gchar *line,
+ GError **error);
GtdTask* gtd_todo_txt_parser_parse_task (GtdProvider *provider,
const gchar *line,
gchar **out_list_name);
+gboolean gtd_todo_txt_parser_parse_task_list_color (GHashTable *name_to_tasklist,
+ const gchar *line,
+ GError **error);
+
G_END_DECLS
#endif /* GTD_TODO_TXT_PARSER_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]