summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am17
-rw-r--r--src/Makefile.in303
-rw-r--r--src/ci_string.h41
-rw-r--r--src/gtkcompletionline.cc1187
-rw-r--r--src/gtkcompletionline.h90
-rw-r--r--src/history.cc167
-rw-r--r--src/history.h71
-rw-r--r--src/main.cc669
-rw-r--r--src/main.h13
-rw-r--r--src/prefs.cc177
-rw-r--r--src/prefs.h45
11 files changed, 2780 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..168be3c
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,17 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = \
+ @GTK_CFLAGS@ @STLPORT_CXXFLAGS@
+
+bin_PROGRAMS = gmrun
+
+gmrun_SOURCES = \
+ gtkcompletionline.cc gtkcompletionline.h \
+ history.cc history.h \
+ main.cc main.h \
+ prefs.cc prefs.h ci_string.h
+
+# gmrun_LDFLAGS = -s
+
+gmrun_LDADD = @GTK_LIBS@ @STLPORT_LDFLAGS@
+
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..7e46523
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,303 @@
+# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CXX = @CXX@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+PACKAGE_DATA_DIR = @PACKAGE_DATA_DIR@
+PKG_CONFIG = @PKG_CONFIG@
+PREFIX = @PREFIX@
+STLPORT_CXXFLAGS = @STLPORT_CXXFLAGS@
+STLPORT_INCDIR = @STLPORT_INCDIR@
+STLPORT_INCLUDES = @STLPORT_INCLUDES@
+STLPORT_LDFLAGS = @STLPORT_LDFLAGS@
+STLPORT_LIBDIR = @STLPORT_LIBDIR@
+VERSION = @VERSION@
+
+INCLUDES = @GTK_CFLAGS@ @STLPORT_CXXFLAGS@
+
+
+bin_PROGRAMS = gmrun
+
+gmrun_SOURCES = gtkcompletionline.cc gtkcompletionline.h history.cc history.h main.cc main.h prefs.cc prefs.h ci_string.h
+
+
+# gmrun_LDFLAGS = -s
+
+gmrun_LDADD = @GTK_LIBS@ @STLPORT_LDFLAGS@
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+PROGRAMS = $(bin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+gmrun_OBJECTS = gtkcompletionline.o history.o main.o prefs.o
+gmrun_DEPENDENCIES =
+gmrun_LDFLAGS =
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+SOURCES = $(gmrun_SOURCES)
+OBJECTS = $(gmrun_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps src/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ list='$(bin_PROGRAMS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ done
+
+.c.o:
+ $(COMPILE) -c $<
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+gmrun: $(gmrun_OBJECTS) $(gmrun_DEPENDENCIES)
+ @rm -f gmrun
+ $(CXXLINK) $(gmrun_LDFLAGS) $(gmrun_OBJECTS) $(gmrun_LDADD) $(LIBS)
+.cc.o:
+ $(CXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = src
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+gtkcompletionline.o: gtkcompletionline.cc gtkcompletionline.h history.h
+history.o: history.cc history.h prefs.h ci_string.h
+main.o: main.cc gtkcompletionline.h history.h prefs.h ci_string.h
+prefs.o: prefs.cc prefs.h ci_string.h ../config.h
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-binPROGRAMS
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-binPROGRAMS
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-binPROGRAMS clean-compile clean-tags clean-generic \
+ mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \
+ distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-binPROGRAMS \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/ci_string.h b/src/ci_string.h
new file mode 100644
index 0000000..aed3001
--- /dev/null
+++ b/src/ci_string.h
@@ -0,0 +1,41 @@
+// $Id: ci_string.h,v 1.2 2001/05/16 14:39:31 mishoo Exp $
+
+// This is a very nice class, probably because it's not coded by me ;=]~
+// Provide a case-insensitive std::string-like class.
+
+#ifndef __CI_STRING_H__
+#define __CI_STRING_H__
+
+#include <string>
+#include <ctype.h>
+
+struct ci_char_traits : public std::char_traits<char>
+{
+ static bool eq( char c1, char c2 ) {
+ return ::tolower(c1) == ::tolower(c2);
+ }
+
+ static bool ne( char c1, char c2 ) {
+ return ::tolower(c1) != ::tolower(c2);
+ }
+
+ static bool lt( char c1, char c2 ) {
+ return ::tolower(c1) < ::tolower(c2);
+ }
+
+ static int compare( const char* s1,
+ const char* s2,
+ size_t n ) {
+ return ::strncasecmp( s1, s2, n );
+ }
+
+ static const char*
+ find( const char* s, int n, char a ) {
+ while ( n-- > 0 && ::tolower(*s) != ::tolower(a) ) ++s;
+ return s;
+ }
+};
+
+typedef std::basic_string<char, ci_char_traits> ci_string;
+
+#endif // __CI_STRING_H__
diff --git a/src/gtkcompletionline.cc b/src/gtkcompletionline.cc
new file mode 100644
index 0000000..374deee
--- /dev/null
+++ b/src/gtkcompletionline.cc
@@ -0,0 +1,1187 @@
+/*****************************************************************************
+ * $Id: gtkcompletionline.cc,v 1.33 2003/11/16 10:55:07 andreas99 Exp $
+ * Copyright (C) 2000, Mishoo
+ * Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
+ *
+ * Distributed under the terms of the GNU General Public License. You are
+ * free to use/modify/distribute this program as long as you comply to the
+ * terms of the GNU General Public License, version 2 or above, at your
+ * option, and provided that this copyright notice remains intact.
+ *****************************************************************************/
+
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkclist.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtkmain.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <set>
+#include <sstream>
+#include <string>
+#include <vector>
+using namespace std;
+
+#include "gtkcompletionline.h"
+
+static int on_row_selected_handler = 0;
+static int on_key_press_handler = 0;
+
+/* GLOBALS */
+
+/* signals */
+enum {
+ UNIQUE,
+ NOTUNIQUE,
+ INCOMPLETE,
+ RUNWITHTERM,
+ SEARCH_MODE,
+ SEARCH_LETTER,
+ SEARCH_NOT_FOUND,
+ EXT_HANDLER,
+ CANCEL,
+ LAST_SIGNAL
+};
+
+#define GEN_COMPLETION_OK 1
+#define GEN_CANT_COMPLETE 2
+#define GEN_NOT_UNIQUE 3
+
+static guint gtk_completion_line_signals[LAST_SIGNAL];
+
+typedef set<string> StrSet;
+typedef vector<string> StrList;
+
+static StrSet path;
+static StrSet execs;
+static StrSet dirlist;
+static string prefix;
+static int g_show_dot_files;
+
+/* callbacks */
+static void gtk_completion_line_class_init(GtkCompletionLineClass *klass);
+static void gtk_completion_line_init(GtkCompletionLine *object);
+
+static gboolean
+on_key_press(GtkCompletionLine *cl, GdkEventKey *event, gpointer data);
+
+/* get_type */
+guint gtk_completion_line_get_type(void)
+{
+ static guint type = 0;
+ if (type == 0)
+ {
+ GtkTypeInfo type_info =
+ {
+ "GtkCompletionLine",
+ sizeof(GtkCompletionLine),
+ sizeof(GtkCompletionLineClass),
+ (GtkClassInitFunc)gtk_completion_line_class_init,
+ (GtkObjectInitFunc)gtk_completion_line_init,
+ /*(GtkArgSetFunc)*/NULL /* reserved */,
+ /*(GtkArgGetFunc)*/NULL /* reserved */
+ };
+ type = gtk_type_unique(gtk_entry_get_type(), &type_info);
+ }
+ return type;
+}
+
+/* class_init */
+static void
+gtk_completion_line_class_init(GtkCompletionLineClass *klass)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass*)klass;
+
+ gtk_completion_line_signals[UNIQUE] =
+ gtk_signal_new("unique",
+ GTK_RUN_FIRST, G_TYPE_FROM_CLASS(object_class),
+ GTK_SIGNAL_OFFSET(GtkCompletionLineClass,
+ unique),
+ gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
+
+ gtk_completion_line_signals[NOTUNIQUE] =
+ gtk_signal_new("notunique",
+ GTK_RUN_FIRST, G_TYPE_FROM_CLASS(object_class),
+ GTK_SIGNAL_OFFSET(GtkCompletionLineClass,
+ notunique),
+ gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
+
+ gtk_completion_line_signals[INCOMPLETE] =
+ gtk_signal_new("incomplete",
+ GTK_RUN_FIRST, G_TYPE_FROM_CLASS(object_class),
+ GTK_SIGNAL_OFFSET(GtkCompletionLineClass,
+ incomplete),
+ gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
+
+ gtk_completion_line_signals[RUNWITHTERM] =
+ gtk_signal_new("runwithterm",
+ GTK_RUN_FIRST, G_TYPE_FROM_CLASS(object_class),
+ GTK_SIGNAL_OFFSET(GtkCompletionLineClass,
+ runwithterm),
+ gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
+
+ gtk_completion_line_signals[SEARCH_MODE] =
+ gtk_signal_new("search_mode",
+ GTK_RUN_FIRST, G_TYPE_FROM_CLASS(object_class),
+ GTK_SIGNAL_OFFSET(GtkCompletionLineClass,
+ search_mode),
+ gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
+
+ gtk_completion_line_signals[SEARCH_NOT_FOUND] =
+ gtk_signal_new("search_not_found",
+ GTK_RUN_FIRST, G_TYPE_FROM_CLASS(object_class),
+ GTK_SIGNAL_OFFSET(GtkCompletionLineClass,
+ search_not_found),
+ gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
+
+ gtk_completion_line_signals[SEARCH_LETTER] =
+ gtk_signal_new("search_letter",
+ GTK_RUN_FIRST, G_TYPE_FROM_CLASS(object_class),
+ GTK_SIGNAL_OFFSET(GtkCompletionLineClass,
+ search_letter),
+ gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
+
+ gtk_completion_line_signals[EXT_HANDLER] =
+ gtk_signal_new("ext_handler",
+ GTK_RUN_FIRST, G_TYPE_FROM_CLASS(object_class),
+ GTK_SIGNAL_OFFSET(GtkCompletionLineClass,
+ ext_handler),
+ gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
+ GTK_TYPE_POINTER);
+
+ gtk_completion_line_signals[CANCEL] =
+ gtk_signal_new("cancel",
+ GTK_RUN_FIRST, G_TYPE_FROM_CLASS(object_class),
+ GTK_SIGNAL_OFFSET(GtkCompletionLineClass,
+ ext_handler),
+ gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
+ GTK_TYPE_POINTER);
+
+ //gtk_object_class_add_signals(object_class,
+ // gtk_completion_line_signals, LAST_SIGNAL);
+
+ klass->unique = NULL;
+ klass->notunique = NULL;
+ klass->incomplete = NULL;
+ klass->runwithterm = NULL;
+ klass->search_mode = NULL;
+ klass->search_letter = NULL;
+ klass->search_not_found = NULL;
+ klass->ext_handler = NULL;
+ klass->cancel = NULL;
+}
+
+/* init */
+static void
+gtk_completion_line_init(GtkCompletionLine *object)
+{
+ /* Add object initialization / creation stuff here */
+
+ object->where = NULL;
+ object->cmpl = NULL;
+ object->win_compl = NULL;
+ object->list_compl = NULL;
+ object->hist_search_mode = GCL_SEARCH_OFF;
+ object->hist_word = new string;
+ object->tabtimeout = 0;
+ object->show_dot_files = 0;
+
+ on_key_press_handler =
+ gtk_signal_connect(GTK_OBJECT(object), "key_press_event",
+ GTK_SIGNAL_FUNC(on_key_press), NULL);
+ gtk_signal_connect(GTK_OBJECT(object), "key_release_event",
+ GTK_SIGNAL_FUNC(on_key_press), NULL);
+
+ object->hist = new HistoryFile();
+
+ object->first_key = 1;
+}
+
+void gtk_completion_line_last_history_item(GtkCompletionLine* object) {
+ const char *last_item = object->hist->last_item();
+ if (last_item) {
+ object->hist->set_default("");
+ const char* txt = object->hist->prev();
+ gtk_entry_set_text(GTK_ENTRY(object),
+ g_locale_to_utf8 (txt, -1, NULL, NULL, NULL));
+ gtk_entry_select_region(GTK_ENTRY(object), 0, strlen(txt));
+ }
+}
+
+string quote_string(const string& str)
+{
+ string res;
+ const char* i = str.c_str();
+ while (*i) {
+ char c = *i++;
+ switch (c) {
+ case ' ':
+ res += '\\';
+ default:
+ res += c;
+ }
+ }
+ return res;
+}
+
+static void
+get_token(istream& is, string& s)
+{
+ s.clear();
+ bool escaped = false;
+ while (!is.eof()) {
+ char c = is.get();
+ if (is.eof())
+ break;
+ if (escaped) {
+ s += c;
+ escaped = false;
+ } else if (c == '\\') {
+ // s += c;
+ escaped = true;
+ } else if (::isspace(c)) {
+ while (::isspace(c) && !is.eof()) c = is.get();
+ if (!is.eof())
+ is.unget();
+ break;
+ } else {
+ s += c;
+ }
+ }
+}
+
+int
+get_words(GtkCompletionLine *object, vector<string>& words)
+{
+ string content(gtk_entry_get_text(GTK_ENTRY(object)));
+ int pos_in_text = gtk_editable_get_position(GTK_EDITABLE(object));
+ int pos = 0;
+ {
+ string::iterator i = content.begin() + pos_in_text;
+ if (i != content.end())
+ content.insert(i, ' ');
+ }
+ istringstream ss(content);
+
+ while (!ss.eof()) {
+ string s;
+ // ss >> s;
+ get_token(ss, s);
+ words.push_back(s);
+ if (ss.eof()) break;
+ if (ss.tellg() < pos_in_text && ss.tellg() >= 0)
+ ++pos;
+ }
+
+ return pos;
+}
+
+int
+set_words(GtkCompletionLine *object, const vector<string>& words, int pos = -1)
+{
+ ostringstream ss;
+ if (pos == -1)
+ pos = words.size() - 1;
+ int where = 0;
+
+ vector<string>::const_iterator
+ i = words.begin(),
+ i_end = words.end();
+
+ while (i != i_end) {
+ ss << quote_string(*i++);
+ if (i != i_end)
+ ss << ' ';
+ if (!pos && !where)
+ where = ss.tellp();
+ else
+ --pos;
+ }
+ ss << ends;
+
+ if (words.size() == 1) {
+ const string& s = words.back();
+ size_t pos = s.rfind('.');
+ if (pos != string::npos)
+ gtk_signal_emit_by_name(
+ GTK_OBJECT(object), "ext_handler", s.substr(pos + 1).c_str());
+ else
+ gtk_signal_emit_by_name(GTK_OBJECT(object), "ext_handler", NULL);
+ }
+
+ gtk_entry_set_text(GTK_ENTRY(object),
+ g_locale_to_utf8 (ss.str().c_str(), -1, NULL, NULL, NULL));
+ gtk_editable_set_position(GTK_EDITABLE(object), where);
+ return where;
+}
+
+static void
+generate_path()
+{
+ char *path_cstr = (char*)getenv("PATH");
+
+ istringstream path_ss(path_cstr);
+ string tmp;
+
+ path.clear();
+ while (!path_ss.eof()) {
+ tmp = "";
+ do {
+ char c;
+ c = path_ss.get();
+ if (c == ':' || path_ss.eof()) break;
+ else tmp += c;
+ } while (true);
+ if (tmp.length() != 0)
+ path.insert(tmp);
+ }
+}
+
+static int
+select_executables_only(const struct dirent* dent)
+{
+ int len = strlen(dent->d_name);
+ int lenp = prefix.length();
+
+ if (dent->d_name[0] == '.') {
+ if (!g_show_dot_files)
+ return 0;
+ if (dent->d_name[1] == '\0')
+ return 0;
+ if ((dent->d_name[1] == '.') && (dent->d_name[2] == '\0'))
+ return 0;
+ }
+ if (dent->d_name[len - 1] == '~')
+ return 0;
+ if (lenp == 0)
+ return 1;
+ if (lenp > len)
+ return 0;
+
+ if (strncmp(dent->d_name, prefix.c_str(), lenp) == 0)
+ return 1;
+
+ return 0;
+}
+
+int my_alphasort(const void* va, const void* vb) {
+ const struct dirent** a = (const struct dirent**)va;
+ const struct dirent** b = (const struct dirent**)vb;
+
+ const char* s1 = (*a)->d_name;
+ const char* s2 = (*b)->d_name;
+
+ int l1 = strlen(s1);
+ int l2 = strlen(s2);
+ int result = strcmp(s1, s2);
+
+ if (result == 0) return 0;
+
+ if (l1 < l2) {
+ int res2 = strncmp(s1, s2, l1);
+ if (res2 == 0) return -1;
+ } else {
+ int res2 = strncmp(s1, s2, l2);
+ if (res2 == 0) return 1;
+ }
+
+ return result;
+}
+
+static void
+generate_execs()
+{
+ execs.clear();
+
+ for (StrSet::iterator i = path.begin(); i != path.end(); i++) {
+ struct dirent **eps;
+ int n = scandir(i->c_str(), &eps, select_executables_only, my_alphasort);
+ if (n >= 0) {
+ for (int j = 0; j < n; j++) {
+ execs.insert(eps[j]->d_name);
+ free(eps[j]);
+ }
+ free(eps);
+ }
+ }
+}
+
+static int
+generate_completion_from_execs(GtkCompletionLine *object)
+{
+ g_list_foreach(object->cmpl, (GFunc)g_string_free, NULL);
+ g_list_free(object->cmpl);
+ object->cmpl = NULL;
+
+ for (StrSet::const_iterator i = execs.begin(); i != execs.end(); i++) {
+ GString *the_fucking_gstring = g_string_new(i->c_str());
+ object->cmpl = g_list_append(object->cmpl, the_fucking_gstring);
+ }
+
+ return 0;
+}
+
+static string
+get_common_part(const char *p1, const char *p2)
+{
+ string ret;
+
+ while (*p1 == *p2 && *p1 != '\0' && *p2 != '\0') {
+ ret += *p1;
+ p1++;
+ p2++;
+ }
+
+ return ret;
+}
+
+static int
+complete_common(GtkCompletionLine *object)
+{
+ GList *l;
+ GList *ls = object->cmpl;
+ vector<string> words;
+ int pos = get_words(object, words);
+ words[pos] = ((GString*)ls->data)->str;
+
+ ls = g_list_next(ls);
+ while (ls != NULL) {
+ words[pos] = get_common_part(words[pos].c_str(),
+ ((GString*)ls->data)->str);
+ ls = g_list_next(ls);
+ }
+
+ set_words(object, words, pos);
+
+ ls = object->cmpl;
+ l = ls;
+/*
+ if (words[pos] == ((GString*)(l->data))->str) {
+ ls = g_list_remove_link(ls, l);
+ ls = g_list_append(ls, l->data);
+ g_list_free_1(l);
+ object->cmpl = ls;
+ }
+*/
+ return 0;
+}
+
+static int
+generate_dirlist(const char *what)
+{
+ char *str = strdup(what);
+ char *p = str + 1;
+ char *filename = str;
+ string dest("/");
+ int n;
+
+ while (*p != '\0') {
+ dest += *p;
+ if (*p == '/') {
+ DIR* dir = opendir(dest.c_str());
+ if (!dir)
+ goto dirty;
+ closedir(dir);
+ filename = p;
+ }
+ ++p;
+ }
+
+ *filename = '\0';
+ filename++;
+ dest = str;
+ dest += '/';
+
+ dirlist.clear();
+ struct dirent **eps;
+ prefix = filename;
+ n = scandir(dest.c_str(), &eps, select_executables_only, my_alphasort);
+ if (n >= 0) {
+ for (int j = 0; j < n; j++) {
+ {
+ string foo(dest);
+ foo += eps[j]->d_name;
+ struct stat filestatus;
+ stat(foo.c_str(), &filestatus);
+ if (S_ISDIR(filestatus.st_mode)) foo += '/';
+ dirlist.insert(foo);
+ }
+ free(eps[j]);
+ }
+ free(eps);
+ }
+
+ free(str);
+ return GEN_COMPLETION_OK;
+
+ dirty:
+ free(str);
+ return GEN_CANT_COMPLETE;
+}
+
+static int
+generate_completion_from_dirlist(GtkCompletionLine *object)
+{
+ g_list_foreach(object->cmpl, (GFunc)g_string_free, NULL);
+ g_list_free(object->cmpl);
+ object->cmpl = NULL;
+
+ for (StrSet::const_iterator i = dirlist.begin(); i != dirlist.end(); i++) {
+ GString *the_fucking_gstring = g_string_new(i->c_str());
+ object->cmpl = g_list_append(object->cmpl, the_fucking_gstring);
+ }
+
+ return 0;
+}
+
+static int
+parse_tilda(GtkCompletionLine *object)
+{
+ string text = gtk_entry_get_text(GTK_ENTRY(object));
+ gint where = (gint)text.find("~");
+ if (where != string::npos) {
+ if ((where > 0) && (text[where - 1] != ' '))
+ return 0;
+ if (where < text.size() - 1 && text[where + 1] != '/') {
+ // FIXME: Parse another user's home
+ } else {
+ string home = g_get_home_dir();
+ size_t i = home.length() - 1;
+ while ((i >= 0) && (home[i] == '/'))
+ home.erase(i--);
+ gtk_editable_insert_text(GTK_EDITABLE(object), home.c_str(), home.length(), &where);
+ gtk_editable_delete_text(GTK_EDITABLE(object), where, where + 1);
+ }
+ }
+
+ return 0;
+}
+
+static void
+complete_from_list(GtkCompletionLine *object)
+{
+ parse_tilda(object);
+ vector<string> words;
+ int pos = get_words(object, words);
+
+ prefix = words[pos];
+
+ if (object->win_compl != NULL) {
+ object->where = (GList*)gtk_clist_get_row_data(
+ GTK_CLIST(object->list_compl), object->list_compl_items_where);
+ words[pos] = ((GString*)object->where->data)->str;
+ int current_pos = set_words(object, words, pos);
+ gtk_entry_select_region(GTK_ENTRY(object),
+ object->pos_in_text, current_pos);
+ int &item = object->list_compl_items_where;
+ gtk_clist_select_row(GTK_CLIST(object->list_compl), item, 0);
+ gtk_clist_moveto(GTK_CLIST(object->list_compl), item, 0, 0.5, 0.0);
+ } else {
+ words[pos] = ((GString*)object->where->data)->str;
+ object->pos_in_text = gtk_editable_get_position(GTK_EDITABLE(object));
+ int current_pos = set_words(object, words, pos);
+ gtk_entry_select_region(GTK_ENTRY(object),
+ object->pos_in_text, current_pos);
+ object->where = g_list_next(object->where);
+ }
+}
+
+static void
+on_row_selected(GtkWidget *ls, gint row, gint col, GdkEvent *ev, gpointer data)
+{
+ GtkCompletionLine *cl = GTK_COMPLETION_LINE(data);
+
+ cl->list_compl_items_where = row;
+ gtk_signal_handler_block(GTK_OBJECT(cl->list_compl),
+ on_row_selected_handler);
+ complete_from_list(cl);
+ gtk_signal_handler_unblock(GTK_OBJECT(cl->list_compl),
+ on_row_selected_handler);
+}
+
+/*
+
+static void
+select_appropiate(GtkCompletionLine *object)
+{
+ for (int i = 0; i < object->list_compl_nr_rows; ++i) {
+ char *text;
+ gtk_clist_get_text(GTK_CLIST(object->list_compl), i, 0, &text);
+ if (strncmp(prefix.c_str(), text, prefix.length())) {
+ gtk_signal_handler_block(GTK_OBJECT(object->list_compl),
+ on_row_selected_handler);
+ gtk_clist_select_row(GTK_CLIST(object->list_compl), i, 0);
+ object->list_compl_items_where = i;
+ gtk_signal_handler_unblock(GTK_OBJECT(object->list_compl),
+ on_row_selected_handler);
+ break;
+ }
+ }
+}
+
+static void
+get_prefix(GtkCompletionLine *object)
+{
+ parse_tilda(object);
+ vector<string> words;
+ int pos = get_words(object, words);
+ prefix = words[pos];
+}
+
+*/
+
+static int
+complete_line(GtkCompletionLine *object)
+{
+ parse_tilda(object);
+ vector<string> words;
+ int pos = get_words(object, words);
+ prefix = words[pos];
+
+ g_show_dot_files = object->show_dot_files;
+ if (prefix[0] != '/') {
+ if (object->where == NULL) {
+ generate_path();
+ generate_execs();
+ generate_completion_from_execs(object);
+ object->where = NULL;
+ }
+ } else if (object->where == NULL) {
+ generate_dirlist(prefix.c_str());
+ generate_completion_from_dirlist(object);
+ object->where = NULL;
+ }
+
+ if (object->cmpl != NULL) {
+ complete_common(object);
+ object->where = object->cmpl;
+ }
+
+ // FUCK C! C++ Rules!
+ if (object->where != NULL) {
+ if (object->win_compl != NULL) {
+ int &item = object->list_compl_items_where;
+ ++item;
+ if (item >= object->list_compl_nr_rows)
+ item = object->list_compl_nr_rows - 1;
+ }
+ complete_from_list(object);
+ } else if (object->cmpl != NULL) {
+ complete_common(object);
+ object->where = object->cmpl;
+ }
+
+ GList *ls = object->cmpl;
+
+ if (g_list_length(ls) == 1) {
+ gtk_signal_emit_by_name(GTK_OBJECT(object), "unique");
+ return GEN_COMPLETION_OK;
+ } else if (g_list_length(ls) == 0 || ls == NULL) {
+ gtk_signal_emit_by_name(GTK_OBJECT(object), "incomplete");
+ return GEN_CANT_COMPLETE;
+ } else if (g_list_length(ls) > 1) {
+ gtk_signal_emit_by_name(GTK_OBJECT(object), "notunique");
+
+ vector<string> words;
+ int pos = get_words(object, words);
+
+ if (words[pos] == ((GString*)ls->data)->str) {
+
+ if (object->win_compl == NULL) {
+ object->win_compl = gtk_window_new(GTK_WINDOW_POPUP);
+ gtk_widget_set_name(object->win_compl, "Msh_Run_Window");
+
+ /*gtk_window_set_position(GTK_WINDOW(object->win_compl),
+ GTK_WIN_POS_MOUSE);*/
+
+ gtk_window_set_policy(GTK_WINDOW(object->win_compl),
+ FALSE, FALSE, TRUE);
+
+ object->list_compl = gtk_clist_new(1);
+
+ on_row_selected_handler =
+ gtk_signal_connect(GTK_OBJECT(object->list_compl), "select_row",
+ GTK_SIGNAL_FUNC(on_row_selected), object);
+
+ gtk_signal_handler_block(GTK_OBJECT(object->list_compl),
+ on_row_selected_handler);
+
+ GList *p = ls;
+ object->list_compl_nr_rows = 0;
+ while (p) {
+ char *tmp[2];
+ tmp[0] = ((GString*)p->data)->str;
+ tmp[1] = NULL;
+ int row = gtk_clist_append(GTK_CLIST(object->list_compl), tmp);
+ gtk_clist_set_row_data(GTK_CLIST(object->list_compl), row, p);
+ object->list_compl_nr_rows++;
+ p = g_list_next(p);
+ }
+
+ GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_OUT);
+ gtk_widget_show(scroll);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scroll),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+
+ gtk_container_set_border_width(GTK_CONTAINER(object->list_compl), 2);
+ gtk_container_add(GTK_CONTAINER (scroll), object->list_compl);
+
+ object->list_compl_items_where = 0;
+
+ gtk_widget_show(object->list_compl);
+ int w = gtk_clist_optimal_column_width(GTK_CLIST(object->list_compl), 0);
+ gtk_widget_set_usize(scroll, w + 40, 150);
+
+ gtk_container_add(GTK_CONTAINER(object->win_compl), scroll);
+
+ GdkWindow *top = gtk_widget_get_parent_window(GTK_WIDGET(object));
+ int x, y;
+ gdk_window_get_position(top, &x, &y);
+ x += GTK_WIDGET(object)->allocation.x;
+ y += GTK_WIDGET(object)->allocation.y +
+ GTK_WIDGET(object)->allocation.height;
+
+ // gtk_widget_popup(object->win_compl, x, y);
+ gtk_window_move(GTK_WINDOW(object->win_compl), x, y);
+ gtk_widget_show(object->win_compl);
+
+ gtk_clist_select_row(GTK_CLIST(object->list_compl),
+ object->list_compl_items_where, 0);
+
+ gtk_signal_handler_unblock(GTK_OBJECT(object->list_compl),
+ on_row_selected_handler);
+ }
+
+ return GEN_COMPLETION_OK;
+ }
+ return GEN_NOT_UNIQUE;
+ }
+
+ return GEN_COMPLETION_OK;
+}
+
+GtkWidget *
+gtk_completion_line_new()
+{
+ return GTK_WIDGET(gtk_type_new(gtk_completion_line_get_type()));
+}
+
+static void
+up_history(GtkCompletionLine* cl)
+{
+ cl->hist->set_default(gtk_entry_get_text(GTK_ENTRY(cl)));
+ gtk_entry_set_text(GTK_ENTRY(cl),
+ g_locale_to_utf8 (cl->hist->prev(), -1, NULL, NULL, NULL));
+}
+
+static void
+down_history(GtkCompletionLine* cl)
+{
+ cl->hist->set_default(gtk_entry_get_text(GTK_ENTRY(cl)));
+ gtk_entry_set_text(GTK_ENTRY(cl),
+ g_locale_to_utf8 (cl->hist->next(), -1, NULL, NULL, NULL));
+}
+
+static int
+search_back_history(GtkCompletionLine* cl, bool avance, bool begin)
+{
+ if (!cl->hist_word->empty()) {
+ const char * histext;
+ if (avance) {
+ histext = cl->hist->prev_to_first();
+ if (histext == NULL) {
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_not_found");
+ return 0;
+ }
+ } else {
+ histext = gtk_entry_get_text(GTK_ENTRY(cl));
+ }
+ while (true) {
+ string s = histext;
+ string::size_type i;
+ i = s.find(*cl->hist_word);
+ if (i != string::npos && !(begin && i != 0)) {
+ const char *tmp = gtk_entry_get_text(GTK_ENTRY(cl));
+ if (!(avance && strcmp(tmp, histext) == 0)) {
+ gtk_entry_set_text(GTK_ENTRY(cl),
+ g_locale_to_utf8 (histext, -1, NULL, NULL, NULL));
+ gtk_entry_select_region(GTK_ENTRY(cl),
+ i, i + cl->hist_word->length());
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_letter");
+ return 1;
+ }
+ }
+ histext = cl->hist->prev_to_first();
+ if (histext == NULL) {
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_not_found");
+ break;
+ }
+ }
+ } else {
+ gtk_entry_select_region(GTK_ENTRY(cl), 0, 0);
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_letter");
+ }
+
+ return 0;
+}
+
+static int
+search_forward_history(GtkCompletionLine* cl, bool avance, bool begin)
+{
+ if (!cl->hist_word->empty()) {
+ const char * histext;
+ if (avance) {
+ histext = cl->hist->next_to_last();
+ if (histext == NULL) {
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_not_found");
+ return 0;
+ }
+ } else {
+ histext = gtk_entry_get_text(GTK_ENTRY(cl));
+ }
+ while (true) {
+ string s = histext;
+ string::size_type i;
+ i = s.find(*cl->hist_word);
+ if (i != string::npos && !(begin && i != 0)) {
+ const char *tmp = gtk_entry_get_text(GTK_ENTRY(cl));
+ if (!(avance && strcmp(tmp, histext) == 0)) {
+ gtk_entry_set_text(GTK_ENTRY(cl),
+ g_locale_to_utf8 (histext, -1, NULL, NULL, NULL));
+ gtk_entry_select_region(GTK_ENTRY(cl),
+ i, i + cl->hist_word->length());
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_letter");
+ return 1;
+ }
+ }
+ histext = cl->hist->next_to_last();
+ if (histext == NULL) {
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_not_found");
+ break;
+ }
+ }
+ } else {
+ gtk_entry_select_region(GTK_ENTRY(cl), 0, 0);
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_letter");
+ }
+
+ return 0;
+}
+
+static int
+search_history(GtkCompletionLine* cl, bool avance, bool begin)
+{
+ switch (cl->hist_search_mode) {
+ case GCL_SEARCH_REW:
+ case GCL_SEARCH_BEG:
+ return search_back_history(cl, avance, begin);
+
+ case GCL_SEARCH_FWD:
+ return search_forward_history(cl, avance, begin);
+
+ default:
+ return -1;
+ }
+}
+
+/*
+static int
+inverse_search_history(GtkCompletionLine* cl, bool avance, bool begin)
+{
+ switch (cl->hist_search_mode) {
+ case GCL_SEARCH_FWD:
+ return search_back_history(cl, avance, begin);
+
+ case GCL_SEARCH_REW:
+ case GCL_SEARCH_BEG:
+ return search_forward_history(cl, avance, begin);
+
+ default:
+ return -1;
+ }
+}
+*/
+
+static void
+search_off(GtkCompletionLine* cl)
+{
+ int pos = gtk_editable_get_position(GTK_EDITABLE(cl));
+ gtk_entry_select_region(GTK_ENTRY(cl), pos, pos);
+ cl->hist_search_mode = GCL_SEARCH_OFF;
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_mode");
+ cl->hist->reset_position();
+}
+
+#define STOP_PRESS \
+ (gtk_signal_emit_stop_by_name(GTK_OBJECT(cl), "key_press_event"))
+#define MODE_BEG \
+ (cl->hist_search_mode == GCL_SEARCH_BEG)
+#define MODE_REW \
+ (cl->hist_search_mode == GCL_SEARCH_REW)
+#define MODE_FWD \
+ (cl->hist_search_mode == GCL_SEARCH_FWD)
+#define MODE_SRC \
+ (cl->hist_search_mode != GCL_SEARCH_OFF)
+
+static gint tab_pressed(GtkCompletionLine* cl)
+{
+ if (MODE_SRC)
+ search_off(cl);
+ complete_line(cl);
+ return FALSE;
+}
+
+static void
+clear_selection(GtkCompletionLine* cl)
+{
+ int pos = gtk_editable_get_position(GTK_EDITABLE(cl));
+ gtk_editable_select_region(GTK_EDITABLE(cl), pos, pos);
+}
+
+static gboolean
+on_key_press(GtkCompletionLine *cl, GdkEventKey *event, gpointer data)
+{
+ static gint tt_id = -1;
+
+ switch (event->type) {
+
+ case GDK_KEY_PRESS:
+
+
+ switch (event->keyval) {
+
+ case GDK_Control_R:
+ case GDK_Control_L:
+ case GDK_Shift_R:
+ case GDK_Shift_L:
+ case GDK_Alt_R:
+ case GDK_Alt_L:
+ break;
+
+ case GDK_Tab:
+ if (tt_id != -1) {
+ gtk_timeout_remove(tt_id);
+ tt_id = -1;
+ }
+ tab_pressed(cl);
+ STOP_PRESS;
+ return TRUE;
+
+ case GDK_Up:
+ if (cl->win_compl != NULL) {
+ int &item = cl->list_compl_items_where;
+ item--;
+ if (item < 0) {
+ item = 0;
+ } else {
+ complete_from_list(cl);
+ }
+ } else {
+ up_history(cl);
+ }
+ if (MODE_SRC) {
+ search_off(cl);
+ }
+ STOP_PRESS;
+ return TRUE;
+
+ case GDK_space:
+ {
+ cl->first_key = 0;
+ bool search = MODE_SRC;
+ if (search)
+ search_off(cl);
+ if (cl->win_compl != NULL) {
+ gtk_widget_destroy(cl->win_compl);
+ cl->win_compl = NULL;
+ if (!search) {
+ int pos = gtk_editable_get_position(GTK_EDITABLE(cl));
+ gtk_entry_select_region(GTK_ENTRY(cl), pos, pos);
+ }
+ }
+ }
+ return FALSE;
+
+ case GDK_Down:
+ if (cl->win_compl != NULL) {
+ int &item = cl->list_compl_items_where;
+ item++;
+ if (item >= cl->list_compl_nr_rows) {
+ item = cl->list_compl_nr_rows - 1;
+ } else {
+ complete_from_list(cl);
+ }
+ } else {
+ down_history(cl);
+ }
+ if (MODE_SRC) {
+ search_off(cl);
+ }
+ STOP_PRESS;
+ return TRUE;
+
+ case GDK_Return:
+ if (cl->win_compl != NULL) {
+ gtk_widget_destroy(cl->win_compl);
+ cl->win_compl = NULL;
+ }
+ if (event->state & GDK_CONTROL_MASK) {
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "runwithterm");
+ } else {
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "activate");
+ }
+ STOP_PRESS;
+ return TRUE;
+
+ case GDK_exclam:
+ if (!MODE_BEG) {
+ if (!MODE_SRC)
+ gtk_editable_delete_selection(GTK_EDITABLE(cl));
+ const char *tmp = gtk_entry_get_text(GTK_ENTRY(cl));
+ if (!(*tmp == '\0' || cl->first_key))
+ goto ordinary;
+ cl->hist_search_mode = GCL_SEARCH_BEG;
+ cl->hist_word->clear();
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_mode");
+ STOP_PRESS;
+ return true;
+ } else goto ordinary;
+
+ case GDK_R:
+ case GDK_r:
+ if (event->state & GDK_CONTROL_MASK) {
+ if (MODE_SRC) {
+ search_back_history(cl, true, MODE_BEG);
+ } else {
+ cl->hist_search_mode = GCL_SEARCH_REW;
+ cl->hist_word->clear();
+ cl->hist->reset_position();
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_mode");
+ }
+ STOP_PRESS;
+ return TRUE;
+ } else goto ordinary;
+
+ case GDK_S:
+ case GDK_s:
+ if (event->state & GDK_CONTROL_MASK) {
+ if (MODE_SRC) {
+ search_forward_history(cl, true, MODE_BEG);
+ } else {
+ cl->hist_search_mode = GCL_SEARCH_FWD;
+ cl->hist_word->clear();
+ cl->hist->reset_position();
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_mode");
+ }
+ STOP_PRESS;
+ return TRUE;
+ } else goto ordinary;
+
+ case GDK_BackSpace:
+ if (MODE_SRC) {
+ if (!cl->hist_word->empty()) {
+ cl->hist_word->erase(cl->hist_word->length() - 1);
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "search_letter");
+ }
+ STOP_PRESS;
+ return TRUE;
+ }
+ return FALSE;
+
+ case GDK_Home:
+ case GDK_End:
+ clear_selection(cl);
+ goto ordinary;
+
+ case GDK_Escape:
+ if (MODE_SRC) {
+ search_off(cl);
+ } else if (cl->win_compl != NULL) {
+ gtk_widget_destroy(cl->win_compl);
+ cl->win_compl = NULL;
+ } else {
+ // user cancelled
+ gtk_signal_emit_by_name(GTK_OBJECT(cl), "cancel");
+ }
+ STOP_PRESS;
+ return TRUE;
+
+ case GDK_G:
+ case GDK_g:
+ if (event->state & GDK_CONTROL_MASK) {
+ search_off(cl);
+ if (MODE_SRC)
+ STOP_PRESS;
+ return TRUE;
+ } else goto ordinary;
+
+ case GDK_E:
+ case GDK_e:
+ if (event->state & GDK_CONTROL_MASK) {
+ search_off(cl);
+ if (MODE_SRC)
+ clear_selection(cl);
+ }
+ goto ordinary;
+
+ ordinary:
+ default:
+ cl->first_key = 0;
+ if (cl->win_compl != NULL) {
+ gtk_widget_destroy(cl->win_compl);
+ cl->win_compl = NULL;
+ }
+ cl->where = NULL;
+ if (MODE_SRC) {
+ if (event->length > 0) {
+ *cl->hist_word += event->string;
+ if (search_history(cl, false, MODE_BEG) <= 0)
+ cl->hist_word->erase(cl->hist_word->length() - 1);
+ STOP_PRESS;
+ return TRUE;
+ } else
+ search_off(cl);
+ }
+ if (cl->tabtimeout != 0) {
+ if (tt_id != -1) {
+ gtk_timeout_remove(tt_id);
+ tt_id = -1;
+ }
+ if (::isprint(*event->string))
+ tt_id = gtk_timeout_add(cl->tabtimeout,
+ GtkFunction(tab_pressed), cl);
+ }
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+#undef STOP_PRESS
+#undef MODE_BEG
+#undef MODE_REW
+#undef MODE_FWD
+#undef MODE_SRC
+
+// Local Variables: ***
+// mode: c++ ***
+// c-basic-offset: 2 ***
+// End: ***
diff --git a/src/gtkcompletionline.h b/src/gtkcompletionline.h
new file mode 100644
index 0000000..5e14cd7
--- /dev/null
+++ b/src/gtkcompletionline.h
@@ -0,0 +1,90 @@
+/*****************************************************************************
+ * $Id: gtkcompletionline.h,v 1.12 2003/11/16 10:43:32 andreas99 Exp $
+ * Copyright (C) 2000, Mishoo
+ * Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
+ *
+ * Distributed under the terms of the GNU General Public License. You are
+ * free to use/modify/distribute this program as long as you comply to the
+ * terms of the GNU General Public License, version 2 or above, at your
+ * option, and provided that this copyright notice remains intact.
+ *****************************************************************************/
+
+
+#ifndef __GTKCOMPLETIONLINE_H__
+#define __GTKCOMPLETIONLINE_H__
+
+#include <gtk/gtkentry.h>
+
+#include <string>
+
+#include "history.h"
+
+extern "C++" {
+
+#define GTK_COMPLETION_LINE(obj) \
+ GTK_CHECK_CAST(obj, gtk_completion_line_get_type(), GtkCompletionLine)
+#define GTK_COMPLETION_LINE_CLASS(klass) \
+ GTK_CHECK_CLASS_CAST(klass, gtk_completion_line_get_type(), GtkCompletionLineClass)
+#define IS_GTK_COMPLETION_LINE(obj) \
+ GTK_CHECK_TYPE(obj, gtk_completion_line_get_type())
+
+ typedef struct _GtkCompletionLine GtkCompletionLine;
+ typedef struct _GtkCompletionLineClass GtkCompletionLineClass;
+
+ enum GCL_SEARCH_MODE
+ {
+ GCL_SEARCH_OFF = 0,
+ GCL_SEARCH_REW = 1,
+ GCL_SEARCH_FWD = 2,
+ GCL_SEARCH_BEG = 3
+ };
+
+ struct _GtkCompletionLine
+ {
+ GtkEntry parent;
+ GtkWidget *win_compl;
+ GtkWidget *list_compl;
+ int list_compl_items_where;
+ int list_compl_nr_rows;
+ int pos_in_text;
+
+ GList *cmpl;
+ GList *where;
+
+ HistoryFile *hist;
+ GCL_SEARCH_MODE hist_search_mode;
+ std::string *hist_word;
+
+ int first_key;
+ int tabtimeout;
+ int show_dot_files;
+ };
+
+ struct _GtkCompletionLineClass
+ {
+ GtkEntryClass parent_class;
+ /* add your CLASS members here */
+
+ void (* unique)(GtkCompletionLine *cl);
+ void (* notunique)(GtkCompletionLine *cl);
+ void (* incomplete)(GtkCompletionLine *cl);
+ void (* runwithterm)(GtkCompletionLine *cl);
+ void (* search_mode)(GtkCompletionLine *cl);
+ void (* search_letter)(GtkCompletionLine *cl);
+ void (* search_not_found)(GtkCompletionLine *cl);
+ void (* ext_handler)(GtkCompletionLine *cl);
+ void (* cancel)(GtkCompletionLine *cl);
+ };
+
+ guint gtk_completion_line_get_type(void);
+ GtkWidget *gtk_completion_line_new();
+
+ void gtk_completion_line_last_history_item(GtkCompletionLine*);
+}
+
+#endif /* __GTKCOMPLETIONLINE_H__ */
+
+// Local Variables: ***
+// mode: c++ ***
+// c-basic-offset: 2 ***
+// End: ***
diff --git a/src/history.cc b/src/history.cc
new file mode 100644
index 0000000..61afba0
--- /dev/null
+++ b/src/history.cc
@@ -0,0 +1,167 @@
+/*****************************************************************************
+ * $Id: history.cc,v 1.10 2002/08/17 13:19:31 mishoo Exp $
+ * Copyright (C) 2000, Mishoo
+ * Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
+ *
+ * Distributed under the terms of the GNU General Public License. You are
+ * free to use/modify/distribute this program as long as you comply to the
+ * terms of the GNU General Public License, version 2 or above, at your
+ * option, and provided that this copyright notice remains intact.
+ *****************************************************************************/
+
+
+#include <glib.h>
+#include <cstdlib>
+#include <cstdio>
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+using namespace std;
+
+#include "history.h"
+#include "prefs.h"
+
+HistoryFile::HistoryFile()
+{
+ m_file_entries = 0;
+ m_filename = g_get_home_dir();
+ m_filename += "/.gmrun_history";
+ m_current = 0;
+ m_default_set = false;
+ read_the_file();
+}
+
+HistoryFile::~HistoryFile()
+{}
+
+void
+HistoryFile::read_the_file()
+{
+ const char *filename = m_filename.c_str();
+ ifstream f(filename);
+ if (!f) return;
+
+ while (!f.eof()) {
+ char line_text[256];
+ string line_str;
+
+ f.getline(line_text, sizeof(line_text));
+ if (*line_text) {
+ line_str = line_text;
+ history.push_back(line_str);
+ }
+ }
+
+ m_file_entries = history.size();
+ m_current = m_file_entries;
+}
+
+void
+HistoryFile::sync_the_file()
+{
+ const char *filename = m_filename.c_str();
+
+ int HIST_MAX_SIZE;
+
+ if (!configuration.get_int("History", HIST_MAX_SIZE))
+ HIST_MAX_SIZE = 20;
+
+ ofstream f(filename, ios::out);
+
+ int start = 0;
+ if (history.size() > (size_t)HIST_MAX_SIZE)
+ start = history.size() - HIST_MAX_SIZE;
+
+ for (size_t i = start; i < history.size(); i++)
+ if (history[i].length() != 0)
+ f << history[i] << endl;
+
+ f.flush();
+}
+
+void
+HistoryFile::append(const char *entry)
+{
+ std::string ent = std::string(entry);
+ if (!history.empty()) {
+ StrArray::reverse_iterator i;
+#ifdef DEBUG
+ for_each(history.begin(), history.end(), DumpString(cerr));
+#endif
+ i = find(history.rbegin(), history.rend(), ent);
+ if (i != history.rend()) {
+#ifdef DEBUG
+ cerr << "erasing "<< ent << endl;
+#endif
+ history.erase(remove(history.begin(), history.end(), ent));
+ }
+ }
+ history.push_back(ent);
+}
+
+void
+HistoryFile::set_default(const char *defstr)
+{
+ if (!m_default_set) {
+ m_default = defstr;
+ m_default_set = true;
+ }
+}
+
+const char *
+HistoryFile::operator [] (size_t index)
+{
+ if (index < 0 || index >= history.size()) {
+ return m_default.c_str();
+ }
+
+ return history[index].c_str();
+}
+
+const char *
+HistoryFile::prev()
+{
+ const char *ret = (*this)[--m_current];
+ if (m_current < 0) m_current = history.size();
+ return ret;
+}
+
+const char *
+HistoryFile::next()
+{
+ const char *ret = (*this)[++m_current];
+ if (m_current >= history.size()) m_current = -1;
+ return ret;
+}
+
+const char *
+HistoryFile::prev_to_first()
+{
+ if (m_current > 0) {
+ return (*this)[--m_current];
+ } else {
+ return NULL;
+ }
+}
+
+const char *
+HistoryFile::next_to_last()
+{
+ if (m_current < history.size()) {
+ return (*this)[++m_current];
+ } else {
+ return NULL;
+ }
+}
+
+void
+HistoryFile::clear_default()
+{
+ m_default_set = false;
+}
+
+void
+HistoryFile::reset_position()
+{
+ m_current = m_file_entries;
+}
diff --git a/src/history.h b/src/history.h
new file mode 100644
index 0000000..9f1d4b9
--- /dev/null
+++ b/src/history.h
@@ -0,0 +1,71 @@
+/*****************************************************************************
+ * $Id: history.h,v 1.11 2002/08/17 13:19:31 mishoo Exp $
+ * Copyright (C) 2000, Mishoo
+ * Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
+ *
+ * Distributed under the terms of the GNU General Public License. You are
+ * free to use/modify/distribute this program as long as you comply to the
+ * terms of the GNU General Public License, version 2 or above, at your
+ * option, and provided that this copyright notice remains intact.
+ *****************************************************************************/
+
+
+#ifndef __HISTORY_H__
+#define __HISTORY_H__
+
+#include <vector>
+#include <string>
+using namespace std;
+
+class HistoryFile
+{
+ protected:
+ int m_file_entries;
+ string m_filename;
+ string m_default;
+ bool m_default_set;
+ int m_current;
+
+ typedef vector<string> StrArray;
+ StrArray history;
+
+ public:
+ HistoryFile();
+ ~HistoryFile();
+
+ void append(const char *entry);
+ void set_default(const char *defstr);
+ void clear_default();
+
+ void reset_position();
+
+ const char * operator [] (size_t index);
+
+ const char * prev();
+ const char * next();
+
+ const char * prev_to_first();
+ const char * next_to_last();
+
+ void sync_the_file();
+
+ inline const char* last_item() {
+ return history.empty() ? 0 : history.back().c_str();
+ }
+
+ inline const char* first_item() {
+ return history.empty() ? 0 : history.front().c_str();
+ }
+
+ protected:
+ void read_the_file();
+ private:
+ struct DumpString {
+ DumpString(std::ostream& o) : _out(o) {}
+ void operator()(std::string& str) { _out << str << endl; }
+ private:
+ std::ostream& _out;
+ };
+};
+
+#endif // __HISTORY_H__
diff --git a/src/main.cc b/src/main.cc
new file mode 100644
index 0000000..dc4b034
--- /dev/null
+++ b/src/main.cc
@@ -0,0 +1,669 @@
+/*****************************************************************************
+ * $Id: main.cc,v 1.26 2003/11/16 10:55:07 andreas99 Exp $
+ * Copyright (C) 2000, Mishoo
+ * Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
+ *
+ * Distributed under the terms of the GNU General Public License. You are
+ * free to use/modify/distribute this program as long as you comply to the
+ * terms of the GNU General Public License, version 2 or above, at your
+ * option, and provided that this copyright notice remains intact.
+ *****************************************************************************/
+
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <algorithm>
+#include <iterator>
+#include <popt.h>
+
+using namespace std;
+
+#ifdef MTRACE
+#include <mcheck.h>
+#endif
+
+#include <unistd.h>
+#include <errno.h>
+
+#include "gtkcompletionline.h"
+#include "prefs.h"
+
+// defined in gtkcompletionline.cc
+int get_words(GtkCompletionLine *object, vector<string>& words);
+string quote_string(const string& str);
+
+struct gigi
+{
+ GtkWidget *w1;
+ GtkWidget *w2;
+};
+
+/// BEGIN: TIMEOUT MANAGEMENT
+
+static gint search_off_timeout(struct gigi *g);
+
+static guint g_search_off_timeout_id = 0;
+
+static void remove_search_off_timeout()
+{
+ if (g_search_off_timeout_id) {
+ gtk_timeout_remove(g_search_off_timeout_id);
+ g_search_off_timeout_id = 0;
+ }
+}
+
+static void add_search_off_timeout(guint32 timeout, struct gigi *g, GtkFunction func = 0)
+{
+ remove_search_off_timeout();
+ if (!func)
+ func = GtkFunction(search_off_timeout);
+ g_search_off_timeout_id = gtk_timeout_add(timeout, func, g);
+}
+
+/// END: TIMEOUT MANAGEMENT
+
+GtkStyle* style_normal(GtkWidget *w)
+{
+ static GtkStyle *style;
+
+ if (!style) {
+ style = gtk_style_copy(gtk_widget_get_style(w));
+ style->fg[GTK_STATE_NORMAL] = (GdkColor){0, 0x0000, 0x0000, 0x0000};
+ gtk_style_ref(style);
+ }
+ return style;
+}
+
+GtkStyle* style_notfound(GtkWidget *w)
+{
+ static GtkStyle *style;
+
+ if (!style) {
+ style = gtk_style_copy(gtk_widget_get_style(w));
+ style->fg[GTK_STATE_NORMAL] = (GdkColor){0, 0xFFFF, 0x0000, 0x0000};
+ gtk_style_ref(style);
+ }
+ return style;
+}
+
+GtkStyle* style_notunique(GtkWidget *w)
+{
+ static GtkStyle *style;
+
+ if (!style) {
+ style = gtk_style_copy(gtk_widget_get_style(w));
+ style->fg[GTK_STATE_NORMAL] = (GdkColor){0, 0x0000, 0x0000, 0xFFFF};
+ gtk_style_ref(style);
+ }
+ return style;
+}
+
+GtkStyle* style_unique(GtkWidget *w)
+{
+ static GtkStyle *style;
+
+ if (!style) {
+ style = gtk_style_copy(gtk_widget_get_style(w));
+ style->fg[GTK_STATE_NORMAL] = (GdkColor){0, 0x0000, 0xFFFF, 0x0000};
+ gtk_style_ref(style);
+ }
+ return style;
+}
+
+static void
+run_with_system(const std::string& command, struct gigi* g)
+{
+ string cmd(command);
+ cmd += '&';
+ int ret = system(cmd.c_str());
+#ifdef DEBUG
+ cerr << "System exit code: " << ret << endl;
+#endif
+ if (ret != -1)
+ gtk_main_quit();
+ else {
+ string error("ERROR: ");
+ error += strerror(errno);
+#ifdef DEBUG
+ cerr << error << endl;
+#endif
+ gtk_label_set_text(GTK_LABEL(g->w1), error.c_str());
+ gtk_widget_set_style(g->w1, style_notfound(g->w1));
+ add_search_off_timeout(2000, g);
+ }
+}
+
+#ifdef USE_SYSTEM
+
+// this version uses the "system" libc function to execute commands.
+static void
+run_the_command(const std::string& command, struct gigi* g)
+{
+ run_with_system(command, g);
+}
+
+#else
+
+// a more elaborate function to avoid system.. though I think that most will
+// prefer the above one. I don't even remember why I coded this... but let it
+// be there.
+static void
+run_the_command(const std::string& command, struct gigi* g)
+{
+ string prog;
+ std::vector<char*> argv;
+
+ string cmd = command + ' ';
+ istringstream iss(cmd);
+#ifdef DEBUG
+ cerr << cmd << endl;
+#endif
+ char what_quote = '"';
+ enum TYPE_CONTEXT {
+ CT_NORMAL = 0,
+ CT_QUOTE,
+ CT_ESCAPE
+ };
+ TYPE_CONTEXT context = CT_NORMAL;
+ TYPE_CONTEXT save_context = CT_NORMAL;
+ string tmp;
+ char c;
+
+ while (!iss.eof()) {
+ c = (char)iss.get();
+ if (iss.eof()) {
+ break;
+ }
+
+ switch (c) {
+ case '\\':
+ if (context != CT_ESCAPE) {
+ save_context = context;
+ context = CT_ESCAPE;
+ } else {
+ goto ordinary;
+ }
+ break;
+
+ case '\'':
+ case '"':
+ if (context == CT_ESCAPE) {
+ goto ordinary;
+ } else {
+ if (context == CT_QUOTE) {
+ if (what_quote == c) {
+ context = CT_NORMAL;
+ } else {
+ goto ordinary;
+ }
+ } else {
+ context = CT_QUOTE;
+ what_quote = c;
+ }
+ }
+ break;
+
+ case ' ':
+ if (context == CT_ESCAPE || context == CT_QUOTE) {
+ goto ordinary;
+ } else if (!tmp.empty()) {
+ if (prog.empty()) {
+ prog = tmp;
+ }
+ char *p = (char*)malloc(tmp.length() + 1);
+ memcpy(p, tmp.c_str(), tmp.length() + 1);
+ argv.push_back(p);
+ tmp.clear();
+ }
+ break;
+
+ ordinary:
+ default:
+ if (context == CT_ESCAPE) {
+ context = save_context;
+ tmp += c;
+ } else if (context == CT_QUOTE) {
+ tmp += c;
+ } else if (c != ' ') {
+ tmp += c;
+ }
+ }
+ }
+ argv.push_back(NULL);
+
+#ifdef DEBUG
+ for (vector<char*>::iterator i = argv.begin(); i != argv.end(); ++i) {
+ if (*i) {
+ cerr << "'" << *i << "'" << endl;
+ }
+ }
+#endif
+
+ execvp(prog.c_str(), (char**)&(*argv.begin()));
+ string error("ERROR: ");
+ error += strerror(errno);
+#ifdef DEBUG
+ cerr << error << endl;
+#endif
+
+ gtk_label_set_text(GTK_LABEL(g->w1), error.c_str());
+ gtk_widget_set_style(g->w1, style_notfound(g->w1));
+ add_search_off_timeout(2000, g);
+}
+#endif
+
+static void
+on_ext_handler(GtkCompletionLine *cl, const char* ext, struct gigi* g)
+{
+ string cmd;
+ if (ext && configuration.get_ext_handler(ext, cmd)) {
+ string str("Handler: ");
+ size_t pos = cmd.find_first_of(" \t");
+ if (pos == string::npos)
+ str += cmd;
+ else
+ str += cmd.substr(0, pos);
+ gtk_label_set_text(GTK_LABEL(g->w2), str.c_str());
+ gtk_widget_show(g->w2);
+ // gtk_timeout_add(1000, GtkFunction(search_off_timeout), g);
+ } else {
+ search_off_timeout(g);
+ }
+}
+
+static void
+on_compline_runwithterm(GtkCompletionLine *cl, struct gigi* g)
+{
+ string command(g_locale_from_utf8 (gtk_entry_get_text(GTK_ENTRY(cl)),
+ -1,
+ NULL,
+ NULL,
+ NULL));
+ string tmp;
+ string term;
+
+ string::size_type i;
+ i = command.find_first_not_of(" \t");
+
+ if (i != string::npos) {
+ if (!configuration.get_string("TermExec", term)) {
+ term = "xterm -e";
+ }
+ tmp = term;
+ tmp += " '";
+ tmp += command + "'";
+ } else {
+ if (!configuration.get_string("Terminal", term)) {
+ tmp = "xterm";
+ } else {
+ tmp = term;
+ }
+ }
+
+#ifdef DEBUG
+ cerr << tmp << endl;
+#endif
+
+ cl->hist->append(command.c_str());
+ cl->hist->sync_the_file();
+ run_with_system(tmp.c_str(), g);
+}
+
+static gint
+search_off_timeout(struct gigi *g)
+{
+ gtk_label_set_text(GTK_LABEL(g->w1), "Run program:");
+ gtk_widget_set_style(g->w1, style_normal(g->w1));
+ gtk_widget_hide(g->w2);
+ return FALSE;
+}
+
+static void
+on_compline_unique(GtkCompletionLine *cl, struct gigi *g)
+{
+ gtk_label_set_text(GTK_LABEL(g->w1), "unique");
+ gtk_widget_set_style(g->w1, style_unique(g->w1));
+ add_search_off_timeout(1000, g);
+}
+
+static void
+on_compline_notunique(GtkCompletionLine *cl, struct gigi *g)
+{
+ gtk_label_set_text(GTK_LABEL(g->w1), "not unique");
+ gtk_widget_set_style(g->w1, style_notunique(g->w1));
+ add_search_off_timeout(1000, g);
+}
+
+static void
+on_compline_incomplete(GtkCompletionLine *cl, struct gigi *g)
+{
+ gtk_label_set_text(GTK_LABEL(g->w1), "not found");
+ gtk_widget_set_style(g->w1, style_notfound(g->w1));
+ add_search_off_timeout(1000, g);
+}
+
+static void
+on_search_mode(GtkCompletionLine *cl, struct gigi *g)
+{
+ if (cl->hist_search_mode != GCL_SEARCH_OFF) {
+ gtk_widget_show(g->w2);
+ gtk_label_set_text(GTK_LABEL(g->w1), "Search:");
+ gtk_label_set_text(GTK_LABEL(g->w2), cl->hist_word->c_str());
+ } else {
+ gtk_widget_hide(g->w2);
+ gtk_label_set_text(GTK_LABEL(g->w1), "Search OFF");
+ add_search_off_timeout(1000, g);
+ }
+}
+
+static void
+on_search_letter(GtkCompletionLine *cl, GtkWidget *label)
+{
+ gtk_label_set_text(GTK_LABEL(label), cl->hist_word->c_str());
+}
+
+static gint
+search_fail_timeout(struct gigi *g)
+{
+ gtk_label_set_text(GTK_LABEL(g->w1), "Search:");
+ gtk_widget_set_style(g->w2, style_notunique(g->w2));
+
+ return FALSE;
+}
+
+static void
+on_search_not_found(GtkCompletionLine *cl, struct gigi *g)
+{
+ gtk_label_set_text(GTK_LABEL(g->w1), "Not Found!");
+ gtk_widget_set_style(g->w2, style_notfound(g->w2));
+ add_search_off_timeout(1000, g, GtkFunction(search_fail_timeout));
+}
+
+static bool
+url_check(GtkCompletionLine *cl, struct gigi *g)
+{
+ string text(g_locale_from_utf8 (gtk_entry_get_text(GTK_ENTRY(cl)),
+ -1,
+ NULL,
+ NULL,
+ NULL));
+
+ string::size_type i;
+ string::size_type sp;
+
+ sp = text.find_first_not_of(" \t");
+ if (sp == string::npos) return true;
+ text = text.substr(sp);
+
+ sp = text.find_first_of(" \t");
+ i = text.find(":");
+
+ if (i != string::npos && i < sp) {
+ // URL entered...
+ string url(text.substr(i + 1));
+ string url_type(text.substr(0, i));
+ string url_handler;
+
+ if (configuration.get_string(string("URL_") + url_type, url_handler)) {
+ string::size_type j = 0;
+
+ do {
+ j = url_handler.find("%s", j);
+ if (j != string::npos) {
+ url_handler.replace(j, 2, url);
+ }
+ } while (j != string::npos);
+
+ j = 0;
+ do {
+ j = url_handler.find("%u", j);
+ if (j != string::npos) {
+ url_handler.replace(j, 2, text);
+ }
+ } while (j != string::npos);
+
+ cl->hist->append(text.c_str());
+ cl->hist->sync_the_file();
+ run_the_command(url_handler.c_str(), g);
+ return true;
+ } else {
+ gtk_label_set_text(GTK_LABEL(g->w1),
+ (string("No URL handler for [") +
+ url_type + "]").c_str());
+ gtk_widget_set_style(g->w1, style_notfound(g->w1));
+ add_search_off_timeout(1000, g);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool
+ext_check(GtkCompletionLine *cl, struct gigi *g)
+{
+ vector<string> words;
+ get_words(cl, words);
+ vector<string>::const_iterator
+ i = words.begin(),
+ i_end = words.end();
+
+ while (i != i_end) {
+ const string& w = quote_string(*i++);
+ if (w[0] == '/') {
+ // absolute path, check for extension
+ size_t pos = w.rfind('.');
+ if (pos != string::npos) {
+ // we have extension
+ string ext = w.substr(pos + 1);
+ string ext_handler;
+ if (configuration.get_ext_handler(ext, ext_handler)) {
+ // we have the handler
+ pos = ext_handler.find("%s");
+ if (pos != string::npos)
+ ext_handler.replace(pos, 2, w);
+ cl->hist->append(w.c_str());
+ cl->hist->sync_the_file();
+ run_the_command(ext_handler.c_str(), g);
+ return true;
+ }
+ }
+ }
+ // FIXME: for now we check only one entry
+ break;
+ }
+
+ return false;
+}
+
+static void
+on_compline_activated(GtkCompletionLine *cl, struct gigi *g)
+{
+ if (url_check(cl, g))
+ return;
+ if (ext_check(cl, g))
+ return;
+
+ string command = g_locale_from_utf8 (gtk_entry_get_text(GTK_ENTRY(cl)),
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+ string::size_type i;
+ i = command.find_first_not_of(" \t");
+
+ if (i != string::npos) {
+ string::size_type j = command.find_first_of(" \t", i);
+ string progname = command.substr(i, j - i);
+ list<string> term_progs;
+ if (configuration.get_string_list("AlwaysInTerm", term_progs)) {
+#ifdef DEBUG
+ cerr << "---" << std::endl;
+ std::copy(term_progs.begin(), term_progs.end(),
+ std::ostream_iterator<string>(cerr, "\n"));
+ cerr << "---" << std::endl;
+#endif
+ list<string>::const_iterator w =
+ std::find(term_progs.begin(), term_progs.end(), progname);
+ if (w != term_progs.end()) {
+ on_compline_runwithterm(cl, g);
+ return;
+ }
+ }
+ cl->hist->append(command.c_str());
+ cl->hist->sync_the_file();
+ run_the_command(command, g);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ GtkWidget *win;
+ GtkWidget *compline;
+ GtkWidget *label_search;
+ struct gigi g;
+
+#ifdef MTRACE
+ mtrace();
+#endif
+
+ gtk_init(&argc, &argv);
+
+ win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_widget_realize(win);
+ gdk_window_set_decorations(win->window, GDK_DECOR_BORDER);
+ gtk_widget_set_name(win, "Msh_Run_Window");
+ gtk_window_set_title(GTK_WINDOW(win), "Execute program feat. completion");
+ gtk_window_set_policy(GTK_WINDOW(win), FALSE, FALSE, TRUE);
+ // gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);
+ gtk_container_set_border_width(GTK_CONTAINER(win), 4);
+ gtk_signal_connect(GTK_OBJECT(win), "destroy",
+ GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
+
+ GtkWidget *hbox = gtk_vbox_new(FALSE, 2);
+ gtk_widget_show(hbox);
+ gtk_container_add(GTK_CONTAINER(win), hbox);
+
+ GtkWidget *hhbox = gtk_hbox_new(FALSE, 2);
+ gtk_widget_show(hhbox);
+ gtk_box_pack_start(GTK_BOX(hbox), hhbox, FALSE, FALSE, 0);
+
+ GtkWidget *label = gtk_label_new("Run program:");
+ gtk_widget_show(label);
+ gtk_misc_set_alignment(GTK_MISC(label), 0.0, 1.0);
+ gtk_misc_set_padding(GTK_MISC(label), 10, 0);
+ gtk_box_pack_start(GTK_BOX(hhbox), label, FALSE, FALSE, 0);
+
+ label_search = gtk_label_new("");
+ gtk_widget_show(label_search);
+ gtk_misc_set_alignment(GTK_MISC(label_search), 1.0, 0.5);
+ gtk_misc_set_padding(GTK_MISC(label_search), 10, 0);
+ gtk_box_pack_start(GTK_BOX(hhbox), label_search, TRUE, TRUE, 0);
+
+ compline = gtk_completion_line_new();
+ gtk_widget_set_name(compline, "Msh_Run_Compline");
+ int prefs_width;
+ if (!configuration.get_int("Width", prefs_width))
+ prefs_width = 500;
+
+ // don't show files starting with "." by default
+ if (!configuration.get_int("ShowDotFiles", GTK_COMPLETION_LINE(compline)->show_dot_files))
+ GTK_COMPLETION_LINE(compline)->show_dot_files = 0;
+
+ {
+ int tmp;
+ if (configuration.get_int("TabTimeout", tmp))
+ ((GtkCompletionLine*)compline)->tabtimeout = tmp;
+ }
+
+ g.w1 = label;
+ g.w2 = label_search;
+
+ gtk_widget_set_usize(compline, prefs_width, -2);
+ gtk_signal_connect(GTK_OBJECT(compline), "cancel",
+ GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
+ gtk_signal_connect(GTK_OBJECT(compline), "activate",
+ GTK_SIGNAL_FUNC(on_compline_activated), &g);
+ gtk_signal_connect(GTK_OBJECT(compline), "runwithterm",
+ GTK_SIGNAL_FUNC(on_compline_runwithterm), &g);
+
+ gtk_signal_connect(GTK_OBJECT(compline), "unique",
+ GTK_SIGNAL_FUNC(on_compline_unique), &g);
+ gtk_signal_connect(GTK_OBJECT(compline), "notunique",
+ GTK_SIGNAL_FUNC(on_compline_notunique), &g);
+ gtk_signal_connect(GTK_OBJECT(compline), "incomplete",
+ GTK_SIGNAL_FUNC(on_compline_incomplete), &g);
+
+ gtk_signal_connect(GTK_OBJECT(compline), "search_mode",
+ GTK_SIGNAL_FUNC(on_search_mode), &g);
+ gtk_signal_connect(GTK_OBJECT(compline), "search_not_found",
+ GTK_SIGNAL_FUNC(on_search_not_found), &g);
+ gtk_signal_connect(GTK_OBJECT(compline), "search_letter",
+ GTK_SIGNAL_FUNC(on_search_letter), label_search);
+
+ gtk_signal_connect(GTK_OBJECT(compline), "ext_handler",
+ GTK_SIGNAL_FUNC(on_ext_handler), &g);
+ gtk_widget_show(compline);
+
+ int shows_last_history_item;
+ if (!configuration.get_int("ShowLast", shows_last_history_item)) {
+ shows_last_history_item = 0;
+ }
+ if (shows_last_history_item) {
+ gtk_completion_line_last_history_item(GTK_COMPLETION_LINE(compline));
+ }
+
+ gtk_box_pack_start(GTK_BOX(hbox), compline, TRUE, TRUE, 0);
+
+ int prefs_top = 80;
+ int prefs_left = 100;
+ configuration.get_int("Top", prefs_top);
+ configuration.get_int("Left", prefs_left);
+
+ // parse commandline options
+ gboolean geo_parsed;
+ char geo_option[30] = "";
+ char *geoptr;
+ poptContext context;
+ int option;
+
+ geoptr = geo_option;
+
+ struct poptOption options[] = {
+ { "geometry", 'g', POPT_ARG_STRING | POPT_ARGFLAG_ONEDASH,
+ &geoptr, 0, "This option specifies the initial "
+ "size and location of the window.", NULL },
+ POPT_AUTOHELP
+ { NULL, '\0', 0, NULL, 0 }
+ };
+
+ context = poptGetContext("popt1", argc, (const char**) argv, options, 0);
+ option = poptGetNextOpt (context);
+
+ if (strcmp (geoptr, ""))
+ {
+ geo_parsed = gtk_window_parse_geometry (GTK_WINDOW (win),
+ geoptr);
+ }
+ else
+ {
+ gtk_widget_set_uposition(win, prefs_left, prefs_top);
+ }
+
+ gtk_widget_show(win);
+
+ gtk_window_set_focus(GTK_WINDOW(win), compline);
+
+ gtk_main();
+}
+
+// Local Variables: ***
+// mode: c++ ***
+// c-basic-offset: 2 ***
+// End: ***
diff --git a/src/main.h b/src/main.h
new file mode 100644
index 0000000..e02475b
--- /dev/null
+++ b/src/main.h
@@ -0,0 +1,13 @@
+/*****************************************************************************
+ * $Id: main.h,v 1.2 2001/05/16 14:39:31 mishoo Exp $
+ * Copyright (C) 2000, Mishoo
+ * Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
+ *
+ * Distributed under the terms of the GNU General Public License. You are
+ * free to use/modify/distribute this program as long as you comply to the
+ * terms of the GNU General Public License, version 2 or above, at your
+ * option, and provided that this copyright notice remains intact.
+ *****************************************************************************/
+
+
+
diff --git a/src/prefs.cc b/src/prefs.cc
new file mode 100644
index 0000000..f9e0485
--- /dev/null
+++ b/src/prefs.cc
@@ -0,0 +1,177 @@
+/*****************************************************************************
+ * $Id: prefs.cc,v 1.9 2002/08/16 10:48:22 mishoo Exp $
+ * Copyright (C) 2000, Mishoo
+ * Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
+ *
+ * Distributed under the terms of the GNU General Public License. You are
+ * free to use/modify/distribute this program as long as you comply to the
+ * terms of the GNU General Public License, version 2 or above, at your
+ * option, and provided that this copyright notice remains intact.
+ *****************************************************************************/
+
+
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+
+#include <list>
+
+#define GMRUNRC "gmrunrc"
+
+using std::ifstream;
+using std::getline;
+using std::string;
+using std::list;
+
+#include "prefs.h"
+#include "config.h"
+
+Prefs configuration;
+
+Prefs::Prefs()
+{
+ string file_name = PACKAGE_DATA_DIR"/";
+ file_name += GMRUNRC;
+ init(file_name);
+
+ file_name = getenv("HOME");
+ if (!file_name.empty()) {
+ string::iterator i = file_name.end() - 1;
+ if (*i == '/') file_name.erase(i);
+ file_name += "/.";
+ file_name += GMRUNRC;
+ init(file_name);
+ }
+}
+
+Prefs::~Prefs()
+{}
+
+bool Prefs::get_string(const string& key, string& val) const
+{
+ CONFIG::const_iterator i;
+ i = vals_.find(ci_string(key.c_str()));
+ if (i != vals_.end()) {
+ val = process(i->second);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool Prefs::get_ext_handler(const std::string& ext, std::string& val) const
+{
+ CONFIG::const_iterator i;
+ i = exts_.find(ci_string(ext.c_str()));
+ if (i != exts_.end()) {
+ val = process(i->second);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool Prefs::get_int(const std::string& key, int& val) const
+{
+ string sval;
+ if (get_string(key, sval)) {
+ int ret;
+ if (sscanf(sval.c_str(), "%d", &ret) == 1) {
+ val = ret;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+}
+
+bool Prefs::init(const string& file_name)
+{
+ ifstream f(file_name.c_str());
+
+ if (!f.good() || f.eof()) return false;
+
+ while (f.good() && !f.eof()) {
+ string line;
+ char key[0x100];
+ char val[0x100];
+
+ getline(f, line);
+ if (f.eof()) break;
+ string::size_type i = line.find_first_not_of(" \t");
+ if (i == string::npos) continue;
+ if (line[i] == '#') continue;
+
+ sscanf(line.c_str(), "%255[a-zA-Z_0-9:,;] = %255[^\n]", key, val);
+ if (strncmp(key, "EXT:", 4) == 0) {
+ string k(key + 4);
+ size_t i = 0;
+ while (i != string::npos) {
+ string ext;
+ size_t j = k.find(',', i);
+ if (j != string::npos) {
+ ext = k.substr(i, j - i);
+ i = j + 1;
+ } else {
+ ext = k.substr(i);
+ i = string::npos;
+ }
+ if (ext.length() > 0) {
+#ifdef DEBUG
+ std::cerr << "Extension: " << ext << " - " << val << std::endl;
+#endif
+ exts_[ext.c_str()] = val;
+ }
+ }
+ } else {
+ vals_[key] = val;
+ }
+
+#ifdef DEBUG
+ std::cerr << "Key: " << key << ", val: " << vals_[key] << std::endl;
+#endif
+ }
+
+ return true;
+}
+
+string Prefs::process(const std::string& cmd) const
+{
+ string::size_type i = cmd.find("${");
+ string::size_type j = cmd.find("}", i);
+
+ if (i == string::npos || j == string::npos) {
+ return cmd;
+ }
+
+ string val;
+ if (!get_string(cmd.substr(i + 2, j - i - 2), val)) return cmd;
+ string ret(cmd);
+ ret.replace(i, j - i + 1, val);
+ return process(ret);
+}
+
+bool Prefs::get_string_list(const string& key, list<string>& val) const
+{
+ string sval;
+ if (get_string(key, sval)) {
+ const char *q, *p = sval.c_str();
+ for (q = sval.c_str(); *q; ++q) {
+ if (::isspace(*q)) {
+ string s(p, q - p);
+ val.push_back(s);
+ while (*q && ::isspace(*q)) ++q;
+ p = q;
+ }
+ }
+ if (p != q) {
+ string s(p, q - p);
+ val.push_back(s);
+ }
+ return (val.size() > 0);
+ }
+ return false;
+}
+
diff --git a/src/prefs.h b/src/prefs.h
new file mode 100644
index 0000000..0732a51
--- /dev/null
+++ b/src/prefs.h
@@ -0,0 +1,45 @@
+/*****************************************************************************
+ * $Id: prefs.h,v 1.6 2002/08/16 10:30:18 mishoo Exp $
+ * Copyright (C) 2000, Mishoo
+ * Author: Mihai Bazon Email: mishoo@fenrir.infoiasi.ro
+ *
+ * Distributed under the terms of the GNU General Public License. You are
+ * free to use/modify/distribute this program as long as you comply to the
+ * terms of the GNU General Public License, version 2 or above, at your
+ * option, and provided that this copyright notice remains intact.
+ *****************************************************************************/
+
+
+#ifndef __PREFS_H__
+#define __PREFS_H__
+
+#include "ci_string.h"
+#include <map>
+#include <list>
+
+class Prefs
+{
+ public:
+ typedef std::map<ci_string, std::string> CONFIG;
+ typedef std::pair<ci_string, std::string> PAIR;
+
+ private:
+ CONFIG vals_;
+ CONFIG exts_;
+
+ bool init(const std::string& file_name);
+ string process(const std::string& cmd) const;
+
+ public:
+ Prefs();
+ ~Prefs();
+
+ bool get_string(const std::string& key, std::string& val) const;
+ bool get_int(const std::string& key, int& val) const;
+ bool get_string_list(const std::string& ket, std::list<string>& val) const;
+ bool get_ext_handler(const std::string& ext, std::string& val) const;
+};
+
+extern Prefs configuration;
+
+#endif /* __PREFS_H__ */