📄 svi_smap.c
字号:
!O_ISSET(sp, O_LEFTRIGHT) && tmp.off > svi_opt_screens(sp, ep, tmp.lno, NULL)) { v_eof(sp, ep, NULL); return (1); } } /* * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b. * * If it's a small screen, and the movement is small, open up the * screen. Otherwise, compress and repaint. If we compress, we * ignore the cursor, the movement is too large to care. */ if (ISSMALLSCREEN(sp)) if (count <= HALFTEXT(sp)) { for (; count && sp->t_rows != sp->t_maxrows; --count, ++sp->t_rows) { if (svi_sm_next(sp, ep, TMAP, &tmp)) return (1); if (TMAP->lno != tmp.lno && !file_gline(sp, ep, tmp.lno, NULL)) break; *++TMAP = tmp; /* svi_sm_next() flushed the cache. */ if (svi_line(sp, ep, TMAP, NULL, NULL)) return (1); } if (count == 0) return (0); } else { MOVE(sp, INFOLINE(sp), 0); clrtoeol(); for (; sp->t_rows > sp->t_minrows; --sp->t_rows, --TMAP) { MOVE(sp, TMAP - HMAP, 0); clrtoeol(); } ignore_cursor = 1; } for (; count; --count) { /* Decide what would show up on the screen. */ if (svi_sm_next(sp, ep, TMAP, &tmp)) return (1); /* If the line doesn't exist, we're done. */ if (TMAP->lno != tmp.lno && !file_gline(sp, ep, tmp.lno, NULL)) break; /* Scroll the screen cursor up one logical line. */ if (svi_sm_1up(sp, ep)) return (1); if (!cursor_move && !ignore_cursor && p > HMAP) --p; } /* If ignoring the cursor, we're done. */ if (ignore_cursor) return (0); if (cursor_move) { /* * If we didn't move enough, head toward EOF. Check to make * sure the lines actually, if the file is smaller than the * screen they may not. */ for (; count; --count, ++p) if (p == TMAP || !file_gline(sp, ep, p[1].lno, NULL)) break; } else { /* * If the line itself moved, invalidate the cursor, because * the comparison with the old line/new line won't be right */ F_SET(SVP(sp), SVI_CUR_INVALID); /* If didn't move enough, it's an error. */ if (count) { v_eof(sp, ep, NULL); return (1); } /* If the cursor moved off the screen, move it to the top. */ if (sp->lno < HMAP->lno) p = HMAP; } /* * On a logical movement, we try and keep the cursor as close as * possible to the last position, but also set it up so that the * next "real" movement will return the cursor to the closest position * to the last real movement. */ if (p->lno != svmap.lno || p->off != svmap.off) { rp->lno = p->lno; rp->cno = svi_cm_private(sp, ep, p->lno, p->off, sp->rcm); } return (0);}/* * svi_sm_1up -- * Scroll the SMAP up one. */intsvi_sm_1up(sp, ep) SCR *sp; EXF *ep;{ /* * Delete the top line of the screen. Shift the screen map up. * Display a new line at the bottom of the screen. */ MOVE(sp, 0, 0); if (svi_deleteln(sp, 1)) return (1); /* One-line screens can fail. */ if (HMAP == TMAP) { if (svi_sm_next(sp, ep, TMAP, TMAP)) return (1); } else { memmove(HMAP, HMAP + 1, (sp->rows - 1) * sizeof(SMAP)); if (svi_sm_next(sp, ep, TMAP - 1, TMAP)) return (1); } /* svi_sm_next() flushed the cache. */ if (svi_line(sp, ep, TMAP, NULL, NULL)) return (1); return (0);}/* * svi_deleteln -- * Delete a line a la curses, make sure to put the information * line and other screens back. */static intsvi_deleteln(sp, cnt) SCR *sp; int cnt;{ size_t oldy, oldx; getyx(stdscr, oldy, oldx); while (cnt--) { deleteln(); MOVE(sp, INFOLINE(sp) - 1, 0); insertln(); MOVEA(sp, oldy, oldx); } return (0);}/* * svi_sm_down -- * Scroll the SMAP down count logical lines. */intsvi_sm_down(sp, ep, rp, count, cursor_move) SCR *sp; EXF *ep; MARK *rp; recno_t count; int cursor_move;{ SMAP *p, svmap; int ignore_cursor; /* Set the default return position. */ rp->lno = sp->lno; rp->cno = sp->cno; /* * Invalidate the cursor. The line is probably going to change, * but if cursor_move isn't set it may not. In any case, this * routine moves the cursor to draw things. */ F_SET(SVP(sp), SVI_CUR_INVALID); /* * There are two forms of this command, one where the cursor tries to * follow the line, and one where it doesn't. In the latter, we try * and keep the cursor at the same position on the screen, but, if the * screen is small enough and the line length large enough, the cursor * can end up in very strange places. Probably not worth fixing. * * Find the line in the SMAP -- ignore the cursor if it wasn't on the * screen. */ if (svi_sm_cursor(sp, ep, &p)) return (1); if (p == NULL) ignore_cursor = 1; else { svmap = *p; ignore_cursor = 0; } /* Check to see if movement is possible. */ if (HMAP->lno == 1 && HMAP->off == 1 && (!cursor_move || ignore_cursor || p == HMAP)) { v_sof(sp, NULL); return (1); } /* * Small screens: see svi/svi_refresh.c:svi_refresh, section 3b. * * If it's a small screen, and the movement is small, open up the * screen. Otherwise, compress and repaint. If we compress, we * ignore the cursor, the movement is too large to care. */ if (ISSMALLSCREEN(sp)) if (count <= HALFTEXT(sp)) { for (; count && sp->t_rows != sp->t_maxrows && (HMAP->lno > 1 || HMAP->off > 1); --count, ++sp->t_rows) { ++TMAP; if (svi_sm_1down(sp, ep)) return (1); if (!cursor_move) ++p; } if (count == 0) return (0); } else { MOVE(sp, INFOLINE(sp), 0); clrtoeol(); for (; sp->t_rows > sp->t_minrows; --sp->t_rows, --TMAP) { MOVE(sp, TMAP - HMAP, 0); clrtoeol(); } ignore_cursor = 1; } for (; count; --count) { /* If the line doesn't exist, we're done. */ if (HMAP->lno == 1 && HMAP->off == 1) break; /* Scroll the screen and cursor down one logical line. */ if (svi_sm_1down(sp, ep)) return (1); if (!cursor_move && !ignore_cursor && p < TMAP) ++p; } /* If ignoring the cursor, we're done. */ if (ignore_cursor) return (0); if (cursor_move) { /* If we didn't move enough, move to SOF. */ if (count) p = HMAP; } else { /* * If the line itself moved, invalidate the cursor, because * the comparison with the old line/new line won't be right. */ F_SET(SVP(sp), SVI_CUR_INVALID); /* If didn't move enough, it's an error. */ if (count) { v_sof(sp, NULL); return (1); } /* If the cursor moved off the screen, move it to the bottom. */ if (sp->lno > TMAP->lno) p = TMAP; } /* * On a logical movement, we try and keep the cursor as close as * possible to the last position, but also set it up so that the * next "real" movement will return the cursor to the closest position * to the last real movement. */ if (p->lno != svmap.lno || p->off != svmap.off) { rp->lno = p->lno; rp->cno = svi_cm_private(sp, ep, p->lno, p->off, sp->rcm); } return (0);}/* * svi_sm_1down -- * Scroll the SMAP down one. */intsvi_sm_1down(sp, ep) SCR *sp; EXF *ep;{ /* * Clear the bottom line of the screen, insert a line at the top * of the screen. Shift the screen map down, display a new line * at the top of the screen. */ MOVE(sp, sp->t_rows, 0); clrtoeol(); MOVE(sp, 0, 0); if (svi_insertln(sp, 1)) return (1); memmove(HMAP + 1, HMAP, (sp->rows - 1) * sizeof(SMAP)); if (svi_sm_prev(sp, ep, HMAP + 1, HMAP)) return (1); /* svi_sm_prev() flushed the cache. */ if (svi_line(sp, ep, HMAP, NULL, NULL)) return (1); return (0);}/* * svi_insertln -- * Insert a line a la curses, make sure to put the information * line and other screens back. */static intsvi_insertln(sp, cnt) SCR *sp; int cnt;{ size_t oldy, oldx; getyx(stdscr, oldy, oldx); while (cnt--) { MOVE(sp, INFOLINE(sp) - 1, 0); deleteln(); MOVEA(sp, oldy, oldx); insertln(); } return (0);}/* * svi_sm_next -- * Fill in the next entry in the SMAP. */intsvi_sm_next(sp, ep, p, t) SCR *sp; EXF *ep; SMAP *p, *t;{ size_t lcnt; SMAP_FLUSH(t); if (O_ISSET(sp, O_LEFTRIGHT)) { t->lno = p->lno + 1; t->off = p->off; } else { lcnt = svi_opt_screens(sp, ep, p->lno, NULL); if (lcnt == p->off) { t->lno = p->lno + 1; t->off = 1; } else { t->lno = p->lno; t->off = p->off + 1; } } return (0);}/* * svi_sm_prev -- * Fill in the previous entry in the SMAP. */intsvi_sm_prev(sp, ep, p, t) SCR *sp; EXF *ep; SMAP *p, *t;{ SMAP_FLUSH(t); if (O_ISSET(sp, O_LEFTRIGHT)) { t->lno = p->lno - 1; t->off = p->off; } else if (p->off != 1) { t->lno = p->lno; t->off = p->off - 1; } else { t->lno = p->lno - 1; t->off = svi_opt_screens(sp, ep, t->lno, NULL); } return (t->lno == 0);}/* * svi_sm_cursor -- * Return the SMAP entry referenced by the cursor. */intsvi_sm_cursor(sp, ep, smp) SCR *sp; EXF *ep; SMAP **smp;{ SMAP *p; /* See if the cursor is not in the map. */ if (sp->lno < HMAP->lno || sp->lno > TMAP->lno) { *smp = NULL; return (0); } /* Find the first occurence of the line. */ for (p = HMAP; p->lno != sp->lno; ++p); /* Fill in the map information until we find the right line. */ for (; p <= TMAP; ++p) { /* Short lines are common and easy to detect. */ if (p != TMAP && (p + 1)->lno != p->lno) { *smp = p; return (0); } if (!SMAP_CACHE(p) && svi_line(sp, ep, p, NULL, NULL)) return (1); if (p->c_eboff >= sp->cno) { *smp = p; return (0); } } /* It was past the end of the map after all. */ *smp = NULL; return (0);}/* * svi_sm_position -- * Return the line/column of the top, middle or last line on the screen. * (The vi H, M and L commands.) Here because only the screen routines * know what's really out there. */intsvi_sm_position(sp, ep, rp, cnt, pos) SCR *sp; EXF *ep; MARK *rp; u_long cnt; enum position pos;{ SMAP *smp; recno_t last; switch (pos) { case P_TOP: /* * !!! * Historically, an invalid count to the H command failed. * We do nothing special here, just making sure that H in * an empty screen works. */ if (cnt > TMAP - HMAP) goto sof; smp = HMAP + cnt; if (cnt && file_gline(sp, ep, smp->lno, NULL) == NULL) {sof: msgq(sp, M_BERR, "Movement past the end-of-screen."); return (1); } break; case P_MIDDLE: /* * !!! * Historically, a count to the M command was ignored. * If the screen isn't filled, find the middle of what's * real and move there. */ if (file_gline(sp, ep, TMAP->lno, NULL) == NULL) { if (file_lline(sp, ep, &last)) return (1); for (smp = TMAP; smp->lno > last && smp > HMAP; --smp); if (smp > HMAP) smp -= (smp - HMAP) / 2; } else smp = (HMAP + (TMAP - HMAP) / 2) + cnt; break; case P_BOTTOM: /* * !!! * Historically, an invalid count to the L command failed. * If the screen isn't filled, find the bottom of what's * real and try to offset from there. */ if (cnt > TMAP - HMAP) goto eof; smp = TMAP - cnt; if (file_gline(sp, ep, smp->lno, NULL) == NULL) { if (file_lline(sp, ep, &last)) return (1); for (; smp->lno > last && smp > HMAP; --smp); if (cnt > smp - HMAP) {eof: msgq(sp, M_BERR, "Movement past the beginning-of-screen."); return (1); } smp -= cnt; } break; default: abort(); } /* Make sure that the cached information is valid. */ if (!SMAP_CACHE(smp) && svi_line(sp, ep, smp, NULL, NULL)) return (1); rp->lno = smp->lno; rp->cno = smp->c_sboff; return (0);}/* * svi_sm_nlines -- * Return the number of screen lines from an SMAP entry to the * start of some file line, less than a maximum value. */recno_tsvi_sm_nlines(sp, ep, from_sp, to_lno, max) SCR *sp; EXF *ep; SMAP *from_sp; recno_t to_lno; size_t max;{ recno_t lno, lcnt; if (O_ISSET(sp, O_LEFTRIGHT)) return (from_sp->lno > to_lno ? from_sp->lno - to_lno : to_lno - from_sp->lno); if (from_sp->lno == to_lno) return (from_sp->off - 1); if (from_sp->lno > to_lno) { lcnt = from_sp->off - 1; /* Correct for off-by-one. */ for (lno = from_sp->lno; --lno >= to_lno && lcnt <= max;) lcnt += svi_opt_screens(sp, ep, lno, NULL); } else { lno = from_sp->lno; lcnt = (svi_opt_screens(sp, ep, lno, NULL) - from_sp->off) + 1; for (; ++lno < to_lno && lcnt <= max;) lcnt += svi_opt_screens(sp, ep, lno, NULL); } return (lcnt);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -