Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement copy + paste command #376

Merged
merged 4 commits into from
Oct 3, 2023
Merged
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ frames/
manpages
completions
dist
vhs
vhs
.idea/
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ There are a few basic types of VHS commands:
* [`Hide`](#hide): hide commands from output
* [`Show`](#show): stop hiding commands from output
* [`Screenshot`](#screenshot): screenshot the current frame
* [`Copy/Paste`](#copy--paste): copy and paste text from clipboard.

### Output

Expand Down Expand Up @@ -714,6 +715,17 @@ The `Screenshot` command captures the current frame (png format).
Screenshot examples/screenshot.png
```

### Copy / Paste

The `Copy` and `Paste` copy and paste the string from clipboard.

```elixir
Copy "https://github.com/charmbracelet"
Type "open "
Sleep 500ms
Paste
```

***

## Continuous Integration
Expand Down
25 changes: 25 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import (
"encoding/json"
"fmt"
"github.com/atotto/clipboard"

Check failure on line 6 in command.go

View workflow job for this annotation

GitHub Actions / lint

File is not `goimports`-ed (goimports)
"io"
"os"
"os/exec"
Expand Down Expand Up @@ -42,6 +43,8 @@
UP,
SOURCE,
SCREENSHOT,
COPY,
PASTE,
}

// String returns the string representation of the command.
Expand Down Expand Up @@ -81,6 +84,8 @@
ALT: ExecuteAlt,
ILLEGAL: ExecuteNoop,
SCREENSHOT: ExecuteScreenshot,
COPY: ExecuteCopy,
PASTE: ExecutePaste,
}

// Command represents a command with options and arguments.
Expand Down Expand Up @@ -259,6 +264,26 @@
}
}

func ExecuteCopy(c Command, _ *VHS) {

Check warning on line 267 in command.go

View workflow job for this annotation

GitHub Actions / lint

exported: exported function ExecuteCopy should have comment or be unexported (revive)
_ = clipboard.WriteAll(c.Args)
}

func ExecutePaste(_ Command, v *VHS) {

Check warning on line 271 in command.go

View workflow job for this annotation

GitHub Actions / lint

exported: exported function ExecutePaste should have comment or be unexported (revive)
clip, err := clipboard.ReadAll()
if err != nil {
return
}
for _, r := range clip {
k, ok := keymap[r]
if ok {
_ = v.Page.Keyboard.Type(k)
} else {
_ = v.Page.MustElement("textarea").Input(string(r))
v.Page.MustWaitIdle()
}
}
}

// Settings maps the Set commands to their respective functions.
var Settings = map[string]CommandFunc{
"FontFamily": ExecuteSetFontFamily,
Expand Down
Binary file added examples/clipboard.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions examples/clipboard.tape
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Output examples/commands/clipboard.gif

Set FontSize 42
Set Height 225

Copy "https://github.com/charmbracelet"
Type "open "
Sleep 500ms
Paste
Sleep 3s
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ require (
require (
github.com/alecthomas/chroma v0.10.0 // indirect
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/caarlos0/sshmarshal v0.1.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFI
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
Expand Down
2 changes: 2 additions & 0 deletions man.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ The following is a list of all possible commands in VHS:
* %Space% [repeat]
* %Source% <path>.tape
* %Screenshot% <path>.png
* %Copy% "<string>"
* %Paste%
`

manOutput = `The Output command instructs VHS where to save the output of the recording.
Expand Down
42 changes: 42 additions & 0 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ func (p *Parser) parseCommand() Command {
return p.parseSource()
case SCREENSHOT:
return p.parseScreenshot()
case COPY:
return p.parseCopy()
case PASTE:
return p.parsePaste()
default:
p.errors = append(p.errors, NewError(p.cur, "Invalid command: "+p.cur.Literal))
return Command{Type: ILLEGAL}
Expand Down Expand Up @@ -395,6 +399,44 @@ func (p *Parser) parseType() Command {
return cmd
}

// parseCopy parses a copy command
// A copy command takes a string to the clipboard
//
// Copy "string"
func (p *Parser) parseCopy() Command {
cmd := Command{Type: COPY}

if p.peek.Type != STRING {
p.errors = append(p.errors, NewError(p.peek, p.cur.Literal+" expects string"))
}
for p.peek.Type == STRING {
p.nextToken()
cmd.Args += p.cur.Literal

// If the next token is a string, add a space between them.
// Since tokens must be separated by a whitespace, this is most likely
// what the user intended.
//
// Although it is possible that there may be multiple spaces / tabs between
// the tokens, however if the user was intending to type multiple spaces
// they would need to use a string literal.

if p.peek.Type == STRING {
cmd.Args += " "
}
}
return cmd
}

// parsePaste parses paste command
// Paste Command the string from the clipboard buffer.
//
// Paste
func (p *Parser) parsePaste() Command {
cmd := Command{Type: PASTE}
return cmd
}

// parseSource parses source command.
// Source command takes a tape path to include in current tape.
//
Expand Down
23 changes: 13 additions & 10 deletions token.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,16 @@ const (
RIGHT = "RIGHT"
UP = "UP"

HIDE = "HIDE"
OUTPUT = "OUTPUT"
REQUIRE = "REQUIRE"
SET = "SET"
SHOW = "SHOW"
SOURCE = "SOURCE"
TYPE = "TYPE"
SCREENSHOT = "SCREENSHOT"

HIDE = "HIDE"
OUTPUT = "OUTPUT"
REQUIRE = "REQUIRE"
SET = "SET"
SHOW = "SHOW"
SOURCE = "SOURCE"
TYPE = "TYPE"
SCREENSHOT = "SCREENSHOT"
COPY = "COPY"
PASTE = "PASTE"
SHELL = "SHELL"
FONT_FAMILY = "FONT_FAMILY" //nolint:revive
FONT_SIZE = "FONT_SIZE" //nolint:revive
Expand Down Expand Up @@ -142,6 +143,8 @@ var keywords = map[string]TokenType{
"true": BOOLEAN,
"false": BOOLEAN,
"Screenshot": SCREENSHOT,
"Copy": COPY,
"Paste": PASTE,
}

// IsSetting returns whether a token is a setting.
Expand All @@ -163,7 +166,7 @@ func IsCommand(t TokenType) bool {
case TYPE, SLEEP,
UP, DOWN, RIGHT, LEFT, PAGEUP, PAGEDOWN,
ENTER, BACKSPACE, DELETE, TAB,
ESCAPE, HOME, INSERT, END, CTRL, SOURCE, SCREENSHOT:
ESCAPE, HOME, INSERT, END, CTRL, SOURCE, SCREENSHOT, COPY, PASTE:
return true
default:
return false
Expand Down
Loading