📄 pager.c
字号:
break; } /* is anything left to do? */ if (ch >= cnt) break; k = mbrtowc (&wc, (char *)buf+ch, cnt-ch, &mbstate); if (k == -2 || k == -1) { dprint (1, (debugfile, "%s:%d: mbrtowc returned %d; errno = %d.\n", __FILE__, __LINE__, k, errno)); if (col + 4 > wrap_cols) break; col += 4; if (pa) printw ("\\%03o", buf[ch]); k = 1; continue; } if (k == 0) k = 1; /* Handle backspace */ special = 0; if (IsWPrint (wc)) { wchar_t wc1; mbstate_t mbstate1; int k1, k2; while ((wc1 = 0, mbstate1 = mbstate, k1 = k + mbrtowc (&wc1, (char *)buf+ch+k, cnt-ch-k, &mbstate1), k1 - k > 0 && wc1 == '\b') && (wc1 = 0, k2 = mbrtowc (&wc1, (char *)buf+ch+k1, cnt-ch-k1, &mbstate1), k2 > 0 && IsWPrint (wc1))) { if (wc == wc1) { special |= (wc == '_' && special & A_UNDERLINE) ? A_UNDERLINE : A_BOLD; } else if (wc == '_' || wc1 == '_') { special |= A_UNDERLINE; wc = (wc1 == '_') ? wc : wc1; } else { /* special = 0; / * overstrike: nothing to do! */ wc = wc1; } ch += k1; k = k2; mbstate = mbstate1; } } if (pa && ((flags & (M_SHOWCOLOR | M_SEARCH | M_PAGER_MARKER)) || special || last_special || pa->attr)) { resolve_color (*lineInfo, n, vch, flags, special, pa); last_special = special; } if (IsWPrint (wc)) { if (wc == ' ') space = ch; t = wcwidth (wc); if (col + t > wrap_cols) break; col += t; if (pa) mutt_addwch (wc); } else if (wc == '\n') break; else if (wc == '\t') { space = ch; t = (col & ~7) + 8; if (t > wrap_cols) break; if (pa) for (; col < t; col++) addch (' '); else col = t; } else if (wc < 0x20 || wc == 0x7f) { if (col + 2 > wrap_cols) break; col += 2; if (pa) printw ("^%c", ('@' + wc) & 0x7f); } else if (wc < 0x100) { if (col + 4 > wrap_cols) break; col += 4; if (pa) printw ("\\%03o", wc); } else { if (col + 1 > wrap_cols) break; ++col; if (pa) addch (replacement_char ()); } } *pspace = space; *pcol = col; *pvch = vch; *pspecial = special; return ch;}/* * Args: * flags M_SHOWFLAT, show characters (used for displaying help) * M_SHOWCOLOR, show characters in color * otherwise don't show characters * M_HIDE, don't show quoted text * M_SEARCH, resolve search patterns * M_TYPES, compute line's type * M_PAGER_NSKIP, keeps leading whitespace * M_PAGER_MARKER, eventually show markers * * Return values: * -1 EOF was reached * 0 normal exit, line was not displayed * >0 normal exit, line was displayed */static intdisplay_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n, int *last, int *max, int flags, struct q_class_t **QuoteList, int *q_level, int *force_redraw, regex_t *SearchRE){ unsigned char buf[LONG_STRING], fmt[LONG_STRING]; unsigned char *buf_ptr = buf; int ch, vch, col, cnt, b_read; int buf_ready = 0, change_last = 0; int special; int offset; int def_color; int m; ansi_attr a = {0,0,0,-1}; regmatch_t pmatch[1]; if (n == *last) { (*last)++; change_last = 1; } if (*last == *max) { safe_realloc (lineInfo, sizeof (struct line_t) * (*max += LINES)); for (ch = *last; ch < *max ; ch++) { memset (&((*lineInfo)[ch]), 0, sizeof (struct line_t)); (*lineInfo)[ch].type = -1; (*lineInfo)[ch].search_cnt = -1; (*lineInfo)[ch].syntax = safe_malloc (sizeof (struct syntax_t)); ((*lineInfo)[ch].syntax)[0].first = ((*lineInfo)[ch].syntax)[0].last = -1; } } /* only do color hiliting if we are viewing a message */ if (flags & (M_SHOWCOLOR | M_TYPES)) { if ((*lineInfo)[n].type == -1) { /* determine the line class */ if (fill_buffer (f, last_pos, (*lineInfo)[n].offset, buf, fmt, sizeof (buf), &buf_ready) < 0) { if (change_last) (*last)--; return (-1); } resolve_types ((char *) fmt, (char *) buf, *lineInfo, n, *last, QuoteList, q_level, force_redraw, flags & M_SHOWCOLOR); /* avoid race condition for continuation lines when scrolling up */ for (m = n + 1; m < *last && (*lineInfo)[m].offset && (*lineInfo)[m].continuation; m++) (*lineInfo)[m].type = (*lineInfo)[n].type; } /* this also prevents searching through the hidden lines */ if ((flags & M_HIDE) && (*lineInfo)[n].type == MT_COLOR_QUOTED) flags = 0; /* M_NOSHOW */ } /* At this point, (*lineInfo[n]).quote may still be undefined. We * don't want to compute it every time M_TYPES is set, since this * would slow down the "bottom" function unacceptably. A compromise * solution is hence to call regexec() again, just to find out the * length of the quote prefix. */ if ((flags & M_SHOWCOLOR) && !(*lineInfo)[n].continuation && (*lineInfo)[n].type == MT_COLOR_QUOTED && (*lineInfo)[n].quote == NULL) { if (fill_buffer (f, last_pos, (*lineInfo)[n].offset, buf, fmt, sizeof (buf), &buf_ready) < 0) { if (change_last) (*last)--; return (-1); } regexec ((regex_t *) QuoteRegexp.rx, (char *) fmt, 1, pmatch, 0); (*lineInfo)[n].quote = classify_quote (QuoteList, (char *) fmt + pmatch[0].rm_so, pmatch[0].rm_eo - pmatch[0].rm_so, force_redraw, q_level); } if ((flags & M_SEARCH) && !(*lineInfo)[n].continuation && (*lineInfo)[n].search_cnt == -1) { if (fill_buffer (f, last_pos, (*lineInfo)[n].offset, buf, fmt, sizeof (buf), &buf_ready) < 0) { if (change_last) (*last)--; return (-1); } offset = 0; (*lineInfo)[n].search_cnt = 0; while (regexec (SearchRE, (char *) fmt + offset, 1, pmatch, (offset ? REG_NOTBOL : 0)) == 0) { if (++((*lineInfo)[n].search_cnt) > 1) safe_realloc (&((*lineInfo)[n].search), ((*lineInfo)[n].search_cnt) * sizeof (struct syntax_t)); else (*lineInfo)[n].search = safe_malloc (sizeof (struct syntax_t)); pmatch[0].rm_so += offset; pmatch[0].rm_eo += offset; ((*lineInfo)[n].search)[(*lineInfo)[n].search_cnt - 1].first = pmatch[0].rm_so; ((*lineInfo)[n].search)[(*lineInfo)[n].search_cnt - 1].last = pmatch[0].rm_eo; if (pmatch[0].rm_eo == pmatch[0].rm_so) offset++; /* avoid degenerate cases */ else offset = pmatch[0].rm_eo; if (!fmt[offset]) break; } } if (!(flags & M_SHOW) && (*lineInfo)[n+1].offset > 0) { /* we've already scanned this line, so just exit */ return (0); } if ((flags & M_SHOWCOLOR) && *force_redraw && (*lineInfo)[n+1].offset > 0) { /* no need to try to display this line... */ return (1); /* fake display */ } if ((b_read = fill_buffer (f, last_pos, (*lineInfo)[n].offset, buf, fmt, sizeof (buf), &buf_ready)) < 0) { if (change_last) (*last)--; return (-1); } /* now chose a good place to break the line */ cnt = format_line (lineInfo, n, buf, flags, 0, b_read, &ch, &vch, &col, &special); buf_ptr = buf + cnt; /* move the break point only if smart_wrap is set */ if (option (OPTWRAP)) { if (cnt < b_read) { if (ch != -1 && buf[cnt] != ' ' && buf[cnt] != '\t' && buf[cnt] != '\n' && buf[cnt] != '\r') { buf_ptr = buf + ch; /* skip trailing blanks */ while (ch && (buf[ch] == ' ' || buf[ch] == '\t' || buf[ch] == '\r')) ch--; /* a very long word with leading spaces causes infinite wrapping */ if ((!ch) && (flags & M_PAGER_NSKIP)) buf_ptr = buf + cnt; else cnt = ch + 1; } else buf_ptr = buf + cnt; /* a very long word... */ } if (!(flags & M_PAGER_NSKIP)) /* skip leading blanks on the next line too */ while (*buf_ptr == ' ' || *buf_ptr == '\t') buf_ptr++; } if (*buf_ptr == '\r') buf_ptr++; if (*buf_ptr == '\n') buf_ptr++; if ((int) (buf_ptr - buf) < b_read && !(*lineInfo)[n+1].continuation) append_line (*lineInfo, n, (int) (buf_ptr - buf)); (*lineInfo)[n+1].offset = (*lineInfo)[n].offset + (long) (buf_ptr - buf); /* if we don't need to display the line we are done */ if (!(flags & M_SHOW)) return 0; /* display the line */ format_line (lineInfo, n, buf, flags, &a, cnt, &ch, &vch, &col, &special); /* avoid a bug in ncurses... */#ifndef USE_SLANG_CURSES if (col == 0) { SETCOLOR (MT_COLOR_NORMAL); addch (' '); }#endif /* end the last color pattern (needed by S-Lang) */ if (special || (col != COLS && (flags & (M_SHOWCOLOR | M_SEARCH)))) resolve_color (*lineInfo, n, vch, flags, 0, &a); /* * Fill the blank space at the end of the line with the prevailing color. * ncurses does an implicit clrtoeol() when you do addch('\n') so we have * to make sure to reset the color *after* that */ if (flags & M_SHOWCOLOR) { m = ((*lineInfo)[n].continuation) ? ((*lineInfo)[n].syntax)[0].first : n; if ((*lineInfo)[m].type == MT_COLOR_HEADER) def_color = ((*lineInfo)[m].syntax)[0].color; else def_color = ColorDefs[ (*lineInfo)[m].type ]; attrset (def_color);#ifdef HAVE_BKGDSET bkgdset (def_color | ' ');#endif } /* ncurses always wraps lines when you get to the right side of the * screen, but S-Lang seems to only wrap if the next character is *not* * a newline (grr!). */#ifndef USE_SLANG_CURSES if (col < COLS)#endif addch ('\n'); /* * reset the color back to normal. This *must* come after the * addch('\n'), otherwise the color for this line will not be * filled to the right margin. */ if (flags & M_SHOWCOLOR) { SETCOLOR(MT_COLOR_NORMAL); BKGDSET(MT_COLOR_NORMAL); } /* build a return code */ if (!(flags & M_SHOW)) flags = 0; return (flags);}static intupNLines (int nlines, struct line_t *info, int cur, int hiding){ while (cur > 0 && nlines > 0) { cur--; if (!hiding || info[cur].type != MT_COLOR_QUOTED) nlines--; } return cur;}static struct mapping_t PagerHelp[] = { { N_("Exit"), OP_EXIT }, { N_("PrevPg"), OP_PREV_PAGE }, { N_("NextPg"), OP_NEXT_PAGE }, { NULL, 0 }};static struct mapping_t PagerHelpExtra[] = { { N_("View Attachm."), OP_VIEW_ATTACHMENTS }, { N_("Del"), OP_DELETE }, { N_("Reply"), OP_REPLY }, { N_("Next"), OP_MAIN_NEXT_UNDELETED }, { NULL, 0 }};/* This pager is actually not so simple as it once was. It now operates in two modes: one for viewing messages and the other for viewing help. These can be distinguished by whether or not ``hdr'' is NULL. The ``hdr'' arg is there so that we can do operations on the current message without the need to pop back out to the main-menu. */int mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra){ static char searchbuf[STRING]; char buffer[LONG_STRING]; char helpstr[SHORT_STRING*2]; char tmphelp[SHORT_STRING*2]; int maxLine, lastLine = 0; struct line_t *lineInfo; struct q_class_t *QuoteList = NULL; int i, j, ch = 0, rc = -1, hideQuoted = 0, q_level = 0, force_redraw = 0; int lines = 0, curline = 0, topline = 0, oldtopline = 0, err, first = 1; int r = -1; int redraw = REDRAW_FULL; FILE *fp = NULL; LOFF_T last_pos = 0, last_offset = 0; int old_smart_wrap, old_markers; struct stat sb; regex_t SearchRE; int SearchCompiled = 0, SearchFlag = 0, SearchBack = 0; int has_types = (IsHeader(extra) || (flags & M_SHOWCOLOR)) ? M_TYPES : 0; /* main message or rfc822 attachment */ int bodyoffset = 1; /* offset of first line of real text */ int statusoffset = 0; /* offset for the status bar */ int helpoffset = LINES - 2; /* offset for the help bar. */ int bodylen = LINES - 2 - bodyoffset; /* length of displayable area */ MUTTMENU *index = NULL; /* the Pager Index (PI) */ int indexoffset = 0; /* offset for the PI */ int indexlen = PagerIndexLines; /* indexlen not always == PIL */ int indicator = indexlen / 3; /* the indicator line of the PI */ int old_PagerIndexLines; /* some people want to resize it * while inside the pager... */ if (!(flags & M_SHOWCOLOR)) flags |= M_SHOWFLAT; if ((fp = fopen (fname, "r")) == NULL) { mutt_perror (fname); return (-1); } if (stat (fname, &sb) != 0) { mutt_perror (fname); fclose (fp); return (-1); } unlink (fname); /* Initialize variables */ if (IsHeader (extra) && !extra->hdr->read) { Context->msgnotreadyet = extra->hdr->msgno; mutt_set_flag (Context, extra->hdr, M_READ, 1); } lineInfo = safe_malloc (sizeof (struct line_t) * (maxLine = LINES)); for (i = 0 ; i < maxLine ; i++) { memset (&lineInfo[i], 0, sizeof (struct line_t)); lineInfo[i].type = -1; lineInfo[i].search_cnt = -1; lineInfo[i].syntax = safe_malloc (sizeof (struct syntax_t)); (lineInfo[i].syntax)[0].first = (lineInfo[i].syntax)[0].last = -1; } mutt_compile_help (helpstr, sizeof (helpstr), MENU_PAGER, PagerHelp); if (IsHeader (extra)) { strfcpy (tmphelp, helpstr, sizeof (tmphelp)); mutt_compile_help (buffer, sizeof (buffer), MENU_PAGER, PagerHelpExtra); snprintf (helpstr, sizeof (helpstr), "%s %s", tmphelp, buffer); } if (!InHelp) { strfcpy (tmphelp, helpstr, sizeof (tmphelp)); mutt_make_help (buffer, sizeof (buffer), _("Help"), MENU_PAGER, OP_HELP); snprintf (helpstr, sizeof (helpstr), "%s %s", tmphelp, buffer); } while (ch != -1) { mutt_curs_set (0);#ifdef USE_IMAP imap_keepalive ();#endif if (redraw & REDRAW_FULL) { SETCOLOR (MT_COLOR_NORMAL); /* clear() doesn't optimize screen redraws */ move (0, 0); clrtobot (); if (IsHeader (extra) && Context->vcount + 1 < PagerIndexLines) indexlen = Context->vcount + 1; else indexlen = PagerIndexLines; indicator = indexlen / 3; if (option (OPTSTATUSONTOP)) { indexoffset = 0; statusoffset = IsHeader (extra) ? indexlen : 0; bodyoffset = statusoffset + 1; helpoffset = LINES - 2; bodylen = helpoffset - bodyoffset; if (!option (OPTHELP)) bodylen++; } else { helpoffset = 0; indexoffset = 1; statusoffset = LINES - 2; if (!option (OPTHELP)) indexoffset = 0; bodyoffset = indexoffset + (IsHeader (extra) ? indexlen : 0); bodylen = statusoffset - bodyoffset; } if (option (OPTHELP)) { SETCOLOR (MT_COLOR_STATUS); move (helpoffset, 0); mutt_paddstr (COLS, helpstr); SETCOLOR (MT_COLOR_NORMAL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -