//=============================================================================
// All command window updates, input, etc happen here -EAD
//=============================================================================
#include <Controls.h>
/* #include <ControlDefinitions.h> */
#include <Events.h>
#include <Fonts.h>
#include <MacWindows.h>
#include "MacGlobals.h"
#include "macint.h"
#include <ctype.h>
#define NIL ((void *) 0)

//=============================================================================
// local variables
//=============================================================================

ControlHandle vScroll;
int 		cursorPos;							/* the cursor's position on the line */
short		linesInView;						/* how many lines are in the window */
int			cmdStart;							/* where (in text record) the current command starts */
TextStyle 	textStyle[2];  						/* styles: bold for user input, plain for output */
/* output is buffered */
Handle hOutputBuffer = NULL;
enum currentStyle { plainStyle, boldStyle } currentStyle;

static void GoStartOfLine (void);
static void GoEndOfLine (void);
static void GoBackOneWord (void);
static void GoForwardOneWord (void);

//=============================================================================
// static void DoScrollBar (ControlHandle control, short change)
//=============================================================================
/* keep track of the user as he fiddles with the scroll bar */
/* This routine is called while the user has the mouse down. */
/* It makes sure the thumb isn't dragged out-of-bounds. */
//=============================================================================

static void DoScrollBar (ControlHandle control, short change) {
    short value = GetControlValue (control), max = GetControlMaximum (control);
    long newval = value + change;  /* this is a long in case we try to go past MAX_INT */
    if (newval < 0) newval = 0; else if (newval > max) newval = max;
    SetControlValue (control, (short) newval);
    if (newval != value) TEScroll (0, (short) (value - newval) * LINEHEIGHT, hTERec);
}

//=============================================================================
// pascal Boolean ScrollClickLoop (void) 
//=============================================================================
//
//=============================================================================

pascal Boolean ScrollClickLoop (void) {
    Rect tempRect;
    Point mouse;
    GrafPtr oldPort;
    RgnHandle oldClip;
    short amount = 0;

    if (FrontWindow () != gCommandWin) return false;

    GetPort (&oldPort);
    SetPort (gCommandWin);
    GetClip (oldClip = NewRgn ());
    SetRect (&tempRect, INT_MIN, INT_MIN, INT_MAX, INT_MAX);
    ClipRect (&tempRect);

    GetMouse (&mouse);
    if (mouse.v < TEXTREC->viewRect.top)  			DoScrollBar (vScroll, -1);
    else if (mouse.v > TEXTREC->viewRect.bottom)	DoScrollBar (vScroll, 1);

    SetClip (oldClip);
    DisposeRgn (oldClip);
    SetPort (oldPort);
    return true;
}

//=============================================================================
// static pascal void ScrollProc (ControlHandle control, short thePart)
//=============================================================================
// for clicks in the scroll bar or arrows; update the window properly
//=============================================================================

pascal void ScrollProc (ControlHandle control, short thePart) {
    short amount;
    WindowPtr window;

    if (!thePart) return;
    window = (*control)->contrlOwner;
    switch (thePart) {
        case kControlUpButtonPart:	amount = -1;				break;
        case kControlDownButtonPart:	amount = 1;					break;
        case kControlPageUpPart:		amount = -linesInView;		break;
        case kControlPageDownPart:	amount = linesInView;		break;
    }
    DoScrollBar (control, amount);
}

//=============================================================================
// Rect SetTERect (void)
//=============================================================================
// set the dimensions of the text record in its window 
//=============================================================================

Rect SetTERect (void) {
    Rect teRect = gCommandWin->portRect;
    teRect.right -= SCROLLER_WIDTH;
    InsetRect (&teRect, TEXT_MARGIN, TEXT_MARGIN);
    linesInView = (teRect.bottom - teRect.top) / LINEHEIGHT;
    teRect.bottom = teRect.top + linesInView * LINEHEIGHT;  /* round off */
    return teRect;
}

//=============================================================================
// static void AdjustCursor (EventRecord *theEvent)
//=============================================================================
// make the pointer an I-beam iff it's in the text window
//=============================================================================

void AdjustCursor (Point theLoc, RgnHandle theRgn) 
{
    RgnHandle	arrowRgn, iBeamRgn, hiliteRgn, tempRgn;
    Rect		theRect;
    Point		thePoint;
   
    if (gInBackground)
        return;

    arrowRgn = NewRgn();
    SetRectRgn(arrowRgn, -32767, -32767, 32767, 32767);

//	GlobalToLocal ((theLoc); ???
    
    if (gCommandWin == FrontWindow () ) {
        SetPort(gCommandWin);
        iBeamRgn = NewRgn();
        hiliteRgn = NewRgn();
        
        theRect = TEXTREC->viewRect;
        LocalToGlobal((Point *)&(theRect.top));
        LocalToGlobal((Point *)&(theRect.bottom));
        RectRgn(iBeamRgn, &theRect);
        
        TEGetHiliteRgn(hiliteRgn, hTERec);
        thePoint.h = thePoint.v = 0;
        LocalToGlobal(&thePoint);
        OffsetRgn(hiliteRgn, thePoint.h, thePoint.v);

        DiffRgn(arrowRgn, hiliteRgn, arrowRgn);
        DiffRgn(arrowRgn, iBeamRgn, arrowRgn);

        DiffRgn(iBeamRgn, hiliteRgn, iBeamRgn);
        
        if (PtInRgn(theLoc, iBeamRgn)) {
            SetCursor(*GetCursor(iBeamCursor));
            CopyRgn(iBeamRgn, theRgn);
        } else if (PtInRgn(theLoc, hiliteRgn)) {
            SetCursor(&qd.arrow);
            CopyRgn(hiliteRgn, theRgn);
        } else {
            SetCursor(&qd.arrow);
            CopyRgn(arrowRgn, theRgn);
        }

        DisposeRgn(iBeamRgn);
        DisposeRgn(hiliteRgn);

    } else  {
        SetCursor(&qd.arrow);
        CopyRgn(arrowRgn, theRgn);
    }

    DisposeRgn(arrowRgn);
}



//=============================================================================
// static void SetScrollRect (void)
//=============================================================================
// Set Scroll bar rec size
//=============================================================================

void SetScrollRect (void) {
    /* set the dimensions of the scroll bar in its window */

// This change fixes the double flash on window resize -EAD

//	MoveControl (vScroll, commandWin->portRect.right - SCROLLER_WIDTH, -1);
//	SizeControl (vScroll, SCROLLER_WIDTH + 1,
//			(commandWin->portRect.bottom - commandWin->portRect.top) - (SCROLLER_WIDTH - 2));
    (*vScroll)->contrlRect.left = gCommandWin->portRect.right - SCROLLER_WIDTH;
    (*vScroll)->contrlRect.top = -1;
    (*vScroll)->contrlRect.right =  gCommandWin->portRect.right + 1;
    (*vScroll)->contrlRect.bottom = gCommandWin->portRect.bottom - (SCROLLER_WIDTH - 1);
    
}

//=============================================================================
// static void AdjustScrollBar (void)
//=============================================================================
// Set the thumb on scrollbar
//=============================================================================

static void AdjustScrollBar (void) {
    /* adjust the scroll bar to match the position of the text view */
    short oldval = GetControlValue (vScroll), oldmax = GetControlMaximum (vScroll);
    short value, max;
    short test;
    
    max = TEXTREC->nLines - linesInView;
    if ((TEXTREC->teLength > 0) && (*(*TEXTREC->hText + TEXTREC->teLength - 1) == '\r')) max++;
    if (max < 0) max = 0;
    if (max != oldmax) SetControlMaximum (vScroll, max);
    value = (short)((TEXTREC->viewRect.top - TEXTREC->destRect.top) / LINEHEIGHT);
//	value = roundup ((TEXTREC->viewRect.top - TEXTREC->destRect.top) / LINEHEIGHT);
    if (value < 0) value = 0; else if (value > max) value = max;
    if (value != oldval) SetControlValue (vScroll, value);
}

static short roundup (float x) {  /* a kludge to round up a float to an int */
    if (((int) x) != ((int) (x += 0.5))) x += 0.5;
    return (int) x;
}

//=============================================================================
// void DoKeyPress (EventRecord *theEvent)
//=============================================================================
// Hanlde Keyboard Input
//=============================================================================

void DoKeyPress (EventRecord *theEvent) {
    short whatKey = theEvent->message & charCodeMask;
    if (theEvent->modifiers & cmdKey) {
        long choice;
        AdjustMenus ();
        if (choice = MenuKey (theEvent->message)) DoMenu (choice);
        else if (((whatKey == 'w') || (whatKey == 'W')) && (FrontWindow () == gGraphicsWin))
            HideGrafWin ();
        else if (whatKey == LEFTARROW)	GoStartOfLine ();
        else if (whatKey == RIGHTARROW)	GoEndOfLine ();
        else if (whatKey == UPARROW)	DoScrollBar (vScroll, - linesInView);
        else if (whatKey == DOWNARROW)	DoScrollBar (vScroll, linesInView);
    }
    else if (theEvent->modifiers & optionKey) {
        if (whatKey == LEFTARROW)		GoBackOneWord ();
        else if (whatKey == RIGHTARROW)	GoForwardOneWord ();
    }
    else switch (whatKey) {
        case PAGEUP:	DoScrollBar (vScroll, -linesInView);	break;
        case PAGEDN:	DoScrollBar (vScroll, linesInView);		break;
        case HOMEKEY:	DoScrollBar (vScroll, INT_MIN);			break;
        case ENDKEY:	DoScrollBar (vScroll, INT_MAX);			break;
        case FNKEY:												break;
        case HELPKEY:											break;
        default: recentChar = theEvent->message & charCodeMask;
    }
}

//=============================================================================
// static void DrawOnlyGrowIcon (WindowPtr window) 
//=============================================================================
// draw growbox on command window with no scoll bars
//=============================================================================

static void DrawOnlyGrowIcon (WindowPtr window) 
{  
    RgnHandle saveRgn;
    Rect growRect;

    growRect = window->portRect;
    growRect.top = growRect.bottom - SCROLLER_WIDTH;
    growRect.left = growRect.right - SCROLLER_WIDTH;
    GetClip (saveRgn = NewRgn ());
    ClipRect (&growRect);
    DrawGrowIcon (window);
    SetClip (saveRgn);
    DisposeRgn (saveRgn);
}

//=============================================================================
// void SetSelection (short start, short end)
//=============================================================================
// set text selection in the command window
//=============================================================================

void SetSelection (short start, short end) {
    TEXTREC->clikStuff = 255;  /* to make sure the caret appears at the start of a line when it should */
    /* see tech note "TextEdit EOL Ambiguity" for more information */
    TESetSelect (start, end, hTERec);
}

//=============================================================================
// static void CancelFlash (void)
//=============================================================================
// cancel the matching-paren flashing
//=============================================================================

static void CancelFlash (void) {
    if (flashTime) {
        flashTime = 0;
        SetSelection (cursorBeforeFlash, cursorBeforeFlash);
    }
}

//=============================================================================
// static void StopPasting (void)
//=============================================================================
// clean up after finishing a paste
//=============================================================================

void StopPasting (void) {
    pastedLength = 0;
    if (pastedTextH) {
        DisposeHandle (pastedTextH);
        pastedTextH = NULL;
    }
}

//=============================================================================
// static void DoStyle (int whatStyle)
//=============================================================================
// set the text to a certain style
//=============================================================================

static void DoStyle (int whatStyle) {
    TESetStyle (doFace, &(textStyle[whatStyle]), false, hTERec);
}

//=============================================================================
// static void FlushOutput (void)
//=============================================================================
// clear out the output buffer, dumping its contents to the window
//=============================================================================

void FlushOutput (void) {
    short totalLines, scrollAmount, max;

    if (outputBufferLength == 0) return;
    CancelFlash ();
    DoStyle (plainStyle);
    HLock (hOutputBuffer);
    TEInsert (*hOutputBuffer, outputBufferLength, hTERec);
    HUnlock (hOutputBuffer);
    outputBufferLength = 0;

    if (TEXTREC->teLength > SCROLLBACK_THRESHHOLD) {  
        /* make sure TE record isn't too long */
#ifdef ORIGINALCODE
        /* I replaced this because Nyquist was crashing after the
           buffer got filled. The replacement below is simpler and
           eliminates the crashes, although it probably could cause
           problems by clearing the selection.
         */
        int i = 1, newLength;
        TEPtr textPtr;
        while ((TEXTREC->teLength - TEXTREC->lineStarts[i]) > 
               (SCROLLBACK_THRESHHOLD - DELETE_BLOCK)) i++;
        i = TEXTREC->lineStarts[i];
        newLength = TEXTREC->teLength - i;
        textPtr = (TEPtr)(*(TEXTREC->hText));
        BlockMoveData ((Ptr)((long)textPtr + i), textPtr, newLength);
        SetHandleSize (TEXTREC->hText, newLength);
        TEXTREC->destRect.top += LINEHEIGHT;
        TECalText (hTERec);
        TEUpdate (&(TEXTREC->viewRect), hTERec);
#else
        /* find the line start after DELETE_BLOCK */
        int i = 1;
        while (TEXTREC->lineStarts[i] < DELETE_BLOCK) i++;
        TESetSelect(0, TEXTREC->lineStarts[i], hTERec);
        TEDelete(hTERec);
        /* after deletion, put cursor back at end of buffer */
        TESetSelect(TEXTREC->teLength, TEXTREC->teLength, hTERec);
#endif
    }
    TESelView (hTERec);
    AdjustScrollBar ();
}

//=============================================================================
// void PrepareForInput (void)
//=============================================================================
// get ready to take input
//=============================================================================

void PrepareForInput (void) {
    FlushOutput ();
    cmdStart = TEXTREC->selStart;
}

//=============================================================================
// static void DeleteRange (void)
//=============================================================================
// delete the selected range of text, updating cmdStart as necessary
//=============================================================================

void DeleteRange (void) {
    if (TEXTREC->selEnd <= cmdStart) return;
    if (TEXTREC->selStart < cmdStart) SetSelection (cmdStart, TEXTREC->selEnd);
    TEDelete (hTERec);
}

//=============================================================================
// static void CopyThisLineToEnd (void)
//=============================================================================
// copy the line the caret is on to the end
//=============================================================================

static void CopyThisLineToEnd (void) {
    char *buffer;
    short b, i, caretOffset;

    /* first find out exactly where it starts */
    i = TEXTREC->nLines-1;  /* first find which line */
    while (TEXTREC->selStart < TEXTREC->lineStarts[i]) i--;
    while ((i > 0) && ((*(TEXTREC->hText))[TEXTREC->lineStarts[i]-1] != '\r'))
        i--;  /* for wrapped lines */
    i = TEXTREC->lineStarts[i];  /* now zero in on the exact character where it begins */
    while ((TEXTCHAR(i) >= '0') && (TEXTCHAR(i) <= '9')) i++;  /* skip error level */
    if ((TEXTCHAR(i) == '>') && (TEXTCHAR(i+1) == ' ')) i+=2;  /* get rid of leading prompt */

    caretOffset = TEXTREC->selStart - i;  /* how many characters in is the caret? */

    /* now put the line into the buffer */
    b = 0;
    while ((TEXTCHAR(i+b) != '\r') && (i+b < TEXTREC->teLength)) b++;  /* find the end of the line */
    buffer = (char *) NewPtr (b);
    BlockMoveData (*TEXTREC->hText + i, buffer, b);
    buffer[b] = '\0';

    /* delete whatever's already on the last line */
    SetSelection (cmdStart, TEXTREC->teLength);
    TEDelete (hTERec);

    DoStyle (boldStyle);
    TEInsert (buffer, b, hTERec);
    DisposePtr (buffer);

    if (caretOffset < 0) caretOffset = b;
    SetSelection (cmdStart + caretOffset, cmdStart + caretOffset);
}

//=============================================================================
// Next four functions possition cursor in text
//=============================================================================

static void GoStartOfLine (void) {
    short whichLine = TEXTREC->nLines - 1;  /* look for the caret; start at the end and go up */
    while (TEXTREC->lineStarts[whichLine] > TEXTREC->selStart) whichLine--;
    SetSelection (TEXTREC->lineStarts[whichLine], TEXTREC->lineStarts[whichLine]);
    AdjustScrollBar ();
}

static void GoEndOfLine (void) {
    short whichLine = TEXTREC->nLines - 1;  /* look for the caret; start at the end and go up */
    while (TEXTREC->lineStarts[whichLine] > TEXTREC->selStart) whichLine--;
    if (whichLine == TEXTREC->nLines - 1)
        SetSelection (TEXTREC->teLength, TEXTREC->teLength);
    else SetSelection (TEXTREC->lineStarts[whichLine+1] - 1, TEXTREC->lineStarts[whichLine+1] - 1);
    AdjustScrollBar ();
}

static void GoBackOneWord (void) {
    short i = TEXTREC->selStart;
    while ((i > 0) && !isalnum (TEXTCHAR(i-1)))	i--;
    while ((i > 0) && isalnum (TEXTCHAR(i-1)))	i--;
    SetSelection (i, i);
}

static void GoForwardOneWord (void) {
    short i = TEXTREC->selStart;
    while ((i < TEXTREC->teLength) && !isalnum (TEXTCHAR(i)))	i++;
    while ((i < TEXTREC->teLength) && isalnum (TEXTCHAR(i)))	i++;
    SetSelection (i, i);
}


//=============================================================================
// static void EditFreely (void)
//=============================================================================
// Enter text into the command windows
//=============================================================================

static void EditFreely (void) {
    Boolean done;
    do {
        done = false;
        DoEvent ();
        if (pastedLength > 0) {  /* if there is still text to paste, paste it */
            int i = 0;
            CancelFlash ();
            if (TEXTREC->selStart < cmdStart) StopPasting ();
            else {
                while ((i < pastedLength) && (((char *)(*pastedTextH))[i] != '\r')) i++;
                DoStyle (boldStyle);
                TEInsert (*pastedTextH, i, hTERec);
                AdjustScrollBar ();
                if (i < pastedLength) {  /* we were stopped by a carriage return, so eat it */
                    i++;
                    done = true;
                }
                pastedLength -= i;
                if (pastedLength > 0) {
                    BlockMoveData ((Ptr)((long)(*pastedTextH) + i), *pastedTextH, pastedLength);
                    SetHandleSize (pastedTextH, pastedLength);
                } else StopPasting ();
            }
        }
        else if (recentChar) {  /* if the last event got us a character, process it */
            int i;
            Boolean wasOnLastLine;
            CancelFlash ();

            if ((TEXTREC->selEnd <= cmdStart) && (TEXTREC->selStart != TEXTREC->selEnd)) continue;
            if (TEXTREC->selStart < cmdStart) SetSelection (cmdStart, TEXTREC->selEnd);
            wasOnLastLine = (TEXTREC->selStart >= cmdStart);

            if ((recentChar & 0xfc) == 0x1c) {  /* was this an arrow key? */
                TEXTREC->clikStuff = 255;  /* to make sure the caret appears where it should */
                TEKey (recentChar, hTERec);
                AdjustScrollBar ();
                continue;
            }
            if (!wasOnLastLine) CopyThisLineToEnd ();
            switch (recentChar) {
            case FWDDEL:
                if (TEXTREC->selStart != TEXTREC->selEnd) DeleteRange ();
                else if ((TEXTREC->selStart >= cmdStart) && (TEXTREC->selStart < TEXTREC->teLength)) {
                    TEDeactivate (hTERec);
                    SetSelection (TEXTREC->selStart, TEXTREC->selStart + 1);
                    TEDelete (hTERec);
                    if (FrontWindow () == gCommandWin) TEActivate (hTERec);
                }
                break;
            case CLRKEY:
                if (TEXTREC->selStart != TEXTREC->selEnd) DeleteRange ();
                break;
            case DELETE:
                if (TEXTREC->selStart != TEXTREC->selEnd) DeleteRange ();
                else if (TEXTREC->selStart > cmdStart) {
                    TEXTREC->clikStuff = 255;  /* to make sure the caret appears where it should */
                    TEKey (DELETE, hTERec);
                }
                break;
            case RETURN:
                if (wasOnLastLine) done = true;
                break;
            case ENTER:  /* ENTER ends command no matter what */
                done = true;
                break;
            default:
                DoStyle (boldStyle);
                TEXTREC->clikStuff = 255;  /* to make sure the caret appears where it should */
                TEKey (recentChar, hTERec);
                if ((recentChar == ')') && (TEXTREC->selStart > cmdStart)) {
                    short parenCount = -1;
                    Boolean inQuotes = false;
                    i = TEXTREC->selStart - 1;
                    while ((--i >= cmdStart) && (parenCount != 0))
                        switch ((*TEXTREC->hText)[i]) {
                        case DBLQUOTE: inQuotes = !inQuotes; break;
                        case '(': if (!inQuotes) parenCount++; break;
                        case ')': if (!inQuotes) parenCount--; break;
                        }
                    if (parenCount == 0) {
                        cursorBeforeFlash = TEXTREC->selStart;
                        SetSelection (i+1, i+2);  /* flash the matching open-paren */
                        flashTime = 10;
                    }
                } else if ((recentChar == DBLQUOTE) && (TEXTREC->selStart > cmdStart)) {
                    i = TEXTREC->selStart - 1;
                    while ((--i >= cmdStart) && ((*TEXTREC->hText)[i] != DBLQUOTE)) ;
                    if ((*TEXTREC->hText)[i] == DBLQUOTE) {
                        cursorBeforeFlash = TEXTREC->selStart;
                        SetSelection (i, i+1);  /* flash the matching double-quote */
                        flashTime = 10;
                    }
                }
            }
            AdjustScrollBar ();
        }
    } while (!done);
}

char *macgets (void) {
    /* retrieve a typed character */
    /* Note that this uses some extensive (and clever, if I may say so myself) buffering. */
    int i, b, bufSize;
    char *ptr, *buffer;
    Boolean done, onLastLine;
    
    PrepareForInput ();
    do {  /* repeat until a full expression has been typed */
        EditFreely ();  /* allow free editing for a while */

        /* Now, we have a complete command to parse, if and only if: */
        /* - the cursor was on the last line when the user pressed Return or Enter, and */
        /* - the user either pressed Enter, or else every '(' since the beginning */
        /*     of the command is matched by a ')'. */
        /* Quoting is watched for.  ( ") is not a complete expression. */

        done = true;
        if (TEXTREC->selStart != TEXTREC->teLength)  /* if we're not at the end already */
            SetSelection (TEXTREC->teLength, TEXTREC->teLength);  /* send cursor to end */
        TEXTREC->clikStuff = 255;  /* to make sure the caret appears where it should */
        TEKey ('\r', hTERec);

        /* check and see if we've completed the command yet */
        if (recentChar != ENTER) {
            Boolean inQuotes = false;
            short parenCount = 0;
            for (i = cmdStart; i < TEXTREC->teLength; i++)
                switch ((*TEXTREC->hText)[i]) {
                case DBLQUOTE: inQuotes = !inQuotes; break;
                case '(': if (!inQuotes) parenCount++; break;
                case ')': if (!inQuotes) parenCount--; break;
                }
            if ((parenCount > 0) || inQuotes) done = false;
        }

        AdjustScrollBar ();
    } while (!done);

    /* put the entire command into the buffer, and return it */
    bufSize = TEXTREC->teLength - cmdStart;
    buffer = (char *) NewPtr (bufSize + 1);
    BlockMoveData (*TEXTREC->hText + cmdStart, buffer, bufSize);
    buffer[bufSize] = '\0';
    return buffer;
}

void macputc (int ch) {
    /* put a char into the output buffer, and flush the buffer if necessary */
    switch (ch) {
        case '\t':
            do { macputc (' '); } while (cursorPos & 7);
            break;
        case DELETE:
            if (cursorPos) cursorPos--;  /* and fall through to default */
        default:
            if (outputBufferLength == MAX_BUF) FlushOutput ();
            if (ch == '\n') {
                cursorPos = 0;
                (*hOutputBuffer)[outputBufferLength++] = '\r';
            } else {
                cursorPos++;
                (*hOutputBuffer)[outputBufferLength++] = ch;
            }
    }
}

void macputs (char *s) {
    /* for completeness */
    while (*s) macputc (*s++);
}

void scrflush (void) {
    extern void osflush (void);
    /* clear out everything */
    FlushOutput ();
    osflush ();
}

void scrclear (void) {
    /* clear text window -- not implemented */
}

//=============================================================================
// static void UpdateCmdWindow (void)
//=============================================================================
// main command window update procedure
//=============================================================================


void UpdateCmdWindow (void) {
    long textBottom;
    Rect tempRect;
    
    InvalRect (&(gCommandWin->portRect));
    BeginUpdate (gCommandWin);
    BlockMoveData(&(gCommandWin->portRect), &tempRect, sizeof(Rect));
    tempRect.right -= SCROLLER_WIDTH;
    EraseRect (&tempRect);
    if (gCommandWinResized) {
        TEXTREC->viewRect = SetTERect ();
        TEXTREC->destRect.right = TEXTREC->viewRect.right;
        TECalText (hTERec);
        SetScrollRect ();
        gCommandWinResized = false;
    }
    DrawOnlyGrowIcon (gCommandWin);
    FlushOutput ();

    TEXTREC->viewRect = SetTERect ();  /* adjust for possible change in height of status line */

    textBottom = TEXTREC->destRect.top + (TEXTREC->nLines * LINEHEIGHT);
    if (TEXTREC->destRect.top > TEXTREC->viewRect.top)
        TEScroll (0, (TEXTREC->viewRect.top - TEXTREC->destRect.top), hTERec);

    if (TEXTREC->destRect.top < TEXTREC->viewRect.top) {  /* make sure we don't get fractions of lineheights */
        int amountOffTheTop = TEXTREC->viewRect.top - TEXTREC->destRect.top;
        if (amountOffTheTop % LINEHEIGHT) TEScroll (0, amountOffTheTop % LINEHEIGHT, hTERec);
    }
    TEUpdate (&(TEXTREC->viewRect), hTERec);
    AdjustScrollBar ();
    UpdateControls (gCommandWin, gCommandWin->visRgn);
    EndUpdate (gCommandWin);
}

void ActivateCmdWindow(void)
{
    TEActivate (hTERec);
    HiliteControl (vScroll, 0);
    DrawOnlyGrowIcon (gCommandWin);			
}

void DeactivateCmdWindow(void)
{
    TEDeactivate (hTERec);
    HiliteControl (vScroll, 255);
    DrawOnlyGrowIcon (gCommandWin);
}

void InitalizeCmdWindow(void)
{

    /* setup the font, size and writing mode for the command window */
    TextFont (kFontIDMonaco);
    TextSize (9);
    TextFace (0);
    TextMode (srcCopy);
    textStyle[plainStyle].tsFace = 0;
    textStyle[boldStyle].tsFace = bold;

    currentStyle = plainStyle;

    {  /* set up scroll bar */
        Rect scrollRect;
        vScroll = NewControl (gCommandWin, &scrollRect, "\p", 0, 0, 0, 0, scrollBarProc, 0L);
        SetScrollRect ();
        ShowControl (vScroll);
    }

    {  /* set up command text record */
        Rect teRect = SetTERect ();
        hTERec = (TEHandle)TEStyleNew (&teRect, &teRect);
         TECalText (hTERec);
        TEAutoView (true, hTERec);
        TESetClickLoop (uppScrollClickLoop, hTERec);
        TEActivate (hTERec);
    }

    hOutputBuffer = NewHandle (MAX_BUF);  /* a handle to a buffer for text to be displayed */
}

void CleanupCmdWindow(void)
{
    StopPasting ();
    CloseWindow (gCommandWin);
    TEDispose (hTERec);
    DisposeHandle (hOutputBuffer);
}