NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
progress.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <stdarg.h>
32 #include <stdbool.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include "mutt/lib.h"
36 #include "config/lib.h"
37 #include "core/lib.h"
38 #include "gui/lib.h"
39 #include "lib.h"
40 #include "mutt_logging.h"
41 #include "muttlib.h"
42 #include "options.h"
43 
47 struct Progress
48 {
49  struct MuttWindow *win;
50  char msg[1024];
51  char sizestr[24];
52  size_t pos;
53  size_t size;
54  size_t inc;
55  uint64_t timestamp;
56  bool is_bytes;
57 };
58 
66 static void message_bar(struct MuttWindow *win, int percent, const char *fmt, ...)
67 {
68  if (!fmt || !win)
69  return;
70 
71  va_list ap;
72  char buf[256], buf2[256];
73  int w = (percent * win->state.cols) / 100;
74  size_t l;
75 
76  va_start(ap, fmt);
77  vsnprintf(buf, sizeof(buf), fmt, ap);
78  l = mutt_strwidth(buf);
79  va_end(ap);
80 
81  mutt_simple_format(buf2, sizeof(buf2), 0, win->state.cols - 2, JUSTIFY_LEFT,
82  0, buf, sizeof(buf), false);
83 
84  mutt_window_move(win, 0, 0);
85 
86  if (mutt_color(MT_COLOR_PROGRESS) == 0)
87  {
88  mutt_window_addstr(win, buf2);
89  }
90  else
91  {
92  if (l < w)
93  {
94  /* The string fits within the colour bar */
96  mutt_window_addstr(win, buf2);
97  w -= l;
98  while (w-- > 0)
99  {
100  mutt_window_addch(win, ' ');
101  }
103  }
104  else
105  {
106  /* The string is too long for the colour bar */
107  int off = mutt_wstr_trunc(buf2, sizeof(buf2), w, NULL);
108 
109  char ch = buf2[off];
110  buf2[off] = '\0';
112  mutt_window_addstr(win, buf2);
113  buf2[off] = ch;
115  mutt_window_addstr(win, &buf2[off]);
116  }
117  }
118 
120  mutt_refresh();
121 }
122 
128 static size_t choose_increment(enum ProgressType type)
129 {
130  const short c_read_inc = cs_subset_number(NeoMutt->sub, "read_inc");
131  const short c_write_inc = cs_subset_number(NeoMutt->sub, "write_inc");
132  const short c_net_inc = cs_subset_number(NeoMutt->sub, "net_inc");
133  const short *incs[] = { &c_read_inc, &c_write_inc, &c_net_inc };
134  return (type >= mutt_array_size(incs)) ? 0 : *incs[type];
135 }
136 
143 static bool pos_needs_update(const struct Progress *progress, long pos)
144 {
145  const unsigned shift = progress->is_bytes ? 10 : 0;
146  return pos >= (progress->pos + (progress->inc << shift));
147 }
148 
155 static bool time_needs_update(const struct Progress *progress, size_t now)
156 {
157  const size_t elapsed = (now - progress->timestamp);
158  const short c_time_inc = cs_subset_number(NeoMutt->sub, "time_inc");
159  return (c_time_inc == 0) || (now < progress->timestamp) || (c_time_inc < elapsed);
160 }
161 
175 void progress_update(struct Progress *progress, size_t pos, int percent)
176 {
177  if (!progress || OptNoCurses)
178  return;
179 
180  const uint64_t now = mutt_date_epoch_ms();
181 
182  const bool update =
183  (pos == 0) /* always show the first update */ ||
184  (pos_needs_update(progress, pos) && time_needs_update(progress, now));
185 
186  if ((progress->inc != 0) && update)
187  {
188  progress->pos = pos;
189  progress->timestamp = now;
190 
191  char posstr[128];
192  if (progress->is_bytes)
193  {
194  const size_t round_pos =
195  (progress->pos / (progress->inc << 10)) * (progress->inc << 10);
196  mutt_str_pretty_size(posstr, sizeof(posstr), round_pos);
197  }
198  else
199  {
200  snprintf(posstr, sizeof(posstr), "%zu", progress->pos);
201  }
202 
203  mutt_debug(LL_DEBUG4, "updating progress: %s\n", posstr);
204 
205  if (progress->size != 0)
206  {
207  if (percent < 0)
208  {
209  percent = 100.0 * progress->pos / progress->size;
210  }
211  message_bar(progress->win, percent, "%s %s/%s (%d%%)", progress->msg,
212  posstr, progress->sizestr, percent);
213  }
214  else
215  {
216  if (percent > 0)
217  message_bar(progress->win, percent, "%s %s (%d%%)", progress->msg, posstr, percent);
218  else
219  mutt_message("%s %s", progress->msg, posstr);
220  }
221  }
222 }
223 
228 void progress_free(struct Progress **ptr)
229 {
230  if (!ptr || !*ptr)
231  return;
232 
234  // struct Progress *progress = *ptr;
235 
236  FREE(ptr);
237 }
238 
246 struct Progress *progress_new(const char *msg, enum ProgressType type, size_t size)
247 {
248  if (OptNoCurses)
249  return NULL;
250 
251  struct Progress *progress = mutt_mem_calloc(1, sizeof(struct Progress));
252 
253  /* Initialize Progress structure */
254  progress->win = msgwin_get_window();
255  mutt_str_copy(progress->msg, msg, sizeof(progress->msg));
256  progress->size = size;
257  progress->inc = choose_increment(type);
258  progress->is_bytes = (type == MUTT_PROGRESS_NET);
259 
260  /* Generate the size string, if a total size was specified */
261  if (progress->size != 0)
262  {
263  if (progress->is_bytes)
264  {
265  mutt_str_pretty_size(progress->sizestr, sizeof(progress->sizestr),
266  progress->size);
267  }
268  else
269  {
270  snprintf(progress->sizestr, sizeof(progress->sizestr), "%zu", progress->size);
271  }
272  }
273 
274  if (progress->inc == 0)
275  {
276  /* This progress bar does not increment - write the initial message */
277  if (progress->size == 0)
278  {
279  mutt_message(progress->msg);
280  }
281  else
282  {
283  mutt_message("%s (%s)", progress->msg, progress->sizestr);
284  }
285  }
286  else
287  {
288  /* This progress bar does increment - perform the initial update */
289  progress_update(progress, 0, 0);
290  }
291  return progress;
292 }
Convenience wrapper for the gui headers.
Log at debug level 4.
Definition: logging.h:43
Progress bar.
Definition: color.h:60
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
uint64_t mutt_date_epoch_ms(void)
Return the number of milliseconds since the Unix epoch.
Definition: date.c:436
Left justify the text.
Definition: curs_lib.h:43
static void message_bar(struct MuttWindow *win, int percent, const char *fmt,...)
Draw a colourful progress bar.
Definition: progress.c:66
size_t size
Total expected size.
Definition: progress.c:53
bool is_bytes
true if measuring bytes
Definition: progress.c:56
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:56
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:259
NeoMutt Logging.
ProgressType
What kind of operation is this progress tracking?
Definition: lib.h:44
static bool pos_needs_update(const struct Progress *progress, long pos)
Do we need to update, given the current pos?
Definition: progress.c:143
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:47
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:246
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
A Progress Bar.
Definition: progress.c:47
Convenience wrapper for the config headers.
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:310
Some miscellaneous functions.
#define mutt_array_size(x)
Definition: memory.h:33
struct MuttWindow * msgwin_get_window(void)
Get the Message Window pointer.
Definition: msgwin.c:253
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:434
Convenience wrapper for the core headers.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
size_t pos
Current postion.
Definition: progress.c:52
Plain text.
Definition: color.h:58
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
static bool time_needs_update(const struct Progress *progress, size_t now)
Do we need to update, given the current time?
Definition: progress.c:155
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:115
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
static size_t choose_increment(enum ProgressType type)
Choose the right increment given a ProgressType.
Definition: progress.c:128
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:983
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1679
size_t inc
Increment size.
Definition: progress.c:54
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:933
char msg[1024]
Message to display.
Definition: progress.c:50
Progress tracks bytes, according to $net_inc
Definition: lib.h:48
void progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:175
uint64_t timestamp
Time of last update.
Definition: progress.c:55
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
int mutt_color(enum ColorId id)
Return the color of an object.
Definition: color.c:1427
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:749
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:228
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
char sizestr[24]
String for percentage/size.
Definition: progress.c:51
Handling of global boolean variables.
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Convenience wrapper for the library headers.
enum WindowType type
Window type, e.g. WT_SIDEBAR.
Definition: mutt_window.h:144
struct MuttWindow * win
Window to draw on.
Definition: progress.c:49
int mutt_window_addch(struct MuttWindow *win, int ch)
Write one character to a Window.
Definition: mutt_window.c:402
void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width, enum FormatJustify justify, char pad_char, const char *s, size_t n, bool arboreal)
Format a string, like snprintf()
Definition: curs_lib.c:716