Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,23 +417,23 @@ func (p *Parser) parseKeypress(ct token.Type) Command {
func (p *Parser) parseOutput() Command {
cmd := Command{Type: token.OUTPUT}

if p.peek.Type != token.STRING {
path, ok := p.parsePathArgument()
if !ok {
p.errors = append(p.errors, NewError(p.cur, "Expected file path after output"))
return cmd
}

ext := filepath.Ext(p.peek.Literal)
ext := filepath.Ext(path)
if ext != "" {
cmd.Options = ext
} else {
cmd.Options = ".png"
if !strings.HasSuffix(p.peek.Literal, "/") {
p.errors = append(p.errors, NewError(p.peek, "Expected folder with trailing slash"))
if !strings.HasSuffix(path, "/") {
p.errors = append(p.errors, NewError(p.cur, "Expected folder with trailing slash"))
}
}

cmd.Args = p.peek.Literal
p.nextToken()
cmd.Args = path
return cmd
}

Expand Down Expand Up @@ -756,28 +756,46 @@ func (p *Parser) parseSource() []Command {
func (p *Parser) parseScreenshot() Command {
cmd := Command{Type: token.SCREENSHOT}

if p.peek.Type != token.STRING {
path, ok := p.parsePathArgument()
if !ok {
p.errors = append(p.errors, NewError(p.cur, "Expected path after Screenshot"))
p.nextToken()
return cmd
}

path := p.peek.Literal

// Check if path has .png extension
ext := filepath.Ext(path)
if ext != ".png" {
p.errors = append(p.errors, NewError(p.peek, "Expected file with .png extension"))
p.nextToken()
p.errors = append(p.errors, NewError(p.cur, "Expected file with .png extension"))
return cmd
}

cmd.Args = path
p.nextToken()

return cmd
}

// parsePathArgument parses either a regular string path or an absolute path
// tokenized as REGEX followed by an optional STRING suffix.
func (p *Parser) parsePathArgument() (string, bool) {
switch p.peek.Type {
case token.STRING:
path := p.peek.Literal
p.nextToken()
return path, true
case token.REGEX:
path := "/" + p.peek.Literal + "/"
p.nextToken()
if p.peek.Type == token.STRING {
path += p.peek.Literal
p.nextToken()
}
return path, true
default:
return "", false
}
}

// Errors returns any errors that occurred during parsing.
func (p *Parser) Errors() []Error {
return p.errors
Expand Down
48 changes: 48 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,54 @@ func TestParseTapeFile(t *testing.T) {
}
}

func TestParseAbsolutePaths(t *testing.T) {
input := `
Output /tmp/demo.gif
Output /tmp/demo.mp4
Output /home/user/recordings/demo.webm
Output /frames/
Output examples/out.gif
Output frames/
Screenshot /tmp/screenshot.png
Screenshot examples/screenshot.png`

expected := []Command{
{Type: token.OUTPUT, Options: ".gif", Args: "/tmp/demo.gif"},
{Type: token.OUTPUT, Options: ".mp4", Args: "/tmp/demo.mp4"},
{Type: token.OUTPUT, Options: ".webm", Args: "/home/user/recordings/demo.webm"},
{Type: token.OUTPUT, Options: ".png", Args: "/frames/"},
{Type: token.OUTPUT, Options: ".gif", Args: "examples/out.gif"},
{Type: token.OUTPUT, Options: ".png", Args: "frames/"},
{Type: token.SCREENSHOT, Args: "/tmp/screenshot.png"},
{Type: token.SCREENSHOT, Args: "examples/screenshot.png"},
}

l := lexer.New(input)
p := New(l)

cmds := p.Parse()

if len(p.Errors()) > 0 {
t.Fatalf("Expected no parser errors, got %v", p.Errors())
}

if len(cmds) != len(expected) {
t.Fatalf("Expected %d commands, got %d", len(expected), len(cmds))
}

for i, cmd := range cmds {
if cmd.Type != expected[i].Type {
t.Errorf("Expected command %d to be %s, got %s", i, expected[i].Type, cmd.Type)
}
if cmd.Args != expected[i].Args {
t.Errorf("Expected command %d to have args %s, got %s", i, expected[i].Args, cmd.Args)
}
if cmd.Options != expected[i].Options {
t.Errorf("Expected command %d to have options %s, got %s", i, expected[i].Options, cmd.Options)
}
}
}

func TestParseCtrl(t *testing.T) {
tests := []struct {
name string
Expand Down