/**********************************************************************/
/*                                                                    */
/*	CRISP - Programmable editor                                   */
/*	===========================                                   */
/*                                                                    */
/*  File:          extra.cr                                           */
/*  Author:        P. D. Fox                                          */
/*  Created:       19 Feb 1990                     		      */
/*                                                                    */
/*  Copyright (c) 1990 Paul Fox                                       */
/*                All Rights Reserved.                                */
/*                                                                    */
/*                                                                    */
/*--------------------------------------------------------------------*/
/*  Description:  Extra editing functions.                            */
/*                                                                    */
/**********************************************************************/

/* SCCS ID: %Z% %M% %R%.%L% */
# include	"crisp.h"

# define	HALF_SEC	500
list	extra_list = {
	"Extras Menu",
	"Edit DOS file",	"edit_dos_file",
	"Edit file again",	"edit_again",
	"Edit text file",	"edit_text_file",
	"Edit binary file",	"edit_binary_file",
	"Grep current word",	"grep_function",
	"Italicise word",	"italicise_word",
	"Join next line",	"join_line",
	"Literal display mode",	"literal",
	"Pipe region",		"pipe_region",
	"Writeable buffer",	"make_writeable",
	"Zoom window",		"zoom"
	};

/**********************************************************************/
/*   Macro  to  extend  the  number of editing keys available. We'll  */
/*   use ^A as an escape code to get to this macro.		      */
/**********************************************************************/
void
extra()
{	int	ch;

	ch = read_char(HALF_SEC);
	if (ch == -1) {
		keyboard_push();
		assign_to_key("<Ctrl-B>", "edit_binary_file");
		assign_to_key("<Ctrl-D>", "edit_dos_file");
		assign_to_key("<Ctrl-E>", "edit_again");
		assign_to_key("<Ctrl-G>", "grep_function");
		assign_to_key("<Ctrl-I>", "italicise_word");
		assign_to_key("<Ctrl-J>", "join_line");
		assign_to_key("<Ctrl-L>", "literal");
		assign_to_key("<Ctrl-P>", "pipe_region");
		assign_to_key("<Ctrl-T>", "edit_text_file");
		assign_to_key("<Ctrl-W>", "make_writeable");
		assign_to_key("<Ctrl-A>", "zoom");
		select_feature(extra_list, 20);
		keyboard_pop();
		return;
		}
	switch (ch) {
		case key_to_int("<Ctrl-B>"):
			edit_binary_file();
			break;
		case key_to_int("<Ctrl-D>"):
			edit_dos_file();
			break;
		case key_to_int("<Ctrl-E>"):
			edit_again();
			break;
		case key_to_int("<Ctrl-G>"):
			grep_function();
			break;
		case key_to_int("<Ctrl-I>"):
			italicise_word();
			break;
		case key_to_int("<Ctrl-J>"):
			join_line();
			break;
		case key_to_int("<Ctrl-L>"):
			literal();
			break;
		case key_to_int("<Ctrl-P>"):
			pipe_region();
			break;
		case key_to_int("<Ctrl-T>"):
			edit_text_file();
			break;
		case key_to_int("<Ctrl-W>"):
			make_writeable();
			break;
		case key_to_int("<Ctrl-A>"):
			zoom();
			break;
		}
}
/**********************************************************************/
/*   Clears the Read-only flag for the current buffer.		      */
/**********************************************************************/
void
make_writeable()
{
	set_buffer_flags(~BF_READONLY);
	message("Buffer now writable.");
}
/**********************************************************************/
/*   Macro  to  re-read  in  a file. Used when a file has changed on  */
/*   disk and we want to see the latest version.		      */
/**********************************************************************/
void
edit_again()
{
	string file_name;
	int	curbuf, line;
	int	l, c;
        string  arg;

	/***********************************************/
	/*   If  buffer  being  viewed  in  more than  */
	/*   one window then we can't do it.	       */
	/***********************************************/
	if (inq_views() > 1) {
		error("Buffer being viewed in %d other windows.",
			inq_views()-1);
		return;
		}
        /***********************************************/
        /*   Give  user  a  last  chance  to lose the  */
        /*   edits.                                    */
        /***********************************************/
        if (inq_modified()) {
        	get_parm(0, arg, "Buffer modified -- are you sure (y/n) ? ");
	        if (upper(substr(arg, 1, 1)) != "Y") {
                        error("Aborted.");
                        return;
                        }
                }	
	inq_top_left(l, c);
	inq_names(file_name);
	inq_position(line);

	curbuf = inq_buffer();
	delete_buffer(curbuf);

	edit_file(file_name);
	set_top_left(l, c);
	goto_line(line);
}

/**********************************************************************/
/*   Macro to italicise a word in nroff/troff format.		      */
/**********************************************************************/
void
italicise_word()
{
	default_word_left();
	insert("\\fI");
	re_search(NULL, "[ \t]|$");
	insert("\\fR");
}

/**********************************************************************/
/*   Do  a  grep  on  all  .[ch]  files in current directory on word  */
/*   where the cursor is. (Similar to a tags function).		      */
/**********************************************************************/
void
grep_function()
{
	string function;
	int	i;
		
	save_position();
	re_search(SF_BACKWARDS, "<|{[~_A-Za-z0-9]\\c}");
	function = ltrim(trim(read()));
	i = re_search(NULL, "[~_A-Za-z0-9]", function);
	if (i > 0)
		function = substr(function, 1, i - 1);
	restore_position();
	if (function == "") {
		beep();
		return;
		}
	grep(function, "*.[ch]");
}
/**********************************************************************/
/*   This  macro  is  used  to  pipe a region to an external command  */
/*   and  replace  the region with the output from the command. This  */
/*   is similar to the !! feature of vi.			      */
/**********************************************************************/
void
pipe_region()
{	string	command;
	int	mark_set;
	
	get_parm(NULL, command, "Pipe to: ");
	if (command == "") {
		message("");
		return;
		}
		
	/***********************************************/
	/*   If  no  marked region, then do the whole  */
	/*   buffer.				       */
	/***********************************************/
	mark_set = inq_marked();
	if (!mark_set) {
		save_position();
		top_of_buffer();
		drop_anchor(MK_LINE);
		end_of_buffer();
		refresh();
		}

	write_block("| " + command + ">/tmp/crpipe.tmp", NULL, TRUE);
	/***********************************************/
	/*   Handle deletion of column markers.	       */
	/***********************************************/
	if (inq_marked() == MK_COLUMN)
		block_delete();
	else
		delete_block();
	read_file("/tmp/crpipe.tmp");
	remove("/tmp/crpipe.tmp");
	
	if (!mark_set) {
		raise_anchor();
		restore_position();
		}
}
void
edit_dos_file()
{
	edit_typed_file("DOS", EDIT_CR);
}
void
edit_text_file()
{
	edit_typed_file("text", EDIT_ASCII);
}
void
edit_binary_file()
{
	edit_typed_file("binary", EDIT_BINARY);
}
void
edit_typed_file(string msg, int flags)
{	string	filename;
	int	ml = inq_msg_level();

	if (get_parm(NULL, filename, "Edit " + msg + " file: ") <= 0 ||
	    filename == "")
	    	return;
	set_msg_level(0);
	edit_file(flags, filename);
	set_msg_level(ml);
	if (substr(inq_message(), 1, 4) == "Edit")
		display_file_name();
}
