NeoMutt  2024-04-25-97-g7d2481
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
window.c
Go to the documentation of this file.
1
69#include "config.h"
70#include <stdbool.h>
71#include <stdio.h>
72#include <string.h>
73#include "private.h"
74#include "mutt/lib.h"
75#include "config/lib.h"
76#include "email/lib.h"
77#include "core/lib.h"
78#include "gui/lib.h"
79#include "color/lib.h"
80#include "expando/lib.h"
81#include "index/lib.h"
82
84
89{
90 struct SbEntry *entry;
92};
93
100static int imap_is_prefix(const char *folder, const char *mbox)
101{
102 int plen = 0;
103
104 struct Url *url_m = url_parse(mbox);
105 struct Url *url_f = url_parse(folder);
106 if (!url_m || !url_f)
107 goto done;
108
109 if (!mutt_istr_equal(url_m->host, url_f->host))
110 goto done;
111
112 if (url_m->user && url_f->user && !mutt_istr_equal(url_m->user, url_f->user))
113 goto done;
114
115 size_t mlen = mutt_str_len(url_m->path);
116 size_t flen = mutt_str_len(url_f->path);
117 if (flen > mlen)
118 goto done;
119
120 if (!mutt_strn_equal(url_m->path, url_f->path, flen))
121 goto done;
122
123 plen = strlen(mbox) - mlen + flen;
124
125done:
126 url_free(&url_m);
127 url_free(&url_f);
128
129 return plen;
130}
131
139static const char *abbrev_folder(const char *mbox, const char *folder, enum MailboxType type)
140{
141 if (!mbox || !folder)
142 return NULL;
143
144 if (type == MUTT_IMAP)
145 {
146 int prefix = imap_is_prefix(folder, mbox);
147 if (prefix == 0)
148 return NULL;
149 return mbox + prefix;
150 }
151
152 const char *const c_sidebar_delim_chars = cs_subset_string(NeoMutt->sub, "sidebar_delim_chars");
153 if (!c_sidebar_delim_chars)
154 return NULL;
155
156 size_t flen = mutt_str_len(folder);
157 if (flen == 0)
158 return NULL;
159 if (strchr(c_sidebar_delim_chars, folder[flen - 1])) // folder ends with a delimiter
160 flen--;
161
162 size_t mlen = mutt_str_len(mbox);
163 if (mlen < flen)
164 return NULL;
165
166 if (!mutt_strn_equal(folder, mbox, flen))
167 return NULL;
168
169 // After the match, check that mbox has a delimiter
170 if (!strchr(c_sidebar_delim_chars, mbox[flen]))
171 return NULL;
172
173 if (mlen > flen)
174 {
175 return mbox + flen + 1;
176 }
177
178 // mbox and folder are equal, use the chunk after the last delimiter
179 while (mlen--)
180 {
181 if (strchr(c_sidebar_delim_chars, mbox[mlen]))
182 {
183 return mbox + mlen + 1;
184 }
185 }
186
187 return NULL;
188}
189
203static const char *abbrev_url(const char *mbox, enum MailboxType type)
204{
205 /* This is large enough to skip `notmuch://`,
206 * but not so large that it will go past the host part. */
207 const int scheme_len = 10;
208
209 size_t len = mutt_str_len(mbox);
210 if ((len < scheme_len) || ((type != MUTT_NNTP) && (type != MUTT_IMAP) &&
211 (type != MUTT_NOTMUCH) && (type != MUTT_POP)))
212 {
213 return mbox;
214 }
215
216 const char split = (type == MUTT_NOTMUCH) ? '?' : '/';
217
218 // Skip over the scheme, e.g. `imaps://`, `notmuch://`
219 const char *last = strchr(mbox + scheme_len, split);
220 if (last)
221 mbox = last + 1;
222 return mbox;
223}
224
232static size_t add_indent(char *buf, size_t buflen, const struct SbEntry *sbe)
233{
234 size_t res = 0;
235 const char *const c_sidebar_indent_string = cs_subset_string(NeoMutt->sub, "sidebar_indent_string");
236 for (int i = 0; i < sbe->depth; i++)
237 {
238 res += mutt_str_copy(buf + res, c_sidebar_indent_string, buflen - res);
239 }
240 return res;
241}
242
250static const struct AttrColor *calc_color(const struct Mailbox *m, bool current, bool highlight)
251{
252 const struct AttrColor *ac = NULL;
253
254 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
256 mutt_str_equal(mailbox_path(m), c_spool_file))
257 {
259 }
260
262 {
264 }
265
267 {
269 }
270
272 {
274 }
275
277 {
279 }
280
281 const struct AttrColor *ac_bg = simple_color_get(MT_COLOR_NORMAL);
283 ac = merged_color_overlay(ac_bg, ac);
284
285 if (current || highlight)
286 {
287 int color;
288 if (current)
289 {
292 else
293 color = MT_COLOR_INDICATOR;
294 }
295 else
296 {
298 }
299
300 ac = merged_color_overlay(ac, simple_color_get(color));
301 }
302
303 return ac;
304}
305
313static int calc_path_depth(const char *mbox, const char *delims, const char **last_part)
314{
315 if (!mbox || !delims || !last_part)
316 return 0;
317
318 int depth = 0;
319 const char *match = NULL;
320 while ((match = strpbrk(mbox, delims)))
321 {
322 depth++;
323 mbox = match + 1;
324 }
325
326 *last_part = mbox;
327 return depth;
328}
329
333void sidebar_bang(const struct ExpandoNode *node, void *data,
334 MuttFormatFlags flags, int max_cols, struct Buffer *buf)
335{
336 const struct SidebarData *sdata = data;
337 const struct SbEntry *sbe = sdata->entry;
338 const struct Mailbox *m = sbe->mailbox;
339
340 if (m->msg_flagged == 0)
341 {
342 buf_strcpy(buf, "");
343 }
344 else if (m->msg_flagged == 1)
345 {
346 buf_strcpy(buf, "!");
347 }
348 else if (m->msg_flagged == 2)
349 {
350 buf_strcpy(buf, "!!");
351 }
352 else
353 {
354 buf_printf(buf, "%d!", m->msg_flagged);
355 }
356}
357
361long sidebar_a_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
362{
363 const struct SidebarData *sdata = data;
364 const struct SbEntry *sbe = sdata->entry;
365 const struct Mailbox *m = sbe->mailbox;
366
367 return m->notify_user;
368}
369
373void sidebar_B(const struct ExpandoNode *node, void *data,
374 MuttFormatFlags flags, int max_cols, struct Buffer *buf)
375{
376 const struct SidebarData *sdata = data;
377 const struct SbEntry *sbe = sdata->entry;
378
379 char tmp[256] = { 0 };
380
381 const size_t ilen = sizeof(tmp);
382 const size_t off = add_indent(tmp, ilen, sbe);
383 snprintf(tmp + off, ilen - off, "%s", sbe->box);
384
385 buf_strcpy(buf, tmp);
386}
387
391long sidebar_d_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
392{
393 const struct SidebarData *sdata = data;
394 const struct SbEntry *sbe = sdata->entry;
395 const struct IndexSharedData *shared = sdata->shared;
396 const struct Mailbox *m = sbe->mailbox;
397 const struct Mailbox *m_cur = shared->mailbox;
398
399 const bool c = m_cur && mutt_str_equal(m_cur->realpath, m->realpath);
400
401 return c ? m_cur->msg_deleted : 0;
402}
403
407void sidebar_D(const struct ExpandoNode *node, void *data,
408 MuttFormatFlags flags, int max_cols, struct Buffer *buf)
409{
410 const struct SidebarData *sdata = data;
411 const struct SbEntry *sbe = sdata->entry;
412
413 char tmp[256] = { 0 };
414
415 const size_t ilen = sizeof(tmp);
416 const size_t off = add_indent(tmp, ilen, sbe);
417
418 if (sbe->mailbox->name)
419 {
420 snprintf(tmp + off, ilen - off, "%s", sbe->mailbox->name);
421 }
422 else
423 {
424 snprintf(tmp + off, ilen - off, "%s", sbe->box);
425 }
426
427 buf_strcpy(buf, tmp);
428}
429
433long sidebar_F_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
434{
435 const struct SidebarData *sdata = data;
436 const struct SbEntry *sbe = sdata->entry;
437 const struct Mailbox *m = sbe->mailbox;
438
439 return m->msg_flagged;
440}
441
445long sidebar_L_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
446{
447 const struct SidebarData *sdata = data;
448 const struct SbEntry *sbe = sdata->entry;
449 const struct IndexSharedData *shared = sdata->shared;
450 const struct Mailbox *m = sbe->mailbox;
451 const struct Mailbox *m_cur = shared->mailbox;
452
453 const bool c = m_cur && mutt_str_equal(m_cur->realpath, m->realpath);
454
455 return c ? m_cur->vcount : m->msg_count;
456}
457
461long sidebar_n_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
462{
463 const struct SidebarData *sdata = data;
464 const struct SbEntry *sbe = sdata->entry;
465 const struct Mailbox *m = sbe->mailbox;
466
467 return m->has_new;
468}
469
473void sidebar_n(const struct ExpandoNode *node, void *data,
474 MuttFormatFlags flags, int max_cols, struct Buffer *buf)
475{
476 const struct SidebarData *sdata = data;
477 const struct SbEntry *sbe = sdata->entry;
478 const struct Mailbox *m = sbe->mailbox;
479
480 // NOTE(g0mb4): use $flag_chars?
481 const char *s = m->has_new ? "N" : " ";
482 buf_strcpy(buf, s);
483}
484
488long sidebar_N_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
489{
490 const struct SidebarData *sdata = data;
491 const struct SbEntry *sbe = sdata->entry;
492 const struct Mailbox *m = sbe->mailbox;
493
494 return m->msg_unread;
495}
496
500long sidebar_o_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
501{
502 const struct SidebarData *sdata = data;
503 const struct SbEntry *sbe = sdata->entry;
504 const struct Mailbox *m = sbe->mailbox;
505
506 return m->msg_unread - m->msg_new;
507}
508
512long sidebar_p_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
513{
514 const struct SidebarData *sdata = data;
515 const struct SbEntry *sbe = sdata->entry;
516 const struct Mailbox *m = sbe->mailbox;
517
518 return m->poll_new_mail;
519}
520
524long sidebar_r_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
525{
526 const struct SidebarData *sdata = data;
527 const struct SbEntry *sbe = sdata->entry;
528 const struct Mailbox *m = sbe->mailbox;
529
530 return m->msg_count - m->msg_unread;
531}
532
536long sidebar_S_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
537{
538 const struct SidebarData *sdata = data;
539 const struct SbEntry *sbe = sdata->entry;
540 const struct Mailbox *m = sbe->mailbox;
541
542 return m->msg_count;
543}
544
548long sidebar_t_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
549{
550 const struct SidebarData *sdata = data;
551 const struct SbEntry *sbe = sdata->entry;
552 const struct IndexSharedData *shared = sdata->shared;
553 const struct Mailbox *m = sbe->mailbox;
554 const struct Mailbox *m_cur = shared->mailbox;
555
556 const bool c = m_cur && mutt_str_equal(m_cur->realpath, m->realpath);
557
558 return c ? m_cur->msg_tagged : 0;
559}
560
564long sidebar_Z_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
565{
566 const struct SidebarData *sdata = data;
567 const struct SbEntry *sbe = sdata->entry;
568 const struct Mailbox *m = sbe->mailbox;
569
570 return m->msg_new;
571}
572
586static void make_sidebar_entry(char *buf, size_t buflen, int width,
587 struct SbEntry *sbe, struct IndexSharedData *shared)
588{
589 struct SidebarData sdata = { sbe, shared };
590
591 struct Buffer *tmp = buf_pool_get();
592 const struct Expando *c_sidebar_format = cs_subset_expando(NeoMutt->sub, "sidebar_format");
593 expando_filter(c_sidebar_format, SidebarRenderData, &sdata,
594 MUTT_FORMAT_NO_FLAGS, width, tmp);
595 mutt_str_copy(buf, buf_string(tmp), buflen);
596 buf_pool_release(&tmp);
597
598 /* Force string to be exactly the right width */
599 int w = mutt_strwidth(buf);
600 int s = mutt_str_len(buf);
601 width = MIN(buflen, width);
602 if (w < width)
603 {
604 /* Pad with spaces */
605 memset(buf + s, ' ', width - w);
606 buf[s + width - w] = '\0';
607 }
608 else if (w > width)
609 {
610 /* Truncate to fit */
611 size_t len = mutt_wstr_trunc(buf, buflen, width, NULL);
612 buf[len] = '\0';
613 }
614}
615
629{
630 /* Aliases for readability */
631 const bool c_sidebar_new_mail_only = cs_subset_bool(NeoMutt->sub, "sidebar_new_mail_only");
632 const bool c_sidebar_non_empty_mailbox_only = cs_subset_bool(NeoMutt->sub, "sidebar_non_empty_mailbox_only");
633 struct SbEntry *sbe = NULL;
634
635 struct IndexSharedData *shared = wdata->shared;
636 struct SbEntry **sbep = NULL;
637 ARRAY_FOREACH(sbep, &wdata->entries)
638 {
639 int i = ARRAY_FOREACH_IDX;
640 sbe = *sbep;
641
642 sbe->is_hidden = false;
643
644 if (!sbe->mailbox->visible)
645 {
646 sbe->is_hidden = true;
647 continue;
648 }
649
650 if (shared->mailbox &&
652 {
653 /* Spool directories are always visible */
654 continue;
655 }
656
659 {
660 /* Explicitly asked to be visible */
661 continue;
662 }
663
664 if (c_sidebar_non_empty_mailbox_only && (i != wdata->opn_index) &&
665 (sbe->mailbox->msg_count == 0))
666 {
667 sbe->is_hidden = true;
668 }
669
670 if (c_sidebar_new_mail_only && (i != wdata->opn_index) &&
671 (sbe->mailbox->msg_unread == 0) && (sbe->mailbox->msg_flagged == 0) &&
672 !sbe->mailbox->has_new)
673 {
674 sbe->is_hidden = true;
675 }
676 }
677}
678
692static bool prepare_sidebar(struct SidebarWindowData *wdata, int page_size)
693{
694 if (ARRAY_EMPTY(&wdata->entries) || (page_size <= 0))
695 return false;
696
697 struct SbEntry **sbep = NULL;
698 const bool c_sidebar_new_mail_only = cs_subset_bool(NeoMutt->sub, "sidebar_new_mail_only");
699 const bool c_sidebar_non_empty_mailbox_only = cs_subset_bool(NeoMutt->sub, "sidebar_non_empty_mailbox_only");
700
701 sbep = (wdata->opn_index >= 0) ? ARRAY_GET(&wdata->entries, wdata->opn_index) : NULL;
702 const struct SbEntry *opn_entry = sbep ? *sbep : NULL;
703 sbep = (wdata->hil_index >= 0) ? ARRAY_GET(&wdata->entries, wdata->hil_index) : NULL;
704 const struct SbEntry *hil_entry = sbep ? *sbep : NULL;
705
707 const short c_sidebar_sort_method = cs_subset_sort(NeoMutt->sub, "sidebar_sort_method");
708 sb_sort_entries(wdata, c_sidebar_sort_method);
709
710 if (opn_entry || hil_entry)
711 {
712 ARRAY_FOREACH(sbep, &wdata->entries)
713 {
714 if ((opn_entry == *sbep) && (*sbep)->mailbox->visible)
715 wdata->opn_index = ARRAY_FOREACH_IDX;
716 if ((hil_entry == *sbep) && (*sbep)->mailbox->visible)
717 wdata->hil_index = ARRAY_FOREACH_IDX;
718 }
719 }
720
721 if ((wdata->hil_index < 0) || (hil_entry && hil_entry->is_hidden) ||
722 (c_sidebar_sort_method != wdata->previous_sort))
723 {
724 if (wdata->opn_index >= 0)
725 {
726 wdata->hil_index = wdata->opn_index;
727 }
728 else
729 {
730 wdata->hil_index = 0;
731 /* Note is_hidden will only be set when `$sidebar_new_mail_only` */
732 if ((*ARRAY_GET(&wdata->entries, 0))->is_hidden && !sb_next(wdata))
733 wdata->hil_index = -1;
734 }
735 }
736
737 /* Set the Top and Bottom to frame the wdata->hil_index in groups of page_size */
738
739 /* If `$sidebar_new_mail_only` or `$sidebar_non_empty_mailbox_only` is set,
740 * some entries may be hidden so we need to scan for the framing interval */
741 if (c_sidebar_new_mail_only || c_sidebar_non_empty_mailbox_only)
742 {
743 wdata->top_index = -1;
744 wdata->bot_index = -1;
745 while (wdata->bot_index < wdata->hil_index)
746 {
747 wdata->top_index = wdata->bot_index + 1;
748 int page_entries = 0;
749 while (page_entries < page_size)
750 {
751 wdata->bot_index++;
752 if (wdata->bot_index >= ARRAY_SIZE(&wdata->entries))
753 break;
754 if (!(*ARRAY_GET(&wdata->entries, wdata->bot_index))->is_hidden)
755 page_entries++;
756 }
757 }
758 }
759 else
760 {
761 /* Otherwise we can just calculate the interval */
762 wdata->top_index = (wdata->hil_index / page_size) * page_size;
763 wdata->bot_index = wdata->top_index + page_size - 1;
764 }
765
766 if (wdata->bot_index > (ARRAY_SIZE(&wdata->entries) - 1))
767 wdata->bot_index = ARRAY_SIZE(&wdata->entries) - 1;
768
769 wdata->previous_sort = c_sidebar_sort_method;
770
771 return (wdata->hil_index >= 0);
772}
773
777int sb_recalc(struct MuttWindow *win)
778{
780 struct IndexSharedData *shared = wdata->shared;
781
782 if (ARRAY_EMPTY(&wdata->entries))
783 {
784 struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
786 struct MailboxNode *np = NULL;
787 STAILQ_FOREACH(np, &ml, entries)
788 {
789 if (np->mailbox->visible)
790 sb_add_mailbox(wdata, np->mailbox);
791 }
793 }
794
795 if (!prepare_sidebar(wdata, win->state.rows))
796 {
797 win->actions |= WA_REPAINT;
798 return 0;
799 }
800
801 int num_rows = win->state.rows;
802 int num_cols = win->state.cols;
803
804 if (ARRAY_EMPTY(&wdata->entries) || (num_rows <= 0))
805 return 0;
806
807 if (wdata->top_index < 0)
808 return 0;
809
810 int width = num_cols - wdata->divider_width;
811 int row = 0;
812 struct Mailbox *m_cur = shared->mailbox;
813 struct SbEntry **sbep = NULL;
814 ARRAY_FOREACH_FROM(sbep, &wdata->entries, wdata->top_index)
815 {
816 if (row >= num_rows)
817 break;
818
819 if ((*sbep)->is_hidden)
820 continue;
821
822 struct SbEntry *entry = (*sbep);
823 struct Mailbox *m = entry->mailbox;
824
825 const int entryidx = ARRAY_FOREACH_IDX;
826 entry->color = calc_color(m, (entryidx == wdata->opn_index),
827 (entryidx == wdata->hil_index));
828
829 if (m_cur && (m_cur->realpath[0] != '\0') &&
830 mutt_str_equal(m->realpath, m_cur->realpath))
831 {
832 m->msg_unread = m_cur->msg_unread;
833 m->msg_count = m_cur->msg_count;
834 m->msg_flagged = m_cur->msg_flagged;
835 }
836
837 const char *path = mailbox_path(m);
838
839 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
840 // Try to abbreviate the full path
841 const char *abbr = abbrev_folder(path, c_folder, m->type);
842 if (!abbr)
843 abbr = abbrev_url(path, m->type);
844 const char *short_path = abbr ? abbr : path;
845
846 /* Compute the depth */
847 const char *last_part = abbr;
848 const char *const c_sidebar_delim_chars = cs_subset_string(NeoMutt->sub, "sidebar_delim_chars");
849 entry->depth = calc_path_depth(abbr, c_sidebar_delim_chars, &last_part);
850
851 const bool short_path_is_abbr = (short_path == abbr);
852 const bool c_sidebar_short_path = cs_subset_bool(NeoMutt->sub, "sidebar_short_path");
853 if (c_sidebar_short_path)
854 {
855 short_path = last_part;
856 }
857
858 // Don't indent if we were unable to create an abbreviation.
859 // Otherwise, the full path will be indent, and it looks unusual.
860 const bool c_sidebar_folder_indent = cs_subset_bool(NeoMutt->sub, "sidebar_folder_indent");
861 if (c_sidebar_folder_indent && short_path_is_abbr)
862 {
863 const short c_sidebar_component_depth = cs_subset_number(NeoMutt->sub, "sidebar_component_depth");
864 if (c_sidebar_component_depth > 0)
865 entry->depth -= c_sidebar_component_depth;
866 }
867 else if (!c_sidebar_folder_indent)
868 {
869 entry->depth = 0;
870 }
871
872 mutt_str_copy(entry->box, short_path, sizeof(entry->box));
873 make_sidebar_entry(entry->display, sizeof(entry->display), width, entry, shared);
874 row++;
875 }
876
877 win->actions |= WA_REPAINT;
878 mutt_debug(LL_DEBUG5, "recalc done, request WA_REPAINT\n");
879 return 0;
880}
881
898static int draw_divider(struct SidebarWindowData *wdata, struct MuttWindow *win,
899 int num_rows, int num_cols)
900{
901 if ((num_rows < 1) || (num_cols < 1) || (wdata->divider_width > num_cols) ||
902 (wdata->divider_width == 0))
903 {
904 return 0;
905 }
906
907 const int width = wdata->divider_width;
908 const char *const c_sidebar_divider_char = cs_subset_string(NeoMutt->sub, "sidebar_divider_char");
909
910 const struct AttrColor *ac = simple_color_get(MT_COLOR_NORMAL);
914
915 const bool c_sidebar_on_right = cs_subset_bool(NeoMutt->sub, "sidebar_on_right");
916 const int col = c_sidebar_on_right ? 0 : (num_cols - width);
917
918 for (int i = 0; i < num_rows; i++)
919 {
920 mutt_window_move(win, col, i);
921
922 if (wdata->divider_type == SB_DIV_USER)
923 mutt_window_addstr(win, NONULL(c_sidebar_divider_char));
924 else
925 mutt_window_addch(win, '|');
926 }
927
929 return width;
930}
931
942static void fill_empty_space(struct MuttWindow *win, int first_row,
943 int num_rows, int div_width, int num_cols)
944{
945 /* Fill the remaining rows with blank space */
946 const struct AttrColor *ac = simple_color_get(MT_COLOR_NORMAL);
949
950 const bool c_sidebar_on_right = cs_subset_bool(NeoMutt->sub, "sidebar_on_right");
951 if (!c_sidebar_on_right)
952 div_width = 0;
953 for (int r = 0; r < num_rows; r++)
954 {
955 mutt_window_move(win, div_width, first_row + r);
957
958 for (int i = 0; i < num_cols; i++)
959 mutt_window_addch(win, ' ');
960 }
961}
962
966int sb_repaint(struct MuttWindow *win)
967{
969 const bool c_sidebar_on_right = cs_subset_bool(NeoMutt->sub, "sidebar_on_right");
970
971 int row = 0;
972 int num_rows = win->state.rows;
973 int num_cols = win->state.cols;
974
975 if (wdata->top_index >= 0)
976 {
977 int col = 0;
978 if (c_sidebar_on_right)
979 col = wdata->divider_width;
980
981 struct SbEntry **sbep = NULL;
982 ARRAY_FOREACH_FROM(sbep, &wdata->entries, wdata->top_index)
983 {
984 if (row >= num_rows)
985 break;
986
987 if ((*sbep)->is_hidden)
988 continue;
989
990 struct SbEntry *entry = (*sbep);
991 mutt_window_move(win, col, row);
993 mutt_window_printf(win, "%s", entry->display);
994 mutt_refresh();
995 row++;
996 }
997 }
998
999 fill_empty_space(win, row, num_rows - row, wdata->divider_width,
1000 num_cols - wdata->divider_width);
1001 draw_divider(wdata, win, num_rows, num_cols);
1002
1003 mutt_debug(LL_DEBUG5, "repaint done\n");
1004 return 0;
1005}
1006
1012const struct ExpandoRenderData SidebarRenderData[] = {
1013 // clang-format off
1016 { ED_SIDEBAR, ED_SID_NAME, sidebar_B, NULL },
1029 { -1, -1, NULL, NULL },
1030 // clang-format on
1031};
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:74
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:87
#define ARRAY_FOREACH_FROM(elem, head, from)
Iterate from an index to the end.
Definition: array.h:223
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:109
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
Color and attribute parsing.
bool simple_color_is_set(enum ColorId cid)
Is the object coloured?
Definition: simple.c:109
struct AttrColor * simple_color_get(enum ColorId cid)
Get the colour of an object by its ID.
Definition: simple.c:88
@ MT_COLOR_SIDEBAR_DIVIDER
Line dividing sidebar from the index/pager.
Definition: color.h:66
@ MT_COLOR_SIDEBAR_NEW
Mailbox with new mail.
Definition: color.h:70
@ MT_COLOR_SIDEBAR_UNREAD
Mailbox with unread mail.
Definition: color.h:73
@ MT_COLOR_INDICATOR
Selected item in list.
Definition: color.h:54
@ MT_COLOR_SIDEBAR_SPOOLFILE
$spool_file (Spool mailbox)
Definition: color.h:72
@ MT_COLOR_SIDEBAR_ORDINARY
Mailbox with no new or flagged messages.
Definition: color.h:71
@ MT_COLOR_SIDEBAR_BACKGROUND
Background colour for the Sidebar.
Definition: color.h:65
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:59
@ MT_COLOR_SIDEBAR_INDICATOR
Current open mailbox.
Definition: color.h:69
@ MT_COLOR_SIDEBAR_HIGHLIGHT
Select cursor.
Definition: color.h:68
@ MT_COLOR_SIDEBAR_FLAGGED
Mailbox with flagged messages.
Definition: color.h:67
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:291
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:143
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:266
const struct Expando * cs_subset_expando(const struct ConfigSubset *sub, const char *name)
Get an Expando config item by name.
Definition: config_type.c:357
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:223
MailboxType
Supported mailbox formats.
Definition: mailbox.h:41
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
@ MUTT_POP
'POP3' Mailbox type
Definition: mailbox.h:52
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:49
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
@ MUTT_MAILBOX_ANY
Match any Mailbox type.
Definition: mailbox.h:42
size_t mutt_wstr_trunc(const char *src, size_t maxlen, size_t maxwid, size_t *width)
Work out how to truncate a widechar string.
Definition: curs_lib.c:383
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:78
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:443
@ ED_SIDEBAR
Sidebar ED_SID_ ExpandoDataSidebar.
Definition: domain.h:54
Structs that make up an email.
int expando_filter(const struct Expando *exp, const struct ExpandoRenderData *rdata, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Render an Expando and run the result through a filter.
Definition: filter.c:141
Parse Expando string.
long sidebar_S_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
Sidebar: number of messages - Implements ExpandoRenderData::get_number() -.
Definition: window.c:536
long sidebar_F_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
Sidebar: Number of flagged messages - Implements ExpandoRenderData::get_number() -.
Definition: window.c:433
long sidebar_N_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
Sidebar: Number of unread messages - Implements ExpandoRenderData::get_number() -.
Definition: window.c:488
long sidebar_a_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
Sidebar: Alert for new mail - Implements ExpandoRenderData::get_number() -.
Definition: window.c:361
long sidebar_L_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
Sidebar: Number of limited messages - Implements ExpandoRenderData::get_number() -.
Definition: window.c:445
long sidebar_t_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
Sidebar: Number of tagged messages - Implements ExpandoRenderData::get_number() -.
Definition: window.c:548
long sidebar_Z_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
Sidebar: Number of new messages - Implements ExpandoRenderData::get_number() -.
Definition: window.c:564
long sidebar_r_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
Sidebar: Number of read messages - Implements ExpandoRenderData::get_number() -.
Definition: window.c:524
long sidebar_o_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
Sidebar: Number of old messages - Implements ExpandoRenderData::get_number() -.
Definition: window.c:500
long sidebar_p_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
Sidebar: Poll for new mail - Implements ExpandoRenderData::get_number() -.
Definition: window.c:512
long sidebar_n_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
Sidebar: New mail flag - Implements ExpandoRenderData::get_number() -.
Definition: window.c:461
long sidebar_d_num(const struct ExpandoNode *node, void *data, MuttFormatFlags flags)
Sidebar: Number of deleted messages - Implements ExpandoRenderData::get_number() -.
Definition: window.c:391
void sidebar_B(const struct ExpandoNode *node, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Sidebar: Name of the mailbox - Implements ExpandoRenderData::get_string() -.
Definition: window.c:373
void sidebar_bang(const struct ExpandoNode *node, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Sidebar: Flagged flags - Implements ExpandoRenderData::get_string() -.
Definition: window.c:333
void sidebar_n(const struct ExpandoNode *node, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Sidebar: New mail flag - Implements ExpandoRenderData::get_string() -.
Definition: window.c:473
void sidebar_D(const struct ExpandoNode *node, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Sidebar: Descriptive name - Implements ExpandoRenderData::get_string() -.
Definition: window.c:407
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
int sb_recalc(struct MuttWindow *win)
Recalculate the Sidebar display - Implements MuttWindow::recalc() -.
Definition: window.c:777
int sb_repaint(struct MuttWindow *win)
Repaint the Sidebar display - Implements MuttWindow::repaint() -.
Definition: window.c:966
Convenience wrapper for the gui headers.
GUI manage the main index (list of emails)
struct ListNode * mutt_list_find(const struct ListHead *h, const char *data)
Find a string in a List.
Definition: list.c:103
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
#define MIN(a, b)
Definition: memory.h:32
const struct AttrColor * merged_color_overlay(const struct AttrColor *base, const struct AttrColor *over)
Combine two colours.
Definition: merged.c:107
Convenience wrapper for the library headers.
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:672
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:425
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:581
const struct AttrColor * mutt_curses_set_color_by_id(enum ColorId cid)
Set the colour and attributes by the colour id.
Definition: mutt_curses.c:79
void mutt_curses_set_color(const struct AttrColor *ac)
Set the colour and attributes for text.
Definition: mutt_curses.c:38
int mutt_window_printf(struct MuttWindow *win, const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:430
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:296
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:415
int mutt_window_addch(struct MuttWindow *win, int ch)
Write one character to a Window.
Definition: mutt_window.c:387
#define WA_REPAINT
Redraw the contents of the Window.
Definition: mutt_window.h:110
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition: neomutt.c:168
size_t neomutt_mailboxlist_get_all(struct MailboxList *head, struct NeoMutt *n, enum MailboxType type)
Get a List of all Mailboxes.
Definition: neomutt.c:191
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: render.h:33
uint8_t MuttFormatFlags
Flags for expando_render(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: render.h:32
bool sb_next(struct SidebarWindowData *wdata)
Find the next unhidden Mailbox.
Definition: functions.c:47
GUI display the mailboxes in a side panel.
@ SB_DIV_USER
User configured using $sidebar_divider_char.
Definition: private.h:80
struct ListHead SidebarPinned
List of mailboxes to always display in the sidebar.
Definition: sidebar.c:43
@ ED_SID_FLAGGED_COUNT
Mailbox.msg_flagged.
Definition: private.h:61
@ ED_SID_READ_COUNT
Mailbox.msg_count, Mailbox.msg_unread.
Definition: private.h:69
@ ED_SID_DESCRIPTION
Mailbox.name.
Definition: private.h:59
@ ED_SID_NEW_MAIL
Mailbox.has_new.
Definition: private.h:65
@ ED_SID_UNSEEN_COUNT
Mailbox.msg_new.
Definition: private.h:72
@ ED_SID_POLL
Mailbox.poll_new_mail.
Definition: private.h:68
@ ED_SID_OLD_COUNT
Mailbox.msg_unread, Mailbox.msg_new.
Definition: private.h:67
@ ED_SID_MESSAGE_COUNT
Mailbox.msg_count.
Definition: private.h:63
@ ED_SID_LIMITED_COUNT
Mailbox.vcount.
Definition: private.h:62
@ ED_SID_UNREAD_COUNT
Mailbox.msg_unread.
Definition: private.h:71
@ ED_SID_TAGGED_COUNT
Mailbox.msg_tagged.
Definition: private.h:70
@ ED_SID_NOTIFY
Mailbox.notify_user.
Definition: private.h:66
@ ED_SID_NAME
SbEntry.box.
Definition: private.h:64
@ ED_SID_DELETED_COUNT
Mailbox.msg_deleted.
Definition: private.h:58
@ ED_SID_FLAGGED
Mailbox.msg_flagged.
Definition: private.h:60
void sb_add_mailbox(struct SidebarWindowData *wdata, struct Mailbox *m)
Add a Mailbox to the Sidebar.
Definition: sidebar.c:88
void sb_sort_entries(struct SidebarWindowData *wdata, enum SortType sort)
Sort the Sidebar entries.
Definition: sort.c:172
struct SidebarWindowData * sb_wdata_get(struct MuttWindow *win)
Get the Sidebar data for this window.
Definition: wdata.c:77
static const char * abbrev_url(const char *mbox, enum MailboxType type)
Abbreviate a url-style Mailbox path.
Definition: window.c:203
static void fill_empty_space(struct MuttWindow *win, int first_row, int num_rows, int div_width, int num_cols)
Wipe the remaining Sidebar space.
Definition: window.c:942
static void update_entries_visibility(struct SidebarWindowData *wdata)
Should a SbEntry be displayed in the sidebar?
Definition: window.c:628
static const struct AttrColor * calc_color(const struct Mailbox *m, bool current, bool highlight)
Calculate the colour of a Sidebar row.
Definition: window.c:250
static const char * abbrev_folder(const char *mbox, const char *folder, enum MailboxType type)
Abbreviate a Mailbox path using a folder.
Definition: window.c:139
static size_t add_indent(char *buf, size_t buflen, const struct SbEntry *sbe)
Generate the needed indentation.
Definition: window.c:232
static int calc_path_depth(const char *mbox, const char *delims, const char **last_part)
Calculate the depth of a Mailbox path.
Definition: window.c:313
static bool prepare_sidebar(struct SidebarWindowData *wdata, int page_size)
Prepare the list of SbEntry's for the sidebar display.
Definition: window.c:692
static int imap_is_prefix(const char *folder, const char *mbox)
Check if folder matches the beginning of mbox.
Definition: window.c:100
static int draw_divider(struct SidebarWindowData *wdata, struct MuttWindow *win, int num_rows, int num_cols)
Draw a line between the sidebar and the rest of neomutt.
Definition: window.c:898
static void make_sidebar_entry(char *buf, size_t buflen, int width, struct SbEntry *sbe, struct IndexSharedData *shared)
Turn mailbox data into a sidebar string.
Definition: window.c:586
const struct ExpandoRenderData SidebarRenderData[]
Callbacks for Sidebar Expandos.
Definition: window.c:83
#define NONULL(x)
Definition: string2.h:37
A curses colour and its attributes.
Definition: attr.h:66
String manipulation buffer.
Definition: buffer.h:36
Basic Expando Node.
Definition: node.h:69
Parsed Expando trees.
Definition: expando.h:41
Data shared between Index, Pager and Sidebar.
Definition: shared_data.h:37
struct Mailbox * mailbox
Current Mailbox.
Definition: shared_data.h:41
List of Mailboxes.
Definition: mailbox.h:166
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:167
A mailbox.
Definition: mailbox.h:79
int vcount
The number of virtual messages.
Definition: mailbox.h:99
bool has_new
Mailbox has new mail.
Definition: mailbox.h:85
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
int msg_new
Number of new messages.
Definition: mailbox.h:92
int msg_count
Total number of messages.
Definition: mailbox.h:88
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
bool poll_new_mail
Check for new mail.
Definition: mailbox.h:115
char * name
A short name for the Mailbox.
Definition: mailbox.h:82
bool notify_user
Notify the user of new mail.
Definition: mailbox.h:113
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:93
bool visible
True if a result of "mailboxes".
Definition: mailbox.h:130
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:90
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:94
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:126
void * wdata
Private data.
Definition: mutt_window.h:144
WindowActionFlags actions
Actions to be performed, e.g. WA_RECALC.
Definition: mutt_window.h:131
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
Info about folders in the sidebar.
Definition: private.h:41
const struct AttrColor * color
Colour to use.
Definition: private.h:47
int depth
Indentation depth.
Definition: private.h:44
char display[256]
Formatted string to display.
Definition: private.h:43
struct Mailbox * mailbox
Mailbox this represents.
Definition: private.h:45
bool is_hidden
Don't show, e.g. $sidebar_new_mail_only.
Definition: private.h:46
char box[256]
Mailbox path (possibly abbreviated)
Definition: private.h:42
Data passed to sidebar_format_str()
Definition: window.c:89
struct IndexSharedData * shared
Shared Index Data.
Definition: window.c:91
struct SbEntry * entry
Info about a folder.
Definition: window.c:90
Sidebar private Window data -.
Definition: private.h:88
short previous_sort
Old $sidebar_sort_method
Definition: private.h:98
int top_index
First mailbox visible in sidebar.
Definition: private.h:93
short divider_width
Width of the divider in screen columns.
Definition: private.h:100
int bot_index
Last mailbox visible in sidebar.
Definition: private.h:96
int hil_index
Highlighted mailbox.
Definition: private.h:95
enum DivType divider_type
Type of divider to use, e.g. SB_DIV_ASCII.
Definition: private.h:99
struct IndexSharedData * shared
Shared Index Data.
Definition: private.h:90
int opn_index
Current (open) mailbox.
Definition: private.h:94
struct MuttWindow * win
Sidebar Window.
Definition: private.h:89
struct SbEntryArray entries
Items to display in the sidebar.
Definition: private.h:91
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:69
char * user
Username.
Definition: url.h:71
char * host
Host.
Definition: url.h:73
char * path
Path.
Definition: url.h:75
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:61
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:239
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:124