%
%  Recall previous commands in MiniBuffer
%  
%  Enables different histories for different minibuffer prompts,
%  for example:
%  
%    mini_use_history("filename");
%    file = read_file_from_mini("Open:");
%    mini_use_history(NULL);   % restore default history
%
%    ...
%    
%    mini_use_history("search");
%    srch = read_mini("Find:", "", "");
%    mini_use_history(NULL);
%    
%  Installation:
%  a) Global
%    1. add hist-cls.sl somewhere on your jed library path
%    2. replace jed/lib/mini.sl with this file
%  b) Local
%    1. Create a subdirecory named <jedhist> in the directory of .jedrc
%    2. Copy the above mentioned files to <jedhist>
%    3. Add the following to .jedrc:
%       () = evalfile("jedhist/mini.sl");
%
%  History:
%    2006-09-21: Marko Mahnic
%      - initial version, based on mini.sl, modified to use HISTORY_Type
%    2007-02-11: Marko Mahnic
%      - mini_load_history and mini_save_history added
%
%  TODO:
%    The history list could switch automatically based on the current
%    minibuffer prompt.
%    
%    define _minibuffer_prompt_changed_hook(prompt)
%    {
%       variable hist;
%       % The regex/histname pairs could be stored in a list
%       if (0 <= string_match(prompt, "^M-x", 1)) hist = "slangname";
%       else if (0 <= string_match(prompt, "^apropos", 1)) hist = "slangname";
%       else if (0 <= string_match(prompt, "^S-Lang>", 1)) hist = "slangexpr";
%       else if (0 <= string_match(prompt, "file", 1)) hist = "filename";
%       else if (0 <= string_match(prompt, "Save as", 1)) hist = "filename";
%       else if (0 <= string_match(prompt, "Search", 1)) hist = "search";
%       else if (0 <= string_match(prompt, "Find", 1)) hist = "search";
%       else if (0 <= string_match(prompt, "Regexp", 1)) hist = "search";
%       ...
%       else hist = "default";
%       mini_use_history(hist);
%    }
%    
require("hist-cls");
require("keydefs");

% If -2, never store duplicates, use Least-Recently-Used strategy
% If -1, store only if not equal to last entered value
% If 0, never store duplicates
custom_variable ("Mini_Store_Duplicates", -2);

% Number of lines for each history table
custom_variable ("Mini_Max_History_Lines", 32);

private variable history = NULL;
private variable aHistory = NULL;

public define mini_use_history(histname)
{
   if (Mini_Max_History_Lines < 8)
      Mini_Max_History_Lines = 8;
   if (Mini_Max_History_Lines > 64)
      Mini_Max_History_Lines = 64;
   
   if (aHistory == NULL)
      aHistory = Assoc_Type[HISTORY_Type];
      
   if (histname == NULL) histname = "default";
   else
   { 
      histname = strtrans(histname, "[]", "  ");
      (,) = strreplace(histname, " ", "", strlen(histname));
      if (histname == "") histname = "default";
   }
   
   if (assoc_key_exists(aHistory, histname))
      history = aHistory[histname];
   else
   {
      history = New_History_Type(Mini_Max_History_Lines);
      history.strategy = Mini_Store_Duplicates;
      aHistory[histname] = history;
   }
}

private define mini_use_this_line ()
{
   erase_buffer ();
   insert (history.get_current_value());
}

define next_mini_command ()
{
   try history.next();
   catch AnyError: return;

   mini_use_this_line();
}

define prev_mini_command ()
{
   if (history.eohp())
      history.set_last_value(line_as_string ());
   
   try history.prev();
   catch AnyError: return;

   mini_use_this_line ();
}

public define mini_exit_minibuffer ()
{
   bol_skip_white ();
   !if (eolp ())
   {
      try 
         history.store_value (line_as_string ());
      catch AnyError: ;
   }
   call ("exit_mini");
}


public define mini_store_lines (lines)
{
   history.set_values(lines);
}

public define mini_set_lines (lines)
{
   history.set_values(lines);
}

public define mini_get_lines (num_p)
{
   return history.get_values(num_p);
}

% This function is called from site.sl AFTER jed.rc has been read but
% before other command line arguments have been parsed.
public define mini_init_minibuffer ()
{
   mini_use_history(NULL);

   variable mini = "Mini_Map";
   !if (keymap_p (mini))
      make_keymap (mini);

   definekey ("next_mini_command", Key_Down, mini);
   definekey ("prev_mini_command", Key_Up, mini);
#ifdef IBMPC_SYSTEM
   definekey ("next_mini_command", "\eOr", mini);
   definekey ("prev_mini_command", "\eOx", mini);
#else 
   definekey ("next_mini_command", "\eOB", mini);
   definekey ("prev_mini_command", "\eOA", mini);
#endif
   definekey ("mini_exit_minibuffer", "\r", mini);
   
   definekey ("exit_mini", "\e\r", mini);
   definekey ("mini_complete", "\t", mini);
   definekey ("mini_complete", " ", mini);

   % Now that we are initialized, remove this function
   eval (".() mini_init_minibuffer");
}

% Save the history to an open text file fp.
public define mini_save_history(fp)
{
   variable keys = assoc_get_keys(aHistory);
   variable lines, k, l, hist, count, not_blank;
   () = fprintf (fp, "%%%% JED: History generated by 'mini_save_history' on %s\n", time ());
   foreach (keys)
   {
      k = ();
      hist = aHistory[k];
      () = fprintf (fp, "[%s]\n", k);
      lines = hist.get_values(&count);
      
      not_blank = where (array_map (Integer_Type, &strlen, lines) > 0);
      foreach (lines [not_blank])
      {
         l = ();
         () = fprintf (fp, ".%s\n", l);
      }
   }
   () = fprintf (fp, "%%%% JED: History end\n");
}

% Load the history from an open text file fp.
public define mini_load_history(fp)
{
   variable hist, line, lines, nonblank;
   
   % recreate the array of histories
   aHistory = NULL;
   mini_use_history(NULL);
   
   % TODO: Search for History tag (eg. %% JED: History)
   hist = NULL;
   while (fgets(&line, fp) > 0)
   {
      if (line[0] == '[')
      {
         hist = strtrim(line, "[]\n\r");
         if (hist == "") hist = NULL;
         else mini_use_history(hist);
      }
      else if (hist != NULL)
      {
        if (line[0] == '.')
        {
           line = strtrim(line, "\n\r")[[1:]];
           if (line != "")
              history.store_value(line);
        }
      }
   }
   
   % use the default history
   mini_use_history(NULL);
}

