This implementation uses GNU readline for the prompt and command
history, with the default file completion enabled. GLib is used to
split the read line into an arguments list.
---
 Makefile.local |    2 +-
 configure      |   40 ++++++++++++++++++-
 notmuch.c      |  115 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 141 insertions(+), 16 deletions(-)

diff --git a/Makefile.local b/Makefile.local
index f9b5a9b..3aff873 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -31,7 +31,7 @@ GPG_FILE=$(SHA1_FILE).asc
 # Smash together user's values with our extra values
 FINAL_CFLAGS = -DNOTMUCH_VERSION=$(VERSION) $(CFLAGS) $(WARN_CFLAGS)
$(CONFIGURE_CFLAGS) $(extra_cflags)
 FINAL_CXXFLAGS = $(CXXFLAGS) $(WARN_CXXFLAGS) $(CONFIGURE_CXXFLAGS)
$(extra_cflags) $(extra_cxxflags)
-FINAL_NOTMUCH_LDFLAGS = $(LDFLAGS) -Llib -lnotmuch
$(AS_NEEDED_LDFLAGS) $(GMIME_LDFLAGS) $(TALLOC_LDFLAGS)
+FINAL_NOTMUCH_LDFLAGS = $(LDFLAGS) -Llib -lnotmuch
$(AS_NEEDED_LDFLAGS) $(GMIME_LDFLAGS) $(TALLOC_LDFLAGS)
$(READLINE_LDFLAGS)
 FINAL_NOTMUCH_LINKER = CC
 ifneq ($(LINKER_RESOLVES_LIBRARY_DEPENDENCIES),1)
 FINAL_NOTMUCH_LDFLAGS += $(CONFIGURE_LDFLAGS)
diff --git a/configure b/configure
index c58dd0f..c9ea920 100755
--- a/configure
+++ b/configure
@@ -259,6 +259,32 @@ else
     errors=$((errors + 1))
 fi

+printf "Checking for readline... "
+
+echo "#include <stdio.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+int main(void)
+{
+    static char *line = (char *)NULL;
+    line = readline(\"\");
+    add_history(line);
+    return 0;
+}" > have_readline.c
+
+if ${CC} -lreadline -o have_readline have_readline.c > /dev/null 2>&1
+then
+    printf "Yes.\n"
+    have_readline=1
+    readline_ldflags="-lreadline"
+else
+    printf "No.\n"
+    have_readline=0
+    errors=$((errors + 1))
+fi
+rm -f have_readline have_readline.c
+
 printf "Checking for valgrind development files... "
 if pkg-config --exists valgrind; then
     printf "Yes.\n"
@@ -341,6 +367,10 @@ EOF
        echo "  The talloc library (including development files such as 
headers)"
        echo "  http://talloc.samba.org/";
     fi
+    if [ $have_readline -eq 0 ]; then
+       echo "  The readline library (including development files such as 
headers)"
+       echo "  http://tiswww.case.edu/php/chet/readline/rltop.html";
+    fi
     cat <<EOF

 With any luck, you're using a modern, package-based operating system
@@ -349,11 +379,11 @@ case a simple command will install everything
you need. For example:

 On Debian and similar systems:

-       sudo apt-get install libxapian-dev libgmime-2.4-dev libtalloc-dev
+       sudo apt-get install libxapian-dev libgmime-2.4-dev libtalloc-dev
libreadline-dev

 Or on Fedora and similar systems:

-       sudo yum install xapian-core-devel gmime-devel libtalloc-devel
+       sudo yum install xapian-core-devel gmime-devel libtalloc-devel 
readline-devel

 On other systems, similar commands can be used, but the details of the
 package names may be different.
@@ -560,6 +590,9 @@ GMIME_LDFLAGS = ${gmime_ldflags}
 TALLOC_CFLAGS = ${talloc_cflags}
 TALLOC_LDFLAGS = ${talloc_ldflags}

+# Flags needed to compile and link against readline
+READLINE_LDFLAGS = ${readline_ldflags}
+
 # Flags needed to have linker set rpath attribute
 RPATH_LDFLAGS = ${rpath_ldflags}

@@ -580,5 +613,6 @@ CONFIGURE_CXXFLAGS =
-DHAVE_GETLINE=\$(HAVE_GETLINE) \$(GMIME_CFLAGS)    \\
                     \$(TALLOC_CFLAGS) -DHAVE_VALGRIND=\$(HAVE_VALGRIND) \\
                     \$(VALGRIND_CFLAGS) \$(XAPIAN_CXXFLAGS)             \\
                      -DHAVE_STRCASESTR=\$(HAVE_STRCASESTR)
-CONFIGURE_LDFLAGS =  \$(GMIME_LDFLAGS) \$(TALLOC_LDFLAGS) \$(XAPIAN_LDFLAGS)
+CONFIGURE_LDFLAGS =  \$(GMIME_LDFLAGS) \$(TALLOC_LDFLAGS) \\
+                     \$(READLINE_LDFLAGS) \$(XAPIAN_LDFLAGS) \\
 EOF
diff --git a/notmuch.c b/notmuch.c
index 9ba0ec0..630e272 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -18,8 +18,17 @@
  *
  * Authors: Carl Worth <cwo...@cworth.org>
  *         Keith Packard <kei...@keithp.com>
+ *          Servilio Afre Puentes <servi...@gmail.com>
  */

+#include <stdio.h>
+
+#include <string.h>
+
+#include <glib.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
 #include "notmuch-client.h"

 typedef int (*command_function_t) (void *ctx, int argc, char *argv[]);
@@ -35,6 +44,9 @@ typedef struct command {
 static int
 notmuch_help_command (void *ctx, int argc, char *argv[]);

+static int
+notmuch_repl_command (void *ctx, int argc, char *argv[]);
+
 static const char search_terms_help[] =
     "\tSeveral notmuch commands accept a comman syntax for search\n"
     "\tterms.\n"
@@ -361,6 +373,10 @@ command_t commands[] = {
       "\tby the \"--format=json\" option of \"notmuch show\". If the\n"
       "\tmessage specified by the search terms does not include a\n"
       "\tpart with the specified \"id\" there will be no output." },
+    { "repl", notmuch_repl_command,
+      NULL,
+      "Execute an interactive interpreter of notmuch commands.",
+      "\tAlso known as a read-eval-print loop.\n" },
     { "config", notmuch_config_command,
       "[get|set] <section>.<item> [value ...]",
       "Get or set settings in the notmuch configuration file.",
@@ -471,6 +487,90 @@ notmuch_help_command (unused (void *ctx), int
argc, char *argv[])
     return 1;
 }

+static int
+notmuch_command_dispatch (void *ctx, int argc, char *argv[])
+{
+    command_t *command;
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE (commands); i++) {
+       command = &commands[i];
+
+       if (strcmp (argv[0], command->name) == 0)
+           return (command->function) (ctx, argc - 1, &argv[1]);
+    }
+
+    fprintf (stderr, "Error: Unknown command '%s' (see \"notmuch help\")\n",
+            argv[0]);
+
+    return 1;
+}
+
+/*
+ * A notmuch REPL (Read-eval-print loop) with readline support.
+ */
+static int
+notmuch_repl_command (void *ctx, unused (int argc), unused (char *argv[]))
+{
+    const char *prompt = "notmuch> ";
+    static char *line = (char *)NULL;
+    int ret = 0;
+    gint read_argc = 0;
+    gchar **read_argv;
+    GError *parse_error;
+
+    /* Initialize readline. */
+    /* Allow conditional parsing of the ~/.inputrc file. */
+    rl_readline_name = "notmuch";
+
+    do
+    {
+        read_argv = NULL;
+        parse_error = NULL;
+        line = readline(prompt);
+       if (line && *line)
+       {
+           g_shell_parse_argv((gchar *)line,
+                              &read_argc,
+                              &read_argv,
+                              &parse_error);
+
+           if (parse_error == NULL)
+           {
+               add_history(line);
+           }
+           free (line);
+           line = (char *)NULL;
+
+           if (parse_error != NULL)
+           {
+               fprintf (stderr, "%s\n", parse_error->message);
+               g_error_free (parse_error);
+               continue;
+           }
+
+           if (STRNCMP_LITERAL (read_argv[0], "repl") == 0)
+           {
+               fprintf (stderr, "No nasty nestings, please!\n");
+               continue;
+           }
+
+           if (STRNCMP_LITERAL (read_argv[0], "quit") == 0)
+           {
+               fprintf (stdout, "Bye!\n");
+               break;
+           }
+
+           ret = notmuch_command_dispatch(ctx,
+                                          read_argc,
+                                          read_argv);
+           g_strfreev(read_argv);
+       }
+    } while (1);
+
+    return 0;
+}
+
 /* Handle the case of "notmuch" being invoked with no command
  * argument. For now we just call notmuch_setup_command, but we plan
  * to be more clever about this in the future.
@@ -539,8 +639,7 @@ int
 main (int argc, char *argv[])
 {
     void *local;
-    command_t *command;
-    unsigned int i;
+    int res;

     local = talloc_new (NULL);

@@ -557,17 +656,9 @@ main (int argc, char *argv[])
        return 0;
     }

-    for (i = 0; i < ARRAY_SIZE (commands); i++) {
-       command = &commands[i];
-
-       if (strcmp (argv[1], command->name) == 0)
-           return (command->function) (local, argc - 2, &argv[2]);
-    }
-
-    fprintf (stderr, "Error: Unknown command '%s' (see \"notmuch help\")\n",
-            argv[1]);
+    res = notmuch_command_dispatch (local, argc - 1, &argv[1]);

     talloc_free (local);

-    return 1;
+    return res;
 }
-- 
1.7.2.3
_______________________________________________
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch

Reply via email to