Skip to content

Commit 98da4b0

Browse files
committed
sheet: Add extension API for transforming the current file
1 parent cda7a61 commit 98da4b0

File tree

6 files changed

+142
-0
lines changed

6 files changed

+142
-0
lines changed

app/cli.c

+6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#ifdef ZSVSHEET_BUILD
2525
#include "sheet/sheet_internal.h"
2626
#include "sheet/handlers_internal.h"
27+
#include "sheet/transformation.h"
2728
#endif
2829
#include "sheet/procedure.h"
2930
#include "sheet/key-bindings.h"
@@ -399,6 +400,11 @@ static struct zsv_ext_callbacks *zsv_ext_callbacks_init(struct zsv_ext_callbacks
399400
e->ext_sheet_open_file = zsvsheet_open_file;
400401
e->ext_sheet_register_proc = zsvsheet_register_proc;
401402
e->ext_sheet_register_proc_key_binding = zsvsheet_register_proc_key_binding;
403+
e->ext_sheet_push_transformation = zsvsheet_push_transformation;
404+
e->ext_sheet_transformation_writer = zsvsheet_transformation_writer;
405+
e->ext_sheet_transformation_parser = zsvsheet_transformation_parser;
406+
e->ext_sheet_transformation_filename = zsvsheet_transformation_filename;
407+
e->ext_sheet_transformation_user_context = zsvsheet_transformation_user_context;
402408
#endif
403409
}
404410
return e;

app/ext_example/my_extension.c

+44
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,45 @@ zsvsheet_status my_test_command_handler(zsvsheet_proc_context_t ctx) {
107107
}
108108
return zsvsheet_status_ok;
109109
}
110+
111+
struct transformation_context {
112+
size_t col_count;
113+
size_t row_count;
114+
};
115+
116+
// Similar to a regular ZSV row handler used in ext_parse_all
117+
void my_transformation_row_handler(void *ctx) {
118+
zsvsheet_transformation trn = ctx;
119+
struct transformation_context *priv = zsv_cb.ext_sheet_transformation_user_context(trn);
120+
zsv_parser parser = zsv_cb.ext_sheet_transformation_parser(trn);
121+
zsv_csv_writer writer = zsv_cb.ext_sheet_transformation_writer(trn);
122+
123+
size_t j = zsv_cb.cell_count(parser);
124+
for (size_t i = 0; i < j; i++) {
125+
struct zsv_cell c = zsv_cb.get_cell(parser, i);
126+
zsv_writer_cell(writer, i == 0, c.str, c.len, c.quoted);
127+
}
128+
129+
priv->col_count += j;
130+
131+
if (!priv->row_count)
132+
zsv_writer_cell_s(writer, 0, (const unsigned char *)"Column count", 0);
133+
else
134+
zsv_writer_cell_zu(writer, 0, priv->col_count);
135+
136+
priv->row_count++;
137+
}
138+
139+
zsvsheet_status my_transformation_command_handler(zsvsheet_proc_context_t ctx) {
140+
struct transformation_context my_ctx = {
141+
.col_count = 0,
142+
.row_count = 0,
143+
};
144+
145+
// TODO: This probably should happen in another worker thread and while that is happening the status should display
146+
// that some work is in progress. The extension author will maybe want to have control over the status message.
147+
return zsv_cb.ext_sheet_push_transformation(ctx, &my_ctx, my_transformation_row_handler);
148+
}
110149
#endif
111150

112151
/**
@@ -141,6 +180,11 @@ enum zsv_ext_status zsv_ext_init(struct zsv_ext_callbacks *cb, zsv_execution_con
141180
if (proc_id < 0)
142181
return zsv_ext_status_error;
143182
zsv_cb.ext_sheet_register_proc_key_binding('t', proc_id);
183+
184+
proc_id = zsv_cb.ext_sheet_register_proc("my-transformation", "my transformation", my_transformation_command_handler);
185+
if (proc_id < 0)
186+
return zsv_ext_status_error;
187+
zsv_cb.ext_sheet_register_proc_key_binding('T', proc_id);
144188
#endif
145189
return zsv_ext_status_ok;
146190
}

app/sheet/handlers.c

+54
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,57 @@ struct zsv_opts zsvsheet_buffer_get_zsv_opts(zsvsheet_buffer_t h) {
126126
struct zsv_opts opts = {0};
127127
return opts;
128128
}
129+
130+
enum zsvsheet_status zsvsheet_push_transformation(zsvsheet_proc_context_t ctx, void *user_context,
131+
void (*row_handler)(void *exec_ctx)) {
132+
zsvsheet_buffer_t buff = zsvsheet_buffer_current(ctx);
133+
const char *filename = zsvsheet_buffer_data_filename(buff);
134+
enum zsvsheet_status stat = zsvsheet_status_error;
135+
136+
if (!filename)
137+
filename = zsvsheet_buffer_filename(buff);
138+
139+
// TODO: custom_prop_handler is not passed to extensions?
140+
struct zsvsheet_transformation_opts opts = {
141+
.custom_prop_handler = NULL,
142+
.input_filename = filename,
143+
};
144+
zsvsheet_transformation trn;
145+
struct zsv_opts zopts = zsvsheet_buffer_get_zsv_opts(buff);
146+
147+
zopts.ctx = user_context;
148+
zopts.row_handler = row_handler;
149+
zopts.stream = fopen(filename, "rb");
150+
151+
if (!zopts.stream)
152+
goto out;
153+
154+
opts.zsv_opts = zopts;
155+
156+
enum zsv_status zst = zsvsheet_transformation_new(opts, &trn);
157+
if (zst != zsv_status_ok)
158+
return stat;
159+
160+
zsv_parser parser = zsvsheet_transformation_parser(trn);
161+
162+
while ((zst = zsv_parse_more(parser)) == zsv_status_ok)
163+
;
164+
165+
switch (zst) {
166+
case zsv_status_no_more_input:
167+
case zsv_status_cancelled:
168+
break;
169+
default:
170+
goto out;
171+
}
172+
173+
zst = zsv_finish(parser);
174+
if (zst != zsv_status_ok)
175+
goto out;
176+
177+
stat = zsvsheet_open_file(ctx, zsvsheet_transformation_filename(trn), &zopts);
178+
179+
out:
180+
zsvsheet_transformation_delete(trn);
181+
return stat;
182+
}

app/sheet/handlers_internal.h

+5
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,9 @@ zsvsheet_status zsvsheet_register_command(int ch, const char *long_name,
9898
zsvsheet_status (*subcommand_handler)(zsvsheet_subcommand_context_t),
9999
zsvsheet_status (*handler)(zsvsheet_context_t));
100100

101+
/**
102+
* Transform the current buffer's underlying file into a new one and open the new file in a buffer
103+
*/
104+
enum zsvsheet_status zsvsheet_push_transformation(zsvsheet_proc_context_t ctx, void *user_context,
105+
void (*row_handler)(void *exec_ctx));
101106
#endif

include/zsv/ext.h

+31
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <stdio.h>
1313
#include "common.h"
1414
#include "ext/sheet.h"
15+
#include "utils/writer.h"
1516

1617
/**
1718
* @file ext.h
@@ -235,6 +236,36 @@ struct zsv_ext_callbacks {
235236
* Get zsv_opts used to open the buffer's data file
236237
*/
237238
struct zsv_opts (*ext_sheet_buffer_get_zsv_opts)(zsvsheet_buffer_t h);
239+
240+
/**
241+
* Create a new buffer from the current one using a transformation
242+
* and make the new buffer the current one
243+
*/
244+
zsvsheet_status (*ext_sheet_push_transformation)(zsvsheet_proc_context_t ctx, void *user_context,
245+
void (*row_handler)(void *ctx));
246+
247+
/**
248+
* Get the writer associated with a transformation.
249+
*
250+
* The transformation itself is passed as the context variable to the row handler
251+
*/
252+
zsv_csv_writer (*ext_sheet_transformation_writer)(zsvsheet_transformation trn);
253+
254+
/**
255+
* Get the user provided context from the context provided to a transformation row handler
256+
*/
257+
void *(*ext_sheet_transformation_user_context)(zsvsheet_transformation trn);
258+
259+
/**
260+
* Get the parser from the context provided to a transformation row handler
261+
*/
262+
zsv_parser (*ext_sheet_transformation_parser)(zsvsheet_transformation trn);
263+
264+
/**
265+
* Get the filename that the transformation writer outputs to from the context provided to a transformation row
266+
* handler.
267+
*/
268+
const char *(*ext_sheet_transformation_filename)(zsvsheet_transformation trn);
238269
};
239270

240271
/** @} */

include/zsv/ext/sheet.h

+2
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@ typedef struct zsvsheet_subcommand_context *zsvsheet_subcommand_context_t;
2121
typedef void *zsvsheet_buffer_t;
2222
// int zsvsheet_ext_keypress(zsvsheet_proc_context_t);
2323

24+
typedef struct zsvsheet_transformation *zsvsheet_transformation;
25+
2426
#endif

0 commit comments

Comments
 (0)