NeoMutt  2021-10-29-220-g2b1eec
Teaching an old dog new tricks
DOXYGEN
display.h File Reference

Pager Display. More...

#include "config.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "mutt/lib.h"
#include "lib.h"
+ Include dependency graph for display.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  TextSyntax
 Highlighting for a piece of text. More...
 
struct  AnsiAttr
 An ANSI escape sequence. More...
 
struct  Line
 A line of text in the pager. More...
 

Macros

#define ANSI_NO_FLAGS   0
 No flags are set. More...
 
#define ANSI_OFF   (1 << 0)
 Turn off colours and attributes. More...
 
#define ANSI_BLINK   (1 << 1)
 Blinking text. More...
 
#define ANSI_BOLD   (1 << 2)
 Bold text. More...
 
#define ANSI_UNDERLINE   (1 << 3)
 Underlined text. More...
 
#define ANSI_REVERSE   (1 << 4)
 Reverse video. More...
 
#define ANSI_COLOR   (1 << 5)
 Use colours. More...
 

Typedefs

typedef uint8_t AnsiFlags
 Flags, e.g. ANSI_OFF. More...
 

Functions

int display_line (FILE *fp, LOFF_T *last_pos, struct Line **lines, int n, int *last, int *max, PagerFlags flags, struct QuoteStyle **quote_list, int *q_level, bool *force_redraw, regex_t *search_re, struct MuttWindow *win_pager)
 Print a line on screen. More...
 

Detailed Description

Pager Display.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file display.h.

Macro Definition Documentation

◆ ANSI_NO_FLAGS

#define ANSI_NO_FLAGS   0

No flags are set.

Definition at line 37 of file display.h.

◆ ANSI_OFF

#define ANSI_OFF   (1 << 0)

Turn off colours and attributes.

Definition at line 38 of file display.h.

◆ ANSI_BLINK

#define ANSI_BLINK   (1 << 1)

Blinking text.

Definition at line 39 of file display.h.

◆ ANSI_BOLD

#define ANSI_BOLD   (1 << 2)

Bold text.

Definition at line 40 of file display.h.

◆ ANSI_UNDERLINE

#define ANSI_UNDERLINE   (1 << 3)

Underlined text.

Definition at line 41 of file display.h.

◆ ANSI_REVERSE

#define ANSI_REVERSE   (1 << 4)

Reverse video.

Definition at line 42 of file display.h.

◆ ANSI_COLOR

#define ANSI_COLOR   (1 << 5)

Use colours.

Definition at line 43 of file display.h.

Typedef Documentation

◆ AnsiFlags

typedef uint8_t AnsiFlags

Flags, e.g. ANSI_OFF.

Definition at line 36 of file display.h.

Function Documentation

◆ display_line()

int display_line ( FILE *  fp,
LOFF_T *  bytes_read,
struct Line **  lines,
int  line_num,
int *  lines_used,
int *  lines_max,
PagerFlags  flags,
struct QuoteStyle **  quote_list,
int *  q_level,
bool *  force_redraw,
regex_t *  search_re,
struct MuttWindow win_pager 
)

Print a line on screen.

Parameters
[in]fpFile to read from
[out]bytes_readOffset into file
[out]linesLine attributes
[in]line_numLine number
[out]lines_usedLast line
[out]lines_maxMaximum number of lines
[in]flagsFlags, see PagerFlags
[out]quote_listEmail quoting style
[out]q_levelLevel of quoting
[out]force_redrawForce a repaint
[out]search_reRegex to highlight
[in]win_pagerWindow to draw into
Return values
-1EOF was reached
0normal exit, line was not displayed
>0normal exit, line was displayed

Definition at line 1039 of file display.c.

1043 {
1044  unsigned char *buf = NULL, *fmt = NULL;
1045  size_t buflen = 0;
1046  unsigned char *buf_ptr = NULL;
1047  int ch, vch, col, cnt, b_read;
1048  int buf_ready = 0;
1049  bool change_last = false;
1050  int special;
1051  int offset;
1052  int def_color;
1053  int m;
1054  int rc = -1;
1055  struct AnsiAttr ansi = { 0, 0, 0, -1 };
1056  regmatch_t pmatch[1];
1057 
1058  if (line_num == *lines_used)
1059  {
1060  (*lines_used)++;
1061  change_last = true;
1062  }
1063 
1064  if (*lines_used == *lines_max)
1065  {
1066  mutt_mem_realloc(lines, sizeof(struct Line) * (*lines_max += LINES));
1067  for (ch = *lines_used; ch < *lines_max; ch++)
1068  {
1069  memset(&((*lines)[ch]), 0, sizeof(struct Line));
1070  (*lines)[ch].cid = -1;
1071  (*lines)[ch].search_arr_size = -1;
1072  (*lines)[ch].syntax = mutt_mem_malloc(sizeof(struct TextSyntax));
1073  ((*lines)[ch].syntax)[0].first = -1;
1074  ((*lines)[ch].syntax)[0].last = -1;
1075  }
1076  }
1077 
1078  struct Line *const curr_line = &(*lines)[line_num];
1079 
1080  if (flags & MUTT_PAGER_LOGS)
1081  {
1082  /* determine the line class */
1083  if (fill_buffer(fp, bytes_read, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1084  {
1085  if (change_last)
1086  (*lines_used)--;
1087  goto out;
1088  }
1089 
1090  curr_line->cid = MT_COLOR_MESSAGE_LOG;
1091  if (buf[11] == 'M')
1092  curr_line->syntax[0].color = MT_COLOR_MESSAGE;
1093  else if (buf[11] == 'W')
1094  curr_line->syntax[0].color = MT_COLOR_WARNING;
1095  else if (buf[11] == 'E')
1096  curr_line->syntax[0].color = MT_COLOR_ERROR;
1097  else
1098  curr_line->syntax[0].color = MT_COLOR_NORMAL;
1099  }
1100 
1101  /* only do color highlighting if we are viewing a message */
1102  if (flags & (MUTT_SHOWCOLOR | MUTT_TYPES))
1103  {
1104  if (curr_line->cid == -1)
1105  {
1106  /* determine the line class */
1107  if (fill_buffer(fp, bytes_read, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1108  {
1109  if (change_last)
1110  (*lines_used)--;
1111  goto out;
1112  }
1113 
1114  resolve_types(win_pager, (char *) fmt, (char *) buf, *lines, line_num, *lines_used,
1115  quote_list, q_level, force_redraw, flags & MUTT_SHOWCOLOR);
1116 
1117  /* avoid race condition for continuation lines when scrolling up */
1118  for (m = line_num + 1;
1119  m < *lines_used && (*lines)[m].offset && (*lines)[m].cont_line; m++)
1120  {
1121  (*lines)[m].cid = curr_line->cid;
1122  }
1123  }
1124 
1125  /* this also prevents searching through the hidden lines */
1126  const short c_toggle_quoted_show_levels =
1127  cs_subset_number(NeoMutt->sub, "toggle_quoted_show_levels");
1128  if ((flags & MUTT_HIDE) && (curr_line->cid == MT_COLOR_QUOTED) &&
1129  ((curr_line->quote == NULL) || (curr_line->quote->quote_n >= c_toggle_quoted_show_levels)))
1130  {
1131  flags = 0; /* MUTT_NOSHOW */
1132  }
1133  }
1134 
1135  /* At this point, (*lines[line_num]).quote may still be undefined. We
1136  * don't want to compute it every time MUTT_TYPES is set, since this
1137  * would slow down the "bottom" function unacceptably. A compromise
1138  * solution is hence to call regexec() again, just to find out the
1139  * length of the quote prefix. */
1140  if ((flags & MUTT_SHOWCOLOR) && !curr_line->cont_line &&
1141  (curr_line->cid == MT_COLOR_QUOTED) && !curr_line->quote)
1142  {
1143  if (fill_buffer(fp, bytes_read, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1144  {
1145  if (change_last)
1146  (*lines_used)--;
1147  goto out;
1148  }
1149 
1150  const struct Regex *c_quote_regex =
1151  cs_subset_regex(NeoMutt->sub, "quote_regex");
1152  if (mutt_regex_capture(c_quote_regex, (char *) fmt, 1, pmatch))
1153  {
1154  curr_line->quote =
1155  qstyle_classify(quote_list, (char *) fmt + pmatch[0].rm_so,
1156  pmatch[0].rm_eo - pmatch[0].rm_so, force_redraw, q_level);
1157  }
1158  else
1159  {
1160  goto out;
1161  }
1162  }
1163 
1164  if ((flags & MUTT_SEARCH) && !curr_line->cont_line && (curr_line->search_arr_size == -1))
1165  {
1166  if (fill_buffer(fp, bytes_read, curr_line->offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1167  {
1168  if (change_last)
1169  (*lines_used)--;
1170  goto out;
1171  }
1172 
1173  offset = 0;
1174  curr_line->search_arr_size = 0;
1175  while (regexec(search_re, (char *) fmt + offset, 1, pmatch,
1176  (offset ? REG_NOTBOL : 0)) == 0)
1177  {
1178  if (++(curr_line->search_arr_size) > 1)
1179  {
1180  mutt_mem_realloc(&(curr_line->search),
1181  (curr_line->search_arr_size) * sizeof(struct TextSyntax));
1182  }
1183  else
1184  curr_line->search = mutt_mem_malloc(sizeof(struct TextSyntax));
1185  pmatch[0].rm_so += offset;
1186  pmatch[0].rm_eo += offset;
1187  (curr_line->search)[curr_line->search_arr_size - 1].first = pmatch[0].rm_so;
1188  (curr_line->search)[curr_line->search_arr_size - 1].last = pmatch[0].rm_eo;
1189 
1190  if (pmatch[0].rm_eo == pmatch[0].rm_so)
1191  offset++; /* avoid degenerate cases */
1192  else
1193  offset = pmatch[0].rm_eo;
1194  if (!fmt[offset])
1195  break;
1196  }
1197  }
1198 
1199  if (!(flags & MUTT_SHOW) && ((*lines)[line_num + 1].offset > 0))
1200  {
1201  /* we've already scanned this line, so just exit */
1202  rc = 0;
1203  goto out;
1204  }
1205  if ((flags & MUTT_SHOWCOLOR) && *force_redraw && ((*lines)[line_num + 1].offset > 0))
1206  {
1207  /* no need to try to display this line... */
1208  rc = 1;
1209  goto out; /* fake display */
1210  }
1211 
1212  b_read = fill_buffer(fp, bytes_read, curr_line->offset, &buf, &fmt, &buflen, &buf_ready);
1213  if (b_read < 0)
1214  {
1215  if (change_last)
1216  (*lines_used)--;
1217  goto out;
1218  }
1219 
1220  /* now chose a good place to break the line */
1221  cnt = format_line(win_pager, lines, line_num, buf, flags, NULL, b_read, &ch,
1222  &vch, &col, &special, win_pager->state.cols);
1223  buf_ptr = buf + cnt;
1224 
1225  /* move the break point only if smart_wrap is set */
1226  const bool c_smart_wrap = cs_subset_bool(NeoMutt->sub, "smart_wrap");
1227  if (c_smart_wrap)
1228  {
1229  if ((cnt < b_read) && (ch != -1) &&
1230  !simple_color_is_header(curr_line->cid) && !IS_SPACE(buf[cnt]))
1231  {
1232  buf_ptr = buf + ch;
1233  /* skip trailing blanks */
1234  while (ch && ((buf[ch] == ' ') || (buf[ch] == '\t') || (buf[ch] == '\r')))
1235  ch--;
1236  /* A very long word with leading spaces causes infinite
1237  * wrapping when MUTT_PAGER_NSKIP is set. A folded header
1238  * with a single long word shouldn't be smartwrapped
1239  * either. So just disable smart_wrap if it would wrap at the
1240  * beginning of the line. */
1241  if (ch == 0)
1242  buf_ptr = buf + cnt;
1243  else
1244  cnt = ch + 1;
1245  }
1246  if (!(flags & MUTT_PAGER_NSKIP))
1247  {
1248  /* skip leading blanks on the next line too */
1249  while ((*buf_ptr == ' ') || (*buf_ptr == '\t'))
1250  buf_ptr++;
1251  }
1252  }
1253 
1254  if (*buf_ptr == '\r')
1255  buf_ptr++;
1256  if (*buf_ptr == '\n')
1257  buf_ptr++;
1258 
1259  if (((int) (buf_ptr - buf) < b_read) && !(*lines)[line_num + 1].cont_line)
1260  append_line(*lines, line_num, (int) (buf_ptr - buf));
1261  (*lines)[line_num + 1].offset = curr_line->offset + (long) (buf_ptr - buf);
1262 
1263  /* if we don't need to display the line we are done */
1264  if (!(flags & MUTT_SHOW))
1265  {
1266  rc = 0;
1267  goto out;
1268  }
1269 
1270  /* display the line */
1271  format_line(win_pager, lines, line_num, buf, flags, &ansi, cnt, &ch, &vch,
1272  &col, &special, win_pager->state.cols);
1273 
1274  /* avoid a bug in ncurses... */
1275  if (col == 0)
1276  {
1278  mutt_window_addch(win_pager, ' ');
1279  }
1280 
1281  /* end the last color pattern (needed by S-Lang) */
1282  if (special || ((col != win_pager->state.cols) && (flags & (MUTT_SHOWCOLOR | MUTT_SEARCH))))
1283  resolve_color(win_pager, *lines, line_num, vch, flags, 0, &ansi);
1284 
1285  /* Fill the blank space at the end of the line with the prevailing color.
1286  * ncurses does an implicit clrtoeol() when you do mutt_window_addch('\n') so we have
1287  * to make sure to reset the color *after* that */
1288  if (flags & MUTT_SHOWCOLOR)
1289  {
1290  m = (curr_line->cont_line) ? (curr_line->syntax)[0].first : line_num;
1291  if ((*lines)[m].cid == MT_COLOR_HEADER)
1292  def_color = ((*lines)[m].syntax)[0].color;
1293  else
1294  def_color = simple_color_get((*lines)[m].cid);
1295 
1296  mutt_curses_set_attr(def_color);
1297  }
1298 
1299  if (col < win_pager->state.cols)
1300  mutt_window_clrtoeol(win_pager);
1301 
1302  /* reset the color back to normal. This *must* come after the
1303  * clrtoeol, otherwise the color for this line will not be
1304  * filled to the right margin. */
1305  if (flags & MUTT_SHOWCOLOR)
1307 
1308  /* build a return code */
1309  if (!(flags & MUTT_SHOW))
1310  flags = 0;
1311 
1312  rc = flags;
1313 
1314 out:
1315  FREE(&buf);
1316  FREE(&fmt);
1317  return rc;
1318 }
bool simple_color_is_header(enum ColorId cid)
Colour is for an Email header.
Definition: simple.c:101
int simple_color_get(enum ColorId cid)
Get the colour of an object by its ID.
Definition: simple.c:68
@ MT_COLOR_MESSAGE
Informational message.
Definition: color.h:51
@ MT_COLOR_QUOTED
Pager: quoted text.
Definition: color.h:57
@ MT_COLOR_HEADER
Message headers (takes a pattern)
Definition: color.h:48
@ MT_COLOR_ERROR
Error message.
Definition: color.h:46
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:53
@ MT_COLOR_MESSAGE_LOG
Menu showing log messages.
Definition: color.h:52
@ MT_COLOR_WARNING
Warning messages.
Definition: color.h:74
static int fill_buffer(FILE *fp, LOFF_T *bytes_read, LOFF_T offset, unsigned char **buf, unsigned char **fmt, size_t *blen, int *buf_ready)
Fill a buffer from a file.
Definition: display.c:793
static void resolve_color(struct MuttWindow *win, struct Line *lines, int line_num, int cnt, PagerFlags flags, int special, struct AnsiAttr *ansi)
Set the colour for a line of text.
Definition: display.c:118
static void resolve_types(struct MuttWindow *win, char *buf, char *raw, struct Line *lines, int line_num, int lines_used, struct QuoteStyle **quote_list, int *q_level, bool *force_redraw, bool q_classify)
Determine the style for a line of text.
Definition: display.c:358
static int format_line(struct MuttWindow *win, struct Line **lines, int line_num, unsigned char *buf, PagerFlags flags, struct AnsiAttr *ansi, int cnt, int *pspace, int *pvch, int *pcol, int *pspecial, int width)
Display a line of text in the pager.
Definition: display.c:847
static void append_line(struct Line *lines, int line_num, int cnt)
Add a new Line to the array.
Definition: display.c:248
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:243
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define FREE(x)
Definition: memory.h:40
bool mutt_regex_capture(const struct Regex *regex, const char *str, size_t nmatch, regmatch_t matches[])
Match a regex against a string, with provided options.
Definition: regex.c:612
void mutt_curses_set_attr(int attr)
Set the attributes for text.
Definition: mutt_curses.c:39
void mutt_curses_set_color_by_id(enum ColorId cid)
Set the current colour for text.
Definition: mutt_curses.c:52
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:241
int mutt_window_addch(struct MuttWindow *win, int ch)
Write one character to a Window.
Definition: mutt_window.c:380
#define MUTT_PAGER_NSKIP
Preserve whitespace with smartwrap.
Definition: lib.h:68
#define MUTT_HIDE
Don't show quoted text.
Definition: lib.h:62
#define MUTT_TYPES
Compute line's type.
Definition: lib.h:64
#define MUTT_SHOWCOLOR
Show characters in color otherwise don't show characters.
Definition: lib.h:61
#define MUTT_PAGER_LOGS
Logview mode.
Definition: lib.h:73
#define MUTT_SEARCH
Resolve search patterns.
Definition: lib.h:63
#define MUTT_SHOW
Definition: lib.h:65
struct QuoteStyle * qstyle_classify(struct QuoteStyle **quote_list, const char *qptr, size_t length, bool *force_redraw, int *q_level)
Find a style for a string.
Definition: quoted.c:223
#define IS_SPACE(ch)
Definition: string2.h:38
An ANSI escape sequence.
Definition: display.h:60
A line of text in the pager.
Definition: display.h:71
short search_arr_size
Number of items in search array.
Definition: display.h:80
struct TextSyntax * search
Array of search text in the line.
Definition: display.h:81
bool cont_line
Continuation of a previous line (wrapped by NeoMutt)
Definition: display.h:74
short cid
Default line colour, e.g. MT_COLOR_QUOTED.
Definition: display.h:73
struct QuoteStyle * quote
Quoting style for this line (pointer into PagerPrivateData->quote_list)
Definition: display.h:83
LOFF_T offset
Offset into Email file (PagerPrivateData->fp)
Definition: display.h:72
struct TextSyntax * syntax
Array of coloured text in the line.
Definition: display.h:78
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
int quote_n
The quoteN colour index for this level.
Definition: quoted.h:67
Cached regular expression.
Definition: regex3.h:90
Highlighting for a piece of text.
Definition: display.h:50
int color
Curses colour of text.
Definition: display.h:51
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
+ Here is the call graph for this function:
+ Here is the caller graph for this function: