/*=========================================================================*/
/*                                                                         */
/*  MISC - assorted macros for the ME Text Editor.                         */
/*         Some of these macros are not earth-shattering, but are included */
/*         for demonstration purposes.                                     */
/*                                                                         */
/*  Written by Marc Adler  Magma Systems                                   */
/*             (Creators of ME and New York Word)                          */
/*                                                                         */
/* Functions :                                                             */
/*   copy_ch_above - copies the char above the cursor & inserts it at the  */
/*                   cursor position                                       */
/*   copy_wd_above - copies the word above the cursor & inserts it at the  */
/*                   cursor position                                       */
/*                                                                         */
/*                                                                         */
/*                                                                         */
/*=========================================================================*/

#include mekeys.h

int     CBRACE;   /* C Braces */

init()
{
  assign_key("copy_ch_above", CTRL_C);
  assign_key("copy_wd_above", CTRL_W);
  assign_key("downpara", 14);
  assign_key("uppara",   16);
}

copy_ch_above()
{
  int c;

  if (up())             /* if we're not at the first line */
  {                     /* go up and get the char above the cursor position */
    if (!is_eol())
      c = currchar();
    else
      c = ' ';
    down();
    if (c == 0)         /* check for a NULL character */
      c = ' ';
    insert(chr(c));     /* insert the string equivalent of the character */
  }
}

copy_wd_above()
{
  int col1, col2;
  string str;

  save_position();
  str = "";

  if (up() && !is_eol())                        /* move the cursor up */
  {
    col1 = currcol();                           /* save the starting column */
    while (!is_eol() && currchar() == ' ')      /* move to 1st char of word */
      right(); 
    while (!is_eol() && currchar() != ' ')      /* move to end of word */
      right();
    col2 = currcol();                           /* get current column */
    if (col2 > col1)                            /* extract the word */
      str = substr(currline(), col1, col2 - col1);
  }

  restore_position();
  insert(str);
}


/* These macros move up and down one paragraph. C programmers who want */
/* to move up and down one function can alter these macros. */

downpara()
{
  while (!is_line_blank(currline()) && currlinenum() < lastlinenum())
    down();
  while (is_line_blank(currline())  && currlinenum() < lastlinenum())
    down();
}

uppara()
{
  if (!is_line_blank(currline()))
    up();      /* don't get stuck at first line of para */
  while (is_line_blank(currline())  && currlinenum() > 1)
    up();
  while (!is_line_blank(currline()) && currlinenum() > 1)
    up();
  if (currlinenum() > 1)
    down();
}

is_line_blank(str)
  string str;
{
  int i;
  int len;

  len = strlen(str);

  for (i = 1;  i <= len;  i = i + 1)
    if (substr(str, i, 1) != " ")
      return 0;
  return 1;
}


/* This macro shifts a marked block of text left or right. You can do */
/* the same thing my marking the area to indent, using the 'indent'   */
/* block command, and using the arrow keys. */

shift()
{
  int line1, line2;
  int n, j;

  /* Prompt the user for the indent width, and check for a bad number. */
  n = atoi(get_tty_str("How many spaces (default 2) ?"));
  if (n == 0)  n = 2;

  line1 = marked_line();    /* get the marked range */
  line2 = currlinenum();
  goline(line1);            /* set the cursor to the start of the area */
  gobol();

  while (currlinenum() <= line2)
  {
    if (n >= 0)         /* shift rightwards - insert n spaces */
    {
      gobol();
      insert(repstr(" ", n));
    }
    else                /* a negative amount means to shift leftwards */
    {
      j = -n;
      while (j > 0)     /* delete 'n' characters */
      {
        delchar();
        j = j - 1;
      }
    }
    down();             /* move down to the next line */
  }

  clear_mark();         /* remove any existing marks */
}



/**************************************************************************/
/* The following macros were written by Blake McBride of Miami, Fla. They */
/* were written for version 1.2, so they could probably be trimmed down   */
/* by using the new library functions.                                    */
/* Any macro contributions will be added to the library - send 'em in!!!  */
/**************************************************************************/

/*************************************************************************
  If you use any of Blake's macros, you might want to place these key
  assignments (and the initialization of CBRACE) in the init() function.

  assign_key("scroll_up",   CTRL_F1);
  assign_key("scroll_down", CTRL_F2);
  assign_key("lbrace", '{');
  assign_key("rbrace", '}');
  CBRACE = 1; 
  assign_key("delete_white_space", ALT_D);
  assign_key("line_to_top", ALT_T);
*************************************************************************/

/* lbrace */
/* If CBRACE is on, insert a brace and start the next line past the indent */
lbrace()
{      
  /* If the CBRACE variable is not set, then insert a brace literally */
  if (!CBRACE)  {
    insert("{");
    return;
  }

  /* Insert a brace, and append a new line */
  insert("{\n");
  up();
  /* Find the first non-blank character on the line */
  for (col = 0; currchar() == ' ';  col++)
    right();
  /* Move to the next line and indent properly */
  gobol();             
  down();
  insert(repstr(" ", col));
  insert("\t");   /* tab past the indentation */
}

/* rbrace */
/* If CBRACE is on, then insert the right brace at the appropriate column */
rbrace()
{
  int  col, i, nb, cc, back;

  if (!CBRACE)  {
    insert("}");
    return;
  }

  gobol();
  save_position();        
  back = nb = 0;

  while (nb || rsearch("{|}"))
  {
    /* If we have a brace, adjust the level */
    if ((cc = currchar()) == '}')
      nb++;
    else if (cc == '{')
      if (--nb <= 0)  break;

    /* Move back a character (6000 chars from the starting pt maximum) */
    if (!left())
    { /* Can't find the match - just insert } at the cursor */
      restore_position();
      insert("}");
      return;
    }
  }

  /* Move to the first non-blank on the left-brace line. Col is the
     column number of the non-blank */
  col = currcol();
  restore_position();

  /* Go to the line we want to insert the right brace in. Move to the
     column which the left brace occured in & insert the matching '}'  */
  insert(repstr(" ", col-1));
  insert("}\n");

  /* Auto-indent next line */
  insert(repstr(" ", col-1));
}
  
  
/* These two functions set and clear CBRACE mode */
cbrace_on()
{
  CBRACE = 1;
}

cbrace_off()
{
  CBRACE = 0;
}



/* Scroll the screen down 1 line */
scroll_down()
{    
  int     flag;
  
  if (get_window_size() != get_window_line())  {
    flag = 1;
    save_position();
  }
  else
    flag = 0;
  home();
  up();
  if (flag)
    restore_position();
  else
    bottom();
}

/* Scroll the screen up one line */
scroll_up()
{
  if (get_window_line() > 1)  {
    flag = 1;
    save_position();
  }
  else
    flag = 0;
  bottom();
  down();
  if (flag)
    restore_position();
  else
    home();
}

/* ALT T */
/* Reposition the current window so the current line is at the top */
line_to_top()
{
  n = get_window_line();
  bottom();
  while (n--)
    if (!down())     break;
  home();
}

/* Returns the line number relative to the top of the window */
get_window_line()
{          
  save_position();
  last = currlinenum();
  home();
  last -= currlinenum() - 1;
  restore_position();           
  return last;
}

/* ALT D */
/* Delete all white space surrounding the cursor */
delete_white_space()
{
  while (currchar() == ' ')     /* trim right */
    delchar();
  while (!is_bol())  {          /* trim left  */
    left();
    if (currchar() != ' ')  {
      right();
      break;
    }
    delchar();
  }
}

/* string_size */
/* The string_size function assumes that the cursor in somewhere within */
/* a C string. It tells the user how long the string is.                */
string_size()
{
  int  i, c;
  
  save_position();

  /* Move left until we find the starting quote */
  left();
  while (currchar() != '"'  &&  !is_bol())
    left();

  if (currchar() != '"')  {      /* no starting quote */
    restore_position();
    bell();
    return;
  }

  /* Move to the closing quote */
  right();
  for (i=0 ; (c=currchar())  &&  c != '"' ; ++i)
    right();
  restore_position();
  if (c != '"')  {      /* unmatched quotes */
    bell();
    return;
  }

  /* Tell the user the length of the string and wait for a key press */
  message(sprintf("String size = %d", i));
  get_tty_char();
}
