Basic support for custom completion handlers with the two "standard"

rl_complete() and rl_list_possib().  Simply leave out complete.o from
the default build and in all programs require these two functions to
be supplied.

A better alternative would be to use function pointers and check those
for NULL in the running code.  With this code, and no completion handler
the editline code will die.
This commit is contained in:
Joachim Nilsson 2008-10-02 01:52:40 +02:00
parent 4a3fbd9187
commit 5c9f0047bb
7 changed files with 164 additions and 13 deletions

43
configure vendored
View File

@ -695,6 +695,8 @@ CPP
GREP GREP
EGREP EGREP
LIBOBJS LIBOBJS
COMPLETE_TRUE
COMPLETE_FALSE
LTLIBOBJS' LTLIBOBJS'
ac_subst_files='' ac_subst_files=''
ac_precious_vars='build_alias ac_precious_vars='build_alias
@ -1283,6 +1285,7 @@ Optional Features:
--enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--disable-dependency-tracking speeds up one-time build --disable-dependency-tracking speeds up one-time build
--enable-dependency-tracking do not reject slow dependency extractors --enable-dependency-tracking do not reject slow dependency extractors
--enable-default-complete Enable default completion handler.
Some influential environment variables: Some influential environment variables:
CC C compiler command CC C compiler command
@ -4970,6 +4973,35 @@ fi
done done
# Check whether --enable-complete was given.
if test "${enable_complete+set}" = set; then
enableval=$enable_complete;
case "${enableval}" in
yes)
complete=true
;;
no)
complete=false
;;
*)
{ { echo "$as_me:$LINENO: error: bad value ${enableval} for --enable-default-complete" >&5
echo "$as_me: error: bad value ${enableval} for --enable-default-complete" >&2;}
{ (exit 1); exit 1; }; }
;;
esac
else
complete=false
fi
if test x$complete = xtrue; then
COMPLETE_TRUE=
COMPLETE_FALSE='#'
else
COMPLETE_TRUE='#'
COMPLETE_FALSE=
fi
ac_config_files="$ac_config_files Makefile src/Makefile include/Makefile man/Makefile examples/Makefile" ac_config_files="$ac_config_files Makefile src/Makefile include/Makefile man/Makefile examples/Makefile"
cat >confcache <<\_ACEOF cat >confcache <<\_ACEOF
@ -5082,6 +5114,13 @@ echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;} Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; } { (exit 1); exit 1; }; }
fi fi
if test -z "${COMPLETE_TRUE}" && test -z "${COMPLETE_FALSE}"; then
{ { echo "$as_me:$LINENO: error: conditional \"COMPLETE\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
echo "$as_me: error: conditional \"COMPLETE\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
: ${CONFIG_STATUS=./config.status} : ${CONFIG_STATUS=./config.status}
ac_clean_files_save=$ac_clean_files ac_clean_files_save=$ac_clean_files
@ -5698,10 +5737,12 @@ CPP!$CPP$ac_delim
GREP!$GREP$ac_delim GREP!$GREP$ac_delim
EGREP!$EGREP$ac_delim EGREP!$EGREP$ac_delim
LIBOBJS!$LIBOBJS$ac_delim LIBOBJS!$LIBOBJS$ac_delim
COMPLETE_TRUE!$COMPLETE_TRUE$ac_delim
COMPLETE_FALSE!$COMPLETE_FALSE$ac_delim
LTLIBOBJS!$LTLIBOBJS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim
_ACEOF _ACEOF
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 81; then if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 83; then
break break
elif $ac_last_try; then elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5

View File

@ -40,4 +40,19 @@ AC_PROG_GCC_TRADITIONAL
AC_FUNC_STAT AC_FUNC_STAT
AC_CHECK_FUNCS([strchr strdup strrchr tcgetattr]) AC_CHECK_FUNCS([strchr strdup strrchr tcgetattr])
AC_ARG_ENABLE([complete],
[ --enable-default-complete Enable default completion handler.],[
case "${enableval}" in
yes)
complete=true
;;
no)
complete=false
;;
*)
AC_MSG_ERROR([bad value ${enableval} for --enable-default-complete])
;;
esac],[complete=false])
AM_CONDITIONAL([COMPLETE], [test x$complete = xtrue])
AC_OUTPUT(Makefile src/Makefile include/Makefile man/Makefile examples/Makefile) AC_OUTPUT(Makefile src/Makefile include/Makefile man/Makefile examples/Makefile)

View File

@ -1,10 +1,10 @@
AUTOMAKE_OPTIONS = foreign AUTOMAKE_OPTIONS = foreign
LDADD = $(top_builddir)/src/libedit.a LDADD = $(top_builddir)/src/libedit.a
AM_CFLAGS = -I$(top_srcdir)/src AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include
# TODO: Port "fileman" example from BSD editline # TODO: Port "fileman" example from BSD editline
noinst_PROGRAMS = testit noinst_PROGRAMS = testit cli
testit_SOURCES = testit.c testit_SOURCES = testit.c
#fileman_SOURCES = fileman.c #fileman_SOURCES = fileman.c

View File

@ -30,7 +30,7 @@ POST_INSTALL = :
NORMAL_UNINSTALL = : NORMAL_UNINSTALL = :
PRE_UNINSTALL = : PRE_UNINSTALL = :
POST_UNINSTALL = : POST_UNINSTALL = :
noinst_PROGRAMS = testit$(EXEEXT) noinst_PROGRAMS = testit$(EXEEXT) cli$(EXEEXT)
subdir = examples subdir = examples
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@ -41,6 +41,10 @@ mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES = CONFIG_CLEAN_FILES =
PROGRAMS = $(noinst_PROGRAMS) PROGRAMS = $(noinst_PROGRAMS)
cli_SOURCES = cli.c
cli_OBJECTS = cli.$(OBJEXT)
cli_LDADD = $(LDADD)
cli_DEPENDENCIES = $(top_builddir)/src/libedit.a
am_testit_OBJECTS = testit.$(OBJEXT) am_testit_OBJECTS = testit.$(OBJEXT)
testit_OBJECTS = $(am_testit_OBJECTS) testit_OBJECTS = $(am_testit_OBJECTS)
testit_LDADD = $(LDADD) testit_LDADD = $(LDADD)
@ -52,8 +56,8 @@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC) CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(testit_SOURCES) SOURCES = cli.c $(testit_SOURCES)
DIST_SOURCES = $(testit_SOURCES) DIST_SOURCES = cli.c $(testit_SOURCES)
ETAGS = etags ETAGS = etags
CTAGS = ctags CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@ -144,7 +148,7 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = foreign AUTOMAKE_OPTIONS = foreign
LDADD = $(top_builddir)/src/libedit.a LDADD = $(top_builddir)/src/libedit.a
AM_CFLAGS = -I$(top_srcdir)/src AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include
testit_SOURCES = testit.c testit_SOURCES = testit.c
all: all-am all: all-am
@ -182,6 +186,9 @@ $(ACLOCAL_M4): $(am__aclocal_m4_deps)
clean-noinstPROGRAMS: clean-noinstPROGRAMS:
-test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
cli$(EXEEXT): $(cli_OBJECTS) $(cli_DEPENDENCIES)
@rm -f cli$(EXEEXT)
$(LINK) $(cli_OBJECTS) $(cli_LDADD) $(LIBS)
testit$(EXEEXT): $(testit_OBJECTS) $(testit_DEPENDENCIES) testit$(EXEEXT): $(testit_OBJECTS) $(testit_DEPENDENCIES)
@rm -f testit$(EXEEXT) @rm -f testit$(EXEEXT)
$(LINK) $(testit_OBJECTS) $(testit_LDADD) $(LIBS) $(LINK) $(testit_OBJECTS) $(testit_LDADD) $(LIBS)
@ -192,6 +199,7 @@ mostlyclean-compile:
distclean-compile: distclean-compile:
-rm -f *.tab.c -rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cli.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testit.Po@am__quote@
.c.o: .c.o:

78
examples/cli.c Normal file
View File

@ -0,0 +1,78 @@
/* The "testit" micro shell, now with command completion.
* To be able to run, don't "--enable-default-complete".
*/
#include "editline.h"
#include <string.h>
char *list[] = {
"foo ", "bar ", "bsd ", "cli ", "ls ", "cd ", "malloc ", "tee ", NULL
};
/*
** Attempt to complete the pathname, returning an allocated copy.
** Fill in *unique if we completed it, or set it to 0 if ambiguous.
*/
char *rl_complete(char *token, int *match)
{
int i;
int index = -1;
int matchlen = 0;
int count = 0;
for (i = 0; list[i]; i++)
{
int partlen = strlen (token); /* Part of token */
if (!strncmp (list[i], token, partlen))
{
index = i;
matchlen = partlen;
count ++;
}
}
if (count == 1)
{
*match = 1;
return strdup (list[index] + matchlen);
}
return NULL;
}
/*
** Return all possible completions.
*/
int rl_list_possib(char *token, char ***av)
{
int i, num, total = 0;
char **copy;
for (num = 0; list[num]; num++)
;
copy = (char **) malloc (num * sizeof(char *));
for (i = 0; i < num; i++)
{
if (!strncmp (list[i], token, strlen (token)))
{
copy[total] = strdup (list[i]);
total ++;
}
}
*av = copy;
return total;
}
int main(int ac, char *av[])
{
char *line;
char *prompt = "cli> ";
while ((line = readline(prompt)) != NULL) {
(void)printf("\t\t\t|%s|\n", line);
free(line);
}
return 0;
}

View File

@ -2,5 +2,8 @@ AUTOMAKE_OPTIONS = foreign
lib_LIBRARIES = libedit.a lib_LIBRARIES = libedit.a
libedit_a_SOURCES = editline.c editline.h complete.c sysunix.c unix.h libedit_a_SOURCES = editline.c editline.h sysunix.c unix.h
if COMPLETE
# Built-in completion handler.
libedit_a_SOURCES += complete.c
endif

View File

@ -30,6 +30,8 @@ POST_INSTALL = :
NORMAL_UNINSTALL = : NORMAL_UNINSTALL = :
PRE_UNINSTALL = : PRE_UNINSTALL = :
POST_UNINSTALL = : POST_UNINSTALL = :
# Built-in completion handler.
@COMPLETE_TRUE@am__append_1 = complete.c
subdir = src subdir = src
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@ -52,8 +54,11 @@ AR = ar
ARFLAGS = cru ARFLAGS = cru
libedit_a_AR = $(AR) $(ARFLAGS) libedit_a_AR = $(AR) $(ARFLAGS)
libedit_a_LIBADD = libedit_a_LIBADD =
am_libedit_a_OBJECTS = editline.$(OBJEXT) complete.$(OBJEXT) \ am__libedit_a_SOURCES_DIST = editline.c editline.h sysunix.c unix.h \
sysunix.$(OBJEXT) complete.c
@COMPLETE_TRUE@am__objects_1 = complete.$(OBJEXT)
am_libedit_a_OBJECTS = editline.$(OBJEXT) sysunix.$(OBJEXT) \
$(am__objects_1)
libedit_a_OBJECTS = $(am_libedit_a_OBJECTS) libedit_a_OBJECTS = $(am_libedit_a_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp depcomp = $(SHELL) $(top_srcdir)/depcomp
@ -63,7 +68,7 @@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
CCLD = $(CC) CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(libedit_a_SOURCES) SOURCES = $(libedit_a_SOURCES)
DIST_SOURCES = $(libedit_a_SOURCES) DIST_SOURCES = $(am__libedit_a_SOURCES_DIST)
ETAGS = etags ETAGS = etags
CTAGS = ctags CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@ -154,7 +159,8 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = foreign AUTOMAKE_OPTIONS = foreign
lib_LIBRARIES = libedit.a lib_LIBRARIES = libedit.a
libedit_a_SOURCES = editline.c editline.h complete.c sysunix.c unix.h libedit_a_SOURCES = editline.c editline.h sysunix.c unix.h \
$(am__append_1)
all: all-am all: all-am
.SUFFIXES: .SUFFIXES: