aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmdline.cpp
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-10 20:08:51 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-11-10 20:08:51 +0100
commitf120e3e367f01f006bd5ddfd9f1ac018273e75e3 (patch)
tree65e51cfbc6bc05eb25d331bcb86ed642a1af6bad /cmdline.cpp
parent5aa548cd63edb8ba12c656300a2a5f0ff62a7b36 (diff)
downloadsciteco-f120e3e367f01f006bd5ddfd9f1ac018273e75e3.tar.gz
filename autocompletion using <CTRL/T> and <TAB>
* <TAB> autocompletion only in specified states * GtkInfoPopup widget to display possible completions, written using Gob2
Diffstat (limited to 'cmdline.cpp')
-rw-r--r--cmdline.cpp140
1 files changed, 140 insertions, 0 deletions
diff --git a/cmdline.cpp b/cmdline.cpp
index 152adc5..9f3a438 100644
--- a/cmdline.cpp
+++ b/cmdline.cpp
@@ -3,6 +3,7 @@
#include <glib.h>
#include <glib/gprintf.h>
+#include <glib/gstdio.h>
#include "sciteco.h"
#include "parser.h"
@@ -11,6 +12,11 @@
static inline const gchar *process_edit_cmd(gchar key);
static gchar *macro_echo(const gchar *macro, const gchar *prefix = "");
+static gchar *filename_complete(const gchar *filename, gchar completed = ' ');
+
+static const gchar *last_occurrence(const gchar *str,
+ const gchar *chars = " \t\v\r\n\f<>,;@");
+static inline gboolean filename_is_dir(const gchar *filename);
gchar *cmdline = NULL;
@@ -24,6 +30,14 @@ cmdline_keypress(gchar key)
gchar *echo;
/*
+ * Cleanup messages, popups, etc...
+ */
+ if (gtk_widget_get_visible(GTK_WIDGET(filename_popup))) {
+ gtk_widget_hide(GTK_WIDGET(filename_popup));
+ gtk_info_popup_clear(filename_popup);
+ }
+
+ /*
* Process immediate editing commands
*/
insert = process_edit_cmd(key);
@@ -74,6 +88,28 @@ process_edit_cmd(gchar key)
}
break;
+ case CTL_KEY('T'): {
+ const gchar *filename = cmdline ? last_occurrence(cmdline) + 1
+ : NULL;
+ gchar *new_chars = filename_complete(filename);
+ if (new_chars)
+ g_stpcpy(insert, new_chars);
+ g_free(new_chars);
+ break;
+ }
+
+ case '\t':
+ if (current_state == &states.file) {
+ gchar *new_chars = filename_complete(strings[0], escape_char);
+ if (new_chars)
+ g_stpcpy(insert, new_chars);
+ g_free(new_chars);
+ break;
+ }
+ insert[0] = key;
+ insert[1] = '\0';
+ break;
+
case '\x1B':
if (cmdline && cmdline[cmdline_len - 1] == '\x1B') {
if (quit_requested) {
@@ -135,3 +171,107 @@ macro_echo(const gchar *macro, const gchar *prefix)
return result;
}
+
+static gchar *
+filename_complete(const gchar *filename, gchar completed)
+{
+ gchar *dirname, *basename;
+ GDir *dir;
+ GList *files = NULL, *matching;
+ GCompletion *completion;
+ gchar *new_prefix;
+ gchar *insert = NULL;
+
+ if (!filename)
+ filename = "";
+
+ if (is_glob_pattern(filename))
+ return NULL;
+
+ dirname = g_path_get_dirname(filename);
+ dir = g_dir_open(dirname, 0, NULL);
+ if (!dir) {
+ g_free(dirname);
+ return NULL;
+ }
+ if (*dirname != *filename)
+ *dirname = '\0';
+
+ while ((basename = (gchar *)g_dir_read_name(dir))) {
+ gchar *filename = g_build_filename(dirname, basename, NULL);
+
+ if (g_file_test(filename, G_FILE_TEST_IS_DIR)) {
+ gchar *new_filename;
+ new_filename = g_strconcat(filename,
+ G_DIR_SEPARATOR_S, NULL);
+ g_free(filename);
+ filename = new_filename;
+ }
+
+ files = g_list_prepend(files, filename);
+ }
+
+ g_free(dirname);
+ g_dir_close(dir);
+
+ completion = g_completion_new(NULL);
+ g_completion_add_items(completion, files);
+
+ matching = g_completion_complete(completion, filename, &new_prefix);
+ if (new_prefix && strlen(new_prefix) > strlen(filename))
+ insert = g_strdup(new_prefix + strlen(filename));
+ g_free(new_prefix);
+
+ if (!insert && g_list_length(matching) > 1) {
+ matching = g_list_sort(matching, (GCompareFunc)g_strcmp0);
+
+ for (GList *file = g_list_first(matching);
+ file != NULL;
+ file = g_list_next(file)) {
+ GtkInfoPopupFileType type;
+
+ type = filename_is_dir((gchar *)file->data)
+ ? GTK_INFO_POPUP_DIRECTORY
+ : GTK_INFO_POPUP_FILE;
+ gtk_info_popup_add_filename(filename_popup,
+ type, (gchar *)file->data);
+ }
+
+ gtk_widget_show(GTK_WIDGET(filename_popup));
+ } else if (g_list_length(matching) == 1 &&
+ !filename_is_dir((gchar *)g_list_first(matching)->data)) {
+ gchar *new_insert;
+
+ new_insert = g_strconcat(insert ? : "",
+ (gchar []){completed, '\0'}, NULL);
+ g_free(insert);
+ insert = new_insert;
+ }
+
+ g_completion_free(completion);
+
+ for (GList *file = g_list_first(files); file; file = g_list_next(file))
+ g_free(file->data);
+ g_list_free(files);
+
+ return insert;
+}
+
+/*
+ * Auxiliary functions
+ */
+
+static const gchar *
+last_occurrence(const gchar *str, const gchar *chars)
+{
+ while (*chars)
+ str = strrchr(str, *chars++) ? : str;
+
+ return str;
+}
+
+static inline gboolean
+filename_is_dir(const gchar *filename)
+{
+ return g_str_has_suffix(filename, G_DIR_SEPARATOR_S);
+}