Skip to content

Commit

Permalink
fix source
Browse files Browse the repository at this point in the history
  • Loading branch information
rsteube committed Jan 4, 2025
1 parent ad1ca7c commit 5d26011
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 86 deletions.
59 changes: 3 additions & 56 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"regexp"
Expand All @@ -12,25 +11,16 @@ import (
"time"

"github.com/atotto/clipboard"
"github.com/charmbracelet/vhs/lexer"
"github.com/charmbracelet/vhs/parser"
"github.com/charmbracelet/vhs/token"
"github.com/go-rod/rod/lib/input"
"github.com/mattn/go-runewidth"
)

// Execute executes a command on a running instance of vhs.
func Execute(c parser.Command, v *VHS) error {
if c.Type == token.SOURCE {
err := ExecuteSourceTape(c, v)
if err != nil {
return fmt.Errorf("failed to execute source tape: %w", err)
}
} else {
err := CommandFuncs[c.Type](c, v)
if err != nil {
return fmt.Errorf("failed to execute command: %w", err)
}
err := CommandFuncs[c.Type](c, v)
if err != nil {
return fmt.Errorf("failed to execute command: %w", err)
}

if v.recording && v.Options.Test.Output != "" {
Expand Down Expand Up @@ -710,49 +700,6 @@ func ExecuteSetCursorBlink(c parser.Command, v *VHS) error {
return nil
}

const sourceDisplayMaxLength = 10

// ExecuteSourceTape is a CommandFunc that executes all commands of source tape.
func ExecuteSourceTape(c parser.Command, v *VHS) error {
tapePath := c.Args
var out io.Writer = os.Stdout
if quietFlag {
out = io.Discard
}

// read tape file
tape, err := os.ReadFile(tapePath)
if err != nil {
return fmt.Errorf("failed to read tape %s: %w", tapePath, err)
}

l := lexer.New(string(tape))
p := parser.New(l)

cmds := p.Parse()
if len(p.Errors()) != 0 {
return InvalidSyntaxError{p.Errors()}
}

displayPath := runewidth.Truncate(strings.TrimSuffix(tapePath, extension), sourceDisplayMaxLength, "…")

// Run all commands from the sourced tape file.
for _, cmd := range cmds {
// Output have to be avoid in order to not overwrite output of the original tape.
if cmd.Type == token.SOURCE ||
cmd.Type == token.OUTPUT {
continue
}
_, _ = fmt.Fprintf(out, "%s %s\n", GrayStyle.Render(displayPath+":"), Highlight(cmd, false))
err := CommandFuncs[cmd.Type](cmd, v)
if err != nil {
return fmt.Errorf("failed to execute command %s: %w", cmd.Type.String(), err)
}
}

return nil
}

// ExecuteScreenshot is a CommandFunc that indicates a new screenshot must be taken.
func ExecuteScreenshot(c parser.Command, v *VHS) error {
v.ScreenshotNextFrame(c.Args)
Expand Down
68 changes: 40 additions & 28 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ type Command struct {
Type CommandType
Options string
Args string
Source string
}

// String returns the string representation of the command.
Expand Down Expand Up @@ -123,15 +124,15 @@ func (p *Parser) Parse() []Command {
p.nextToken()
continue
}
cmds = append(cmds, p.parseCommand())
cmds = append(cmds, p.parseCommand()...)
p.nextToken()
}

return cmds
}

// parseCommand parses a command.
func (p *Parser) parseCommand() Command {
func (p *Parser) parseCommand() []Command {
switch p.cur.Type {
case token.SPACE,
token.BACKSPACE,
Expand All @@ -146,42 +147,42 @@ func (p *Parser) parseCommand() Command {
token.UP,
token.PAGEUP,
token.PAGEDOWN:
return p.parseKeypress(p.cur.Type)
return []Command{p.parseKeypress(p.cur.Type)}
case token.SET:
return p.parseSet()
return []Command{p.parseSet()}
case token.OUTPUT:
return p.parseOutput()
return []Command{p.parseOutput()}
case token.SLEEP:
return p.parseSleep()
return []Command{p.parseSleep()}
case token.TYPE:
return p.parseType()
return []Command{p.parseType()}
case token.CTRL:
return p.parseCtrl()
return []Command{p.parseCtrl()}
case token.ALT:
return p.parseAlt()
return []Command{p.parseAlt()}
case token.SHIFT:
return p.parseShift()
return []Command{p.parseShift()}
case token.HIDE:
return p.parseHide()
return []Command{p.parseHide()}
case token.REQUIRE:
return p.parseRequire()
return []Command{p.parseRequire()}
case token.SHOW:
return p.parseShow()
return []Command{p.parseShow()}
case token.WAIT:
return p.parseWait()
return []Command{p.parseWait()}
case token.SOURCE:
return p.parseSource()
case token.SCREENSHOT:
return p.parseScreenshot()
return []Command{p.parseScreenshot()}
case token.COPY:
return p.parseCopy()
return []Command{p.parseCopy()}
case token.PASTE:
return p.parsePaste()
return []Command{p.parsePaste()}
case token.ENV:
return p.parseEnv()
return []Command{p.parseEnv()}
default:
p.errors = append(p.errors, NewError(p.cur, "Invalid command: "+p.cur.Literal))
return Command{Type: token.ILLEGAL}
return []Command{{Type: token.ILLEGAL}}
}
}

Expand Down Expand Up @@ -652,13 +653,13 @@ func (p *Parser) parseEnv() Command {
// Source command takes a tape path to include in current tape.
//
// Source <path>
func (p *Parser) parseSource() Command {
func (p *Parser) parseSource() []Command {
cmd := Command{Type: token.SOURCE}

if p.peek.Type != token.STRING {
p.errors = append(p.errors, NewError(p.cur, "Expected path after Source"))
p.nextToken()
return cmd
return []Command{cmd}
}

srcPath := p.peek.Literal
Expand All @@ -668,15 +669,15 @@ func (p *Parser) parseSource() Command {
if ext != ".tape" {
p.errors = append(p.errors, NewError(p.peek, "Expected file with .tape extension"))
p.nextToken()
return cmd
return []Command{cmd}
}

// Check if tape exist
if _, err := os.Stat(srcPath); os.IsNotExist(err) {
notFoundErr := fmt.Sprintf("File %s not found", srcPath)
p.errors = append(p.errors, NewError(p.peek, notFoundErr))
p.nextToken()
return cmd
return []Command{cmd}
}

// Check if source tape contains nested Source command
Expand All @@ -685,7 +686,7 @@ func (p *Parser) parseSource() Command {
readErr := fmt.Sprintf("Unable to read file: %s", srcPath)
p.errors = append(p.errors, NewError(p.peek, readErr))
p.nextToken()
return cmd
return []Command{cmd}
}

srcTape := string(d)
Expand All @@ -694,7 +695,7 @@ func (p *Parser) parseSource() Command {
readErr := fmt.Sprintf("Source tape: %s is empty", srcPath)
p.errors = append(p.errors, NewError(p.peek, readErr))
p.nextToken()
return cmd
return []Command{cmd}
}

srcLexer := lexer.New(srcTape)
Expand All @@ -706,7 +707,7 @@ func (p *Parser) parseSource() Command {
if cmd.Type == token.SOURCE {
p.errors = append(p.errors, NewError(p.peek, "Nested Source detected"))
p.nextToken()
return cmd
return []Command{cmd}
}
}

Expand All @@ -715,12 +716,23 @@ func (p *Parser) parseSource() Command {
if len(srcErrors) > 0 {
p.errors = append(p.errors, NewError(p.peek, fmt.Sprintf("%s has %d errors", srcPath, len(srcErrors))))
p.nextToken()
return cmd
return []Command{cmd}
}

cmd.Args = p.peek.Literal
filtered := make([]Command, 0, len(srcCmds))
for _, srcCmd := range srcCmds {
// Output have to be avoid in order to not overwrite output of the original tape.
if srcCmd.Type == token.SOURCE ||
srcCmd.Type == token.OUTPUT {
continue
}
srcCmd.Source = cmd.Args
filtered = append(filtered, srcCmd)
}

p.nextToken()
return cmd
return filtered
}

// parseScreenshot parses screenshot command.
Expand Down
14 changes: 12 additions & 2 deletions syntax.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import (

"github.com/charmbracelet/vhs/parser"
"github.com/charmbracelet/vhs/token"
"github.com/mattn/go-runewidth"
)

const sourceDisplayMaxLength = 10

// Highlight syntax highlights a command for prettier printing.
// It takes an argument whether or not to print the command in a faint style to
// represent hidden commands.
Expand All @@ -18,11 +21,17 @@ func Highlight(c parser.Command, faint bool) string {
argsStyle = NumberStyle
)

sourcePrefix := ""
if c.Source != "" {
displayPath := runewidth.Truncate(strings.TrimSuffix(c.Source, extension), sourceDisplayMaxLength, "…")
sourcePrefix = GrayStyle.Render(displayPath+":") + " "
}

if faint {
if c.Options != "" {
return FaintStyle.Render(fmt.Sprintf("%s %s %s", c.Type, c.Options, c.Args))
return sourcePrefix + FaintStyle.Render(fmt.Sprintf("%s %s %s", c.Type, c.Options, c.Args))
}
return FaintStyle.Render(fmt.Sprintf("%s %s", c.Type, c.Args))
return sourcePrefix + FaintStyle.Render(fmt.Sprintf("%s %s", c.Type, c.Args))
}

switch c.Type {
Expand Down Expand Up @@ -55,6 +64,7 @@ func Highlight(c parser.Command, faint bool) string {
}

var s strings.Builder
s.WriteString(sourcePrefix)
s.WriteString(CommandStyle.Render(c.Type.String()) + " ")
if c.Options != "" {
s.WriteString(optionsStyle.Render(c.Options))
Expand Down

0 comments on commit 5d26011

Please sign in to comment.