Branch: refs/heads/master
Author: Thomas Martitz <kugel(a)rockbox.org>
Committer: Thomas Martitz <kugel(a)rockbox.org>
Date: Mon, 03 Dec 2018 21:33:59 UTC
Commit: fb9673eb61c44baba6a94f7ad3ef429ffa021c73
https://github.com/geany/geany/commit/fb9673eb61c44baba6a94f7ad3ef429ffa021…
Log Message:
-----------
api: pass gtkdoc annotation parameter as-is
The array annotation has many possible parameters, this avoids having a Doxygen
command for each one.
Luckily you can define Doxygen commands multiple times with different a number
of parameters each.
Modified Paths:
--------------
doc/Doxyfile.in
src/utils.c
Modified: doc/Doxyfile.in
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -263,7 +263,7 @@ ALIASES += "cb=\noop \xmlonly <simplesect kind=\"geany:scope\">not
ALIASES += "cbdata=\noop \xmlonly <simplesect kind=\"geany:closure\"></simplesect>\endxmlonly"
ALIASES += "cbfree=\noop \xmlonly <simplesect kind=\"geany:destroy\"></simplesect>\endxmlonly"
ALIASES += "array=\noop \xmlonly <simplesect kind=\"geany:array\"></simplesect>\endxmlonly"
-ALIASES += "arraylen{1}=\noop \xmlonly <simplesect kind=\"geany:array\">length=\1</simplesect>\endxmlonly"
+ALIASES += "array{1}=\noop \xmlonly <simplesect kind=\"geany:array\">\1</simplesect>\endxmlonly"
# This tag can be used to specify a number of word-keyword mappings (TCL only).
Modified: src/utils.c
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -2155,7 +2155,7 @@ gchar *utils_strv_find_lcs(gchar **strv, size_t num)
* The algorthm strips the common prefix (e-g. the user's home directory) and
* replaces the longest common substring with an ellipsis ("...").
*
- * @param file_names @arraylen{num} The list of strings to process.
+ * @param file_names @array{length=num} The list of strings to process.
* @param num The number of strings contained in @a file_names. Can be 0 if it's terminated by @c NULL.
* @return @transfer{full} A newly-allocated array of transformed paths strings, terminated by
@c NULL. Use @c g_strfreev() to free it.
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Thomas Martitz <kugel(a)rockbox.org>
Committer: Thomas Martitz <kugel(a)rockbox.org>
Date: Mon, 03 Dec 2018 21:33:59 UTC
Commit: c05837055b0533504b85966852b6f26551616e30
https://github.com/geany/geany/commit/c05837055b0533504b85966852b6f26551616…
Log Message:
-----------
api: export new utils_strv_shorten_file_list() function
Since I based the algorithm of the above function on code in one of my python
plugins, I would like to remove the implementation in my plugin and call
Geany's function.
Modified Paths:
--------------
src/utils.c
Modified: src/utils.c
9 lines changed, 6 insertions(+), 3 deletions(-)
===================================================================
@@ -2146,7 +2146,7 @@ gchar *utils_strv_find_lcs(gchar **strv, size_t num)
}
-/* * Transform file names in a list to be shorter.
+/** Transform file names in a list to be shorter.
*
* This function takes a list of file names (porbably with absolute paths), and
* transforms the paths such that they are short but still unique. This is intended
@@ -2156,10 +2156,13 @@ gchar *utils_strv_find_lcs(gchar **strv, size_t num)
* The algorthm strips the common prefix (e-g. the user's home directory) and
* replaces the longest common substring with "...".
*
- * @param file_names The list of strings to process.
+ * @param file_names @arraylen{num} The list of strings to process.
* @param num The number of strings contained in @a strv. Can be 0 if @a strv is a @c GStrv
- * @return A newly-allocated NULL-terminated array of transformed paths strings. Use @c g_strfreev() to free it.
+ * @return @transfer{full} A newly-allocated NULL-terminated array of transformed paths strings. Use @c g_strfreev() to free it.
+ *
+ * @since 1.34 (API 239)
*/
+GEANY_API_SYMBOL
gchar **utils_strv_shorten_file_list(gchar **file_names, size_t num)
{
gint i, j;
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Thomas Martitz <kugel(a)rockbox.org>
Committer: Thomas Martitz <kugel(a)rockbox.org>
Date: Mon, 03 Dec 2018 21:33:59 UTC
Commit: 724e7886dec8da92cc3e7b50c861499a6b6932eb
https://github.com/geany/geany/commit/724e7886dec8da92cc3e7b50c861499a6b693…
Log Message:
-----------
Changes for review comments
- Notably the utils_strv_{find_common_prefix,find_lcs,shorten_file_list}
now take -1 for num to mean to compute the array length.
- utils_strv_find_common_prefix implementation simplified.
- if num == 0 is passed to the above functions the passed strv is not
dereferenced (so could be NULL).
Modified Paths:
--------------
src/symbols.c
src/utils.c
src/utils.h
Modified: src/symbols.c
4 lines changed, 2 insertions(+), 2 deletions(-)
===================================================================
@@ -1933,10 +1933,10 @@ static void show_goto_popup(GeanyDocument *doc, GPtrArray *tags, gboolean have_b
GdkEventButton *button_event = NULL;
TMTag *tmtag;
guint i;
- gchar **short_names, **file_names, **p;
+ gchar **short_names, **file_names;
menu = gtk_menu_new();
- /* If popup would show multiple files presend a smart file list that allows
+ /* If popup would show multiple files present a smart file list that allows
* to easily distinguish the files while avoiding the file paths in their entirety */
file_names = g_new(gchar *, tags->len);
foreach_ptr_array(tmtag, i, tags)
Modified: src/utils.c
47 lines changed, 22 insertions(+), 25 deletions(-)
===================================================================
@@ -2049,51 +2049,45 @@ gchar **utils_strv_join(gchar **first, gchar **second)
* The size of the list may be given explicitely, but defaults to @c g_strv_length(strv).
*
* @param strv The list of strings to process.
- * @param num The number of strings contained in @a strv. Can be 0 if it's terminated by @c NULL.
+ * @param num The number of strings contained in @a strv. Can be -1 if it's terminated by @c NULL.
*
* @return The common prefix that is part of all strings (maybe empty), or NULL if an empty list
* was passed in.
*/
-static gchar *utils_strv_find_common_prefix(gchar **strv, gsize num)
+static gchar *utils_strv_find_common_prefix(gchar **strv, gssize num)
{
- gchar *prefix;
-
if (!NZV(strv))
return NULL;
- if (num == 0)
+ if (num == -1)
num = g_strv_length(strv);
- prefix = g_strdup(strv[0]);
-
- for (gint i = 0; prefix[i]; i++)
+ for (gsize i = 0; strv[0][i]; i++)
{
for (gsize j = 1; j < num; j++)
{
- gchar *s = strv[j];
- if (s[i] != prefix[i])
+ if (strv[j][i] != strv[0][i])
{
- /* terminate prefix on first mismatch and return */
- prefix[i] = '\0';
- break;
+ /* return prefix on first mismatch */
+ return g_strndup(strv[0], i);
}
}
- if (prefix[i] == '\0')
- break;
}
- return prefix;
+
+ return g_strdup(strv[0]);
}
+
/* * Returns the longest common substring in a list of strings.
*
* The size of the list may be given explicitely, but defaults to @c g_strv_length(strv).
*
* @param strv The list of strings to process.
- * @param num The number of strings contained in @a strv. Can be 0 if it's terminated by @c NULL.
+ * @param num The number of strings contained in @a strv. Can be -1 if it's terminated by @c NULL.
*
* @return The common prefix that is part of all strings.
*/
-static gchar *utils_strv_find_lcs(gchar **strv, gsize num)
+static gchar *utils_strv_find_lcs(gchar **strv, gssize num)
{
gchar *first, *_sub, *sub;
gsize n_chars;
@@ -2102,15 +2096,15 @@ static gchar *utils_strv_find_lcs(gchar **strv, gsize num)
char *lcs;
gsize found;
- if (strv == NULL)
+ if (num == -1)
+ num = g_strv_length(strv);
+
+ if (num < 1)
return NULL;
first = strv[0];
len = strlen(first);
- if (num == 0)
- num = g_strv_length(strv);
-
/* sub is the working area where substrings from first are copied to */
sub = g_malloc(len+1);
lcs = g_strdup("");
@@ -2154,24 +2148,27 @@ static gchar *utils_strv_find_lcs(gchar **strv, gsize num)
* replaces the longest common substring with an ellipsis ("...").
*
* @param file_names @array{length=num} The list of strings to process.
- * @param num The number of strings contained in @a file_names. Can be 0 if it's terminated by @c NULL.
+ * @param num The number of strings contained in @a file_names. Can be -1 if it's terminated by @c NULL.
* @return @transfer{full} A newly-allocated array of transformed paths strings, terminated by
@c NULL. Use @c g_strfreev() to free it.
*
* @since 1.34 (API 239)
*/
GEANY_API_SYMBOL
-gchar **utils_strv_shorten_file_list(gchar **file_names, gsize num)
+gchar **utils_strv_shorten_file_list(gchar **file_names, gssize num)
{
gsize i;
gchar *prefix, *substring, *lcs;
gchar *start, *end;
gchar **names;
gsize prefix_len, lcs_len;
+ /* We don't dereference file_names if num == 0. */
+ g_return_val_if_fail(num == 0 || file_names != NULL, NULL);
+
/* The return value shall have exactly the same size as the input. If the input is a
* GStrv (last element is NULL), the output will follow suit. */
- if (!num)
+ if (num == -1)
num = g_strv_length(file_names);
/* Always include a terminating NULL, enables easy freeing with g_strfreev() */
names = g_new0(gchar *, num + 1);
Modified: src/utils.h
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -301,7 +301,7 @@ gchar **utils_strv_new(const gchar *first, ...) G_GNUC_NULL_TERMINATED;
gchar **utils_strv_join(gchar **first, gchar **second) G_GNUC_WARN_UNUSED_RESULT;
-gchar **utils_strv_shorten_file_list(gchar **file_names, size_t num);
+gchar **utils_strv_shorten_file_list(gchar **file_names, gssize num);
GSList *utils_get_config_files(const gchar *subdir);
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Thomas Martitz <kugel(a)rockbox.org>
Committer: Thomas Martitz <kugel(a)rockbox.org>
Date: Mon, 03 Dec 2018 21:33:59 UTC
Commit: 7fdd360b85fe3a920f9510a18e32afa6ee83fe22
https://github.com/geany/geany/commit/7fdd360b85fe3a920f9510a18e32afa6ee83f…
Log Message:
-----------
Fix one oops and a couple of mistakes in comments, found by review.
Modified Paths:
--------------
src/utils.c
Modified: src/utils.c
18 lines changed, 9 insertions(+), 9 deletions(-)
===================================================================
@@ -2046,10 +2046,10 @@ gchar **utils_strv_join(gchar **first, gchar **second)
/* * Returns the common prefix in a list of strings.
*
- * The size of the list may be given explicitely automatically determined if passed a GStrv.
+ * The size of the list may be given explicitely, but defaults to @c g_strv_length(strv).
*
* @param strv The list of strings to process.
- * @param num The number of strings contained in @a strv. Can be 0 if @a strv is a @c GStrv
+ * @param num The number of strings contained in @a strv. Can be 0 if it's terminated by @c NULL.
*
* @return The common prefix that is part of all strings (maybe empty), or NULL if an empty list
* was passed in.
@@ -2068,7 +2068,6 @@ static gchar *utils_strv_find_common_prefix(gchar **strv, size_t num)
for (gint i = 0; prefix[i]; i++)
{
- foreach_strv(ptr, &strv[1])
for (gint j = 1; j < num; j++)
{
gchar *s = strv[j];
@@ -2085,12 +2084,12 @@ static gchar *utils_strv_find_common_prefix(gchar **strv, size_t num)
return prefix;
}
-/* * Returns the common prefix in a list of strings.
+/* * Returns the longest common substring in a list of strings.
*
- * The size of the list may be given explicitely automatically determined if passed a GStrv.
+ * The size of the list may be given explicitely, but defaults to @c g_strv_length(strv).
*
* @param strv The list of strings to process.
- * @param num The number of strings contained in @a strv. Can be 0 if @a strv is a @c GStrv
+ * @param num The number of strings contained in @a strv. Can be 0 if it's terminated by @c NULL.
*
* @return The common prefix that is part of all strings.
*/
@@ -2154,11 +2153,12 @@ gchar *utils_strv_find_lcs(gchar **strv, size_t num)
* in duplicates (showing the full path might be inappropriate).
*
* The algorthm strips the common prefix (e-g. the user's home directory) and
- * replaces the longest common substring with "...".
+ * replaces the longest common substring with an ellipsis ("...").
*
* @param file_names @arraylen{num} The list of strings to process.
- * @param num The number of strings contained in @a strv. Can be 0 if @a strv is a @c GStrv
- * @return @transfer{full} A newly-allocated NULL-terminated array of transformed paths strings. Use @c g_strfreev() to free it.
+ * @param num The number of strings contained in @a file_names. Can be 0 if it's terminated by @c NULL.
+ * @return @transfer{full} A newly-allocated array of transformed paths strings, terminated by
+ @c NULL. Use @c g_strfreev() to free it.
*
* @since 1.34 (API 239)
*/
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Thomas Martitz <kugel(a)rockbox.org>
Committer: Thomas Martitz <kugel(a)rockbox.org>
Date: Mon, 03 Dec 2018 21:33:59 UTC
Commit: e0a2c6277ae739de6af6c1df311fc9979b54915a
https://github.com/geany/geany/commit/e0a2c6277ae739de6af6c1df311fc9979b549…
Log Message:
-----------
Refactoring and review comments
- Fix lots of compiler warnings
- Fix a bug where a long base name would prevent ellipsizing the longest
common substring
- rewrite utils_strv_shorten_file_list to be more clear (hopefully)
- use g_strlcpy
- optimize case where the longest common substring need not be searched for
Modified Paths:
--------------
src/utils.c
Modified: src/utils.c
115 lines changed, 63 insertions(+), 52 deletions(-)
===================================================================
@@ -2054,9 +2054,9 @@ gchar **utils_strv_join(gchar **first, gchar **second)
* @return The common prefix that is part of all strings (maybe empty), or NULL if an empty list
* was passed in.
*/
-static gchar *utils_strv_find_common_prefix(gchar **strv, size_t num)
+static gchar *utils_strv_find_common_prefix(gchar **strv, gsize num)
{
- gchar *prefix, **ptr;
+ gchar *prefix;
if (!NZV(strv))
return NULL;
@@ -2068,7 +2068,7 @@ static gchar *utils_strv_find_common_prefix(gchar **strv, size_t num)
for (gint i = 0; prefix[i]; i++)
{
- for (gint j = 1; j < num; j++)
+ for (gsize j = 1; j < num; j++)
{
gchar *s = strv[j];
if (s[i] != prefix[i])
@@ -2093,14 +2093,14 @@ static gchar *utils_strv_find_common_prefix(gchar **strv, size_t num)
*
* @return The common prefix that is part of all strings.
*/
-gchar *utils_strv_find_lcs(gchar **strv, size_t num)
+static gchar *utils_strv_find_lcs(gchar **strv, gsize num)
{
- gchar *first, *other, *_sub, *sub;
+ gchar *first, *_sub, *sub;
gsize n_chars;
gsize len;
gsize max = 0;
char *lcs;
- gint found;
+ gsize found;
if (strv == NULL)
return NULL;
@@ -2122,11 +2122,9 @@ gchar *utils_strv_find_lcs(gchar **strv, size_t num)
break;
for (n_chars = 1; n_chars <= chars_left; n_chars++)
{
- /* strlcpy() ftw! */
- memcpy(sub, _sub, n_chars);
- sub[n_chars] = '\0';
+ g_strlcpy(sub, _sub, n_chars+1);
found = 1;
- for (gint i = 1; i < num; i++)
+ for (gsize i = 1; i < num; i++)
{
if (strstr(strv[i], sub) == NULL)
break;
@@ -2147,7 +2145,7 @@ gchar *utils_strv_find_lcs(gchar **strv, size_t num)
/** Transform file names in a list to be shorter.
*
- * This function takes a list of file names (porbably with absolute paths), and
+ * This function takes a list of file names (probably with absolute paths), and
* transforms the paths such that they are short but still unique. This is intended
* for dialogs which present the file list to the user, where the base name may result
* in duplicates (showing the full path might be inappropriate).
@@ -2163,73 +2161,86 @@ gchar *utils_strv_find_lcs(gchar **strv, size_t num)
* @since 1.34 (API 239)
*/
GEANY_API_SYMBOL
-gchar **utils_strv_shorten_file_list(gchar **file_names, size_t num)
+gchar **utils_strv_shorten_file_list(gchar **file_names, gsize num)
{
- gint i, j;
- gchar *prefix, *substring, *name, *sep, **s;
- TMTag *tmtag;
+ gsize i;
+ gchar *prefix, *substring, *lcs;
+ gchar *start, *end;
gchar **names;
- gsize len;
+ gsize prefix_len, lcs_len;
/* The return value shall have exactly the same size as the input. If the input is a
* GStrv (last element is NULL), the output will follow suit. */
if (!num)
num = g_strv_length(file_names);
/* Always include a terminating NULL, enables easy freeing with g_strfreev() */
- names = g_new(gchar *, num + 1);
- names[num] = 0;
+ names = g_new0(gchar *, num + 1);
prefix = utils_strv_find_common_prefix(file_names, num);
/* First: determine the common prefix, that will be stripped.
* Don't strip single-letter prefixes, such as '/' */
- len = 0;
+ prefix_len = 0;
if (NZV(prefix) && prefix[1])
{
/* Only strip directory components, include trailing '/' */
- sep = strrchr(prefix, G_DIR_SEPARATOR);
- if (sep)
- len = sep - prefix + 1;
+ start = strrchr(prefix, G_DIR_SEPARATOR);
+ if (start)
+ prefix_len = start - prefix + 1;
}
- for (i = 0; i < num; i++)
- names[i] = g_strdup(file_names[i] + len);
+ /* Second: determine the longest common substring (lcs), that will be ellipsized. Look
+ * only at the directory parts since we don't want the file name to be detected as the lcs.
+ * Also, the first component cannot be common (since it would be part of the common prefix),
+ * so ignore that as well.
+ * Surround with dir separators so that we can easily determine the boundaries for ellipsizing. */
+ for (i = 0; i < num; i++) {
+ start = strchr(file_names[i] + prefix_len, G_DIR_SEPARATOR);
+ end = start ? strrchr(start+1, G_DIR_SEPARATOR) : NULL;
+ /* Breaking out early will also skip looking for lcs (wouldn't succeed anyway). */
+ if (!start || !end)
+ break;
+ names[i] = g_strndup(start, end-start+1);
+ }
- /* Second: determine the longest common substring, that will be ellipsized */
- substring = utils_strv_find_lcs(names, num);
+ lcs_len = 0;
+ substring = (i == num) ? utils_strv_find_lcs(names, num) : NULL;
if (NZV(substring))
{
- /* Only ellipsize directory components. Directory delimiters ought
- * to be part of the substring. If it doesn't contain at least two
- * separators, then there isn't even a single directory to ellipsize
- * (also take care to not ellipsize the base file name). */
- gchar *start;
- sep = strchr(substring, G_DIR_SEPARATOR);
-
- if (sep)
+ /* Strip leading component. */
+ start = strchr(substring, G_DIR_SEPARATOR);
+ if (start)
{
- len = 0;
- start = sep + 1;
- sep = strrchr(start, G_DIR_SEPARATOR);
- if (sep)
+ lcs = start + 1;
+ /* Strip trailing components (perhaps empty). */
+ end = strrchr(lcs, G_DIR_SEPARATOR);
+ if (end)
{
- *sep = '\0';
- len = strlen(start);
- }
- /* Don't bother for tiny substrings. */
- if (len >= 5)
- {
- for (i = 0; i < num; i++)
- {
- gchar *s = strstr(names[i], start);
- gchar *rem = s + len; /* +1 skips over the leading '/' */
- gsize copy_n = strlen(rem) + 1; /* include NUL */
- memcpy(s, "...", 3); /* Maybe replace with unicode's "…" ? */
- memmove(s+3, rem, copy_n);
- }
+ *end = '\0';
+ lcs_len = strlen(lcs);
+ /* Don't bother for tiny common parts (which are often just "." or "/"). */
+ if (lcs_len < 5)
+ lcs_len = 0;
}
}
}
+ /* Finally build the shortened list of unique file names */
+ for (i = 0; i < num; i++)
+ {
+ start = file_names[i] + prefix_len;
+ if (lcs_len == 0)
+ { /* no lcs, copy without prefix */
+ SETPTR(names[i], g_strdup(start));
+ }
+ else
+ {
+ const gchar *lcs_start = strstr(start, lcs);
+ const gchar *lcs_end = lcs_start + lcs_len;
+ /* Maybe replace with unicode's "…" ? */
+ SETPTR(names[i], g_strdup_printf("%.*s...%s", (int)(lcs_start - start), start, lcs_end));
+ }
+ }
+
g_free(substring);
g_free(prefix);
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Colomban Wendling <ban(a)herbesfolles.org>
Committer: Thomas Martitz <kugel(a)rockbox.org>
Date: Mon, 03 Dec 2018 21:33:59 UTC
Commit: 8f16685d9e29fc260eb43c6eb61bbf6ee54ee4df
https://github.com/geany/geany/commit/8f16685d9e29fc260eb43c6eb61bbf6ee54ee…
Log Message:
-----------
Fix a few signed vs unsigned comparisons
Modified Paths:
--------------
src/utils.c
src/utils.h
Modified: src/utils.c
33 lines changed, 17 insertions(+), 16 deletions(-)
===================================================================
@@ -2049,18 +2049,19 @@ gchar **utils_strv_join(gchar **first, gchar **second)
* The size of the list may be given explicitely, but defaults to @c g_strv_length(strv).
*
* @param strv The list of strings to process.
- * @param num The number of strings contained in @a strv. Can be -1 if it's terminated by @c NULL.
+ * @param strv_len The number of strings contained in @a strv. Can be -1 if it's terminated by @c NULL.
*
* @return The common prefix that is part of all strings (maybe empty), or NULL if an empty list
* was passed in.
*/
-static gchar *utils_strv_find_common_prefix(gchar **strv, gssize num)
+static gchar *utils_strv_find_common_prefix(gchar **strv, gssize strv_len)
{
+ gsize num;
+
if (!NZV(strv))
return NULL;
- if (num == -1)
- num = g_strv_length(strv);
+ num = (strv_len == -1) ? g_strv_length(strv) : (gsize) strv_len;
for (gsize i = 0; strv[0][i]; i++)
{
@@ -2083,22 +2084,21 @@ static gchar *utils_strv_find_common_prefix(gchar **strv, gssize num)
* The size of the list may be given explicitely, but defaults to @c g_strv_length(strv).
*
* @param strv The list of strings to process.
- * @param num The number of strings contained in @a strv. Can be -1 if it's terminated by @c NULL.
+ * @param strv_len The number of strings contained in @a strv. Can be -1 if it's terminated by @c NULL.
*
* @return The common prefix that is part of all strings.
*/
-static gchar *utils_strv_find_lcs(gchar **strv, gssize num)
+static gchar *utils_strv_find_lcs(gchar **strv, gssize strv_len)
{
gchar *first, *_sub, *sub;
+ gsize num;
gsize n_chars;
gsize len;
gsize max = 0;
char *lcs;
gsize found;
- if (num == -1)
- num = g_strv_length(strv);
-
+ num = (strv_len == -1) ? g_strv_length(strv) : (gsize) strv_len;
if (num < 1)
return NULL;
@@ -2147,29 +2147,30 @@ static gchar *utils_strv_find_lcs(gchar **strv, gssize num)
* The algorthm strips the common prefix (e-g. the user's home directory) and
* replaces the longest common substring with an ellipsis ("...").
*
- * @param file_names @array{length=num} The list of strings to process.
- * @param num The number of strings contained in @a file_names. Can be -1 if it's terminated by @c NULL.
+ * @param file_names @array{length=file_names_len} The list of strings to process.
+ * @param file_names_len The number of strings contained in @a file_names. Can be -1 if it's
+ * terminated by @c NULL.
* @return @transfer{full} A newly-allocated array of transformed paths strings, terminated by
@c NULL. Use @c g_strfreev() to free it.
*
* @since 1.34 (API 239)
*/
GEANY_API_SYMBOL
-gchar **utils_strv_shorten_file_list(gchar **file_names, gssize num)
+gchar **utils_strv_shorten_file_list(gchar **file_names, gssize file_names_len)
{
+ gsize num;
gsize i;
gchar *prefix, *substring, *lcs;
gchar *start, *end;
gchar **names;
gsize prefix_len, lcs_len;
- /* We don't dereference file_names if num == 0. */
- g_return_val_if_fail(num == 0 || file_names != NULL, NULL);
+ /* We don't dereference file_names if file_names_len == 0. */
+ g_return_val_if_fail(file_names_len == 0 || file_names != NULL, NULL);
/* The return value shall have exactly the same size as the input. If the input is a
* GStrv (last element is NULL), the output will follow suit. */
- if (num == -1)
- num = g_strv_length(file_names);
+ num = (file_names_len == -1) ? g_strv_length(file_names) : (gsize) file_names_len;
/* Always include a terminating NULL, enables easy freeing with g_strfreev() */
names = g_new0(gchar *, num + 1);
Modified: src/utils.h
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -301,7 +301,7 @@ gchar **utils_strv_new(const gchar *first, ...) G_GNUC_NULL_TERMINATED;
gchar **utils_strv_join(gchar **first, gchar **second) G_GNUC_WARN_UNUSED_RESULT;
-gchar **utils_strv_shorten_file_list(gchar **file_names, gssize num);
+gchar **utils_strv_shorten_file_list(gchar **file_names, gssize file_names_len);
GSList *utils_get_config_files(const gchar *subdir);
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Thomas Martitz <kugel(a)rockbox.org>
Committer: Thomas Martitz <kugel(a)rockbox.org>
Date: Mon, 03 Dec 2018 20:51:01 UTC
Commit: 4956b05d1e9052861deb3608673da25741bc6013
https://github.com/geany/geany/commit/4956b05d1e9052861deb3608673da25741bc6…
Log Message:
-----------
utils: add functions to process file name list
1) utils_strv_find_common_prefix
Locates the common prefix.
2) utils_strv_find_lcs
Finds the longest common substring.
3) utils_strv_shorten_file_list
Transforms the file list by removing the common prefix and ellipsizing
the longest common substring. This is intended to be used for fixing #1069.
Although only 3 will be used immediately, I separated the functionality, so
that the other two function can be used on their own.
Modified Paths:
--------------
src/utils.c
src/utils.h
Modified: src/utils.c
192 lines changed, 192 insertions(+), 0 deletions(-)
===================================================================
@@ -2044,6 +2044,198 @@ gchar **utils_strv_join(gchar **first, gchar **second)
return strv;
}
+/* * Returns the common prefix in a list of strings.
+ *
+ * The size of the list may be given explicitely automatically determined if passed a GStrv.
+ *
+ * @param strv The list of strings to process.
+ * @param num The number of strings contained in @a strv. Can be 0 if @a strv is a @c GStrv
+ *
+ * @return The common prefix that is part of all strings (maybe empty), or NULL if an empty list
+ * was passed in.
+ */
+static gchar *utils_strv_find_common_prefix(gchar **strv, size_t num)
+{
+ gchar *prefix, **ptr;
+
+ if (!NZV(strv))
+ return NULL;
+
+ if (num == 0)
+ num = g_strv_length(strv);
+
+ prefix = g_strdup(strv[0]);
+
+ for (gint i = 0; prefix[i]; i++)
+ {
+ foreach_strv(ptr, &strv[1])
+ for (gint j = 1; j < num; j++)
+ {
+ gchar *s = strv[j];
+ if (s[i] != prefix[i])
+ {
+ /* terminate prefix on first mismatch and return */
+ prefix[i] = '\0';
+ break;
+ }
+ }
+ if (prefix[i] == '\0')
+ break;
+ }
+ return prefix;
+}
+
+/* * Returns the common prefix in a list of strings.
+ *
+ * The size of the list may be given explicitely automatically determined if passed a GStrv.
+ *
+ * @param strv The list of strings to process.
+ * @param num The number of strings contained in @a strv. Can be 0 if @a strv is a @c GStrv
+ *
+ * @return The common prefix that is part of all strings.
+ */
+gchar *utils_strv_find_lcs(gchar **strv, size_t num)
+{
+ gchar *first, *other, *_sub, *sub;
+ gsize n_chars;
+ gsize len;
+ gsize max = 0;
+ char *lcs;
+ gint found;
+
+ if (strv == NULL)
+ return NULL;
+
+ first = strv[0];
+ len = strlen(first);
+
+ if (num == 0)
+ num = g_strv_length(strv);
+
+ /* sub is the working area where substrings from first are copied to */
+ sub = g_malloc(len+1);
+ lcs = g_strdup("");
+ foreach_str(_sub, first)
+ {
+ gsize chars_left = len - (_sub - first);
+ /* No point in continuing if the remainder is too short */
+ if (max > chars_left)
+ break;
+ for (n_chars = 1; n_chars <= chars_left; n_chars++)
+ {
+ /* strlcpy() ftw! */
+ memcpy(sub, _sub, n_chars);
+ sub[n_chars] = '\0';
+ found = 1;
+ for (gint i = 1; i < num; i++)
+ {
+ if (strstr(strv[i], sub) == NULL)
+ break;
+ found++;
+ }
+ if (found == num && n_chars > max)
+ {
+ max = n_chars;
+ SETPTR(lcs, g_strdup(sub));
+ }
+ }
+ }
+ g_free(sub);
+
+ return lcs;
+}
+
+
+/** Transform file names in a list to be shorter.
+ *
+ * This function takes a list of file names (porbably with absolute paths), and
+ * transforms the paths such that they are short but still unique. This is intended
+ * for dialogs which present the file list to the user, where the base name may result
+ * in duplicates (showing the full path might be inappropriate).
+ *
+ * The algorthm strips the common prefix (e-g. the user's home directory) and
+ * replaces the longest common substring with "...".
+ *
+ * @param file_names @arraylen{num} The list of strings to process.
+ * @param num The number of strings contained in @a strv. Can be 0 if @a strv is a @c GStrv
+ * @return @transfer{full} A newly-allocated NULL-terminated array of transformed paths strings. Use @c g_strfreev() to free it.
+ *
+ * @since 1.31 (API 232
+ */
+GEANY_API_SYMBOL
+gchar **utils_strv_shorten_file_list(gchar **file_names, size_t num)
+{
+ gint i, j;
+ gchar *prefix, *substring, *name, *sep, **s;
+ TMTag *tmtag;
+ gchar **names;
+ gsize len;
+
+ /* The return value shall have exactly the same size as the input. If the input is a
+ * GStrv (last element is NULL), the output will follow suit. */
+ if (!num)
+ num = g_strv_length(file_names);
+ /* Always include a terminating NULL, enables easy freeing with g_strfreev() */
+ names = g_new(gchar *, num + 1);
+ names[num] = 0;
+
+ prefix = utils_strv_find_common_prefix(file_names, num);
+ /* First: determine the common prefix, that will be stripped.
+ * Don't strip single-letter prefixes, such as '/' */
+ len = 0;
+ if (NZV(prefix) && prefix[1])
+ {
+ /* Only strip directory components, include trailing '/' */
+ sep = strrchr(prefix, G_DIR_SEPARATOR);
+ if (sep)
+ len = sep - prefix + 1;
+ }
+
+ for (i = 0; i < num; i++)
+ names[i] = g_strdup(file_names[i] + len);
+
+ /* Second: determine the longest common substring, that will be ellipsized */
+ substring = utils_strv_find_lcs(names, num);
+ if (NZV(substring))
+ {
+ /* Only ellipsize directory components. Directory delimiters ought
+ * to be part of the substring. If it doesn't contain at least two
+ * separators, then there isn't even a single directory to ellipsize
+ * (also take care to not ellipsize the base file name). */
+ gchar *start;
+ sep = strchr(substring, G_DIR_SEPARATOR);
+
+ if (sep)
+ {
+ len = 0;
+ start = sep + 1;
+ sep = strrchr(start, G_DIR_SEPARATOR);
+ if (sep)
+ {
+ *sep = '\0';
+ len = strlen(start);
+ }
+ /* Don't bother for tiny substrings. */
+ if (len >= 5)
+ {
+ for (i = 0; i < num; i++)
+ {
+ gchar *s = strstr(names[i], start);
+ gchar *rem = s + len; /* +1 skips over the leading '/' */
+ gsize copy_n = strlen(rem) + 1; /* include NUL */
+ memcpy(s, "...", 3); /* Maybe replace with unicode's "…" ? */
+ memmove(s+3, rem, copy_n);
+ }
+ }
+ }
+ }
+
+ g_free(substring);
+ g_free(prefix);
+
+ return names;
+}
+
/* Try to parse a date using g_date_set_parse(). It doesn't take any format hint,
* obviously g_date_set_parse() uses some magic.
Modified: src/utils.h
2 lines changed, 2 insertions(+), 0 deletions(-)
===================================================================
@@ -301,6 +301,8 @@ gchar **utils_strv_new(const gchar *first, ...) G_GNUC_NULL_TERMINATED;
gchar **utils_strv_join(gchar **first, gchar **second) G_GNUC_WARN_UNUSED_RESULT;
+gchar **utils_strv_shorten_file_list(gchar **file_names, size_t num);
+
GSList *utils_get_config_files(const gchar *subdir);
gchar *utils_get_help_url(const gchar *suffix);
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Thomas Martitz <kugel(a)rockbox.org>
Committer: Thomas Martitz <kugel(a)rockbox.org>
Date: Mon, 03 Dec 2018 20:51:01 UTC
Commit: b116a66862eb89b0c12833eb9bc6ecafcb6c7284
https://github.com/geany/geany/commit/b116a66862eb89b0c12833eb9bc6ecafcb6c7…
Log Message:
-----------
symbols: provide a bit more path information in the goto-symbol popup.
>From #1069:
> At the moment if symbols of the same name are defined in identically named
> files, it's hard to distinguish which file is which because there's no path
> in the popup.
> The popup should show part of the path until a directory where the paths
> differ so it's possible to distinguish the different files. At the same time
> there should probably be some top limit for the length of the paths as they
> can make the popup too wide.
This addresses the above by showing more of the file's paths but still try
to make it as short as possible. The file list is processed by the new
utils_strv_shorten_file_list(), as a result the popup will list files with
the common prefix stripped and the longest common sub-path ellipsized.
As a result, the file list shows enough of the path to make them unique but
still is still very short and doesn't make the dialog too wide.
Fixes #1069.
Modified Paths:
--------------
src/symbols.c
src/utils.c
Modified: src/symbols.c
13 lines changed, 11 insertions(+), 2 deletions(-)
===================================================================
@@ -1933,15 +1933,23 @@ static void show_goto_popup(GeanyDocument *doc, GPtrArray *tags, gboolean have_b
GdkEventButton *button_event = NULL;
TMTag *tmtag;
guint i;
-
+ gchar **short_names, **file_names, **p;
menu = gtk_menu_new();
+ /* If popup would show multiple files presend a smart file list that allows
+ * to easily distinguish the files while avoiding the file paths in their entirety */
+ file_names = g_new(gchar *, tags->len);
+ foreach_ptr_array(tmtag, i, tags)
+ file_names[i] = tmtag->file->file_name;
+ short_names = utils_strv_shorten_file_list(file_names, tags->len);
+ g_free(file_names);
+
foreach_ptr_array(tmtag, i, tags)
{
GtkWidget *item;
GtkWidget *label;
GtkWidget *image;
- gchar *fname = g_path_get_basename(tmtag->file->file_name);
+ gchar *fname = short_names[i];
gchar *text;
if (! first && have_best)
@@ -1964,6 +1972,7 @@ static void show_goto_popup(GeanyDocument *doc, GPtrArray *tags, gboolean have_b
g_free(text);
g_free(fname);
}
+ g_free(short_names);
gtk_widget_show_all(menu);
Modified: src/utils.c
9 lines changed, 3 insertions(+), 6 deletions(-)
===================================================================
@@ -2146,7 +2146,7 @@ gchar *utils_strv_find_lcs(gchar **strv, size_t num)
}
-/** Transform file names in a list to be shorter.
+/* * Transform file names in a list to be shorter.
*
* This function takes a list of file names (porbably with absolute paths), and
* transforms the paths such that they are short but still unique. This is intended
@@ -2156,13 +2156,10 @@ gchar *utils_strv_find_lcs(gchar **strv, size_t num)
* The algorthm strips the common prefix (e-g. the user's home directory) and
* replaces the longest common substring with "...".
*
- * @param file_names @arraylen{num} The list of strings to process.
+ * @param file_names The list of strings to process.
* @param num The number of strings contained in @a strv. Can be 0 if @a strv is a @c GStrv
- * @return @transfer{full} A newly-allocated NULL-terminated array of transformed paths strings. Use @c g_strfreev() to free it.
- *
- * @since 1.31 (API 232
+ * @return A newly-allocated NULL-terminated array of transformed paths strings. Use @c g_strfreev() to free it.
*/
-GEANY_API_SYMBOL
gchar **utils_strv_shorten_file_list(gchar **file_names, size_t num)
{
gint i, j;
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).