
/*
 * EDITCOMMANDS.C
 * (c) 1992-3 J.Harper
 */

#include "jed.h"
#include "jed_protos.h"

Prototype   VALUE * cmd_split	    (LONG, VALUE *);
Prototype   VALUE * cmd_join	    (LONG, VALUE *);
Prototype   VALUE * cmd_insert	    (LONG, VALUE *);
Prototype   VALUE * cmd_delete	    (LONG, VALUE *);
Prototype   VALUE * cmd_copy	    (LONG, VALUE *);
Prototype   VALUE * cmd_cut	    (LONG, VALUE *);
Prototype   VALUE * cmd_block	    (LONG, VALUE *);
Prototype   VALUE * cmd_clear	    (LONG, VALUE *);
Prototype   VALUE * cmd_undo	    (LONG, VALUE *);
Prototype   VALUE * cmd_extract	    (LONG, VALUE *);
Prototype   VALUE * cmd_poke	    (LONG, VALUE *);
Prototype   VALUE * cmd_toupper	    (LONG, VALUE *);
Prototype   VALUE * cmd_tolower	    (LONG, VALUE *);
Prototype   VALUE * cmd_changecase  (LONG, VALUE *);
Local	    UBYTE   changecase	    (UBYTE);
Prototype   VALUE * cmd_isalpha	    (LONG, VALUE *);
Prototype   VALUE * cmd_isdigit	    (LONG, VALUE *);
Prototype   VALUE * cmd_isalnum	    (LONG, VALUE *);
Prototype   VALUE * cmd_isspace	    (LONG, VALUE *);

VALUE *
cmd_split(LONG argc, VALUE *argv)
{
    VW *vw = CurrVW;
    TX *tx = vw->vw_Tx;
    BOOL rc = FALSE;
    setrefresh(RFF_ALLFROM, vw->vw_CursorPos.pos_Col, vw->vw_CursorPos.pos_Line);
    if(padcursor())
    {
	if(splitline())
	{
	    if(tx->tx_Lines[vw->vw_CursorPos.pos_Line].ln_Strlen == 1)
	    {
		if(vw->vw_Prefs.prf_AutoIndent)
		    vw->vw_CursorPos.pos_Col = (WORD)spclen(tx->tx_Lines[vw->vw_CursorPos.pos_Line - 1].ln_Line);
		else
		    vw->vw_CursorPos.pos_Col = vw->vw_Prefs.prf_LeftMargin;
	    }
	    resyncxy();
	    tx->tx_Changes++;
	    rc = TRUE;
	}
    }
    setnumres(rc);
    return(&RES);
}

VALUE *
cmd_join(LONG argc, VALUE *argv)
{
    VW *vw = CurrVW;
    TX *tx = vw->vw_Tx;
    BOOL rc = FALSE;
    if(vw->vw_CursorPos.pos_Line < (tx->tx_NumLines - 1))
    {
	setrefresh(RFF_ALLFROM, vw->vw_CursorPos.pos_Col, vw->vw_CursorPos.pos_Line);
	if(padcursor())
	{
	    if(joinlines())
	    {
		resyncx();
		tx->tx_Changes++;
		rc = TRUE;
	    }
	}
    }
    setnumres(rc);
    return(&RES);
}

/*
 * Section types or,
 * s `string'
 * a ascii#
 * f `file'
 * cb unit#
 */
VALUE *
cmd_insert(LONG argc, VALUE *argv)
{
    if(TPLATE2(VTF_STRING, VTF_ANY))
    {
	VW *vw = CurrVW;
	TX *tx = vw->vw_Tx;
	STRPTR arg = ARG1.val_Value.String;
	LONG rc;

	if(padcursor())
	{
	    POS oldcursor = vw->vw_CursorPos;
	    switch(tolower(*arg))
	    {
		case 's':
		    if(!(rc = insertstring(ARG2.val_Value.String, vw->vw_Prefs.prf_TabSize)))
			settitle(NoMemMsg);
		    resyncxy();
		    tx->tx_Changes++;
		    break;
		case 'a':
		    UBYTE string[2];
		    string[0] = (UBYTE)ARG2.val_Value.Number;
		    string[1] = 0;
		    if(!(rc = insertstring(string, vw->vw_Prefs.prf_TabSize)))
			settitle(NoMemMsg);
		    resyncx();
		    tx->tx_Changes++;
		    break;
		case 'f':
		    STRPTR file = squirrelfile(ARG2.val_Value.String);
		    if(file)
		    {
			if(!(rc = insertstring(file, vw->vw_Prefs.prf_DiskTab)))
			    settitle(NoMemMsg);
			resyncxy();
			tx->tx_Changes++;
			freestring(file);
		    }
		    else
			rc = FALSE;
		    break;
		case 'c':
		    if(arg[1] == 'b')
		    {
			LONG unit = ((ARG2.val_Type == VTF_NUMBER) ? ARG2.val_Value.Number : 0);
			STRPTR text = readclip(unit);
			if(text)
			{
			    if(!(rc = insertstring(text, vw->vw_Prefs.prf_DiskTab)))
				settitle(NoMemMsg);
			    resyncxy();
			    tx->tx_Changes++;
			    FreeVec(text);
			}
			else
			    rc = FALSE;
		    }
		    else
			rc = FALSE;
		    break;
		default:
		    if(rc = insertsection(arg))
			tx->tx_Changes++;
		    resyncxy();
		    break;
	    }
	    vw->vw_AutoMark = oldcursor;
	}
	else
	    rc = FALSE;
	setnumres(rc);
    }
    return(&RES);
}

VALUE *
cmd_delete(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	BOOL rc = FALSE;
	if(padcursor())
	{
	    VW *vw = CurrVW;
	    POS endpos;
	    POS oldcurs = vw->vw_CursorPos;
	    if(getsection(ARG1.val_Value.String, &endpos))
	    {
		deletesection(&endpos);
		vw->vw_Tx->tx_Changes++;
		rc = TRUE;
	    }
	    else
		vw->vw_CursorPos = oldcurs;
	}
	setnumres(rc);
    }
    return(&RES);
}

/*
 * (copy `sectType' unit#)
 * copies text onto the clipboard unit#
 */
VALUE *
cmd_copy(LONG argc, VALUE *argv)
{
    if(TPLATE2(VTF_STRING, VTF_ANY))
    {
	BOOL rc = FALSE;
	if(padcursor())
	{
	    VW *vw = CurrVW;
	    POS endpos, oldcurs = vw->vw_CursorPos;
	    if(getsection(ARG1.val_Value.String, &endpos))
		rc = writeclip((ARG2.val_Type == VTF_NUMBER) ? ARG2.val_Value.Number : 0, &vw->vw_CursorPos, &endpos);
	    vw->vw_CursorPos = oldcurs;
	}
	setnumres(rc);
    }
    return(&RES);
}

/*
 * (cut `sectType' unit#)
 * copies text to the clipboard then deletes it from the file.
 */
VALUE *
cmd_cut(LONG argc, VALUE *argv)
{
    if(TPLATE2(VTF_STRING, VTF_ANY))
    {
	BOOL rc = FALSE;
	if(padcursor())
	{
	    VW *vw = CurrVW;
	    POS startpos, endpos;
	    startpos = vw->vw_CursorPos;
	    if(getsection(ARG1.val_Value.String, &endpos))
	    {
		POS startstore = vw->vw_CursorPos;
		vw->vw_CursorPos = startpos;
		startpos = startstore;
		if(writeclip((ARG2.val_Type == VTF_NUMBER) ? ARG2.val_Value.Number : 0, &startpos, &endpos))
		{
		    vw->vw_CursorPos = startstore;
		    deletesection(&endpos);
		    vw->vw_Tx->tx_Changes++;
		    rc = TRUE;
		}
	    }
	}
	setnumres(rc);
    }
    return(&RES);
}

/*
 * (block `type')
 *
 * sets block marks, either uses standard section type or,
 *	t   -	toggle between, set start, set end, kill block
 *	s   -	set start
 *	e   -	set end
 *	k   -	kill block
 */
VALUE *
cmd_block(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	VW *vw = CurrVW;
	STRPTR arg = ARG1.val_Value.String;

	if(!stricmp(arg, "t"))
	{
	    switch(vw->vw_BlockStatus)
	    {
		case 0:
		    vw->vw_BlockStatus = -1;
		    setblockrefresh();
		    break;
		case 1:
		    vw->vw_Block[1] = vw->vw_CursorPos;
		    vw->vw_BlockStatus = 0;
		    orderblock();
		    setblockrefresh();
		    break;
		case 2:
		    vw->vw_Block[0] = vw->vw_CursorPos;
		    vw->vw_BlockStatus = 0;
		    orderblock();
		    setblockrefresh();
		    break;
		case -1:
		    vw->vw_Block[0] = vw->vw_CursorPos;
		    vw->vw_BlockStatus = 1;
		    break;
	    }
	}
	else if(!stricmp(arg, "s"))
	{
	    switch(vw->vw_BlockStatus)
	    {
		case 0:
		    setblockrefresh();
		    vw->vw_Block[0] = vw->vw_CursorPos;
		    orderblock();
		    setblockrefresh();
		    break;
		case 2:
		    vw->vw_Block[0] = vw->vw_CursorPos;
		    vw->vw_BlockStatus = 0;
		    orderblock();
		    setblockrefresh();
		    break;
		case -1:
		    vw->vw_Block[0] = vw->vw_CursorPos;
		    vw->vw_BlockStatus = 1;
		    break;
	    }
	}
	else if(!stricmp(arg, "e"))
	{
	    switch(vw->vw_BlockStatus)
	    {
		case 0:
		    setblockrefresh();
		    vw->vw_Block[1] = vw->vw_CursorPos;
		    orderblock();
		    setblockrefresh();
		    break;
		case 1:
		    vw->vw_Block[1] = vw->vw_CursorPos;
		    vw->vw_BlockStatus = 0;
		    orderblock();
		    setblockrefresh();
		    break;
		case -1:
		    vw->vw_Block[1] = vw->vw_CursorPos;
		    vw->vw_BlockStatus = 2;
		    break;
	    }
	}
	else if(!stricmp(arg, "k"))
	{
	    if(!vw->vw_BlockStatus)
	    {
		vw->vw_BlockStatus = -1;
		setblockrefresh();
	    }
	}
	else
	{
	    POS cursorsafe = vw->vw_CursorPos;
	    if(!vw->vw_BlockStatus)
		setblockrefresh();
	    if(getsection(arg, &vw->vw_Block[1]))
	    {
		vw->vw_Block[0] = vw->vw_CursorPos;
		vw->vw_BlockStatus = 0;
	    }
	    else
		vw->vw_BlockStatus = -1;
	    vw->vw_CursorPos = cursorsafe;
	    setblockrefresh();
	}
	setnumres(TRUE);
    }
    return(&RES);
}

VALUE *
cmd_clear(LONG argc, VALUE *argv)
{
    VW *vw = CurrVW;
    TX *tx = vw->vw_Tx;
    BOOL rc = FALSE;
    if((!tx->tx_Changes) || (ezreq("OK to lose %ld changes\nto file %s", "Yeah|Cancel", tx->tx_Changes, tx->tx_TitleName)))
    {
	clearlinelist(tx);
	freestring(tx->tx_TitleName);
	freestring(tx->tx_FileName);
	tx->tx_FileName = savestring("");
	tx->tx_TitleName = savestring("Untitled");
	tx->tx_Changes = 0;
	resetallviews(tx);
	resetslptxtitles(tx);
	if(tx->tx_ResetPrefs)
	    getdefprefs(tx);
	rc = TRUE;
    }
    setnumres(rc);
    return(&RES);
}

/*
 * (undo `type')
 * type,
 *  l	--  undo line only if on the line in undo buffer
 *  L	--  undo line even if buffer and cursor pos don't match
 */
VALUE *
cmd_undo(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	VW *vw = CurrVW;
	TX *tx = vw->vw_Tx;
	BOOL rc = FALSE;
	switch(*(ARG1.val_Value.String))
	{
	    case 'l':
		if(vw->vw_LineUndo.line != vw->vw_CursorPos.pos_Line)
		{
		    settitle("error: undo buffer not from this line");
		    goto lu_end;
		}
		/* fall through */
	    case 'L':
		if(vw->vw_LineUndo.line < tx->tx_NumLines)
		{
		    if(vw->vw_LineUndo.text)
		    {
			LINE *line = tx->tx_Lines + vw->vw_LineUndo.line;
			WORD nllen = strlen(vw->vw_LineUndo.text);
			WORD diff = nllen - (line->ln_Strlen - 1);
			STRPTR tln = line->ln_Line;
			LONG tchg = tx->tx_Changes;
			line->ln_Line = vw->vw_LineUndo.text;
			line->ln_Strlen = nllen + 1;
			tx->tx_Changes = vw->vw_LineUndo.changes;
			vw->vw_LineUndo.text = tln;
			vw->vw_LineUndo.changes = tchg;
			if(diff < 0)
			    keeppossubx(-diff);
			setrefresh(RFF_LINEFROM, 0, vw->vw_LineUndo.line);
			resyncx();
			rc = TRUE;
		    }
		    else
			settitle("error: nothing in undo buffer");
		}
lu_end:		break;
	    default:
		settitle(BadArgMsg);
		break;
	}
	setnumres(rc);
    }
    return(&RES);
}

/*
 * (extract `sectionType')
 */
VALUE *
cmd_extract(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	VW *vw = CurrVW;
	POS oldcurs = vw->vw_CursorPos;
	POS endpos;
	if(getsection(ARG1.val_Value.String, &endpos))
	{
	    LINE *line = vw->vw_Tx->tx_Lines + vw->vw_CursorPos.pos_Line;
	    STRPTR text;
	    LONG length = sectionlength(&vw->vw_CursorPos, &endpos) + 1;
	    if(text = AllocVec(length, 0L))
	    {
		copysection(&vw->vw_CursorPos, &endpos, text);
		text[length] = 0;
		setstrres(text);
	    }
	    else
		settitle(NoMemMsg);
	}
	vw->vw_CursorPos = oldcurs;
    }
    return(&RES);
}

/*
 * (poke asciival)
 */
VALUE *
cmd_poke(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_NUMBER))
    {
	VW *vw = CurrVW;
	BOOL rc = FALSE;
	if(padcursor())
	{
	    LINE *line = vw->vw_Tx->tx_Lines + vw->vw_CursorPos.pos_Line;
	    if(vw->vw_CursorPos.pos_Col == (line->ln_Strlen - 1))
	    {
		STRPTR newline = AllocVec(line->ln_Strlen + 1, 0);
		if(newline)
		{
		    memcpy(newline, line->ln_Line, line->ln_Strlen - 1);
		    newline[vw->vw_CursorPos.pos_Col] = (UBYTE)ARG1.val_Value.Number;
		    newline[vw->vw_CursorPos.pos_Col + 1] = 0;
		    stuffline(newline, vw->vw_CursorPos.pos_Line);
		    rc = TRUE;
		}
		else
		    settitle(NoMemMsg);
	    }
	    else
	    {
		line->ln_Line[vw->vw_CursorPos.pos_Col] = (UBYTE)ARG1.val_Value.Number;
		rc = TRUE;
	    }
	}
	vw->vw_Tx->tx_Changes++;
	setrefresh(RFF_LINEFROM, vw->vw_CursorPos.pos_Col, vw->vw_CursorPos.pos_Line);
	setnumres(rc);
    }
    return(&RES);
}

/*
 * (toupper `section')
 * (tolower `section')
 * (changecase `section')
 */
VALUE *
cmd_toupper(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	VW *vw = CurrVW;
	POS oldcurs = vw->vw_CursorPos;
	POS endpos;
	BOOL rc = FALSE;
	if(getsection(ARG1.val_Value.String, &endpos))
	{
	    TX *tx = vw->vw_Tx;
	    LINE *line = tx->tx_Lines + vw->vw_CursorPos.pos_Line;

	    setrefresh((endpos.pos_Line > vw->vw_CursorPos.pos_Line) ? RFF_ALLFROM : RFF_LINEFROM, vw->vw_CursorPos.pos_Col, vw->vw_CursorPos.pos_Line);
	    while(vw->vw_CursorPos.pos_Line < endpos.pos_Line)
	    {
		while(vw->vw_CursorPos.pos_Col < line->ln_Strlen)
		    line->ln_Line[vw->vw_CursorPos.pos_Col] = toupper(line->ln_Line[vw->vw_CursorPos.pos_Col++]);
		vw->vw_CursorPos.pos_Col = 0;
		vw->vw_CursorPos.pos_Line++;
		line++;
	    }
	    while(vw->vw_CursorPos.pos_Col < endpos.pos_Col)
		line->ln_Line[vw->vw_CursorPos.pos_Col] = toupper(line->ln_Line[vw->vw_CursorPos.pos_Col++]);
	    vw->vw_CursorPos = oldcurs;
	    rc = TRUE;
	}
	setnumres(rc);
    }
    return(&RES);
}

VALUE *
cmd_tolower(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	VW *vw = CurrVW;
	POS oldcurs = vw->vw_CursorPos;
	POS endpos;
	BOOL rc = FALSE;
	if(getsection(ARG1.val_Value.String, &endpos))
	{
	    TX *tx = vw->vw_Tx;
	    LINE *line = tx->tx_Lines + vw->vw_CursorPos.pos_Line;

	    setrefresh((endpos.pos_Line > vw->vw_CursorPos.pos_Line) ? RFF_ALLFROM : RFF_LINEFROM, vw->vw_CursorPos.pos_Col, vw->vw_CursorPos.pos_Line);
	    while(vw->vw_CursorPos.pos_Line < endpos.pos_Line)
	    {
		while(vw->vw_CursorPos.pos_Col < line->ln_Strlen)
		    line->ln_Line[vw->vw_CursorPos.pos_Col] = tolower(line->ln_Line[vw->vw_CursorPos.pos_Col++]);
		vw->vw_CursorPos.pos_Col = 0;
		vw->vw_CursorPos.pos_Line++;
		line++;
	    }
	    while(vw->vw_CursorPos.pos_Col < endpos.pos_Col)
		line->ln_Line[vw->vw_CursorPos.pos_Col] = tolower(line->ln_Line[vw->vw_CursorPos.pos_Col++]);
	    vw->vw_CursorPos = oldcurs;
	    rc = TRUE;
	}
	setnumres(rc);
    }
    return(&RES);
}

VALUE *
cmd_changecase(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	VW *vw = CurrVW;
	POS oldcurs = vw->vw_CursorPos;
	POS endpos;
	BOOL rc = FALSE;
	if(getsection(ARG1.val_Value.String, &endpos))
	{
	    TX *tx = vw->vw_Tx;
	    LINE *line = tx->tx_Lines + vw->vw_CursorPos.pos_Line;

	    setrefresh((endpos.pos_Line > vw->vw_CursorPos.pos_Line) ? RFF_ALLFROM : RFF_LINEFROM, vw->vw_CursorPos.pos_Col, vw->vw_CursorPos.pos_Line);
	    while(vw->vw_CursorPos.pos_Line < endpos.pos_Line)
	    {
		while(vw->vw_CursorPos.pos_Col < line->ln_Strlen)
		    line->ln_Line[vw->vw_CursorPos.pos_Col] = changecase(line->ln_Line[vw->vw_CursorPos.pos_Col++]);
		vw->vw_CursorPos.pos_Col = 0;
		vw->vw_CursorPos.pos_Line++;
		line++;
	    }
	    while(vw->vw_CursorPos.pos_Col < endpos.pos_Col)
		line->ln_Line[vw->vw_CursorPos.pos_Col] = changecase(line->ln_Line[vw->vw_CursorPos.pos_Col++]);
	    vw->vw_CursorPos = oldcurs;
	    rc = TRUE;
	}
	setnumres(rc);
    }
    return(&RES);
}

Local UBYTE
changecase(UBYTE c)
{
    if(isupper(c))
	return(tolower(c));
    else if(islower(c))
	return(toupper(c));
    return(c);
}

VALUE *
cmd_isalpha(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_NUMBER))
    {
	setnumres(isalpha(ARG1.val_Value.Number));
    }
    return(&RES);
}

VALUE *
cmd_isdigit(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_NUMBER))
    {
	setnumres(isdigit(ARG1.val_Value.Number));
    }
    return(&RES);
}

VALUE *
cmd_isalnum(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_NUMBER))
    {
	setnumres(isalnum(ARG1.val_Value.Number));
    }
    return(&RES);
}

VALUE *
cmd_isspace(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_NUMBER))
    {
	setnumres(isspace(ARG1.val_Value.Number));
    }
    return(&RES);
}
