NeoMutt  2020-11-20
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 <string.h>
34 #include "mutt/lib.h"
35 #include "gui/lib.h"
36 #include "progress.h"
37 #include "mutt_globals.h"
38 #include "mutt_logging.h"
39 #include "muttlib.h"
40 #include "options.h"
41 
42 /* These Config Variables are only used in progress.c */
43 short C_TimeInc;
44 short C_ReadInc;
45 short C_WriteInc;
46 short C_NetInc;
47 
54 static void message_bar(int percent, const char *fmt, ...)
55 {
56  if (!fmt || !MessageWindow)
57  return;
58 
59  va_list ap;
60  char buf[256], buf2[256];
61  int w = (percent * MessageWindow->state.cols) / 100;
62  size_t l;
63 
64  va_start(ap, fmt);
65  vsnprintf(buf, sizeof(buf), fmt, ap);
66  l = mutt_strwidth(buf);
67  va_end(ap);
68 
69  mutt_simple_format(buf2, sizeof(buf2), 0, MessageWindow->state.cols - 2,
70  JUSTIFY_LEFT, 0, buf, sizeof(buf), false);
71 
73 
74  if (Colors->defs[MT_COLOR_PROGRESS] == 0)
75  {
76  mutt_window_addstr(buf2);
77  }
78  else
79  {
80  if (l < w)
81  {
82  /* The string fits within the colour bar */
84  mutt_window_addstr(buf2);
85  w -= l;
86  while (w-- > 0)
87  {
88  mutt_window_addch(' ');
89  }
91  }
92  else
93  {
94  /* The string is too long for the colour bar */
95  int off = mutt_wstr_trunc(buf2, sizeof(buf2), w, NULL);
96 
97  char ch = buf2[off];
98  buf2[off] = '\0';
100  mutt_window_addstr(buf2);
101  buf2[off] = ch;
103  mutt_window_addstr(&buf2[off]);
104  }
105  }
106 
107  clrtoeol();
108  mutt_refresh();
109 }
110 
116 static size_t progress_choose_increment(enum ProgressType type)
117 {
118  static short *incs[] = { &C_ReadInc, &C_WriteInc, &C_NetInc };
119  return (type >= mutt_array_size(incs)) ? 0 : *incs[type];
120 }
121 
128 static bool progress_pos_needs_update(const struct Progress *progress, long pos)
129 {
130  const unsigned shift = progress->is_bytes ? 10 : 0;
131  return pos >= (progress->pos + (progress->inc << shift));
132 }
133 
140 static bool progress_time_needs_update(const struct Progress *progress, size_t now)
141 {
142  const size_t elapsed = (now - progress->timestamp);
143  return (C_TimeInc == 0) || (now < progress->timestamp) || (C_TimeInc < elapsed);
144 }
145 
153 void mutt_progress_init(struct Progress *progress, const char *msg,
154  enum ProgressType type, size_t size)
155 {
156  if (!progress || OptNoCurses)
157  return;
158 
159  /* Initialize Progress structure */
160  memset(progress, 0, sizeof(struct Progress));
161  mutt_str_copy(progress->msg, msg, sizeof(progress->msg));
162  progress->size = size;
163  progress->inc = progress_choose_increment(type);
164  progress->is_bytes = (type == MUTT_PROGRESS_NET);
165 
166  /* Generate the size string, if a total size was specified */
167  if (progress->size != 0)
168  {
169  if (progress->is_bytes)
170  {
171  mutt_str_pretty_size(progress->sizestr, sizeof(progress->sizestr),
172  progress->size);
173  }
174  else
175  {
176  snprintf(progress->sizestr, sizeof(progress->sizestr), "%zu", progress->size);
177  }
178  }
179 
180  if (progress->inc == 0)
181  {
182  /* This progress bar does not increment - write the initial message */
183  if (progress->size == 0)
184  {
185  mutt_message(progress->msg);
186  }
187  else
188  {
189  mutt_message("%s (%s)", progress->msg, progress->sizestr);
190  }
191  }
192  else
193  {
194  /* This progress bar does increment - perform the initial update */
195  mutt_progress_update(progress, 0, 0);
196  }
197 }
198 
212 void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
213 {
214  if (OptNoCurses)
215  return;
216 
217  const uint64_t now = mutt_date_epoch_ms();
218 
219  const bool update = (pos == 0) /* always show the first update */ ||
220  (progress_pos_needs_update(progress, pos) &&
221  progress_time_needs_update(progress, now));
222 
223  if (progress->inc != 0 && update)
224  {
225  progress->pos = pos;
226  progress->timestamp = now;
227 
228  char posstr[128];
229  if (progress->is_bytes)
230  {
231  const size_t round_pos =
232  (progress->pos / (progress->inc << 10)) * (progress->inc << 10);
233  mutt_str_pretty_size(posstr, sizeof(posstr), round_pos);
234  }
235  else
236  {
237  snprintf(posstr, sizeof(posstr), "%zu", progress->pos);
238  }
239 
240  mutt_debug(LL_DEBUG4, "updating progress: %s\n", posstr);
241 
242  if (progress->size != 0)
243  {
244  if (percent < 0)
245  {
246  percent = 100.0 * progress->pos / progress->size;
247  }
248  message_bar(percent, "%s %s/%s (%d%%)", progress->msg, posstr,
249  progress->sizestr, percent);
250  }
251  else
252  {
253  if (percent > 0)
254  message_bar(percent, "%s %s (%d%%)", progress->msg, posstr, percent);
255  else
256  mutt_message("%s %s", progress->msg, posstr);
257  }
258  }
259 
260  if (progress->pos >= progress->size)
262 }
Convenience wrapper for the gui headers.
Progress tracks bytes, according to $net_inc
Definition: progress.h:44
Log at debug level 4.
Definition: logging.h:43
ProgressType
What kind of operation is this progress tracking?
Definition: progress.h:40
Progress bar.
Definition: color.h:79
uint64_t mutt_date_epoch_ms(void)
Return the number of milliseconds since the Unix epoch.
Definition: date.c:425
Left justify the text.
Definition: curs_lib.h:47
size_t size
Definition: progress.h:55
bool is_bytes
Definition: progress.h:58
#define mutt_message(...)
Definition: logging.h:83
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:57
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:131
NeoMutt Logging.
static void message_bar(int percent, const char *fmt,...)
Draw a colourful progress bar.
Definition: progress.c:54
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:48
static bool progress_pos_needs_update(const struct Progress *progress, long pos)
Do we need to update, given the current pos?
Definition: progress.c:128
A progress bar.
Definition: progress.h:50
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:382
Some miscellaneous functions.
#define mutt_array_size(x)
Definition: memory.h:33
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
size_t pos
Definition: progress.h:54
Progress bar.
Plain text.
Definition: color.h:77
short C_ReadInc
Config: Update the progress bar after this many records read (0 to disable)
Definition: progress.c:44
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:108
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:120
struct MuttWindow * MessageWindow
Message Window, ":set", etc.
Definition: mutt_window.c:47
static size_t progress_choose_increment(enum ProgressType type)
Choose the right increment given a ProgressType.
Definition: progress.c:116
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1359
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1659
size_t inc
Definition: progress.h:56
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:1309
char msg[1024]
Definition: progress.h:52
void mutt_progress_init(struct Progress *progress, const char *msg, enum ProgressType type, size_t size)
Set up a progress bar.
Definition: progress.c:153
uint64_t timestamp
Definition: progress.h:57
Definition: color.h:129
static bool progress_time_needs_update(const struct Progress *progress, size_t now)
Do we need to update, given the current time?
Definition: progress.c:140
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:492
short C_WriteInc
Config: Update the progress bar after this many records written (0 to disable)
Definition: progress.c:45
short C_NetInc
Config: (socket) Update the progress bar after this many KB sent/received (0 to disable) ...
Definition: progress.c:46
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:716
short C_TimeInc
Config: Frequency of progress bar updates (milliseconds)
Definition: progress.c:43
char sizestr[24]
Definition: progress.h:53
int mutt_window_addstr(const char *str)
Write a string to a Window.
Definition: mutt_window.c:522
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Convenience wrapper for the library headers.
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:1093