home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / eel / pntstk04.zip / POINTSTK.E < prev   
Text File  |  1991-08-12  |  14KB  |  566 lines

  1. /*
  2.  * For Epsilon version 5.0:
  3.  *
  4.  * Copyright (C) 1991, K. Shane Hartman
  5.  *
  6.  * This file is free software; you can redistribute it and/or modify
  7.  * it so long as this notice is preserved and no fee is charged (other than 
  8.  * reasonable media fees) for distribution.  You are forbidden to deny these
  9.  * rights to any other user of Epsilon.  Lugaru Software Ltd. may incorporate 
  10.  * any and all of this code into Epsilon and have all rights to
  11.  * the code, since it is only useful for Epsilon.  It would be better if 
  12.  * implemented at a lowlevel, though, rather than EEL.
  13.  *
  14.  * This file is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  17.  *
  18.  * Implements stack of points that can be pushed and popped ala Gnu Emacs 
  19.  * or Zmacs.  Also, implements registers (named points) like Gnu emacs.
  20.  *
  21.  * If POINTSTK_DONT_SUPERSEDE is NOT defined (default NOT defined), this
  22.  * file will supersede many Lugaru commands so that the point is pushed
  23.  * whenever these commands are executed.  In general, these commands are
  24.  * the ones that can take you far away from where you were (like
  25.  * goto-end, pluck-tag, etc.).  To go back to where you were you can just
  26.  * do C-u Alt-Space (or M-x pop-point).
  27.  *
  28.  * If POINTSTK_VERBOSE is defined (default NOT defined), then you will be
  29.  * told in the echo area every time the point has been pushed or popped.
  30.  * Otherwise, the commands are quiet (except for explicit push or pop
  31.  * point commands).
  32.  *
  33.  * Registers are like bookmarks.  You use C-x S (set-register) to remember
  34.  * a position and a buffer (where you are when the command is issued).  You
  35.  * are prompted for a single character name ('A' - 'Z').  C-x J (jump-register)
  36.  * can be used to return to the remembered position (C-x J Z would return
  37.  * to the location stored in register Z.
  38.  * 
  39.  * Also note the commented command M-x edit-registers.
  40.  *
  41.  *
  42.  * Revison History: for epsilon 5.0
  43.  * Send bug fixes, comments or suggestions to shane@ai.mit.edu.
  44.  *
  45.  * Version 1.2: 07/17/91 shane@ai.mit.edu distributed
  46.  * Version 1.3: 08/02/91 shane@ai.mit.edu Offer Lugaru rights to the code.
  47.  * Version 1.4: 08/09/91 johnk@wrq.com (John Kercheval) add automatic pushes
  48.  *         for several key functions.  Move push and pop messages to
  49.  *         push_or_pop_point to prevent unwanted messages during
  50.  *         processing.  Make pop_point and push_point commands so they
  51.  *         are bindable. 
  52.  *              08/12/91 shane@ai.mit.edu Integrated these
  53.  *         changes and added conditionals to control the verbose messages
  54.  *         and superceding of routines (POINTSTK_DONT_SUPERSEDE,
  55.  *         POINTSTK_VERBOSE).  The default behavior is to add automatic
  56.  *         pushes and do them quietly as described above.
  57.  *
  58.  */
  59.  
  60. #include "eel.h"
  61.  
  62. /*
  63.  * POINT STACK
  64.  */
  65.  
  66. #define STACK_DEPTH 32                  /* Maximum stack depth */
  67.  
  68. typedef struct selt
  69. {
  70.   int spot;
  71.   char *buff;
  72. } SELT;
  73.  
  74. SELT point_stack[STACK_DEPTH];          /* Points are saved here */
  75.  
  76. int stackp = 0;
  77.  
  78. /*
  79.  * REGISTERS
  80.  */
  81.  
  82. typedef struct reg
  83. {
  84.   int *spot;
  85.   char *buff;
  86. } REGISTER;
  87.  
  88. #define REGCOUNT 26
  89.  
  90. REGISTER registers[REGCOUNT];
  91.  
  92. /*
  93.  * Initialization
  94.  */
  95.  
  96. init_point_stack()
  97. {
  98.   int i;
  99.   
  100.   for (i = 0; i < REGCOUNT; i++)
  101.   {
  102.     registers[i].buff = 0;
  103.     registers[i].spot = 0;
  104.   }
  105.   for (i = 0; i < STACK_DEPTH; i++)
  106.   {
  107.     point_stack[i].spot = 0;
  108.     point_stack[i].buff = 0;    
  109.   }
  110.   stackp = 0;
  111.  
  112. #ifndef POINTSTK_DONT_SUPERSEDE  
  113.  
  114.   /*
  115.    * function name replacements for pointstk sensitive functions
  116.    */
  117.  
  118.   if (!find_index ("old_goto_end"))
  119.     replace_name ("goto_end", "old_goto_end");
  120.   else
  121.     drop_name ("goto_end");
  122.   replace_name ("pstk_goto_end", "goto_end");
  123.   
  124.   if (!find_index ("old_goto_beginning"))
  125.     replace_name ("goto_beginning", "old_goto_beginning");
  126.   else
  127.     drop_name ("goto_beginning");
  128.   replace_name ("pstk_goto_beginning", "goto_beginning");
  129.   
  130.   if (!find_index ("old_pluck_tag"))
  131.     replace_name ("pluck_tag", "old_pluck_tag");
  132.   else
  133.     drop_name ("pluck_tag");
  134.   replace_name ("pstk_pluck_tag", "pluck_tag");
  135.   
  136.   if (!find_index ("old_goto_tag"))
  137.     replace_name ("goto_tag", "old_goto_tag");
  138.   else
  139.     drop_name ("goto_tag");
  140.   replace_name ("pstk_goto_tag", "goto_tag");
  141.   
  142.   if (!find_index ("old_regex_search"))
  143.     replace_name ("regex_search", "old_regex_search");
  144.   else
  145.     drop_name ("regex_search");
  146.   replace_name ("pstk_regex_search", "regex_search");
  147.   
  148.   if (!find_index ("old_incremental_search"))
  149.     replace_name ("incremental_search", "old_incremental_search");
  150.   else
  151.     drop_name ("incremental_search");
  152.   replace_name ("pstk_incremental_search", "incremental_search");
  153.   
  154.   if (!find_index ("reverse_incremental_search"))
  155.     replace_name ("reverse_incremental_search", "old_reverse_incremental_search");
  156.   else
  157.     drop_name ("reverse_incremenatal_search");
  158.   replace_name ("pstk_reverse_incremental_search", "reverse_incremental_search");
  159.   
  160.   if (!find_index ("old_reverse_regex_search"))
  161.     replace_name ("reverse_regex_search", "old_reverse_regex_search");
  162.   else
  163.     drop_name ("reverse_regex_search");
  164.   replace_name ("pstk_reverse_regex_search", "reverse_regex_search");
  165.   
  166.   if (!find_index ("old_reverse_string_search"))
  167.     replace_name ("reverse_string_search", "old_reverse_string_search");
  168.   else
  169.     drop_name ("reverse_string_search");
  170.   replace_name ("pstk_reverse_string_search", "reverse_string_search");
  171.   
  172.   if (!find_index ("old_string_search"))
  173.     replace_name ("string_search", "old_string_search");
  174.   else
  175.     drop_name ("string_search");
  176.   replace_name ("pstk_string_search", "string_search");
  177.   
  178.   if (!find_index ("old_start_process"))
  179.     replace_name ("start_process", "old_start_process");
  180.   else
  181.     drop_name ("start_process");
  182.   replace_name ("pstk_start_process", "start_process");
  183.   
  184.   if (!find_index ("old_goto_line"))
  185.     replace_name ("goto_line", "old_goto_line");
  186.   else
  187.     drop_name ("goto_line");
  188.   replace_name ("pstk_goto_line", "goto_line");
  189.   
  190.   if (!find_index ("old_find_file"))
  191.     replace_name ("find_file", "old_find_file");
  192.   else
  193.     drop_name ("find_file");
  194.   replace_name ("pstk_find_file", "find_file");
  195.   
  196.   if (!find_index ("old_visit_file"))
  197.     replace_name ("visit_file", "old_visit_file");
  198.   else
  199.     drop_name ("visit_file");
  200.   replace_name ("pstk_visit_file", "visit_file");
  201.   
  202.   if (!find_index ("old_make"))
  203.     replace_name ("make", "old_make");
  204.   else
  205.     drop_name ("make");
  206.   replace_name ("pstk_make", "make");
  207.   
  208.   if (!find_index ("old_next_error"))
  209.     replace_name ("next_error", "old_next_error");
  210.   else
  211.     drop_name ("next_error");
  212.   replace_name ("pstk_next_error", "next_error");
  213.  
  214. #endif  /* POINTSTK_DONT_SUPERSEDE */
  215. }
  216.  
  217. /*
  218.  * Functions with added support for point stack.  These "wrappers" push
  219.  * the point stack and then execute the old command (courtesy of John
  220.  * Kercheval).  This way, you don't have to modify all the Lugaru code to
  221.  * push the point stack.  Since I (shane) have already done so, I have
  222.  * conditionalized the code so that if POINTSK_DONT_SUPERSEDE is defined,
  223.  * this will not occur.  Most users will probably want to leave
  224.  * POINTSK_DONT_SUPERSEDE undefined (unless you have already changed all
  225.  * the Lugaru code as I have done).
  226.  *
  227.  * There is one advantage to modifying Lugaru code: these superseded commands
  228.  * push the point even if the original command is aborted (or fails).  If you
  229.  * modify Lugaru code, you can insert calls to do_push_point at exactly the
  230.  * right place.  Given the hassle of maintaining changes between releases of
  231.  * Epsilon, the approach below is probably better.
  232.  */
  233.  
  234. #ifndef POINTSTK_DONT_SUPERSEDE
  235.  
  236. pstk_goto_end() {
  237.   push_point();
  238.   old_goto_end();
  239. }
  240. pstk_goto_beginning() {
  241.   push_point();
  242.   old_goto_beginning();
  243. }
  244. pstk_pluck_tag() {
  245.   push_point();
  246.   old_pluck_tag();
  247. }
  248. pstk_goto_tag() {
  249.   push_point();
  250.   old_goto_tag();
  251. }
  252. pstk_regex_search() {
  253.   push_point();
  254.   old_regex_search();
  255. }
  256. pstk_incremental_search() {
  257.   push_point();
  258.   old_incremental_search();
  259. }
  260. pstk_reverse_incremental_search() {
  261.   push_point();
  262.   old_reverse_incremental_search();
  263. }
  264. pstk_reverse_regex_search() {
  265.   push_point();
  266.   old_reverse_regex_search();
  267. }
  268. pstk_reverse_string_search() {
  269.   push_point();
  270.   old_reverse_string_search();
  271. }
  272. pstk_string_search() {
  273.   push_point();
  274.   old_string_search();
  275. }
  276. pstk_start_process() {
  277.   push_point();
  278.   old_start_process();
  279. }
  280. pstk_goto_line() {
  281.   push_point();
  282.   old_goto_line();
  283. }
  284. pstk_find_file() {
  285.   push_point();
  286.   old_find_file();
  287. }
  288. pstk_visit_file() {
  289.   push_point();
  290.   old_visit_file();
  291. }
  292. pstk_make() {
  293.   push_point();
  294.   old_make();
  295. }
  296. pstk_next_error() {
  297.   push_point();
  298.   old_next_error();
  299. }
  300.  
  301. #endif                                  /* POINTSTK_DONT_SUPERSEDE */
  302.  
  303. when_loading()
  304. {
  305.   init_point_stack();
  306. }
  307.  
  308. /*************
  309.  * Point Stack
  310.  */
  311.  
  312. do_push_point(bpoint, bname)
  313. int bpoint;
  314. char *bname;
  315. {
  316.   if (stackp == (STACK_DEPTH - 1))
  317.   {
  318.     int i;
  319.     
  320.     if (point_stack[0].buff)
  321.       free (point_stack[0].buff);
  322.     for (i = 1; i < STACK_DEPTH; i++)
  323.     {
  324.       point_stack[i - 1].buff = point_stack[i].buff;
  325.       point_stack[i - 1].spot = point_stack[i].spot;
  326.     }
  327.     stackp--;
  328.   }
  329.   point_stack[stackp].spot = bpoint;
  330.   point_stack[stackp].buff = malloc (strlen (bname) + 1);
  331.   strcpy (point_stack[stackp].buff, bname);
  332.   stackp++;
  333. #ifdef POINTSTK_VERBOSE
  334.   say ("Point pushed.");
  335. #endif  
  336. }
  337.  
  338. command push_point()
  339. {
  340.   do_push_point (point, bufname);
  341. }
  342.  
  343. command pop_point()
  344. {
  345.   int i;
  346.  
  347. tail_recurse:
  348.   if (stackp > 0 && point_stack[--stackp].buff)
  349.   {
  350.     if (!exist (point_stack[stackp].buff))
  351.     {
  352.       free (point_stack[stackp].buff);
  353.       point_stack[stackp].buff = 0;
  354.       goto tail_recurse;
  355.     }
  356.     to_buffer (point_stack[stackp].buff);
  357.     point = point_stack[stackp].spot;
  358.     free (point_stack[stackp].buff);
  359.     point_stack[stackp].buff = 0;
  360.     point_stack[stackp].spot = 0;
  361. #ifdef POINTSTK_VERBOSE
  362.     say ("Point popped");
  363. #endif    
  364.   }
  365.   else 
  366.   {
  367.     stackp = 0;
  368.     ding ();
  369.   }
  370. }
  371.  
  372. /* 
  373.  * With argument pops the stack and moves you there
  374.  * With no argument, saves the point and buffer name on the stack 
  375.  */
  376. command
  377. push_or_pop_point() on reg_tab[ALT(' ')]
  378. {
  379.   if (has_arg)
  380.   {
  381.     iter = 0;
  382.     if (stackp > 0)
  383.     {
  384.       pop_point ();
  385. #ifndef POINTSTK_VERBOSE
  386.       say ("Point popped.");
  387. #endif
  388.     }
  389.     else
  390.       exchange_point_and_mark ();
  391.   }
  392.   else
  393.   {
  394.     mark = point;
  395.     push_point ();
  396. #ifndef POINTSTK_VERBOSE
  397.     say ("Point pushed");
  398. #endif    
  399.   }
  400. }
  401.  
  402. /***********
  403.  * Registers
  404.  */
  405.  
  406. clear_register(reg)
  407. REGISTER *reg;
  408. {
  409.   if (reg->buff)
  410.   {
  411.     free (reg->buff);
  412.     reg->buff = 0;
  413.   }
  414.   if (reg->spot)
  415.   {
  416.     free_spot (reg->spot);
  417.     reg->spot = 0;
  418.   }
  419. }
  420.  
  421. command
  422. set_register() on cx_tab['s']
  423. {
  424.   char k;
  425.   int reg;
  426.   
  427.   say ("Set Register: ");
  428.   term_position (14, 24);
  429.   k = getkey ();
  430.   if (k == abort_key) 
  431.     error ("Aborted");
  432.   reg = toupper (k);
  433.   reg -= 'A';
  434.   if (reg < 0 || reg >= REGCOUNT)
  435.     error ("Invalid register: %c", (char) k);
  436.   clear_register (®isters[reg]);
  437.   registers[reg].buff = malloc (strlen (bufname) + 1);
  438.   strcpy (registers[reg].buff, bufname);
  439.   registers[reg].spot = alloc_spot ();
  440.   say ("Set register %c", (char) (reg + 'A'));
  441. }
  442.  
  443. jump_register_1(k)
  444. char k;
  445. {
  446.   int reg = toupper (k);
  447.  
  448.   reg -= 'A';
  449.   if (reg >= 0 && reg < REGCOUNT)
  450.   {
  451.     if (registers[reg].buff && registers[reg].spot)
  452.     {
  453.       if (exist (registers[reg].buff))
  454.       {
  455.         to_buffer (registers[reg].buff);
  456.         point = *registers[reg].spot;
  457.         say ("");
  458.         return;
  459.       }
  460.       clear_register (®isters[reg]);
  461.     }
  462.   }
  463.   error ("Invalid register: %c", (char) k);
  464. }
  465.  
  466. command
  467. jump_register() on cx_tab['j']
  468. {
  469.   char k;
  470.   int reg;
  471.   
  472.   say ("Jump Register: ");
  473.   term_position (15, 24);
  474.   k = getkey ();
  475.   if (k == abort_key) 
  476.     error ("Aborted");
  477.   jump_register_1 (k);
  478. }
  479.  
  480. /*
  481.  * I dont use this but its ok.  It gives a buffer list of bookmarks and
  482.  * lets you select one.  M-x edit-registers.
  483.  *
  484.  */
  485.  
  486. #ifdef WANT_EDIT_REGISTERS
  487. reged_jump()
  488. {
  489.   jump_register_1 (key);
  490. }
  491.  
  492. keytable reged_tab;
  493.  
  494. when_loading()
  495. {
  496.     int i;
  497.  
  498.     for (i = 0; i < NUMKEYS; i++)
  499.   {
  500.     reged_tab[i] = -1;
  501.     }
  502.   for (i = 'a'; i <= 'z'; i++)
  503.   {
  504.     reged_tab[i] = (short) reged_jump;
  505.     reged_tab[i + 'A' - 'a'] = (short) case_indirect;
  506.   }
  507. }
  508.  
  509. char reged_mode_name[] = "Registers";
  510.  
  511. command edit_registers() on cx_tab[CTRL('J')]
  512. {
  513.   int i;
  514.   int valid = 0;
  515.   char *obufname = bufname;
  516.   
  517.   zap ("*Registers*");
  518.   bufname = "*Registers*";
  519.     mode_keys = reged_tab;
  520.     major_mode = reged_mode_name;
  521.     make_mode ();
  522.   for (i = 0; i < REGCOUNT; i++)
  523.   {
  524.     if (registers[i].buff && registers[i].spot && exist (registers[i].buff))
  525.     {
  526.       char line[60];
  527.       int opoint;
  528.       int start;
  529.       int end;
  530.       
  531.       bufname = registers[i].buff;
  532.       opoint = point;
  533.       start = point = *registers[i].spot;
  534.       to_end_line();
  535.       end = point;
  536.       if (end - start >= sizeof (line))
  537.         end = start + sizeof (line) - 1;
  538.       grab (start, end, line);
  539.       point = opoint;
  540.       bufname = "*Registers*";
  541.       bprintf ("%c: %s\n", (char) ('A' + i), line);
  542.       valid++;
  543.     }
  544.   }
  545.   bufname = obufname;
  546.   if (valid)
  547.   {
  548.     char k;
  549.  
  550.     view_buffer ("*Registers*");
  551.     k = getkey ();
  552.     k = (char) toupper (k);
  553.     if (k >= 'A' && k <= 'Z')
  554.       jump_register_1 (k);
  555.   }
  556.   else
  557.   {
  558.     say ("No registers set");
  559.     ding ();
  560.   }
  561.   delete_buffer ("*Registers*");    
  562. }
  563. #endif
  564.  
  565.  
  566.