Skip to content

Commit 3649a2f

Browse files
committed
✨ feat(cli): auto-expand table dicts to markdown nodes in CLI output
Table objects returned from table::tables() are now automatically expanded to markdown nodes when output via the CLI, matching the existing behavior for section dicts. Users can output table objects directly without calling table::to_markdown(). Also fixes a bug in table::add_row() where new cells were assigned the same row index as existing data rows due to missing +1 offset for the header row.
1 parent f978e5b commit 3649a2f

File tree

4 files changed

+114
-2
lines changed

4 files changed

+114
-2
lines changed

crates/mq-lang/modules/table.mq

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def add_row(table, row):
6262
else: do
6363
var i = 0
6464
| let cells = foreach (cell, row):
65-
to_md_table_cell(cell, len(table[:rows]), i)
65+
to_md_table_cell(cell, len(table[:rows]) + 1, i)
6666
| i += 1
6767
end
6868
| set(table, :rows, table[:rows] + [cells])

crates/mq-run/src/cli.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ impl Cli {
736736
let type_key = mq_lang::Ident::new("type");
737737
matches!(
738738
map.get(&type_key),
739-
Some(mq_lang::RuntimeValue::Symbol(s)) if matches!(s.as_str().as_str(), "section")
739+
Some(mq_lang::RuntimeValue::Symbol(s)) if matches!(s.as_str().as_str(), "section" | "table")
740740
)
741741
}
742742

@@ -760,6 +760,21 @@ impl Cli {
760760
}
761761
Some(nodes)
762762
}
763+
"table" => {
764+
// Reconstruct table nodes in the same order as table::to_markdown():
765+
// header cells + align row + flattened data rows
766+
let mut nodes = Vec::new();
767+
if let Some(header) = map.get(&mq_lang::Ident::new("header")) {
768+
Self::collect_markdown_nodes(header, &mut nodes);
769+
}
770+
if let Some(align) = map.get(&mq_lang::Ident::new("align")) {
771+
Self::collect_markdown_nodes(align, &mut nodes);
772+
}
773+
if let Some(rows) = map.get(&mq_lang::Ident::new("rows")) {
774+
Self::collect_markdown_nodes(rows, &mut nodes);
775+
}
776+
Some(nodes)
777+
}
763778
// To add a new expandable type: add a match arm here.
764779
_ => None,
765780
},

crates/mq-run/tests/integration_tests.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,21 @@ In {year}, the snowfall was above average.
141141
"# Introduction\n\nBody text.\n",
142142
Some("Body text.\n")
143143
)]
144+
#[case::table_auto_expand(
145+
vec!["--unbuffered", "-A", r#"import "table" | table::tables()"#],
146+
"| Name | Age |\n| ---- | --- |\n| Alice | 30 |\n| Bob | 25 |\n",
147+
Some("|Name|Age|\n|---|---|\n|Alice|30|\n|Bob|25|\n")
148+
)]
149+
#[case::table_auto_expand_first(
150+
vec!["--unbuffered", "-A", r#"import "table" | table::tables() | first()"#],
151+
"| Name | Age |\n| ---- | --- |\n| Alice | 30 |\n| Bob | 25 |\n",
152+
Some("|Name|Age|\n|---|---|\n|Alice|30|\n|Bob|25|\n")
153+
)]
154+
#[case::table_auto_expand_add_row(
155+
vec!["--unbuffered", "-A", r#"import "table" | table::tables() | first() | table::add_row(["Charlie", "35"])"#],
156+
"| Name | Age |\n| ---- | --- |\n| Alice | 30 |\n",
157+
Some("|Name|Age|\n|---|---|\n|Alice|30|\n|Charlie|35|\n")
158+
)]
144159
#[case::capture_named_groups(
145160
vec!["--unbuffered", "-I", "text", r#"capture("(?P<year>\\d{4})-(?P<month>\\d{2})-(?P<day>\\d{2})")"#],
146161
"2024-01-15",

docs/books/src/start/example.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,88 @@ Use the tool like this.
391391

392392
**Output**: `["Introduction", "Usage"]`
393393

394+
## Table Operations
395+
396+
The table module provides functions for extracting and transforming Markdown tables.
397+
398+
> **Note**: Table functions need all document nodes at once. Use `-A` on the command line, or `nodes` in inline queries. Unlike the section module, `import "table"` must be written explicitly.
399+
400+
### Extract Tables
401+
402+
**`-A` flag** (command line):
403+
404+
```bash
405+
$ mq -A 'import "table" | table::tables()' README.md
406+
```
407+
408+
**`import` + `nodes`** (inline query or script):
409+
410+
```mq
411+
import "table"
412+
| nodes
413+
| table::tables()
414+
```
415+
416+
Table objects are automatically expanded to Markdown nodes in CLI output, so `to_markdown()` is not needed.
417+
418+
> **Note (code usage)**: When using the table module from Rust or other code (not the CLI), table objects are plain dicts and must be explicitly converted with `table::to_markdown()`:
419+
>
420+
> ```mq
421+
> import "table"
422+
> | nodes
423+
> | table::tables()
424+
> | table::to_markdown()
425+
> ```
426+
427+
**Input example**:
428+
429+
```markdown
430+
| Name | Age |
431+
| ----- | --- |
432+
| Alice | 30 |
433+
| Bob | 25 |
434+
```
435+
436+
**Output**:
437+
438+
```markdown
439+
| Name | Age |
440+
| ----- | --- |
441+
| Alice | 30 |
442+
| Bob | 25 |
443+
```
444+
445+
### Add a Row to a Table
446+
447+
```bash
448+
$ mq -A 'import "table" | table::tables() | first() | table::add_row(["Charlie", "35"])' README.md
449+
```
450+
451+
**Input example**:
452+
453+
```markdown
454+
| Name | Age |
455+
| ----- | --- |
456+
| Alice | 30 |
457+
```
458+
459+
**Output**:
460+
461+
```markdown
462+
| Name | Age |
463+
| ------- | --- |
464+
| Alice | 30 |
465+
| Charlie | 35 |
466+
```
467+
468+
### Convert Table to CSV
469+
470+
```bash
471+
$ mq -A 'import "table" | table::tables() | first() | table::to_csv()' README.md
472+
```
473+
474+
**Output**: Returns the table as a CSV string.
475+
394476
## Custom Functions and Programming
395477

396478
### Define Custom Function

0 commit comments

Comments
 (0)