[BACK]Return to tty.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/tty.c, Revision 1.7

1.7     ! niklas      1: /*     $OpenBSD$       */
        !             2:
1.1       deraadt     3: /*
1.2       millert     4:  * Terminfo display driver
1.1       deraadt     5:  *
1.2       millert     6:  * Terminfo is a terminal information database and routines to describe
                      7:  * terminals on most modern UNIX systems.  Many other systems have adopted
1.1       deraadt     8:  * this as a reasonable way to allow for widly varying and ever changing
                      9:  * varieties of terminal types.         This should be used where practical.
                     10:  */
1.5       millert    11: /*
                     12:  * Known problems: If you have a terminal with no clear to end of screen and
                     13:  * memory of lines below the ones visible on the screen, display will be
                     14:  * wrong in some cases.  I doubt that any such terminal was ever made, but I
                     15:  * thought everyone with delete line would have clear to end of screen too...
1.1       deraadt    16:  *
1.5       millert    17:  * Code for terminals without clear to end of screen and/or clear to end of line
                     18:  * has not been extensivly tested.
1.1       deraadt    19:  *
1.5       millert    20:  * Cost calculations are very rough.  Costs of insert/delete line may be far
                     21:  * from the truth.  This is accentuated by display.c not knowing about
                     22:  * multi-line insert/delete.
1.1       deraadt    23:  *
1.5       millert    24:  * Using scrolling region vs insert/delete line should probably be based on cost
                     25:  * rather than the assuption that scrolling region operations look better.
1.1       deraadt    26:  */
                     27:
1.6       millert    28: #include "def.h"
1.1       deraadt    29:
1.6       millert    30: #include <term.h>
1.5       millert    31:
1.6       millert    32: #ifdef NO_RESIZE
                     33: static int      setttysize     __P((void));
                     34: #endif /* NO_RESIZE */
1.1       deraadt    35:
1.6       millert    36: static int      charcost       __P((char *));
1.1       deraadt    37:
1.6       millert    38: static int      cci;
                     39: static int      insdel;        /* Do we have both insert & delete line? */
                     40: static char    *scroll_fwd;    /* How to scroll forward. */
1.1       deraadt    41:
                     42: /*
                     43:  * Initialize the terminal when the editor
                     44:  * gets started up.
                     45:  */
1.5       millert    46: VOID
                     47: ttinit()
                     48: {
1.6       millert    49:        char    *tv_stype, *p;
                     50:
                     51: /* system dependent function to determine terminal type, if necessary. */
                     52: #ifndef gettermtype
                     53:        char    *gettermtype();
                     54: #endif /* gettermtype */
1.1       deraadt    55:
1.2       millert    56:        if ((tv_stype = gettermtype()) == NULL)
1.6       millert    57:                panic("Could not determine terminal type!");
                     58:
1.5       millert    59:        if (setupterm(tv_stype, 1, NULL)) {
1.6       millert    60:                (void)asprintf(&p, "Unknown terminal type: %s", tv_stype);
1.2       millert    61:                panic(p);
1.1       deraadt    62:        }
1.6       millert    63:
1.2       millert    64:        scroll_fwd = scroll_forward;
1.6       millert    65:        if (scroll_fwd == NULL || *scroll_fwd == '\0') {
1.2       millert    66:                /* this is what GNU Emacs does */
                     67:                scroll_fwd = parm_down_cursor;
1.6       millert    68:                if (scroll_fwd == NULL || *scroll_fwd == '\0')
1.2       millert    69:                        scroll_fwd = "\n";
1.1       deraadt    70:        }
1.6       millert    71:
                     72:        if (cursor_address == NULL || cursor_up == NULL)
                     73:                panic("This terminal is too stupid to run mg");
                     74:
                     75:        /* set nrow & ncol */
                     76:        ttresize();
1.1       deraadt    77:
1.2       millert    78:        if (!clr_eol)
                     79:                tceeol = ncol;
                     80:        else
                     81:                tceeol = charcost(clr_eol);
1.1       deraadt    82:
                     83:        /* Estimate cost of inserting a line */
1.2       millert    84:        if (change_scroll_region && scroll_reverse)
1.5       millert    85:                tcinsl = charcost(change_scroll_region) * 2 +
1.6       millert    86:                    charcost(scroll_reverse);
1.2       millert    87:        else if (parm_insert_line)
                     88:                tcinsl = charcost(parm_insert_line);
                     89:        else if (insert_line)
                     90:                tcinsl = charcost(insert_line);
                     91:        else
1.6       millert    92:                /* make this cost high enough */
                     93:                tcinsl = NROW * NCOL;
1.1       deraadt    94:
                     95:        /* Estimate cost of deleting a line */
1.2       millert    96:        if (change_scroll_region)
1.5       millert    97:                tcdell = charcost(change_scroll_region) * 2 +
1.6       millert    98:                    charcost(scroll_fwd);
1.2       millert    99:        else if (parm_delete_line)
                    100:                tcdell = charcost(parm_delete_line);
                    101:        else if (delete_line)
                    102:                tcdell = charcost(delete_line);
1.5       millert   103:        else
1.6       millert   104:                /* make this cost high enough */
                    105:                tcdell = NROW * NCOL;
1.1       deraadt   106:
                    107:        /* Flag to indicate that we can both insert and delete lines */
1.6       millert   108:        insdel = (insert_line || parm_insert_line) &&
                    109:            (delete_line || parm_delete_line);
1.1       deraadt   110:
1.2       millert   111:        if (enter_ca_mode)
1.6       millert   112:                /* enter application mode */
                    113:                putpad(enter_ca_mode, 1);
1.3       millert   114:
                    115:        setttysize();
1.1       deraadt   116: }
                    117:
                    118: /*
1.4       millert   119:  * Re-initialize the terminal when the editor is resumed.
                    120:  * The keypad_xmit doesn't really belong here but...
                    121:  */
1.5       millert   122: VOID
                    123: ttreinit()
                    124: {
1.4       millert   125:        if (enter_ca_mode)
1.6       millert   126:                /* enter application mode */
                    127:                putpad(enter_ca_mode, 1);
1.4       millert   128:        if (keypad_xmit)
1.6       millert   129:                /* turn on keypad */
                    130:                putpad(keypad_xmit, 1);
1.4       millert   131:
                    132:        setttysize();
                    133: }
                    134:
                    135: /*
1.6       millert   136:  * Clean up the terminal, in anticipation of a return to the command
                    137:  * interpreter. This is a no-op on the ANSI display. On the SCALD display,
                    138:  * it sets the window back to half screen scrolling. Perhaps it should
                    139:  * query the display for the increment, and put it back to what it was.
1.1       deraadt   140:  */
1.5       millert   141: VOID
                    142: tttidy()
                    143: {
                    144: #ifdef XKEYS
                    145:        ttykeymaptidy();
1.6       millert   146: #endif /* XKEYS */
                    147:
1.2       millert   148:        /* set the term back to normal mode */
                    149:        if (exit_ca_mode)
                    150:                putpad(exit_ca_mode, 1);
1.1       deraadt   151: }
                    152:
                    153: /*
1.6       millert   154:  * Move the cursor to the specified origin 0 row and column position. Try to
                    155:  * optimize out extra moves; redisplay may have left the cursor in the right
1.1       deraadt   156:  * location last time!
                    157:  */
1.5       millert   158: VOID
                    159: ttmove(row, col)
1.6       millert   160:        int row, col;
1.5       millert   161: {
                    162:        if (ttrow != row || ttcol != col) {
                    163:                putpad(tgoto(cursor_address, col, row), 1);
                    164:                ttrow = row;
                    165:                ttcol = col;
                    166:        }
1.1       deraadt   167: }
                    168:
                    169: /*
                    170:  * Erase to end of line.
                    171:  */
1.5       millert   172: VOID
                    173: tteeol()
                    174: {
1.6       millert   175:        int     i;
1.2       millert   176:
                    177:        if (clr_eol)
                    178:                putpad(clr_eol, 1);
                    179:        else {
1.6       millert   180:                i = ncol - ttcol;
1.2       millert   181:                while (i--)
                    182:                        ttputc(' ');
                    183:                ttrow = ttcol = HUGE;
                    184:        }
1.1       deraadt   185: }
                    186:
                    187: /*
                    188:  * Erase to end of page.
                    189:  */
1.5       millert   190: VOID
                    191: tteeop()
                    192: {
1.6       millert   193:        int     line;
1.2       millert   194:
                    195:        if (clr_eos)
                    196:                putpad(clr_eos, nrow - ttrow);
                    197:        else {
                    198:                putpad(clr_eol, 1);
                    199:                if (insdel)
                    200:                        ttdell(ttrow + 1, lines, lines - ttrow - 1);
1.6       millert   201:                else {
                    202:                        /* do it by hand */
1.2       millert   203:                        for (line = ttrow + 1; line <= lines; ++line) {
                    204:                                ttmove(line, 0);
                    205:                                tteeol();
                    206:                        }
                    207:                }
                    208:                ttrow = ttcol = HUGE;
1.1       deraadt   209:        }
                    210: }
                    211:
                    212: /*
                    213:  * Make a noise.
                    214:  */
1.5       millert   215: VOID
                    216: ttbeep()
                    217: {
1.2       millert   218:        putpad(bell, 1);
1.1       deraadt   219:        ttflush();
                    220: }
                    221:
                    222: /*
1.6       millert   223:  * Insert nchunk blank line(s) onto the screen, scrolling the last line on
                    224:  * the screen off the bottom.  Use the scrolling region if possible for a
                    225:  * smoother display.  If there is no scrolling region, use a set of insert
                    226:  * and delete line sequences.
1.1       deraadt   227:  */
1.5       millert   228: VOID
                    229: ttinsl(row, bot, nchunk)
1.6       millert   230:        int row, bot, nchunk;
1.5       millert   231: {
1.6       millert   232:        int     i, nl;
1.1       deraadt   233:
1.6       millert   234:        /* Case of one line insert is special. */
                    235:        if (row == bot) {
                    236:                ttmove(row, 0);
1.2       millert   237:                tteeol();
                    238:                return;
                    239:        }
                    240:        if (change_scroll_region && scroll_reverse) {
1.5       millert   241:                /* Use scroll region and back index      */
1.2       millert   242:                nl = bot - row;
1.5       millert   243:                ttwindow(row, bot);
1.2       millert   244:                ttmove(row, 0);
                    245:                while (nchunk--)
                    246:                        putpad(scroll_reverse, nl);
                    247:                ttnowindow();
                    248:                return;
                    249:        } else if (insdel) {
1.5       millert   250:                ttmove(1 + bot - nchunk, 0);
1.2       millert   251:                nl = nrow - ttrow;
                    252:                if (parm_delete_line)
                    253:                        putpad(tgoto(parm_delete_line, 0, nchunk), nl);
                    254:                else
1.6       millert   255:                        /* For all lines in the chunk... */
1.5       millert   256:                        for (i = 0; i < nchunk; i++)
1.2       millert   257:                                putpad(delete_line, nl);
                    258:                ttmove(row, 0);
1.6       millert   259:
                    260:                /* ttmove() changes ttrow */
                    261:                nl = nrow - ttrow;
                    262:
1.2       millert   263:                if (parm_insert_line)
                    264:                        putpad(tgoto(parm_insert_line, 0, nchunk), nl);
                    265:                else
                    266:                        /* For all lines in the chunk */
1.5       millert   267:                        for (i = 0; i < nchunk; i++)
1.2       millert   268:                                putpad(insert_line, nl);
                    269:                ttrow = HUGE;
                    270:                ttcol = HUGE;
                    271:        } else
                    272:                panic("ttinsl: Can't insert/delete line");
1.1       deraadt   273: }
                    274:
                    275: /*
1.6       millert   276:  * Delete nchunk line(s) from "row", replacing the bottom line on the
                    277:  * screen with a blank line.  Unless we're using the scrolling region,
                    278:  * this is done with crafty sequences of insert and delete lines.  The
                    279:  * presence of the echo area makes a boundry condition go away.
1.1       deraadt   280:  */
1.5       millert   281: VOID
1.1       deraadt   282: ttdell(row, bot, nchunk)
1.6       millert   283:        int row, bot, nchunk;
1.1       deraadt   284: {
1.6       millert   285:        int     i, nl;
1.1       deraadt   286:
1.6       millert   287:        /* One line special cases */
                    288:        if (row == bot) {
1.2       millert   289:                ttmove(row, 0);
                    290:                tteeol();
                    291:                return;
                    292:        }
1.6       millert   293:        /* scrolling region */
                    294:        if (change_scroll_region) {
1.2       millert   295:                nl = bot - row;
                    296:                ttwindow(row, bot);
                    297:                ttmove(bot, 0);
                    298:                while (nchunk--)
                    299:                        putpad(scroll_fwd, nl);
                    300:                ttnowindow();
1.6       millert   301:        /* else use insert/delete line */
1.5       millert   302:        } else if (insdel) {
1.6       millert   303:                ttmove(row, 0);
1.2       millert   304:                nl = nrow - ttrow;
                    305:                if (parm_delete_line)
                    306:                        putpad(tgoto(parm_delete_line, 0, nchunk), nl);
                    307:                else
1.5       millert   308:                        /* For all lines in the chunk    */
                    309:                        for (i = 0; i < nchunk; i++)
1.2       millert   310:                                putpad(delete_line, nl);
1.5       millert   311:                ttmove(1 + bot - nchunk, 0);
1.6       millert   312:
                    313:                /* ttmove() changes ttrow */
                    314:                nl = nrow - ttrow;
1.2       millert   315:                if (parm_insert_line)
                    316:                        putpad(tgoto(parm_insert_line, 0, nchunk), nl);
                    317:                else
                    318:                        /* For all lines in the chunk */
1.5       millert   319:                        for (i = 0; i < nchunk; i++)
1.2       millert   320:                                putpad(insert_line, nl);
                    321:                ttrow = HUGE;
                    322:                ttcol = HUGE;
                    323:        } else
                    324:                panic("ttdell: Can't insert/delete line");
1.1       deraadt   325: }
                    326:
                    327: /*
1.6       millert   328:  * This routine sets the scrolling window on the display to go from line
                    329:  * "top" to line "bot" (origin 0, inclusive).  The caller checks for the
                    330:  * pathological 1-line scroll window which doesn't work right and avoids
                    331:  * it.  The "ttrow" and "ttcol" variables are set to a crazy value to
                    332:  * ensure that the next call to "ttmove" does not turn into a no-op (the
                    333:  * window adjustment moves the cursor).
1.1       deraadt   334:  */
1.5       millert   335: VOID
1.1       deraadt   336: ttwindow(top, bot)
1.6       millert   337:        int top, bot;
1.1       deraadt   338: {
1.2       millert   339:        if (change_scroll_region && (tttop != top || ttbot != bot)) {
                    340:                putpad(tgoto(change_scroll_region, bot, top), nrow - ttrow);
1.5       millert   341:                ttrow = HUGE;   /* Unknown.              */
1.1       deraadt   342:                ttcol = HUGE;
1.5       millert   343:                tttop = top;    /* Remember region.      */
1.1       deraadt   344:                ttbot = bot;
                    345:        }
                    346: }
                    347:
                    348: /*
1.6       millert   349:  * Switch to full screen scroll. This is used by "spawn.c" just before it
                    350:  * suspends the editor and by "display.c" when it is getting ready to
                    351:  * exit.  This function does a full screen scroll by telling the terminal
                    352:  * to set a scrolling region that is lines or nrow rows high, whichever is
                    353:  * larger.  This behavior seems to work right on systems where you can set
                    354:  * your terminal size.
1.1       deraadt   355:  */
1.5       millert   356: VOID
1.1       deraadt   357: ttnowindow()
                    358: {
1.2       millert   359:        if (change_scroll_region) {
                    360:                putpad(tgoto(change_scroll_region,
1.5       millert   361:                       (nrow > lines ? nrow : lines) - 1, 0), nrow - ttrow);
                    362:                ttrow = HUGE;   /* Unknown.              */
1.2       millert   363:                ttcol = HUGE;
1.5       millert   364:                tttop = HUGE;   /* No scroll region.     */
1.2       millert   365:                ttbot = HUGE;
                    366:        }
1.1       deraadt   367: }
                    368:
                    369: /*
1.6       millert   370:  * Set the current writing color to the specified color. Watch for color
                    371:  * changes that are not going to do anything (the color is already right)
                    372:  * and don't send anything to the display.  The rainbow version does this
                    373:  * in putline.s on a line by line basis, so don't bother sending out the
                    374:  * color shift.
1.1       deraadt   375:  */
1.5       millert   376: VOID
1.2       millert   377: ttcolor(color)
1.6       millert   378:        int color;
1.2       millert   379: {
                    380:        if (color != tthue) {
1.6       millert   381:                if (color == CTEXT)
                    382:                        /* normal video */
1.5       millert   383:                        putpad(exit_standout_mode, 1);
1.6       millert   384:                else if (color == CMODE)
                    385:                        /* reverse video */
1.5       millert   386:                        putpad(enter_standout_mode, 1);
1.6       millert   387:                /* save the color */
                    388:                tthue = color;
1.1       deraadt   389:        }
                    390: }
                    391:
                    392: /*
1.6       millert   393:  * This routine is called by the "refresh the screen" command to try
                    394:  * to resize the display. The new size, which must not exceed the NROW
                    395:  * and NCOL limits, is stored back into "nrow" and * "ncol". Display can
                    396:  * always deal with a screen NROW by NCOL. Look in "window.c" to see how
                    397:  * the caller deals with a change.
1.1       deraadt   398:  */
1.5       millert   399: VOID
                    400: ttresize()
                    401: {
1.6       millert   402:        /* found in "ttyio.c" */
                    403:        setttysize();
1.2       millert   404:
1.6       millert   405:        /* ask OS for tty size and check limits */
                    406:        if (nrow < 1)
1.1       deraadt   407:                nrow = 1;
                    408:        else if (nrow > NROW)
                    409:                nrow = NROW;
                    410:        if (ncol < 1)
                    411:                ncol = 1;
                    412:        else if (ncol > NCOL)
                    413:                ncol = NCOL;
                    414: }
                    415:
                    416: #ifdef NO_RESIZE
1.5       millert   417: static
                    418: setttysize()
                    419: {
1.3       millert   420:        nrow = lines;
                    421:        ncol = columns;
1.1       deraadt   422: }
1.6       millert   423: #endif /* NO_RESIZE */
1.1       deraadt   424:
1.6       millert   425: /*
                    426:  * fake char output for charcost()
                    427:  */
1.5       millert   428: /* ARGSUSED */
1.6       millert   429: static int
1.1       deraadt   430: fakec(c)
1.6       millert   431:        char c;
1.1       deraadt   432: {
                    433:        cci++;
1.6       millert   434:        return 0;
1.1       deraadt   435: }
                    436:
                    437: /* calculate the cost of doing string s */
1.6       millert   438: static int
1.5       millert   439: charcost(s)
1.6       millert   440:        char *s;
1.5       millert   441: {
1.6       millert   442:        int     cci = 0;
1.1       deraadt   443:
1.2       millert   444:        tputs(s, nrow, fakec);
                    445:        return (cci);
1.1       deraadt   446: }