home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / AP / JED / JED097-1.TAR / jed / src / cmds.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-12  |  30.4 KB  |  1,461 lines

  1. /*
  2.  *  Copyright (c) 1992, 1994 John E. Davis  (davis@amy.tch.harvard.edu)
  3.  *  All Rights Reserved.
  4.  */
  5. #include <stdio.h>
  6. #include <string.h>
  7.  
  8. #include "config.h"
  9. #include "slang.h"
  10. #include "buffer.h"
  11. #include "screen.h"
  12. #include "window.h"
  13. #include "ins.h"
  14. #include "ledit.h"
  15. #include "cmds.h"
  16. #include "line.h"
  17. #include "paste.h"
  18. #include "display.h"
  19. #include "vterm.h"
  20. #include "sysdep.h"
  21. #include "text.h"
  22. #include "file.h"
  23. #include "misc.h"
  24. #include "search.h"
  25. #include "hooks.h"
  26. #include "abbrev.h"
  27.  
  28. void (*X_Suspend_Hook)(void);
  29.  
  30. int Blink_Flag = 1;
  31. int Indented_Text_Mode = 0;           /* if non zero, intent line after wrap */
  32. int Kill_Line_Feature = 1;           /* non-zero means kill through eol if bolp  */
  33. int C_Bra_Newline = 1;               /* if zero, do not insert newline before '{' */
  34.  
  35. int C_Comment_Hint;
  36.  
  37.  
  38. static char *Top_Of_Buffer_Error = "Top Of Buffer.";
  39. static char *End_Of_Buffer_Error = "End Of Buffer.";
  40.  
  41. /* return 1 if line extends beyond the screen */
  42. int long_line(void)
  43. {
  44.     int p, col;
  45.  
  46.     col = Screen_Col;
  47.     p = Point;
  48.     Point = CLine->len - 1;
  49.     if ((*(CLine->data + Point) != '\n') || (CBuf == MiniBuffer)) Point++;
  50.     if (calculate_column() >= JWindow->width - 1)
  51.       {
  52.       Point = p;
  53.       Screen_Col = col;
  54.       return(1);
  55.       }
  56.     Screen_Col = col;
  57.     Point = p;
  58.     return(0);
  59. }
  60.  
  61. #define FAST_NOT_OK ((Repeat_Factor != NULL) || JWindow->trashed\
  62.         || (ch < ' ') || (ch > 126) || Input_Buffer_Len\
  63.     || Suspend_Screen_Update\
  64.         || (Screen_Col >= JWindow->width - 2) || (JWindow->column > 1)\
  65.     || Batch || (CLine->len == 0)\
  66.     || ((CBuf->marks != NULL) && Wants_Attributes)\
  67.     || input_pending(&Number_Zero) || Executing_Keyboard_Macro\
  68.         || tabs_present()\
  69.     || (Read_This_Character != NULL))
  70.  
  71. /* This routine moves CLine and point to the matching '{' or whatever.  It
  72.  *  returns 1 if it lies outside the screen, 0 if inside and -1 if not found
  73.  *  and -2 if it looked back for more than count lines and not found.  It
  74.  *  can get messed up if there are delimeters in comments unless they are
  75.  *  properly enclosed like the above---- Later I will add a find matching
  76.  *  forward function, then I will search back for the beginning comment
  77.  *  and go from there.
  78.  */
  79. /* count is the number of lines to go back and shift is distance back to
  80.    start searching from. (usually 0, 1, or 2) */
  81. int find_matching(char ch, int count, int shift)
  82. {
  83.    int slash, ret = 0;
  84.    int lang = ! (CBuf->modes & WRAP_MODE), inc = 0, lang_and_not_inc;
  85.    register int n = 1, in;
  86.    register unsigned char *p, starp, *cline_data;
  87.    unsigned char *prev, *p1;
  88.    char ch1, save;
  89.    char quote = '\\';
  90.    char cb1 = '/', cb2 = '*', ce1 = '*', ce2  = '/';
  91.    
  92.    
  93.  
  94.     ch1 = '(';
  95.     if (ch == '}') ch1 = '{'; else if (ch == ']') ch1 = '[';
  96.  
  97.     p = CLine->data + Point - shift;
  98.     if (p < CLine->data)
  99.       {
  100.           if (CLine->prev == NULL) return(-1);
  101.           if (CLine == JWindow->beg.line) ret = 1;
  102.           CLine = CLine->prev; LineNum--;
  103.       p = CLine->data + (CLine->len - 1);
  104.        }
  105.      in = 0;
  106.    /* if (Point > 1) prev = p - 1; else prev = p; */
  107.    prev = p;
  108.    lang_and_not_inc = lang;
  109.    
  110.    cline_data = CLine->data;
  111.  
  112.     while(count)
  113.       {
  114.      p1  = p - 1;
  115.      starp = *p;
  116.      if ((starp <= '\'') && (starp >= '"')
  117.          && ((starp == '\'') || (starp == '"')) && lang_and_not_inc)
  118.        {
  119.           slash = 0;
  120.           save = starp;
  121.           while((p > cline_data) && (*(p - 1) == (unsigned char) quote))
  122.         {
  123.            p--;
  124.            slash = !slash;
  125.         }
  126.  
  127.           if (!slash)
  128.         {
  129.            if (in == 0) in = save; else if (in == save) in = 0;
  130.         }
  131.        }
  132.      
  133.           
  134.           if (!in)
  135.             {
  136.            /* This is specific to C.  I need to generalize to other languages. */
  137.            if ((ce2 == (char) *p) && (p > cline_data)
  138.            && (*p1 == (unsigned char) ce1) && lang)
  139.          {
  140.             p = p1;
  141.             inc = 1;
  142.             lang_and_not_inc = 0;
  143.          }
  144.            else if ((cb2 == (char) *p) && (p > cline_data)
  145.            && (*p1 == (unsigned char) cb1) && lang)
  146.          {
  147.             if (inc == 0) 
  148.               {
  149.              Point = (int) (p1 - cline_data);
  150.              return (-2);
  151.               }
  152.             p = p1;
  153.             inc = 0;
  154.             lang_and_not_inc = lang;
  155.          }
  156.            starp = *p;
  157.            if (!inc && ((starp == '[') || (starp == '{') || (starp == '('))) n--;
  158.            else if (!inc && ((starp == '}') || (starp == ']') || (starp == ')'))) n++;
  159.             }
  160.  
  161.      if (!n) break;
  162.      if (p == cline_data)
  163.        {
  164.           if (CLine == JWindow->beg.line) ret = 1;
  165.           if (CLine->prev == NULL) break;
  166.           CLine = CLine->prev;
  167.           count--; LineNum--;
  168.           p = CLine->data + (CLine->len - 1);
  169.           cline_data = CLine->data;
  170.        }
  171.           else p--;
  172.       }
  173.     Point = (int) (p - CLine->data);
  174.     if ((n == 0) && (*p == (unsigned char) ch1)) return(ret);
  175.     if (lang) if ((*prev == '\'') || (*prev == '"')) return(-2);
  176.     return(-1);
  177. }
  178.  
  179. /* blink the matching fence.  This assumes that the window is ok */
  180. void blink_match(char ch)
  181. {
  182.    Line *save;
  183.    int pnt, code, matchp;
  184.    unsigned int l;
  185.    char buf[600], strbuf[256];
  186.  
  187.    if (!Blink_Flag || (Repeat_Factor != NULL) || Batch) return;
  188.    if (JWindow->trashed) update((Line *) NULL, 0, 0);
  189.    if (JWindow->trashed) return;
  190.    pnt = Point;
  191.    save = CLine;
  192.    l = LineNum;
  193.    code = find_matching(ch, 500, 2);
  194.    if (code == -1)
  195.      {
  196.     if ((! (CBuf->modes == WRAP_MODE)) && (!IS_MINIBUFFER)) message("Mismatch??");
  197.      }
  198.    else if (code == 0)
  199.      {
  200.     /* update((Line *) NULL, 0, 0); */
  201.     point_cursor(0);
  202.     input_pending(&Number_Ten);   /* sleep((unsigned) 1); */
  203.     Point = pnt;
  204.     CLine = save;
  205.     LineNum = l;
  206.     point_cursor(0);
  207.     return;
  208.      }
  209.    else if (code == 1)
  210.      {
  211.     matchp = Point;
  212.     Point = 0;
  213.     strcpy(buf, "Matches ");
  214.     skip_whitespace();
  215.     if ((matchp == Point) && prevline(&Number_One))
  216.       {
  217.          Point = 0;
  218.          strcat(buf, make_line_string(strbuf));
  219.          nextline(&Number_One);
  220.          Point = 0;
  221.       }
  222.     strcat(buf, make_line_string(strbuf));
  223.     message(buf);
  224.      }
  225.    Point = pnt;
  226.    CLine = save;
  227.    LineNum = l;
  228. }
  229.  
  230. int goto_match()
  231. {
  232.     char *p;
  233.     Line *save;
  234.     int pnt, code;
  235.    unsigned int l;
  236.    
  237.     p = (char *) (CLine->data + Point);
  238.     if ((*p != ')') && (*p != '}') && (*p != ']')) return(0);
  239.     save = CLine;
  240.     pnt = Point;
  241.    l = LineNum;
  242.     code = find_matching(*p, -1, 1);  /* -1 since we want to shif back 1 */
  243.     if (code == -1)
  244.       {
  245.      if (!IS_MINIBUFFER) msg_error("Mismatch!!");
  246.      CLine = save;
  247.      Point = pnt;
  248.      LineNum = l;
  249.      return(0);
  250.       }
  251.     return(1);
  252. }
  253.  
  254.  
  255. int newline()
  256. {
  257.    int push = 0;
  258.    CHECK_READ_ONLY
  259.    
  260.    if (CBuf == MiniBuffer) return exit_minibuffer();
  261.    
  262.    /* This bit of nonsense gives a better looking screen update */
  263.    if (bolp() && (CLine->prev != NULL) && (CLine->len > 1))
  264.       {
  265.           push = 1;
  266.           push_spot();
  267.           CLine = CLine->prev;
  268.      LineNum--;
  269.       Point = 0;
  270.           eol();
  271.       } 
  272.  
  273.     split_line();
  274.     ins('\n');
  275.    check_line();
  276.     if (push)
  277.       {
  278.           pop_spot();
  279.           return(1);
  280.       }
  281.  
  282.     Point--;
  283.     forwchars(&Number_One);
  284.     return(1);
  285. }
  286.  
  287. int previous_char_cmd()
  288. {
  289.    int pnt;
  290.    Cursor_Motion = 1;
  291.    if (bobp())
  292.      {
  293.     msg_error(Top_Of_Buffer_Error);
  294.     return(0);
  295.      }
  296.  
  297.    pnt = Point - 1;
  298.    backwchars(&Number_One);
  299.    Goal_Column = calculate_column();
  300.       /* For syntax highlighting */
  301.    if ((Last_Key_Function != (VOID *) previous_char_cmd) &&
  302.        ((Last_Key_Function == (VOID *) ins_char_cmd)
  303.        || (Last_Key_Function == (VOID *) delete_char_cmd)
  304.        || (Last_Key_Function == (VOID *) backward_delete_char_cmd)
  305.        || (Last_Key_Function == (VOID *) backward_delete_char_untabify)))
  306.      register_change(0);
  307.  
  308.    return (pnt == -1) || JWindow->trashed;
  309. }
  310.  
  311. /* Slang calls by reference so make this a pointer ! */
  312. void insert_whitespace(int *n)
  313. {
  314.    int tab = Buffer_Local.tab;
  315.    int c1, c2, i, k, nspace;
  316.  
  317.    if ((nspace = *n) <= 0) return;
  318.    CHECK_READ_ONLY_VOID
  319.    c1 = calculate_column() - 1;
  320.    c2 = c1 + nspace;
  321.  
  322.    if (tab)
  323.      {
  324.     i = c1 / tab;
  325.     k = c2 / tab - i;
  326.     if (k) nspace = c2 - (i + k) * tab;
  327.     ins_char_n_times('\t', k);
  328.      }
  329.    ins_char_n_times(' ', nspace);
  330. }
  331.  
  332. /* check from point to end of line looking for tabs */
  333. int tabs_present(void)
  334. {
  335.     unsigned char *p, *pmax;
  336.  
  337.     if (!Buffer_Local.tab) return(0);
  338.     pmax = CLine->data + CLine->len;
  339.     p = CLine->data + Point;
  340.  
  341.     while (p < pmax) if (*p++ == '\t') return(1);
  342.     return(0);
  343. }
  344.  
  345. int delete_char_cmd()
  346. {
  347.    int upd, n;
  348.    char ch;
  349.  
  350.    CHECK_READ_ONLY
  351.    if (eobp())
  352.       {
  353.           msg_error(End_Of_Buffer_Error);
  354.           return(0);
  355.       }
  356.  
  357.     ch = *(CLine->data + Point);
  358.  
  359.     if (FAST_NOT_OK || long_line ()
  360.     || *tt_Term_Cannot_Insert
  361.     )
  362.       {
  363.      
  364.      if ((Point == 0) && eolp()) n = 1; else n = 0;
  365.      /* same effect, update looks better */     
  366.      n = backwchars(&n);
  367.      del();
  368.      forwchars(&n);
  369.      upd = 1;
  370.       }
  371.     else
  372.       {
  373.      upd = ((CBuf->flags & BUFFER_TRASHED) == 0);
  374.      fast_del();
  375.      tt_delete_char ();
  376.       }
  377.  
  378.     return(upd);
  379. }
  380.  
  381. int backward_delete_char_cmd()
  382. {
  383.    char ch;
  384.    int ret;
  385.  
  386.    CHECK_READ_ONLY
  387.     if (bobp())
  388.       {
  389.           msg_error(Top_Of_Buffer_Error);
  390.           return(0);
  391.       }
  392.  
  393.     if (bolp())
  394.       {
  395.      backwchars(&Number_One);
  396.      return delete_char_cmd();
  397.       }
  398.  
  399.     ch = *(CLine->data + (Point - 1));
  400.  
  401.     if (FAST_NOT_OK || long_line ()
  402.     || *tt_Term_Cannot_Insert
  403.     )
  404.       {
  405.       backwchars(&Number_One);
  406.       del();
  407.       return(1);
  408.       }
  409.  
  410.    ret = ((CBuf->flags & BUFFER_TRASHED) == 0);
  411.    backwchars(&Number_One);
  412.    tt_putchar('\b');
  413.     Screen_Col--;
  414.    fast_del();
  415.     tt_delete_char();
  416.     return(ret);
  417. }
  418.  
  419. int backward_delete_char_untabify()
  420. {
  421.     unsigned char *p;
  422.     int n;
  423.  
  424.    CHECK_READ_ONLY
  425.     p = CLine->data + (Point - 1);
  426.  
  427.     /* note that short circuit is assumed to avoid seg fault */
  428.     if (!Point || bobp() || (*p != '\t') || !Buffer_Local.tab) return backward_delete_char_cmd();
  429.  
  430.     n = calculate_column() - 1;
  431.     backwchars(&Number_One);
  432.     del();
  433.     n = n - calculate_column();
  434.     ins_char_n_times(' ', n);
  435.  
  436.     return(1);
  437. }
  438.  
  439. int previous_line_cmd()
  440. {
  441.    int ret, gc;
  442.  
  443.    if (CLine == CBuf->beg)
  444.      {
  445.           msg_error(Top_Of_Buffer_Error);
  446.           return(0);
  447.      }
  448.    check_line();
  449.     gc = calculate_column();
  450.     if (Cursor_Motion <= 0) Goal_Column = gc;
  451.     else if (Goal_Column < gc) Goal_Column = gc;
  452.  
  453.    Cursor_Motion = 2;
  454.    
  455.       /* For syntax highlighting */
  456.    if ((Last_Key_Function != (VOID *) previous_line_cmd) &&
  457.        ((Last_Key_Function == (VOID *) ins_char_cmd)
  458.        || (Last_Key_Function == (VOID *) delete_char_cmd)
  459.        || (Last_Key_Function == (VOID *) backward_delete_char_cmd)
  460.        || (Last_Key_Function == (VOID *) backward_delete_char_untabify)))
  461.      register_change(0);   
  462.    
  463.    ret = JWindow->trashed || (CLine == JScreen[JWindow->top - 1].line);
  464.    
  465.    CLine = CLine->prev;
  466.    LineNum--;
  467.    point_column(Goal_Column);
  468.    return(ret);
  469. }
  470.  
  471. int next_line_cmd()
  472. {
  473.    int ret, gc;
  474.  
  475.    if (CLine == CBuf->end)
  476.      {
  477.     msg_error(End_Of_Buffer_Error);
  478.     return(0);
  479.      }
  480.    check_line();
  481.    gc = calculate_column();
  482.    if (Cursor_Motion <= 0) Goal_Column = gc;
  483.    else if (Goal_Column < gc) Goal_Column = gc;
  484.  
  485.    Cursor_Motion = 2;
  486.    
  487.    /* For syntax highlighting */
  488.    if ((Last_Key_Function != (VOID *) next_line_cmd) &&
  489.        ((Last_Key_Function == (VOID *) ins_char_cmd)
  490.        || (Last_Key_Function == (VOID *) delete_char_cmd)
  491.        || (Last_Key_Function == (VOID *) backward_delete_char_cmd)
  492.        || (Last_Key_Function == (VOID *) backward_delete_char_untabify)))
  493.      register_change(0);
  494.  
  495.    ret = JWindow->trashed || (CLine == JScreen[JWindow->top + JWindow->rows - 2].line);
  496.    
  497.    CLine = CLine->next;
  498.    LineNum++;
  499.    point_column(Goal_Column);
  500.    return(ret);
  501. }
  502.  
  503. int next_char_cmd()
  504. {
  505.    Cursor_Motion = 1;
  506.    
  507.    /* For syntax highlighting */
  508.    if ((Last_Key_Function != (VOID *) next_char_cmd) &&
  509.        ((Last_Key_Function == (VOID *) ins_char_cmd)
  510.        || (Last_Key_Function == (VOID *) delete_char_cmd)
  511.        || (Last_Key_Function == (VOID *) backward_delete_char_cmd)
  512.        || (Last_Key_Function == (VOID *) backward_delete_char_untabify)))
  513.      register_change(0);
  514.        
  515.    if (!forwchars(&Number_One))
  516.      {
  517.     msg_error(End_Of_Buffer_Error);
  518.     return (0);
  519.      }
  520.    Goal_Column = calculate_column();
  521.    return !Point || JWindow->trashed;  /* Point = 0 ==> moved a line */
  522. }
  523.  
  524. extern Buffer *Paste_Buffer;
  525.  
  526. int kill_line()
  527. {
  528.    int n, pnt, flag = 0;
  529.    
  530.    CHECK_READ_ONLY
  531.  
  532.     if (eobp())
  533.       {
  534.           msg_error(End_Of_Buffer_Error);
  535.           return(0);
  536.       }
  537.    
  538.    push_mark();
  539.    push_spot();
  540.    pnt = Point;
  541.    eol();
  542.    n = Point - pnt;
  543.    if ((!pnt && Kill_Line_Feature) || !n)
  544.      {
  545.  
  546.     /* Either of these (flag =0,1) have the same effect on the buffer.
  547.      *  However, the first sets the mark at the end of the line and moves
  548.      *  the point to the end of the previous line.  This way the current
  549.      *  line structure is deleted and the screen update looks better. 
  550.      */
  551.     if (!pnt && (CLine->prev != NULL) && (CLine->next != NULL)) 
  552.       {
  553.          flag = 1;
  554.          forwchars(&Number_One);
  555.       }
  556.     else n += forwchars(&Number_One);
  557.     
  558.      }
  559.     
  560.    if ((Last_Key_Function == (VOID *) kill_line) && (Paste_Buffer != NULL))
  561.      {
  562.     copy_region_to_buffer(Paste_Buffer);
  563.      }
  564.    else copy_to_pastebuffer();
  565.    pop_spot();
  566.    if (flag) n += backwchars(&Number_One);
  567.    generic_deln(&n);
  568.    if (flag) forwchars(&Number_One);
  569.    return(1);
  570. }
  571.  
  572.    
  573. /* get indent value of current line, n is the column */
  574. unsigned char *get_current_indent(int *n)
  575. {
  576.    unsigned char *p, *pmax;
  577.    int tab;
  578.  
  579.    tab = Buffer_Local.tab;
  580.    p = CLine->data;
  581.    pmax = CLine->data + CLine->len;
  582.    *n = 0;
  583.    while((p < pmax) && ((*p == ' ') || (tab && (*p == '\t'))))
  584.      {
  585.     if (*p == '\t')
  586.       *n = tab * (*n / tab + 1);
  587.     else (*n)++;
  588.  
  589.     p++;
  590.      }
  591.    return(p);
  592. }
  593.  
  594. /* returns desired indentation as well as a char that may be used for 
  595.    subsequent indentation */
  596. unsigned char *get_indent(int *pt)
  597. {
  598.    int n, ret;
  599.    
  600.    unsigned char *p;
  601.  
  602.    p = get_current_indent(&n);
  603.  
  604.    if (CBuf->modes & C_MODE)
  605.      {
  606.     C_Comment_Hint = 0;
  607.     push_spot();
  608.     eol();
  609.     if (find_matching(')', 50, 0) >= 0)   /* goback 50 lines */
  610.       {
  611.          n = calculate_column() - User_Vars.c_indent;
  612.          p = CLine->data + Point;
  613.       }
  614.     else
  615.       {
  616.          pop_spot(); push_spot (); eol ();
  617.          ret = find_matching('}', 500, 0);
  618.          if (ret >= 0)
  619.            {
  620.           p = get_current_indent(&n);
  621.           push_spot ();
  622.           if ((*p != '{') && Point)
  623.             {
  624.                /* handle this sort of thing:
  625.             * if (line1
  626.             *     || line_2) {
  627.             *   then_this;
  628.                 * }
  629.             */
  630.                p = CLine->data + (Point - 1);
  631.  
  632.                while ((*p <= ' ') && (p > CLine->data)) p--;
  633.                if (*p == ')')
  634.              {
  635.                 Point = (int) (p - CLine->data);
  636.                 find_matching(')', -1, 1); /* -1 since we want to shif back 1 */
  637.                 if (*(CLine->data + Point) ==  '(')
  638.                   (void) get_current_indent (&n);
  639.              }
  640.             }
  641.           pop_spot ();
  642.           p = CLine->data + Point;
  643.            }
  644.          else if ((ret == -2) && looking_at("/*"))
  645.            {
  646.           n = calculate_column() - User_Vars.c_indent;
  647.           p = CLine->data + Point;
  648.           C_Comment_Hint = 1;
  649.            }
  650.          else
  651.          n = 0;               /* give up */
  652. #if 0
  653.          /* Not found and not in comment */
  654.            {
  655.           /* try this */
  656.           pop_spot (); push_spot (); eol ();
  657.           if (search_backward(")"))
  658.             {
  659.                find_matching(')', -1, 1);  /* -1 since we want to shif back 1 */
  660.             }
  661.           p = get_current_indent(&n);
  662.           /* n -= User_Vars.c_indent; */
  663.            }
  664. #endif
  665.       }
  666.     pop_spot ();
  667.      }
  668.    if (n < 0) n = 0;
  669.    *pt = n;
  670.    return(p);
  671. }
  672.  
  673. int trim_whitespace()
  674. {
  675.     unsigned char *p;
  676.     int n, save_point, len;
  677.  
  678.    CHECK_READ_ONLY
  679.     len = CLine->len;
  680.     if (len == 0) return(0);
  681.  
  682.     save_point = Point;
  683.     if (Point == len) Point--;
  684.  
  685.     /* Note that we save the point before --ing it.  This way the comparison
  686.        made below will effectively restore it if pointing at non whitespace */
  687.  
  688.     p = CLine->data + Point;
  689.     if (!bolp() && (*p == '\n') && (CBuf != MiniBuffer))
  690.       {
  691.           Point--;
  692.           p--;
  693.       }
  694.  
  695.     while ((Point > 0) && ((*p == '\t') || (*p == ' ')))
  696.       {
  697.           Point--;
  698.           p--;
  699.       }
  700.  
  701.     if (save_point != Point) if (!eolp() && ((*p != ' ') && (*p != '\t')))
  702.       {
  703.           Point++;
  704.           p++;
  705.       }
  706.  
  707.     n = 0;
  708.     /* this needs to be inlined.  Actually for undo, I need del(n)! */
  709.    while (((*p == ' ') || (*p == '\t')) && !eolp()) p++, n++;
  710.    deln(&n);
  711.    return(1);
  712. }
  713.  
  714. /* indent line to column n */
  715. void indent_to(int n)
  716. {
  717.     int m;
  718.  
  719.     get_current_indent(&m);
  720.  
  721.     if (n != m)
  722.       {
  723.      Point = 0;
  724.      trim_whitespace();
  725.      if (n >= 0) insert_whitespace(&n);
  726.       }
  727. }
  728.  
  729. int indent_line()
  730. {
  731.     char ch, ch1;
  732.     int n, n1;
  733.  
  734.    CHECK_READ_ONLY
  735.     if (CLine == CBuf->beg) return(0);
  736.  
  737.     push_spot();
  738.     CLine = CLine->prev;
  739.     ch = (char) *get_indent(&n);
  740.     CLine = CLine->next;
  741.  
  742.     if (CBuf->modes & C_MODE)
  743.       {
  744.      ch1 = (char) *get_current_indent(&n1);
  745.  
  746.      if (ch1 == '#') n = 0;
  747.      else if (n || (ch == '{') || (C_Bra_Newline == 0))
  748.        {
  749.           if ((ch1 == '{') && (ch == '{')) n += User_Vars.c_brace;
  750.           if ((ch1 != '}') && ((n != 0) || (ch == '{'))) 
  751.               n += User_Vars.c_indent;
  752.        }
  753.  
  754.       }
  755.  
  756.     indent_to(n);
  757.  
  758.     pop_spot();
  759.  
  760.     /* This moves the cursor to the first non whitspace char if we are
  761.        before it.  Otherwise leave it alone */
  762.  
  763.     n1 = calculate_column();
  764.     get_current_indent(&n);
  765.     if (n1 <= n) point_column(n + 1);
  766.    
  767.    if (CBuf->indent_hook != NULL)  SLexecute_function(CBuf->indent_hook);
  768.  
  769.     return(1);
  770. }
  771.  
  772. int newline_and_indent()
  773. {
  774.     newline();
  775.     indent_line();
  776.     return(1);
  777. }
  778.  
  779. int ins_char_cmd()
  780. {
  781.    char ch;
  782.    
  783.    int wrap = User_Vars.wrap_column;
  784.    int ret, ll;
  785.  
  786.    CHECK_READ_ONLY
  787.     ch = (char) SLang_Last_Key_Char;
  788.  
  789.     if (ch == '\n')
  790.       {
  791.           newline();
  792.           return(1);
  793.       }
  794.    
  795. #ifdef HAS_ABBREVS   
  796.    if (CBuf->flags & ABBREV_MODE) 
  797.      {
  798.     expand_abbrev (ch);
  799.      }
  800. #endif
  801.    
  802.    if ((CBuf->flags & OVERWRITE_MODE) && !eolp()) del();
  803.    
  804.     if (((ch == ' ') || (Point >= wrap)) && (CBuf->modes & WRAP_MODE)
  805.     && (calculate_column() > wrap)) /* JWindow->width */
  806.       {
  807.      ins(ch);
  808.      wrap_line(0);            /* do not format--- just wrap */
  809.      if (Indented_Text_Mode) indent_line();
  810.      if (CBuf->wrap_hook != NULL)
  811.        SLexecute_function(CBuf->wrap_hook);
  812.  
  813.      return(1);
  814.       }
  815.  
  816.     if ((ch == ' ') || FAST_NOT_OK  || (CBuf->flags & OVERWRITE_MODE) 
  817.     || (*tt_Term_Cannot_Insert && !eolp())
  818.     )
  819.       {
  820.      ins(ch);
  821.      if (((ch == '}') || (ch == ')') || (ch == ']'))
  822.          && !input_pending(&Number_Zero)) blink_match(ch);
  823.      return(1);
  824.       }
  825.  
  826.  
  827.    ret = ((CBuf->flags & BUFFER_TRASHED) == 0) || (User_Prefers_Line_Numbers > 1);
  828.    
  829.    if (long_line ()) ll = 1; else ll = 0;
  830.    ret = ret || ll;
  831.  
  832.    /* fast_ins goes first so that screen structure is updated now
  833.       for following calls to use. */    
  834.  
  835.    fast_ins(ch);
  836.    if (!eolp() || ll)
  837.      {
  838.     tt_begin_insert();
  839.     tt_putchar(ch);
  840.     tt_end_insert();
  841.     if (ll) register_change(0);
  842.      }
  843.    else tt_putchar(ch);
  844.    Screen_Col++;
  845.    if ((ch == ')') || (ch == '}') || (ch == ']')) blink_match(ch);
  846.    return(ret);
  847. }
  848.  
  849. /* returns 1 if in string or char, -1 if (looks like) comment, 0 otherwise */
  850. static int in_string (void)
  851. {
  852.    register unsigned char *p, *pmax, ch;
  853.    int in_c, psave = Point;
  854.    unsigned char in_s;
  855.    
  856.    Point = 0; skip_whitespace ();
  857.    p = CLine->data + Point;
  858.    pmax = CLine->data + psave;
  859.    Point = psave;
  860.    
  861.    if (p >= pmax) return 0;
  862.    
  863.    /* look for the comment style supported by jed. */
  864.    if ((*p == '*') && ((p + 1) < pmax) && (*(p + 1) <= ' ')) return -1;
  865.    
  866.    in_s = in_c = 0;
  867.    
  868.    while (p < pmax)
  869.      {
  870.         if ((ch = *p++) <= ' ') continue;
  871.     if (in_s)
  872.       {
  873.          if (ch == in_s) in_s = 0;
  874.          else if (ch == '\\') p++;
  875.       }
  876.     else if (in_c && (ch == '*') && (p < pmax) && (*p == '/'))
  877.       {
  878.          p++;
  879.          in_c = 0;
  880.       }
  881.     else if (ch == '"') in_s = ch;
  882.     else if (ch == '\'') in_s = ch;
  883.     else if ((ch == '/') && (p < pmax) && (*p == '*'))
  884.       {
  885.          p++;
  886.          in_c = 1;
  887.       }
  888.      }
  889.    if (in_s) return 1;
  890.    if (in_c) return -1;
  891.    return 0;
  892. }
  893.  
  894. int brace_bra_cmd()
  895. {
  896.    int n;
  897.    unsigned char *p;
  898.    CHECK_READ_ONLY
  899.    
  900.    p = CLine->data + (Point - 1);
  901.    
  902.    if ((!(CBuf->modes & C_MODE)) || (!eolp())
  903.          || (Point && ((*p == '\'') || (*p == '"') || in_string ())))
  904.       {
  905.          return ins_char_cmd();
  906.       }
  907.  
  908.    /* some people prefer insert,newline.  I prefer newline, insert, newline. */
  909.  
  910.    p = get_current_indent(&n);
  911.    if (C_Bra_Newline && 
  912.        ((p < CLine->data + CLine->len) && (*p > (unsigned char) ' '))) newline();
  913.    else ins(' ');
  914.    indent_line();
  915.    ins('{');
  916.    if (n != 0) indent_line();
  917.    newline_and_indent();
  918.    return(1);
  919. }
  920.  
  921. int brace_ket_cmd()
  922. {
  923.    int n;
  924.    int pnt = Point;
  925.    unsigned char *prev, *p;
  926.  
  927.    CHECK_READ_ONLY
  928.    if (((CBuf->modes & C_MODE) == 0)
  929.        || in_string ())
  930.      return ins_char_cmd();
  931.    
  932.    prev = CLine->data + (Point - 1);
  933.    skip_whitespace();
  934.    if (!eolp() || (pnt && ((*prev == '"') || (*prev == '\''))))
  935.      {
  936.     Point = pnt;
  937.     return ins_char_cmd();
  938.      }
  939.  
  940.    p = get_current_indent(&n);
  941.    if ((p < CLine->data + CLine->len) && (*p > (unsigned char) ' ')) newline();
  942.    ins('}');
  943.    indent_line();
  944.    JWindow->trashed = 1;
  945.    update((Line *) NULL, 0, 0);
  946.    blink_match('}');
  947.    if (C_Bra_Newline) newline_and_indent();
  948.    return(1);
  949. }
  950.  
  951. int eol_cmd()
  952. {
  953.     if (!eolp())
  954.       eol();
  955.     if (! (CBuf->flags & READ_ONLY)) trim_whitespace();
  956.     return(1);
  957. }
  958.  
  959.  
  960. int sys_spawn_cmd()
  961. {
  962.    if (Batch) return (0);
  963.    if (X_Suspend_Hook != NULL)
  964.      {
  965.     (*X_Suspend_Hook) ();
  966.     return (0);
  967.      }
  968.  
  969.    SLang_run_hooks("suspend_hook", NULL, NULL);
  970.    if (SLang_Error) return(0);
  971.    reset_display();
  972.    reset_tty();
  973.    sys_suspend();
  974.    init_tty();
  975.    init_display(1);
  976.    /* cls(); */
  977.    SLang_run_hooks("resume_hook", NULL, NULL);
  978.    check_buffers();
  979.    return(1);
  980. }
  981.  
  982. int quit_jed(void)
  983. {
  984.    Buffer *b = CBuf;
  985.    
  986.    /* Any buffer marked with AUTO_SAVE_JUST_SAVE flag should be saved 
  987.     * if it has not already been.  That is what the flag is for and this
  988.     * code fragment carries this out.
  989.     */
  990.    do 
  991.      {
  992.     if ((b->flags & AUTO_SAVE_JUST_SAVE) 
  993.         && (b->flags & BUFFER_TRASHED)
  994.         && (*b->file))
  995.       {
  996.          while (b->narrow != NULL) widen_buffer(b);
  997.          auto_save_buffer(b);      /* actually, it will save it */
  998.       }
  999.     b = b->next;
  1000.      }
  1001.    while (b != CBuf);
  1002.  
  1003.    reset_display();
  1004.    reset_tty();
  1005. #ifdef VMS
  1006.    vms_cancel_exithandler();
  1007. #endif
  1008. #ifdef SLANG_STATS
  1009.    SLang_dump_stats("slang.dat");
  1010. #endif
  1011. #ifdef MALLOC_DEBUG
  1012.    SLmalloc_dump_statistics ();
  1013. #endif
  1014.    exit(0);
  1015.    return(1);
  1016. }
  1017.  
  1018.  
  1019. int quoted_insert()
  1020. {
  1021.    char ch;
  1022.    int lerr = SLang_Error;
  1023.    
  1024.    CHECK_READ_ONLY
  1025.    if (*Error_Buffer || SLKeyBoard_Quit) return(0);
  1026.    if (Repeat_Factor != NULL)
  1027.      {
  1028.     ch = *Repeat_Factor;
  1029.     Repeat_Factor = NULL;
  1030.      }
  1031.    else
  1032.      {
  1033.     SLang_Key_TimeOut_Flag = 1;
  1034.     ch = jed_getkey();
  1035.     SLang_Key_TimeOut_Flag = 0;
  1036.      }
  1037.    
  1038.    
  1039.    SLang_Error = lerr;  /* ^G may set it */
  1040.   
  1041.    if ((ch == '\n') && (CBuf == MiniBuffer))
  1042.      {
  1043.     ins('\n');
  1044.     /* msg_error("Not allowed!"); */
  1045.     return (1);
  1046.      }
  1047.  
  1048.    SLKeyBoard_Quit = 0;
  1049.    ins_char_n_times(ch, 1);
  1050.    
  1051.    if (((ch == '}') || (ch == ')') || (ch == ']'))
  1052.        && !input_pending(&Number_Zero)) blink_match(ch);
  1053.  
  1054.    return(1);
  1055. }
  1056.  
  1057. /* I should try it like emacs--- if prefix argument, then save all without user
  1058.    intervention */
  1059. int save_some_buffers(void)
  1060. {
  1061.    Buffer *b, *tmp;
  1062.    int ans = 0;
  1063.    char msg[256];
  1064.    int err;
  1065.  
  1066.    b = CBuf;
  1067.    do
  1068.      {
  1069.     if ((b->flags & AUTO_SAVE_BUFFER) && (b->flags & BUFFER_TRASHED)
  1070.         && (*b->file))
  1071.       {
  1072.          sprintf(msg,"Buffer %s not saved. Save it? (y/n)", b->name);
  1073.          flush_message(msg);
  1074.          ans = my_getkey();
  1075.          while (1)
  1076.            {
  1077.           if ((ans == 'y') || (ans == 'Y'))
  1078.             {
  1079.                tmp = CBuf;
  1080.                switch_to_buffer(b);
  1081.                while (b->narrow != NULL) widen_buffer(b);
  1082.                err = write_file_with_backup(b->dir, b->file);
  1083.                switch_to_buffer(tmp);
  1084.                  if (err < 0) return(-1);
  1085.                b->flags &= ~BUFFER_TRASHED;
  1086.                b->flags |= AUTO_SAVE_BUFFER;
  1087.                b->hits = 0;
  1088.                break;
  1089.             }
  1090.           else if ((ans == 'n') || (ans == 'N'))
  1091.             {
  1092.                /* disabling this */
  1093.                /* auto_save_buffer(b); */
  1094.                break;
  1095.             }
  1096.           else if (SLKeyBoard_Quit) 
  1097.             {
  1098.                /* warning--- bug here if user edits file at
  1099.                startup and forgets to save it then aborts. */
  1100.                return(-1);
  1101.             }
  1102.           else 
  1103.             {
  1104.                beep();
  1105.                sprintf(msg,"Buffer %s not saved. Save it", b->name);
  1106.                ans = get_yes_no(msg);
  1107.                if (ans == 1) ans = 'y'; else if (!ans) ans = 'n'; 
  1108.                else return(-1);
  1109.             }
  1110.            }
  1111.       }
  1112.  
  1113.     b = b->next;
  1114.      }
  1115.    while (b != CBuf);
  1116.    message(" ");
  1117.    return(1);
  1118. }
  1119.  
  1120. int exit_jed()
  1121. {
  1122.    static int in_exit_jed = 0;
  1123.    
  1124.    if (!in_exit_jed)
  1125.      {
  1126.     in_exit_jed = 1;
  1127.     if (SLang_run_hooks("exit_hook", NULL, NULL)) 
  1128.       {
  1129.          in_exit_jed = 0;
  1130.          return(1);
  1131.       }
  1132.      }
  1133.    
  1134.    in_exit_jed = 0;
  1135.    if (SLang_Error) return(0);
  1136.    if (save_some_buffers() > 0) quit_jed();
  1137.    return(1);
  1138. }
  1139.  
  1140. int jed_buffer_visible (char *b)
  1141. {
  1142.    Buffer *buf;
  1143.    return ((NULL != (buf = find_buffer(b))) && (NULL != buffer_visible(buf)));
  1144. }
  1145.  
  1146. static void scroll_completion (int dir)
  1147. {
  1148.    Window_Type *w;
  1149.    
  1150.    if (jed_buffer_visible (Completion_Buffer))
  1151.      {
  1152.     pop_to_buffer (Completion_Buffer);
  1153.        if (dir > 0) pagedown_cmd (); else pageup_cmd ();
  1154.     while (!IS_MINIBUFFER) other_window (); 
  1155.      }
  1156.    else
  1157.      {
  1158.     w = JWindow;
  1159.     other_window();
  1160.     if (!IS_MINIBUFFER)
  1161.       {
  1162.          if (dir > 0) pagedown_cmd (); else pageup_cmd ();
  1163.       }
  1164.     while (JWindow != w) other_window ();
  1165.      }
  1166. }
  1167.  
  1168.  
  1169. static int Last_Page_Line;
  1170. static int Last_Page_Point;
  1171.  
  1172. /* the page up/down commands set cursor_motion to -1 because we do not
  1173.    want to use any goal column information */
  1174. int pagedown_cmd()
  1175. {
  1176.    int col;
  1177.    int n = JWindow->rows, dn, lpl, lp;
  1178.    
  1179.    Cursor_Motion = -1;
  1180.    if (IS_MINIBUFFER)
  1181.      {
  1182.     scroll_completion (1);
  1183.     return 1;
  1184.      }
  1185.  
  1186.    if (eobp()) 
  1187.      {
  1188.     msg_error(End_Of_Buffer_Error);
  1189.     return 1;
  1190.      }
  1191.    
  1192.    if ((CBuf != JWindow->buffer) || JWindow->trashed || (n == 1)) return(nextline(&n));
  1193.    
  1194.    lpl = window_line();
  1195.    lp = Last_Page_Point;
  1196.    Last_Page_Point = Point;
  1197.    col = calculate_column ();
  1198.    dn = n - lpl;
  1199.    if (dn == nextline(&dn)) recenter(&Number_One);
  1200.    goto_column1 (&col);
  1201.    if (Last_Key_Function == (VOID *) pageup_cmd) 
  1202.      {
  1203.     dn = Last_Page_Line - 1;
  1204.     nextline(&dn);
  1205.     Point = lp;
  1206.      }
  1207.    else if (CLine->next == NULL) eol(); else Point = 0;
  1208.    Last_Page_Line = lpl;
  1209.    
  1210.    return(1);
  1211. }
  1212.  
  1213. int pageup_cmd()
  1214. {
  1215.    int n = JWindow->rows, dn, lpl, lp, col;
  1216.  
  1217.    Cursor_Motion = -1;
  1218.  
  1219.    if (IS_MINIBUFFER)
  1220.      {
  1221.     scroll_completion (-1);
  1222.     return 1;
  1223.      }
  1224.    
  1225.    if (bobp()) 
  1226.      {
  1227.     msg_error(Top_Of_Buffer_Error);
  1228.     return 1;
  1229.      }
  1230.    
  1231.    if ((CBuf != JWindow->buffer) || JWindow->trashed || (n == 1)) return(prevline(&n));
  1232.   
  1233.    lpl = window_line();
  1234.    lp = Last_Page_Point;
  1235.    Last_Page_Point = Point;
  1236.    dn = lpl - 1;
  1237.    col = calculate_column ();
  1238.    prevline(&dn);
  1239.    (void) goto_column1(&col);
  1240.    recenter(&JWindow->rows);
  1241.    
  1242.    if (Last_Key_Function == (VOID *) pagedown_cmd)
  1243.      {
  1244.     dn = n - Last_Page_Line;
  1245.     prevline(&dn);
  1246.     Point = lp;
  1247.      }
  1248.    else Point = 0; /* something like: Point = point_column(JWindow->column) better? */
  1249.    Last_Page_Line = lpl; 
  1250.    return(1);
  1251. }
  1252.  
  1253.  
  1254. int scroll_right()
  1255. {
  1256.    if (JWindow->column == 1) return(0);
  1257.  
  1258.    if ((JWindow->column = JWindow->column - JWindow->width / 2) < 1)
  1259.      {
  1260.     JWindow->column = 1;
  1261.      }
  1262.  
  1263.    touch_window();
  1264.    return(1);
  1265. }
  1266.  
  1267. int scroll_left()
  1268. {
  1269.     JWindow->column = JWindow->column + JWindow->width / 2;
  1270.     touch_window();
  1271.     return(1);
  1272. }
  1273.  
  1274. /* goto to column c, returns actual column */
  1275. int goto_column1(int *cp)
  1276. {
  1277.    int c1, c = *cp;
  1278.    if (c <= 0) return(0);  /* not valid */
  1279.    eol();
  1280.    c1 = calculate_column();
  1281.    if (c1 > c)
  1282.      {
  1283.     point_column(c);
  1284.     c1 = calculate_column();
  1285.      }
  1286.    return(c1);
  1287. }
  1288.  
  1289. /* move cursor to column c adding spaces if necessary */
  1290. void goto_column(int *c)
  1291. {
  1292.    int c1;
  1293.    if (*c <= 0) return;
  1294.    c1 = *c - goto_column1(c);
  1295.    insert_whitespace(&c1);
  1296. }
  1297.  
  1298. /* does not leave current line */
  1299. unsigned int skip_whitespace()
  1300. {
  1301.    unsigned char *p, *pmax;
  1302.  
  1303.    if (CLine->len == 0) return('\n');
  1304.  
  1305.    p = CLine->data + Point;
  1306.    eol();
  1307.    pmax = CLine->data + Point;
  1308.    while(p < pmax)
  1309.      {
  1310.     if ((*p != ' ') && (*p != '\t')) break;
  1311.     p++;
  1312.      }
  1313.    Point = (int) (p - CLine->data);
  1314.    return(*p);
  1315. }
  1316.  
  1317. #define upcase(ch) (Case_Sensitive ? ch : UPPER_CASE(ch))
  1318.  
  1319.  
  1320. /* returns < 0 if what is smaller than current thing, 0 if matched, pos otherwise */
  1321. int looking_at(char *what)
  1322. {
  1323.    register unsigned char *p, *pmax;
  1324.    register unsigned char *w = (unsigned char *) what, ch;
  1325.    Line *l = CLine;
  1326.    
  1327.    p = l->data + Point;
  1328.    while (1)
  1329.      {
  1330.     pmax = l->data + l->len;
  1331.     while (((ch = *w) != 0) && (p < pmax))
  1332.       {
  1333.          if ((upcase(ch) != upcase(*p))) return 0;
  1334.          p++; w++;
  1335.       }
  1336.     if (ch == 0) return 1;
  1337.     l = l->next;
  1338.     if (l == NULL) return 0;
  1339.     p = l->data;
  1340.      }
  1341. }
  1342.  
  1343. void jed_make_lut (unsigned char *lut, unsigned char *range, unsigned char reverse)
  1344. {
  1345.    register unsigned char *l = lut, *lmax = lut + 256;
  1346.    int i, r1, r2;
  1347.  
  1348.    while (l < lmax) *l++ = reverse;
  1349.    
  1350.    while (*range)
  1351.      {
  1352.     r1 = *range;
  1353.     if (*(range + 1) == '-')
  1354.       {
  1355.          range += 2;
  1356.          r2 = *range;
  1357.       }
  1358.     else r2 = r1;
  1359.     
  1360.     for (i = r1; i <= r2; i++) lut[i] = !reverse;
  1361.     if (*range) range++;
  1362.      }
  1363.    
  1364.    /* more flexibility is achieved with following line */ 
  1365.    if (reverse && lut['\n']) lut['\n'] = 0; 
  1366. }
  1367.  
  1368.  
  1369.  
  1370. void skip_chars1(char *range, int reverse)
  1371. {
  1372.    unsigned char lut[256];
  1373.    unsigned char *p, *pmax;
  1374.    Line *line;
  1375.    int n = 0;
  1376.    
  1377.    jed_make_lut(lut, (unsigned char *) range, (unsigned char) reverse);
  1378.    
  1379.    line = CLine;
  1380.    while (line != NULL)
  1381.      {
  1382.     CLine = line;
  1383.     p = line->data + Point;
  1384.     pmax = line->data + line->len;
  1385.  
  1386.     while (p < pmax)
  1387.       {
  1388.          if (0 == lut[*p])
  1389.            {
  1390.           Point = (int)(p - CLine->data);
  1391.                   LineNum += n;
  1392.           return;
  1393.            }
  1394.          p++;
  1395.       }
  1396.     Point = 0;
  1397.     line = CLine->next;
  1398.         n++;
  1399.      }
  1400.    eob();
  1401. }
  1402.  
  1403. void bskip_chars1(char *range, int reverse)
  1404. {
  1405.    unsigned char lut[256];
  1406.    unsigned char *p;
  1407.    Line *line = CLine;
  1408.    int n = 0;
  1409.    
  1410.    jed_make_lut(lut, (unsigned char *) range, (unsigned char) reverse);
  1411.    
  1412.    while (1)
  1413.      {
  1414.     if (Point == 0) 
  1415.       {
  1416.          if (lut['\n'] == 0) return;
  1417.          if (NULL == (line = CLine->prev)) break;
  1418.          Point = line->len - 1;
  1419.              n++;
  1420.       }
  1421.     
  1422.     CLine = line;
  1423.          
  1424.     p = line->data + (Point - 1);
  1425.  
  1426.     while (p >= line->data)
  1427.       {
  1428.          if (0 == lut[*p])
  1429.            {
  1430.           Point = 1 + (int)(p - line->data);
  1431.                   LineNum -= n;
  1432.           return;
  1433.            }
  1434.          
  1435.          p--;
  1436.       }
  1437.     Point = 0;
  1438.      }
  1439.    bob();
  1440. }
  1441.  
  1442. void skip_chars (char *range)
  1443. {
  1444.    if (*range == '^') skip_chars1(range + 1, 1);
  1445.    else 
  1446.      {
  1447.     if (*range == '\\') range++;
  1448.     skip_chars1(range, 0);
  1449.      }
  1450. }
  1451.  
  1452. void bskip_chars (char *range)
  1453. {
  1454.    if (*range == '^') bskip_chars1(range + 1, 1);
  1455.    else 
  1456.      {
  1457.     if (*range == '\\') range++;
  1458.     bskip_chars1(range, 0);
  1459.      }
  1460. }
  1461.