NeoMutt  2023-11-03-107-g582dc1
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
window.c
Go to the documentation of this file.
1
68#include "config.h"
69#include <stdbool.h>
70#include <stdint.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 "index/lib.h"
81#include "format_flags.h"
82#include "muttlib.h"
83
88{
89 struct SbEntry *entry;
91};
92
99static int imap_is_prefix(const char *folder, const char *mbox)
100{
101 int plen = 0;
102
103 struct Url *url_m = url_parse(mbox);
104 struct Url *url_f = url_parse(folder);
105 if (!url_m || !url_f)
106 goto done;
107
108 if (!mutt_istr_equal(url_m->host, url_f->host))
109 goto done;
110
111 if (url_m->user && url_f->user && !mutt_istr_equal(url_m->user, url_f->user))
112 goto done;
113
114 size_t mlen = mutt_str_len(url_m->path);
115 size_t flen = mutt_str_len(url_f->path);
116 if (flen > mlen)
117 goto done;
118
119 if (!mutt_strn_equal(url_m->path, url_f->path, flen))
120 goto done;
121
122 plen = strlen(mbox) - mlen + flen;
123
124done:
125 url_free(&url_m);
126 url_free(&url_f);
127
128 return plen;
129}
130
138static const char *abbrev_folder(const char *mbox, const char *folder, enum MailboxType type)
139{
140 if (!mbox || !folder)
141 return NULL;
142
143 if (type == MUTT_IMAP)
144 {
145 int prefix = imap_is_prefix(folder, mbox);
146 if (prefix == 0)
147 return NULL;
148 return mbox + prefix;
149 }
150
151 const char *const c_sidebar_delim_chars = cs_subset_string(NeoMutt->sub, "sidebar_delim_chars");
152 if (!c_sidebar_delim_chars)
153 return NULL;
154
155 size_t flen = mutt_str_len(folder);
156 if (flen == 0)
157 return NULL;
158 if (strchr(c_sidebar_delim_chars, folder[flen - 1])) // folder ends with a delimiter
159 flen--;
160
161 size_t mlen = mutt_str_len(mbox);
162 if (mlen < flen)
163 return NULL;
164
165 if (!mutt_strn_equal(folder, mbox, flen))
166 return NULL;
167
168 // After the match, check that mbox has a delimiter
169 if (!strchr(c_sidebar_delim_chars, mbox[flen]))
170 return NULL;
171
172 if (mlen > flen)
173 {
174 return mbox + flen + 1;
175 }
176
177 // mbox and folder are equal, use the chunk after the last delimiter
178 while (mlen--)
179 {
180 if (strchr(c_sidebar_delim_chars, mbox[mlen]))
181 {
182 return mbox + mlen + 1;
183 }
184 }
185
186 return NULL;
187}
188
202static const char *abbrev_url(const char *mbox, enum MailboxType type)
203{
204 /* This is large enough to skip `notmuch://`,
205 * but not so large that it will go past the host part. */
206 const int scheme_len = 10;
207
208 size_t len = mutt_str_len(mbox);
209 if ((len < scheme_len) || ((type != MUTT_NNTP) && (type != MUTT_IMAP) &&
210 (type != MUTT_NOTMUCH) && (type != MUTT_POP)))
211 {
212 return mbox;
213 }
214
215 const char split = (type == MUTT_NOTMUCH) ? '?' : '/';
216
217 // Skip over the scheme, e.g. `imaps://`, `notmuch://`
218 const char *last = strchr(mbox + scheme_len, split);
219 if (last)
220 mbox = last + 1;
221 return mbox;
222}
223
231static size_t add_indent(char *buf, size_t buflen, const struct SbEntry *sbe)
232{
233 size_t res = 0;
234 const char *const c_sidebar_indent_string = cs_subset_string(NeoMutt->sub, "sidebar_indent_string");
235 for (int i = 0; i < sbe->depth; i++)
236 {
237 res += mutt_str_copy(buf + res, c_sidebar_indent_string, buflen - res);
238 }
239 return res;
240}
241
249static const struct AttrColor *calc_color(const struct Mailbox *m, bool current, bool highlight)
250{
251 const struct AttrColor *ac = NULL;
252
253 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
255 mutt_str_equal(mailbox_path(m), c_spool_file))
256 {
258 }
259
261 {
263 }
264
266 {
268 }
269
271 {
273 }
274
276 {
278 }
279
280 const struct AttrColor *ac_bg = simple_color_get(MT_COLOR_NORMAL);
282 ac = merged_color_overlay(ac_bg, ac);
283
284 if (current || highlight)
285 {
286 int color;
287 if (current)
288 {
291 else
292 color = MT_COLOR_INDICATOR;
293 }
294 else
295 {
297 }
298
299 ac = merged_color_overlay(ac, simple_color_get(color));
300 }
301
302 return ac;
303}
304
312static int calc_path_depth(const char *mbox, const char *delims, const char **last_part)
313{
314 if (!mbox || !delims || !last_part)
315 return 0;
316
317 int depth = 0;
318 const char *match = NULL;
319 while ((match = strpbrk(mbox, delims)))
320 {
321 depth++;
322 mbox = match + 1;
323 }
324
325 *last_part = mbox;
326 return depth;
327}
328
350static const char *sidebar_format_str(char *buf, size_t buflen, size_t col, int cols,
351 char op, const char *src, const char *prec,
352 const char *if_str, const char *else_str,
353 intptr_t data, MuttFormatFlags flags)
354{
355 struct SidebarData *sdata = (struct SidebarData *) data;
356 struct SbEntry *sbe = sdata->entry;
357 struct IndexSharedData *shared = sdata->shared;
358 char fmt[256] = { 0 };
359
360 if (!sbe || !shared || !buf)
361 return src;
362
363 buf[0] = '\0'; /* Just in case there's nothing to do */
364
365 struct Mailbox *m = sbe->mailbox;
366 if (!m)
367 return src;
368
369 struct Mailbox *m_cur = shared->mailbox;
370
371 bool c = m_cur && mutt_str_equal(m_cur->realpath, m->realpath);
372
373 bool optional = (flags & MUTT_FORMAT_OPTIONAL);
374
375 switch (op)
376 {
377 case 'a':
378 if (!optional)
379 {
380 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
381 snprintf(buf, buflen, fmt, m->notify_user);
382 }
383 else
384 {
385 if (m->notify_user == 0)
386 optional = false;
387 }
388 break;
389
390 case 'B':
391 case 'D':
392 {
393 char indented[256] = { 0 };
394 size_t ilen = sizeof(indented);
395 size_t off = add_indent(indented, ilen, sbe);
396 snprintf(indented + off, ilen - off, "%s",
397 ((op == 'D') && sbe->mailbox->name) ? sbe->mailbox->name : sbe->box);
398 mutt_format_s(buf, buflen, prec, indented);
399 break;
400 }
401
402 case 'd':
403 if (!optional)
404 {
405 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
406 snprintf(buf, buflen, fmt, c ? m_cur->msg_deleted : 0);
407 }
408 else if ((c && (m_cur->msg_deleted == 0)) || !c)
409 {
410 optional = false;
411 }
412 break;
413
414 case 'F':
415 if (!optional)
416 {
417 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
418 snprintf(buf, buflen, fmt, m->msg_flagged);
419 }
420 else if (m->msg_flagged == 0)
421 {
422 optional = false;
423 }
424 break;
425
426 case 'L':
427 if (!optional)
428 {
429 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
430 snprintf(buf, buflen, fmt, c ? m_cur->vcount : m->msg_count);
431 }
432 else if ((c && (m_cur->vcount == m->msg_count)) || !c)
433 {
434 optional = false;
435 }
436 break;
437
438 case 'N':
439 if (!optional)
440 {
441 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
442 snprintf(buf, buflen, fmt, m->msg_unread);
443 }
444 else if (m->msg_unread == 0)
445 {
446 optional = false;
447 }
448 break;
449
450 case 'n':
451 if (!optional)
452 {
453 snprintf(fmt, sizeof(fmt), "%%%sc", prec);
454 snprintf(buf, buflen, fmt, m->has_new ? 'N' : ' ');
455 }
456 else if (m->has_new == false)
457 {
458 optional = false;
459 }
460 break;
461
462 case 'o':
463 if (!optional)
464 {
465 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
466 snprintf(buf, buflen, fmt, m->msg_unread - m->msg_new);
467 }
468 else if ((c && (m_cur->msg_unread - m_cur->msg_new) == 0) || !c)
469 {
470 optional = false;
471 }
472 break;
473
474 case 'p':
475 if (!optional)
476 {
477 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
478 snprintf(buf, buflen, fmt, m->poll_new_mail);
479 }
480 else
481 {
482 if (m->poll_new_mail == 0)
483 optional = false;
484 }
485 break;
486
487 case 'r':
488 if (!optional)
489 {
490 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
491 snprintf(buf, buflen, fmt, m->msg_count - m->msg_unread);
492 }
493 else if ((c && (m_cur->msg_count - m_cur->msg_unread) == 0) || !c)
494 {
495 optional = false;
496 }
497 break;
498
499 case 'S':
500 if (!optional)
501 {
502 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
503 snprintf(buf, buflen, fmt, m->msg_count);
504 }
505 else if (m->msg_count == 0)
506 {
507 optional = false;
508 }
509 break;
510
511 case 't':
512 if (!optional)
513 {
514 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
515 snprintf(buf, buflen, fmt, c ? m_cur->msg_tagged : 0);
516 }
517 else if ((c && (m_cur->msg_tagged == 0)) || !c)
518 {
519 optional = false;
520 }
521 break;
522
523 case 'Z':
524 if (!optional)
525 {
526 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
527 snprintf(buf, buflen, fmt, m->msg_new);
528 }
529 else if ((c && (m_cur->msg_new) == 0) || !c)
530 {
531 optional = false;
532 }
533 break;
534
535 case '!':
536 if (m->msg_flagged == 0)
537 {
538 mutt_format_s(buf, buflen, prec, "");
539 }
540 else if (m->msg_flagged == 1)
541 {
542 mutt_format_s(buf, buflen, prec, "!");
543 }
544 else if (m->msg_flagged == 2)
545 {
546 mutt_format_s(buf, buflen, prec, "!!");
547 }
548 else
549 {
550 snprintf(fmt, sizeof(fmt), "%d!", m->msg_flagged);
551 mutt_format_s(buf, buflen, prec, fmt);
552 }
553 break;
554 }
555
556 if (optional)
557 {
558 mutt_expando_format(buf, buflen, col, cols, if_str, sidebar_format_str, data, flags);
559 }
560 else if (flags & MUTT_FORMAT_OPTIONAL)
561 {
562 mutt_expando_format(buf, buflen, col, cols, else_str, sidebar_format_str, data, flags);
563 }
564
565 /* We return the format string, unchanged */
566 return src;
567}
568
582static void make_sidebar_entry(char *buf, size_t buflen, int width,
583 struct SbEntry *sbe, struct IndexSharedData *shared)
584{
585 struct SidebarData sdata = { sbe, shared };
586
587 const char *const c_sidebar_format = cs_subset_string(NeoMutt->sub, "sidebar_format");
588 mutt_expando_format(buf, buflen, 0, width, NONULL(c_sidebar_format),
589 sidebar_format_str, (intptr_t) &sdata, MUTT_FORMAT_NO_FLAGS);
590
591 /* Force string to be exactly the right width */
592 int w = mutt_strwidth(buf);
593 int s = mutt_str_len(buf);
594 width = MIN(buflen, width);
595 if (w < width)
596 {
597 /* Pad with spaces */
598 memset(buf + s, ' ', width - w);
599 buf[s + width - w] = '\0';
600 }
601 else if (w > width)
602 {
603 /* Truncate to fit */
604 size_t len = mutt_wstr_trunc(buf, buflen, width, NULL);
605 buf[len] = '\0';
606 }
607}
608
622{
623 /* Aliases for readability */
624 const bool c_sidebar_new_mail_only = cs_subset_bool(NeoMutt->sub, "sidebar_new_mail_only");
625 const bool c_sidebar_non_empty_mailbox_only = cs_subset_bool(NeoMutt->sub, "sidebar_non_empty_mailbox_only");
626 struct SbEntry *sbe = NULL;
627
628 struct IndexSharedData *shared = wdata->shared;
629 struct SbEntry **sbep = NULL;
630 ARRAY_FOREACH(sbep, &wdata->entries)
631 {
632 int i = ARRAY_FOREACH_IDX;
633 sbe = *sbep;
634
635 sbe->is_hidden = false;
636
637 if (!sbe->mailbox->visible)
638 {
639 sbe->is_hidden = true;
640 continue;
641 }
642
643 if (shared->mailbox &&
645 {
646 /* Spool directories are always visible */
647 continue;
648 }
649
652 {
653 /* Explicitly asked to be visible */
654 continue;
655 }
656
657 if (c_sidebar_non_empty_mailbox_only && (i != wdata->opn_index) &&
658 (sbe->mailbox->msg_count == 0))
659 {
660 sbe->is_hidden = true;
661 }
662
663 if (c_sidebar_new_mail_only && (i != wdata->opn_index) &&
664 (sbe->mailbox->msg_unread == 0) && (sbe->mailbox->msg_flagged == 0) &&
665 !sbe->mailbox->has_new)
666 {
667 sbe->is_hidden = true;
668 }
669 }
670}
671
685static bool prepare_sidebar(struct SidebarWindowData *wdata, int page_size)
686{
687 if (ARRAY_EMPTY(&wdata->entries) || (page_size <= 0))
688 return false;
689
690 struct SbEntry **sbep = NULL;
691 const bool c_sidebar_new_mail_only = cs_subset_bool(NeoMutt->sub, "sidebar_new_mail_only");
692 const bool c_sidebar_non_empty_mailbox_only = cs_subset_bool(NeoMutt->sub, "sidebar_non_empty_mailbox_only");
693
694 sbep = (wdata->opn_index >= 0) ? ARRAY_GET(&wdata->entries, wdata->opn_index) : NULL;
695 const struct SbEntry *opn_entry = sbep ? *sbep : NULL;
696 sbep = (wdata->hil_index >= 0) ? ARRAY_GET(&wdata->entries, wdata->hil_index) : NULL;
697 const struct SbEntry *hil_entry = sbep ? *sbep : NULL;
698
700 const short c_sidebar_sort_method = cs_subset_sort(NeoMutt->sub, "sidebar_sort_method");
701 sb_sort_entries(wdata, c_sidebar_sort_method);
702
703 if (opn_entry || hil_entry)
704 {
705 ARRAY_FOREACH(sbep, &wdata->entries)
706 {
707 if ((opn_entry == *sbep) && (*sbep)->mailbox->visible)
708 wdata->opn_index = ARRAY_FOREACH_IDX;
709 if ((hil_entry == *sbep) && (*sbep)->mailbox->visible)
710 wdata->hil_index = ARRAY_FOREACH_IDX;
711 }
712 }
713
714 if ((wdata->hil_index < 0) || (hil_entry && hil_entry->is_hidden) ||
715 (c_sidebar_sort_method != wdata->previous_sort))
716 {
717 if (wdata->opn_index >= 0)
718 {
719 wdata->hil_index = wdata->opn_index;
720 }
721 else
722 {
723 wdata->hil_index = 0;
724 /* Note is_hidden will only be set when `$sidebar_new_mail_only` */
725 if ((*ARRAY_GET(&wdata->entries, 0))->is_hidden && !sb_next(wdata))
726 wdata->hil_index = -1;
727 }
728 }
729
730 /* Set the Top and Bottom to frame the wdata->hil_index in groups of page_size */
731
732 /* If `$sidebar_new_mail_only` or `$sidebar_non_empty_mailbox_only` is set,
733 * some entries may be hidden so we need to scan for the framing interval */
734 if (c_sidebar_new_mail_only || c_sidebar_non_empty_mailbox_only)
735 {
736 wdata->top_index = -1;
737 wdata->bot_index = -1;
738 while (wdata->bot_index < wdata->hil_index)
739 {
740 wdata->top_index = wdata->bot_index + 1;
741 int page_entries = 0;
742 while (page_entries < page_size)
743 {
744 wdata->bot_index++;
745 if (wdata->bot_index >= ARRAY_SIZE(&wdata->entries))
746 break;
747 if (!(*ARRAY_GET(&wdata->entries, wdata->bot_index))->is_hidden)
748 page_entries++;
749 }
750 }
751 }
752 else
753 {
754 /* Otherwise we can just calculate the interval */
755 wdata->top_index = (wdata->hil_index / page_size) * page_size;
756 wdata->bot_index = wdata->top_index + page_size - 1;
757 }
758
759 if (wdata->bot_index > (ARRAY_SIZE(&wdata->entries) - 1))
760 wdata->bot_index = ARRAY_SIZE(&wdata->entries) - 1;
761
762 wdata->previous_sort = c_sidebar_sort_method;
763
764 return (wdata->hil_index >= 0);
765}
766
770int sb_recalc(struct MuttWindow *win)
771{
773 struct IndexSharedData *shared = wdata->shared;
774
775 if (ARRAY_EMPTY(&wdata->entries))
776 {
777 struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
779 struct MailboxNode *np = NULL;
780 STAILQ_FOREACH(np, &ml, entries)
781 {
782 if (np->mailbox->visible)
783 sb_add_mailbox(wdata, np->mailbox);
784 }
786 }
787
788 if (!prepare_sidebar(wdata, win->state.rows))
789 {
790 win->actions |= WA_REPAINT;
791 return 0;
792 }
793
794 int num_rows = win->state.rows;
795 int num_cols = win->state.cols;
796
797 if (ARRAY_EMPTY(&wdata->entries) || (num_rows <= 0))
798 return 0;
799
800 if (wdata->top_index < 0)
801 return 0;
802
803 int width = num_cols - wdata->divider_width;
804 int row = 0;
805 struct Mailbox *m_cur = shared->mailbox;
806 struct SbEntry **sbep = NULL;
807 ARRAY_FOREACH_FROM(sbep, &wdata->entries, wdata->top_index)
808 {
809 if (row >= num_rows)
810 break;
811
812 if ((*sbep)->is_hidden)
813 continue;
814
815 struct SbEntry *entry = (*sbep);
816 struct Mailbox *m = entry->mailbox;
817
818 const int entryidx = ARRAY_FOREACH_IDX;
819 entry->color = calc_color(m, (entryidx == wdata->opn_index),
820 (entryidx == wdata->hil_index));
821
822 if (m_cur && (m_cur->realpath[0] != '\0') &&
823 mutt_str_equal(m->realpath, m_cur->realpath))
824 {
825 m->msg_unread = m_cur->msg_unread;
826 m->msg_count = m_cur->msg_count;
827 m->msg_flagged = m_cur->msg_flagged;
828 }
829
830 const char *path = mailbox_path(m);
831
832 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
833 // Try to abbreviate the full path
834 const char *abbr = abbrev_folder(path, c_folder, m->type);
835 if (!abbr)
836 abbr = abbrev_url(path, m->type);
837 const char *short_path = abbr ? abbr : path;
838
839 /* Compute the depth */
840 const char *last_part = abbr;
841 const char *const c_sidebar_delim_chars = cs_subset_string(NeoMutt->sub, "sidebar_delim_chars");
842 entry->depth = calc_path_depth(abbr, c_sidebar_delim_chars, &last_part);
843
844 const bool short_path_is_abbr = (short_path == abbr);
845 const bool c_sidebar_short_path = cs_subset_bool(NeoMutt->sub, "sidebar_short_path");
846 if (c_sidebar_short_path)
847 {
848 short_path = last_part;
849 }
850
851 // Don't indent if we were unable to create an abbreviation.
852 // Otherwise, the full path will be indent, and it looks unusual.
853 const bool c_sidebar_folder_indent = cs_subset_bool(NeoMutt->sub, "sidebar_folder_indent");
854 if (c_sidebar_folder_indent && short_path_is_abbr)
855 {
856 const short c_sidebar_component_depth = cs_subset_number(NeoMutt->sub, "sidebar_component_depth");
857 if (c_sidebar_component_depth > 0)
858 entry->depth -= c_sidebar_component_depth;
859 }
860 else if (!c_sidebar_folder_indent)
861 {
862 entry->depth = 0;
863 }
864
865 mutt_str_copy(entry->box, short_path, sizeof(entry->box));
866 make_sidebar_entry(entry->display, sizeof(entry->display), width, entry, shared);
867 row++;
868 }
869
870 win->actions |= WA_REPAINT;
871 mutt_debug(LL_DEBUG5, "recalc done, request WA_REPAINT\n");
872 return 0;
873}
874
891static int draw_divider(struct SidebarWindowData *wdata, struct MuttWindow *win,
892 int num_rows, int num_cols)
893{
894 if ((num_rows < 1) || (num_cols < 1) || (wdata->divider_width > num_cols) ||
895 (wdata->divider_width == 0))
896 {
897 return 0;
898 }
899
900 const int width = wdata->divider_width;
901 const char *const c_sidebar_divider_char = cs_subset_string(NeoMutt->sub, "sidebar_divider_char");
902
903 const struct AttrColor *ac = simple_color_get(MT_COLOR_NORMAL);
907
908 const bool c_sidebar_on_right = cs_subset_bool(NeoMutt->sub, "sidebar_on_right");
909 const int col = c_sidebar_on_right ? 0 : (num_cols - width);
910
911 for (int i = 0; i < num_rows; i++)
912 {
913 mutt_window_move(win, col, i);
914
915 if (wdata->divider_type == SB_DIV_USER)
916 mutt_window_addstr(win, NONULL(c_sidebar_divider_char));
917 else
918 mutt_window_addch(win, '|');
919 }
920
922 return width;
923}
924
935static void fill_empty_space(struct MuttWindow *win, int first_row,
936 int num_rows, int div_width, int num_cols)
937{
938 /* Fill the remaining rows with blank space */
939 const struct AttrColor *ac = simple_color_get(MT_COLOR_NORMAL);
942
943 const bool c_sidebar_on_right = cs_subset_bool(NeoMutt->sub, "sidebar_on_right");
944 if (!c_sidebar_on_right)
945 div_width = 0;
946 for (int r = 0; r < num_rows; r++)
947 {
948 mutt_window_move(win, div_width, first_row + r);
950
951 for (int i = 0; i < num_cols; i++)
952 mutt_window_addch(win, ' ');
953 }
954}
955
959int sb_repaint(struct MuttWindow *win)
960{
962 const bool c_sidebar_on_right = cs_subset_bool(NeoMutt->sub, "sidebar_on_right");
963
964 int row = 0;
965 int num_rows = win->state.rows;
966 int num_cols = win->state.cols;
967
968 if (wdata->top_index >= 0)
969 {
970 int col = 0;
971 if (c_sidebar_on_right)
972 col = wdata->divider_width;
973
974 struct SbEntry **sbep = NULL;
975 ARRAY_FOREACH_FROM(sbep, &wdata->entries, wdata->top_index)
976 {
977 if (row >= num_rows)
978 break;
979
980 if ((*sbep)->is_hidden)
981 continue;
982
983 struct SbEntry *entry = (*sbep);
984 mutt_window_move(win, col, row);
986 mutt_window_printf(win, "%s", entry->display);
987 mutt_refresh();
988 row++;
989 }
990 }
991
992 fill_empty_space(win, row, num_rows - row, wdata->divider_width,
993 num_cols - wdata->divider_width);
994 draw_divider(wdata, win, num_rows, num_cols);
995
996 mutt_debug(LL_DEBUG5, "repaint done\n");
997 return 0;
998}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:211
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:73
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
#define ARRAY_FOREACH_FROM(elem, head, from)
Iterate from an index to the end.
Definition: array.h:222
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:108
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:65
@ MT_COLOR_SIDEBAR_NEW
Mailbox with new mail.
Definition: color.h:69
@ MT_COLOR_SIDEBAR_UNREAD
Mailbox with unread mail.
Definition: color.h:72
@ MT_COLOR_INDICATOR
Selected item in list.
Definition: color.h:53
@ MT_COLOR_SIDEBAR_SPOOLFILE
$spool_file (Spool mailbox)
Definition: color.h:71
@ MT_COLOR_SIDEBAR_ORDINARY
Mailbox with no new or flagged messages.
Definition: color.h:70
@ MT_COLOR_SIDEBAR_BACKGROUND
Background colour for the Sidebar.
Definition: color.h:64
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:58
@ MT_COLOR_SIDEBAR_INDICATOR
Current open mailbox.
Definition: color.h:68
@ MT_COLOR_SIDEBAR_HIGHLIGHT
Select cursor.
Definition: color.h:67
@ MT_COLOR_SIDEBAR_FLAGGED
Mailbox with flagged messages.
Definition: color.h:66
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:144
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:267
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
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:394
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:75
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:454
Structs that make up an email.
void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string.
Definition: format.c:215
Flags to control mutt_expando_format()
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
static const char * sidebar_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Format a string for the sidebar - Implements format_t -.
Definition: window.c:350
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t callback, intptr_t data, MuttFormatFlags flags)
Expand expandos (x) in a string -.
Definition: muttlib.c:739
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
int sb_recalc(struct MuttWindow *win)
Recalculate the Sidebar display - Implements MuttWindow::recalc() -.
Definition: window.c:770
int sb_repaint(struct MuttWindow *win)
Repaint the Sidebar display - Implements MuttWindow::repaint() -.
Definition: window.c:959
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:102
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
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
#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:775
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:763
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:497
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
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:653
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:81
void mutt_curses_set_color(const struct AttrColor *ac)
Set the colour and attributes for text.
Definition: mutt_curses.c:40
int mutt_window_printf(struct MuttWindow *win, const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:431
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:297
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:416
int mutt_window_addch(struct MuttWindow *win, int ch)
Write one character to a Window.
Definition: mutt_window.c:388
#define WA_REPAINT
Redraw the contents of the Window.
Definition: mutt_window.h:111
Some miscellaneous functions.
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition: neomutt.c:162
size_t neomutt_mailboxlist_get_all(struct MailboxList *head, struct NeoMutt *n, enum MailboxType type)
Get a List of all Mailboxes.
Definition: neomutt.c:185
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
bool sb_next(struct SidebarWindowData *wdata)
Find the next unhidden Mailbox.
Definition: functions.c:46
GUI display the mailboxes in a side panel.
@ SB_DIV_USER
User configured using $sidebar_divider_char.
Definition: private.h:56
struct ListHead SidebarPinned
List of mailboxes to always display in the sidebar.
Definition: sidebar.c:43
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:170
struct SidebarWindowData * sb_wdata_get(struct MuttWindow *win)
Get the Sidebar data for this window.
Definition: wdata.c:76
static const char * abbrev_url(const char *mbox, enum MailboxType type)
Abbreviate a url-style Mailbox path.
Definition: window.c:202
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:935
static void update_entries_visibility(struct SidebarWindowData *wdata)
Should a SbEntry be displayed in the sidebar?
Definition: window.c:621
static const struct AttrColor * calc_color(const struct Mailbox *m, bool current, bool highlight)
Calculate the colour of a Sidebar row.
Definition: window.c:249
static const char * abbrev_folder(const char *mbox, const char *folder, enum MailboxType type)
Abbreviate a Mailbox path using a folder.
Definition: window.c:138
static size_t add_indent(char *buf, size_t buflen, const struct SbEntry *sbe)
Generate the needed indentation.
Definition: window.c:231
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:312
static bool prepare_sidebar(struct SidebarWindowData *wdata, int page_size)
Prepare the list of SbEntry's for the sidebar display.
Definition: window.c:685
static int imap_is_prefix(const char *folder, const char *mbox)
Check if folder matches the beginning of mbox.
Definition: window.c:99
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:891
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:582
#define NONULL(x)
Definition: string2.h:37
A curses colour and its attributes.
Definition: attr.h:66
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:153
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:154
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:114
char * name
A short name for the Mailbox.
Definition: mailbox.h:82
bool notify_user
Notify the user of new mail.
Definition: mailbox.h:112
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:93
bool visible
True if a result of "mailboxes".
Definition: mailbox.h:129
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:127
void * wdata
Private data.
Definition: mutt_window.h:145
WindowActionFlags actions
Actions to be performed, e.g. WA_RECALC.
Definition: mutt_window.h:132
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
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:88
struct IndexSharedData * shared
Shared Index Data.
Definition: window.c:90
struct SbEntry * entry
Info about a folder.
Definition: window.c:89
Sidebar private Window data -.
Definition: private.h:64
short previous_sort
Old $sidebar_sort_method
Definition: private.h:74
int top_index
First mailbox visible in sidebar.
Definition: private.h:69
short divider_width
Width of the divider in screen columns.
Definition: private.h:76
int bot_index
Last mailbox visible in sidebar.
Definition: private.h:72
int hil_index
Highlighted mailbox.
Definition: private.h:71
enum DivType divider_type
Type of divider to use, e.g. SB_DIV_ASCII.
Definition: private.h:75
struct IndexSharedData * shared
Shared Index Data.
Definition: private.h:66
int opn_index
Current (open) mailbox.
Definition: private.h:70
struct MuttWindow * win
Sidebar Window.
Definition: private.h:65
struct SbEntryArray entries
Items to display in the sidebar.
Definition: private.h:67
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:238
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition: url.c:123