mirror of
https://github.com/maaslalani/slides.git
synced 2026-01-08 22:07:59 -05:00
Ensure file is executable for preprocessing to work
This commit is contained in:
23
README.md
23
README.md
@@ -65,13 +65,26 @@ Create slides and present them without ever leaving your terminal.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Include ASCII graphs with GraphViz + graph-easy.
|
# Pre-process slides
|
||||||
https://dot-to-ascii.ggerganov.com/
|
|
||||||
|
|
||||||
┌──────────┐ ┌────────────┐ ┌────────┐
|
You can add a code block with ~~~ and write a command to run before displaying
|
||||||
│ GraphViz │ ──▶ │ graph-easy │ ──▶ │ slides │
|
the slides, the text inside the code block will be passed as stdin to the command
|
||||||
└──────────┘ └────────────┘ └────────┘
|
and the code block will be replaced with the stdout of the command.
|
||||||
|
|
||||||
|
~~~graph-easy --as=boxart
|
||||||
|
[ A ] - to -> [ B ]
|
||||||
|
~~~
|
||||||
|
|
||||||
|
The above will be pre-processed to look like:
|
||||||
|
|
||||||
|
┌───┐ to ┌───┐
|
||||||
|
│ A │ ────> │ B │
|
||||||
|
└───┘ └───┘
|
||||||
|
|
||||||
|
For security reasons, you must pass a file that has execution permissions
|
||||||
|
for the slides to be pre-processed.
|
||||||
|
|
||||||
|
chmod +x file.md
|
||||||
```
|
```
|
||||||
|
|
||||||
Checkout the [example slides](./examples).
|
Checkout the [example slides](./examples).
|
||||||
|
|||||||
2
examples/import.md
Normal file
2
examples/import.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
This is just an example of how to import text from other files with
|
||||||
|
preprocess.md
|
||||||
48
examples/preprocess.md
Normal file → Executable file
48
examples/preprocess.md
Normal file → Executable file
@@ -1,8 +1,36 @@
|
|||||||
# Slides
|
# Slides
|
||||||
|
|
||||||
|
You can add a code block with three tildes (~) and write a command to run before displaying
|
||||||
|
the slides, the text inside the code block will be passed as stdin to the command
|
||||||
|
and the code block will be replaced with the stdout of the command.
|
||||||
|
|
||||||
|
```
|
||||||
|
~~~graph-easy --as=boxart
|
||||||
|
[ A ] - to -> [ B ]
|
||||||
|
~~~
|
||||||
|
```
|
||||||
|
|
||||||
|
The above will be pre-processed to look like:
|
||||||
|
|
||||||
|
NOTE: You need `graph-easy` installed and in your `$PATH`
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───┐ to ┌───┐
|
||||||
|
│ A │ ────> │ B │
|
||||||
|
└───┘ └───┘
|
||||||
|
```
|
||||||
|
|
||||||
|
For security reasons, you must pass a file that has execution permissions
|
||||||
|
for the slides to be pre-processed.
|
||||||
|
|
||||||
|
```
|
||||||
|
chmod +x file.md
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
~~~sd replaced processed
|
~~~sd replaced processed
|
||||||
This content will be replaced and passed into stdin
|
This content will be passed in as stdin and will be replaced.
|
||||||
of the command above
|
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -11,21 +39,13 @@ Any command will work
|
|||||||
|
|
||||||
~~~echo "You can do whatever, really"
|
~~~echo "You can do whatever, really"
|
||||||
This doesn't matter, since it will be replaced by the stdout
|
This doesn't matter, since it will be replaced by the stdout
|
||||||
of the command above
|
of the command above because the command will disregard stdin.
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Pre-process Graphs
|
You can use this to import snippets of code from other files:
|
||||||
|
|
||||||
~~~graph-easy --as=boxart
|
~~~xargs cat
|
||||||
[ A ] - to -> [ B ]
|
examples/import.md
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
The above will be pre-processed to look like:
|
|
||||||
|
|
||||||
```
|
|
||||||
┌───┐ to ┌───┐
|
|
||||||
│ A │ ────> │ B │
|
|
||||||
└───┘ └───┘
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
package file
|
package file
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,3 +17,8 @@ func Exists(filepath string) bool {
|
|||||||
}
|
}
|
||||||
return !info.IsDir()
|
return !info.IsDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsExecutable returns whether a file has execution permissions
|
||||||
|
func IsExecutable(s fs.FileInfo) bool {
|
||||||
|
return s.Mode().Perm()&0111 == 0111
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package file_test
|
package file_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/maaslalani/slides/internal/file"
|
"github.com/maaslalani/slides/internal/file"
|
||||||
@@ -26,3 +29,44 @@ func TestExists(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsExecutable(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
perm fs.FileMode
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{0101, false},
|
||||||
|
{0111, true},
|
||||||
|
{0644, false},
|
||||||
|
{0666, false},
|
||||||
|
{0777, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(fmt.Sprint(tc.perm), func(t *testing.T) {
|
||||||
|
tmp, err := os.CreateTemp(os.TempDir(), "slides-*")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("failed to create temp file")
|
||||||
|
}
|
||||||
|
defer os.Remove(tmp.Name())
|
||||||
|
|
||||||
|
err = tmp.Chmod(tc.perm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := tmp.Stat()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("failed to stat file")
|
||||||
|
}
|
||||||
|
|
||||||
|
want := tc.expected
|
||||||
|
got := file.IsExecutable(s)
|
||||||
|
if tc.expected != got {
|
||||||
|
t.Log(want)
|
||||||
|
t.Log(got)
|
||||||
|
t.Fatalf("IsExecutable returned an incorrect result, want: %t, got %t", want, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/glamour"
|
"github.com/charmbracelet/glamour"
|
||||||
"github.com/maaslalani/slides/internal/code"
|
"github.com/maaslalani/slides/internal/code"
|
||||||
|
"github.com/maaslalani/slides/internal/file"
|
||||||
"github.com/maaslalani/slides/internal/meta"
|
"github.com/maaslalani/slides/internal/meta"
|
||||||
"github.com/maaslalani/slides/internal/process"
|
"github.com/maaslalani/slides/internal/process"
|
||||||
"github.com/maaslalani/slides/styles"
|
"github.com/maaslalani/slides/styles"
|
||||||
@@ -68,8 +69,6 @@ func (m *Model) Load() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
content = process.Pre(content)
|
|
||||||
|
|
||||||
slides := strings.Split(content, delimiter)
|
slides := strings.Split(content, delimiter)
|
||||||
|
|
||||||
metaData, exists := meta.New().ParseHeader(slides[0])
|
metaData, exists := meta.New().ParseHeader(slides[0])
|
||||||
@@ -162,7 +161,15 @@ func readFile(path string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(b), err
|
content := string(b)
|
||||||
|
|
||||||
|
// Pre-process slides if the file is executable to avoid
|
||||||
|
// unintentional code execution when presenting slides
|
||||||
|
if file.IsExecutable(s) {
|
||||||
|
content = process.Pre(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
return content, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func readStdin() (string, error) {
|
func readStdin() (string, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user