Annotation of 43BSDReno/contrib/emacs-18.55/src/scroll.c, revision 1.1

1.1     ! root        1: /* Calculate what ins/del line to do, and do it, for Emacs redisplay.
        !             2:    Copyright (C) 1985, 1986 Free Software Foundation, Inc.
        !             3: 
        !             4: This file is part of GNU Emacs.
        !             5: 
        !             6: GNU Emacs is distributed in the hope that it will be useful,
        !             7: but WITHOUT ANY WARRANTY.  No author or distributor
        !             8: accepts responsibility to anyone for the consequences of using it
        !             9: or for whether it serves any particular purpose or works at all,
        !            10: unless he says so in writing.  Refer to the GNU Emacs General Public
        !            11: License for full details.
        !            12: 
        !            13: Everyone is granted permission to copy, modify and redistribute
        !            14: GNU Emacs, but only under the conditions described in the
        !            15: GNU Emacs General Public License.   A copy of this license is
        !            16: supposed to have been given to you along with GNU Emacs so you
        !            17: can know your rights and responsibilities.  It should be in a
        !            18: file named COPYING.  Among other things, the copyright notice
        !            19: and this notice must be preserved on all copies.  */
        !            20: 
        !            21: 
        !            22: #include "config.h"
        !            23: #include "termchar.h"
        !            24: #include "dispextern.h"
        !            25: 
        !            26: #define max(a, b) ((a) > (b) ? (a) : (b))
        !            27: #define min(a, b) ((a) < (b) ? (a) : (b))
        !            28: 
        !            29: /* All costs measured in characters.  Therefore, no cost
        !            30:    can exceed MScreenLength * MScreenWidth (or so).
        !            31:    That is about 10000, which fits in a short.  */
        !            32: 
        !            33: #define INFINITY 15000
        !            34: 
        !            35: struct matrix_elt
        !            36:   {
        !            37:     /* Cost of outputting through this line
        !            38:        if no insert/delete is done just above it.  */
        !            39:     short writecost;
        !            40:     /* Cost of outputting through this line
        !            41:        if an insert is done just above it.  */
        !            42:     short insertcost;
        !            43:     /* Cost of outputting through this line
        !            44:        if a delete is done just above it.  */
        !            45:     short deletecost;
        !            46:     /* Number of inserts so far in this run of inserts,
        !            47:        for the cost in insertcost.  */
        !            48:     char insertcount;
        !            49:     /* Number of deletes so far in this run of deletes,
        !            50:        for the cost in deletecost.  */
        !            51:     char deletecount;
        !            52:   };
        !            53: 
        !            54: /* See CalcIDCosts for on the arrays below */
        !            55: int ILcost[MScreenLength];/* ov(n) + 1*mf(n) */
        !            56: int DLcost[MScreenLength];/* ov(n) + 1*mf(n) */
        !            57: int ILncost[MScreenLength];/* mf(n) */
        !            58: int DLncost[MScreenLength];/* mf(n) */
        !            59: 
        !            60: scrolling_1 (window_size, unchanged_at_top, unchanged_at_bottom,
        !            61:             draw_cost, old_hash, new_hash, free_at_end)
        !            62:      int window_size, unchanged_at_top, unchanged_at_bottom;
        !            63:      int *draw_cost;
        !            64:      int *old_hash;
        !            65:      int *new_hash;
        !            66:      int free_at_end;
        !            67: {
        !            68:   struct matrix_elt *matrix;
        !            69:   matrix = ((struct matrix_elt *)
        !            70:            alloca ((window_size + 1) * (window_size + 1) * sizeof *matrix));
        !            71: 
        !            72:   calculate_scrolling (matrix, window_size, unchanged_at_bottom,
        !            73:                       draw_cost, old_hash, new_hash,
        !            74:                       free_at_end);
        !            75:   do_scrolling (matrix, window_size, unchanged_at_top);
        !            76: }
        !            77: 
        !            78: /* Determine, in matrix[i,j], the cost of updating the first j old lines
        !            79:    into the first i new lines.
        !            80:    This involves using insert or delete somewhere if i != j.
        !            81:    For each matrix elements, three kinds of costs are recorded:
        !            82:    the smallest cost that ends with an insert, the smallest
        !            83:    cost that ends with a delete, and the smallest cost that
        !            84:    ends with neither one.  These are kept separate because
        !            85:    on some terminals the cost of doing an insert varies
        !            86:    depending on whether one was just done, etc.  */
        !            87: 
        !            88: /* draw_cost[VPOS] is the cost of outputting new line at VPOS.
        !            89:    old_hash[VPOS] is the hash code of the old line at VPOS.
        !            90:    new_hash[VPOS] is the hash code of the new line at VPOS.
        !            91:    Note that these are not true screen vpos's, but relative
        !            92:    to the place at which the first mismatch between old and
        !            93:    new contents appears.  */
        !            94: 
        !            95: calculate_scrolling (matrix, window_size, lines_below,
        !            96:                     draw_cost, old_hash, new_hash,
        !            97:                     free_at_end)
        !            98:      /* matrix is of size window_size + 1 on each side.  */
        !            99:      struct matrix_elt *matrix;
        !           100:      int window_size;
        !           101:      int *draw_cost;
        !           102:      int *old_hash;
        !           103:      int *new_hash;
        !           104:      int free_at_end;
        !           105: {
        !           106:   register int i, j;
        !           107:   register struct matrix_elt *p, *p1;
        !           108:   register int cost, cost1;
        !           109: 
        !           110:   int lines_moved = window_size + (scroll_region_ok ? 0 : lines_below);
        !           111:   int *first_insert_cost = &ILcost[screen_height - lines_moved];
        !           112:   int *first_delete_cost = &DLcost[screen_height - lines_moved];
        !           113:   int *next_insert_cost = &ILncost[screen_height - lines_moved];
        !           114:   int *next_delete_cost = &DLncost[screen_height - lines_moved];
        !           115: 
        !           116:   /* initialize the top left corner of the matrix */
        !           117:   matrix->writecost = 0;
        !           118:   matrix->insertcost = INFINITY;
        !           119:   matrix->deletecost = INFINITY;
        !           120:   matrix->insertcount = 0;
        !           121:   matrix->deletecount = 0;
        !           122: 
        !           123:   /* initialize the left edge of the matrix */
        !           124:   cost = first_insert_cost[1] - next_insert_cost[1];
        !           125:   for (i = 1; i <= window_size; i++)
        !           126:     {
        !           127:       p = matrix + i * (window_size + 1);
        !           128:       cost += draw_cost[i] + next_insert_cost[i];
        !           129:       p->insertcost = cost;
        !           130:       p->writecost = INFINITY;
        !           131:       p->deletecost = INFINITY;
        !           132:       p->insertcount = i;
        !           133:       p->deletecount = 0;
        !           134:     }
        !           135: 
        !           136:   /* initialize the top edge of the matrix */
        !           137:   cost = first_delete_cost[1] - next_delete_cost[1];
        !           138:   for (j = 1; j <= window_size; j++)
        !           139:     {
        !           140:       cost += next_delete_cost[j];
        !           141:       matrix[j].deletecost = cost;
        !           142:       matrix[j].writecost = INFINITY;
        !           143:       matrix[j].insertcost = INFINITY;
        !           144:       matrix[j].deletecount = j;
        !           145:       matrix[j].insertcount = 0;
        !           146:     }
        !           147: 
        !           148:   /* `i' represents the vpos among new screen contents.
        !           149:      `j' represents the vpos among the old screen contents.  */
        !           150:   p = matrix + window_size + 2;        /* matrix [1, 1] */
        !           151:   for (i = 1; i <= window_size; i++, p++)
        !           152:     for (j = 1; j <= window_size; j++, p++)
        !           153:       {
        !           154:        /* p contains the address of matrix [i, j] */
        !           155: 
        !           156:        /* First calculate the cost assuming we do
        !           157:           not insert or delete above this line.
        !           158:           That is, if we update through line i-1
        !           159:           based on old lines through j-1,
        !           160:           and then just change old line j to new line i.  */
        !           161:        p1 = p - window_size - 2; /* matrix [i-1, j-1] */
        !           162:        cost = p1->writecost;
        !           163:        if (cost > p1->insertcost)
        !           164:          cost = p1->insertcost;
        !           165:        if (cost > p1->deletecost)
        !           166:          cost = p1->deletecost;
        !           167:        if (old_hash[j] != new_hash[i])
        !           168:          cost += draw_cost[i];
        !           169:        p->writecost = cost;
        !           170: 
        !           171:        /* Calculate the cost if we do an insert-line
        !           172:           before outputting this line.
        !           173:           That is, we update through line i-1
        !           174:           based on old lines through j,
        !           175:           do an insert-line on line i,
        !           176:           and then output line i from scratch,
        !           177:           leaving old lines starting from j for reuse below.  */
        !           178:        p1 = p - window_size - 1; /* matrix [i-1, j] */
        !           179:        /* No need to think about doing a delete followed
        !           180:           immediately by an insert.  It cannot be as good
        !           181:           as not doing either of them.  */
        !           182:        if (free_at_end == i)
        !           183:          {
        !           184:            cost = p1->writecost;
        !           185:            cost1 = p1->insertcost;
        !           186:          }
        !           187:        else
        !           188:          {
        !           189:            cost = p1->writecost + first_insert_cost[i];
        !           190:            if (p1->insertcount > i)
        !           191:              abort ();
        !           192:            cost1 = p1->insertcost + next_insert_cost[i - p1->insertcount];
        !           193:          }
        !           194:        p->insertcost = min (cost, cost1) + draw_cost[i];
        !           195:        p->insertcount = (cost < cost1) ? 1 : p1->insertcount + 1;
        !           196:        if (p->insertcount > i)
        !           197:          abort ();
        !           198: 
        !           199:        /* Calculate the cost if we do a delete line after
        !           200:           outputting this line.
        !           201:           That is, we update through line i
        !           202:           based on old lines through j-1,
        !           203:           and throw away old line j.  */
        !           204:        p1 = p - 1;             /* matrix [i, j-1] */
        !           205:        /* No need to think about doing an insert followed
        !           206:           immediately by a delete.  */
        !           207:        if (free_at_end == i)
        !           208:          {
        !           209:            cost = p1->writecost;
        !           210:            cost1 = p1->deletecost;
        !           211:          }
        !           212:        else
        !           213:          {
        !           214:            cost = p1->writecost + first_delete_cost[i];
        !           215:            cost1 = p1->deletecost + next_delete_cost[i];
        !           216:          }
        !           217:        p->deletecost = min (cost, cost1);
        !           218:        p->deletecount = (cost < cost1) ? 1 : p1->deletecount + 1;
        !           219:       }
        !           220: }
        !           221: 
        !           222: /* Perform insert-lines and delete-lines operations
        !           223:  according to the costs in the matrix.
        !           224:  Updates the contents of PhysScreen to record what was done. */
        !           225: 
        !           226: do_scrolling (matrix, window_size, unchanged_at_top)
        !           227:      struct matrix_elt *matrix;
        !           228:      int window_size;
        !           229:      int unchanged_at_top;
        !           230: {
        !           231:   register struct matrix_elt *p;
        !           232:   register int i, j;
        !           233:   struct { int count, pos; } queue[MScreenLength];
        !           234:   int offset = unchanged_at_top;
        !           235:   int qi = 0;
        !           236:   int window = 0;
        !           237:   register int tem;
        !           238:   extern struct display_line *PhysScreen[MScreenLength + 1];
        !           239:   extern struct display_line *OPhysScreen[MScreenLength + 1];
        !           240: 
        !           241: /* First do all deletions of lines; queue up insertions.
        !           242:   Also move lines to correct slots in PhysScreen */
        !           243: 
        !           244:   i = j = window_size;
        !           245: 
        !           246:   while (i > 0 || j > 0)
        !           247:     {
        !           248:       p = matrix + i * (window_size + 1) + j;
        !           249:       tem = p->insertcost;
        !           250:       if (tem < p->writecost && tem < p->deletecost)
        !           251:        {
        !           252:          /* Insert should be done at vpos i-1, plus maybe some before */
        !           253:          queue[qi].count = p->insertcount;
        !           254:          i -= p->insertcount;
        !           255:          queue[qi++].pos = i + unchanged_at_top;
        !           256:        }
        !           257:       else if (p->deletecost < p->writecost)
        !           258:        {
        !           259:          /* Old line at vpos j-1, and maybe some before it,
        !           260:             should be deleted */
        !           261:          j -= p->deletecount;
        !           262:          if (!window)
        !           263:            {
        !           264:              set_terminal_window (window_size + unchanged_at_top);
        !           265:              window = 1;
        !           266:            }
        !           267:          ins_del_lines (j + unchanged_at_top, - p->deletecount);
        !           268:        }
        !           269:       else
        !           270:        {
        !           271:          /* Best thing done here is no insert or delete */
        !           272:          /* Old line at vpos j-1 ends up at vpos i-1 */
        !           273:          PhysScreen[i + offset] = OPhysScreen[j + offset];
        !           274:          i--;
        !           275:          j--;
        !           276:        }
        !           277:     }
        !           278: 
        !           279:   if (!window && qi)
        !           280:     {
        !           281:       set_terminal_window (window_size + unchanged_at_top);
        !           282:       window = 1;
        !           283:     }
        !           284: 
        !           285:   /* Now do all insertions */
        !           286: 
        !           287:   for (i = qi - 1; i >= 0; i--)
        !           288:     {
        !           289:       ins_del_lines (queue[i].pos, queue[i].count);
        !           290:       /* mark the inserted lines as clear */
        !           291:       tem = queue[i].pos;
        !           292:       for (j = tem + queue[i].count; j > tem; j--)
        !           293:        PhysScreen[j] = 0;
        !           294:     }
        !           295: 
        !           296:   if (window)
        !           297:     set_terminal_window (0);
        !           298: }
        !           299: 
        !           300: /* Return number of lines in common between PhysScreen and DesiredScreen,
        !           301:    considering only vpos range START to END (not including END).
        !           302:    Ignores short lines (length < 20) on the assumption that
        !           303:    avoiding redrawing such a line will have little weight.  */
        !           304: 
        !           305: int
        !           306: scrolling_max_lines_saved (start, end, oldhash, newhash, cost)
        !           307:      int start, end;
        !           308:      int *oldhash, *newhash, *cost;
        !           309: {
        !           310:   struct { int hash; int count; } lines[01000];
        !           311:   register int i, h;
        !           312:   register int matchcount = 0;
        !           313: 
        !           314:   bzero (lines, sizeof lines);
        !           315: 
        !           316:   /* Put new lines' hash codes in hash table.  */
        !           317:   for (i = start; i < end; i++)
        !           318:     {
        !           319:       if (cost[i] > 20)
        !           320:        {
        !           321:          h = newhash[i] & 0777;
        !           322:          lines[h].hash = newhash[i];
        !           323:          lines[h].count++;
        !           324:        }
        !           325:     }
        !           326: 
        !           327:   /* Look up old line hash codes in the hash table.
        !           328:      Count number of matches between old lines and new.  */
        !           329: 
        !           330:   for (i = start; i < end; i++)
        !           331:     {
        !           332:       h = oldhash[i] & 0777;
        !           333:       if (oldhash[i] == lines[h].hash)
        !           334:        {
        !           335:          matchcount++;
        !           336:          if (--lines[h].count == 0)
        !           337:            lines[h].hash = 0;
        !           338:        }
        !           339:     }
        !           340: 
        !           341:   return matchcount;
        !           342: }
        !           343: 
        !           344: /* Return a measure of the cost of moving the lines
        !           345:    starting with vpos FROM, up to but not including vpos TO,
        !           346:    down by AMOUNT lines (AMOUNT may be negative).
        !           347:    These are the same arguments that might be given to
        !           348:    scroll_screen_lines to perform this scrolling.  */
        !           349: 
        !           350: scroll_cost (from, to, amount)
        !           351:      int from, to, amount;
        !           352: {
        !           353:   /* Compute how many lines, at bottom of screen,
        !           354:      will not be involved in actual motion.  */
        !           355:   int ok_below = screen_height - to;
        !           356:   if (amount > 0) ok_below -= amount;
        !           357:   if (! scroll_region_ok) ok_below = 0;
        !           358: 
        !           359:   if (amount == 0)
        !           360:     return 0;
        !           361: 
        !           362:   if (amount < 0)
        !           363:     {
        !           364:       int temp = to;
        !           365:       to = from + amount;
        !           366:       from = temp + amount;
        !           367:       amount = - amount;
        !           368:     }
        !           369: 
        !           370:   from += ok_below;
        !           371:   to += ok_below;
        !           372: 
        !           373:   return ILcost[from] + (amount - 1) * ILncost[from]
        !           374:     + DLcost[to] + (amount - 1) * DLncost[to];
        !           375: }
        !           376: 
        !           377: /* Calculate the insert and delete line costs.
        !           378: 
        !           379:    We keep the ID costs in a precomputed array based on the position
        !           380:    at which the I or D is performed.  Also, there are two kinds of ID
        !           381:    costs: the "once-only" and the "repeated".  This is to handle both
        !           382:    those terminals that are able to insert N lines at a time (once-
        !           383:    only) and those that must repeatedly insert one line.
        !           384: 
        !           385:    The cost to insert N lines at line L is
        !           386:            [tt.t_ILov  + (screen_height + 1 - L) * tt.t_ILpf] +
        !           387:        N * [tt.t_ILnov + (screen_height + 1 - L) * tt.t_ILnpf]
        !           388: 
        !           389:    ILov represents the basic insert line overhead.  ILpf is the padding
        !           390:    required to allow the terminal time to move a line: insertion at line
        !           391:    L changes (screen_height + 1 - L) lines.
        !           392: 
        !           393:    The first bracketed expression above is the overhead; the second is
        !           394:    the multiply factor.  Both are dependent only on the position at
        !           395:    which the insert is performed.  We store the overhead in ILcost and
        !           396:    the multiply factor in ILncost.  Note however that any insertion
        !           397:    must include at least one multiply factor.  Rather than compute this
        !           398:    as ILcost[line]+ILncost[line], we add ILncost into ILcost.  This is
        !           399:    reasonable because of the particular algorithm used in calcM.
        !           400: 
        !           401:    Deletion is essentially the same as insertion.
        !           402:  */
        !           403: 
        !           404: CalcIDCosts (ins_line_string, multi_ins_string,
        !           405:             del_line_string, multi_del_string,
        !           406:             setup_string, cleanup_string)
        !           407:      char *ins_line_string, *multi_ins_string;
        !           408:      char *del_line_string, *multi_del_string;
        !           409:      char *setup_string, *cleanup_string;
        !           410: {
        !           411:   /* Discourage long scrolls slightly on fast lines.
        !           412:      This says that scrolling nearly the full length of the screen
        !           413:      is not worth it if reprinting takes less than 1/4 second.  */
        !           414:   int extra = baud_rate / (10 * 4 * screen_height);
        !           415: 
        !           416:   CalcIDCosts1 (ins_line_string, multi_ins_string,
        !           417:                setup_string, cleanup_string,
        !           418:                ILcost, ILncost, extra);
        !           419:   CalcIDCosts1 (del_line_string, multi_del_string,
        !           420:                setup_string, cleanup_string,
        !           421:                DLcost, DLncost, 0);
        !           422: }
        !           423: 
        !           424: CalcIDCosts1 (one_line_string, multi_string,
        !           425:              setup_string, cleanup_string,
        !           426:              costvec, ncostvec, extra)
        !           427:      char *one_line_string, *multi_string;
        !           428:      char *setup_string, *cleanup_string;
        !           429:      int *costvec, *ncostvec;
        !           430:      int extra;
        !           431: {
        !           432:   if (multi_string)
        !           433:     CalcLID (string_cost (multi_string),
        !           434:             per_line_cost (multi_string),
        !           435:             extra, 0, costvec, ncostvec);
        !           436:   else if (one_line_string)
        !           437:     CalcLID (string_cost (setup_string) + string_cost (cleanup_string), 0,
        !           438:             string_cost (one_line_string) + extra,
        !           439:             per_line_cost (one_line_string),
        !           440:             costvec, ncostvec);
        !           441:   else
        !           442:     CalcLID (9999, 0, 9999, 0,
        !           443:             costvec, ncostvec);
        !           444: }
        !           445: 
        !           446: /* Calculate the line ID overhead and multiply factor values */
        !           447: CalcLID (ov1, pf1, ovn, pfn, ov, mf)
        !           448:      int ov1, ovn;
        !           449:      int pf1, pfn;
        !           450:      register int *ov, *mf;
        !           451: {
        !           452:   register int i;
        !           453:   register int insert_overhead = ov1 * 10 + screen_height * pf1;
        !           454:   register int next_insert_cost = ovn * 10 + screen_height * pfn;
        !           455: 
        !           456:   for (i = screen_height - 1; i > 0; i--)
        !           457:     {
        !           458:       *mf++ = next_insert_cost / 10;
        !           459:       next_insert_cost -= pfn;
        !           460:       *ov++ = (insert_overhead + next_insert_cost) / 10;
        !           461:       insert_overhead -= pf1;
        !           462:     }
        !           463: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.