/********************************************************************
 *                                                                  *
 *      CRISP - Custom Reduced Instruction Set Programmers Editor   *
 *                                                                  *
 *      (C) Paul Fox, 1989, 1990, 1991                              *
 *                                                                  *
 *    Please See COPYLEFT notice.                                   *
 *                                                                  *
 ********************************************************************/
# include	"crisp.h"

/**********************************************************************/
/*   Width of C comment if it starts in column 0.		      */
/**********************************************************************/
# define	RMARGIN		63

/**********************************************************************/
/*   Width of C comment if its indented.			      */
/**********************************************************************/
# define	C_INDENTED_MARGIN 40
# define	C_LMARGIN	3 /* Left hand margin after open comment.  */
# define	C_RMARGIN	3 /* Right hand margin before close comment.*/

int	wp_rmargin = RMARGIN;
int	wp_ragged = FALSE;
int	wp_autowrap = FALSE;
int	wp_quiet = FALSE;

/**********************************************************************/
/*   Flag  set  if  we  have  nroff-style  file (so we know that dot  */
/*   commands terminate a paragraph).				      */
/**********************************************************************/
int	nroff_file = TRUE;
/**********************************************************************/
/*   Following  variable  set to TRUE whilst doing a C comment. When  */
/*   this  is  TRUE  the  right  margin  moves  with  the left. When  */
/*   FALSE, the right margin is a constant.			      */
/**********************************************************************/
int	wp_cstyle = FALSE;

list	wp_list = {
		"Autowrap          : ", {"Off", "On"},
		"Margins           : ", {"Justified", "Ragged"},
		"Right Hand Margin : ", "",
		};
void
wp_options()
{
	list	r_list;

	r_list[0] = wp_autowrap;
	r_list[1] = wp_ragged;
	/***********************************************/
	/*   Make the margin a string field.	       */
	/***********************************************/
	r_list[2] = "" + wp_rmargin;

	wp_list[2 * 3 - 1] = "" + wp_rmargin;
	r_list = field_list("Document Options", r_list, wp_list);
	wp_autowrap = r_list[0];
	wp_ragged = r_list[1];
	wp_rmargin = atoi(r_list[2]);
	if (wp_autowrap)
		register_macro(REG_TYPED, "reg_autowrap", TRUE);
	else
		unregister_macro(REG_TYPED, "reg_autowrap", TRUE);
}
void
autowrap()
{
	wp_autowrap = !wp_autowrap;
	if (wp_autowrap) {
		message("Autowrap turned on.");
		register_macro(REG_TYPED, "reg_autowrap", TRUE);
		}
	else {
		message("Autowrap turned off.");
		unregister_macro(REG_TYPED, "reg_autowrap", TRUE);
		}
}
string
get_autowrap()
{
	return wp_autowrap ? "yes" : "no";
}
string
get_justification()
{
	return wp_ragged ? "no" : "yes";
}
void
reg_autowrap()
{	int	col;
	string	ch;

	/***********************************************/
	/*   If not at end of line then don't do       */
	/*   anything special.			       */
	/***********************************************/
	if (read(1) != "\n") {
		return;
		}

	/***********************************************/
	/*   Look at the character just inserted.      */
	/***********************************************/
	prev_char();
	/***********************************************/
	/*   If not a space, or we havent exceeded     */
	/*   the line length then don't do anything    */
	/*   just yet.				       */
	/***********************************************/
	inq_position(NULL, col);
	if ((ch = read(1)) != " " || col < wp_rmargin) {
		next_char();
		return;
		}
	drop_anchor(MK_LINE);
	wp_quiet = TRUE;
	default_format_block();
	wp_quiet = FALSE;
	up();
	end_of_line();
	insert(" ");
}
/**********************************************************************/
/*   Prompt for margin size and turn autowrap on.		      */
/**********************************************************************/
void
margin()
{
	wp_ragged = TRUE;
	if (get_parm(0, wp_rmargin, "Right hand margin: ", NULL, wp_rmargin))
		if (!wp_autowrap)
			autowrap();
	message("");
}
string
get_margin()
{
	return "" + wp_rmargin;
}
/**********************************************************************/
/*   Yacc files have C style comments.				      */
/**********************************************************************/
void
y_format_block()
{
	c_format_block();
}
void
y_uncomment_block()
{
	c_uncomment_block();
}
void
cr_uncomment_block()
{
	c_uncomment_block();
}
void
c_uncomment_block()
{
	int	start_line,
		start_col,
		end_line,
		end_col;
	inq_marked(start_line, start_col, end_line, end_col);
	message("Stripping existing comments.");
	save_position();
	re_translate(SF_GLOBAL | SF_BLOCK, 
		"<[^A-Za-z0-9]@{[A-Za-z0-9]}", "\\0");
	re_translate(SF_GLOBAL | SF_BLOCK, "\\*{/}@[ \t]@$", "");
	restore_position();
}
void
h_format_block()
{
	c_format_block();
}
void
cr_format_block()
{
	c_format_block();
}
void
c_format_block()
{
	int	start_line,
		start_col,
		end_line,
		end_col,
		offset,
		saved_margin = wp_rmargin,
		insert_vert = FALSE;
	int	saved_nroff_file = nroff_file;
	string	indent_string;
	string	s, s1;
	
	if (inq_marked(start_line, start_col, end_line, end_col) == 0) {
		error("No marked block.");
		return;
		}

	save_position();
	move_abs(start_line, 1);
	s1 = read();
	re_search(NULL, "[^ \t]");
	inq_position(NULL, offset);
	offset --;
	if (offset)
		wp_rmargin = C_INDENTED_MARGIN;
	move_abs(start_line - 1, 1);
	s = compress(read(), TRUE);
	if (start_line == 1 || s == "" ||
	    substr(s, 1, 2) != "/*")
		insert_vert = TRUE;
	restore_position();
	
	c_uncomment_block();

	/***********************************************/
	/*   Make  sure  right hand margin moves with  */
	/*   the indentation level.		       */
	/***********************************************/
	wp_cstyle = TRUE;
	nroff_file = FALSE;
	if (default_format_block() < 0) {
		nroff_file = saved_nroff_file;
		wp_rmargin = saved_margin;
		wp_cstyle = FALSE;
		return;
		}
	nroff_file = saved_nroff_file;
	wp_cstyle = FALSE;
	inq_position(end_line);

	/***********************************************/
	/*   Now  put  comment  characters around the  */
	/*   formatted text.			       */
	/***********************************************/
	message("Adding C comments.");
	goto_line(start_line);
	end_col = wp_rmargin + C_LMARGIN + 2 + C_RMARGIN;

	/***********************************************/
	/*   Take    the   white   space   from   the  */
	/*   beginning  of  the  first  line  of  the  */
	/*   comment  to  indicate how much to indent  */
	/*   by.				       */
	/***********************************************/
	indent_string = substr(s1, 1, strlen(s1) - strlen(ltrim(s1)));

	if (insert_vert) {
		insert(indent_string);
		insert("/");
		insert("*", end_col - 1);
		insert("/\n");
		}
	while (start_line < end_line) {
		insert(indent_string);
		insert("/*");
		insert(" ", C_LMARGIN);
		move_abs(0, end_col + offset);
		insert("*/");
		down();
		beginning_of_line();
		++ start_line;
		}
	if (insert_vert) {
		insert(indent_string);
		insert("/");
		insert("*", end_col - 1);
		insert("/\n");
		}
	wp_rmargin = saved_margin;
	message("Formatting complete.");
}

/**********************************************************************/
/*   Macro  to  format  a  block  of  text  (justify  left and right  */
/*   margins). Returns -1 if no marked area; 0 if successful.	      */
/**********************************************************************/
int
default_format_block()
{
	int	start_line,
		start_col,
		end_line,
		end_col,
		space,
		num_spaces,
		num_to_make_up,
		i, j,
		para_no,
		line_no;

	string	line,
		new_line,
		indent,
		rest1,
		rest_of_line;
	int	saved_margin = wp_rmargin;

	if (inq_marked(start_line, start_col, end_line, end_col) == 0) {
		error("No marked block.");
		return -1;
		}

	/***********************************************/
	/*   Strip   off   any   leading   tabs   and  */
	/*   remember   how   much   first  line  was  */
	/*   indented so we can re-indent later.       */
	/***********************************************/
	save_position();
	goto_line(start_line);
	indent = "";
	while (index(" \t", read(1))) {
		indent += read(1);
		next_char();
		}
	inq_position(NULL, j);
	if (!wp_cstyle) {
		wp_rmargin -= j;
		if (wp_rmargin < 10)
			wp_rmargin = 10;
		}
	restore_position();
	if (indent != "")
		re_translate(SF_GLOBAL | SF_BLOCK, "<[ \t]+", "");
	raise_anchor();

	while (start_line <= end_line) {
		goto_line(start_line);
		line = "";
		line_no = start_line;

		++ para_no;
		if (! wp_quiet)
			message("Formatting paragraph %d.", para_no);

		while (line_no <= end_line) {
			new_line = read();
			if (strlen(new_line) < 2 || 
			    (nroff_file && substr(new_line, 1, 1) == "."))
				break;
			line += " " + new_line;
			delete_line();
			-- end_line;
			}
		start_line = line_no;
		line = compress(line, TRUE);

		/***********************************************/
		/*   While  line  is too long to fit, we keep  */
		/*   chopping  the  line  and  inserting  the  */
		/*   formatted remains.			       */
		/***********************************************/
		while (strlen(line) > wp_rmargin) {
			rest_of_line = substr(line, wp_rmargin);
			line = substr(line, 1, wp_rmargin - 1);
			space = rindex(line, " ");
			rest_of_line = substr(line, space) + rest_of_line;
			line = substr(line, 1, space - 1);
			/*
			/*   Insert line a word at a time, so that we can
			/*   space fill as we go along.
			/**/
			if (wp_ragged)
				num_spaces = 0;
			else {
				num_to_make_up = wp_rmargin - strlen(line);
				num_spaces = string_count(line, " ");
				i = num_to_make_up / num_spaces + 1;
				j = num_to_make_up % num_spaces;
				}
			insert(indent);
			while (num_spaces) {
				space = index(line, " ");
				if (space == 0)
					break;
				rest1 = substr(line, space + 1);
				line = substr(line, 1, space - 1);
				insert(line);
				insert(" ", i);
				if (j) {
					-- j;
					insert(" ");
					}
				-- num_spaces;
				line = rest1;
				}
			insert(line + "\n");
			line = compress(rest_of_line, TRUE);
			++ end_line;
			++ start_line;
			}
		if (line != "") {
			insert(indent);
			insert(line + "\n");
			++ end_line;
			++ start_line;
			}
		++ start_line;
		refresh();
		}
	if (! wp_quiet)
		message("");
	wp_rmargin = saved_margin;
	return 0;
}
/**********************************************************************/
/*   Function to center lines of text.				      */
/**********************************************************************/
void
center()
{
	int	num_lines;
	int	cur_line;
	int	start_line, end_line;
	string	line;
	
	inq_position(cur_line);
	/***********************************************/
	/*   If  we  got an argument then center that  */
	/*   number  of  lines.  If not and we have a  */
	/*   marked   region  then  center  that.  If  */
	/*   neither  of  these  just  center current  */
	/*   line.				       */
	/***********************************************/
	if (get_parm(0, num_lines) > 0) {
		start_line = cur_line;
		end_line = cur_line + num_lines - 1;
		}
	else if (inq_marked(start_line, NULL, end_line) == 0) {
		start_line = cur_line;
		end_line = start_line;
		}
	
	save_position();
	while (start_line <= end_line) {
		move_abs(start_line, 1);
		line = trim(ltrim(read()));
		delete_to_eol();
		move_rel(NULL, (wp_rmargin - strlen(line)) / 2);
		insert(line);
		start_line++;
		}
	restore_position();
}
