mirror of
https://github.com/maaslalani/slides.git
synced 2026-01-10 23:08:04 -05:00
Add pre-processing of slides
This commit is contained in:
31
examples/preprocess.md
Normal file
31
examples/preprocess.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Slides
|
||||
|
||||
~~~sd replaced processed
|
||||
This content will be replaced and passed into stdin
|
||||
of the command above
|
||||
~~~
|
||||
|
||||
---
|
||||
|
||||
Any command will work
|
||||
|
||||
~~~echo "You can do whatever, really"
|
||||
This doesn't matter, since it will be replaced by the stdout
|
||||
of the command above
|
||||
~~~
|
||||
|
||||
---
|
||||
|
||||
Pre-process Graphs
|
||||
|
||||
~~~graph-easy --as=boxart
|
||||
[ A ] - to -> [ B ]
|
||||
~~~
|
||||
|
||||
The above will be pre-processed to look like:
|
||||
|
||||
```
|
||||
┌───┐ to ┌───┐
|
||||
│ A │ ────> │ B │
|
||||
└───┘ └───┘
|
||||
```
|
||||
38
internal/process/execute_test.go
Normal file
38
internal/process/execute_test.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package process
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestExecute(t *testing.T) {
|
||||
tt := []struct {
|
||||
block Block
|
||||
want string
|
||||
}{
|
||||
{
|
||||
block: Block{
|
||||
Command: "cat",
|
||||
Input: "Hello, world!",
|
||||
},
|
||||
want: "Hello, world!",
|
||||
},
|
||||
{
|
||||
block: Block{
|
||||
Command: "sd Find Replace",
|
||||
Input: "Find",
|
||||
},
|
||||
want: "Replace",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.want, func(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.SkipNow()
|
||||
}
|
||||
tc.block.Execute()
|
||||
got := tc.block.Output
|
||||
if tc.want != got {
|
||||
t.Fatalf("Invalid execution, want %s, got %s", tc.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
69
internal/process/process.go
Normal file
69
internal/process/process.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package process
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Block represents a pre-processable block which looks like the following: It
|
||||
// is delimited by ~~~ and contains a command to be run along with the input to
|
||||
// be passed, the entire block should be replaced with its command output
|
||||
//
|
||||
// ~~~sd block process
|
||||
// block
|
||||
// ~~~
|
||||
type Block struct {
|
||||
Command string
|
||||
Input string
|
||||
Output string
|
||||
Raw string
|
||||
}
|
||||
|
||||
func (b Block) String() string {
|
||||
return fmt.Sprintf("===\n%s\n%s\n%s\n===", b.Raw, b.Command, b.Input)
|
||||
}
|
||||
|
||||
// ?: means non-capture group
|
||||
var reng = regexp.MustCompile("~~~(.+)\n(?:.|\n)*?\n~~~\\s?")
|
||||
var reg = regexp.MustCompile("(?s)~~~(.+?)\n(.*?)\n~~~\\s?")
|
||||
|
||||
// Parse takes some markdown and returns blocks to be pre-processed
|
||||
func Parse(markdown string) []Block {
|
||||
var blocks []Block
|
||||
matches := reng.FindAllString(markdown, -1)
|
||||
for _, match := range matches {
|
||||
m := reg.FindStringSubmatch(match)
|
||||
blocks = append(blocks, Block{
|
||||
Command: m[1],
|
||||
Input: m[2],
|
||||
Raw: strings.TrimSuffix(m[0], "\n"),
|
||||
})
|
||||
}
|
||||
return blocks
|
||||
}
|
||||
|
||||
// Execute takes performs the execution of the block's command
|
||||
// by passing in the block's input as stdin and sets the block output
|
||||
func (b *Block) Execute() {
|
||||
c := strings.Split(b.Command, " ")
|
||||
cmd := exec.Command(c[0], c[1:]...)
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer stdin.Close()
|
||||
_, _ = io.WriteString(stdin, b.Input)
|
||||
}()
|
||||
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b.Output = string(out)
|
||||
}
|
||||
64
internal/process/process_test.go
Normal file
64
internal/process/process_test.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package process
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
md := `
|
||||
# Slide
|
||||
|
||||
~~~sd Replace Process
|
||||
Replace
|
||||
~~~
|
||||
|
||||
Hello
|
||||
|
||||
~~~sd Replace Process
|
||||
Replace
|
||||
Multi-line input
|
||||
~~~
|
||||
|
||||
~~~echo -n World
|
||||
Hello
|
||||
~~~
|
||||
|
||||
---
|
||||
|
||||
# Next Slide
|
||||
|
||||
GraphViz Test
|
||||
|
||||
~~~graph-easy --as=boxart
|
||||
digraph {
|
||||
A -> B
|
||||
}
|
||||
~~~
|
||||
`
|
||||
|
||||
got := Parse(md)
|
||||
want := []Block{{
|
||||
Command: "sd Replace Process",
|
||||
Input: "Replace",
|
||||
Raw: "~~~sd Replace Process\nReplace\n~~~",
|
||||
}, {
|
||||
Command: "sd Replace Process",
|
||||
Input: "Replace\nMulti-line input",
|
||||
Raw: "~~~sd Replace Process\nReplace\nMulti-line input\n~~~",
|
||||
}, {
|
||||
Command: "echo -n World",
|
||||
Input: "Hello",
|
||||
Raw: "~~~echo -n World\nHello\n~~~",
|
||||
}, {
|
||||
Command: "graph-easy --as=boxart",
|
||||
Input: "digraph {\n A -> B\n}",
|
||||
Raw: "~~~graph-easy --as=boxart\ndigraph {\n A -> B\n}\n~~~",
|
||||
}}
|
||||
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Log(want)
|
||||
t.Log(got)
|
||||
t.Fatal("Did not parse blocks correctly")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user