Logo Search packages:      
Sourcecode: jed version File versions

cmds.c

/* -*- mode: c; mode: fold -*- */
/* Copyright (c) 1992, 1998, 2000, 2002 John E. Davis
 * This file is part of JED editor library source.
 *
 * You may distribute this file under the terms the GNU General Public
 * License.  See the file COPYING for more information.
 */
#include "config.h"
#include "jed-feat.h"

/*{{{ #include files */

#include <stdio.h>

#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif

#include <slang.h>

#include "jdmacros.h"

#include <string.h>

#include "buffer.h"
#include "screen.h"
#include "window.h"
#include "ins.h"
#include "ledit.h"
#include "cmds.h"
#include "line.h"
#include "paste.h"
#include "display.h"
#include "sysdep.h"
#include "text.h"
#include "file.h"
#include "misc.h"
#include "search.h"
#include "hooks.h"
#include "abbrev.h"
#include "indent.h"
#if JED_HAS_SUBPROCESSES
# include "jprocess.h"
#endif
#include "sig.h"

#if JED_HAS_LINE_ATTRIBUTES
# include "lineattr.h"
#endif

/*}}}*/

/* fast insert/delete not implemented */
#define USE_FAST_INSDEL 0

/*{{{ Global variables */

void (*X_Suspend_Hook)(void);
int Blink_Flag = 1;
int Indented_Text_Mode = 0;          /* if non zero, intent line after wrap */
int Kill_Line_Feature = 1;           /* non-zero means kill through eol if bolp  */
int Jed_Tab_Default = 8;
int Jed_Wrap_Column = 72;
int Jed_Suspension_Not_Allowed = 0;
int Jed_Use_Tabs = 1;

/*}}}*/

/*{{{ Static variables */

static char *Top_Of_Buffer_Error = "Top Of Buffer.";
static char *End_Of_Buffer_Error = "End Of Buffer.";

/*}}}*/
/*{{{ Static functions */

#if USE_FAST_INSDEL

static void fast_ins(char ch) /*{{{*/
{
}

/*}}}*/

static void fast_del() /*{{{*/
{
}

/*}}}*/

/* return 1 if line extends beyond the screen */
static int long_line(void)
{
   int p, col;
   
   col = Screen_Col;
   p = Point;
   Point = CLine->len - 1;
   if ((*(CLine->data + Point) != '\n') || (CBuf == MiniBuffer)) Point++;
   if (calculate_column() >= JWindow->width - 1)
     {
      Point = p;
      Screen_Col = col;
      return(1);
     }
   Screen_Col = col;
   Point = p;
   return(0);
}

/* check from point to end of line looking for tabs */
static int tabs_present(void)
{
   unsigned char *p, *pmax;
   
   if (!Buffer_Local.tab) return(0);
   pmax = CLine->data + CLine->len;
   p = CLine->data + Point;
   
   while (p < pmax) if (*p++ == '\t') return(1);
   return(0);
}

static int fast_not_ok (unsigned char ch)
{
   return 1;

   return ((Repeat_Factor != NULL) || JWindow->trashed
         || (ch < 32) || (ch > 126) || Input_Buffer_Len
         || Suspend_Screen_Update
         || (Screen_Col >= JWindow->width - 2) || (JWindow->column > 1)
         || Batch || (CLine->len == 0)
         || ((CBuf->marks != NULL) && Wants_Attributes)
#if JED_HAS_LINE_ATTRIBUTES
         || ((CLine->next != NULL) && (CLine->next->flags & JED_LINE_HIDDEN))
#endif         
         || input_pending(&Number_Zero) || Executing_Keyboard_Macro
         || tabs_present()
         || (Read_This_Character != NULL));
}
#endif                               /* USE_FAST_INSDEL */

#if JED_HAS_LINE_ATTRIBUTES
static int check_line_attr_no_modify (Line *l)
{
   if (0 == (l->flags & JED_LINE_HIDDEN))
     return 0;
   
   msg_error ("You cannot edit this hidden line.");
   return -1;
}
#endif

static int next_visible_lines (int n)
{
#if JED_HAS_LINE_ATTRIBUTES
   int dn;
   int i;
   
   i = 0;
   while (i < n)
     {
      Line *l = CLine;
      
      dn = 0;
      do
        {
           l = l->next;
           dn++;
        }
      while ((l != NULL) && (l->flags & JED_LINE_HIDDEN));
      
      if (l == NULL) break;
      
      CLine = l;
      LineNum += dn;
      i++;
     }
   if (i) Point = 0;
   return i;
#else
   return nextline (&n);
#endif
}

static int prev_visible_lines (int n)
{
#if JED_HAS_LINE_ATTRIBUTES
   int i, dn;
   
   i = 0;
   while (i < n)
     {
      Line *l = CLine;
      
      dn = 0;
      do
        {
           l = l->prev;
           dn++;
        }
      while ((l != NULL) && (l->flags & JED_LINE_HIDDEN));
      
      if (l == NULL) break;
      
      CLine = l;
      LineNum -= dn;
      i++;
     }
   if (i) eol ();                    /* leave point at eol */
   return i;
#else
   return prevline (&n);
#endif
}

static int prev_visible_chars (int n)
{
#if JED_HAS_LINE_ATTRIBUTES
   push_mark ();
   n = backwchars (&n);
   if (n && (CLine->flags & JED_LINE_HIDDEN))
     {
      jed_skip_hidden_lines_backward (&Number_One);
      if (CLine->flags & JED_LINE_HIDDEN)
        {
           pop_mark (&Number_One);
           return 0;
        }
     }
   pop_mark (&Number_Zero);
   return n;
#else
   return backwchars (&n);
#endif
}

static int next_visible_chars (int n)
{
#if JED_HAS_LINE_ATTRIBUTES
   push_mark ();
   n = forwchars (&n);
   if (n && (CLine->flags & JED_LINE_HIDDEN))
     {
      jed_skip_hidden_lines_forward (&Number_One);
      if (CLine->flags & JED_LINE_HIDDEN)
        {
           pop_mark (&Number_One);
           return 0;
        }
     }
   pop_mark (&Number_Zero);
   return n;
#else
   return forwchars (&n);
#endif
}

static void check_last_key_function (FVOID_STAR f)
{
   /* For syntax highlighting */
   if (Last_Key_Function != f)
     touch_window ();
#if 0
       && ((Last_Key_Function == (FVOID_STAR) ins_char_cmd)
         || (Last_Key_Function == (FVOID_STAR) eol_cmd)
         || (Last_Key_Function == (FVOID_STAR) delete_char_cmd)
         || (Last_Key_Function == (FVOID_STAR) backward_delete_char_cmd)
         || (Last_Key_Function == (FVOID_STAR) backward_delete_char_untabify)))
     
     register_change(0);
#endif
}

   
static void next_line_prev_line_helper (int *gcp, int *ret, int dr, FVOID_STAR f)
{
   int gc;

   (void) dr;
   check_line();
   gc = calculate_column();
   if (Cursor_Motion <= 0) Goal_Column = gc;
   else if (Goal_Column < gc) Goal_Column = gc;
   *gcp = gc;
   
   Cursor_Motion = 2;
   
   check_last_key_function (f);
   *ret = 1;
#if 0
   *ret = (JWindow->trashed 
         || (CLine == JScreen[JWindow->sy + dr].line)
#if JED_HAS_LINE_ATTRIBUTES
         || (CLine->flags & JED_LINE_IS_READONLY)
#endif
         );
#endif
}

static void eob_bob_error (int f)
{   
   char *str;
   
   if (CBuf->bob_eob_error_hook != NULL)
     {
      SLang_push_integer (f);
      SLexecute_function (CBuf->bob_eob_error_hook);
      return;
     }
   
   if (f < 0)
     str = Top_Of_Buffer_Error;
   else 
     str = End_Of_Buffer_Error;
   
   msg_error (str);
}

/*}}}*/

/*{{{ interactive insert/delete functions */

/*{{{ Interactive char deletion functions */

int delete_char_cmd (void)
{
   int upd, n;
#if USE_FAST_INSDEL
   char ch;
#endif

   CHECK_READ_ONLY
#if 0
     ;
#endif

#if JED_HAS_LINE_ATTRIBUTES
   if (check_line_attr_no_modify (CLine))
     return 0;
#endif

   if (eobp())
     {
      msg_error(End_Of_Buffer_Error);
      return(0);
     }
   
#if USE_FAST_INSDEL
   ch = *(CLine->data + Point);
   if (fast_not_ok ((unsigned char) ch) || long_line () || *tt_Term_Cannot_Insert)
     {
#endif
      if ((Point == 0) && eolp()
#if JED_HAS_LINE_ATTRIBUTES
          && ((CLine->prev != NULL)
            && (0 == (CLine->prev->flags & JED_LINE_IS_READONLY)))
#endif
          ) n = 1;
      else n = 0;
      /* same effect, update looks better */
      n = backwchars(&n);
      (void) jed_del();
      forwchars(&n);
      upd = 1;
#if USE_FAST_INSDEL
     }
   else
     {
      upd = ((CBuf->flags & BUFFER_MODIFIED) == 0);
      fast_del();
      tt_delete_char ();
     }
#endif
   return(upd);
}

int backward_delete_char_cmd()
{
#if USE_FAST_INSDEL
   char ch;
   int ret;
#endif
   CHECK_READ_ONLY
#if 0
     ;
#endif

   if (bobp())
     {
      msg_error(Top_Of_Buffer_Error);
      return(0);
     }
   
#if JED_HAS_LINE_ATTRIBUTES
   if (check_line_attr_no_modify (CLine))
     return 0;
#endif

   if (bolp())
     {
#if JED_HAS_LINE_ATTRIBUTES
      if (check_line_attr_no_modify (CLine->prev))
        return 0;
#endif
      backwchars(&Number_One);
      return delete_char_cmd();
     }
   
#if USE_FAST_INSDEL
   ch = *(CLine->data + (Point - 1));
   if (fast_not_ok ((unsigned char) ch) || long_line () || *tt_Term_Cannot_Insert)
     {
#endif
      backwchars(&Number_One);
      (void) jed_del();
      return 1;
#if USE_FAST_INSDEL
     }

   ret = ((CBuf->flags & BUFFER_MODIFIED) == 0);
   backwchars(&Number_One);
   tt_putchar('\b');
   Screen_Col--;
   fast_del();
   tt_delete_char();
   return(ret);
#endif
}

int backward_delete_char_untabify()
{
   unsigned char *p;
   int n;
   
   CHECK_READ_ONLY
#if 0
     ;
#endif
#if JED_HAS_LINE_ATTRIBUTES
   if (check_line_attr_no_modify (CLine))
     return 0;
#endif   
   p = CLine->data + (Point - 1);
   
   if (!Point || (*p != '\t') || !Buffer_Local.tab) 
     return backward_delete_char_cmd();
   
   n = calculate_column() - 1;
   backwchars(&Number_One);
   if (-1 == jed_del())
     return -1;

   n = n - calculate_column();
   (void) jed_ins_char_n_times(' ', n);
   
   return(1);
}

/*}}}*/

/*{{{ newline_and_indent */
int newline_and_indent ()
{
   static int in_function;
   if (in_function) return -1;
   
#if JED_HAS_LINE_ATTRIBUTES
   if (check_line_attr_no_modify (CLine)
       || ((CLine->next != NULL) 
         && eolp () && check_line_attr_no_modify (CLine->next)))
     return 0;
#endif
   
   if (CBuf->newline_indent_hook != NULL)
     {
      in_function = 1;
      SLexecute_function(CBuf->newline_indent_hook);
      in_function = 0;
      return 1;
     }
   if (0 == jed_insert_newline ())
     indent_line();
   return(1);
}

/*}}}*/
/*{{{ newline */

int newline (void)
{
   CHECK_READ_ONLY
#if 0
     ;
#endif

   if (CBuf == MiniBuffer) return exit_minibuffer();
   
   (void) jed_insert_newline ();
   return(1);
}

int newline_cmd (void)
{
#if JED_HAS_LINE_ATTRIBUTES
   if (check_line_attr_no_modify (CLine)
       || ((CLine->next != NULL) 
         && eolp () && check_line_attr_no_modify (CLine->next)))
     return 0;
#endif
   return newline ();
}

/*}}}*/

/*{{{ ins_char_cmd */
int ins_char_cmd (void)
{
   char ch;
   int wrap = Jed_Wrap_Column;
   int do_blink;
   int did_abbrev = 0;

#if USE_FAST_INSDEL
   int ret, ll;
#endif
   CHECK_READ_ONLY
#if 0
     ;
#endif
#if JED_HAS_LINE_ATTRIBUTES
   if (check_line_attr_no_modify (CLine))
     return 0;
#endif
   
   ch = (char) SLang_Last_Key_Char;
   
   if (ch == '\n')
     {
      newline();
      return(1);
     }
   
#if JED_HAS_ABBREVS
   if (CBuf->flags & ABBREV_MODE)
     {
      if (-1 == (did_abbrev = expand_abbrev (ch)))
        return -1;
     }
#endif
   
   if ((CBuf->flags & OVERWRITE_MODE) && !eolp())
     {
      if ((did_abbrev == 0)
          && (-1 == jed_del ()))
        return -1;
     }

   if (((ch == ' ') || (Point >= wrap)) && (CBuf->modes & WRAP_MODE)
       && (calculate_column() > wrap)) /* JWindow->width */
     {
      unsigned int this_line_num = LineNum;
      
      if ((did_abbrev == 0)
          && (-1 == jed_ins (ch)))
        return -1;

      wrap_line(0);                 /* do not format--- just wrap */
      
      /* There is a bug involving wrapping a very long line containing
       * no whitespace and then we try to insert a character.  This work
       * arounds the bug.
       */
      if ((this_line_num == LineNum)
          && (ch == ' ')
          && (calculate_column () > wrap))
        {
           int one = 1;
           if (0 == forwchars (&one))
             newline ();
        }

      if (Indented_Text_Mode) indent_line ();
      if (CBuf->wrap_hook != NULL)
        SLexecute_function(CBuf->wrap_hook);
      
      return(1);
     }
   
   do_blink = ((((CBuf->syntax_table != NULL)
             && ((CBuf->syntax_table->char_syntax[(unsigned char) ch] & CLOSE_DELIM_SYNTAX)))
            || ((ch == ')') || (ch == '}') || (ch == ']')))
             && !input_pending(&Number_Zero));
#if USE_FAST_INSDEL
   if ((ch == ' ') || fast_not_ok ((unsigned char) ch) || (CBuf->flags & OVERWRITE_MODE)
       || (*tt_Term_Cannot_Insert && !eolp()))
     {
#endif
      if (did_abbrev == 0)
        (void) jed_ins(ch);
      if (do_blink) blink_match ();
      return 1;
#if USE_FAST_INSDEL
     }
   
   if (did_abbrev)
     return 1;

   ret = ((CBuf->flags & BUFFER_MODIFIED) == 0) || (User_Prefers_Line_Numbers > 1);
   
   if (long_line ()) ll = 1; else ll = 0;
   ret = ret || ll;
   
   /* fast_ins goes first so that screen structure is updated now
    for following calls to use. */
   
   fast_ins(ch);
   if (!eolp() || ll)
     {
      tt_begin_insert();
      tt_putchar(ch);
      tt_end_insert();
      if (ll) register_change(0);
     }
   else tt_putchar(ch);
   Screen_Col++;
   
   if (do_blink) blink_match ();

   return(ret);
#endif
}

/*}}}*/
/*{{{ quoted_insert */
int quoted_insert()
{
   char ch;
   int lerr = SLang_Error;
   
   CHECK_READ_ONLY
     if (*Error_Buffer || SLKeyBoard_Quit) return(0);
   if (Repeat_Factor != NULL)
     {
      ch = *Repeat_Factor;
      Repeat_Factor = NULL;
     }
   else
     {
      SLang_Key_TimeOut_Flag = 1;
      ch = jed_getkey();
      SLang_Key_TimeOut_Flag = 0;
     }
   
   
   SLang_Error = lerr;  /* ^G may set it */
   
   if ((ch == '\n') && (CBuf == MiniBuffer))
     {
      (void) jed_ins('\n');
      /* msg_error("Not allowed!"); */
      return (1);
     }
   
   SLKeyBoard_Quit = 0;
   if (-1 == jed_ins_char_n_times(ch, 1))
     return -1;
   
   
   if ((CBuf->syntax_table != NULL)
       && (CBuf->syntax_table->char_syntax[(unsigned char) ch] & CLOSE_DELIM_SYNTAX)
       && !input_pending(&Number_Zero)) blink_match (); /* (ch); */
   
   return(1);
}

/*}}}*/

/*{{{ kill_line */
int kill_line (void)
{
   int n, pnt, flag = 0;
   
   CHECK_READ_ONLY
     
     if (eobp())
     {
      msg_error(End_Of_Buffer_Error);
      return(0);
     }
   
   push_mark();
   push_spot();
   pnt = Point;
   eol();
   n = Point - pnt;
   if ((!pnt && Kill_Line_Feature) || !n)
     {
      
      /* Either of these (flag =0,1) have the same effect on the buffer.
       *  However, the first sets the mark at the end of the line and moves
       *  the point to the end of the previous line.  This way the current
       *  line structure is deleted and the screen update looks better.
       */
      if (!pnt && (CLine->prev != NULL) && (CLine->next != NULL))
        {
           flag = 1;
           forwchars(&Number_One);
        }
      else n += forwchars(&Number_One);
      
     }
   
   if ((Last_Key_Function == (FVOID_STAR) kill_line) && (Paste_Buffer != NULL))
     {
      copy_region_to_buffer(Paste_Buffer);
     }
   else copy_to_pastebuffer();
   pop_spot();
   if (flag) n += backwchars(&Number_One);
   (void) jed_generic_deln (n);
   if (flag) forwchars(&Number_One);
   return(1);
}

/*}}}*/

/*}}}*/
/*{{{ interactive cursor movement functions */

/*{{{ Interactive char/line movement functions */

int previous_line_cmd (void)
{
   int ret, gc;
   
   next_line_prev_line_helper (&gc, &ret, 0, (FVOID_STAR) previous_line_cmd);
   
   if ((CLine == CBuf->beg)
       || (1 != prev_visible_lines (1)))
     {
      eob_bob_error (-1);
      return 1;
     }
   
   point_column(Goal_Column);
   return(ret);
}


int next_line_cmd (void)
{
   int ret, gc;
   
   next_line_prev_line_helper (&gc, &ret, JWindow->rows - 1, (FVOID_STAR) next_line_cmd);
   
   if ((CLine == CBuf->end)
       || (1 != next_visible_lines (1)))
     {
      eob_bob_error (1);
      return 1;
     }
   
   point_column(Goal_Column);
   return(ret);
}

int previous_char_cmd (void)
{
   int pnt;
   
   Cursor_Motion = 1;
   pnt = Point - 1;
   
   /* check_last_key_function ((FVOID_STAR) previous_char_cmd); */
   
   if (1 != prev_visible_chars (1))
     {
      eob_bob_error (-2);
      return 1;
     }
   
   Goal_Column = calculate_column();
   return (pnt == -1) || JWindow->trashed;
}

int next_char_cmd ()
{
   Cursor_Motion = 1;
   
   /* check_last_key_function ((FVOID_STAR) next_char_cmd); */
   
   if (1 != next_visible_chars (1))
     {
      eob_bob_error (2);
      return 1;
     }
   
   Goal_Column = calculate_column ();
   return !Point || JWindow->trashed;  /* Point = 0 ==> moved a line */
}

/*}}}*/

/*{{{ eol_cmd */
int eol_cmd (void)
{
   eol();
   if ((0 == (CBuf->flags & READ_ONLY))
#if JED_HAS_LINE_ATTRIBUTES
       && (0 == (CLine->flags & JED_LINE_IS_READONLY))
#endif
       )
     trim_whitespace();
   return(1);
}

/*}}}*/

/*{{{ Scrolling/pageup/down functions */

int jed_buffer_visible (char *b)
{
   return buffer_visible (find_buffer(b));
}

static void scroll_completion (int dir)
{
   Window_Type *w;
   
   if (jed_buffer_visible (Completion_Buffer))
     {
      pop_to_buffer (Completion_Buffer);
      if (dir > 0) pagedown_cmd (); else pageup_cmd ();
      while (!IS_MINIBUFFER) other_window ();
     }
   else
     {
      w = JWindow;
      other_window();
      if (!IS_MINIBUFFER)
        {
           if (dir > 0) pagedown_cmd (); else pageup_cmd ();
        }
      while (JWindow != w) other_window ();
     }
}

int goto_bottom_of_window (void)
{
   int n;
   
   n = JWindow->rows - window_line ();

   return n == next_visible_lines (n);
}

void goto_top_of_window (void)
{
   int n;
   
   n = window_line () - 1;
   (void) prev_visible_lines (n);
}


static int Last_Page_Line;
static int Last_Page_Point;

/* the page up/down commands set cursor_motion to -1 because we do not
 want to use any goal column information */
int pagedown_cmd()
{
   int col, this_line, this_point;
   int n;
   
   Cursor_Motion = -1;
   if (IS_MINIBUFFER)
     {
      scroll_completion (1);
      return 1;
     }
   
   if (eobp())
     {
      eob_bob_error (3);
      return 1;
     }
   
   n = JWindow->rows;
   if ((CBuf != JWindow->buffer) || (n == 1))
     {
      return next_visible_lines (n);
     }
   
   if (JWindow->trashed)
     {
      update (NULL, 0, 0, 1);
      if (JWindow->trashed) return next_visible_lines (n);
     }

   /* This is ugly. */
   
   this_line = LineNum;
   this_point = Point;
   
   col = calculate_column ();
   if (goto_bottom_of_window ())
     {
      recenter (&Number_One);
     }
   
   goto_column1 (&col);
   
   if ((Last_Key_Function == (FVOID_STAR) pageup_cmd)
       && (Jed_This_Key_Function == (FVOID_STAR) pagedown_cmd))
     {
      goto_line (&Last_Page_Line);
      if (Last_Page_Point < CLine->len)
        Point = Last_Page_Point;
     }
   else if (CLine->next == NULL) eol(); else Point = 0;
   
   Last_Page_Line = this_line;
   Last_Page_Point = this_point;
   
   return(1);
}

int pageup_cmd (void)
{
   int col, this_line, this_point;
   int n;
   
   Cursor_Motion = -1;
   
   if (IS_MINIBUFFER)
     {
      scroll_completion (-1);
      return 1;
     }
   
   if (bobp())
     {
      eob_bob_error (-3);
      return 1;
     }
   
   n = JWindow->rows;
   if ((CBuf != JWindow->buffer) || (n == 1))
     {
      return prev_visible_lines (n);
     }
   
   if (JWindow->trashed)
     {
      update (NULL, 0, 0, 1);
      if (JWindow->trashed) return prev_visible_lines (n);
     }
   
   this_line = LineNum;
   this_point = Point;
   col = calculate_column ();
   goto_top_of_window ();
   (void) goto_column1(&col);
   recenter(&JWindow->rows);
   
   if ((Last_Key_Function == (FVOID_STAR) pagedown_cmd) 
       && (Jed_This_Key_Function == (FVOID_STAR) pageup_cmd))
     {
      goto_line (&Last_Page_Line);
      if (Last_Page_Point < CLine->len)
        Point = Last_Page_Point;
     }
   else Point = 0; /* something like: Point = point_column(JWindow->column) better? */
   Last_Page_Line = this_line;
   Last_Page_Point = this_point;
   return(1);
}


int scroll_right()
{
   if (JWindow->hscroll_column == 1) return(0);
   
   if ((JWindow->hscroll_column = JWindow->hscroll_column - JWindow->width / 2) < 1)
     {
      JWindow->hscroll_column = 1;
     }
   
   touch_window();
   return(1);
}

int scroll_left ()
{
   JWindow->hscroll_column = JWindow->hscroll_column + JWindow->width / 2;
   touch_window();
   return(1);
}

/*}}}*/

/*}}}*/

/*{{{ Whitespace and Indention functions */

void insert_whitespace(int *n)
{
   int tab = Buffer_Local.tab;
   int c1, c2, i, k, nspace;
   
   if ((nspace = *n) <= 0) return;
   CHECK_READ_ONLY_VOID
     c1 = calculate_column() - 1;
   c2 = c1 + nspace;
   
   if (tab && Jed_Use_Tabs)
     {
      i = c1 / tab;
      k = c2 / tab - i;
      if (k) nspace = c2 - (i + k) * tab;
      (void) jed_ins_char_n_times('\t', k);
     }
   (void) jed_ins_char_n_times(' ', nspace);
}

/* get indent value of current line, n is the column */
unsigned char *get_current_indent(int *np)
{
   unsigned char *p, *pmax;
   int tab, n;
   
   tab = Buffer_Local.tab;
   p = CLine->data;
   pmax = CLine->data + CLine->len;
   n = 0;
   while((p < pmax) && ((*p == ' ') || (tab && (*p == '\t'))))
     {
      if (*p == '\t')
        n = tab * (n / tab + 1);
      else n++;
      p++;
     }
   *np = n;
   return p;
}


int trim_whitespace ()
{
   register unsigned char *p, *pmax, ch;
   int n, save_point, len;
   
   CHECK_READ_ONLY
     len = CLine->len;
   if (len == 0) return(0);
   
   save_point = Point;
   if (Point == len) Point--;
   
   /* Note that we save the point before --ing it.  This way the comparison
    made below will effectively restore it if pointing at non whitespace */
   
   p = CLine->data + Point;
   if (Point && (*p == '\n') && (CBuf != MiniBuffer))
     {
      Point--;
      p--;
     }
   
   while ((Point > 0) && (((ch = *p) == '\t') || (ch == ' ')))
     {
      Point--;
      p--;
     }
   
   if (save_point != Point) if (!eolp() && ((*p != ' ') && (*p != '\t')))
     {
      Point++;
      p++;
     }
   
   n = 0;
   /* this needs to be inlined.  Actually for undo, I need del(n)! */
   pmax = CLine->data + CLine->len;
   while ((p < pmax) && ((ch = *p) != '\n')
        && ((ch == ' ') || (ch == '\t'))) p++, n++;
   
   (void) jed_deln (n);
   return(1);
}

/* indent line to column n */
void indent_to(int n)
{
   int m;
   
   get_current_indent(&m);
   
   if (n != m)
     {
      Point = 0;
      trim_whitespace();
      if (n >= 0) insert_whitespace(&n);
     }
}

int indent_line ()
{
   int n, n1;
   static int in_function;
   
   if (in_function) return -1;
   
   if (CBuf->indent_hook != NULL)
     {
      in_function = 1;
      SLexecute_function(CBuf->indent_hook);
      in_function = 0;
      return 1;
     }
   
   CHECK_READ_ONLY
     
     if (CLine == CBuf->beg) return(0);
   
   push_spot();
   CLine = CLine->prev;
   get_current_indent (&n);
   CLine = CLine->next;
   indent_to(n);
   pop_spot();
   
   /* This moves the cursor to the first non whitspace char if we are
    before it.  Otherwise leave it alone */
   
   n1 = calculate_column();
   get_current_indent(&n);
   if (n1 <= n) point_column(n + 1);
   return 1;
}

/*}}}*/

/*{{{ goto_column and goto_column1 */

/* goto to column c, returns actual column */
int goto_column1(int *cp)
{
   int c1, c = *cp;
   if (c <= 0) c = 1;
   eol();
   c1 = calculate_column();
   if (c1 > c)
     {
      point_column(c);
      c1 = calculate_column();
     }
   return(c1);
}

/* move cursor to column c adding spaces if necessary */
void goto_column(int *c)
{
   int c1 = *c;
   if (c1 <= 0) c1 = 1;
   c1 = c1 - goto_column1(&c1);
   insert_whitespace(&c1);
}

/*}}}*/
/*{{{ skip_whitespace */

/* does not leave current line */
unsigned int skip_whitespace()
{
   unsigned char *p, *pmax;
   
   if (CLine->len == 0) return('\n');
   
   p = CLine->data + Point;
   eol();
   pmax = CLine->data + Point;
   while(p < pmax)
     {
      if ((*p != ' ') && (*p != '\t')) break;
      p++;
     }
   Point = (int) (p - CLine->data);
   if (Point == CLine->len) return '\n';
   return(*p);
}

/*}}}*/
/*{{{ skip_chars1 */
void skip_chars1(char *range, int reverse)
{
   unsigned char lut[256];
   unsigned char *p, *pmax;
   Line *line;
   int n = 0;
   
   SLmake_lut(lut, (unsigned char *) range, (unsigned char) reverse);
   /* more flexibility is achieved with following line */
   if (reverse && lut['\n']) lut['\n'] = 0;
   
   line = CLine;
   while (line != NULL)
     {
      CLine = line;
      p = line->data + Point;
      pmax = line->data + line->len;
      
      while (p < pmax)
        {
           if (0 == lut[*p])
             {
              Point = (int)(p - CLine->data);
                  LineNum += n;
              return;
             }
           p++;
        }
      Point = 0;
      line = CLine->next;
        n++;
     }
   eob();
}

/*}}}*/
/*{{{ bskip_chars1 */

void bskip_chars1(char *range, int reverse)
{
   unsigned char lut[256];
   unsigned char *p;
   Line *line = CLine;
   int n = 0;
   
   SLmake_lut(lut, (unsigned char *) range, (unsigned char) reverse);
   /* more flexibility is achieved with following line */
   if (reverse && lut['\n']) lut['\n'] = 0;
   
   while (1)
     {
      if (Point == 0)
        {
           if (lut['\n'] == 0) return;
           if (NULL == (line = CLine->prev)) break;
           Point = line->len - 1;
             n++;
        }
      
      CLine = line;
      
      p = line->data + (Point - 1);
      
      while (p >= line->data)
        {
           if (0 == lut[*p])
             {
              Point = 1 + (int)(p - line->data);
                  LineNum -= n;
              return;
             }
           
           p--;
        }
      Point = 0;
     }
   bob();
}

/*}}}*/
/*{{{ skip_chars */
void skip_chars (char *range)
{
   if (*range == '^') skip_chars1(range + 1, 1);
   else
     {
      if (*range == '\\') range++;
      skip_chars1(range, 0);
     }
}

/*}}}*/
/*{{{ bskip_chars */
void bskip_chars (char *range)
{
   if (*range == '^') bskip_chars1(range + 1, 1);
   else
     {
      if (*range == '\\') range++;
      bskip_chars1(range, 0);
     }
}

/*}}}*/

/*{{{ looking_at */

/* returns < 0 if what is smaller than current thing, 0 if matched, pos otherwise */
int looking_at(char *what)
{
   register unsigned char *p, *pmax;
   register unsigned char *w = (unsigned char *) what, ch;
   Line *l = CLine;
   
   p = l->data + Point;
   while (1)
     {
      pmax = l->data + l->len;
      while (((ch = *w) != 0) && (p < pmax))
        {
#define upcase(ch) (Case_Sensitive ? ch : UPPER_CASE(ch))
           if ((upcase(ch) != upcase(*p))) return 0;
           p++; w++;
        }
      if (ch == 0) return 1;
      l = l->next;
      if (l == NULL) return 0;
      p = l->data;
     }
}

/*}}}*/

/*{{{ Exiting the editor */

/*{{{ sys_spawn_cmd */

int jed_spawn_fg_process (int (*f)(VOID_STAR), VOID_STAR cd)
{
   int status;
   int inited;

   if ((Jed_Secure_Mode)
       || (Jed_Suspension_Not_Allowed))
     {
      msg_error ("Access to shell denied.");
      return -1;
     }

   /* FIXME: X_Suspend_Hook should not be here.  Currently, this hook is
    * used only by GUI jed, where suspension makes no sense.  Of course in
    * this case, spawning a foreground process also does not make sense.
    */
   if (Batch || (X_Suspend_Hook != NULL))
     return (*f) (cd);

   SLsig_block_signals ();
   inited = Jed_Display_Initialized;
   SLsig_unblock_signals ();
   
   jed_reset_display();
#if !defined(IBMPC_SYSTEM) && !defined(VMS)
   jed_reset_signals ();
#endif
   reset_tty();

   status = (*f) (cd);

   if (inited)
     {
#if !defined(IBMPC_SYSTEM) && !defined(VMS)
      init_signals();
#endif
      if (-1 == init_tty())
        {
           exit_error ("Unable to initialize terminal.", 0);
        }
   
      flush_input ();
      jed_init_display ();
     }

   check_buffers();
   return status;
}

static int suspend_func (void *unused)
{
   (void) unused;
   
   if (X_Suspend_Hook != NULL)
    (*X_Suspend_Hook) ();
   else
     sys_suspend();
   
   return 0;
}
   
int sys_spawn_cmd (void)
{
   if (jed_va_run_hooks ("_jed_suspend_hooks", JED_HOOKS_RUN_UNTIL_0, 0) <= 0)
     return 0;
   
   (void) jed_spawn_fg_process (suspend_func, NULL);

   (void) jed_va_run_hooks ("_jed_resume_hooks", JED_HOOKS_RUN_ALL, 0);

   return 0;
}
   

/*}}}*/
   
/*{{{ jed_quit_jed */
int jed_quit_jed(int status)
{
   Buffer *b;

   (void) jed_va_run_hooks ("_jed_quit_hooks", JED_HOOKS_RUN_ALL, 0);

   b = CBuf;
   /* Any buffer marked with AUTO_SAVE_JUST_SAVE flag should be saved
    * if it has not already been.  That is what the flag is for and this
    * code fragment carries this out.
    */
   do
     {
      if ((b->flags & AUTO_SAVE_JUST_SAVE)
          && (b->flags & BUFFER_MODIFIED)
          && (*b->file))
        {
           while (b->narrow != NULL) widen_buffer(b);
           auto_save_buffer(b);      /* actually, it will save it */
        }
      
#if defined(__WIN32__) && JED_HAS_SUBPROCESSES
      if (b->subprocess)
        jed_kill_process (b->subprocess - 1);
#endif

      (void) jed_unlock_buffer_file (b);
      
      b = b->next;
     }
   while (b != CBuf);
   
   jed_reset_display();
   reset_tty();
#ifdef VMS
   vms_cancel_exithandler();
#endif
#ifdef SLANG_STATS
   SLang_dump_stats("slang.dat");
#endif
#ifdef MALLOC_DEBUG
   SLmalloc_dump_statistics ();
#endif
   /* SLstring_dump_stats (); */
   exit (status);
   return(1);
}


/*}}}*/


/*{{{ save_some_buffers */
/* I should try it like emacs--- if prefix argument, then save all without user
 intervention */
int save_some_buffers (void)
{
   Buffer *b, *tmp;
   int ans = 0;
   int err;
   
   b = CBuf;
   do
     {
      if ((b->flags & BUFFER_MODIFIED)
          && (*b->file))
        {
           if (b->flags & AUTO_SAVE_JUST_SAVE) ans = 1;
           else ans = jed_vget_y_n ("Buffer %s not saved. Save it",
                              b->name);
           
           if (ans == -1)
             /* warning--- bug here if user edits file at
            startup and forgets to save it then aborts. */
             return -1;
           
           if (ans == 1)
             {
              tmp = CBuf;
              switch_to_buffer(b);

              /* It should not be necessary to do this here.  Lower
               * level routines will do it.
               */
              /* while (b->narrow != NULL) widen_buffer(b); */

              err = jed_save_buffer_cmd ();
              switch_to_buffer(tmp);
              if (err < 0) return -1;
              /* b->flags &= ~BUFFER_MODIFIED; */
              /* b->flags |= AUTO_SAVE_BUFFER; */
              b->hits = 0;
             }
        }
      
      b = b->next;
     }
   while (b != CBuf);

   clear_message ();
   return 1;
}

/*}}}*/
/*{{{ exit_jed */
int jed_exit_jed (int status)
{
   static int in_exit_jed = 0;
   
   if (in_exit_jed == 0)
     {
      in_exit_jed = 1;
      if (jed_va_run_hooks ("_jed_exit_hooks", JED_HOOKS_RUN_UNTIL_0, 0) <= 0)
        {
           in_exit_jed = 0;
           return -1;
        }
     }

   in_exit_jed = 0;
   if (SLang_Error) return -1;

#if JED_HAS_SUBPROCESSES
   if (1 != jed_processes_ok_to_exit ())
     return 1;
#endif
   
   if (save_some_buffers() > 0) jed_quit_jed(status);
   return 1;
}

/*}}}*/

/*}}}*/

int jed_exit_jed_cmd (void)
{
   return jed_exit_jed (0);
}

Generated by  Doxygen 1.6.0   Back to index