NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
node_padding.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <stdio.h>
32#include "mutt/lib.h"
33#include "gui/lib.h"
34#include "node_padding.h"
35#include "definition.h"
36#include "node.h"
37#include "node_container.h"
38#include "parse.h"
39#include "render.h"
40
47{
49
50 priv->pad_type = pad_type;
51
52 return priv;
53}
54
60{
61 if (!ptr || !*ptr)
62 return;
63
64 FREE(ptr);
65}
66
75int pad_string(const struct ExpandoNode *node, struct Buffer *buf, int max_cols)
76{
77 const int pad_len = mutt_str_len(node->text);
78 const int pad_cols = mutt_strnwidth(node->text, pad_len);
79 int total_cols = 0;
80
81 if (pad_len != 0)
82 {
83 while (pad_cols <= max_cols)
84 {
85 buf_addstr_n(buf, node->text, pad_len);
86
87 max_cols -= pad_cols;
88 total_cols += pad_cols;
89 }
90 }
91
92 if (max_cols > 0)
93 {
94 buf_add_printf(buf, "%*s", max_cols, "");
95 total_cols += max_cols;
96 }
97
98 return total_cols;
99}
100
105 const struct ExpandoRenderCallback *erc, struct Buffer *buf,
106 int max_cols, void *data, MuttFormatFlags flags)
107{
108 struct ExpandoNode *left = node_get_child(node, ENP_LEFT);
109
110 int total_cols = node_render(left, erc, buf, max_cols, data, flags);
111
112 total_cols += pad_string(node, buf, max_cols - total_cols);
113
114 return total_cols;
115}
116
124 const struct ExpandoRenderCallback *erc, struct Buffer *buf,
125 int max_cols, void *data, MuttFormatFlags flags)
126{
127 struct Buffer *buf_left = buf_pool_get();
128 struct Buffer *buf_pad = buf_pool_get();
129 struct Buffer *buf_right = buf_pool_get();
130
131 int cols_used = 0;
132
133 struct ExpandoNode *left = node_get_child(node, ENP_LEFT);
134 if (left)
135 cols_used += node_render(left, erc, buf_left, max_cols - cols_used, data, flags);
136
137 struct ExpandoNode *right = node_get_child(node, ENP_RIGHT);
138 if (right)
139 cols_used += node_render(right, erc, buf_right, max_cols - cols_used, data, flags);
140
141 if (max_cols > cols_used)
142 cols_used += pad_string(node, buf_pad, max_cols - cols_used);
143
144 buf_addstr(buf, buf_string(buf_left));
145 buf_addstr(buf, buf_string(buf_pad));
146 buf_addstr(buf, buf_string(buf_right));
147
148 buf_pool_release(&buf_left);
149 buf_pool_release(&buf_pad);
150 buf_pool_release(&buf_right);
151
152 return cols_used;
153}
154
162 const struct ExpandoRenderCallback *erc, struct Buffer *buf,
163 int max_cols, void *data, MuttFormatFlags flags)
164{
165 struct Buffer *buf_left = buf_pool_get();
166 struct Buffer *buf_pad = buf_pool_get();
167 struct Buffer *buf_right = buf_pool_get();
168
169 int cols_used = 0;
170
171 struct ExpandoNode *right = node_get_child(node, ENP_RIGHT);
172 if (right)
173 cols_used += node_render(right, erc, buf_right, max_cols - cols_used, data, flags);
174
175 struct ExpandoNode *left = node_get_child(node, ENP_LEFT);
176 if (left)
177 cols_used += node_render(left, erc, buf_left, max_cols - cols_used, data, flags);
178
179 if (max_cols > cols_used)
180 cols_used += pad_string(node, buf_pad, max_cols - cols_used);
181
182 buf_addstr(buf, buf_string(buf_left));
183 buf_addstr(buf, buf_string(buf_pad));
184 buf_addstr(buf, buf_string(buf_right));
185
186 buf_pool_release(&buf_left);
187 buf_pool_release(&buf_pad);
188 buf_pool_release(&buf_right);
189
190 return cols_used;
191}
192
201 const char *start, const char *end)
202{
203 struct ExpandoNode *node = node_new();
204
205 node->type = ENT_PADDING;
206 node->text = mutt_strn_dup(start, end - start);
207
208 switch (pad_type)
209 {
210 case EPT_FILL_EOL:
212 break;
213 case EPT_HARD_FILL:
215 break;
216 case EPT_SOFT_FILL:
218 break;
219 };
220
221 node->ndata = node_padding_private_new(pad_type);
223
224 return node;
225}
226
233struct ExpandoNode *node_padding_parse(const char *str, struct ExpandoFormat *fmt,
234 int did, int uid, ExpandoParserFlags flags,
235 const char **parsed_until,
236 struct ExpandoParseError *err)
237{
238 if (fmt)
239 {
240 // L10N: Padding expandos, %* %> %|, don't use formatting, e.g. %-30x
241 snprintf(err->message, sizeof(err->message), _("Padding cannot be formatted"));
242 err->position = str;
243 return NULL;
244 }
245
246 if (flags & EP_CONDITIONAL)
247 {
248 snprintf(err->message, sizeof(err->message),
249 // L10N: Conditional Expandos can only depend on other Expandos
250 // e.g. "%<X?apple>" displays "apple" if "%X" is true.
251 _("Padding cannot be used as a condition"));
252 err->position = str;
253 return NULL;
254 }
255
256 enum ExpandoPadType pt = 0;
257 if (*str == '|')
258 {
259 pt = EPT_FILL_EOL;
260 }
261 else if (*str == '>')
262 {
263 pt = EPT_HARD_FILL;
264 }
265 else if (*str == '*')
266 {
267 pt = EPT_SOFT_FILL;
268 }
269 else
270 {
271 return NULL;
272 }
273 str++;
274
275 size_t consumed = mutt_mb_charlen(str, NULL);
276 if (consumed == 0)
277 {
278 str = " "; // Default to a space
279 consumed = 1;
280 }
281
282 *parsed_until = str + consumed;
283 return node_padding_new(pt, str, str + consumed);
284}
285
291{
292 if (!ptr || !*ptr)
293 return;
294
295 struct ExpandoNode *parent = *ptr;
296 struct ExpandoNode **np = NULL;
297 ARRAY_FOREACH(np, &parent->children)
298 {
299 if (!np || !*np)
300 continue;
301
302 // Repad any children, recursively
304
305 struct ExpandoNode *node = *np;
306 if (node->type != ENT_PADDING)
307 continue;
308
309 struct ExpandoNode *node_left = node_container_new();
310 struct ExpandoNode *node_right = node_container_new();
311
312 if (ARRAY_FOREACH_IDX_np > 0)
313 {
314 for (int i = 0; i < ARRAY_FOREACH_IDX_np; i++)
315 {
316 node_add_child(node_left, node_get_child(parent, i));
317 }
318 }
319
320 size_t count = ARRAY_SIZE(&parent->children);
321 if ((ARRAY_FOREACH_IDX_np + 1) < count)
322 {
323 for (int i = ARRAY_FOREACH_IDX_np + 1; i < count; i++)
324 {
325 node_add_child(node_right, node_get_child(parent, i));
326 }
327 }
328
329 // All the children have been transferred
330 ARRAY_FREE(&parent->children);
331
332 node_add_child(node, node_left);
333 node_add_child(node, node_right);
334
335 node_add_child(parent, node);
336
337 break; // Only repad the first padding node
338 }
339}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:214
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:204
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:204
size_t buf_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition buffer.c:96
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
size_t mutt_strnwidth(const char *s, size_t n)
Measure a string's width in screen cells.
Definition curs_lib.c:458
Define an Expando format string.
uint8_t ExpandoParserFlags
Flags for expando_parse(), e.g. EP_CONDITIONAL.
Definition definition.h:33
#define EP_CONDITIONAL
Expando is being used as a condition.
Definition definition.h:35
Expando Parsing.
struct ExpandoNode * node_padding_parse(const char *str, struct ExpandoFormat *fmt, int did, int uid, ExpandoParserFlags flags, const char **parsed_until, struct ExpandoParseError *err)
Parse a Padding Expando - Implements ExpandoDefinition::parse() -.
int node_padding_render_eol(const struct ExpandoNode *node, const struct ExpandoRenderCallback *erc, struct Buffer *buf, int max_cols, void *data, MuttFormatFlags flags)
Render End-of-Line Padding - Implements ExpandoNode::render() -.
int node_padding_render_soft(const struct ExpandoNode *node, const struct ExpandoRenderCallback *erc, struct Buffer *buf, int max_cols, void *data, MuttFormatFlags flags)
Render Soft Padding - Implements ExpandoNode::render() -.
int node_padding_render_hard(const struct ExpandoNode *node, const struct ExpandoRenderCallback *erc, struct Buffer *buf, int max_cols, void *data, MuttFormatFlags flags)
Render Hard Padding - Implements ExpandoNode::render() -.
Convenience wrapper for the gui headers.
int mutt_mb_charlen(const char *s, int *width)
Count the bytes in a (multibyte) character.
Definition mbyte.c:55
#define FREE(x)
Definition memory.h:62
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:47
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition string.c:382
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:498
struct ExpandoNode * node_new(void)
Create a new empty ExpandoNode.
Definition node.c:39
struct ExpandoNode * node_get_child(const struct ExpandoNode *node, int index)
Get a child of an ExpandoNode.
Definition node.c:91
void node_add_child(struct ExpandoNode *node, struct ExpandoNode *child)
Add a child to an ExpandoNode.
Definition node.c:76
Basic Expando Node.
@ ENT_PADDING
Padding: soft, hard, EOL.
Definition node.h:40
struct ExpandoNode * node_container_new(void)
Create a new Container ExpandoNode.
Expando Node for a Container.
void node_padding_private_free(void **ptr)
Free Padding private data - Implements ExpandoNode::ndata_free()
void node_padding_repad(struct ExpandoNode **ptr)
Rearrange Padding in a tree of ExpandoNodes.
int pad_string(const struct ExpandoNode *node, struct Buffer *buf, int max_cols)
Pad a buffer with a character.
struct NodePaddingPrivate * node_padding_private_new(enum ExpandoPadType pad_type)
Create new Padding private data.
struct ExpandoNode * node_padding_new(enum ExpandoPadType pad_type, const char *start, const char *end)
Creata new Padding ExpandoNode.
Expando Node for Padding.
@ ENP_LEFT
Index of Left-Hand Nodes.
@ ENP_RIGHT
Index of Right-Hand Nodes.
ExpandoPadType
Padding type.
@ EPT_FILL_EOL
Fill to the end-of-line.
@ EPT_SOFT_FILL
Soft-fill: right-hand-side will be truncated.
@ EPT_HARD_FILL
Hard-fill: left-hand-side will be truncated.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
int node_render(const struct ExpandoNode *node, const struct ExpandoRenderCallback *erc, struct Buffer *buf, int max_cols, void *data, MuttFormatFlags flags)
Render a tree of ExpandoNodes into a string.
Definition render.c:45
Render Expandos using Data.
uint8_t MuttFormatFlags
Flags for expando_render(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition render.h:32
String manipulation buffer.
Definition buffer.h:36
Formatting information for an Expando.
Definition node.h:53
Basic Expando Node.
Definition node.h:67
int uid
Unique ID, e.g. ED_EMA_SIZE.
Definition node.h:70
void * ndata
Private node data.
Definition node.h:77
int(* render)(const struct ExpandoNode *node, const struct ExpandoRenderCallback *erc, struct Buffer *buf, int max_cols, void *data, MuttFormatFlags flags)
Definition node.h:92
int did
Domain ID, e.g. ED_EMAIL.
Definition node.h:69
const char * text
Node-specific text.
Definition node.h:73
enum ExpandoNodeType type
Type of Node, e.g. ENT_EXPANDO.
Definition node.h:68
void(* ndata_free)(void **ptr)
Function to free the private node data.
Definition node.h:78
struct ExpandoNodeArray children
Children nodes.
Definition node.h:75
Buffer for parsing errors.
Definition parse.h:37
char message[1024]
Error message.
Definition parse.h:38
const char * position
Position of error in original string.
Definition parse.h:39
Private data for a Padding Node -.
enum ExpandoPadType pad_type
Padding type.