From: servilio <servilio@gmail.com>
To: notmuch <notmuch@notmuchmail.org>
Subject: [PATCH] Implement a simple read-eval-print loop.
Date: Sat, 20 Nov 2010 09:20:14 -0500 [thread overview]
Message-ID: <AANLkTi=7eCt0=NqUiJFrGDcaZ17LOd3qNNqN1-ASwYzr@mail.gmail.com> (raw)
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 <cworth@cworth.org>
* Keith Packard <keithp@keithp.com>
+ * Servilio Afre Puentes <servilio@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
next reply other threads:[~2010-11-20 14:20 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-11-20 14:20 servilio [this message]
2010-11-20 21:15 ` [PATCH] Implement a simple read-eval-print loop Michal Sojka
2010-11-20 23:38 ` servilio
2010-11-21 17:35 ` Austin Clements
2010-11-21 21:10 ` Michal Sojka
2010-11-21 21:51 ` Michal Sojka
2010-11-21 22:14 ` Michael Hudson
2010-11-21 23:50 ` Austin Clements
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://notmuchmail.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='AANLkTi=7eCt0=NqUiJFrGDcaZ17LOd3qNNqN1-ASwYzr@mail.gmail.com' \
--to=servilio@gmail.com \
--cc=notmuch@notmuchmail.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://yhetil.org/notmuch.git/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).