Skip to content

Commit 7acc694

Browse files
committed
clipboard: Add subcommand to-host
Signed-off-by: Paulo Gomes <[email protected]>
1 parent acc5f40 commit 7acc694

File tree

5 files changed

+76
-14
lines changed

5 files changed

+76
-14
lines changed

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,19 @@ qubesome start -git https://github.com/qubesome/sample-dotfiles -local <local_gi
5555

5656
Copy clipboard from the host to the i3 profile:
5757
```
58-
qubesome clipboard --from-host i3
58+
qubesome clip from-host i3
59+
```
60+
61+
Copy clipboard from the i3 profile to the host:
62+
```
63+
qubesome clip to-host i3
5964
```
6065

6166
#### Available Commands
6267

6368
- `qubesome start`: Start a qubesome environment for a given profile.
6469
- `qubesome run`: Run qubesome workloads.
65-
- `qubesome clipboard`: Manage the images within your workloads.
70+
- `qubesome clip`: Manage the images within your workloads.
6671
- `qubesome images`: Manage the images within your workloads.
6772
- `qubesome xdg`: Handle xdg-open based via qubesome.
6873

cmd/cli/clipboard.go

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ func clipboardCommand() *cli.Command {
2828
Usage: "enable sharing of clipboard across profiles and the host",
2929
Commands: []*cli.Command{
3030
{
31-
Name: "from-host",
31+
Name: "from-host",
32+
Usage: "copies the clipboard contents from the host to a profile",
3233
Arguments: []cli.Argument{
3334
&cli.StringArg{
3435
Name: "target_profile",
@@ -64,7 +65,8 @@ func clipboardCommand() *cli.Command {
6465
},
6566
},
6667
{
67-
Name: "from-profile",
68+
Name: "from-profile",
69+
Usage: "copies the clipboard contents between profiles",
6870
Arguments: []cli.Argument{
6971
&cli.StringArg{
7072
Name: "source_profile",
@@ -105,6 +107,43 @@ func clipboardCommand() *cli.Command {
105107
opts = append(opts, clipboard.WithContentType(typ))
106108
}
107109

110+
return clipboard.Run(
111+
opts...,
112+
)
113+
},
114+
},
115+
{
116+
Name: "to-host",
117+
Usage: "copies the clipboard contents from a profile to the host",
118+
Arguments: []cli.Argument{
119+
&cli.StringArg{
120+
Name: "source_profile",
121+
Min: 1,
122+
Max: 1,
123+
Destination: &sourceProfile,
124+
},
125+
},
126+
Flags: []cli.Flag{
127+
clipType,
128+
},
129+
Action: func(ctx context.Context, c *cli.Command) error {
130+
cfg := profileConfigOrDefault(sourceProfile)
131+
132+
target, ok := cfg.Profiles[sourceProfile]
133+
if !ok {
134+
return fmt.Errorf("no active profile %q found", sourceProfile)
135+
}
136+
137+
opts := []command.Option[clipboard.Options]{
138+
clipboard.WithSourceProfile(target),
139+
clipboard.WithTargetHost(),
140+
}
141+
142+
if typ := c.String("type"); typ != "" {
143+
fmt.Println(typ)
144+
opts = append(opts, clipboard.WithContentType(typ))
145+
}
146+
108147
return clipboard.Run(
109148
opts...,
110149
)

internal/clipboard/clipboard.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77

88
"github.com/qubesome/cli/internal/command"
99
"github.com/qubesome/cli/internal/files"
10-
"github.com/qubesome/cli/internal/types"
1110
"golang.org/x/sys/execabs"
1211
)
1312

@@ -22,37 +21,43 @@ func Run(opts ...command.Option[Options]) error {
2221
opt(o)
2322
}
2423

25-
var from uint8
26-
var to *types.Profile
24+
var from, target uint8
25+
var profile string
2726

2827
if o.SourceProfile != nil {
2928
from = o.SourceProfile.Display
29+
profile = o.SourceProfile.Name
3030
}
3131

32-
if o.TargetProfile != nil {
33-
to = o.TargetProfile
32+
if o.TargetProfile == nil && !o.ToHost {
33+
return fmt.Errorf("target profile cannot be nil when ToHost is false")
3434
}
3535

36-
if !validTarget(o.ContentType) {
37-
return fmt.Errorf("%w: %s", ErrUnsupportedCopyType, o.ContentType)
36+
if o.TargetProfile != nil {
37+
target = o.TargetProfile.Display
38+
profile = o.TargetProfile.Name
3839
}
3940

40-
if from == to.Display {
41+
if from == target {
4142
return ErrCannotCopyClipboardWithinSameDisplay
4243
}
4344

45+
if !validTarget(o.ContentType) {
46+
return fmt.Errorf("%w: %s", ErrUnsupportedCopyType, o.ContentType)
47+
}
48+
4449
targetExtra := ""
4550
if o.ContentType != "" {
4651
targetExtra = fmt.Sprintf("-t %s", o.ContentType)
4752
}
4853

49-
cookiePath, err := files.ServerCookiePath(to.Name)
54+
cookiePath, err := files.ServerCookiePath(profile)
5055
if err != nil {
5156
return fmt.Errorf("cannot get X magic cookie path: %w", err)
5257
}
5358

5459
xclip := fmt.Sprintf("%s -selection clip -o -display :%d | XAUTHORITY=%s %s -selection clip %s -i -display :%d",
55-
files.XclipBinary, int(from), cookiePath, files.XclipBinary, targetExtra, int(to.Display))
60+
files.XclipBinary, int(from), cookiePath, files.XclipBinary, targetExtra, int(target))
5661

5762
slog.Debug("clipboard copy", "command", []string{files.ShBinary, "-c", xclip})
5863
cmd := execabs.Command(files.ShBinary, "-c", xclip) //nolint

internal/clipboard/clipboard_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ func TestCopy(t *testing.T) {
3030
target: "foo",
3131
wantErr: "unsupported copy type",
3232
},
33+
{
34+
name: "no target",
35+
from: &types.Profile{Display: 0},
36+
wantErr: "target profile cannot be nil when ToHost is false",
37+
},
3338
}
3439

3540
for _, tc := range tests {

internal/clipboard/options.go

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

88
type Options struct {
99
FromHost bool
10+
ToHost bool
1011
SourceProfile *types.Profile
1112
TargetProfile *types.Profile
1213
ContentType string
@@ -29,8 +30,15 @@ func WithTargetProfile(p *types.Profile) command.Option[Options] {
2930
o.TargetProfile = p
3031
}
3132
}
33+
3234
func WithContentType(t string) command.Option[Options] {
3335
return func(o *Options) {
3436
o.ContentType = t
3537
}
3638
}
39+
40+
func WithTargetHost() command.Option[Options] {
41+
return func(o *Options) {
42+
o.ToHost = true
43+
}
44+
}

0 commit comments

Comments
 (0)