Index: README ================================================================== --- README +++ README @@ -1,8 +1,8 @@ - FILE: "/diska/home/joze/src/tclreadline/README" - LAST MODIFICATION: "Mon Aug 23 19:42:31 1999 (joze)" + FILE: "/home/joze/src/tclreadline/README" + LAST MODIFICATION: "Sat Aug 28 23:30:56 1999 (joze)" (C) 1998, 1999 by Johannes Zellner, $Id$ --- tclreadline -- gnu readline for tcl @@ -74,10 +74,35 @@ does the rest. 4. History and Changes. ----------------------- + +tclreadline-0.9.2: (Aug 1999) + + changes: + - history event `!' expansion on + - if tclreadline::historyLength >= 0, + tclreadline::write will truncate the historyfile + to this value. + By default tclreadline::historyfile == -1, that + is no truncation occurs. + + fixes: + - after having at least one character typed, X events + were not processed any more until pressing . + + +tclreadline-0.9.1: (Aug 1999) + + changes: + - new variable tclreadline_patchLevel + - tclreadline::Loop takes an optional + + fixes: + - tying to fix configure problems. + tclreadline-0.9: (Aug 1999) changes: - tclreadline::readline customcompleter @@ -97,12 +122,14 @@ bug fixes: - lines added to tcl's history. (were only in readline's hist.) - macro mappings didn't work. (only when hitting mapped characters more than once.) - various changes and fixes in configure.in + tclreadline-0.8: (May 1999) - adapted for tcl8.1. - minor bug fixes. + tclreadline-0.7: (Feb 1999) first `public release'. Index: TODO ================================================================== --- TODO +++ TODO @@ -1,10 +1,10 @@ /* ================================================================== - FILE: "/krispc6/home/joze/src/tclreadline/TOOD" - LAST MODIFICATION: "Sat May 8 14:06:05 1999 (joze)" + FILE: "/home/joze/src/tclreadline/TODO" + LAST MODIFICATION: "Sat Aug 28 23:20:25 1999 (joze)" (C) 1998, 1999 by Johannes Zellner, $Id$ --- tclreadline -- gnu readline for tcl @@ -27,11 +27,16 @@ , http://www.zellner.org/tclreadline/ ================================================================== */ - + write README. - + write docs. - + use *forced* TCL_PREFIX or TCL_EXEC_PREFIX for installation. - (unless specified via --prefix or --exec-prefix). - + write make release entry in Makefile.in - + update make ci. + + history_truncate_file(int n, char* historyfile) + verwenden, um nur eine begrenze Zahl zu schreiben. + + + wenn nur ein array Element von a vorliegt, + wird trotzdem nur auf $a( completed. --> ändern. + + + custom completers: + prüfen, ob ein completer für eine Funktion da ist ... + z.B.: `set' könnte für alle Variblennamen completen. + + + history_expansion mit (z.B. !$). Index: configure.in ================================================================== --- configure.in +++ configure.in @@ -1,8 +1,8 @@ # -*- autoconf -*- -# FILE: "/diska/home/joze/src/tclreadline/configure.in" -# LAST MODIFICATION: "Wed Aug 25 16:17:27 1999 (joze)" +# FILE: "/home/joze/src/tclreadline/configure.in" +# LAST MODIFICATION: "Sat Aug 28 22:23:57 1999 (joze)" # (C) 1998, 1999 by Johannes Zellner, # $Id$ # --- # # tclreadline -- gnu readline for tcl @@ -35,11 +35,11 @@ AC_INIT(tclreadline.c) TCLREADLINE_MAJOR_VERSION=0 TCLREADLINE_MINOR_VERSION=9 -TCLREADLINE_PATCHLEVEL=1 +TCLREADLINE_PATCHLEVEL=2 TCLREADLINE_VERSION=$TCLREADLINE_MAJOR_VERSION.$TCLREADLINE_MINOR_VERSION VERSION=$TCLREADLINE_VERSION AC_PREREQ(2.13) Index: sample.tclshrc ================================================================== --- sample.tclshrc +++ sample.tclshrc @@ -1,8 +1,8 @@ #!/bin/sh -# FILE: "/diska/home/joze/src/tclreadline/sample.tclshrc" -# LAST MODIFICATION: "Mon Aug 23 17:50:54 1999 (joze)" +# FILE: "/home/joze/src/tclreadline/sample.tclshrc" +# LAST MODIFICATION: "Sat Aug 28 23:41:17 1999 (joze)" # (C) 1999 by Johannes Zellner, # $Id$ # vim:set ft=tcl: \ exec tclsh "$0" "$@" @@ -42,11 +42,15 @@ # uncomment the folling line, if you want # to change tclreadline's print behaviour # frequently with less typing. # # namespace import tclreadline::Print + + # store maximal this much lines in the history file + # + set tclreadline::historyLength 200 # go to tclrealdine's main loop. # tclreadline::Loop } Index: tclreadline.c ================================================================== --- tclreadline.c +++ tclreadline.c @@ -1,10 +1,10 @@ /* ================================================================== - FILE: "/diska/home/joze/src/tclreadline/tclreadline.c" - LAST MODIFICATION: "Fri Aug 27 16:18:44 1999 (joze)" + FILE: "/home/joze/src/tclreadline/tclreadline.c" + LAST MODIFICATION: "Sat Aug 28 23:56:10 1999 (joze)" (C) 1998, 1999 by Johannes Zellner, $Id$ --- tclreadline -- gnu readline for tcl @@ -68,11 +68,11 @@ int argc, char** argv); void TclReadlineDataAvailableHandler(ClientData clientData, int mask); void TclReadlineLineCompleteHandler(char* ptr); int Tclreadline_SafeInit(Tcl_Interp* interp); int Tclreadline_Init(Tcl_Interp* interp); -char* TclReadlineInitialize(char* historyfile); +int TclReadlineInitialize(Tcl_Interp* interp, char* historyfile); int blank_line(char* str); char** TclReadlineCompletion(char* text, int start, int end); char* TclReadline0generator(char* text, int state); char* TclReadlineKnownCommands(char* text, int state, int mode); int TclReadlineParse(char** args, int maxargs, char* buf); @@ -90,10 +90,11 @@ static int tclrl_state = TCL_OK; static char* tclrl_eof_string = (char*) NULL; static char* tclrl_line = (char*) NULL; static char* tclrl_custom_completer = (char*) NULL; static int tclrl_use_builtin_completer = 1; +static int tclrl_history_length = -1; Tcl_Interp* tclrl_interp = (Tcl_Interp*) NULL; char* stripleft(char* in) @@ -172,12 +173,16 @@ TclReadlineLineCompleteHandler); Tcl_CreateFileHandler(0, TCL_READABLE, TclReadlineDataAvailableHandler, (ClientData) NULL); - while (LINE_PENDING == tclrl_line_complete && TCL_OK == tclrl_state) { + while (LINE_PENDING == tclrl_line_complete + && TCL_OK == tclrl_state && !rl_done) { Tcl_DoOneEvent(0); + /* + rl_inhibit_completion = 0; + */ } Tcl_DeleteFileHandler(0); if ((LINE_EOF == tclrl_line_complete) && tclrl_eof_string) { @@ -184,15 +189,29 @@ Tcl_Eval(interp, tclrl_eof_string); return tclrl_state; } status = history_expand(tclrl_line, &expansion); - if (status == 1) + if (status >= 1) { +#if 0 + Tcl_Channel channel = Tcl_MakeFileChannel(stdout, TCL_WRITABLE); + /* Tcl_RegisterChannel(interp, channel); */ + (void) Tcl_WriteChars(channel, expansion, -1); + Tcl_Flush(channel); + Tcl_Close(interp, channel); +#else printf("%s\n", expansion); - else if (status == -1) - Tcl_AppendResult(interp, "error in history expansion\n", - (char*) NULL); +#endif + } + else if (status == -1) { + Tcl_AppendResult + (interp, "error in history expansion\n", (char*) NULL); + return TCL_ERROR; + } + /** + * TODO: status == 2 ... + */ if (expansion && *expansion) add_history(expansion); Tcl_AppendResult(interp, expansion, (char*) NULL); @@ -202,18 +221,23 @@ return tclrl_state; } else if (c == 'i' && strncmp(argv[1], "initialize", length) == 0) { if (3 != argc) goto BAD_COMMAND; else - Tcl_AppendResult(interp, TclReadlineInitialize(argv[2]), - (char*) NULL); + return TclReadlineInitialize(interp, argv[2]); } else if (c == 'w' && strncmp(argv[1], "write", length) == 0) { - if (3 != argc) + if (3 != argc) { goto BAD_COMMAND; - else if (write_history(argv[2])) - Tcl_AppendResult(interp, "unable to write history to \"", - argv[2], "\"\n", (char*) NULL); + } else if (write_history(argv[2])) { + Tcl_AppendResult(interp, "unable to write history to `", + argv[2], "'\n", (char*) NULL); + return TCL_ERROR; + } + if (tclrl_history_length >= 0) { + history_truncate_file(argv[2], tclrl_history_length); + } + return TCL_OK; } else if (c == 'a' && strncmp(argv[1], "add", length) == 0) { if (3 != argc) goto BAD_COMMAND; else if (TclReadlineKnownCommands(argv[2], (int) 0, _CMD_SET)) Tcl_AppendResult(interp, "unable to add command \"", @@ -279,12 +303,11 @@ { #if 0 fprintf(stderr, "(TclReadlineDataAvailableHandler) mask = %d\n", mask); #endif if (mask & TCL_READABLE) { - while (0 == rl_done) - rl_callback_read_char(); + rl_callback_read_char(); } } void TclReadlineLineCompleteHandler(char* ptr) @@ -314,18 +337,24 @@ } int Tclreadline_Init(Tcl_Interp *interp) { + int status; Tcl_CreateCommand(interp, "::tclreadline::readline", TclReadlineCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); tclrl_interp = interp; + status = Tcl_LinkVar + (interp, "::tclreadline::historyLength", + (char*) &tclrl_history_length, TCL_LINK_INT); + if (TCL_OK != status) + return status; return Tcl_PkgProvide(interp, "tclreadline", TCLREADLINE_VERSION); } -char* -TclReadlineInitialize(char* historyfile) +int +TclReadlineInitialize(Tcl_Interp* interp, char* historyfile) { rl_readline_name = "tclreadline"; /* rl_special_prefixes = "${\""; */ rl_special_prefixes = "${"; /** @@ -344,15 +373,17 @@ * try to read historyfile in home * directory. If this failes, this * is *not* an error. */ rl_attempted_completion_function = (CPPFunction *) TclReadlineCompletion; - if (read_history(historyfile)) - return "unable to read history file"; - - else - return ""; + if (read_history(historyfile)) { + if (write_history(historyfile)) { + Tcl_AppendResult (interp, "warning: `", + historyfile, "' is not writable.", (char*) NULL); + } + } + return TCL_OK; } int blank_line(char* str) { @@ -372,43 +403,81 @@ #if 0 fprintf(stderr, "DEBUG> TclReadlineCompletion: text=|%s|\n", text); fprintf(stderr, "DEBUG> TclReadlineCompletion: start=|%d|\n", start); fprintf(stderr, "DEBUG> TclReadlineCompletion: end=|%d|\n", end); #endif + +#if 0 + char* history_event = (char*) NULL; + if (text) { + if ('!' == text[0]) + history_event = strdup(text); + else if (start && rl_line_buffer[start - 1] == '!' /* for '$' */) { + int len = strlen(text); + history_event = strncpy((char*) malloc(sizeof(char) * (len + 1)), + rl_line_buffer[start - 1], len); + history_event[len] = '\0'; /* terminate */ + } + } + if (history_event) +#endif + + if (text && ('!' == text[0] + || (start && rl_line_buffer[start - 1] == '!' /* for '$' */))) { + char* expansion = (char*) NULL; + int oldlen = strlen(rl_line_buffer); + int status = history_expand(rl_line_buffer, &expansion); + if (status >= 1) { + rl_extend_line_buffer(strlen(expansion) + 1); + strcpy(rl_line_buffer, expansion); + rl_end = strlen(expansion); + rl_point += strlen(expansion) - oldlen; + FREE(expansion); + /* rl_redisplay(); */ + /* + * TODO: + * because we return 0 == matches, + * the filename completer will still beep. + rl_inhibit_completion = 1; + */ + return matches; + } + FREE(expansion); + } if (tclrl_custom_completer) { char start_s[BUFSIZ], end_s[BUFSIZ]; Tcl_Obj* obj; Tcl_Obj** objv; int objc; char* quoted_text = TclReadlineQuote(text, "$[]{}\""); char* quoted_rl_line_buffer = TclReadlineQuote(rl_line_buffer, "$[]{}\""); - /* +#if 0 fprintf (stderr, "(TclReadlineCompletion) rl_line_buffer = |%s|\n", rl_line_buffer); fprintf (stderr, "(TclReadlineCompletion) quoted_rl_line_buffer = |%s|\n", quoted_rl_line_buffer); fprintf (stderr, "(TclReadlineCompletion) text = |%s|\n", text); fprintf (stderr, "(TclReadlineCompletion) quoted_text = |%s|\n", quoted_text); - */ +#endif sprintf(start_s, "%d", start); sprintf(end_s, "%d", end); Tcl_ResetResult(tclrl_interp); /* clear result space */ tclrl_state = Tcl_VarEval(tclrl_interp, tclrl_custom_completer, " \"", quoted_text, "\" ", start_s, " ", end_s, " \"", quoted_rl_line_buffer, "\"", (char*) NULL); FREE(quoted_text); FREE(quoted_rl_line_buffer); if (TCL_OK != tclrl_state) { - fprintf (stderr, "%s\n", Tcl_GetStringResult(tclrl_interp)); - /* + fprintf(stderr, "%s\n", Tcl_GetStringResult(tclrl_interp)); +#if 0 Tcl_AppendResult (tclrl_interp, "`", tclrl_custom_completer, " {", text, "} ", start_s, " ", end_s, " {", rl_line_buffer, "}' failed.", (char*) NULL); - */ +#endif return matches; } obj = Tcl_GetObjResult(tclrl_interp); Tcl_ListObjGetElements(tclrl_interp, obj, &objc, &objv); /* fprintf (stderr, "(TclReadlineCompletion) objc = %d\n", objc); */ @@ -457,10 +526,11 @@ int i, argc; char** name; char* local_line = (char*) NULL; int sub; + switch (mode) { case _CMD_SET: @@ -494,10 +564,11 @@ local_line = strdup(rl_line_buffer); sub = TclReadlineParse(args, sizeof(args), local_line); /* * fprintf (stderr, "(TclReadlineKnownCommands) state=%d\n", state); + * fprintf (stderr, "(TclReadlineKnownCommands) text = |%s|\n", text); */ if (0 == sub || (1 == sub && '\0' != text[0])) { if (!state) { new = cmds; @@ -511,63 +582,10 @@ return (char*) NULL; } else { if (!state) { -#if 0 - fprintf (stderr, - "(TclReadlineKnownCommands) _CMD_SUB_GET = |%s| %d %d\n", - text, state, mode); -#endif - - /* - len = strlen(local_line); - stripright(local_line); - */ - -#if 0 - if (len != strlen(local_line)) { -#endif -#if 0 - } else { - sub = TclReadlineParse(args, sizeof(args), local_line) - 1; - } -#endif -#if 0 - { - int i; - fprintf (stderr, "\n"); - for (i = 0; i < sub; i++) - fprintf (stderr, "|%s|\n", args[i]); - } - - fprintf (stderr, - "(TclReadlineKnownCommands) args[sub - 1] = |%s|\n", - args[sub - 1]); -#endif -#if 0 - if (sub > 0 && args[sub - 1] && *(args[sub - 1]) == '$') { - char* var = strdup(args[sub - 1] + 1); - char* ptr = var; - int varlen; - if (var) - varlen = strlen(var); - else - return (char*) NULL; - if (!varlen) { - FREE(var); - return (char* ) NULL; - } else if ('{' == var[0]) { - ptr++; - varlen--; - } - fprintf (stderr, "(TclReadlineKnownCommands) $\n"); - FREE(var); - return (char* ) NULL; - } -#endif - new = cmds; len = strlen(text); while (new && (name = new->cmd)) { if (!strcmp(name[0], args[0])) Index: tclreadline.n.in ================================================================== --- tclreadline.n.in +++ tclreadline.n.in @@ -1,10 +1,10 @@ .TH tclreadline n "@TCLREADLINE_VERSION@.@TCLREADLINE_PATCHLEVEL@" "Johannes Zellner" .\" (C) 1999 by Johannes Zellner -.\" FILE: "/diska/home/joze/src/tclreadline/tclreadline.n.in" -.\" LAST MODIFICATION: "Wed Aug 25 16:32:02 1999 (joze)" +.\" FILE: "/home/joze/src/tclreadline/tclreadline.n.in" +.\" LAST MODIFICATION: "Sat Aug 28 23:38:44 1999 (joze)" .\" (C) 1998, 1999 by Johannes Zellner, .\" $Id$ .\" --- .\" .\" tclreadline -- gnu readline for the tcl scripting language @@ -79,11 +79,15 @@ .SH "COMMANDS" If you want to use \fBtclreadline\fP as a line interface for developing tcl scripts, you probably don't have to read -this section. +this section. In this case the only thing you should do is +to modify your .tclshrc according to the section \fBFILES\fP. + +For the functionality of the GNU readline you should refer to +the readline's documentation. .PP The following list will give all commands, which are currently implemented in the shared lib (e.g. libtclreadline@TCLREADLINE_VERSION@.so). Additional commands were introduced in a startup script @@ -168,10 +172,12 @@ .TP 5 \fB::tclreadline::readline write\fP \fIhistoryfile\fP writes the history to the \fIhistoryfile\fP. This command is called automatically from the internal routine ::tclreadline::Exit. +If the variable \fBtclreadline::historyLength\fP is non-negative, +the historyfile will be truncated to hold only this number lines. .TP 5 \fB::tclreadline::Print\fP [\fIyes / no\fP] turns on or off the default behavior of tclsh to print the result of every command. This is turned on by default, so it will just behave @@ -225,24 +231,33 @@ .\" .SH "ENVIRONMENT VARIABLES" .SH "VARIABLES" -\fItclreadline\fP defines the following variables in the global namespace: +\fItclreadline\fP defines the following variables in the +namespace \fI::tclreadline\fP: +(for backwards compatiblity the global variables tclreadline_version, + tclreadline_patchLevel and tclreadline_library are still present). .TP 5 -\fBtclreadline_version\fP +\fBtclreadline::version\fP holds the version string "@TCLREADLINE_VERSION@". .TP 5 -\fBtclreadline_patchLevel\fP +\fBtclreadline::patchLevel\fP holds the patch level string "@TCLREADLINE_VERSION@.@TCLREADLINE_PATCHLEVEL@". .TP 5 -\fBtclreadline_library\fP +\fBtclreadline::library\fP holds the library string "@TCLREADLINE_LIBRARY@". +.TP 5 +\fBtclreadline::historyLength\fP +Number of lines, which will be written to the historyfile. +This number is -1 by default, which means that the historyfile +will not be truncated. See also \fBtclreadline::write\fP. + .SH "FILES" the \fB.tclshrc\fP file in the HOME directory, which is read on tclsh startup. Alternatively, the name of this initialization file might be \fB.wishrc\fP ... depending on what interpreter you use. Index: tclreadlineInit.tcl.in ================================================================== --- tclreadlineInit.tcl.in +++ tclreadlineInit.tcl.in @@ -1,8 +1,8 @@ #!/usr/local/bin/tclsh -# FILE: "/diska/home/joze/src/tclreadline/tclreadlineInit.tcl.in" -# LAST MODIFICATION: "Wed Aug 25 16:27:19 1999 (joze)" +# FILE: "/home/joze/src/tclreadline/tclreadlineInit.tcl.in" +# LAST MODIFICATION: "Sun Aug 29 00:03:22 1999 (joze)" # (C) 1998, 1999 by Johannes Zellner, # $Id$ # --- # # tclreadline -- gnu readline for tcl @@ -36,16 +36,23 @@ proc ::tclreadline::Init {} { global tclreadline_version global tclreadline_library global tclreadline_patchLevel + + variable version + variable library + variable patchLevel set tclreadline_version @TCLREADLINE_VERSION@ + set version @TCLREADLINE_VERSION@ set tclreadline_library @TCLREADLINE_LIBRARY@ + set library @TCLREADLINE_LIBRARY@ # NOTE, that tclreadline_patchLevel is the complete patchlevel string. # set tclreadline_patchLevel @TCLREADLINE_VERSION@.@TCLREADLINE_PATCHLEVEL@ + set patchLevel @TCLREADLINE_VERSION@.@TCLREADLINE_PATCHLEVEL@ if [catch {load @TCLREADLINE_LIBRARY@/@TCLREADLINE_LIB_FILE@} msg] { puts stderr $msg exit 2 } Index: tclreadlineSetup.tcl.in ================================================================== --- tclreadlineSetup.tcl.in +++ tclreadlineSetup.tcl.in @@ -1,8 +1,8 @@ #!/usr/local/bin/tclsh -# FILE: "/diska/home/joze/src/tclreadline/tclreadlineSetup.tcl.in" -# LAST MODIFICATION: "Fri Aug 27 16:08:15 1999 (joze)" +# FILE: "/home/joze/src/tclreadline/tclreadlineSetup.tcl.in" +# LAST MODIFICATION: "Sat Aug 28 23:58:03 1999 (joze)" # (C) 1998, 1999 by Johannes Zellner, # $Id$ # --- # # tclreadline -- gnu readline for tcl @@ -379,13 +379,15 @@ catch {rename ::tclreadline::Exit ""} rename exit ::tclreadline::Exit proc exit {args} { - catch { + if {[catch { ::tclreadline::readline write \ [::tclreadline::HistoryFileGet] + } msg]} { + puts stderr $msg } if [catch "eval ::tclreadline::Exit $args" message] { puts stderr "error:" puts stderr "$message"