- );
- }
-);
-
type WorkspaceListEntry = {
windowId: string;
workspace: Workspace;
@@ -175,15 +57,21 @@ const WorkspaceSwitcher = forwardRef((_, ref) => {
setWorkspaceList(newList);
}, []);
+ useEffect(
+ () =>
+ waveEventSubscribe({
+ eventType: "workspace:update",
+ handler: () => fireAndForget(updateWorkspaceList),
+ }),
+ []
+ );
+
useEffect(() => {
fireAndForget(updateWorkspaceList);
}, []);
const onDeleteWorkspace = useCallback((workspaceId: string) => {
getApi().deleteWorkspace(workspaceId);
- setTimeout(() => {
- fireAndForget(updateWorkspaceList);
- }, 10);
}, []);
const isActiveWorkspaceSaved = !!(activeWorkspace.name && activeWorkspace.icon);
@@ -266,9 +154,16 @@ const WorkspaceSwitcherItem = ({
const setWorkspace = useCallback((newWorkspace: Workspace) => {
if (newWorkspace.name != "") {
- setObjectValue({ ...newWorkspace, otype: "workspace" }, undefined, true);
+ fireAndForget(() =>
+ WorkspaceService.UpdateWorkspace(
+ workspace.oid,
+ newWorkspace.name,
+ newWorkspace.icon,
+ newWorkspace.color,
+ false
+ )
+ );
}
- setWorkspaceEntry({ ...workspaceEntry, workspace: newWorkspace });
}, []);
const isActive = !!workspaceEntry.windowId;
diff --git a/pkg/service/workspaceservice/workspaceservice.go b/pkg/service/workspaceservice/workspaceservice.go
index b48bafcc8..1c86ff77b 100644
--- a/pkg/service/workspaceservice/workspaceservice.go
+++ b/pkg/service/workspaceservice/workspaceservice.go
@@ -50,6 +50,9 @@ func (svc *WorkspaceService) UpdateWorkspace(ctx context.Context, workspaceId st
return nil, fmt.Errorf("error updating workspace: %w", err)
}
+ wps.Broker.Publish(wps.WaveEvent{
+ Event: wps.Event_WorkspaceUpdate})
+
updates := waveobj.ContextGetUpdatesRtn(ctx)
go func() {
defer panichandler.PanicHandler("WorkspaceService:UpdateWorkspace:SendUpdateEvents")
diff --git a/pkg/wcore/window.go b/pkg/wcore/window.go
index 53fd823c1..19dea5392 100644
--- a/pkg/wcore/window.go
+++ b/pkg/wcore/window.go
@@ -28,7 +28,8 @@ func SwitchWorkspace(ctx context.Context, windowId string, workspaceId string) (
if err != nil {
return nil, fmt.Errorf("error getting window: %w", err)
}
- if window.WorkspaceId == workspaceId {
+ curWsId := window.WorkspaceId
+ if curWsId == workspaceId {
return nil, nil
}
@@ -45,24 +46,24 @@ func SwitchWorkspace(ctx context.Context, windowId string, workspaceId string) (
return nil, err
}
}
-
- curWs, err := GetWorkspace(ctx, window.WorkspaceId)
+ window.WorkspaceId = workspaceId
+ err = wstore.DBUpdate(ctx, window)
if err != nil {
- return nil, fmt.Errorf("error getting current workspace: %w", err)
+ return nil, fmt.Errorf("error updating window: %w", err)
}
- deleted, err := DeleteWorkspace(ctx, curWs.OID, false)
+
+ deleted, err := DeleteWorkspace(ctx, curWsId, false)
if err != nil {
return nil, fmt.Errorf("error deleting current workspace: %w", err)
}
if !deleted {
- log.Printf("current workspace %s was not deleted\n", curWs.OID)
+ log.Printf("current workspace %s was not deleted\n", curWsId)
} else {
- log.Printf("deleted current workspace %s\n", curWs.OID)
+ log.Printf("deleted current workspace %s\n", curWsId)
}
- window.WorkspaceId = workspaceId
log.Printf("switching window %s to workspace %s\n", windowId, workspaceId)
- return ws, wstore.DBUpdate(ctx, window)
+ return ws, nil
}
func GetWindow(ctx context.Context, windowId string) (*waveobj.Window, error) {
diff --git a/pkg/wcore/workspace.go b/pkg/wcore/workspace.go
index c0b2da324..b3143b2ab 100644
--- a/pkg/wcore/workspace.go
+++ b/pkg/wcore/workspace.go
@@ -122,6 +122,7 @@ func DeleteWorkspace(ctx context.Context, workspaceId string, force bool) (bool,
return false, fmt.Errorf("error closing tab: %w", err)
}
}
+ windowId, err := wstore.DBFindWindowForWorkspaceId(ctx, workspaceId)
err = wstore.DBDelete(ctx, waveobj.OType_Workspace, workspaceId)
if err != nil {
return false, fmt.Errorf("error deleting workspace: %w", err)
@@ -129,6 +130,12 @@ func DeleteWorkspace(ctx context.Context, workspaceId string, force bool) (bool,
log.Printf("deleted workspace %s\n", workspaceId)
wps.Broker.Publish(wps.WaveEvent{
Event: wps.Event_WorkspaceUpdate})
+ if windowId != "" {
+ err = CloseWindow(ctx, windowId, false)
+ if err != nil {
+ return false, fmt.Errorf("error closing window: %w", err)
+ }
+ }
return true, nil
}
From 95b1767c4557cf975cd2223081749e107cc5a3a2 Mon Sep 17 00:00:00 2001
From: Mike Sawka
Date: Tue, 17 Dec 2024 11:55:34 -0800
Subject: [PATCH 13/35] fix terminal escape sequence printing bug (#1544)
## Summary by CodeRabbit
- **Bug Fixes**
- Improved handling of terminal data processing by ensuring it only
occurs when the terminal is fully initialized.
---
frontend/app/view/term/termwrap.ts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/frontend/app/view/term/termwrap.ts b/frontend/app/view/term/termwrap.ts
index 84c940ca3..0ab2ea634 100644
--- a/frontend/app/view/term/termwrap.ts
+++ b/frontend/app/view/term/termwrap.ts
@@ -165,6 +165,9 @@ export class TermWrap {
}
handleTermData(data: string) {
+ if (!this.loaded) {
+ return;
+ }
const b64data = util.stringToBase64(data);
RpcApi.ControllerInputCommand(TabRpcClient, { blockid: this.blockId, inputdata64: b64data });
}
From f5305cc8dd78609ad0966117a18ec64d2875b9fb Mon Sep 17 00:00:00 2001
From: Sylvie Crowe <107814465+oneirocosm@users.noreply.github.com>
Date: Tue, 17 Dec 2024 12:22:57 -0800
Subject: [PATCH 14/35] Disable Wsh on Remotes where the Domain Socket Listener
Fails (#1542)
A recent change meant that if certain operations for setting up wsh
failed, a fallback would be employed to launch the terminal without the
wsh connection. This adds the domain socket listener to the list of
things that are allowed to fail before retrying without wsh instead of
failing outright.
---
pkg/remote/conncontroller/conncontroller.go | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/pkg/remote/conncontroller/conncontroller.go b/pkg/remote/conncontroller/conncontroller.go
index b66088923..1215be657 100644
--- a/pkg/remote/conncontroller/conncontroller.go
+++ b/pkg/remote/conncontroller/conncontroller.go
@@ -509,11 +509,6 @@ func (conn *SSHConn) connectInternal(ctx context.Context, connFlags *wshrpc.Conn
conn.WithLock(func() {
conn.Client = client
})
- err = conn.OpenDomainSocketListener()
- if err != nil {
- log.Printf("error: unable to open domain socket listener for %s: %v\n", conn.GetName(), err)
- return err
- }
config := wconfig.ReadFullConfig()
enableWsh := config.Settings.ConnWshEnabled
askBeforeInstall := config.Settings.ConnAskBeforeWshInstall
@@ -545,15 +540,22 @@ func (conn *SSHConn) connectInternal(ctx context.Context, connFlags *wshrpc.Conn
}
if conn.WshEnabled.Load() {
- csErr := conn.StartConnServer()
- if csErr != nil {
- log.Printf("error: unable to start conn server for %s: %v\n", conn.GetName(), csErr)
+ dsErr := conn.OpenDomainSocketListener()
+ var csErr error
+ if dsErr != nil {
+ log.Printf("error: unable to open domain socket listener for %s: %v\n", conn.GetName(), dsErr)
+ } else {
+ csErr = conn.StartConnServer()
+ if csErr != nil {
+ log.Printf("error: unable to start conn server for %s: %v\n", conn.GetName(), csErr)
+ }
+ }
+ if dsErr != nil || csErr != nil {
log.Print("attempting to run with nowsh instead")
conn.WithLock(func() {
conn.WshError = csErr.Error()
})
conn.WshEnabled.Store(false)
- //return fmt.Errorf("conncontroller %s start wsh connserver error: %v", conn.GetName(), csErr)
}
}
} else {
From 799aecd501553662613128d83913b768857076b7 Mon Sep 17 00:00:00 2001
From: Evan Simkowitz
Date: Tue, 17 Dec 2024 13:00:55 -0800
Subject: [PATCH 15/35] Add ZDOTDIR after JWT token for WSL commands (#1546)
---
pkg/shellexec/shellexec.go | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/pkg/shellexec/shellexec.go b/pkg/shellexec/shellexec.go
index d22cdbb1f..2c811d85c 100644
--- a/pkg/shellexec/shellexec.go
+++ b/pkg/shellexec/shellexec.go
@@ -167,9 +167,6 @@ func StartWslShellProc(ctx context.Context, termSize waveobj.TermSize, cmdStr st
homeDir := wsl.GetHomeDir(conn.Context, client)
shellOpts = append(shellOpts, "~", "-d", client.Name())
- if isZshShell(shellPath) {
- shellOpts = append(shellOpts, fmt.Sprintf(`ZDOTDIR="%s/.waveterm/%s"`, homeDir, shellutil.ZshIntegrationDir))
- }
var subShellOpts []string
if cmdStr == "" {
@@ -216,6 +213,10 @@ func StartWslShellProc(ctx context.Context, termSize waveobj.TermSize, cmdStr st
} else {
shellOpts = append(shellOpts, "--", fmt.Sprintf(`%s=%s`, wshutil.WaveJwtTokenVarName, jwtToken))
}
+
+ if isZshShell(shellPath) {
+ shellOpts = append(shellOpts, fmt.Sprintf(`ZDOTDIR="%s/.waveterm/%s"`, homeDir, shellutil.ZshIntegrationDir))
+ }
shellOpts = append(shellOpts, shellPath)
shellOpts = append(shellOpts, subShellOpts...)
log.Printf("full cmd is: %s %s", "wsl.exe", strings.Join(shellOpts, " "))
From 0a3dadb6285b2752f036c377a017a849b6ba7fe5 Mon Sep 17 00:00:00 2001
From: Evan Simkowitz
Date: Tue, 17 Dec 2024 14:11:40 -0800
Subject: [PATCH 16/35] Add `wsh wavepath` command for getting Wave paths
(#1545)
---
cmd/wsh/cmd/wshcmd-wavepath.go | 135 +++++++++++++++++++++++++++++
docs/docs/wsh-reference.mdx | 48 ++++++++++
frontend/app/store/wshclientapi.ts | 5 ++
frontend/layout/lib/layoutModel.ts | 5 ++
frontend/types/gotypes.d.ts | 10 +++
go.mod | 1 +
go.sum | 2 +
pkg/waveobj/wtype.go | 1 +
pkg/wshrpc/wshclient/wshclient.go | 6 ++
pkg/wshrpc/wshrpctypes.go | 9 ++
pkg/wshrpc/wshserver/wshserver.go | 39 +++++++++
11 files changed, 261 insertions(+)
create mode 100644 cmd/wsh/cmd/wshcmd-wavepath.go
diff --git a/cmd/wsh/cmd/wshcmd-wavepath.go b/cmd/wsh/cmd/wshcmd-wavepath.go
new file mode 100644
index 000000000..fcfcbc7f3
--- /dev/null
+++ b/cmd/wsh/cmd/wshcmd-wavepath.go
@@ -0,0 +1,135 @@
+// Copyright 2024, Command Line Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+package cmd
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+
+ "github.com/spf13/cobra"
+ "github.com/wavetermdev/waveterm/pkg/wshrpc"
+ "github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
+)
+
+var wavepathCmd = &cobra.Command{
+ Use: "wavepath {config|data|log}",
+ Short: "Get paths to various waveterm files and directories",
+ RunE: wavepathRun,
+ PreRunE: preRunSetupRpcClient,
+}
+
+func init() {
+ wavepathCmd.Flags().BoolP("open", "o", false, "Open the path in a new block")
+ wavepathCmd.Flags().BoolP("open-external", "O", false, "Open the path in the default external application")
+ wavepathCmd.Flags().BoolP("tail", "t", false, "Tail the last 100 lines of the log")
+ rootCmd.AddCommand(wavepathCmd)
+}
+
+func wavepathRun(cmd *cobra.Command, args []string) (rtnErr error) {
+ defer func() {
+ sendActivity("wavepath", rtnErr == nil)
+ }()
+
+ if len(args) == 0 {
+ OutputHelpMessage(cmd)
+ return fmt.Errorf("no arguments. wsh wavepath requires a type argument (config, data, or log)")
+ }
+ if len(args) > 1 {
+ OutputHelpMessage(cmd)
+ return fmt.Errorf("too many arguments. wsh wavepath requires exactly one argument")
+ }
+
+ pathType := args[0]
+ if pathType != "config" && pathType != "data" && pathType != "log" {
+ OutputHelpMessage(cmd)
+ return fmt.Errorf("invalid path type %q. must be one of: config, data, log", pathType)
+ }
+
+ tail, _ := cmd.Flags().GetBool("tail")
+ if tail && pathType != "log" {
+ return fmt.Errorf("--tail can only be used with the log path type")
+ }
+
+ open, _ := cmd.Flags().GetBool("open")
+ openExternal, _ := cmd.Flags().GetBool("open-external")
+
+ path, err := wshclient.PathCommand(RpcClient, wshrpc.PathCommandData{
+ PathType: pathType,
+ Open: open,
+ OpenExternal: openExternal,
+ }, nil)
+ if err != nil {
+ return fmt.Errorf("getting path: %w", err)
+ }
+
+ if tail && pathType == "log" {
+ err = tailLogFile(path)
+ if err != nil {
+ return fmt.Errorf("tailing log file: %w", err)
+ }
+ return nil
+ }
+
+ WriteStdout("%s\n", path)
+ return nil
+}
+
+func tailLogFile(path string) error {
+ file, err := os.Open(path)
+ if err != nil {
+ return fmt.Errorf("opening log file: %w", err)
+ }
+ defer file.Close()
+
+ // Get file size
+ stat, err := file.Stat()
+ if err != nil {
+ return fmt.Errorf("getting file stats: %w", err)
+ }
+
+ // Read last 16KB or whole file if smaller
+ readSize := int64(16 * 1024)
+ var offset int64
+ if stat.Size() > readSize {
+ offset = stat.Size() - readSize
+ }
+
+ _, err = file.Seek(offset, 0)
+ if err != nil {
+ return fmt.Errorf("seeking file: %w", err)
+ }
+
+ buf := make([]byte, readSize)
+ n, err := file.Read(buf)
+ if err != nil && err != io.EOF {
+ return fmt.Errorf("reading file: %w", err)
+ }
+ buf = buf[:n]
+
+ // Skip partial line at start if we're not at beginning of file
+ if offset > 0 {
+ idx := bytes.IndexByte(buf, '\n')
+ if idx >= 0 {
+ buf = buf[idx+1:]
+ }
+ }
+
+ // Split into lines
+ lines := bytes.Split(buf, []byte{'\n'})
+
+ // Take last 100 lines if we have more
+ startIdx := 0
+ if len(lines) > 100 {
+ startIdx = len(lines) - 100
+ }
+
+ // Print lines
+ for _, line := range lines[startIdx:] {
+ WriteStdout("%s\n", string(line))
+ }
+
+ return nil
+}
diff --git a/docs/docs/wsh-reference.mdx b/docs/docs/wsh-reference.mdx
index b5c095ed5..2931c4683 100644
--- a/docs/docs/wsh-reference.mdx
+++ b/docs/docs/wsh-reference.mdx
@@ -693,4 +693,52 @@ wsh setvar -b client MYVAR=value
Variables set with these commands persist across sessions and can be used to store configuration values, secrets, or any other string data that needs to be accessible across blocks or tabs.
+## wavepath
+
+The `wavepath` command lets you get the paths to various Wave Terminal directories and files, including configuration, data storage, and logs.
+
+```bash
+wsh wavepath {config|data|log}
+```
+
+This command returns the full path to the requested Wave Terminal system directory or file. It's useful for accessing Wave's configuration files, data storage, or checking logs.
+
+Flags:
+
+- `-o, --open` - open the path in a new block
+- `-O, --open-external` - open the path in the default external application
+- `-t, --tail` - show the last ~100 lines of the log file (only valid for log path)
+
+Examples:
+
+```bash
+# Get path to config directory
+wsh wavepath config
+
+# Get path to data directory
+wsh wavepath data
+
+# Get path to log file
+wsh wavepath log
+
+# Open log file in a new block
+wsh wavepath -o log
+
+# Open config directory in system file explorer
+wsh wavepath -O config
+
+# View recent log entries
+wsh wavepath -t log
+```
+
+The command will show you the full path to:
+
+- `config` - Where Wave Terminal stores its configuration files
+- `data` - Where Wave Terminal stores its persistent data
+- `log` - The main Wave Terminal log file
+
+:::tip
+Use the `-t` flag with the log path to quickly view recent log entries without having to open the full file. This is particularly useful for troubleshooting.
+:::
+
diff --git a/frontend/app/store/wshclientapi.ts b/frontend/app/store/wshclientapi.ts
index a5e75774d..846091596 100644
--- a/frontend/app/store/wshclientapi.ts
+++ b/frontend/app/store/wshclientapi.ts
@@ -202,6 +202,11 @@ class RpcApiType {
return client.wshRpcCall("notify", data, opts);
}
+ // command "path" [call]
+ PathCommand(client: WshClient, data: PathCommandData, opts?: RpcOpts): Promise {
+ return client.wshRpcCall("path", data, opts);
+ }
+
// command "remotefiledelete" [call]
RemoteFileDeleteCommand(client: WshClient, data: string, opts?: RpcOpts): Promise {
return client.wshRpcCall("remotefiledelete", data, opts);
diff --git a/frontend/layout/lib/layoutModel.ts b/frontend/layout/lib/layoutModel.ts
index 1a70fc22d..7f8479c0a 100644
--- a/frontend/layout/lib/layoutModel.ts
+++ b/frontend/layout/lib/layoutModel.ts
@@ -412,6 +412,11 @@ export class LayoutModel {
for (const action of actions) {
switch (action.actiontype) {
case LayoutTreeActionType.InsertNode: {
+ if (action.ephemeral) {
+ this.newEphemeralNode(action.blockid);
+ break;
+ }
+
const insertNodeAction: LayoutTreeInsertNodeAction = {
type: LayoutTreeActionType.InsertNode,
node: newLayoutNode(undefined, undefined, undefined, {
diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts
index afd817690..895494bda 100644
--- a/frontend/types/gotypes.d.ts
+++ b/frontend/types/gotypes.d.ts
@@ -139,6 +139,7 @@ declare global {
blockdef: BlockDef;
rtopts?: RuntimeOpts;
magnified?: boolean;
+ ephemeral?: boolean;
};
// wshrpc.CommandCreateSubBlockData
@@ -400,6 +401,7 @@ declare global {
indexarr?: number[];
focused: boolean;
magnified: boolean;
+ ephemeral: boolean;
};
// waveobj.LayoutState
@@ -562,6 +564,14 @@ declare global {
prompt: OpenAIPromptMessageType[];
};
+ // wshrpc.PathCommandData
+ type PathCommandData = {
+ pathtype: string;
+ open: boolean;
+ openexternal: boolean;
+ tabid: string;
+ };
+
// waveobj.Point
type Point = {
x: number;
diff --git a/go.mod b/go.mod
index c713a76c6..772c34c62 100644
--- a/go.mod
+++ b/go.mod
@@ -20,6 +20,7 @@ require (
github.com/sawka/txwrap v0.2.0
github.com/shirou/gopsutil/v4 v4.24.11
github.com/skeema/knownhosts v1.3.0
+ github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/spf13/cobra v1.8.1
github.com/ubuntu/gowsl v0.0.0-20240906163211-049fd49bd93b
github.com/wavetermdev/htmltoken v0.2.0
diff --git a/go.sum b/go.sum
index b59c00510..8429144ec 100644
--- a/go.sum
+++ b/go.sum
@@ -68,6 +68,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
+github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
+github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
diff --git a/pkg/waveobj/wtype.go b/pkg/waveobj/wtype.go
index 9fa4bb3d1..af775e019 100644
--- a/pkg/waveobj/wtype.go
+++ b/pkg/waveobj/wtype.go
@@ -208,6 +208,7 @@ type LayoutActionData struct {
IndexArr *[]int `json:"indexarr,omitempty"`
Focused bool `json:"focused"`
Magnified bool `json:"magnified"`
+ Ephemeral bool `json:"ephemeral"`
}
type LeafOrderEntry struct {
diff --git a/pkg/wshrpc/wshclient/wshclient.go b/pkg/wshrpc/wshclient/wshclient.go
index d8aa04748..3dce286c4 100644
--- a/pkg/wshrpc/wshclient/wshclient.go
+++ b/pkg/wshrpc/wshclient/wshclient.go
@@ -247,6 +247,12 @@ func NotifyCommand(w *wshutil.WshRpc, data wshrpc.WaveNotificationOptions, opts
return err
}
+// command "path", wshserver.PathCommand
+func PathCommand(w *wshutil.WshRpc, data wshrpc.PathCommandData, opts *wshrpc.RpcOpts) (string, error) {
+ resp, err := sendRpcRequestCallHelper[string](w, "path", data, opts)
+ return resp, err
+}
+
// command "remotefiledelete", wshserver.RemoteFileDeleteCommand
func RemoteFileDeleteCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
_, err := sendRpcRequestCallHelper[any](w, "remotefiledelete", data, opts)
diff --git a/pkg/wshrpc/wshrpctypes.go b/pkg/wshrpc/wshrpctypes.go
index ed5aaa7bb..71806f6b0 100644
--- a/pkg/wshrpc/wshrpctypes.go
+++ b/pkg/wshrpc/wshrpctypes.go
@@ -149,6 +149,7 @@ type WshRpcInterface interface {
ActivityCommand(ctx context.Context, data ActivityUpdate) error
GetVarCommand(ctx context.Context, data CommandVarData) (*CommandVarResponseData, error)
SetVarCommand(ctx context.Context, data CommandVarData) error
+ PathCommand(ctx context.Context, data PathCommandData) (string, error)
// connection functions
ConnStatusCommand(ctx context.Context) ([]ConnStatus, error)
@@ -290,6 +291,7 @@ type CommandCreateBlockData struct {
BlockDef *waveobj.BlockDef `json:"blockdef"`
RtOpts *waveobj.RuntimeOpts `json:"rtopts,omitempty"`
Magnified bool `json:"magnified,omitempty"`
+ Ephemeral bool `json:"ephemeral,omitempty"`
}
type CommandCreateSubBlockData struct {
@@ -604,6 +606,13 @@ type CommandVarResponseData struct {
Exists bool `json:"exists"`
}
+type PathCommandData struct {
+ PathType string `json:"pathtype"`
+ Open bool `json:"open"`
+ OpenExternal bool `json:"openexternal"`
+ TabId string `json:"tabid" wshcontext:"TabId"`
+}
+
type ActivityDisplayType struct {
Width int `json:"width"`
Height int `json:"height"`
diff --git a/pkg/wshrpc/wshserver/wshserver.go b/pkg/wshrpc/wshserver/wshserver.go
index 9e0cd1702..b4e2acfec 100644
--- a/pkg/wshrpc/wshserver/wshserver.go
+++ b/pkg/wshrpc/wshserver/wshserver.go
@@ -12,10 +12,12 @@ import (
"fmt"
"io/fs"
"log"
+ "path/filepath"
"regexp"
"strings"
"time"
+ "github.com/skratchdot/open-golang/open"
"github.com/wavetermdev/waveterm/pkg/blockcontroller"
"github.com/wavetermdev/waveterm/pkg/filestore"
"github.com/wavetermdev/waveterm/pkg/panichandler"
@@ -183,6 +185,7 @@ func (ws *WshServer) CreateBlockCommand(ctx context.Context, data wshrpc.Command
ActionType: wcore.LayoutActionDataType_Insert,
BlockId: blockData.OID,
Magnified: data.Magnified,
+ Ephemeral: data.Ephemeral,
Focused: true,
})
if err != nil {
@@ -829,3 +832,39 @@ func (ws *WshServer) SetVarCommand(ctx context.Context, data wshrpc.CommandVarDa
envStr := envutil.MapToEnv(envMap)
return filestore.WFS.WriteFile(ctx, data.ZoneId, data.FileName, []byte(envStr))
}
+
+func (ws *WshServer) PathCommand(ctx context.Context, data wshrpc.PathCommandData) (string, error) {
+ pathType := data.PathType
+ openInternal := data.Open
+ openExternal := data.OpenExternal
+ var path string
+ switch pathType {
+ case "config":
+ path = wavebase.GetWaveConfigDir()
+ case "data":
+ path = wavebase.GetWaveDataDir()
+ case "log":
+ path = filepath.Join(wavebase.GetWaveDataDir(), "waveapp.log")
+ }
+
+ if openInternal && openExternal {
+ return "", fmt.Errorf("open and openExternal cannot both be true")
+ }
+
+ if openInternal {
+ _, err := ws.CreateBlockCommand(ctx, wshrpc.CommandCreateBlockData{BlockDef: &waveobj.BlockDef{Meta: map[string]any{
+ waveobj.MetaKey_View: "preview",
+ waveobj.MetaKey_File: path,
+ }}, Ephemeral: true, TabId: data.TabId})
+
+ if err != nil {
+ return path, fmt.Errorf("error opening path: %w", err)
+ }
+ } else if openExternal {
+ err := open.Run(path)
+ if err != nil {
+ return path, fmt.Errorf("error opening path: %w", err)
+ }
+ }
+ return path, nil
+}
From a06ba64e2f167d15a132ab0d93b03a62bf7ea4a9 Mon Sep 17 00:00:00 2001
From: Mike Sawka
Date: Tue, 17 Dec 2024 14:23:27 -0800
Subject: [PATCH 17/35] document markdown font size settings (#1547)
## Summary by CodeRabbit
- **New Features**
- Introduced new configuration options for markdown rendering:
- `markdown:fontsize` for normal text size (default 14px).
- `markdown:fixedfontsize` for code block text size (default 12px).
---
docs/docs/config.mdx | 2 ++
1 file changed, 2 insertions(+)
diff --git a/docs/docs/config.mdx b/docs/docs/config.mdx
index c72095558..c960d8be5 100644
--- a/docs/docs/config.mdx
+++ b/docs/docs/config.mdx
@@ -46,6 +46,8 @@ wsh editconfig
| editor:minimapenabled | bool | set to false to disable editor minimap |
| editor:stickyscrollenabled | bool | enables monaco editor's stickyScroll feature (pinning headers of current context, e.g. class names, method names, etc.), defaults to false |
| editor:wordwrap | bool | set to true to enable word wrapping in the editor (defaults to false) |
+| markdown:fontsize | float64 | font size for the normal text when rendering markdown in preview. headers are scaled up from this size, (default 14px) |
+| markdown:fixedfontsize | float64 | font size for the code blocks when rendering markdown in preview (default is 12px) |
| web:openlinksinternally | bool | set to false to open web links in external browser |
| web:defaulturl | string | default web page to open in the web widget when no url is provided (homepage) |
| web:defaultsearch | string | search template for web searches. e.g. `https://www.google.com/search?q={query}`. "\{query}" gets replaced by search term |
From 801034c87d0856051bdbd6375bf0c4c8b15f74b8 Mon Sep 17 00:00:00 2001
From: "wave-builder[bot]"
<181805596+wave-builder[bot]@users.noreply.github.com>
Date: Tue, 17 Dec 2024 22:24:41 +0000
Subject: [PATCH 18/35] chore: bump package version to 0.10.2-beta.0
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index cdb5a81ca..6497727ea 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"productName": "Wave",
"description": "Open-Source AI-Native Terminal Built for Seamless Workflows",
"license": "Apache-2.0",
- "version": "0.10.1",
+ "version": "0.10.2-beta.0",
"homepage": "https://waveterm.dev",
"build": {
"appId": "dev.commandline.waveterm"
From dbc2be1c1e9272a948ad08c20666af307eddb24c Mon Sep 17 00:00:00 2001
From: Sylvie Crowe <107814465+oneirocosm@users.noreply.github.com>
Date: Tue, 17 Dec 2024 15:25:34 -0800
Subject: [PATCH 19/35] Global Hotkey Docs (#1548)
Adds the following changes:
- renames "key:globalhotkey" to "app:globalhotkey"
- adds globalhostkey documentation (especially in regard to what keys are allowed)
- improves the algorithm that converts electron keybindings from wave keybindings
- fixes some regexp problems
---
docs/docs/config.mdx | 42 ++++++++++++++++++++++
docs/docs/keybindings.mdx | 4 +++
emain/emain-util.ts | 66 +++++++++++++++++++++++++++++++++++
emain/emain.ts | 2 +-
frontend/types/gotypes.d.ts | 4 +--
pkg/wconfig/metaconsts.go | 6 ++--
pkg/wconfig/settingsconfig.go | 6 ++--
7 files changed, 121 insertions(+), 9 deletions(-)
diff --git a/docs/docs/config.mdx b/docs/docs/config.mdx
index c960d8be5..49cada776 100644
--- a/docs/docs/config.mdx
+++ b/docs/docs/config.mdx
@@ -25,6 +25,7 @@ wsh editconfig
| Key Name | Type | Function |
| ------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| app:globalhotkey | string | A systemwide keybinding to open your most recent wave window. This is a set of key names separated by `:`. For more info, see [Customizable Systemwide Global Hotkey](#customizable-systemwide-global-hotkey) |
| ai:preset | string | the default AI preset to use |
| ai:baseurl | string | Set the AI Base Url (must be OpenAI compatible) |
| ai:apitoken | string | your AI api token |
@@ -190,3 +191,44 @@ wsh editconfig termthemes.json
| background | CSS color | | | background color (default when no color code is applied), must have alpha channel (#rrggbbaa) if you want the terminal to be transparent |
| cursorAccent | CSS color | | | color for cursor |
| selectionBackground | CSS color | | | background color for selected text |
+
+### Customizable Systemwide Global Hotkey
+
+Wave allows settings a custom global hotkey to open your most recent window from anywhere in your computer. This has the name `"app:globalhotkey"` in the `settings.json` file and takes the form of a series of key names separated by the `:` character. We support the following key names:
+
+- `Ctrl`
+- `Cmd`
+- `Shift`
+- `Alt`
+- `Option`
+- `Meta`
+- `Super`
+- Digits (non-numpad) represented by `c{Digit0}` through `c{Digit9}`
+- Letters `a` though `z`
+- F keys `F1` through `F20`
+- Soft keys `Soft1` through `Soft4`. These are essentially the same as `F21` through `F24`.
+- Space represented as a literal space
+- `Enter` (This is labeled as return on Mac)
+- `Tab`
+- `CapsLock`
+- `NumLock`
+- `Backspace` (This is labeled as delete on Mac)
+- `Delete`
+- `Insert`
+- The arrow keys `ArrowUp`, `ArrowDown`, `ArrowLeft`, and `ArrowRight`
+- `Home`
+- `End`
+- `PageUp`
+- `PageDown`
+- `Esc`
+- Volume controls `AudioVolumeUp`, `AudioVolumeDown`, `AudioVolumeMute`
+- Media controls `MediaTrackNext`, `MediaTrackPrevious`, `MediaPlayPause`, and `MediaStop`
+- `PrintScreen`
+- Numpad keys represented by `c{Numpad0}` through `c{Numpad9}`
+- The numpad decimal represented by `Decimal`
+- The numpad plus/add represented by `Add`
+- The numpad minus/subtract represented by `Subtract`
+- The numpad star/multiply represented by `Multiply`
+- The numpad slash/divide represented by `Divide`
+
+As an example, to set the key to the combination of Control, Option, and the letter E, you would configure it to `"Ctrl:Opt:e"`.
diff --git a/docs/docs/keybindings.mdx b/docs/docs/keybindings.mdx
index 2313bacc3..cfb1569e5 100644
--- a/docs/docs/keybindings.mdx
+++ b/docs/docs/keybindings.mdx
@@ -71,4 +71,8 @@ replace "Cmd" with "Alt" (note that "Ctrl" is "Ctrl" on both Mac, Windows, and L
| ---------------- | ------------- |
| | Clear AI Chat |
+## Customizeable Systemwide Global Hotkey
+
+Wave allows setting a custom global hotkey to focus your most recent window from anywhere in your computer. For more information on this, see [the config docs](./config#customizable-systemwide-global-hotkey).
+
diff --git a/emain/emain-util.ts b/emain/emain-util.ts
index 16fbf9367..601b1b7f3 100644
--- a/emain/emain-util.ts
+++ b/emain/emain-util.ts
@@ -170,6 +170,9 @@ export function ensureBoundsAreVisible(bounds: electron.Rectangle): electron.Rec
export function waveKeyToElectronKey(waveKey: string): string {
const waveParts = waveKey.split(":");
const electronParts: Array = waveParts.map((part: string) => {
+ const digitRegexpMatch = new RegExp("^c{Digit([0-9])}$").exec(part);
+ const numpadRegexpMatch = new RegExp("^c{Numpad([0-9])}$").exec(part);
+ const lowercaseCharMatch = new RegExp("^([a-z])$").exec(part);
if (part == "ArrowUp") {
return "Up";
}
@@ -182,6 +185,69 @@ export function waveKeyToElectronKey(waveKey: string): string {
if (part == "ArrowRight") {
return "Right";
}
+ if (part == "Soft1") {
+ return "F21";
+ }
+ if (part == "Soft2") {
+ return "F22";
+ }
+ if (part == "Soft3") {
+ return "F23";
+ }
+ if (part == "Soft4") {
+ return "F24";
+ }
+ if (part == " ") {
+ return "Space";
+ }
+ if (part == "CapsLock") {
+ return "Capslock";
+ }
+ if (part == "NumLock") {
+ return "Numlock";
+ }
+ if (part == "ScrollLock") {
+ return "Scrolllock";
+ }
+ if (part == "AudioVolumeUp") {
+ return "VolumeUp";
+ }
+ if (part == "AudioVolumeDown") {
+ return "VolumeDown";
+ }
+ if (part == "AudioVolumeMute") {
+ return "VolumeMute";
+ }
+ if (part == "MediaTrackNext") {
+ return "MediaNextTrack";
+ }
+ if (part == "MediaTrackPrevious") {
+ return "MediaPreviousTrack";
+ }
+ if (part == "Decimal") {
+ return "numdec";
+ }
+ if (part == "Add") {
+ return "numadd";
+ }
+ if (part == "Subtract") {
+ return "numsub";
+ }
+ if (part == "Multiply") {
+ return "nummult";
+ }
+ if (part == "Divide") {
+ return "numdiv";
+ }
+ if (digitRegexpMatch && digitRegexpMatch.length > 1) {
+ return digitRegexpMatch[1];
+ }
+ if (numpadRegexpMatch && numpadRegexpMatch.length > 1) {
+ return `num${numpadRegexpMatch[1]}`;
+ }
+ if (lowercaseCharMatch && lowercaseCharMatch.length > 1) {
+ return lowercaseCharMatch[1].toUpperCase();
+ }
return part;
});
diff --git a/emain/emain.ts b/emain/emain.ts
index c5cf985be..a4511db45 100644
--- a/emain/emain.ts
+++ b/emain/emain.ts
@@ -611,7 +611,7 @@ async function appMain() {
fireAndForget(createNewWaveWindow);
}
});
- const rawGlobalHotKey = launchSettings?.["key:globalhotkey"];
+ const rawGlobalHotKey = launchSettings?.["app:globalhotkey"];
if (rawGlobalHotKey) {
registerGlobalHotkey(rawGlobalHotKey);
}
diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts
index 895494bda..c0149d01e 100644
--- a/frontend/types/gotypes.d.ts
+++ b/frontend/types/gotypes.d.ts
@@ -616,6 +616,8 @@ declare global {
// wconfig.SettingsType
type SettingsType = {
+ "app:*"?: boolean;
+ "app:globalhotkey"?: string;
"ai:*"?: boolean;
"ai:preset"?: string;
"ai:apitype"?: string;
@@ -674,8 +676,6 @@ declare global {
"window:magnifiedblocksize"?: number;
"window:magnifiedblockblurprimarypx"?: number;
"window:magnifiedblockblursecondarypx"?: number;
- "key:*"?: boolean;
- "key:globalhotkey"?: string;
"telemetry:*"?: boolean;
"telemetry:enabled"?: boolean;
"conn:*"?: boolean;
diff --git a/pkg/wconfig/metaconsts.go b/pkg/wconfig/metaconsts.go
index 6e62b5c20..7e95579ad 100644
--- a/pkg/wconfig/metaconsts.go
+++ b/pkg/wconfig/metaconsts.go
@@ -6,6 +6,9 @@
package wconfig
const (
+ ConfigKey_AppClear = "app:*"
+ ConfigKey_AppGlobalHotkey = "app:globalhotkey"
+
ConfigKey_AiClear = "ai:*"
ConfigKey_AiPreset = "ai:preset"
ConfigKey_AiApiType = "ai:apitype"
@@ -75,9 +78,6 @@ const (
ConfigKey_WindowMagnifiedBlockBlurPrimaryPx = "window:magnifiedblockblurprimarypx"
ConfigKey_WindowMagnifiedBlockBlurSecondaryPx = "window:magnifiedblockblursecondarypx"
- ConfigKey_KeyClear = "key:*"
- ConfigKey_KeyGlobalHotkey = "key:globalhotkey"
-
ConfigKey_TelemetryClear = "telemetry:*"
ConfigKey_TelemetryEnabled = "telemetry:enabled"
diff --git a/pkg/wconfig/settingsconfig.go b/pkg/wconfig/settingsconfig.go
index 6b9e58319..8b312db4b 100644
--- a/pkg/wconfig/settingsconfig.go
+++ b/pkg/wconfig/settingsconfig.go
@@ -33,6 +33,9 @@ const AnySchema = `
`
type SettingsType struct {
+ AppClear bool `json:"app:*,omitempty"`
+ AppGlobalHotkey string `json:"app:globalhotkey,omitempty"`
+
AiClear bool `json:"ai:*,omitempty"`
AiPreset string `json:"ai:preset,omitempty"`
AiApiType string `json:"ai:apitype,omitempty"`
@@ -102,9 +105,6 @@ type SettingsType struct {
WindowMagnifiedBlockBlurPrimaryPx *int64 `json:"window:magnifiedblockblurprimarypx,omitempty"`
WindowMagnifiedBlockBlurSecondaryPx *int64 `json:"window:magnifiedblockblursecondarypx,omitempty"`
- KeyClear bool `json:"key:*,omitempty"`
- KeyGlobalHotkey string `json:"key:globalhotkey,omitempty"`
-
TelemetryClear bool `json:"telemetry:*,omitempty"`
TelemetryEnabled bool `json:"telemetry:enabled,omitempty"`
From 69bb1d4274a7f1c87e14042b87cafb4df9383f1c Mon Sep 17 00:00:00 2001
From: Sylvie Crowe <107814465+oneirocosm@users.noreply.github.com>
Date: Tue, 17 Dec 2024 17:06:34 -0800
Subject: [PATCH 20/35] Fish and Pwsh Examples (#1549)
This adds example widgets to the docs for fish and powershell core
(pwsh)
---
docs/docs/customwidgets.mdx | 60 +++++++++++++++++++++++++++++++++++--
1 file changed, 58 insertions(+), 2 deletions(-)
diff --git a/docs/docs/customwidgets.mdx b/docs/docs/customwidgets.mdx
index ca61fdb0f..8f693ee58 100644
--- a/docs/docs/customwidgets.mdx
+++ b/docs/docs/customwidgets.mdx
@@ -109,9 +109,65 @@ The `WidgetConfigType` takes the usual options common to all widgets. The `MetaT
| "term:localshellpath" | (optional) Sets the shell used for running your widget command. Only works locally. If left blank, wave will determine your system default instead. |
| "term:localshellopts" | (optional) Sets the shell options meant to be used with `"term:localshellpath"`. This is useful if you are using a nonstandard shell and need to provide a specific option that we do not cover. Only works locally. Defaults to an empty string. |
-## Example Terminal Widgets
+## Example Shell Widgets
-Here are a few simple widgets to serve as examples.
+If you have multiple shells installed on your machine, there may be times when you want to use a non-default shell. For cases like this, it is easy to create a widget for each.
+
+Suppose you want a widget to launch a `fish` shell. Once you have `fish` installed on your system, you can define a widget as
+
+```json
+{
+ <... other widgets go here ...>,
+ "fish" : {
+ "icon": "fish",
+ "color": "#4abc39",
+ "label": "fish",
+ "blockdef": {
+ "meta": {
+ "view": "term",
+ "controller": "shell",
+ "term:localshellpath": "/usr/local/bin/fish",
+ "term:localshellopts": "-i -l"
+ }
+ }
+ },
+ <... other widgets go here ...>
+}
+```
+
+:::info
+It is very possible that `fish` is not in your path. In this case, using `"fish"` as the value of `"term:localshellpath"` will not work. In these cases, you will need to provide a direct path to it. This is often somewhere like `"/usr/local/bin/fish"`, but it may be different on your system.
+:::
+
+If you want to do the same for something like Powershell Core, or `pwsh`, you can define the widget as
+
+```json
+{
+ <... other widgets go here ...>,
+ "pwsh" : {
+ "icon": "rectangle-terminal",
+ "color": "#2671be",
+ "label": "pwsh",
+ "blockdef": {
+ "meta": {
+ "view": "term",
+ "controller": "shell",
+ "term:localshellpath": "pwsh"
+ }
+ }
+ },
+ <... other widgets go here ...>
+}
+```
+
+:::info
+It is very possible that `pwsh` is not in your path. In this case, using `"pwsh"` as the value of `"term:localshellpath"` will not work. In these cases, you will need to provide a direct path to it. This could be somewhere like `"/usr/local/bin/pwsh"` on a Unix system or "C:\\Program Files\\PowerShell\\7\\pwsh.exe" on
+Windows. but it may be different on your system. Also note that both `pwsh.exe` and `pwsh` work on Windows, but only `pwsh` works on Unix systems.
+:::
+
+## Example Cmd Widgets
+
+Here are a few simple cmd widgets to serve as examples.
Suppose I want a widget that will run speedtest-go when opened. Then, I can define a widget as
From 410c01cae32ecd69339320c04b36f556521eb77f Mon Sep 17 00:00:00 2001
From: Sylvie Crowe <107814465+oneirocosm@users.noreply.github.com>
Date: Wed, 18 Dec 2024 00:19:15 -0800
Subject: [PATCH 21/35] Connections Examples (#1552)
Adds a few examples to the `connections.mdx` file to show:
- hiding a connection
- re-ordering connections
- theming connections
- disabling wsh for a connection
---
docs/docs/connections.mdx | 66 +++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/docs/docs/connections.mdx b/docs/docs/connections.mdx
index 4fb79ba62..066410a92 100644
--- a/docs/docs/connections.mdx
+++ b/docs/docs/connections.mdx
@@ -76,6 +76,72 @@ In addition to the regular ssh config file, wave also has its own config file to
| term:theme | This string can be used to specify a terminal theme for blocks using this connection. The block metadata takes priority over this setting. It defaults to null which means the global setting will be used instead. |
| ssh:identityfile | A list of strings containing the paths to identity files that will be used. If a `wsh ssh` command using the `-i` flag is successful, the identity file will automatically be added here. |
+### Example Internal Configurations
+
+Here are a couple examples of things you can do using the internal configuration file `connections.json`:
+
+#### Hiding a Connection
+
+Suppose you have a connection named `github.com` in your `~/.ssh/config` file that shows up as `git@github.com` in the connections dropdown. While it does belong in the config file for authentication reasons, it makes no sense to be in the dropdown since it doesn't involve connecting to a remote environment. In that case, you can hide it as in the example below:
+
+```json
+{
+ <... other connections go here ...>,
+ "git@github.com" : {
+ "display:hidden": true
+ },
+ <... other connections go here ...>
+}
+```
+
+#### Moving a Connection
+
+Suppose you have a connection named `rarelyused` that shows up as `myusername@rarelyused:9999` in the connections dropdown. Since it's so rarely used, you would prefer to move it later in the list. In that case, you can move it as in the example below:
+
+```json
+{
+ <... other connections go here ...>,
+ "myusername@rarelyused:9999" : {
+ "display:order": 100
+ },
+ <... other connections go here ...>
+}
+```
+
+#### Theming a Connection
+
+Suppose you have a connection named `myhost` that shows up as `myusername@myhost` in the connections dropdown. You use this connection a lot, but you keep getting it mixed up with your local connections. In this case, you can use the internal configuration file to style it differently. For example:
+
+```json
+{
+ <... other connections go here ...>,
+ "myusername@myhost" : {
+ "term:theme": "warmyellow",
+ "term:fontsize": 16,
+ "term:fontfamily": "menlo"
+ },
+ <... other connections go here ...>
+}
+```
+
+This style, font size, and font family will then only apply to the widgets that are using this connection.
+
+### Disabling Wsh for a Connection
+
+While Wave provides an option disable `wsh` when first connecting to a remote, there are cases where you may wish to disable it afterward. The easiest way to do this is by editing the `connections.json` file. Suppose the connection shows up in the dropdown as `root@wshless`. Then you can disable it manually with the following line:
+
+```json
+{
+ <... other connections go here ...>,
+ "root@wshless" : {
+ "conn:enablewsh": false,
+ },
+ <... other connections go here ...>
+}
+```
+
+Note that this same line gets added to your `connections.json` file automatically when you choose to disable `wsh` in gui when initially connecting.
+
## Managing Connections with the CLI
The `wsh` command gives some commands specifically for interacting with the connections. You can view these [here](/wsh-reference#conn).
From cc6da280323964066a6b0ab5537e47092033a87c Mon Sep 17 00:00:00 2001
From: Evan Simkowitz
Date: Wed, 18 Dec 2024 08:14:27 -0800
Subject: [PATCH 22/35] Add FAQ for WSH outside of Wave (#1558)
Adds FAQ explaining that WSH doesn't work outside of Wave
---
docs/docs/faq.mdx | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/docs/docs/faq.mdx b/docs/docs/faq.mdx
index dac3754ed..d8b84a151 100644
--- a/docs/docs/faq.mdx
+++ b/docs/docs/faq.mdx
@@ -30,3 +30,7 @@ Just remember in JSON, backslashes need to be escaped. So add this to your [sett
```json
"term:localshellpath": "C:\\Program Files\\Git\\bin\\bash.exe"
```
+
+### Can I use WSH outside of Wave?
+
+`wsh` is an internal CLI for extending control over Wave to the command line, you can learn more about it [here](./wsh). To prevent misuse by other applications, `wsh` requires an access token provided by Wave to work and will not function outside of the app.
From 007c2391f1369971c732557a4de4b517490555a4 Mon Sep 17 00:00:00 2001
From: Sylvie Crowe <107814465+oneirocosm@users.noreply.github.com>
Date: Wed, 18 Dec 2024 13:15:28 -0800
Subject: [PATCH 23/35] Shell Example Pictures (#1562)
- adds pictures to the fish and pwsh examples
- reformats some tabs as spaces in the example json
- adds missing brackets around some older json examples
- rewords repetitive parts of the shell examples
---
docs/docs/customwidgets.mdx | 70 +++++++++++++++----------
docs/docs/img/widget-example-fish.webp | Bin 0 -> 130078 bytes
docs/docs/img/widget-example-pwsh.webp | Bin 0 -> 132266 bytes
3 files changed, 43 insertions(+), 27 deletions(-)
create mode 100644 docs/docs/img/widget-example-fish.webp
create mode 100644 docs/docs/img/widget-example-pwsh.webp
diff --git a/docs/docs/customwidgets.mdx b/docs/docs/customwidgets.mdx
index 8f693ee58..44e6a95d0 100644
--- a/docs/docs/customwidgets.mdx
+++ b/docs/docs/customwidgets.mdx
@@ -118,25 +118,28 @@ Suppose you want a widget to launch a `fish` shell. Once you have `fish` install
```json
{
<... other widgets go here ...>,
- "fish" : {
- "icon": "fish",
- "color": "#4abc39",
- "label": "fish",
- "blockdef": {
- "meta": {
- "view": "term",
- "controller": "shell",
- "term:localshellpath": "/usr/local/bin/fish",
- "term:localshellopts": "-i -l"
- }
- }
- },
+ "fish" : {
+ "icon": "fish",
+ "color": "#4abc39",
+ "label": "fish",
+ "blockdef": {
+ "meta": {
+ "view": "term",
+ "controller": "shell",
+ "term:localshellpath": "/usr/local/bin/fish",
+ "term:localshellopts": "-i -l"
+ }
+ }
+ },
<... other widgets go here ...>
}
```
+This adds an icon to the widget bar that you can press to launch a terminal running the `fish` shell.
+![The example fish widget](./img/widget-example-fish.webp)
+
:::info
-It is very possible that `fish` is not in your path. In this case, using `"fish"` as the value of `"term:localshellpath"` will not work. In these cases, you will need to provide a direct path to it. This is often somewhere like `"/usr/local/bin/fish"`, but it may be different on your system.
+It is possible that `fish` is not in your path. If this is true, using `"fish"` as the value of `"term:localshellpath"` will not work. In these cases, you will need to provide a direct path to it. This is often somewhere like `"/usr/local/bin/fish"`, but it may be different on your system.
:::
If you want to do the same for something like Powershell Core, or `pwsh`, you can define the widget as
@@ -144,24 +147,27 @@ If you want to do the same for something like Powershell Core, or `pwsh`, you ca
```json
{
<... other widgets go here ...>,
- "pwsh" : {
- "icon": "rectangle-terminal",
- "color": "#2671be",
- "label": "pwsh",
- "blockdef": {
- "meta": {
- "view": "term",
- "controller": "shell",
- "term:localshellpath": "pwsh"
- }
- }
- },
+ "pwsh" : {
+ "icon": "rectangle-terminal",
+ "color": "#2671be",
+ "label": "pwsh",
+ "blockdef": {
+ "meta": {
+ "view": "term",
+ "controller": "shell",
+ "term:localshellpath": "pwsh"
+ }
+ }
+ },
<... other widgets go here ...>
}
```
+This adds an icon to the widget bar that you can press to launch a terminal running the `pwsh` shell.
+![The example pwsh widget](./img/widget-example-pwsh.webp)
+
:::info
-It is very possible that `pwsh` is not in your path. In this case, using `"pwsh"` as the value of `"term:localshellpath"` will not work. In these cases, you will need to provide a direct path to it. This could be somewhere like `"/usr/local/bin/pwsh"` on a Unix system or "C:\\Program Files\\PowerShell\\7\\pwsh.exe" on
+It is possible that `pwsh` is not in your path. If this is true, using `"pwsh"` as the value of `"term:localshellpath"` will not work. In these cases, you will need to provide a direct path to it. This could be somewhere like `"/usr/local/bin/pwsh"` on a Unix system or "C:\\Program Files\\PowerShell\\7\\pwsh.exe" on
Windows. but it may be different on your system. Also note that both `pwsh.exe` and `pwsh` work on Windows, but only `pwsh` works on Unix systems.
:::
@@ -198,6 +204,7 @@ Using `"cmd"` for the `"controller"` is the simplest way to accomplish this. `"c
Now suppose I wanted to run a TUI app, for instance, `dua`. Well, it turns out that you can more or less do the same thing:
```json
+{
<... other widgets go here ...>,
"dua" : {
"icon": "brands@linux",
@@ -211,6 +218,7 @@ Now suppose I wanted to run a TUI app, for instance, `dua`. Well, it turns out t
}
},
<... other widgets go here ...>
+}
```
This adds an icon to the widget bar that you can press to launch a terminal running the `dua` command.
@@ -252,6 +260,7 @@ The `WidgetConfigType` takes the usual options common to all widgets. The `MetaT
Say you want a widget that automatically starts at YouTube and will use YouTube as the home page. This can be done using:
```json
+{
<... other widgets go here ...>,
"youtube" : {
"icon": "brands@youtube",
@@ -265,6 +274,7 @@ Say you want a widget that automatically starts at YouTube and will use YouTube
}
},
<... other widgets go here ...>
+}
```
This adds an icon to the widget bar that you can press to launch a web widget on the youtube homepage.
@@ -273,6 +283,7 @@ This adds an icon to the widget bar that you can press to launch a web widget on
Alternatively, say you want a web widget that opens to github as if it were a bookmark, but will use google as its home page after that. This can easily be done with:
```json
+{
<... other widgets go here ...>,
"github" : {
"icon": "brands@github",
@@ -286,6 +297,7 @@ Alternatively, say you want a web widget that opens to github as if it were a bo
}
},
<... other widgets go here ...>
+}
```
This adds an icon to the widget bar that you can press to launch a web widget on the github homepage.
@@ -326,6 +338,7 @@ The `WidgetConfigType` takes the usual options common to all widgets. The `MetaT
Suppose you have a build process that lasts 3 minutes and you'd like to be able to see the entire build on the sysinfo graph. Also, you would really like to view both the cpu and memory since both are impacted by this process. In that case, you can set up a widget as follows:
```json
+{
<... other widgets go here ...>,
"3min-info" : {
"icon": "circle-3",
@@ -339,6 +352,7 @@ Suppose you have a build process that lasts 3 minutes and you'd like to be able
}
},
<... other widgets go here ...>
+}
```
This adds an icon to the widget bar that you can press to launch the CPU and Memory plots by default with 180 seconds of data.
@@ -347,6 +361,7 @@ This adds an icon to the widget bar that you can press to launch the CPU and Mem
Now, suppose you are fine with the default 100 points (and 100 seconds) but would like to show all of the CPU data when launched. In that case, you can write:
```json
+{
<... other widgets go here ...>,
"all-cpu" : {
"icon": "chart-scatter",
@@ -359,6 +374,7 @@ Now, suppose you are fine with the default 100 points (and 100 seconds) but woul
}
},
<... other widgets go here ...>
+}
```
This adds an icon to the widget bar that you can press to launch All CPU plots by default.
diff --git a/docs/docs/img/widget-example-fish.webp b/docs/docs/img/widget-example-fish.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0819ce981d02455283f4d983b42a1146bd85b0b6
GIT binary patch
literal 130078
zcmbrmV|ZoTwly5vwr$(4*tYFd#je