Add fix-create-new-cat.diff
authorMyhailo Danylenko <isbear@ukrpost.net>
Wed, 08 Aug 2012 12:30:46 +0300
changeset 42 0ee5e9903fa1
parent 41 446ad24e6187
child 43 e0cda680d7a8
Add fix-create-new-cat.diff
dynamic-layout.diff
fix-create-new-cat.diff
series
templates.diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dynamic-layout.diff	Wed Aug 08 12:30:46 2012 +0300
@@ -0,0 +1,65 @@
+# HG changeset patch
+# Parent ebe29230ffb5572d2c37ab811d34ae970d6293ca
+[work-in-progress] Allow user to specify top to bottom window order
+
+diff -r ebe29230ffb5 mcabber/mcabber/utils.c
+--- a/mcabber/mcabber/utils.c	Wed Aug 01 23:44:09 2012 +0300
++++ b/mcabber/mcabber/utils.c	Fri Aug 03 14:35:36 2012 +0300
+@@ -650,6 +650,42 @@
+   g_free(arglst);
+ }
+ 
++//  parse_list(arg, cb, udata)
++// Calls cb for every element in space/semicolon/comma-separated list.
++// Designed to work in-place, so, no escapes, quoting etc.
++// Terminates parsing if callback returns false.
++void parse_list(const char *arg, parse_list_cb_t cb, void *udata)
++{
++  const char *p, *start;
++  enum {
++    in_space,
++    in_string,
++  } state;
++
++  if (!arg) 
++    return;
++
++  state = in_space;
++  while ( *p ) {
++    if ( *p == ' ' || *p == ';' || *p == ',' ) {
++      if ( state == in_string ) {
++        if ( ! cb ( start, p, udata ) )
++          return;
++        state = in_space;
++      }
++    } else {
++      if ( state == in_space ) {
++        start = p;
++        state = in_string;
++      }
++    }
++    p ++;
++  }
++
++  if ( state == in_string )
++    cb ( start, p, udata );
++}
++
+ //  replace_nl_with_dots(bufstr)
+ // Replace '\n' with "(...)" (or with a NUL if the string is too short)
+ void replace_nl_with_dots(char *bufstr)
+diff -r ebe29230ffb5 mcabber/mcabber/utils.h
+--- a/mcabber/mcabber/utils.h	Wed Aug 01 23:44:09 2012 +0300
++++ b/mcabber/mcabber/utils.h	Fri Aug 03 14:35:36 2012 +0300
+@@ -43,6 +43,11 @@
+ char **split_arg(const char *arg, unsigned int n, int dontstriplast);
+ void free_arg_lst(char **arglst);
+ 
++/* fast in-place string split on space/semicolon/comma
++ * stops processing if callback returns false value */
++typedef int (*parse_list_cb_t)(const char *start, const char *end, void *udata);
++void parse_list(const char *arg, parse_list_cb_t cb, void *udata);
++
+ void replace_nl_with_dots(char *bufstr);
+ char *ut_expand_tabs(const char *text);
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fix-create-new-cat.diff	Wed Aug 08 12:30:46 2012 +0300
@@ -0,0 +1,20 @@
+# HG changeset patch
+# Parent 26edaf6ea10b8db2ed07da3e4ad9bee03077de84
+
+diff -r 26edaf6ea10b mcabber/mcabber/compl.c
+--- a/mcabber/mcabber/compl.c	Mon Jul 30 22:39:17 2012 +0200
++++ b/mcabber/mcabber/compl.c	Wed Aug 08 12:15:20 2012 +0300
+@@ -97,10 +97,11 @@
+ // as it is likely to change in future.
+ guint compl_new_category(void)
+ {
++  const guint maxcat = 8 * sizeof (registered_cats);
+   guint i = 0;
+-  while ((registered_cats >> i) & 1)
++  while ((registered_cats >> i) & 1 && i < maxcat)
+     i++;
+-  if (i >= 8 * sizeof (registered_cats))
++  if (i >= maxcat)
+     return 0;
+   else {
+     guint64 id = 1 << i;
--- a/series	Wed Aug 01 23:43:46 2012 +0300
+++ b/series	Wed Aug 08 12:30:46 2012 +0300
@@ -1,3 +1,4 @@
+fix-create-new-cat.diff
 update-help.diff
 add-offline-message.diff
 fix-receipts.diff
@@ -8,4 +9,5 @@
 roster-state-colors.diff
 add-cmake.diff
 use-gslice.diff
+dynamic-layout.diff
 templates.diff
--- a/templates.diff	Wed Aug 01 23:43:46 2012 +0300
+++ b/templates.diff	Wed Aug 08 12:30:46 2012 +0300
@@ -1,10 +1,10 @@
 # HG changeset patch
-# Parent 456d832740146c5c9a0428c9ca0a1a0c431481b0
+# Parent 9ad6f102a38b4e7b040f8efc311de6a2dda22805
 [work-in-progress] Use templates for statusbars
 
-diff -r 456d83274014 mcabber/CMakeLists.txt
---- a/mcabber/CMakeLists.txt	Fri Jul 20 17:29:53 2012 +0300
-+++ b/mcabber/CMakeLists.txt	Fri Jul 20 17:30:20 2012 +0300
+diff -r 9ad6f102a38b mcabber/CMakeLists.txt
+--- a/mcabber/CMakeLists.txt	Fri Aug 03 14:40:25 2012 +0300
++++ b/mcabber/CMakeLists.txt	Mon Aug 06 22:53:57 2012 +0300
 @@ -154,8 +154,8 @@
  
  ## Define targets
@@ -16,9 +16,9 @@
  	xmpp xmpp_helper xmpp_iq xmpp_iqrequest xmpp_muc xmpp_s10n )
  if ( NOT MODULES_ENABLE )
  	list ( APPEND mcabber_SUBSYSTEMS extcmd fifo )
-diff -r 456d83274014 mcabber/mcabber/parser.c
+diff -r 9ad6f102a38b mcabber/mcabber/parser.c
 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/parser.c	Fri Jul 20 17:30:20 2012 +0300
++++ b/mcabber/mcabber/parser.c	Mon Aug 06 22:53:57 2012 +0300
 @@ -0,0 +1,853 @@
 +
 +/* Copyright 2012 Myhailo Danylenko
@@ -873,9 +873,9 @@
 +}
 +
 +/* vim: se ts=4 sw=4: */
-diff -r 456d83274014 mcabber/mcabber/parser.h
+diff -r 9ad6f102a38b mcabber/mcabber/parser.h
 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/parser.h	Fri Jul 20 17:30:20 2012 +0300
++++ b/mcabber/mcabber/parser.h	Mon Aug 06 22:53:57 2012 +0300
 @@ -0,0 +1,77 @@
 +
 +#ifndef MCABBER_PARSER_H
@@ -954,10 +954,57 @@
 +
 +# endif
 +
-diff -r 456d83274014 mcabber/mcabber/templates.c
+diff -r 9ad6f102a38b mcabber/mcabber/settings.c
+--- a/mcabber/mcabber/settings.c	Fri Aug 03 14:40:25 2012 +0300
++++ b/mcabber/mcabber/settings.c	Mon Aug 06 22:53:57 2012 +0300
+@@ -363,6 +363,32 @@
+   return 0;
+ }
+ 
++//  settings_tmpl_set(option, value)
++// Sets option, escaping it for use in templates.
++// Could be more efficient with notifiers instead of guards.
++void settings_tmpl_set(const gchar *key, const gchar *value)
++{
++  if (value && *value) {
++    const gchar *p = strchr(value, '%');
++    if (p) {
++      GString *result = g_string_new(NULL);
++      const gchar *s   = value;
++      while (p) {
++        g_string_append_len(result, s, p - s + 1);
++        g_string_append_c(result, '%');
++        s = ++ p;
++        p = strchr(s, '%');
++      }
++      if (*s)
++        g_string_append(result, s);
++      settings_set(SETTNIGS_TYPE_OPTION, key, result -> str);
++      g_string_free(result, TRUE);
++      return;
++    }
++  }
++  settings_set ( SETTNIGS_TYPE_OPTION, key, value );
++}
++
+ //  settings_get_status_msg(status)
+ // Return a string with the current status message:
+ // - if there is a user-defined message ("message" option),
+diff -r 9ad6f102a38b mcabber/mcabber/settings.h
+--- a/mcabber/mcabber/settings.h	Fri Aug 03 14:40:25 2012 +0300
++++ b/mcabber/mcabber/settings.h	Mon Aug 06 22:53:57 2012 +0300
+@@ -37,6 +37,7 @@
+ void    settings_opt_set_raw(const gchar *key, const gchar *value);
+ void    settings_set(guint type, const gchar *key, const gchar *value);
+ void    settings_del(guint type, const gchar *key);
++void    settings_tmpl_set(const gchar *key, const gchar *value);
+ const gchar *settings_get(guint type, const gchar *key);
+ int     settings_get_int(guint type, const gchar *key);
+ const gchar *settings_get_status_msg(enum imstatus status);
+diff -r 9ad6f102a38b mcabber/mcabber/templates.c
 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/templates.c	Fri Jul 20 17:30:20 2012 +0300
-@@ -0,0 +1,277 @@
++++ b/mcabber/mcabber/templates.c	Mon Aug 06 22:53:57 2012 +0300
+@@ -0,0 +1,368 @@
 +
 +/* Copyright 2012 Myhailo Danylenko
 + *
@@ -991,15 +1038,26 @@
 +//
 +
 +typedef void (*tmpl_callback_t) ( const gchar * expansion, gpointer udata );
++typedef void (*tmpl_root_callback_t) ( const tmpl_link_struct_t * expansion, gpointer udata );
++
++typedef enum {
++	root_template,     // fully processed $ and % templates
++	shortcut_template, // no-callback $-only but %-propagating templates
++	user_template,     // $-only templates with callback
++} template_type_t;
 +
 +typedef struct {
-+	gchar           * name;
-+	tmpl_callback_t   callback;
-+	gpointer          userdata;
-+	gboolean          in_use;
-+	GSList          * guards;
-+	gboolean          changed;
-+	gchar           * prev_expansion;
++	gchar           * name;          // variable name
++	template_type_t   type;          // can be only one (for simplicity)
++	tmpl_callback_t   callback;      // for root it is %-callback, for user it is $-callback
++	gpointer          userdata;      // userdata for callback
++	GSList          * guards;        // $-guards
++	gboolean          in_use;        // to mark root templates for drop
++	gboolean          changed;       // $-changed flag
++	gboolean          chunk_changed; // %-changed flag
++	gchar           * expansion;     // expansion of template
++	GSList          * templates;     // root templates, that use this chunk template // roots? :D
++	GSList          * chunks;        // chunk templates in use by this root template
 +} template_t;
 +
 +typedef struct {
@@ -1007,9 +1065,17 @@
 +	GSList * templates;
 +} tmpl_guard_t;
 +
-+static GHashTable * tmpl_templates   = NULL;
-+static GHashTable * tmpl_guards      = NULL;
-+static guint        tmpl_attached_id = 0;
++typedef struct tmpl_link_struct tmpl_link_t;
++struct tmpl_link_struct {
++	tmpl_link_type_t   type;
++	guint              color;
++	gchar            * string;
++	tmpl_link_t      * next;
++};
++
++static GHashTable * tmpl_templates      = NULL;
++static GHashTable * tmpl_guards         = NULL;
++static guint        tmpl_attached_id    = 0;
 +
 +//
 +//  predeclarations
@@ -1029,10 +1095,18 @@
 +	guard -> templates = g_slist_remove ( guard -> templates, template );
 +}
 +
++// [cb] drops template from chunk's 'templates' list
++static void tmpl_unchunk ( gpointer data, gpointer udata )
++{
++	template_t * chunk    = data;
++	template_t * template = udata;
++	chunk -> templates = g_slist_remove ( chunk -> templates, template );
++}
++
 +// [destructor cb] releases guard hash table entry
 +static void tmpl_free_guard ( gpointer data )
 +{
-+	tmpl_guard_t *guard = data;
++	tmpl_guard_t * guard = data;
 +	settings_del_guard ( guard -> name );
 +	g_slist_free ( guard -> templates );
 +	g_free ( guard -> name );
@@ -1042,14 +1116,32 @@
 +// [destructor cb] releases taken guards and frees command
 +static void tmpl_free_template ( gpointer data )
 +{
-+	template_t *template = data;
++	template_t * template = data;
++	// not running unchunk, as it was done earlier
++	// or it is global destruction and chunk may no longer exist
++	g_slist_free ( template -> chunks );
++	g_slist_free ( template -> templates );
 +	g_slist_foreach ( template -> guards, tmpl_unguard, template );
 +	g_slist_free ( template -> guards );
 +	g_free ( template -> name );
-+	g_free ( template -> prev_expansion );
++	g_free ( template -> expansion );
 +	g_slice_free ( template_t, template );
 +}
 +
++// [cb] sets changed flag on template
++static void template_set_changed ( gpointer data, gpointer udata )
++{
++	template_t * template = data;
++	template -> changed   = TRUE;
++}
++
++// [cb] sets chunk_changed flag on template
++static void template_set_chunk_changed ( gpointer data, gpointer udata )
++{
++	template_t * template     = data;
++	template -> chunk_changed = TRUE;
++}
++
 +// install guard (name must be glib-allocated string)
 +static void tmpl_install_guard ( gchar *name, template_t *template, settings_guard_t callback )
 +{
@@ -1092,24 +1184,17 @@
 +	return result;
 +}
 +
-+// [cb] mark unused guards for removal
-+static gboolean tmpl_drop_unused_guards ( gpointer key, gpointer value, gpointer udata )
-+{
-+	tmpl_guard_t * guard = value;
-+	if ( guard -> templates == NULL )
-+		return TRUE;
-+	return FALSE;
-+}
-+
-+// [cb] mark deleted templates for removal, reevaluate changed
-+static gboolean reevaluate_template ( gpointer key, gpointer value, gpointer udata )
++// [cb]
++// drop dependencies for unused root templates,
++// update expansion of all $-changed templates,
++// reinstall guards,
++// mark dependencies as %-changed,
++// call $-callbacks
++static void evaluate_template1 ( gpointer key, gpointer value, gpointer udata )
 +{
 +	template_t * template = value;
 +
-+	if ( ! template -> in_use )
-+		return TRUE;
-+
-+	if ( template -> changed ) {
++	if ( template -> changed && template -> in_use ) {
 +		const gchar * expression = settings_opt_get ( template -> name );
 +		gchar       * expansion  = NULL;
 +		// release guards (but do not free them)
@@ -1130,15 +1215,71 @@
 +		// re-install guard on template itself
 +		tmpl_install_guard ( g_strdup ( template -> name ), template, tmpl_guard );
 +		template -> changed = FALSE;
-+		// pass result to callback
-+		if ( g_strcmp0 ( expansion, template -> prev_expansion ) ) {
-+			g_free ( template -> prev_expansion );
-+			template -> prev_expansion = expansion;
-+			template -> callback ( expansion, template -> userdata );
++		// check, if expansion has changed
++		if ( g_strcmp0 ( expansion, template -> expansion ) ) {
++			g_free ( template -> expansion );
++			template -> expansion = expansion;
++			if ( template -> type == user_template )
++				// pass result to callback
++				template -> callback ( expansion, template -> userdata );
++			else if ( template -> type == chunk_template )
++				// mark %-dependencies as %-changed
++				g_slist_foreach ( template -> templates, tmpl_set_chunk_changed, NULL );
++			else if ( template -> type == root_template )
++				// mark self as %-changed
++				template -> chunk_changed = TRUE;
++			else
++				g_assert_not_reached ();
 +		} else
 +			g_free ( expansion );
 +	}
++}
 +
++// [cb]
++// evaluate %-changed templates,
++// rebuild dependencies, call %-callbacks
++static void evaluate_template2 ( gpointer key, gpointer value, gpointer udata )
++{
++	template_t * template = value;
++
++	if ( template -> type == root_template ) {
++		if ( ! template -> in_use ) {
++			// release chunks
++			g_slist_foreach ( template -> chunks, tmpl_unchunk, template );
++			g_slist_free ( template -> chunks );
++			template -> chunks = NULL;
++		} else if ( template -> chun_changed ) {
++			const char *expansion = template -> expansion;
++			// release chunks
++			g_slist_foreach ( template -> chunks, tmpl_unchunk, template );
++			g_slist_free ( template -> chunks );
++			template -> chunks = NULL;
++			// evaluate template
++			GError * error = NULL;
++			template_link_t * result = tmpl_chunk_expand ( expansion, tmpl_get_chunk, template, NULL, &error );
++			// FIXME
++		}
++	}
++}
++
++// [cb] mark deleted templates for removal
++static gboolean tmpl_drop_unused_templates ( gpointer key, gpointer value, gpointer udata )
++{
++	template_t * template = value;
++	if ( template -> type == chunk_template )
++		// drop chunk templates with no dependent root templates
++		return template -> templates == NULL;
++	else
++		// drop user templates, marked as unused
++		return ! template -> in_use;
++}
++
++// [cb] mark unused guards for removal
++static gboolean tmpl_drop_unused_guards ( gpointer key, gpointer value, gpointer udata )
++{
++	tmpl_guard_t * guard = value;
++	if ( guard -> templates == NULL )
++		return TRUE;
 +	return FALSE;
 +}
 +
@@ -1147,8 +1288,12 @@
 +{
 +	// allow reschedule in a process of reevaluation
 +	tmpl_attached_id = 0;
-+	// drop removed & reevaluate changed templates
-+	g_hash_table_foreach_remove ( tmpl_templates, reevaluate_template, NULL );
++	// release chunks of unused root templates, update expansion of $-changed templates, call $-callbacks
++	g_hash_table_foreach ( tmpl_templates, evaluate_template1, NULL );
++	// reevaluate %-changed templates, call %-callbacks
++	g_hash_table_foreach ( tmpl_templates, evaluate_template2, NULL );
++	// drop removed chunk-templates
++	g_hash_table_foreach_remove ( tmpl_templates, tmpl_drop_unused_templates, NULL );
 +	// free unused guards TODO do only when needed
 +	g_hash_table_foreach_remove ( tmpl_guards, tmpl_drop_unused_guards, NULL );
 +	// always return false, this is oneshot idle call
@@ -1166,13 +1311,6 @@
 +	}
 +}
 +
-+// [cb] sets changed flag on template
-+static void template_set_changed ( gpointer data, gpointer udata )
-+{
-+	template_t * template = data;
-+	template -> changed   = TRUE;
-+}
-+
 +// [guard] generic guard for variable
 +static gchar *tmpl_guard ( const gchar *key, const gchar *new_value )
 +{
@@ -1235,9 +1373,9 @@
 +}
 +
 +/* vim: se ts=4 sw=4: */
-diff -r 456d83274014 mcabber/mcabber/templates.h
+diff -r 9ad6f102a38b mcabber/mcabber/templates.h
 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/templates.h	Fri Jul 20 17:30:20 2012 +0300
++++ b/mcabber/mcabber/templates.h	Mon Aug 06 22:53:57 2012 +0300
 @@ -0,0 +1,44 @@
 +
 +/* Copyright 2012 Myhailo Danylenko
@@ -1283,64 +1421,3 @@
 +void templates_uninit ( void );
 +
 +/* vim: se ts=4 sw=4: */
-diff -r 456d83274014 mcabber/mcabber/utils.c
---- a/mcabber/mcabber/utils.c	Fri Jul 20 17:29:53 2012 +0300
-+++ b/mcabber/mcabber/utils.c	Fri Jul 20 17:30:20 2012 +0300
-@@ -650,6 +650,42 @@
-   g_free(arglst);
- }
- 
-+//  parse_list(arg, cb, udata)
-+// Calls cb for every element in space/semicolon/comma-separated list.
-+// Designed to work in-place, so, no escapes, quoting etc.
-+// Terminates parsing if callback returns false.
-+void parse_list(const char *arg, parse_list_cb_t cb, void *udata)
-+{
-+  const char *p, *start;
-+  enum {
-+    in_space,
-+    in_string,
-+  } state;
-+
-+  if (!arg) 
-+    return;
-+
-+  state = in_space;
-+  while ( *p ) {
-+    if ( *p == ' ' || *p == ';' || *p == ',' ) {
-+      if ( state == in_string ) {
-+        if ( ! cb ( start, p, udata ) )
-+          return;
-+        state = in_space;
-+      }
-+    } else {
-+      if ( state == in_space ) {
-+        start = p;
-+        state = in_string;
-+      }
-+    }
-+    p ++;
-+  }
-+
-+  if ( state == in_string )
-+    cb ( start, p, udata );
-+}
-+
- //  replace_nl_with_dots(bufstr)
- // Replace '\n' with "(...)" (or with a NUL if the string is too short)
- void replace_nl_with_dots(char *bufstr)
-diff -r 456d83274014 mcabber/mcabber/utils.h
---- a/mcabber/mcabber/utils.h	Fri Jul 20 17:29:53 2012 +0300
-+++ b/mcabber/mcabber/utils.h	Fri Jul 20 17:30:20 2012 +0300
-@@ -43,6 +43,11 @@
- char **split_arg(const char *arg, unsigned int n, int dontstriplast);
- void free_arg_lst(char **arglst);
- 
-+/* fast in-place string split on space/semicolon/comma
-+ * stops processing if callback returns false value */
-+typedef int (*parse_list_cb_t)(const char *start, const char *end, void *udata);
-+void parse_list(const char *arg, parse_list_cb_t cb, void *udata);
-+
- void replace_nl_with_dots(char *bufstr);
- char *ut_expand_tabs(const char *text);
-