// Write "== " to mode line and return count. static int wupd_tab(int lchar) { vtputc(lchar); vtputc(lchar); vtputc(' '); return 3; }
// Update the current line to the virtual screen in given window. static void vupd_dotline(EWindow *winp) { Line *lnp; // Line to update. int sline; // Physical screen line to update. int i; // Search down to the line we want... lnp = winp->w_face.wf_toplnp; sline = winp->w_toprow; while(lnp != winp->w_face.wf_dot.lnp) { ++sline; lnp = lforw(lnp); } // and update the virtual line. vscreen[sline]->v_flags |= VFCHGD; taboff = winp->w_face.wf_fcol; vtmove(sline,-taboff); // Move each char of line to virtual screen until at end. for(i = 0; i < lused(lnp); ++i) vtputc(lgetc(lnp,i)); #if COLOR vscreen[sline]->v_rfcolor = winp->w_face.wf_fcolor; vscreen[sline]->v_rbcolor = winp->w_bcolor; #endif vteeol(); taboff = 0; }
// Write a string to the virtual screen. Return number of characters written. static int vtputs(char *strp) { int c; int count = 0; while((c = *strp++) != '\0') count += vtputc(c); return count; }
// Write a character to the virtual screen. The virtual row and column are updated. Return number of characters written. If // we are not yet at the left edge, don't write it. If the line is too long put a "$" in the last column. This routine only // (1), puts printing characters into the virtual terminal buffers; and (2), checks for column overflow. static int vtputc(int c) { Video *vp; // Pointer to line being updated. int vtcol0 = vtcol; // Defeat automatic sign extension. c &= 0xff; // Line receiving this character. vp = vscreen[vtrow]; if(vtcol >= (int) term.t_ncol) { // We are at the right edge! ++vtcol; vp->v_text[term.t_ncol - 1] = '$'; } else if(c == '\t') { // Output a hardware tab as the right number of spaces. do { vtputc(' '); } while(((vtcol + taboff) % (htabsize)) != 0); } else if(c < 0x20 || c == 0x7F) { // Control character. vtputc('^'); vtputc(c ^ 0x40); } else if(c > 0x7f && (modetab[MDR_GLOBAL].flags & MDESC8)) { char wkbuf[5],*strp = wkbuf; // Display character with high bit set symbolically. sprintf(wkbuf,"<%.2X>",c); do { vtputc(*strp++); } while(*strp != '\0'); } else { // It's normal, just put it in the screen map. if(vtcol >= 0) vp->v_text[vtcol] = c; ++vtcol; } return vtcol - vtcol0; }
static void show_line(struct line *lp) { int i = 0, len = llength(lp); while (i < len) { unicode_t c; i += utf8_to_unicode(lp->l_text, i, len, &c); vtputc(c); } }
/* * Write a character to the virtual screen. The virtual row and * column are updated. If we are not yet on left edge, don't print * it yet. If the line is too long put a "$" in the last column. * * This routine only puts printing characters into the virtual * terminal buffers. Only column overflow is checked. */ static void vtputc(int c) { struct video *vp; /* ptr to line being updated */ /* In case somebody passes us a signed char.. */ if (c < 0) { c += 256; if (c < 0) return; } vp = vscreen[vtrow]; if (vtcol >= term.t_ncol) { ++vtcol; vp->v_text[term.t_ncol - 1] = '$'; return; } if (c == '\t') { do { vtputc(' '); } while (((vtcol + taboff) & tabmask) != 0); return; } if (c < 0x20) { vtputc('^'); vtputc(c ^ 0x40); return; } if (c == 0x7f) { vtputc('^'); vtputc('?'); return; } if (c >= 0x80 && c <= 0xA0) { static const char hex[] = "0123456789abcdef"; vtputc('\\'); vtputc(hex[c >> 4]); vtputc(hex[c & 15]); return; } if (vtcol >= 0) vp->v_text[vtcol] = c; ++vtcol; }
// Transfer all lines in given window to virtual screen. static void vupd_all(EWindow *winp) { Line *lnp; // Line to update. int sline; // Physical screen line to update. int i; int nlines; // Number of lines in the current window. // Search down the lines, updating them. lnp = winp->w_face.wf_toplnp; sline = winp->w_toprow; nlines = winp->w_nrows; taboff = winp->w_face.wf_fcol; while(sline < winp->w_toprow + nlines) { // Update the virtual line. vscreen[sline]->v_flags |= VFCHGD; vscreen[sline]->v_left = FARRIGHT; vscreen[sline]->v_right = 0; vtmove(sline,-taboff); // If we are not at the end... if(lnp != winp->w_bufp->b_hdrlnp) { for(i = 0; i < lused(lnp); ++i) vtputc(lgetc(lnp,i)); lnp = lforw(lnp); } // Make sure we are on screen. if(vtcol < 0) vtcol = 0; // On to the next line. #if COLOR vscreen[sline]->v_rfcolor = winp->w_face.wf_fcolor; vscreen[sline]->v_rbcolor = winp->w_bcolor; #endif vteeol(); ++sline; } taboff = 0; }
// De-extend any line in any window that needs it. static void supd_dex(void) { EWindow *winp; Line *lnp; int i,j; int nlines; // Number of lines in the current window. winp = wheadp; do { lnp = winp->w_face.wf_toplnp; i = winp->w_toprow; nlines = winp->w_nrows; while(i < winp->w_toprow + nlines) { if(vscreen[i]->v_flags & VFEXT) { if(winp != curwp || lnp != winp->w_face.wf_dot.lnp || curcol < (int) term.t_ncol - 1) { if(lnp == winp->w_bufp->b_hdrlnp) vtmove(i,0); else { taboff = winp->w_face.wf_fcol; vtmove(i,-taboff); for(j = 0; j < lused(lnp); ++j) vtputc(lgetc(lnp,j)); taboff = 0; } vteeol(); // This line is no longer extended. vscreen[i]->v_flags &= ~VFEXT; vscreen[i]->v_flags |= VFCHGD; } } if(lnp != winp->w_bufp->b_hdrlnp) lnp = lforw(lnp); ++i; } // Onward to the next window. } while((winp = winp->w_nextp) != NULL); }
// Update the extended line which the cursor is currently on at a column greater than the terminal width. The line will be // scrolled right or left to let the user see where the cursor is. static void vupd_ext(void) { int rcursor; // Real cursor location. Line *lnp; // Pointer to current line. int j; // Index into line. // Calculate what column the real cursor will end up in. rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin; // 10% width <= rcursor < 90% lbound = curcol - rcursor + 1; taboff = lbound + curwp->w_face.wf_fcol; // Write the current line to the virtual screen. vtmove(currow,-taboff); // Start scanning offscreen. lnp = curwp->w_face.wf_dot.lnp; // Line to output. for(j = 0; j < lused(lnp); ++j) // Until the end-of-line. vtputc(lgetc(lnp,j)); // Truncate the virtual line, restore tab offset. vteeol(); taboff = 0; // and put a '$' in column 1. vscreen[currow]->v_text[0] = '$'; }
// Redisplay the mode line for the window pointed to by winp. If popbuf is NULL, display a fully-formatted mode line containing // the current buffer's name and filename (but in condensed form if the current terminal width is less than 96 columns); // otherwise, display only the buffer name and filename of buffer "popbuf". This is the only routine that has any idea of how // the mode line is formatted. You can change the mode line format by hacking at this routine. Called by "update" any time // there is a dirty window. void wupd_modeline(EWindow *winp,Buffer *popbuf) { int c; int n; // Cursor position. Buffer *bufp; ModeSpec *msp; int lchar; int condensed = term.t_ncol < 80 ? -1 : term.t_ncol < 96 ? 1 : 0; char wkbuf[32]; // Work buffer. static struct { // Mode display parameters. int leadch,trailch; uint flags; } *mdp,md[] = { {'(',')',0}, {'[',']',0}, {-1,-1,0}}; n = winp->w_toprow + winp->w_nrows; // Row location. // Note that we assume that setting REVERSE will cause the terminal driver to draw with the inverted relationship of // fcolor and bcolor, so that when we say to set the foreground color to "white" and background color to "black", the // fact that "reverse" is enabled means that the terminal driver actually draws "black" on a background of "white". // Makes sense, no? This way, devices for which the color controls are optional will still get the "reverse" signals. vscreen[n]->v_left = 0; vscreen[n]->v_right = term.t_ncol; #if COLOR vscreen[n]->v_flags |= VFCHGD | VFCOLOR; // Redraw next time. vscreen[n]->v_rfcolor = 7; // Black on. vscreen[n]->v_rbcolor = 0; // White... #else vscreen[n]->v_flags |= VFCHGD; // Redraw next time. #endif vtmove(n,0); // Seek to right line. if(winp == curwp) // Make the current buffer stand out. lchar = '='; #if REVSTA else if(opflags & OPHAVEREV) lchar = ' '; #endif else lchar = '-'; // Full display? if(popbuf == NULL) { bufp = winp->w_bufp; vtputc((bufp->b_flags & BFTRUNC) ? '#' : lchar); // "#" if truncated. vtputc((bufp->b_flags & BFCHGD) ? '*' : lchar); // "*" if changed. vtputc((bufp->b_flags & BFNARROW) ? '<' : lchar); // "<" if narrowed. vtputc(' '); n = 4; // Display program name and version. if(!condensed) { sprintf(wkbuf,"%s %s ",Myself,Version); n += vtputs(wkbuf); } // Are we horizontally scrolled? if(winp->w_face.wf_fcol > 0) { sprintf(wkbuf,"[<%d] ",winp->w_face.wf_fcol); n += vtputs(wkbuf); } // Display the screen number if bottom window and there's more than one screen. if(winp->w_nextp == NULL && scrcount() > 1) { sprintf(wkbuf,"S%hu ",cursp->s_num); n += vtputs(wkbuf); } // Display keyboard macro recording state. if(kmacro.km_state == KMRECORD) n += vtputs("*R* "); // Display the line and/or column point position if enabled and winp is current window. if(winp == curwp) { if(curbp->b_modes & MDLINE) { sprintf(wkbuf,"L:%ld ",getlinenum(bufp,winp->w_face.wf_dot.lnp)); n += vtputs(wkbuf); } if(curbp->b_modes & MDCOL) { sprintf(wkbuf,"C:%d ",getccol()); n += vtputs(wkbuf); } } // Display the modes, in short form if condensed display. md[0].flags = modetab[MDR_GLOBAL].flags & modetab[MDR_SHOW].flags; md[1].flags = winp->w_bufp->b_modes; mdp = md; do { msp = ((c = mdp->leadch) == '[') ? bmodeinfo : gmodeinfo; do { if(mdp->flags & msp->mask) { n += vtputc(c); c = ' '; if(condensed >= 0) n += vtputs(msp->mlname); else { n += vtputc(msp->mlname[0]); if(msp->mlname[1] != '\0') n += vtputc(msp->mlname[1]); } } } while((++msp)->name != NULL); if(c != mdp->leadch) { n += vtputc(mdp->trailch); n += vtputc(' '); } } while((++mdp)->leadch > 0); #if 0 // Display internal modes on modeline. vtputc(lchar); vtputc((winp->w_flags & WFCOLOR) ? 'C' : lchar); vtputc((winp->w_flags & WFMODE) ? 'M' : lchar); vtputc((winp->w_flags & WFHARD) ? 'H' : lchar); vtputc((winp->w_flags & WFEDIT) ? 'E' : lchar); vtputc((winp->w_flags & WFMOVE) ? 'V' : lchar); vtputc((winp->w_flags & WFFORCE) ? 'F' : lchar); vtputc(lchar); n += 8; #endif n += wupd_tab(lchar); } else { n = 0; bufp = popbuf; vtputc(lchar); n += wupd_tab(lchar) + 1; } // Display the buffer name. n += vtputs(bufp->b_bname) + 1; vtputc(' '); // Display the filename in the remaining space using strfit(). if(bufp->b_fname != NULL) { char wkbuf[TT_MAXCOLS]; n += wupd_tab(lchar); if(condensed < 0) { vtputc(*text34); // "File: " vtputc(':'); vtputc(' '); n += 3; } else n += vtputs(text34); // "File: " n += vtputs(strfit(wkbuf,term.t_ncol - n - 1,bufp->b_fname,0)) + 1; vtputc(' '); } // If it's the current window, not a pop-up, "pwd" mode, and room still available, display the working directory as // well. if(winp == curwp && popbuf == NULL && (modetab[MDR_GLOBAL].flags & MDWKDIR) && ((int) term.t_ncol - n) > 12) { char *wdp; char wkbuf[TT_MAXCOLS]; n += wupd_tab(lchar); n += vtputs(text274); // "WD: " (void) getwkdir(&wdp,false); n += vtputs(strfit(wkbuf,term.t_ncol - n - 1,wdp,0)) + 1; vtputc(' '); } // Pad to full width. while(n < (int) term.t_ncol) { vtputc(lchar); ++n; } }
// Display a pop-up window and page it for the user. If altmodeline is true, display buffer name and filename (only) on bottom // mode line. If endprompt is true, wait for user to press a key before returning (regardless of page size). Current bindings // (if any) for backPage, forwPage, backLine, and forwLine commands are recognized as well as 'b' (backward page), 'f' or space // (forward page), 'u' (backward half page), 'd' (forward half page), 'g' (goto first page), 'G' (goto last page), ESC or 'q' // (exit), and '?' (help). Any non-navigation key gets pushed back into the input stream to be interpeted later as a command. // Return status. int bpop(Buffer *bufp,bool altmodeline,bool endprompt) { Line *lnp1,*lnp,*lpmax; int crow; // Current screen row number. int disprows; // Total number of display rows. int halfpage; // Rows in a half page. int n; // Rows to move. ushort ek; // Input extended key. char *strp,*strpz; // Line text pointers. char *hprompt = NULL; // Help prompt; bool firstpass = true; // Display special mode line if requested. if(altmodeline) { // Find last window on screen and rewrite its mode line. wupd_modeline(wnextis(NULL),bufp); } // Set up and display a pop-up "window". disprows = term.t_nrow - 2; // Check if buffer will fit on one page and if not, set lpmax to first line of last page. lpmax = NULL; n = 0; for(lnp = lforw(bufp->b_hdrlnp); lnp != bufp->b_hdrlnp; lnp = lforw(lnp)) { if(++n > disprows) { // Find beginning of last page. lpmax = bufp->b_hdrlnp; n = disprows; do { lpmax = lback(lpmax); } while(--n > 0); break; } } // Begin at the beginning. lnp1 = lforw(bufp->b_hdrlnp); halfpage = disprows / 2; n = 0; // Display a page (beginning at line lnp1 + n) and prompt for a naviagtion command. Loop until exit key entered or // endprompt is false and buffer fits on one page (lpmax is NULL). for(;;) { lnp = lnp1; // Moving backward? if(n < 0) { do { // At beginning of buffer? if(lpmax == NULL || lnp1 == lforw(bufp->b_hdrlnp)) break; // No, back up one line. lnp1 = lback(lnp1); } while(++n < 0); } // Moving forward? else if(n > 0) { do { // At end of buffer or max line? if(lpmax == NULL || lnp1 == bufp->b_hdrlnp || lnp1 == lpmax) break; // No, move forward one line. lnp1 = lforw(lnp1); } while(--n > 0); } // Illegal command? if(n != 0 && lnp1 == lnp) // Yes, ignore it. n = 0; else { // Found first row ... display page. lnp = lnp1; crow = 0; do { // At end of buffer? if(lnp == bufp->b_hdrlnp) { // Yes, erase remaining lines on physical screen. while(crow < disprows) { vtmove(crow,0); vteeol(); #if COLOR vscreen[crow]->v_rfcolor = gfcolor; vscreen[crow]->v_rbcolor = gbcolor; #endif vscreen[crow]->v_left = FARRIGHT; vscreen[crow]->v_right = 0; #if COLOR vscreen[crow++]->v_flags |= VFCHGD | VFCOLOR; #else vscreen[crow++]->v_flags |= VFCHGD; #endif } break; } // Update the virtual screen image for this line. Characters past right edge of screen won't be // displayed, so ignore those. vtmove(crow,0); strpz = (strp = ltext(lnp)) + (lused(lnp) <= (int) term.t_ncol ? lused(lnp) : term.t_ncol); while(strp < strpz) vtputc(*strp++); vteeol(); #if COLOR vscreen[crow]->v_rfcolor = gfcolor; vscreen[crow]->v_rbcolor = gbcolor; #endif vscreen[crow]->v_left = FARRIGHT; vscreen[crow]->v_right = 0; #if COLOR vscreen[crow++]->v_flags |= VFCHGD | VFCOLOR; #else vscreen[crow++]->v_flags |= VFCHGD; #endif // On to the next line. lnp = lforw(lnp); } while(crow < disprows); // Screen is full. Copy the virtual screen to the physical screen. if(pupd_all(false) != SUCCESS) return rc.status; // Bail out if called from terminp() and one-page buffer. if(firstpass && !endprompt && lpmax == NULL) goto uexit; firstpass = false; } // Display prompt. mlputs(MLHOME | MLFORCE,hprompt != NULL ? hprompt : lpmax == NULL || lnp1 == lpmax ? text201 : ": "); // "End: " if(TTflush() != SUCCESS) return rc.status; // Get response. for(;;) { // Get a keystroke and decode it. if(getkey(&ek) != SUCCESS) return rc.status; // Exit? if(ek == (CTRL | '[') || ek == 'q') goto uexit; // Forward whole page? if(ek == ' ' || ek == 'f' || iscmd(ek,forwPage)) { n = disprows - overlap; break; } // Forward half page? if(ek == 'd') { n = halfpage; break; } // Backward whole page? if(ek == 'b' || iscmd(ek,backPage)) { n = overlap - disprows; break; } // Backward half page? if(ek == 'u') { n = -halfpage; break; } // Forward a line? if(iscmd(ek,forwLine)) { n = 1; break; } // Backward a line? if(iscmd(ek,backLine)) { n = -1; break; } // First page? if(ek == 'g') { if(lpmax == NULL || lnp1 == lforw(bufp->b_hdrlnp)) n = -1; // Force beep. else { lnp1 = lforw(bufp->b_hdrlnp); n = 0; } break; } // Last page? if(ek == 'G') { if(lpmax == NULL || lnp1 == lpmax) n = 1; // Force beep. else { lnp1 = lpmax; n = 0; } break; } // Help? if(ek == '?') { StrList msg; // Get string list... if(vopen(&msg,NULL,false) != 0) return vrcset(); // build prompt... if(vputs(text202,&msg) != 0) // "(<SPC>,f" return vrcset(); if(hkey(&msg,forwPage,0) != SUCCESS) return rc.status; if(vputs(text203,&msg) != 0) // ") +page (b" return vrcset(); if(hkey(&msg,backPage,0) != SUCCESS) return rc.status; if(vputs(text204,&msg) != 0) // ") -page (d) +half (u) -half" return vrcset(); if(hkey(&msg,forwLine,'+') != SUCCESS || hkey(&msg,backLine,'-') != SUCCESS) return rc.status; if(vputs(text206,&msg) != 0) // " (g) first (G) last (ESC,q) quit (?) help: " return vrcset(); // and display it. if(vclose(&msg) != 0) return vrcset(); mlputs(MLHOME | MLFORCE,msg.sl_vp->v_strp); } else { // Other key. "Unget" the key for reprocessing and return. tungetc(ek); goto uexit; } } } uexit: uphard(); if(endprompt) mlerase(MLFORCE); return rc.status; }