/* ########################################################################

		    SMAC FILE USED BY XCORAL EDITOR

   File: mode-ext.sc
   Path: /home/thierry/Xcoral/lib/xcoral/mode-ext.sc
   Description: 
   Created: Sun Aug  7 16:09:33 MET 1994
   Author: Thierry Emery
   Modified: Mon May 21 22:21:30 2001
   Last maintained by: Thierry Emery

   RCS $Revision$ $State$
   

   ########################################################################

   Note: extensions of C and C++ modes
   
   Requires: mode.sc
	     utilities.sc

   Defines: next_form, next_form_and_delete, current_form,
	    delete_current_form, transpose_forms, blink_paren,
	    current_indent, remove_indent, reindent_to,
	    indent_region, delete_previous_char_untabify

   Suggested bindings: "^xy" transpose_forms
                       "^]z" blink_paren
		       "^h" delete_previous_char_untabify

   ########################################################################

   Copyright (c) : Thierry Emery

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

   ######################################################################## */


{
  if (! function("goto_beginning_of_c_definition"))
    load_file("mode.sc");
  if (! function("window_substring"))
    load_file("utilities.sc");
}

/* -------------------------------------------------------------------------
   extract and optionnally (depending on <delete_p>) delete next form (malloc)
   ------------------------------------------------------------------------- */

char* next_form_delete_opt(int delete_p) {

  int origin=current_position(),beg,end;
  char* form;

  forward_c_form();
  end = current_position();
  backward_c_form();
  beg = current_position();
  form = window_substring(beg,end);
  if (delete_p)
    delete_region(beg,end);
  
  goto_char(origin);
  
  return form;
}

/* -------------------------------------------------------------------------
   extract next form (malloc)
   ------------------------------------------------------------------------- */

char* next_form() {

  return next_form_delete_opt(0);
}

/* -------------------------------------------------------------------------
   extract and delete next form (malloc)
   ------------------------------------------------------------------------- */

char* next_form_and_delete() {

  return next_form_delete_opt(1);
}

/* -------------------------------------------------------------------------
   current form (malloc)
   ------------------------------------------------------------------------- */

char* current_form() {

  forward_c_form();
  backward_c_form();

  return next_form();
}

/* -------------------------------------------------------------------------
   delete current form
   ------------------------------------------------------------------------- */

void delete_current_form() {

  forward_c_form();
  backward_c_form();
  delete_next_c_form();
}

/* -------------------------------------------------------------------------
   transpose current and preceding form
   ------------------------------------------------------------------------- */

void transpose_forms() {

  char* current;
  
  forward_c_form();
  backward_c_form();
  current=next_form_and_delete();
  backward_c_form();
  insert_string(current);
  free(current);
}


/* -------------------------------------------------------------------------
   blink at matching parenthesis
   ------------------------------------------------------------------------- */

void blink_paren() {

  int origin=current_position(), blpos;
  
  if (strchr(")}]", previous_char())) {
    backward_c_form();
    blpos = current_position();
    goto_char(origin);
    blink(blpos);
  }
}

/* --------------------------------------------------------------------------------
   current indent
   -------------------------------------------------------------------------------- */

int current_indent() {

  int origin = current_position(), indent = 0;

  goto_beginning_of_line();
  c_jump_spaces_forward();
  indent = c_column(current_position());
  goto_char(origin);

  return indent;
}

/* --------------------------------------------------------------------------------
   remove indent
   -------------------------------------------------------------------------------- */

void remove_indent() {

  int origin = current_position();

  goto_beginning_of_line();
  while (current_char() && strchr(" \t", current_char())) {
    delete_char();
    if (current_position() < origin) {
      origin--;
    }
  }
  goto_char(origin);
}

/* --------------------------------------------------------------------------------
   reindent_to: copied from latex_change_column()
   -------------------------------------------------------------------------------- */

int reindent_to(int column) {

  int correction = 0;

  goto_beginning_of_line();
  
  /* add necessary tabs */
  
  for (; column >= 8; column -= 8)
    switch (current_char()) {
    case ' ' :
      replace_char('\t');
    case '\t' :
      goto_next_char();
      break;
    default:
      insert_char('\t');
      correction += 1;
  }
  
  /* add necessary spaces */
  
  while (column--)
    switch (current_char()) {
    case '\t' :
      replace_char(' ');
    case ' ' :
      goto_next_char();
      break;
    default:
      insert_char(' ');
      correction += 1;
  }
  
  /* remove undesired tabs and spaces */
  
  if (! correction)
    while (current_char() && strchr(" \t", current_char())) {
    delete_char();
    correction -= 1;
  }
  
  return correction;
}

/* --------------------------------------------------------------------------------
   indent_region 
   -------------------------------------------------------------------------------- */

void latex_indent_region();
void shell_script_indent_region();

indent_region()
{
    char *mode_name = current_mode();
    
    if ((strcmp(mode_name,"C-mode") == 0)
	||(strcmp(mode_name,"C++mode") == 0)) {
	c_indent_region();
    }
    else if ((strcmp(mode_name,"Latex") == 0)) {
	latex_indent_region();
    }
    else if ((strcmp(mode_name,"shell") == 0)) {
	shell_script_indent_region();
    }
    else
      /* Other modes */
      ;

    if(mode_name)
      free(mode_name);
}

/* -------------------------------------------------------------------------
   delete previous char
   and if it was a TAB insert enough spaces to go left one column only
   ------------------------------------------------------------------------- */

void delete_previous_char_untabify() {

  if (previous_char() == '\t') {
    int after_column = c_column(current_position()), before_column = c_column(current_position()-1);
    delete_previous_char();
    while (++before_column < after_column)
     insert_char(' ');
  }
  else
   delete_previous_char();
}

