55 const unsigned int NUM_SIG_LINES = 4;
56 unsigned int count = 0;
58 while ((offset > 0) && (count <= NUM_SIG_LINES))
69 if (count > NUM_SIG_LINES)
95 const int *cnt = (
const int *) m1;
98 if (*cnt < stx->
first)
100 if (*cnt >= stx->
last)
120 static struct AttrColor last_color = { 0 };
128 last_color.
attrs = 0;
131 if (lines[line_num].cont_line)
134 if (!cnt && c_markers)
180 matching_chunk = bsearch(&cnt, lines[m].syntax, lines[m].syntax_arr_size,
182 if (matching_chunk && (cnt >= matching_chunk->
first) &&
183 (cnt < matching_chunk->last))
190 if ((flags &
MUTT_SEARCH) && lines[m].search_arr_size)
192 matching_chunk = bsearch(&cnt, lines[m].
search, lines[m].search_arr_size,
194 if (matching_chunk && (cnt >= matching_chunk->
first) &&
195 (cnt < matching_chunk->last))
203 if (special & A_BOLD)
208 color.
attrs |= A_BOLD;
210 else if (special & A_UNDERLINE)
215 color.
attrs |= A_UNDERLINE;
217 else if (special & A_ITALIC)
222 color.
attrs |= A_ITALIC;
248 lines[line_num + 1].
cid = lines[line_num].
cid;
249 (lines[line_num + 1].
syntax)[0].attr_color = (lines[line_num].syntax)[0].attr_color;
253 for (m = line_num; m >= 0; m--)
254 if (lines[m].cont_line == 0)
257 (lines[line_num + 1].
syntax)[0].first = m;
258 (lines[line_num + 1].
syntax)[0].last = (lines[line_num].cont_line) ?
259 cnt + (lines[line_num].
syntax)[0].last :
271 for (; (p[0] == q[0]) && (q[0] !=
'\0') && (p[0] !=
'\0') && (q[0] !=
'\a') &&
277 return (
int) (*p - *q);
311 bool is_quote =
false;
313 regmatch_t pmatch_internal[1], smatch[1];
316 pmatch = pmatch_internal;
323 if (smatch[0].rm_so > 0)
325 char c = line[smatch[0].rm_so];
326 line[smatch[0].rm_so] = 0;
331 line[smatch[0].rm_so] = c;
355 struct Line *lines,
int line_num,
int lines_used,
357 bool *force_redraw,
bool q_classify)
360 struct RegexColorList *head = NULL;
361 regmatch_t pmatch[1];
379 if ((line_num > 0) && ((buf[0] ==
' ') || (buf[0] ==
'\t')))
381 lines[line_num].
cid = lines[line_num - 1].
cid;
382 if (!c_header_color_partial)
384 (lines[line_num].
syntax)[0].attr_color =
385 (lines[line_num - 1].syntax)[0].attr_color;
397 if (!c_header_color_partial)
401 if (regexec(&color_line->
regex, buf, 0, NULL, 0) == 0)
408 lines[line_num].syntax[0].attr_color, &color_line->
attr_color);
409 if (lines[line_num].cont_header)
413 for (j = line_num - 1; j >= 0 && lines[j].
cont_header; --j)
415 lines[j].
cid = lines[line_num].
cid;
421 lines[j].
cid = lines[line_num].
cid;
424 *force_redraw =
true;
440 while ((i < lines_used) && (
check_sig(buf, lines, i - 1) == 0) &&
445 if (lines[i].syntax_arr_size)
453 else if (
check_sig(buf, lines, line_num - 1) == 0)
458 if (q_classify && (lines[line_num].quote == NULL))
461 pmatch[0].rm_eo - pmatch[0].rm_so,
462 force_redraw, q_level);
478 if ((nl > 0) && (buf[nl - 1] ==
'\n'))
509 if ((regexec(&color_line->
regex, buf + offset, 1, pmatch,
510 ((offset != 0) ? REG_NOTBOL : 0)) != 0))
519 if (pmatch[0].rm_eo == pmatch[0].rm_so)
528 if (lines[line_num].syntax_arr_size == SHRT_MAX)
533 if (++(lines[line_num].syntax_arr_size) > 1)
536 (lines[line_num].syntax_arr_size) *
sizeof(
struct TextSyntax));
540 memset(ts, 0,
sizeof(*ts));
544 pmatch[0].rm_so += offset;
545 pmatch[0].rm_eo += offset;
547 if (!found || (pmatch[0].rm_so < (lines[line_num].syntax)[i].
first) ||
548 ((pmatch[0].rm_so == (lines[line_num].syntax)[i].
first) &&
549 (pmatch[0].rm_eo > (lines[line_num].syntax)[i].
last)))
552 (lines[line_num].
syntax)[i].first = pmatch[0].rm_so;
553 (lines[line_num].
syntax)[i].
last = pmatch[0].rm_eo;
555 else if ((pmatch[0].rm_so == (lines[line_num].syntax)[i].first) &&
556 (pmatch[0].rm_eo == (lines[line_num].syntax)[i].last))
559 (lines[line_num].syntax)[i].attr_color, &color_line->
attr_color);
560 (lines[line_num].
syntax)[i].
first = pmatch[0].rm_so;
561 (lines[line_num].
syntax)[i].
last = pmatch[0].rm_eo;
572 }
while (found || null_rx);
584 if ((nl > 0) && (buf[nl - 1] ==
'\n'))
600 if (regexec(&color_line->
regex, buf + offset, 1, pmatch,
601 ((offset != 0) ? REG_NOTBOL : 0)) != 0)
606 if (pmatch[0].rm_eo != pmatch[0].rm_so)
610 if (++(lines[line_num].syntax_arr_size) > 1)
613 (lines[line_num].syntax_arr_size) *
sizeof(
struct TextSyntax));
617 memset(ts, 0,
sizeof(*ts));
621 pmatch[0].rm_so += offset;
622 pmatch[0].rm_eo += offset;
623 if (!found || (pmatch[0].rm_so < (lines[line_num].syntax)[i].
first) ||
624 ((pmatch[0].rm_so == (lines[line_num].syntax)[i].
first) &&
625 (pmatch[0].rm_eo > (lines[line_num].syntax)[i].
last)))
631 (lines[line_num].syntax)[i].attr_color, &color_line->
attr_color);
632 (lines[line_num].
syntax)[i].
first = pmatch[0].rm_so;
633 (lines[line_num].
syntax)[i].
last = pmatch[0].rm_eo;
635 else if ((pmatch[0].rm_so == (lines[line_num].syntax)[i].first) &&
636 (pmatch[0].rm_eo == (lines[line_num].syntax)[i].last))
639 (lines[line_num].syntax)[i].attr_color, &color_line->
attr_color);
640 (lines[line_num].
syntax)[i].
first = pmatch[0].rm_so;
641 (lines[line_num].
syntax)[i].
last = pmatch[0].rm_eo;
654 }
while (found || null_rx);
684 if ((s[0] ==
'\010') && (s > src))
704 else if (strip_markers && (s[0] ==
'\033') && (s[1] ==
']') &&
728static int fill_buffer(FILE *fp, LOFF_T *bytes_read, LOFF_T offset,
unsigned char **buf,
729 unsigned char **fmt,
size_t *blen,
int *buf_ready)
736 if (offset != *bytes_read)
751 *bytes_read = ftello(fp);
752 b_read = (int) (*bytes_read - offset);
760 *fmt = (
unsigned char *) stripped.
data;
785 int cnt,
int *pspace,
int *pvch,
int *pcol,
786 int *pspecial,
int width,
struct AttrColorList *ansi_list)
790 size_t col = c_markers ? (*lines)[line_num].cont_line : 0;
792 int ch, vch, last_special = -1, special = 0, t;
794 mbstate_t mbstate = { 0 };
802 for (ch = 0, vch = 0; ch < cnt; ch += k, vch += k)
805 if (buf[ch] ==
'\033')
807 int len =
ansi_color_parse((
const char *) buf + ch, ansi, ansi_list, !c_allow_ansi);
811 while ((cnt - ch >= 2) && (buf[ch] ==
'\033') && (buf[ch + 1] ==
']') &&
815 while (buf[ch++] !=
'\a')
824 k = mbrtowc(&wc, (
char *) buf + ch, cnt - ch, &mbstate);
825 if ((k == (
size_t) (-2)) || (k == (
size_t) (-1)))
827 if (k == (
size_t) (-1))
828 memset(&mbstate, 0,
sizeof(mbstate));
830 if ((col + 4) > wrap_cols)
844 if ((wc == 0x200B) || (wc == 0x200C) || (wc == 0xFEFF))
861 mbstate_t mbstate1 = mbstate;
862 size_t k1 = mbrtowc(&wc1, (
char *) buf + ch + k, cnt - ch - k, &mbstate1);
863 while ((k1 != (
size_t) (-2)) && (k1 != (
size_t) (-1)) && (k1 > 0) && (wc1 ==
'\b'))
865 const size_t k2 = mbrtowc(&wc1, (
char *) buf + ch + k + k1,
866 cnt - ch - k - k1, &mbstate1);
867 if ((k2 == (
size_t) (-2)) || (k2 == (
size_t) (-1)) || (k2 == 0) || (!
IsWPrint(wc1)))
872 special |= ((wc ==
'_') && (special & A_UNDERLINE)) ? A_UNDERLINE : A_BOLD;
874 else if ((wc ==
'_') || (wc1 ==
'_'))
876 special |= A_UNDERLINE;
877 wc = (wc1 ==
'_') ? wc : wc1;
888 k1 = mbrtowc(&wc1, (
char *) buf + ch + k, cnt - ch - k, &mbstate1);
893 special || last_special || ansi->
attrs))
895 resolve_color(win, *lines, line_num, vch, flags, special, ansi);
896 last_special = special;
908 if (col + t > wrap_cols)
923 for (; col < t; col++)
928 else if ((wc < 0x20) || (wc == 0x7f))
930 if (col + 2 > wrap_cols)
938 if (col + 4 > wrap_cols)
946 if (col + 1 > wrap_cols)
980 int line_num,
int *lines_used,
int *lines_max,
982 bool *force_redraw, regex_t *search_re,
983 struct MuttWindow *win_pager,
struct AttrColorList *ansi_list)
985 unsigned char *buf = NULL, *fmt = NULL;
987 unsigned char *buf_ptr = NULL;
988 int ch, vch, col, cnt, b_read;
990 bool change_last =
false;
997 regmatch_t pmatch[1];
999 if (line_num == *lines_used)
1005 if (*lines_used == *lines_max)
1008 for (ch = *lines_used; ch < *lines_max; ch++)
1010 memset(&((*lines)[ch]), 0,
sizeof(
struct Line));
1011 (*lines)[ch].cid = -1;
1012 (*lines)[ch].search_arr_size = -1;
1014 ((*lines)[ch].syntax)[0].first = -1;
1015 ((*lines)[ch].syntax)[0].last = -1;
1019 struct Line *
const cur_line = &(*lines)[line_num];
1024 if (
fill_buffer(fp, bytes_read, cur_line->
offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1034 else if (buf[11] ==
'W')
1036 else if (buf[11] ==
'E')
1045 if (cur_line->
cid == -1)
1048 if (
fill_buffer(fp, bytes_read, cur_line->
offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1055 resolve_types(win_pager, (
char *) fmt, (
char *) buf, *lines, line_num, *lines_used,
1059 for (m = line_num + 1;
1060 m < *lines_used && (*lines)[m].offset && (*lines)[m].cont_line; m++)
1062 (*lines)[m].cid = cur_line->
cid;
1069 ((cur_line->
quote == NULL) || (cur_line->
quote->
quote_n >= c_toggle_quoted_show_levels)))
1083 if (
fill_buffer(fp, bytes_read, cur_line->
offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1094 pmatch[0].rm_eo - pmatch[0].rm_so,
1095 force_redraw, q_level);
1105 if (
fill_buffer(fp, bytes_read, cur_line->
offset, &buf, &fmt, &buflen, &buf_ready) < 0)
1114 while (regexec(search_re, (
char *) fmt + offset, 1, pmatch,
1115 (offset ? REG_NOTBOL : 0)) == 0)
1124 memset(ts, 0,
sizeof(*ts));
1130 pmatch[0].rm_so += offset;
1131 pmatch[0].rm_eo += offset;
1135 if (pmatch[0].rm_eo == pmatch[0].rm_so)
1138 offset = pmatch[0].rm_eo;
1144 if (!(flags &
MUTT_SHOW) && ((*lines)[line_num + 1].offset > 0))
1150 if ((flags &
MUTT_SHOWCOLOR) && *force_redraw && ((*lines)[line_num + 1].offset > 0))
1157 b_read =
fill_buffer(fp, bytes_read, cur_line->
offset, &buf, &fmt, &buflen, &buf_ready);
1166 cnt =
format_line(win_pager, lines, line_num, buf, flags, NULL, b_read, &ch,
1167 &vch, &col, &special, win_pager->
state.
cols, ansi_list);
1168 buf_ptr = buf + cnt;
1174 if ((cnt < b_read) && (ch != -1) &&
1179 while (ch && ((buf[ch] ==
' ') || (buf[ch] ==
'\t') || (buf[ch] ==
'\r')))
1187 buf_ptr = buf + cnt;
1194 while ((*buf_ptr ==
' ') || (*buf_ptr ==
'\t'))
1199 if (*buf_ptr ==
'\r')
1201 if (*buf_ptr ==
'\n')
1204 if (((
int) (buf_ptr - buf) < b_read) && !(*lines)[line_num + 1].cont_line)
1205 append_line(*lines, line_num, (
int) (buf_ptr - buf));
1206 (*lines)[line_num + 1].offset = cur_line->
offset + (long) (buf_ptr - buf);
1216 format_line(win_pager, lines, line_num, buf, flags, &ansi, cnt, &ch, &vch,
1217 &col, &special, win_pager->
state.
cols, ansi_list);
1228 resolve_color(win_pager, *lines, line_num, vch, flags, 0, &ansi);
1237 def_color = ((*lines)[m].syntax)[0].
attr_color;
1251 if (col < win_pager->state.cols)
int ansi_color_parse(const char *str, struct AnsiColor *ansi, struct AttrColorList *acl, bool dry_run)
Parse a string of ANSI escape sequence.
int ansi_color_seq_length(const char *str)
Is this an ANSI escape sequence?
bool attr_color_match(struct AttrColor *ac1, struct AttrColor *ac2)
Do the colours match?
struct AttrColor attr_color_copy(const struct AttrColor *ac)
Copy a colour.
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Color and attribute parsing.
struct RegexColorList * regex_colors_get_list(enum ColorId cid)
Return the RegexColorList for a colour id.
bool simple_color_is_header(enum ColorId cid)
Colour is for an Email header.
bool simple_color_is_set(enum ColorId cid)
Is the object coloured?
struct AttrColor * simple_color_get(enum ColorId cid)
Get the colour of an object by its ID.
@ MT_COLOR_MARKERS
Pager: markers, line continuation.
@ MT_COLOR_MESSAGE
Informational message.
@ MT_COLOR_QUOTED
Pager: quoted text.
@ MT_COLOR_HEADER
Message headers (takes a pattern)
@ MT_COLOR_ERROR
Error message.
@ MT_COLOR_BOLD
Bold text.
@ MT_COLOR_BODY
Pager: highlight body of message (takes a pattern)
@ MT_COLOR_HDRDEFAULT
Header default colour.
@ MT_COLOR_NORMAL
Plain text.
@ MT_COLOR_ATTACH_HEADERS
MIME attachment test (takes a pattern)
@ MT_COLOR_SEARCH
Pager: search matches.
@ MT_COLOR_MESSAGE_LOG
Menu showing log messages.
@ MT_COLOR_ITALIC
Italic text.
@ MT_COLOR_ATTACHMENT
MIME attachments text (entire line)
@ MT_COLOR_WARNING
Warning messages.
@ MT_COLOR_UNDERLINE
Underlined text.
@ MT_COLOR_SIGNATURE
Pager: signature lines.
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
int mutt_addwch(struct MuttWindow *win, wchar_t wc)
Addwch would be provided by an up-to-date curses library.
static int format_line(struct MuttWindow *win, struct Line **lines, int line_num, unsigned char *buf, PagerFlags flags, struct AnsiColor *ansi, int cnt, int *pspace, int *pvch, int *pcol, int *pspecial, int width, struct AttrColorList *ansi_list)
Display a line of text in the pager.
static int check_protected_header_marker(const char *p)
Check that the unique marker is present.
void mutt_buffer_strip_formatting(struct Buffer *dest, const char *src, bool strip_markers)
Removes ANSI and backspace formatting.
bool mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
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.
static int check_sig(const char *s, struct Line *info, int offset)
Check for an email signature.
static int comp_syntax_t(const void *m1, const void *m2)
Search for a Syntax using bsearch(3)
static int check_attachment_marker(const char *p)
Check that the unique marker is present.
static void resolve_color(struct MuttWindow *win, struct Line *lines, int line_num, int cnt, PagerFlags flags, int special, struct AnsiColor *ansi)
Set the colour for a line of text.
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.
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, struct AttrColorList *ansi_list)
Print a line on screen.
static void append_line(struct Line *lines, int line_num, int cnt)
Add a new Line to the array.
static int check_marker(const char *q, const char *p)
Check that the unique marker is present.
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
#define MUTT_RL_EOL
don't strip \n / \r\n
#define mutt_debug(LEVEL,...)
Convenience wrapper for the gui headers.
@ LL_DEBUG3
Log at debug level 3.
@ LL_DEBUG2
Log at debug level 2.
@ LL_DEBUG1
Log at debug level 1.
bool mutt_mb_is_display_corrupting_utf8(wchar_t wc)
Will this character corrupt the display?
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
struct AttrColor * merged_color_overlay(struct AttrColor *base, struct AttrColor *over)
Combine two colours.
bool CharsetIsUtf8
Is the user's current character set utf-8?
wchar_t ReplacementChar
When a Unicode character can't be displayed, use this instead.
Convenience wrapper for the library headers.
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.
const char * state_attachment_marker(void)
Get a unique (per-run) ANSI string to mark PGP messages in an email.
const char * state_protected_header_marker(void)
Get a unique (per-run) ANSI string to mark protected headers in an email.
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
void mutt_curses_set_color(struct AttrColor *ac)
Set the colour and attributes for text.
struct AttrColor * mutt_curses_set_color_by_id(enum ColorId cid)
Set the colour and attributes by the colour id.
int mutt_window_printf(struct MuttWindow *win, const char *fmt,...)
Write a formatted string to a Window.
void mutt_window_get_coords(struct MuttWindow *win, int *col, int *row)
Get the cursor position in the Window.
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
int mutt_window_addch(struct MuttWindow *win, int ch)
Write one character to a Window.
#define STAILQ_FOREACH(var, head, field)
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.
int attrs
Attributes, e.g. A_BOLD.
struct AttrColor * attr_color
Curses colour of text.
A curses colour and its attributes.
int attrs
Text attributes, e.g. A_BOLD.
struct CursesColor * curses_color
Underlying Curses colour.
String manipulation buffer.
char * dptr
Current read/write position.
char * data
Pointer to data.
A line of text in the pager.
short search_arr_size
Number of items in search array.
struct TextSyntax * search
Array of search text in the line.
bool cont_line
Continuation of a previous line (wrapped by NeoMutt)
short cid
Default line colour, e.g. MT_COLOR_QUOTED.
struct QuoteStyle * quote
Quoting style for this line (pointer into PagerPrivateData->quote_list)
LOFF_T offset
Offset into Email file (PagerPrivateData->fp)
bool cont_header
Continuation of a header line (wrapped by MTA)
short syntax_arr_size
Number of items in syntax array.
struct TextSyntax * syntax
Array of coloured text in the line.
struct WindowState state
Current state of the Window.
Container for Accounts, Notifications.
struct ConfigSubset * sub
Inherited config items.
struct AttrColor * attr_color
Colour and attribute of the text.
size_t prefix_len
Length of the prefix string.
int quote_n
The quoteN colour index for this level.
A regular expression and a color to highlight a line.
regex_t regex
Compiled regex.
struct AttrColor attr_color
Colour and attributes to apply.
bool stop_matching
Used by the pager for body patterns, to prevent the color from being retried once it fails.
Cached regular expression.
Highlighting for a piece of text.
struct AttrColor * attr_color
Curses colour of text.
int last
Last character in line to be coloured (not included)
int first
First character in line to be coloured.
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.