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


# define	SHM_CHAR	0x01	/* Char/line mode.	*/
# define	SHM_ECHO_OFF	0x02	/* ECHO turned off.	*/

# define	MAX_HISTORY	20

# define	LOCAL	1

string	prompt_regexp = "^*[:$#%] @\\c";
int	sh_key_map, sh_id;
list	sh_list = 
	{"Character Mode", "sh_select",
		"message \"Characters directly sent to process buffer.\"",
	"Line Mode", "sh_select",
		"message \"Local editing of line before sending to buffer.\"",
        "Echo Toggle", "sh_select",
		"message \"Toggle between local echo.\""
	};
void
main()
{
	keyboard_push();
	keyboard_typeables();
	sh_key_map = inq_keyboard();

	assign_to_key("<Enter>", 	"sh_send_line");
	assign_to_key("<Backspace>", 	"sh_backspace");
	assign_to_key("<Del>", 		"sh_delete");
	assign_to_key("#127", 		"sh_delete");
	assign_to_key("<Ins>", 		"sh_paste");
	assign_to_key("<Ctrl-C>", 	"sh_send_sig");
	assign_to_key("<Ctrl-N>", 	"sh_next_cmd");
	assign_to_key("<Ctrl-O>", 	"sh_popup");
	assign_to_key("<Ctrl-P>", 	"sh_prev_cmd");
	keyboard_pop(1);
}
void
bash()
{
	create_shell("bash", "Bash-Buffer", PF_ECHO | PF_NOINSERT);
}
void
ksh()
{
	create_shell("/bin/ksh", "Korn-Shell-Buffer", PF_ECHO | PF_NOINSERT);
}
void
sh()
{
	create_shell("/bin/sh", "Shell-Buffer", PF_ECHO | PF_NOINSERT);
}
void
csh()
{
	create_shell("/bin/csh", "Cshell-Buffer", PF_ECHO | PF_NOINSERT);
}
void
tcsh()
{
	create_shell("/bin/tcsh", "Tcshell-Buffer", PF_ECHO | PF_NOINSERT);
}
void
cmd()
{
	create_shell("cmd", "Command-Buffer", PF_ECHO | PF_NOINSERT);
}
int
create_shell(string shell_path, string buffer_name, int sh_flags)
{
	string	tmpbuf,
		sh_newline;	/* Newline character for buffer.*/
	int	sh_start_line,	/* Place where input started. */
		sh_start_col,
		sh_end_line,	/* Place where input cursor */
		sh_end_col,	/* has got to. */
		sh_cmd,		/* Where to place next command on history */
		sh_index,	/* Index to current command. */
		sh_mode;
		
	list	sh_history;
	int	sh_buf;

	if (++sh_id > 1) {
		sprintf(tmpbuf, "-%d", sh_id);
		buffer_name += tmpbuf;
		}

	sh_buf = create_buffer(buffer_name, NULL, 0);
	set_buffer(sh_buf);
	set_buffer_flags(~BF_TABS, BF_ANSI);
	attach_buffer(sh_buf);
	inq_names(tmpbuf, NULL, NULL);
	autosave_disable(tmpbuf);

	make_local_variable(
		sh_start_line, sh_start_col,
		sh_end_line, sh_end_col,
		sh_mode,
		sh_index,
		sh_cmd,
		sh_history,
		sh_newline,
		sh_flags
		);
	sh_cmd = 0;
	sh_index = 0;
	sh_mode = 0;
	sh_start_line = -1;
	/*----------------------------------------
	/*   Default newline character is \n but
	/*   allow calling macro to override it.
	/*----------------------------------------*/
	sh_newline = "\n";
	get_parm(3, sh_newline);
	register_macro(REG_TYPED, "sh_insert", LOCAL);
	connect(sh_flags, shell_path);
	use_local_keyboard(sh_key_map);

	return(sh_buf);
}
void
sh_popup()
{       int     result;
	extern int sh_mode;
	
        select_list("Options", "", 3, sh_list, 2);
        refresh();
        switch (result) {
                case 1: sh_char_mode();
			break;
                case 2: sh_line_mode();
			break;
		case 3: if (sh_mode & SHM_ECHO_OFF)
				sh_mode &= ~SHM_ECHO_OFF;
			else
				sh_mode |= SHM_ECHO_OFF;
			break;
                }
}
void
sh_select()
{	extern int result;

	inq_position(result);
	push_back(key_to_int("<Esc>"));
}
/**********************************************************************/
/*   Send a SIGINT to the process.				      */
/**********************************************************************/
void
sh_send_sig()
{
	send_signal(2);
}
void
sh_backspace()
{	extern int sh_mode;

	if (sh_mode & SHM_CHAR) {
		insert_process("\x8");
		return;
		}

	backspace();
}
void
sh_delete()
{	extern int sh_mode;

	if (sh_mode & SHM_CHAR) {
		insert_process("\x7f");
		return;
		}

	delete_character();
}
void
sh_insert()
{	extern int sh_mode;
	extern int sh_start_line, sh_start_col;
	extern int sh_flags;

	if (sh_mode & SHM_CHAR) {
		prev_char();
		insert_process(read(1));
		if (sh_mode & SHM_ECHO_OFF)
			delete_char();
		else
			next_char();
		return;
		}

	if (sh_start_line < 0) {
		sh_flags &= ~PF_OVERWRITE;
		connect(sh_flags);
		inq_position(sh_start_line, sh_start_col);
		-- sh_start_col;
		return;
		}
}
void
sh_char_mode()
{	extern int sh_mode;

	connect(PF_OVERWRITE);
	sh_mode |= SHM_CHAR | SHM_ECHO_OFF;
}
void
sh_line_mode()
{	extern int sh_mode;

	connect(PF_ECHO | PF_NOINSERT);
	sh_mode = sh_mode & ~SHM_CHAR;
}
void
sh_next_cmd()
{	extern int sh_index;

	sh_recall(sh_index, 1);
}
void
sh_prev_cmd()
{	extern int sh_index;

	sh_recall(sh_index, -1);
}
void
sh_recall(int n, int inc)
{	extern int sh_mode, sh_index;
	extern int sh_start_line, sh_start_col;
	int	l;
	declare	atom;
	extern list sh_history;

	if (sh_mode & SHM_CHAR) {
		self_insert();
		return;
		}

	n += inc;

	if (n < 0)
		n = MAX_HISTORY - 1;
	if (n >= MAX_HISTORY)
		n = 0;

	atom = sh_history[n];
	if (!is_string(atom)) {
		atom = "";
		get_parm(0, n);
		}
	if (sh_start_line >= 0) {
		inq_position(l);
		if (sh_start_line != l)
			delete_to_eol();
		else {
			move_abs(sh_start_line, sh_start_col);
			delete_to_eol();
			}
		}

	inq_position(sh_start_line, sh_start_col);
	insert(atom);

	sh_index = n;
}
void
sh_paste()
{	extern int sh_start_line, sh_start_col;

	end_of_line();
	if (sh_start_line < 0) {
		inq_position(sh_start_line, sh_start_col);
		}
	paste();
	sh_insert();
}
void
sh_send_line()
{
	string	line;
	int	l, c, pl, pc;
	extern list sh_history;
	extern int sh_mode, sh_cmd, sh_index, sh_start_line;
	extern string sh_newline;
	extern int sh_flags;

	if (sh_mode & SHM_CHAR) {
		if ((sh_mode & SHM_ECHO_OFF) == 0)
			insert("\n");
		inq_position(l, c);
		set_process_position(l, c);
		insert_process(sh_newline);
		return;
		}

	/***********************************************/
	/*   Try  and  locate  where  line came from.  */
	/*   If  on  last line of buffer, then we can  */
	/*   believe    the    sh_start_col    field,  */
	/*   otherwise  we  try  and  strip  off  the  */
	/*   possible  prompt  at  the  beginning  of  */
	/*   the line.				       */
	/***********************************************/
	inq_process_position(pl, pc);
	inq_position(l, c);
	if (l == pl) {
		move_abs(0, pc);
		line = read();
		}

	line = ltrim(trim(line));
	
	if (line != "") {
		sh_history[sh_cmd] = line;
		++ sh_cmd;
		if (sh_cmd >= MAX_HISTORY)
			sh_cmd = 0;
		sh_index = sh_cmd;
		}

	sh_start_line = -1;
	end_of_buffer();
	insert("\n");
	inq_position(l, c);
	set_process_position(l, c);
	insert_process(line + "\n");
	
	sh_flags |= PF_OVERWRITE;
	connect(sh_flags);
}


