Skip to content

Commit 5d26011

Browse files
committed
fix source
1 parent ad1ca7c commit 5d26011

File tree

3 files changed

+55
-86
lines changed

3 files changed

+55
-86
lines changed

command.go

Lines changed: 3 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package main
33
import (
44
"encoding/json"
55
"fmt"
6-
"io"
76
"os"
87
"os/exec"
98
"regexp"
@@ -12,25 +11,16 @@ import (
1211
"time"
1312

1413
"github.com/atotto/clipboard"
15-
"github.com/charmbracelet/vhs/lexer"
1614
"github.com/charmbracelet/vhs/parser"
1715
"github.com/charmbracelet/vhs/token"
1816
"github.com/go-rod/rod/lib/input"
19-
"github.com/mattn/go-runewidth"
2017
)
2118

2219
// Execute executes a command on a running instance of vhs.
2320
func Execute(c parser.Command, v *VHS) error {
24-
if c.Type == token.SOURCE {
25-
err := ExecuteSourceTape(c, v)
26-
if err != nil {
27-
return fmt.Errorf("failed to execute source tape: %w", err)
28-
}
29-
} else {
30-
err := CommandFuncs[c.Type](c, v)
31-
if err != nil {
32-
return fmt.Errorf("failed to execute command: %w", err)
33-
}
21+
err := CommandFuncs[c.Type](c, v)
22+
if err != nil {
23+
return fmt.Errorf("failed to execute command: %w", err)
3424
}
3525

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

713-
const sourceDisplayMaxLength = 10
714-
715-
// ExecuteSourceTape is a CommandFunc that executes all commands of source tape.
716-
func ExecuteSourceTape(c parser.Command, v *VHS) error {
717-
tapePath := c.Args
718-
var out io.Writer = os.Stdout
719-
if quietFlag {
720-
out = io.Discard
721-
}
722-
723-
// read tape file
724-
tape, err := os.ReadFile(tapePath)
725-
if err != nil {
726-
return fmt.Errorf("failed to read tape %s: %w", tapePath, err)
727-
}
728-
729-
l := lexer.New(string(tape))
730-
p := parser.New(l)
731-
732-
cmds := p.Parse()
733-
if len(p.Errors()) != 0 {
734-
return InvalidSyntaxError{p.Errors()}
735-
}
736-
737-
displayPath := runewidth.Truncate(strings.TrimSuffix(tapePath, extension), sourceDisplayMaxLength, "…")
738-
739-
// Run all commands from the sourced tape file.
740-
for _, cmd := range cmds {
741-
// Output have to be avoid in order to not overwrite output of the original tape.
742-
if cmd.Type == token.SOURCE ||
743-
cmd.Type == token.OUTPUT {
744-
continue
745-
}
746-
_, _ = fmt.Fprintf(out, "%s %s\n", GrayStyle.Render(displayPath+":"), Highlight(cmd, false))
747-
err := CommandFuncs[cmd.Type](cmd, v)
748-
if err != nil {
749-
return fmt.Errorf("failed to execute command %s: %w", cmd.Type.String(), err)
750-
}
751-
}
752-
753-
return nil
754-
}
755-
756703
// ExecuteScreenshot is a CommandFunc that indicates a new screenshot must be taken.
757704
func ExecuteScreenshot(c parser.Command, v *VHS) error {
758705
v.ScreenshotNextFrame(c.Args)

parser/parser.go

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ type Command struct {
6565
Type CommandType
6666
Options string
6767
Args string
68+
Source string
6869
}
6970

7071
// String returns the string representation of the command.
@@ -123,15 +124,15 @@ func (p *Parser) Parse() []Command {
123124
p.nextToken()
124125
continue
125126
}
126-
cmds = append(cmds, p.parseCommand())
127+
cmds = append(cmds, p.parseCommand()...)
127128
p.nextToken()
128129
}
129130

130131
return cmds
131132
}
132133

133134
// parseCommand parses a command.
134-
func (p *Parser) parseCommand() Command {
135+
func (p *Parser) parseCommand() []Command {
135136
switch p.cur.Type {
136137
case token.SPACE,
137138
token.BACKSPACE,
@@ -146,42 +147,42 @@ func (p *Parser) parseCommand() Command {
146147
token.UP,
147148
token.PAGEUP,
148149
token.PAGEDOWN:
149-
return p.parseKeypress(p.cur.Type)
150+
return []Command{p.parseKeypress(p.cur.Type)}
150151
case token.SET:
151-
return p.parseSet()
152+
return []Command{p.parseSet()}
152153
case token.OUTPUT:
153-
return p.parseOutput()
154+
return []Command{p.parseOutput()}
154155
case token.SLEEP:
155-
return p.parseSleep()
156+
return []Command{p.parseSleep()}
156157
case token.TYPE:
157-
return p.parseType()
158+
return []Command{p.parseType()}
158159
case token.CTRL:
159-
return p.parseCtrl()
160+
return []Command{p.parseCtrl()}
160161
case token.ALT:
161-
return p.parseAlt()
162+
return []Command{p.parseAlt()}
162163
case token.SHIFT:
163-
return p.parseShift()
164+
return []Command{p.parseShift()}
164165
case token.HIDE:
165-
return p.parseHide()
166+
return []Command{p.parseHide()}
166167
case token.REQUIRE:
167-
return p.parseRequire()
168+
return []Command{p.parseRequire()}
168169
case token.SHOW:
169-
return p.parseShow()
170+
return []Command{p.parseShow()}
170171
case token.WAIT:
171-
return p.parseWait()
172+
return []Command{p.parseWait()}
172173
case token.SOURCE:
173174
return p.parseSource()
174175
case token.SCREENSHOT:
175-
return p.parseScreenshot()
176+
return []Command{p.parseScreenshot()}
176177
case token.COPY:
177-
return p.parseCopy()
178+
return []Command{p.parseCopy()}
178179
case token.PASTE:
179-
return p.parsePaste()
180+
return []Command{p.parsePaste()}
180181
case token.ENV:
181-
return p.parseEnv()
182+
return []Command{p.parseEnv()}
182183
default:
183184
p.errors = append(p.errors, NewError(p.cur, "Invalid command: "+p.cur.Literal))
184-
return Command{Type: token.ILLEGAL}
185+
return []Command{{Type: token.ILLEGAL}}
185186
}
186187
}
187188

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

658659
if p.peek.Type != token.STRING {
659660
p.errors = append(p.errors, NewError(p.cur, "Expected path after Source"))
660661
p.nextToken()
661-
return cmd
662+
return []Command{cmd}
662663
}
663664

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

674675
// Check if tape exist
675676
if _, err := os.Stat(srcPath); os.IsNotExist(err) {
676677
notFoundErr := fmt.Sprintf("File %s not found", srcPath)
677678
p.errors = append(p.errors, NewError(p.peek, notFoundErr))
678679
p.nextToken()
679-
return cmd
680+
return []Command{cmd}
680681
}
681682

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

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

700701
srcLexer := lexer.New(srcTape)
@@ -706,7 +707,7 @@ func (p *Parser) parseSource() Command {
706707
if cmd.Type == token.SOURCE {
707708
p.errors = append(p.errors, NewError(p.peek, "Nested Source detected"))
708709
p.nextToken()
709-
return cmd
710+
return []Command{cmd}
710711
}
711712
}
712713

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

721722
cmd.Args = p.peek.Literal
723+
filtered := make([]Command, 0, len(srcCmds))
724+
for _, srcCmd := range srcCmds {
725+
// Output have to be avoid in order to not overwrite output of the original tape.
726+
if srcCmd.Type == token.SOURCE ||
727+
srcCmd.Type == token.OUTPUT {
728+
continue
729+
}
730+
srcCmd.Source = cmd.Args
731+
filtered = append(filtered, srcCmd)
732+
}
733+
722734
p.nextToken()
723-
return cmd
735+
return filtered
724736
}
725737

726738
// parseScreenshot parses screenshot command.

syntax.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ import (
77

88
"github.com/charmbracelet/vhs/parser"
99
"github.com/charmbracelet/vhs/token"
10+
"github.com/mattn/go-runewidth"
1011
)
1112

13+
const sourceDisplayMaxLength = 10
14+
1215
// Highlight syntax highlights a command for prettier printing.
1316
// It takes an argument whether or not to print the command in a faint style to
1417
// represent hidden commands.
@@ -18,11 +21,17 @@ func Highlight(c parser.Command, faint bool) string {
1821
argsStyle = NumberStyle
1922
)
2023

24+
sourcePrefix := ""
25+
if c.Source != "" {
26+
displayPath := runewidth.Truncate(strings.TrimSuffix(c.Source, extension), sourceDisplayMaxLength, "…")
27+
sourcePrefix = GrayStyle.Render(displayPath+":") + " "
28+
}
29+
2130
if faint {
2231
if c.Options != "" {
23-
return FaintStyle.Render(fmt.Sprintf("%s %s %s", c.Type, c.Options, c.Args))
32+
return sourcePrefix + FaintStyle.Render(fmt.Sprintf("%s %s %s", c.Type, c.Options, c.Args))
2433
}
25-
return FaintStyle.Render(fmt.Sprintf("%s %s", c.Type, c.Args))
34+
return sourcePrefix + FaintStyle.Render(fmt.Sprintf("%s %s", c.Type, c.Args))
2635
}
2736

2837
switch c.Type {
@@ -55,6 +64,7 @@ func Highlight(c parser.Command, faint bool) string {
5564
}
5665

5766
var s strings.Builder
67+
s.WriteString(sourcePrefix)
5868
s.WriteString(CommandStyle.Render(c.Type.String()) + " ")
5969
if c.Options != "" {
6070
s.WriteString(optionsStyle.Render(c.Options))

0 commit comments

Comments
 (0)