/* * Name: MicroEMACS * Digital ANSI terminal display * Version: 29 * Last edit: 10-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy * * The SCALD display is just an ANSI display, with * some special hacks to kludge around the bugs, and * to make it a bit more friendly. The support is * unquestionably non-optimal. The costs are wrong; in * fact, display should be fixed up to understand non * linear cost devices like the SCALD. The BackIndex * sequence used in the insert line is defective in * the display firmware, so we set the cost high to * discourage its use. Perhaps the cost should be * set to infinity! */ #include "def.h" #define SCALD 0 /* Buggy display. */ #define BEL 0x07 /* BEL character. */ #define ESC 0x1B /* ESC character. */ #define LF 0x0A /* Line feed. */ extern int ttrow; extern int ttcol; extern int tttop; extern int ttbot; extern int tthue; #if SCALD int tceeol = 3; /* Costs, SCALDstation. */ int tcinsl = 100; int tcdell = 100; #else int tceeol = 3; /* Costs, ANSI display. */ int tcinsl = 17; int tcdell = 16; #endif /* * Initialize the terminal when the editor * gets started up. This is a no-op on the ANSI * display. On the SCALD display, it turns off the * half-screen scroll, because this appears to really * confuse the scrolling region firmware in the * display. */ ttinit() { #if SCALD ttputc(ESC); /* Cancel jump interval. */ ttputc('['); asciiparm(1); ttputc('j'); #endif ttputc(ESC); ttputc('='); } /* * Clean up the terminal, in anticipation of * a return to the command interpreter. This is a no-op * on the ANSI display. On the SCALD display, it sets the * window back to half screen scrolling. Perhaps it should * query the display for the increment, and put it * back to what it was. */ tttidy() { #if SCALD ttputc(ESC); /* Half screen. */ ttputc('['); asciiparm(nrow/2); ttputc('j'); #endif } /* * Move the cursor to the specified * origin 0 row and column position. Try to * optimize out extra moves; redisplay may * have left the cursor in the right * location last time! */ ttmove(row, col) { if (ttrow!=row || ttcol!=col) { ttputc(ESC); ttputc('['); asciiparm(row+1); ttputc(';'); asciiparm(col+1); ttputc('H'); ttrow = row; ttcol = col; } } /* * Erase to end of line. */ tteeol() { ttputc(ESC); ttputc('['); ttputc('K'); } /* * Erase to end of page. */ tteeop() { ttputc(ESC); ttputc('['); ttputc('J'); } /* * Make a noise. */ ttbeep() { ttputc(BEL); ttflush(); } /* * Convert a number to decimal * ascii, and write it out. Used to * deal with numeric arguments. */ asciiparm(n) register int n; { register int q; q = n/10; if (q != 0) asciiparm(q); ttputc((n%10) + '0'); } /* * Insert a block of blank lines onto the * screen, using a scrolling region that starts at row * "row" and extends down to row "bot". Deal with the one * line case, which is a little bit special, with special * case code. Put all of the back index commands out * in a block. The SCALDstation loses the position * of the cursor. */ ttinsl(row, bot, nchunk) { if (row == bot) { /* Funny case. */ if (nchunk != 1) abort(); ttmove(row, 0); tteeol(); } else { /* General case. */ ttwindow(row, bot); ttmove(row, 0); while (nchunk--) { ttputc(ESC); /* Back index. */ ttputc('M'); } #if SCALD ttrow = HUGE; ttcol = HUGE; #endif } } /* * Delete a block of lines, with the uppermost * line at row "row", in a screen slice that extends to * row "bot". The "nchunk" is the number of lines that have * to be deleted. Watch for the pathalogical 1 line case, * where the scroll region is *not* the way to do it. * The block delete is used by the slightly more * optimal display code. */ ttdell(row, bot, nchunk) { if (row == bot) { /* Funny case. */ if (nchunk != 1) abort(); ttmove(row, 0); tteeol(); } else { /* General case. */ ttwindow(row, bot); ttmove(bot, 0); while (nchunk--) ttputc(LF); #if SCALD ttrow = HUGE; ttcol = HUGE; #endif } } /* * This routine sets the scrolling window * on the display to go from line "top" to line * "bot" (origin 0, inclusive). The caller checks * for the pathalogical 1 line scroll window that * doesn't work right, and avoids it. The "ttrow" * and "ttcol" variables are set to a crazy value * to ensure that the next call to "ttmove" does * not turn into a no-op (the window adjustment * moves the cursor). */ ttwindow(top, bot) { if (tttop!=top || ttbot!=bot) { ttputc(ESC); ttputc('['); asciiparm(top+1); ttputc(';'); asciiparm(bot+1); ttputc('r'); ttrow = HUGE; /* Unknown. */ ttcol = HUGE; tttop = top; /* Remember region. */ ttbot = bot; } } /* * Switch to full screen scroll. This is * used by "spawn.c" just before is suspends the * editor, and by "display.c" when it is getting ready * to exit. This function gets to full screen scroll * by sending a DECSTBM with default parameters, but * I think that this is wrong. The SRM seems to say * that the default for Pb is 24, not the size of the * screen, which seems really dumb. Do I really have * to read the size of the screen as in "ttresize" * to do this right? */ ttnowindow() { ttputc(ESC); ttputc('['); ttputc(';'); ttputc('r'); ttrow = HUGE; /* Unknown. */ ttcol = HUGE; tttop = HUGE; /* No scroll region. */ ttbot = HUGE; } /* * Set the current writing color to the * specified color. Watch for color changes that are * not going to do anything (the color is already right) * and don't send anything to the display. * The rainbow version does this in putline.s on a * line by line basis, so don't bother sending * out the color shift. */ ttcolor(color) register int color; { if (color != tthue) { /* if !RAINBOW */ if (color == CTEXT) { /* Normal video. */ ttputc(ESC); ttputc('['); ttputc('m'); } else if (color == CMODE) { /* Reverse video. */ ttputc(ESC); ttputc('['); ttputc('7'); ttputc('m'); } /* endif */ tthue = color; /* Save the color. */ } } /* * This routine is called by the * "refresh the screen" command to try and resize * the display. The new size, which must be deadstopped * to not exceed the NROW and NCOL limits, it stored * back into "nrow" and "ncol". Display can always deal * with a screen NROW by NCOL. Look in "window.c" to * see how the caller deals with a change. */ ttresize() { register int c; register int newnrow; register int newncol; ttputc(ESC); /* Off the end of the */ ttputc('['); /* world. The terminal */ asciiparm(HUGE); /* will chop it. */ ttputc(';'); asciiparm(HUGE); ttputc('H'); ttrow = HUGE; /* Unknown. */ ttcol = HUGE; ttputc(ESC); /* Report position. */ ttputc('['); ttputc('6'); ttputc('n'); ttflush(); if (ttgetc()!=ESC || ttgetc()!='[') return; newnrow = 0; while ((c=ttgetc())>='0' && c<='9') newnrow = 10*newnrow + c - '0'; if (c != ';') return; newncol = 0; while ((c=ttgetc())>='0' && c<='9') newncol = 10*newncol + c - '0'; if (c != 'R') return; if (newnrow < 1) /* Check limits. */ newnrow = 1; else if (newnrow > NROW) newnrow = NROW; if (newncol < 1) newncol = 1; else if (newncol > NCOL) newncol = NCOL; nrow = newnrow; ncol = newncol; }