jed-users mailing list

[2002 Date Index] [2002 Thread Index] [Other years]
[Thread Prev] [Thread Next]      [Date Prev] [Date Next]

[no subject]


On Fri, 8 Mar 2002, Guenter Milde wrote:

> this time I have a small patch for search.sl, that makes the replacement
> command behave more user-friendly (IMHO):
>
>   If a region is defined, it is suggested as "string to be replaced"
>
>   If no region is define, the word under the cursor is suggested as "string
>   to be replaced"
>
> Saves me a lot of keypresses.


Fine.

But still more could (and should) be done to improve the user-friendliness
of the search and replace parts of Jed (I think).
Many of us who grew up with Borland editors still remember how easy it was
to toggle between doing

               search  or  replace,
in direction
               forwards or backwards
for
    strings  or  words   or  regular expressions


Some time ago I tried to write improved search and replace functions called
searchx and replacex.

searchx can do forward and backward searching.
(replacex is forwards only.)
The function searchx_toggle which toggles between "strings", "words" and
"regexps".
The function repeat_searchx repeats the last operation, whether it was
searching or replacing.

The code could probably be better, but it seems to work.




JL

-- 
Jørgen Larsen          http://dirac.ruc.dk/~jl/

 "Musica est exercitium arithmeticae occultum
  nescientis se numerare animi."   -- Leibniz
% searchx.sl        -*- SLang -*-
%  
% extended search and replace functions for Jed.
% 
% Jørgen Larsen <jl@xxxxxxxxxxxx>   2002
% 
% Defines the following public functions:
%    searchx  :  searchx(1) = search forward,  searchx(-1) = search backward
%    replacex :  a replace function
%    repeat_searchx :  repeat last operation (search or replace)
%    searchx_toggle :  toggles between operating on words, strings and regular expressions.


% Key bindings in IDE mode:
% 
% setkey ("searchx (1)", "^QF");
% setkey ("searchx (1)", "^Q^F");
% setkey ("searchx (-1)", "^Qf");
% setkey ("searchx_toggle", "^Q^L");
% setkey ("searchx_toggle", "^QL");
% setkey ("repeat_searchx", "^L");
% setkey ("replacex", "^Q^A"); 
% setkey ("replacex", "^QA"); 


require ("regexp");
autoload ("search_search_function", "search");
autoload ("replace_do_replace", "search");

%% Internal constants - not to be changed:
variable
  WORD_TARGET = 0, STRING_TARGET = 1, REGEXP_TARGET = 2,
  FORWARD = 1, BACKWARD = -1,
  SEARCH_OPERATION = 0, REPLACE_OPERATION = 1,
  LAST_REPLACE;

%% Some names used in the user dialog.
variable Targetnamelist = "Word,String,RegExp";
variable Targetname = strtok (Targetnamelist, ",");

%% The variables  Current_*  hold current settings.
%% Here they are assigned default values.
variable
  Current_Direction = FORWARD,
  Current_Target = STRING_TARGET,
  Current_Operation = SEARCH_OPERATION;



static define get_region_or_word ()
{
   if (markp ())
     {
        check_region (0);
        exchange_point_and_mark (0);
        bufsubstr ();   % this is the return value
     }
   else
     {
        bskip_word_chars ();
        if (Current_Direction == FORWARD) push_spot ();
        push_mark ();
        skip_word_chars ();
        if (Current_Direction == BACKWARD) push_spot ();
        bufsubstr ();    % this is the return value
        pop_mark_0 ();
        pop_spot ();
     }
}


public define searchx (direc)
{
   Current_Operation = SEARCH_OPERATION;
   Current_Direction = direc;
   variable not_found = 1, pat = get_region_or_word ();
  % !if (strlen (pat)) pat = LAST_SEARCH;

   variable direc_name = "forward";
   if (Current_Direction == BACKWARD) direc_name = "backward";

   pat = read_mini (strcat ("Search ", direc_name, " for ", Targetname[Current_Target], ":"), Null_String, pat);

   !if (strlen (pat)) return;

   if (Current_Target == WORD_TARGET) pat = strcat ("\\<", pat, "\\>");
   save_search_string (pat);

   push_mark();
   ERROR_BLOCK
     {
	pop_mark (not_found);
     }

   if (Current_Target == STRING_TARGET)
     {
        if (Current_Direction == FORWARD)
          not_found = not fsearch (pat);
        else
          not_found = not bsearch (pat);
     }
   else % search for word or regexp.
     not_found = not (search_maybe_again (&re_search_dir, pat,
                                          Current_Direction,
                                          &_function_return_1));

   if (not_found) error ("Not found.");
   EXECUTE_ERROR_BLOCK;
}

% This is a slightly modified version of  replace_with_query  (from srchmisc.sl)
% wd_replace_with_query  replaces words.
static define wd_replace_with_query (search_fun, pat, rep, query, rep_fun)
{
   variable n, prompt, doit, err, ch, pat_len;
   variable undo_stack_type = struct
     {
        rep_len,
          prev_string,
          user_mark,
          next
     };
   variable undo_stack = NULL;
   variable tmp;

   prompt =  sprintf ("Replace word '%s' with '%s'? (y/n/!/+/q/h)", pat, rep);
   pat = strcat ("\\<", pat, "\\>");

   while (pat_len = @search_fun (pat), pat_len >= 0)
     {
	!if (query)
	  {
	     tmp = create_user_mark ();
	     () = @rep_fun (rep, pat_len);
	     if (tmp == create_user_mark ())
	       go_right_1 ();
	     continue;
	  }

	do
	  {
	     message(prompt);
	     mark_next_nchars (pat_len, -1);

	     ch = getkey ();
	     if (ch == 'r')
	       {
		  recenter (window_info('r') / 2);
	       }

	  }
        while (ch == 'r');

	switch(ch)
	  { case 'u' and (undo_stack != NULL) :
	     goto_user_mark (undo_stack.user_mark);
	     push_spot ();
	     () = @rep_fun (undo_stack.prev_string, undo_stack.rep_len);
	     pop_spot ();
	     undo_stack = undo_stack.next;
	  }
	  { case 'y' :
	     tmp = @undo_stack_type;
	     tmp.next = undo_stack;
	     undo_stack = tmp;

	     push_spot(); push_mark ();
	     go_right (pat_len); undo_stack.prev_string = bufsubstr ();
	     pop_spot ();
	     undo_stack.user_mark = create_user_mark ();
	     undo_stack.rep_len  = @rep_fun (rep, pat_len);
	  }
	  { case 'n' : go_right_1 ();}
	  { case '+' : () = @rep_fun (rep, pat_len);
             break;
	  }
	  { case '!' :
	     query = 0;
	  }
          { case 'q' : break; }
          {
	     flush ("y:replace, n:skip, !:replace all, u: undo last, +:replace then quit, q:quit");
	     () = input_pending (30);
	  }
     }
}


public define replacex ()
{
   Current_Operation = REPLACE_OPERATION;

   push_mark ();

   variable not_found = 1;
   ERROR_BLOCK
     {
	pop_mark (not_found);
     }

   variable rep, pat = get_region_or_word ();
   % !if (strlen (pat)) pat = LAST_SEARCH;

   pat = read_mini (strcat ("Replace ",  Targetname[Current_Target], ":"), Null_String, pat);
   rep = read_mini (strcat ("  replace '", pat, "' with:"), Null_String, Null_String);

   !if (strlen (pat)) error ();

   save_search_string (pat);
   LAST_REPLACE = rep;

   if (Current_Target == WORD_TARGET)
     wd_replace_with_query (&research_search_function, pat, rep, 1, &re_replace_function);
   else
     if (Current_Target == REGEXP_TARGET)
       replace_with_query (&research_search_function, pat, rep, 1, &re_replace_function);
   else
        replace_with_query (&search_search_function, pat, rep, 1, &replace_do_replace);

   message ("Done.");
   EXECUTE_ERROR_BLOCK;
}


% repeat the last operation, whatever it was.
public define repeat_searchx ()
{
   if (Current_Operation == REPLACE_OPERATION)
     {
        switch (Current_Target)
          { case WORD_TARGET :
             wd_replace_with_query (&research_search_function, LAST_SEARCH, LAST_REPLACE, 1, &re_replace_function);
          }
          { case REGEXP_TARGET :
             replace_with_query (&research_search_function, LAST_SEARCH, LAST_REPLACE, 1, &re_replace_function);
          }
          { % case STRING_TARGET :
             replace_with_query (&search_search_function, LAST_SEARCH, LAST_REPLACE, 1, &replace_do_replace);
          }
     }
   else % Current_Operation == SEARCH_OPERATION 
     if (Current_Direction == FORWARD)
       {
          go_right_1 ();
          if (Current_Target == STRING_TARGET)
            {!if (fsearch (LAST_SEARCH)) error ("Not found.");}
          else
            !if (re_fsearch (LAST_SEARCH)) error ("Not found.");
       }
   else % Current_Direction == BACKWARD
     {
        go_left_1 ();
        if (Current_Target == STRING_TARGET)
          {!if (bsearch (LAST_SEARCH)) error ("Not found.");}
        else
          !if (re_bsearch (LAST_SEARCH)) error ("Not found.");
     }
}


public define searchx_toggle ()
{
   variable a;
   a =  read_string_with_completion ("Search for which target (Word/String/Regexp):", 
                                     Targetname [Current_Target], Targetnamelist );
   if (strlen (a))
     switch (toupper (a[0]))
       { case 'W' : Current_Target = WORD_TARGET;
       }
     { case 'S' : Current_Target = STRING_TARGET;
     }
     { case 'R' : Current_Target = REGEXP_TARGET;
     };
   message ( strcat ( "Current target is ", Targetname [Current_Target]));
}

provide ("searchx");


[2002 date index] [2002 thread index]
[Thread Prev] [Thread Next]      [Date Prev] [Date Next]