icewm/configure.in | 16 ++++ icewm/src/aaddressbar.cc | 173 ++++++++++++++++++++++++++++++++++++++++++++++ icewm/src/config.h.in | 3 + icewm/src/yinput.cc | 2 +- 4 files changed, 193 insertions(+), 1 deletions(-) diff --git a/icewm/configure.in b/icewm/configure.in index 58f248e..6a9ea8e 100644 --- a/icewm/configure.in +++ b/icewm/configure.in @@ -482,6 +482,22 @@ AC_ARG_ENABLE(xfreetype, features="${features} corefonts" fi +dnl =================================================== Support for readline === +dnl +AC_ARG_ENABLE(readline, + [ --with-readline Enable readline & history support]) + if test "$with_readline" != "no"; then + AC_CHECK_LIB(history, using_history, + CORE_LIBS="${CORE_LIBS} -lhistory -lreadline" + features="${features} readline" + [ AC_DEFINE(HAVE_READLINE, 1, [Enable readline & history support]) ], + [ AC_MSG_ERROR([Unable to find history library])]) + AC_CHECK_LIB(ncurses, copywin, + CORE_LIBS="${CORE_LIBS} -lncurses" + [ ], + [ AC_MSG_ERROR([Unable to find ncurses library])]) + fi + dnl ============================================================= GUI Events === dnl AC_ARG_ENABLE(guievents, diff --git a/icewm/src/aaddressbar.cc b/icewm/src/aaddressbar.cc index 31c5e83..1767031 100644 --- a/icewm/src/aaddressbar.cc +++ b/icewm/src/aaddressbar.cc @@ -15,8 +15,144 @@ #include "sysdep.h" #include "default.h" +#ifdef HAVE_READLINE +#include +#include + +char *extract_colon_unit (char *string, int *p_index) +{ + int i, start, len; + char *value = NULL; + + if (string == 0) + return (string); + + len = strlen (string); + if (*p_index >= len) + return ((char *)NULL); + + i = *p_index; + + if (i && string[i] == ':') + i++; + + for (start = i; string[i] && string[i] != ':'; i++) + ; + + *p_index = i; + + if (i == start) + { + if (string[i]) + (*p_index)++; + /* Return "" in the case of a trailing `:'. */ + value = new char[1]; + value[0] = '\0'; + } + else + { + int len = i-start; + value = new char[len+1]; + strncpy(value, string+start,len); + value[len] = '\0'; + } + + return (value); +} + +char *find_completion(const char *text,int *state) { + char *path = getenv("PATH"); + char *current_path; + char **matches = NULL; + char *filename = NULL; + char *found = NULL; + int path_index, text_len = strlen(text), found_len = 0, path_len = 0; + struct stat st; + + *state = 0; + path_index = 0; + if (text[0] != '/' && text[0] != '~') { + while (path && path[path_index]) { + current_path = extract_colon_unit(path, &path_index); + if (current_path && *current_path) { + filename = new char[2+strlen(current_path)+text_len]; + sprintf(filename,"%s/%s",current_path,text); + path_len = strlen(current_path)+1; + free(current_path); + matches = rl_completion_matches(filename, rl_filename_completion_function); + if (matches) { + //if (!matches[1]) { + char *f = *matches+path_len; + int len = strlen(f); + if (len < found_len) { + free(found); + found = strdup(f); + found_len = len; + *state = 3; + } else if (*state) { + *state = 2; + if (found) { + free(found); + found = NULL; + } + } else { + found = strdup(*matches+path_len); + found_len = strlen(found); + if (matches[1]) + *state = 3; + else + *state = 1; + } + //} else { + // *state = 2; + // } + } + if (*state == 2) + return NULL; + } + } + } else { + const char *wtilde = NULL; + int len = -1; + if (text[0] == '~') { + wtilde = text; + text = tilde_expand(text); + len = strlen(text); + } + matches = rl_completion_matches(text, rl_filename_completion_function); + if (matches) { + stat(*matches,&st); + if (len > 0) { + *matches += len; + len = text_len+strlen(*matches); + found = new char[len+2]; + if (S_ISDIR(st.st_mode) && !matches[1]) { + sprintf(found,"%s%s/",wtilde,*matches); + } else { + sprintf(found,"%s%s",wtilde,*matches); + } + } else { + if (S_ISDIR(st.st_mode) && !matches[1]) { + found = new char[strlen(*matches)+2]; + sprintf(found,"%s/",*matches); + } else { + found = strdup(*matches); + } + } + if (matches[1]) + *state = 3; + else + *state = 1; + } + } + return found; +} +#endif /* HAVE_READLINE */ AddressBar::AddressBar(YWindow *parent): YInputLine(parent) { +#ifdef HAVE_READLINE + using_history(); +#endif } AddressBar::~AddressBar() { @@ -27,7 +163,41 @@ bool AddressBar::handleKey(const XKeyEvent &key) { KeySym k = XKeycodeToKeysym(xapp->display(), (KeyCode)key.keycode, 0); int m = KEY_MODMASK(key.state); +#ifdef HAVE_READLINE + if (k == XK_Tab) { + int state=0, p; + char *f; + char *text = strdup(getText()); + p = prevWord(strlen(text), false); + text += p; + f = find_completion(text,&state); + if (state & 1) { + char *t = f; + if (p != 0) { + t = new char[strlen(f)+p+2]; + *text = '\0'; + text -= p; + sprintf(t,"%s%s",text,f); + free(text); + free(f); + } + setText(t); + free(t); + } + if (!state || state & 2) + ; // printf("\a\n"); + return true; // for future compatibility + } else if (k == XK_Up || k == XK_Down) { + HIST_ENTRY *hist; + hist = k == XK_Down ? next_history() : previous_history(); + if (hist == NULL) + return true; + setText(hist->line); + return true; + } else if (k == XK_KP_Enter || k == XK_Return) { +#else if (k == XK_KP_Enter || k == XK_Return) { +#endif const char *t = getText(); const char *args[7]; int i = 0; @@ -50,6 +220,9 @@ bool AddressBar::handleKey(const XKeyEvent &key) { if (m & ControlMask) if (t == 0 || t[0] == 0) args[1] = 0; +#ifdef HAVE_READLINE + add_history((char *)t); +#endif app->runProgram(args[0], args); selectAll(); return true; diff --git a/icewm/src/config.h.in b/icewm/src/config.h.in index ce58d3a..5c1f553 100644 --- a/icewm/src/config.h.in +++ b/icewm/src/config.h.in @@ -351,5 +351,8 @@ /* Define to 1 if the X Window System is missing or not being used. */ #undef X_DISPLAY_MISSING +/* Define to 1 if the readline (address bar history) support used. */ +#undef HAVE_READLINE + /* Define to `unsigned int' if does not define. */ #undef size_t diff --git a/icewm/src/yinput.cc b/icewm/src/yinput.cc index 3647241..6e81368 100644 --- a/icewm/src/yinput.cc +++ b/icewm/src/yinput.cc @@ -84,7 +84,7 @@ void YInputLine::setText(const char *text) { fText = newstr(text); markPos = curPos = leftOfs = 0; if (fText) - curPos = strlen(fText); + markPos = curPos = strlen(fText); limit(); repaint(); }