X-Git-Url: https://git.llucax.com/software/mutt-debian.git/blobdiff_plain/14c29200cb58d3c4a0830265f2433849781858d0..5f2a574d6c8989bc7f90612704e3e5f255b5cb58:/pager.c diff --git a/pager.c b/pager.c index c88b5d4..e19174c 100644 --- a/pager.c +++ b/pager.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1996-2002 Michael R. Elkins + * Copyright (C) 1996-2002,2007 Michael R. Elkins * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,17 +26,10 @@ #include "keymap.h" #include "mutt_menu.h" #include "mapping.h" -#include "sort.h" #include "pager.h" #include "attach.h" #include "mbyte.h" -#include "mx.h" - -#ifdef USE_IMAP -#include "imap_private.h" -#endif - #include "mutt_crypt.h" #include @@ -117,6 +110,7 @@ struct line_t struct syntax_t *syntax; struct syntax_t *search; struct q_class_t *quote; + unsigned int is_cont_hdr; /* this line is a continuation of the previous header line */ }; #define ANSI_OFF (1<<0) @@ -719,27 +713,51 @@ resolve_types (char *buf, char *raw, struct line_t *lineInfo, int n, int last, if (n == 0 || ISHEADER (lineInfo[n-1].type)) { - if (buf[0] == '\n') { + if (buf[0] == '\n') /* end of header */ + { lineInfo[n].type = MT_COLOR_NORMAL; getyx(stdscr, brailleLine, brailleCol); - } else if (n > 0 && (buf[0] == ' ' || buf[0] == '\t')) - { - lineInfo[n].type = lineInfo[n-1].type; /* wrapped line */ - (lineInfo[n].syntax)[0].color = (lineInfo[n-1].syntax)[0].color; } else { - lineInfo[n].type = MT_COLOR_HDEFAULT; - color_line = ColorHdrList; - while (color_line) + /* if this is a continuation of the previous line, use the previous + * line's color as default. */ + if (n > 0 && (buf[0] == ' ' || buf[0] == '\t')) + { + lineInfo[n].type = lineInfo[n-1].type; /* wrapped line */ + (lineInfo[n].syntax)[0].color = (lineInfo[n-1].syntax)[0].color; + lineInfo[n].is_cont_hdr = 1; + } + else + { + lineInfo[n].type = MT_COLOR_HDEFAULT; + } + + for (color_line = ColorHdrList; color_line; color_line = color_line->next) { if (REGEXEC (color_line->rx, buf) == 0) { lineInfo[n].type = MT_COLOR_HEADER; lineInfo[n].syntax[0].color = color_line->pair; + if (lineInfo[n].is_cont_hdr) + { + /* adjust the previous continuation lines to reflect the color of this continuation line */ + int j; + for (j = n - 1; j >= 0 && lineInfo[j].is_cont_hdr; --j) + { + lineInfo[j].type = lineInfo[n].type; + lineInfo[j].syntax[0].color = lineInfo[n].syntax[0].color; + } + /* now adjust the first line of this header field */ + if (j >= 0) + { + lineInfo[j].type = lineInfo[n].type; + lineInfo[j].syntax[0].color = lineInfo[n].syntax[0].color; + } + *force_redraw = 1; /* the previous lines have already been drawn on the screen */ + } break; } - color_line = color_line->next; } } } @@ -819,8 +837,14 @@ resolve_types (char *buf, char *raw, struct line_t *lineInfo, int n, int last, if (lineInfo[n].type == MT_COLOR_NORMAL || lineInfo[n].type == MT_COLOR_QUOTED) { - i = 0; + size_t nl; + + /* don't consider line endings part of the buffer + * for regex matching */ + if ((nl = mutt_strlen (buf)) > 0 && buf[nl-1] == '\n') + buf[nl-1] = 0; + i = 0; offset = 0; lineInfo[n].chunks = 0; do @@ -870,6 +894,8 @@ resolve_types (char *buf, char *raw, struct line_t *lineInfo, int n, int last, else offset = (lineInfo[n].syntax)[i].last; } while (found || null_rx); + if (nl > 0) + buf[nl] = '\n'; } } @@ -995,18 +1021,18 @@ trim_incomplete_mbyte(unsigned char *buf, size_t len) } static int -fill_buffer (FILE *f, LOFF_T *last_pos, LOFF_T offset, unsigned char *buf, - unsigned char *fmt, size_t blen, int *buf_ready) +fill_buffer (FILE *f, LOFF_T *last_pos, LOFF_T offset, unsigned char **buf, + unsigned char **fmt, size_t *blen, int *buf_ready) { - unsigned char *p; + unsigned char *p, *q; static int b_read; - + int l; + if (*buf_ready == 0) { - buf[blen - 1] = 0; if (offset != *last_pos) fseeko (f, offset, 0); - if (fgets ((char *) buf, blen - 1, f) == NULL) + if ((*buf = (unsigned char *) mutt_read_line ((char *) *buf, blen, f, &l, M_EOL)) == NULL) { fmt[0] = 0; return (-1); @@ -1015,26 +1041,29 @@ fill_buffer (FILE *f, LOFF_T *last_pos, LOFF_T offset, unsigned char *buf, b_read = (int) (*last_pos - offset); *buf_ready = 1; + safe_realloc (fmt, *blen); + /* incomplete mbyte characters trigger a segfault in regex processing for * certain versions of glibc. Trim them if necessary. */ - if (b_read == blen - 2) - b_read -= trim_incomplete_mbyte(buf, b_read); + if (b_read == *blen - 2) + b_read -= trim_incomplete_mbyte(*buf, b_read); /* copy "buf" to "fmt", but without bold and underline controls */ - p = buf; + p = *buf; + q = *fmt; while (*p) { - if (*p == '\010' && (p > buf)) + if (*p == '\010' && (p > *buf)) { if (*(p+1) == '_') /* underline */ p += 2; - else if (*(p+1)) /* bold or overstrike */ + else if (*(p+1) && q > *fmt) /* bold or overstrike */ { - *(fmt-1) = *(p+1); + *(q-1) = *(p+1); p += 2; } else /* ^H */ - *fmt++ = *p++; + *q++ = *p++; } else if (*p == '\033' && *(p+1) == '[' && is_ansi (p + 2)) { @@ -1048,9 +1077,9 @@ fill_buffer (FILE *f, LOFF_T *last_pos, LOFF_T offset, unsigned char *buf, ; } else - *fmt++ = *p++; + *q++ = *p++; } - *fmt = 0; + *q = 0; } return b_read; } @@ -1065,9 +1094,11 @@ static int format_line (struct line_t **lineInfo, int n, unsigned char *buf, int ch, vch, k, last_special = -1, special = 0, t; wchar_t wc; mbstate_t mbstate; - int wrap_cols = mutt_term_width ((flags & M_PAGER_NOWRAP) ? 0 : Wrap); - + + if (check_attachment_marker ((char *)buf) == 0) + wrap_cols = COLS; + /* FIXME: this should come from lineInfo */ memset(&mbstate, 0, sizeof(mbstate)); @@ -1106,6 +1137,12 @@ static int format_line (struct line_t **lineInfo, int n, unsigned char *buf, if (k == 0) k = 1; + if (Charset_is_utf8 && (wc == 0x200B || wc == 0xFEFF)) + { + dprint (3, (debugfile, "skip zero-width character U+%04X\n", (unsigned short)wc)); + continue; + } + /* Handle backspace */ special = 0; if (IsWPrint (wc)) @@ -1229,7 +1266,8 @@ display_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 = NULL, *fmt = NULL; + size_t buflen = 0; unsigned char *buf_ptr = buf; int ch, vch, col, cnt, b_read; int buf_ready = 0, change_last = 0; @@ -1237,6 +1275,7 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n, int offset; int def_color; int m; + int rc = -1; ansi_attr a = {0,0,0,-1}; regmatch_t pmatch[1]; @@ -1265,11 +1304,11 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n, 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 (fill_buffer (f, last_pos, (*lineInfo)[n].offset, &buf, &fmt, &buflen, &buf_ready) < 0) { if (change_last) (*last)--; - return (-1); + goto out; } resolve_types ((char *) fmt, (char *) buf, *lineInfo, n, *last, @@ -1294,11 +1333,11 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n, 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 (fill_buffer (f, last_pos, (*lineInfo)[n].offset, &buf, &fmt, &buflen, &buf_ready) < 0) { if (change_last) (*last)--; - return (-1); + goto out; } regexec ((regex_t *) QuoteRegexp.rx, (char *) fmt, 1, pmatch, 0); (*lineInfo)[n].quote = classify_quote (QuoteList, @@ -1309,11 +1348,11 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n, 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 (fill_buffer (f, last_pos, (*lineInfo)[n].offset, &buf, &fmt, &buflen, &buf_ready) < 0) { if (change_last) (*last)--; - return (-1); + goto out; } offset = 0; @@ -1342,20 +1381,22 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n, if (!(flags & M_SHOW) && (*lineInfo)[n+1].offset > 0) { /* we've already scanned this line, so just exit */ - return (0); + rc = 0; + goto out; } if ((flags & M_SHOWCOLOR) && *force_redraw && (*lineInfo)[n+1].offset > 0) { /* no need to try to display this line... */ - return (1); /* fake display */ + rc = 1; + goto out; /* fake display */ } - if ((b_read = fill_buffer (f, last_pos, (*lineInfo)[n].offset, buf, fmt, - sizeof (buf), &buf_ready)) < 0) + if ((b_read = fill_buffer (f, last_pos, (*lineInfo)[n].offset, &buf, &fmt, + &buflen, &buf_ready)) < 0) { if (change_last) (*last)--; - return (-1); + goto out; } /* now chose a good place to break the line */ @@ -1367,7 +1408,8 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n, { if (cnt < b_read) { - if (ch != -1 && buf[cnt] != ' ' && buf[cnt] != '\t' && buf[cnt] != '\n' && buf[cnt] != '\r') + if (ch != -1 && buf[0] != ' ' && buf[0] != '\t' && + buf[cnt] != ' ' && buf[cnt] != '\t' && buf[cnt] != '\n' && buf[cnt] != '\r') { buf_ptr = buf + ch; /* skip trailing blanks */ @@ -1399,7 +1441,10 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n, /* if we don't need to display the line we are done */ if (!(flags & M_SHOW)) - return 0; + { + rc = 0; + goto out; + } /* display the line */ format_line (lineInfo, n, buf, flags, &a, cnt, &ch, &vch, &col, &special); @@ -1460,7 +1505,12 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n, if (!(flags & M_SHOW)) flags = 0; - return (flags); + rc = flags; + +out: + FREE(&buf); + FREE(&fmt); + return rc; } static int @@ -1500,7 +1550,7 @@ static struct mapping_t PagerHelpExtra[] = { int mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra) { - static char searchbuf[STRING]; + static char searchbuf[STRING] = ""; char buffer[LONG_STRING]; char helpstr[SHORT_STRING*2]; char tmphelp[SHORT_STRING*2]; @@ -1509,7 +1559,7 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra) 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 r = -1, wrapped = 0, searchctx = 0; int redraw = REDRAW_FULL; FILE *fp = NULL; LOFF_T last_pos = 0, last_offset = 0; @@ -1543,7 +1593,7 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra) if (stat (fname, &sb) != 0) { mutt_perror (fname); - fclose (fp); + safe_fclose (&fp); return (-1); } unlink (fname); @@ -1584,10 +1634,6 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra) { mutt_curs_set (0); -#ifdef USE_IMAP - imap_keepalive (); -#endif - if (redraw & REDRAW_FULL) { SETCOLOR (MT_COLOR_NORMAL); @@ -1654,8 +1700,7 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra) { /* only allocate the space if/when we need the index. Initialise the menu as per the main index */ - index = mutt_new_menu(); - index->menu = MENU_MAIN; + index = mutt_new_menu(MENU_MAIN); index->make_entry = index_make_entry; index->color = index_color; index->max = Context->vcount; @@ -1750,21 +1795,21 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra) SETCOLOR (MT_COLOR_STATUS); BKGDSET (MT_COLOR_STATUS); CLEARLINE (statusoffset); - if (IsHeader (extra)) + + if (IsHeader (extra) || IsMsgAttach (extra)) { size_t l1 = COLS * MB_LEN_MAX; size_t l2 = sizeof (buffer); - hfi.hdr = extra->hdr; + hfi.hdr = (IsHeader (extra)) ? extra->hdr : extra->bdy->hdr; mutt_make_string_info (buffer, l1 < l2 ? l1 : l2, NONULL (PagerFmt), &hfi, M_FORMAT_MAKEPRINT); + mutt_paddstr (COLS, buffer); } - else if (IsMsgAttach (extra)) + else { - size_t l1 = COLS * MB_LEN_MAX; - size_t l2 = sizeof (buffer); - hfi.hdr = extra->bdy->hdr; - mutt_make_string_info (buffer, l1 < l2 ? l1 : l2, NONULL (PagerFmt), &hfi, M_FORMAT_MAKEPRINT); + char bn[STRING]; + snprintf (bn, sizeof (bn), "%s (%s)", banner, pager_progress_str); + mutt_paddstr (COLS, bn); } - mutt_paddstr (COLS, IsHeader (extra) || IsMsgAttach (extra) ? buffer : banner); BKGDSET (MT_COLOR_NORMAL); SETCOLOR (MT_COLOR_NORMAL); } @@ -1969,12 +2014,19 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra) case OP_SEARCH_OPPOSITE: if (SearchCompiled) { + wrapped = 0; + + if (SearchContext > 0 && SearchContext < LINES - 2 - option (OPTHELP) ? 1 : 0) + searchctx = SearchContext; + else + searchctx = 0; + search_next: if ((!SearchBack && ch==OP_SEARCH_NEXT) || (SearchBack &&ch==OP_SEARCH_OPPOSITE)) { /* searching forward */ - for (i = topline + 1; i < lastLine; i++) + for (i = wrapped ? 0 : topline + searchctx + 1; i < lastLine; i++) { if ((!hideQuoted || lineInfo[i].type != MT_COLOR_QUOTED) && !lineInfo[i].continuation && lineInfo[i].search_cnt > 0) @@ -1983,13 +2035,19 @@ search_next: if (i < lastLine) topline = i; - else + else if (wrapped || !option (OPTWRAPSEARCH)) mutt_error _("Not found."); + else + { + mutt_message _("Search wrapped to top."); + wrapped = 1; + goto search_next; + } } else { /* searching backward */ - for (i = topline - 1; i >= 0; i--) + for (i = wrapped ? lastLine : topline + searchctx - 1; i >= 0; i--) { if ((!hideQuoted || (has_types && lineInfo[i].type != MT_COLOR_QUOTED)) && @@ -1999,12 +2057,23 @@ search_next: if (i >= 0) topline = i; - else + else if (wrapped || !option (OPTWRAPSEARCH)) mutt_error _("Not found."); + else + { + mutt_message _("Search wrapped to bottom."); + wrapped = 1; + goto search_next; + } } if (lineInfo[topline].search_cnt > 0) + { SearchFlag = M_SEARCH; + /* give some context for search results */ + if (topline - searchctx > 0) + topline -= searchctx; + } break; } @@ -2013,9 +2082,10 @@ search_next: case OP_SEARCH: case OP_SEARCH_REVERSE: strfcpy (buffer, searchbuf, sizeof (buffer)); - if (mutt_get_field ((SearchBack ? _("Reverse search: ") : - _("Search: ")), buffer, sizeof (buffer), - M_CLEAR) != 0) + if (mutt_get_field ((ch == OP_SEARCH || ch == OP_SEARCH_NEXT) ? + _("Search for: ") : _("Reverse search for: "), + buffer, sizeof (buffer), + M_CLEAR) != 0) break; if (!strcmp (buffer, searchbuf)) @@ -2028,6 +2098,7 @@ search_next: else ch = OP_SEARCH_OPPOSITE; + wrapped = 0; goto search_next; } } @@ -2058,7 +2129,6 @@ search_next: { regerror (err, &SearchRE, buffer, sizeof (buffer)); mutt_error ("%s", buffer); - regfree (&SearchRE); for (i = 0; i < maxLine ; i++) { /* cleanup */ @@ -2111,7 +2181,17 @@ search_next: mutt_error _("Not found."); } else + { SearchFlag = M_SEARCH; + /* give some context for search results */ + if (SearchContext > 0 && SearchContext < LINES - 2 - option (OPTHELP) ? 1 : 0) + searchctx = SearchContext; + else + searchctx = 0; + if (topline - searchctx > 0) + topline -= searchctx; + } + } redraw = REDRAW_BODY; break; @@ -2272,6 +2352,20 @@ search_next: } break; + case OP_MAIN_SET_FLAG: + case OP_MAIN_CLEAR_FLAG: + CHECK_MODE(IsHeader (extra)); + CHECK_READONLY; + + if (mutt_change_flag (extra->hdr, (ch == OP_MAIN_SET_FLAG)) == 0) + redraw |= REDRAW_STATUS | REDRAW_INDEX; + if (extra->hdr->deleted && option (OPTRESOLVE)) + { + ch = -1; + rc = OP_MAIN_NEXT_UNDELETED; + } + break; + case OP_DELETE_THREAD: case OP_DELETE_SUBTHREAD: CHECK_MODE(IsHeader (extra)); @@ -2658,13 +2752,17 @@ search_next: redraw = REDRAW_FULL; break; + case OP_WHAT_KEY: + mutt_what_key (); + break; + default: ch = -1; break; } } - fclose (fp); + safe_fclose (&fp); if (IsHeader (extra)) { Context->msgnotreadyet = -1;