Skip to content

Commit

Permalink
feat: execute code on slides
Browse files Browse the repository at this point in the history
  • Loading branch information
maaslalani committed Jun 21, 2021
1 parent eb132e8 commit eae6b6f
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 16 deletions.
50 changes: 50 additions & 0 deletions examples/code_blocks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Code blocks

Slides allows you to execute code blocks directly inside your slides!

Just press `e` and the result of the code block will be displayed as virtual
text in your slides.

Currently supported languages:
* `bash`
* `go`
* `ruby`
* `python`

---

### Bash

```bash
ls
```

---

### Go

```go
package main

import "fmt"

func main() {
fmt.Println("Hello, world!")
}
```

---

### Ruby

```ruby
puts "Hello, world!"
```

---

### Python

```python
print("Hello, world!")
```
2 changes: 1 addition & 1 deletion internal/code/code.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type Result struct {
}

// ?: means non-capture group
var re = regexp.MustCompile("(?:```|~~~)(.*)\n(.*)\n(?:```|~~~)")
var re = regexp.MustCompile("(?s)(?:```|~~~)(\\w+)\n(.*)\n(?:```|~~~)\n")

var (
ErrParse = errors.New("Error: could not parse code block")
Expand Down
38 changes: 24 additions & 14 deletions internal/code/code_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,28 +37,38 @@ fmt.Println("Hello, world!")
},
{
markdown: `
# Slide 1
Just a regular slide, no code block
`,
expected: code.Block{},
},
{
markdown: `
# Multiple Code Blocks
# Welcome to Slides
A terminal based presentation tool
~~~go
fmt.Println("Oh no!")
~~~
package main
# Secondary Code Block
~~~ruby
puts "We will only parse the first code block"
import "fmt"
func main() {
fmt.Println("Written in Go!")
}
~~~
`,
expected: code.Block{
Code: `fmt.Println("Oh no!")`,
Code: `package main
import "fmt"
func main() {
fmt.Println("Written in Go!")
}`,
Language: "go",
},
},
{
markdown: `
# Slide 1
Just a regular slide, no code block
`,
expected: code.Block{},
},
{
markdown: ``,
expected: code.Block{},
Expand Down
20 changes: 19 additions & 1 deletion internal/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/glamour"
"github.com/maaslalani/slides/internal/code"
"github.com/maaslalani/slides/internal/meta"
"github.com/maaslalani/slides/styles"
"io"
Expand All @@ -29,6 +30,9 @@ type Model struct {
Theme glamour.TermRendererOption
FileName string
viewport viewport.Model
// VirtualText is used for additional information that is not part of the
// original slides, it will be displayed on a slide and reset on page change
VirtualText string
}

type fileWatchMsg struct{}
Expand Down Expand Up @@ -96,10 +100,22 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if m.Page < len(m.Slides)-1 {
m.Page++
}
m.VirtualText = ""
case "up", "j", "left", "h", "p":
if m.Page > 0 {
m.Page--
}
m.VirtualText = ""
case "e":
// Run code block
block, err := code.Parse(m.Slides[m.Page])
if err != nil {
// We couldn't parse the code block on the screen
m.VirtualText = "\n" + err.Error()
return m, nil
}
res := code.Execute(block)
m.VirtualText = res.Out
}

case fileWatchMsg:
Expand All @@ -118,7 +134,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

func (m Model) View() string {
r, _ := glamour.NewTermRenderer(m.Theme, glamour.WithWordWrap(0))
slide, err := r.Render(m.Slides[m.Page])
slide := m.Slides[m.Page]
slide += m.VirtualText
slide, err := r.Render(slide)
if err != nil {
slide = fmt.Sprintf("Error: Could not render markdown! (%v)", err)
}
Expand Down

0 comments on commit eae6b6f

Please sign in to comment.