This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository efm2.
View the commit online.
commit 38f0570028d3d4176f2fccc3e3b45d0770df8c99
Author: Carsten Haitzler (Rasterman) <[email protected]>
AuthorDate: Sat Jan 31 10:32:52 2026 +0000
typebuf - add completing abs, user and relatve path and go there
---
src/efm/efm.c | 16 +--
src/efm/efm_typebuf.c | 355 +++++++++++++++++++++++++++++++++++++++++++++++---
src/efm/efm_util.c | 17 +++
src/efm/efm_util.h | 1 +
4 files changed, 361 insertions(+), 28 deletions(-)
diff --git a/src/efm/efm.c b/src/efm/efm.c
index 4ea7d55..410e572 100644
--- a/src/efm/efm.c
+++ b/src/efm/efm.c
@@ -1560,19 +1560,12 @@ efm_path_get(Evas_Object *obj)
void
efm_path_parent(Evas_Object *obj)
{
- char *tmps, *p;
+ char *tmps;
ENTRY;
if (!sd->config.path) return;
- tmps = strdup(sd->config.path);
+ tmps = _path_parent(sd->config.path);
if (!tmps) return;
- p = strrchr(tmps, '/');
- if ((p) && (p != tmps))
- {
- *p = 0;
- p = strrchr(tmps, '/');
- if (p) p[1] = 0;
- }
eina_stringshare_replace(&sd->config.path, tmps);
_reset(sd);
free(tmps);
@@ -1850,8 +1843,9 @@ _menu_icon_radcheck_add(Evas_Object *o_base, int icon_col, const char *icon, int
return o_table;
}
-static void _menu_create_walk(void *data, Evas_Object *obj, const Efm_Menu *m,
- Evas_Object *o_menu, Elm_Object_Item *it_parent)
+static void
+_menu_create_walk(void *data, Evas_Object *obj, const Efm_Menu *m,
+ Evas_Object *o_menu, Elm_Object_Item *it_parent)
{
Elm_Object_Item *it;
Evas_Object *o, *o_radio = NULL, *o_table;
diff --git a/src/efm/efm_typebuf.c b/src/efm/efm_typebuf.c
index 7d5bb32..f138d87 100644
--- a/src/efm/efm_typebuf.c
+++ b/src/efm/efm_typebuf.c
@@ -1,7 +1,6 @@
+#define EFL_BETA_API_SUPPORT 1
#include "efm_typebuf.h"
#include "efm_util.h"
-#include "eina_stringshare.h"
-#include "elm_entry_eo.legacy.h"
static int
_typebuf_command_detect(const char *str)
@@ -128,6 +127,317 @@ _has_glob(const char *glob)
return EINA_FALSE;
}
+static int
+_cb_complete_dir_sort(char *f1, char *f2)
+{
+ return strcmp(f1, f2);
+}
+
+static char *
+_complete_dir(const char *str)
+{
+ Eina_Iterator *it;
+ Eina_File_Direct_Info *info;
+ size_t len = strlen(str);
+ char *dir = ecore_file_dir_get(str);
+ char *ret = NULL, *s;
+ Eina_List *opts = NULL;
+
+ if (!dir) return NULL;
+ it = eina_file_direct_ls(dir);
+ if (!it) goto done;
+ EINA_ITERATOR_FOREACH(it, info)
+ { // walk dir and find files that match partial start string
+ if ((!strncmp(str, info->path, len))
+ && ((info->type == EINA_FILE_DIR) || (info->type == EINA_FILE_LNK)))
+ {
+ if (ecore_file_is_dir(info->path))
+ { // completion must be a dir (resolves a symlink too)
+ Eina_Strbuf *buf = eina_strbuf_new();
+
+ if (buf)
+ {
+ eina_strbuf_append(buf, info->path);
+ eina_strbuf_append(buf, "/");
+ ret = strdup(eina_strbuf_string_get(buf));
+ // add this path to our options for complete
+ opts = eina_list_append(opts, ret);
+ eina_strbuf_free(buf);
+ }
+ }
+ break;
+ }
+ }
+ eina_iterator_free(it);
+done:
+ free(dir);
+ opts = eina_list_sort(opts, 0, (Eina_Compare_Cb)_cb_complete_dir_sort);
+ // take first result in sorted list
+ ret = opts->data;
+ opts->data = ""
+ // free out tmp list of options
+ EINA_LIST_FREE(opts, s) free(s);
+ return ret;
+}
+
+////////////////
+static Eina_Bool
+_has_path_full(const char *str)
+{
+ return eina_fnmatch("/*", str, EINA_FNMATCH_CASEFOLD);
+}
+
+static void
+_path_full_hilight(Smart_Data *sd, const char *str)
+{
+ Eina_Strbuf *buf = eina_strbuf_new();
+ const char *s;
+
+ if (!buf) return;
+ for (s = str; *s; s++)
+ {
+ if (*s == '/')
+ {
+ eina_strbuf_append(buf, "<hilight>");
+ eina_strbuf_append_char(buf, *s);
+ eina_strbuf_append(buf, "</>");
+ }
+ else eina_strbuf_append_char(buf, *s);
+ }
+ elm_entry_entry_set(sd->o_typebuf, eina_strbuf_string_get(buf));
+ eina_strbuf_free(buf);
+}
+
+static Eina_Bool
+_path_full(Smart_Data *sd, const char *str)
+{
+ if (!_has_path_full(str)) return EINA_FALSE;
+ _path_full_hilight(sd, str);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_path_full_complete(Smart_Data *sd, const char *str)
+{
+ char *complete;
+
+ if (!_has_path_full(str)) return EINA_FALSE;
+ complete = _complete_dir(str);
+ if (complete)
+ {
+ _path_full_hilight(sd, complete);
+ elm_entry_cursor_end_set(sd->o_typebuf);
+ free(complete);
+ }
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_path_full_run(Smart_Data *sd, const char *str)
+{
+ if (!_has_path_full(str)) return EINA_FALSE;
+ if (ecore_file_is_dir(str)) efm_path_set(sd->o_smart, str);
+ return EINA_TRUE;
+}
+
+////////////////
+static Eina_Bool
+_has_path_relative(const char *str)
+{
+ return eina_fnmatch("../*", str, EINA_FNMATCH_CASEFOLD);
+}
+
+static void
+_path_relative_hilight(Smart_Data *sd, const char *str)
+{
+ Eina_Strbuf *buf = eina_strbuf_new();
+ const char *s;
+
+ if (!buf) return;
+ // we know str already has "../" at the start
+ if (str[0] && str[1] && str[2])
+ {
+ eina_strbuf_append(buf, "<hilight>..</>");
+ for (s = str + 2; *s; s++) // skip the ../
+ {
+ if (*s == '/')
+ {
+ eina_strbuf_append(buf, "<hilight>");
+ eina_strbuf_append_char(buf, *s);
+ eina_strbuf_append(buf, "</>");
+ }
+ else eina_strbuf_append_char(buf, *s);
+ }
+ elm_entry_entry_set(sd->o_typebuf, eina_strbuf_string_get(buf));
+ }
+ eina_strbuf_free(buf);
+}
+
+static Eina_Bool
+_path_relative(Smart_Data *sd, const char *str)
+{
+ if (!_has_path_relative(str)) return EINA_FALSE;
+ _path_relative_hilight(sd, str);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_path_relative_complete(Smart_Data *sd, const char *str)
+{
+ Eina_Strbuf *buf;
+ char *tmps;
+
+ if (!_has_path_relative(str)) return EINA_FALSE;
+ // str starts with ../ so find parent
+ tmps = _path_parent(sd->config.path);
+ if (!tmps) return EINA_TRUE;
+ buf = eina_strbuf_new();
+ if (!buf) goto done;
+ eina_strbuf_append(buf, tmps);
+ eina_strbuf_append(buf, str + 3);
+ free(tmps);
+ tmps = _complete_dir(eina_strbuf_string_get(buf));
+ eina_strbuf_free(buf);
+ if (tmps)
+ {
+ _path_full_hilight(sd, tmps);
+ elm_entry_cursor_end_set(sd->o_typebuf);
+ }
+done:
+ free(tmps);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_path_relative_run(Smart_Data *sd, const char *str)
+{
+ Eina_Strbuf *buf;
+ char *tmps;
+ const char *path;
+
+ if (!_has_path_relative(str)) return EINA_FALSE;
+ tmps = _path_parent(sd->config.path);
+ if (!tmps) return EINA_TRUE;
+ buf = eina_strbuf_new();
+ if (!buf) goto done;
+ eina_strbuf_append(buf, tmps);
+ eina_strbuf_append(buf, str + 3);
+ path = eina_strbuf_string_get(buf);
+ if (ecore_file_is_dir(path)) efm_path_set(sd->o_smart, path);
+ eina_strbuf_free(buf);
+done:
+ free(tmps);
+ return EINA_TRUE;
+}
+
+////////////////
+static Eina_Bool
+_has_path_user(const char *str)
+{
+ return eina_fnmatch("~*/*", str, EINA_FNMATCH_CASEFOLD);
+}
+
+static void
+_path_user_hilight(Smart_Data *sd, const char *str)
+{
+ Eina_Strbuf *buf = eina_strbuf_new();
+ char *home = NULL, *h;
+ const char *s, *rest;
+
+ if (!buf) return;
+ // we know str already has ~/ or ~user/ at the start
+ rest = strchr(str, '/');
+ if (!rest) goto done;
+ rest++;
+ // make new home string that has just ~/ or ~user/ withotu the rest
+ home = strdup(str);
+ if (!home) goto done;
+ h = strchr(home, '/');
+ if (h) h[1] = 0;
+ eina_strbuf_append(buf, "<hilight>");
+ eina_strbuf_append(buf, home);
+ eina_strbuf_append(buf, "</>");
+ for (s = rest; *s; s++)
+ {
+ if (*s == '/')
+ {
+ eina_strbuf_append(buf, "<hilight>");
+ eina_strbuf_append_char(buf, *s);
+ eina_strbuf_append(buf, "</>");
+ }
+ else eina_strbuf_append_char(buf, *s);
+ }
+ elm_entry_entry_set(sd->o_typebuf, eina_strbuf_string_get(buf));
+done:
+ free(home);
+ eina_strbuf_free(buf);
+}
+
+static Eina_Bool
+_path_user(Smart_Data *sd, const char *str)
+{
+ if (!_has_path_user(str)) return EINA_FALSE;
+ _path_user_hilight(sd, str);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_path_user_complete(Smart_Data *sd, const char *str)
+{
+ const char *rest, *s1, *s2;
+ char *home = NULL, *h;
+ char *resolve = NULL, *complete = NULL, *src = ""
+ Eina_Strbuf *buf;
+
+ if (!_has_path_user(str)) return EINA_FALSE;
+ // we know str already has ~/ or ~user/ at the start
+ rest = strchr(str, '/');
+ if (!rest) goto done;
+ rest++;
+ // make new home string that has just ~/ or ~user/ withotu the rest
+ home = strdup(str);
+ if (!home) goto done;
+ h = strchr(home, '/');
+ if (h) h[1] = 0;
+ buf = eina_strbuf_new();
+ if (buf)
+ {
+ resolve = eina_vpath_resolve(home);
+ if (!resolve) goto done;
+ src = ""
+ if (!src) goto done;
+ complete = _complete_dir(src);
+ // while home resolved + complete match strings...
+ for (s1 = resolve, s2 = complete; (*s1) && (*s2) && (*s1 == *s2);
+ s1++, s2++);
+ eina_strbuf_append(buf, home);
+ eina_strbuf_append(buf, s2);
+ _path_user_hilight(sd, eina_strbuf_string_get(buf));
+ elm_entry_cursor_end_set(sd->o_typebuf);
+ eina_strbuf_free(buf);
+ }
+done:
+ free(src);
+ free(resolve);
+ free(home);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_path_user_run(Smart_Data *sd, const char *str)
+{
+ char *path;
+
+ if (!_has_path_user(str)) return EINA_FALSE;
+ path = eina_vpath_resolve(str);
+ if (path)
+ {
+ if (ecore_file_is_dir(path)) efm_path_set(sd->o_smart, path);
+ free(path);
+ }
+ return EINA_TRUE;
+}
+
static void
_typebuf_update(Smart_Data *sd, const char *str)
{
@@ -148,8 +458,10 @@ _typebuf_update(Smart_Data *sd, const char *str)
size_t tblen = strlen(str);
if (tblen == 0) _efm_sel_none(sd);
- else
- {
+ // check special paths first
+ else if ((!_path_full(sd, str)) && (!_path_relative(sd, str))
+ && (!_path_user(sd, str)))
+ { // not a special path - glob matching
if (!_has_glob(str))
{ // if we don't end in * or ] or ? assume a * on the end
char *tb = alloca(tblen + 2);
@@ -214,20 +526,25 @@ _typebuf_complete(Smart_Data *sd)
}
else
{
- Icon *ic = _efm_sel_first_get(sd);
-
- printf("XXX: selected %p\n", ic);
- if (ic)
+ if ((!_path_full_complete(sd, s))
+ && (!_path_relative_complete(sd, s))
+ && (!_path_user_complete(sd, s)))
{
- char *s2 = elm_entry_utf8_to_markup(ic->info.file);
- _typebuf_command_clear(sd, s2);
- elm_entry_cursor_end_set(sd->o_typebuf);
- free(s2);
- _efm_sel_none(sd);
- _icon_select(ic);
- _efm_icon_bring_in(ic);
+ Icon *ic = _efm_sel_first_get(sd);
+
+ printf("XXX: selected %p\n", ic);
+ if (ic)
+ {
+ char *s2 = elm_entry_utf8_to_markup(ic->info.file);
+ _typebuf_command_clear(sd, s2);
+ elm_entry_cursor_end_set(sd->o_typebuf);
+ free(s2);
+ _efm_sel_none(sd);
+ _icon_select(ic);
+ _efm_icon_bring_in(ic);
+ }
+ _typebuf_cmd_reset(sd);
}
- _typebuf_cmd_reset(sd);
}
free(s);
}
@@ -302,7 +619,11 @@ _cb_typebuf_activated(void *data, Evas_Object *obj EINA_UNUSED,
}
else
{
- _efm_icons_run(sd, EINA_FALSE);
+ if ((!_path_full_run(sd, s)) && (!_path_relative_run(sd, s))
+ && (!_path_user_run(sd, s)))
+ {
+ _efm_icons_run(sd, EINA_FALSE);
+ }
}
typebuf_del(sd);
_typebuf_cmd_reset(sd);
diff --git a/src/efm/efm_util.c b/src/efm/efm_util.c
index 394996b..acbb358 100644
--- a/src/efm/efm_util.c
+++ b/src/efm/efm_util.c
@@ -3040,4 +3040,21 @@ _flex_icon_add(Evas_Object *o_base, const char *icon)
}
}
return o;
+}
+
+char *
+_path_parent(const char *path)
+{
+ char *tmps, *p;
+
+ tmps = strdup(path);
+ if (!tmps) return NULL;
+ p = strrchr(tmps, '/');
+ if ((p) && (p != tmps))
+ {
+ *p = 0;
+ p = strrchr(tmps, '/');
+ if (p) p[1] = 0;
+ }
+ return tmps;
}
\ No newline at end of file
diff --git a/src/efm/efm_util.h b/src/efm/efm_util.h
index afad3b5..362ac6c 100644
--- a/src/efm/efm_util.h
+++ b/src/efm/efm_util.h
@@ -81,5 +81,6 @@ Eina_Bool _efm_icons_run(Smart_Data *sd, Eina_Bool last_sel);
void _efm_icon_bring_in(Icon *icon);
Evas_Object *_flex_icon_add(Evas_Object *o_base, const char *icon);
+char *_path_parent(const char *path);
#endif
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.