# HG changeset patch # User Pascal Dupuis and John W. Eaton # Date 1294821619 18000 # Node ID a1deab9a6e71aa196ba83f83c49761d0c1cb76dd # Parent 571bfa4fc29590e7e4c519d605bd1846468f1a63 bash-like history control diff --git a/doc/ChangeLog b/doc/ChangeLog --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,8 @@ +2011-01-12 John W. Eaton + + * interpreter/basics.txi (Commands For History): + Document history_control. + 2011-01-10 John W. Eaton * interpreter/contributors.in: Add Konstantinos Poulios to the list. diff --git a/doc/interpreter/basics.txi b/doc/interpreter/basics.txi --- a/doc/interpreter/basics.txi +++ b/doc/interpreter/basics.txi @@ -660,6 +660,8 @@ @DOCSTRING(saving_history) +@DOCSTRING(history_control) + @DOCSTRING(history_file) @DOCSTRING(history_size) diff --git a/liboctave/ChangeLog b/liboctave/ChangeLog --- a/liboctave/ChangeLog +++ b/liboctave/ChangeLog @@ -1,3 +1,25 @@ +2011-01-12 Pascal Dupuis + John W. Eaton + + * cmd-hist.cc (command_history::process_histcontrol, + command_history::hist_control, command_history::process_histcontrol, + command_history::hist_control): New functions. + (command_history::initialize, command_history::do_initialize): + New arg, control_arg. + * cmd-hist.cc (gnu_history::do_add): Pass history_control to + octave_add_history. + * cmd-hist.h (command_history::process_histcontrol, + command_history::hist_control, command_history::process_histcontrol, + command_history::hist_control): Provide decls. + (command_history::history_control): New data member. + + * oct-rl-hist.c (octave_add_history): New arg, history_control. + Return int, not void. + (check_history_control, hc_erasedups): New static functions + borrowed from Bash. + * oct-rl-hist.h (octave_add_history): Fix decl. + (HC_IGNSPACE, HC_IGNDUPS, HC_ERASEDUPS): New #defined constants. + 2011-01-06 John W. Eaton * oct-md5.cc (oct_md5_file): Tag call to fclose with gnulib::. diff --git a/liboctave/cmd-hist.cc b/liboctave/cmd-hist.cc --- a/liboctave/cmd-hist.cc +++ b/liboctave/cmd-hist.cc @@ -117,9 +117,7 @@ || (s.length () == 1 && (s[0] == '\r' || s[0] == '\n'))) return; - ::octave_add_history (s.c_str ()); - - lines_this_session++; + lines_this_session += ::octave_add_history (s.c_str (), history_control); } } @@ -421,10 +419,11 @@ void command_history::initialize (bool read_history_file, - const std::string& f_arg, int sz) + const std::string& f_arg, int sz, + const std::string & control_arg) { if (instance_ok ()) - instance->do_initialize (read_history_file, f_arg, sz); + instance->do_initialize (read_history_file, f_arg, sz, control_arg); } bool @@ -454,6 +453,20 @@ } void +command_history::process_histcontrol (const std::string& control_arg) +{ + if (instance_ok ()) + instance->do_process_histcontrol(control_arg); +} + +std::string +command_history::histcontrol (void) +{ + return (instance_ok ()) + ? instance->do_histcontrol () : std::string (); +} + +void command_history::set_size (int n) { if (instance_ok ()) @@ -643,10 +656,12 @@ void command_history::do_initialize (bool read_history_file, - const std::string& f_arg, int sz) + const std::string& f_arg, int sz, + const std::string & control_arg) { command_history::set_file (f_arg); command_history::set_size (sz); + command_history::process_histcontrol (control_arg); if (read_history_file) command_history::read (false); @@ -666,6 +681,77 @@ xfile = f; } +void +command_history::do_process_histcontrol (const std::string& control_arg) +{ + history_control = 0; + + size_t len = control_arg.length (); + size_t beg = 0; + + while (beg < len) + { + if (control_arg[beg] == ':') + beg++; + else + { + size_t end = control_arg.find (":", beg); + + if (end == std::string::npos) + end = len; + + std::string tmp = control_arg.substr (beg, end-beg); + + if (tmp == "erasedups") + history_control |= HC_ERASEDUPS; + else if (tmp == "ignoreboth") + history_control |= HC_IGNDUPS|HC_IGNSPACE; + else if (tmp == "ignoredups") + history_control |= HC_IGNDUPS; + else if (tmp == "ignorespace") + history_control |= HC_IGNSPACE; + else + (*current_liboctave_warning_handler) + ("unknown histcontrol directive %s", tmp.c_str ()); + + if (end != std::string::npos) + beg = end + 1; + } + } +} + +std::string +command_history::do_histcontrol (void) const +{ + // FIXME -- instead of reconstructing this value, should we just save + // the string we were given when constructing the command_history + // object? + + std::string retval; + + if (history_control & HC_IGNSPACE) + retval.append ("ignorespace"); + + if (history_control & HC_IGNDUPS) + { + if (retval.length() > 0) + retval.append (":"); + + retval.append ("ignoredups"); + } + + if (history_control & HC_ERASEDUPS) + { + if (retval.length() > 0) + retval.append (":"); + + retval.append ("erasedups"); + } + + return retval; +} + + std::string command_history::do_file (void) { diff --git a/liboctave/cmd-hist.h b/liboctave/cmd-hist.h --- a/liboctave/cmd-hist.h +++ b/liboctave/cmd-hist.h @@ -34,14 +34,14 @@ protected: command_history (void) - : initialized (false), ignoring_additions (false), lines_in_file (0), - lines_this_session (0), xfile (), xsize (-1) { } + : initialized (false), ignoring_additions (false), history_control (0), + lines_in_file (0), lines_this_session (0), xfile (), xsize (-1) { } public: virtual ~command_history (void) { } - static void initialize (bool, const std::string&, int); + static void initialize (bool, const std::string&, int, const std::string&); static bool is_initialized (void); @@ -49,6 +49,10 @@ static std::string file (void); + static void process_histcontrol (const std::string&); + + static std::string histcontrol (void); + static void set_size (int); static int size (void); @@ -132,7 +136,11 @@ virtual std::string do_file (void); - virtual void do_initialize (bool, const std::string&, int); + virtual void do_process_histcontrol (const std::string&); + + virtual std::string do_histcontrol (void) const; + + virtual void do_initialize (bool, const std::string&, int, const std::string&); virtual bool do_is_initialized (void) const; @@ -197,7 +205,10 @@ // TRUE means we are ignoring new additions. bool ignoring_additions; - // The number of hisory lines we read from the history file. + // Bitmask for history control options. See oct-rl-hist.h. + int history_control; + + // The number of history lines we read from the history file. int lines_in_file; // The number of history lines we've saved so far. diff --git a/liboctave/oct-rl-hist.c b/liboctave/oct-rl-hist.c --- a/liboctave/oct-rl-hist.c +++ b/liboctave/oct-rl-hist.c @@ -24,6 +24,8 @@ #include #endif +#include "oct-rl-hist.h" + #if defined (USE_READLINE) #include @@ -32,10 +34,82 @@ #include -void -octave_add_history (const char *line) +/* check_history_control, hc_erasedup, and the core of + octave_add_history were borrowed from Bash. */ + +/* Check LINE against what HISTCONTROL says to do. Returns 1 if the line + should be saved; 0 if it should be discarded. */ +static int +check_history_control (const char *line, int history_control) { - add_history (line); + HIST_ENTRY *temp; + int r; + + if (history_control == 0) + return 1; + + /* ignorespace or ignoreboth */ + if ((history_control & HC_IGNSPACE) && *line == ' ') + return 0; + + /* ignoredups or ignoreboth */ + if (history_control & HC_IGNDUPS) + { + using_history (); + temp = previous_history (); + + r = (temp == 0 || strcmp (temp->line, line)); + + using_history (); + + if (r == 0) + return r; + } + + return 1; +} + +/* Remove all entries matching LINE from the history list. Triggered when + HISTCONTROL includes `erasedups'. */ + +static void +hc_erasedups (const char *line) +{ + HIST_ENTRY *temp; + int r; + + using_history (); + while (temp = previous_history ()) + { + if (! strcmp (temp->line, line)) + { + r = where_history (); + remove_history (r); + } + } + using_history (); +} + +/* Check LINE against HISTCONTROL and add it to the history if it's OK. + Returns 1 if the line was saved in the history, 0 otherwise. */ + +int +octave_add_history (const char *line, int history_control) +{ + if (check_history_control (line, history_control)) + { + /* We're committed to saving the line. If the user has requested it, + remove other matching lines from the history. */ + + if (history_control & HC_ERASEDUPS) + hc_erasedups (line); + + add_history (line); + + return 1; + } + + return 0; } int diff --git a/liboctave/oct-rl-hist.h b/liboctave/oct-rl-hist.h --- a/liboctave/oct-rl-hist.h +++ b/liboctave/oct-rl-hist.h @@ -28,7 +28,11 @@ { #endif -extern void octave_add_history (const char *); +#define HC_IGNSPACE 0x01 +#define HC_IGNDUPS 0x02 +#define HC_ERASEDUPS 0x04 + +extern int octave_add_history (const char *, int); extern int octave_where_history (void); diff --git a/src/ChangeLog b/src/ChangeLog --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,13 @@ +2011-01-12 John W. Eaton + + *oct-hist.cc (Fhistory_control): New function. + +2011-01-12 Pascal Dupuis + + * oct-hist.cc (default_history_control): New function. + (initialize_history): Pass Vhistory control to + command_history::initialize. + 2011-01-11 Konstantinos Poulios * gl-render.cc (opengl_renderer::draw_axes): Improve positioning diff --git a/src/oct-hist.cc b/src/oct-hist.cc --- a/src/oct-hist.cc +++ b/src/oct-hist.cc @@ -114,6 +114,24 @@ static int Vhistory_size = default_history_size (); static std::string +default_history_control (void) +{ + std::string retval; + + std::string env_histcontrol = octave_env::getenv ("OCTAVE_HISTCONTROL"); + + if (! env_histcontrol.empty ()) + { + return env_histcontrol; + } + + return retval; +} + +// The number of lines to keep in the history file. +static std::string Vhistory_control = default_history_control (); + +static std::string default_history_timestamp_format (void) { return @@ -520,7 +538,8 @@ void initialize_history (bool read_history_file) { - command_history::initialize (read_history_file, Vhistory_file, Vhistory_size); + command_history::initialize (read_history_file, Vhistory_file, Vhistory_size, + Vhistory_control); } void @@ -650,6 +669,39 @@ return retval; } +DEFUN (history_control, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {@var{val} =} history_control ()\n\ +@deftypefnx {Built-in Function} {@var{old_val} =} history_control (@var{new_val})\n\ +Query or set the internal variable that specifies how commands are saved\n\ +to the history list. The default value is an empty character string,\n\ +but may be overridden by the environment variable\n\ +@w{@env{OCTAVE_HISTCONTROL}}.\n\ +\n\ +The value of @code{history_control} is a colon-separated list of values\n\ +controlling how commands are saved on the history list. If the list\n\ +of values includes @code{ignorespace}, lines which begin with a space\n\ +character are not saved in the history list. A value of @code{ignoredups}\n\ +causes lines matching the previous history entry to not be saved.\n\ +A value of @code{ignoreboth} is shorthand for @code{ignorespace} and\n\ +@code{ignoredups}. A value of @code{erasedups} causes all previous lines\n\ +matching the current line to be removed from the history list before that\n\ +line is saved. Any value not in the above list is ignored. If\n\ +@code{history_control} is the empty string, all commands are saved on\n\ +the history list, subject to the value of @code{saving_history}.\n\ +@seealso{history_file, history_size, history_timestamp_format_string, saving_history}\n\ +@end deftypefn") +{ + std::string saved_history_control = Vhistory_control; + + octave_value retval = SET_INTERNAL_VARIABLE (history_control); + + if (Vhistory_control != saved_history_control) + command_history::process_histcontrol (Vhistory_control); + + return retval; +} + DEFUN (history_size, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} history_size ()\n\ @@ -716,7 +768,7 @@ @deftypefnx {Built-in Function} {@var{old_val} =} saving_history (@var{new_val})\n\ Query or set the internal variable that controls whether commands entered\n\ on the command line are saved in the history file.\n\ -@seealso{history_file, history_size, history_timestamp_format_string}\n\ +@seealso{history_control, history_file, history_size, history_timestamp_format_string}\n\ @end deftypefn") { octave_value retval = SET_INTERNAL_VARIABLE (saving_history);