Skip to content

Commit f173e6d

Browse files
authored
Merge pull request #110 from nushell-prophet/parse-md
Add parse-md command for semantic markdown parsing
2 parents 02933e7 + 4521d6a commit f173e6d

12 files changed

Lines changed: 1060 additions & 21 deletions

README.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ numd run $path --ignore-git-check
113113
Use the `--eval` option to prepend Nushell code to the intermediate script. This lets you set visual settings and other configuration before your code runs.
114114

115115
```nushell
116-
let path = $nu.temp-path | path join simple_nu_table.md
116+
let path = $nu.temp-dir | path join simple_nu_table.md
117117
118118
# let's generate some markdown and save it to the `simple_nu_table.md` file in the temp directory
119119
"```nushell\n[[a b c]; [1 2 3]]\n```\n" | save -f $path
@@ -209,6 +209,33 @@ numd capture stop --help
209209
# =>
210210
```
211211

212+
### `numd parse-md`
213+
214+
Parse markdown into a table of semantic blocks (headers, paragraphs, code blocks, lists, blockquotes, frontmatter) with extracted content and metadata.
215+
216+
```nushell
217+
numd parse-md --help
218+
# => Parse markdown into semantic blocks
219+
# =>
220+
# => Usage:
221+
# => > parse-md (file)
222+
# =>
223+
# => Flags:
224+
# => -h, --help: Display the help message for this command
225+
# =>
226+
# => Parameters:
227+
# => file <path>: optional path to markdown file (can also pipe content) (optional)
228+
# =>
229+
# => Input/output types:
230+
# => ╭───┬─────────┬────────╮
231+
# => │ # │ input │ output │
232+
# => ├───┼─────────┼────────┤
233+
# => │ 0 │ string │ table │
234+
# => │ 1 │ nothing │ table │
235+
# => ╰───┴─────────┴────────╯
236+
# =>
237+
```
238+
212239
### Some random familiar examples
213240

214241
```nushell
@@ -234,7 +261,7 @@ ls z_examples | sort-by name | reject modified size
234261
# => 4
235262
236263
git tag | lines | sort -n | last
237-
# => 0.2.2
264+
# => 0.3.0
238265
```
239266

240267
## Real fight examples to try

numd/commands.nu

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ export def list-fence-options []: nothing -> table {
432432
# Expand short options for code block execution to their long forms.
433433
@example "expand short option to long form" {
434434
convert-short-options 'O'
435-
} --result 'no-output'
435+
} --result "no-output"
436436
export def convert-short-options [
437437
option: string
438438
]: nothing -> string {
@@ -449,7 +449,7 @@ export def convert-short-options [
449449
# Escape symbols to be printed unchanged inside a `print "something"` statement.
450450
@example "escape quotes for print statement" {
451451
'abcd"dfdaf" "' | quote-for-print
452-
} --result '"abcd\"dfdaf\" \""'
452+
} --result "\"abcd\\\"dfdaf\\\" \\\"\""
453453
export def quote-for-print []: string -> string {
454454
# `to json` might give similar results, yet it replaces new lines
455455
# which spoils readability of intermediate scripts
@@ -517,7 +517,9 @@ export def code-block-marker [
517517
# Generate a command to highlight code using Nushell syntax highlighting.
518518
@example "generate syntax highlighting command" {
519519
'ls' | generate-highlight-print
520-
} --result "\"ls\" | nu-highlight | print\n\n"
520+
} --result "\"ls\" | nu-highlight | print
521+
522+
"
521523
export def generate-highlight-print []: string -> string {
522524
quote-for-print
523525
| pipe-to { nu-highlight | print }
@@ -531,12 +533,12 @@ export def trim-trailing-comments []: string -> string {
531533
}
532534

533535
# Extract the last span from a command to determine if `| print` can be appended.
534-
@example "pipeline ending with command" { get-last-span 'let a = 1..10; $a | length' } --result 'length'
535-
@example "pipeline ending with assignment" { get-last-span 'let a = 1..10; let b = $a | length' } --result 'let b = $a | length'
536-
@example "statement ending with semicolon" { get-last-span 'let a = 1..10; ($a | length);' } --result 'let a = 1..10; ($a | length);'
537-
@example "expression in parentheses" { get-last-span 'let a = 1..10; ($a | length)' } --result '($a | length)'
538-
@example "single assignment" { get-last-span 'let a = 1..10' } --result 'let a = 1..10'
539-
@example "string literal" { get-last-span '"abc"' } --result '"abc"'
536+
@example "pipeline ending with command" { get-last-span 'let a = 1..10; $a | length' } --result "length"
537+
@example "pipeline ending with assignment" { get-last-span 'let a = 1..10; let b = $a | length' } --result "let b = $a | length"
538+
@example "statement ending with semicolon" { get-last-span 'let a = 1..10; ($a | length);' } --result "let a = 1..10; ($a | length);"
539+
@example "expression in parentheses" { get-last-span 'let a = 1..10; ($a | length)' } --result "($a | length)"
540+
@example "single assignment" { get-last-span 'let a = 1..10' } --result "let a = 1..10"
541+
@example "string literal" { get-last-span '"abc"' } --result "\"abc\""
540542
export def get-last-span [
541543
command: string
542544
]: nothing -> string {
@@ -582,7 +584,7 @@ export def can-append-print [
582584
# Generate a pipeline that captures command output with `# =>` prefix for inline display.
583585
@example "generate inline output capture pipeline" {
584586
'ls' | generate-inline-output-pipeline
585-
} --result "ls | table --width 120 | default '' | into string | lines | each {$'# => ($in)' | str trim --right} | str join (char nl) | str replace -r '\\s*$' (char nl)"
587+
} --result "ls | table --width ($env.numd?.table-width? | default 120) | default '' | into string | lines | each { $'# => ($in)' | str trim --right } | str join (char nl) | str replace -r '\\s*$' (char nl)"
586588
export def generate-inline-output-pipeline []: string -> string {
587589
generate-table-statement
588590
| pipe-to {
@@ -597,13 +599,13 @@ export def generate-print-statement []: string -> string {
597599
}
598600

599601
# Generate a table statement with width evaluated at runtime from $env.numd.table-width.
600-
@example "default table width" { 'ls' | generate-table-statement } --result 'ls | table --width ($env.numd?.table-width? | default 120)'
602+
@example "default table width" { 'ls' | generate-table-statement } --result "ls | table --width ($env.numd?.table-width? | default 120)"
601603
export def generate-table-statement []: string -> string {
602604
pipe-to { table --width ($env.numd?.table-width? | default 120) }
603605
}
604606

605607
# Wrap code in a try-catch block to handle errors gracefully.
606-
@example "wrap command in try-catch" { 'ls' | wrap-in-try-catch } --result 'try {ls} catch {|error| $error}'
608+
@example "wrap command in try-catch" { 'ls' | wrap-in-try-catch } --result "try {ls} catch {|error| $error}"
607609
export def wrap-in-try-catch [
608610
--new-instance # execute in a separate Nushell instance to get formatted error messages
609611
]: string -> string {
@@ -646,7 +648,7 @@ export def generate-block-markers [
646648
}
647649

648650
# Parse options from a code fence and return them as a list.
649-
@example "parse fence options with short forms" { '```nu no-run, t' | extract-fence-options } --result ['no-run' 'try']
651+
@example "parse fence options with short forms" { '```nu no-run, t' | extract-fence-options } --result [no-run, try]
650652
export def extract-fence-options []: string -> list<string> {
651653
str replace -r '```nu(shell)?\s*' ''
652654
| split row ','
@@ -658,7 +660,7 @@ export def extract-fence-options []: string -> list<string> {
658660
# Modify a path by adding a prefix, suffix, extension, or parent directory.
659661
@example "build path with all modifiers" {
660662
'numd/capture.nu' | build-modified-path --extension '.md' --prefix 'pref_' --suffix '_suf' --parent_dir abc
661-
} --result 'numd/abc/pref_capture_suf.nu.md'
663+
} --result "numd/abc/pref_capture_suf.nu.md"
662664
export def build-modified-path [
663665
--prefix: string
664666
--suffix: string

numd/live.nu

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
export def 'filename-set' [
2+
file = 'numdlive.md'
3+
] {
4+
$env.numd.live-filename = $file
5+
}
6+
7+
export def 'file-name' [] {
8+
$env.numd?.live-filename?
9+
| default 'numdlive.md'
10+
}
11+
12+
export def 'append-block' [] {
13+
if $env.numd?.live-print? == true {
14+
print --no-newline
15+
} else {
16+
save --append (file-name)
17+
}
18+
}
19+
20+
export def 'h' [
21+
$index
22+
$header
23+
] {
24+
seq 1 $index
25+
| each { '#' }
26+
| append ' '
27+
| append $header
28+
| str join
29+
| str replace -ar "\n*$" "\n\n"
30+
| append-block
31+
}
32+
33+
export def 'h1' [
34+
$text: string
35+
] {
36+
h 1 $text
37+
}
38+
39+
export def 'h2' [
40+
$text: string
41+
] {
42+
h 2 $text
43+
}
44+
45+
export def 'h3' [
46+
$text: string
47+
] {
48+
h 3 $text
49+
}
50+
51+
export def 'h4' [
52+
$text: string
53+
] {
54+
h 4 $text
55+
}
56+
57+
export def 'h5' [
58+
$text: string
59+
] {
60+
h 5 $text
61+
}
62+
63+
export def 'h6' [
64+
$text: string
65+
] {
66+
h 6 $text
67+
}
68+
69+
# > numd list-code-options | values | each {$'--($in)'} | to text
70+
71+
export def 'code' [
72+
$code_block
73+
--indent-output
74+
--inline
75+
--no-output
76+
--no-run
77+
--try
78+
--new-instance
79+
--comment: string = '' # add comment to the code
80+
] {
81+
let $comment = $comment
82+
| if $in != '' {
83+
lines
84+
| compact --empty
85+
| str replace -r '^#? ?' '# '
86+
| $"($in)\n"
87+
} else { '' }
88+
89+
let $code = $code_block
90+
| if $inline {
91+
str replace -r '^(> )?' '> '
92+
} else { }
93+
| $'($comment)($in)'
94+
95+
let $code_fence_with_options = [
96+
(if $indent_output { 'indent-output' })
97+
(if $no_output { 'no-output' })
98+
(if $no_run { 'no-run' })
99+
(if $try { 'try' })
100+
(if $new_instance { 'new-instance' })
101+
]
102+
| compact
103+
| if $in == [] { } else { sort | str join ',' | $' ($in)' }
104+
| $'```nushell($in)'
105+
106+
[
107+
$code_fence_with_options
108+
$code
109+
'```'
110+
''
111+
]
112+
| to text
113+
| append-block
114+
}
115+
116+
# add a paragraph
117+
export def 'p' [
118+
$text
119+
] {
120+
$text
121+
| str replace -r "\\s*$" "\n\n"
122+
| append-block
123+
}
124+
125+
export def 'pseudo-xml' [
126+
tag: string
127+
--close
128+
] {
129+
if not $close { $'<($tag)>' } else { $'</($tag)>' }
130+
| append-block
131+
}

0 commit comments

Comments
 (0)