mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-02-08 00:21:23 +01:00
new config system (#283)
This commit is contained in:
parent
c9c555452a
commit
8630e23239
10
Taskfile.yml
10
Taskfile.yml
@ -164,17 +164,19 @@ tasks:
|
|||||||
generate:
|
generate:
|
||||||
desc: Generate Typescript bindings for the Go backend.
|
desc: Generate Typescript bindings for the Go backend.
|
||||||
cmds:
|
cmds:
|
||||||
- go run cmd/generate/main-generate.go
|
- go run cmd/generatets/main-generatets.go
|
||||||
- go run cmd/generatewshclient/main-generatewshclient.go
|
- go run cmd/generatego/main-generatego.go
|
||||||
sources:
|
sources:
|
||||||
- "cmd/generate/*.go"
|
- "cmd/generatego/*.go"
|
||||||
- "cmd/generatewshclient/*.go"
|
- "cmd/generatets/*.go"
|
||||||
- "pkg/service/**/*.go"
|
- "pkg/service/**/*.go"
|
||||||
- "pkg/waveobj/wtype.go"
|
- "pkg/waveobj/wtype.go"
|
||||||
- "pkg/wconfig/**/*.go"
|
- "pkg/wconfig/**/*.go"
|
||||||
- "pkg/wstore/*.go"
|
- "pkg/wstore/*.go"
|
||||||
- "pkg/wshrpc/**/*.go"
|
- "pkg/wshrpc/**/*.go"
|
||||||
- "pkg/tsgen/**/*.go"
|
- "pkg/tsgen/**/*.go"
|
||||||
|
- "pkg/gogen/**/*.go"
|
||||||
|
- "pkg/wconfig/**/*.go"
|
||||||
- "pkg/eventbus/eventbus.go"
|
- "pkg/eventbus/eventbus.go"
|
||||||
generates:
|
generates:
|
||||||
- frontend/types/gotypes.d.ts
|
- frontend/types/gotypes.d.ts
|
||||||
|
77
cmd/generatego/main-generatego.go
Normal file
77
cmd/generatego/main-generatego.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/gogen"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wconfig"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
const WshClientFileName = "pkg/wshrpc/wshclient/wshclient.go"
|
||||||
|
const WaveObjMetaConstsFileName = "pkg/waveobj/metaconsts.go"
|
||||||
|
const SettingsMetaConstsFileName = "pkg/wconfig/metaconsts.go"
|
||||||
|
|
||||||
|
func GenerateWshClient() {
|
||||||
|
fmt.Fprintf(os.Stderr, "generating wshclient file to %s\n", WshClientFileName)
|
||||||
|
var buf strings.Builder
|
||||||
|
gogen.GenerateBoilerplate(&buf, "wshclient", []string{
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wshutil",
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wshrpc",
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/waveobj",
|
||||||
|
})
|
||||||
|
wshDeclMap := wshrpc.GenerateWshCommandDeclMap()
|
||||||
|
for _, key := range utilfn.GetOrderedMapKeys(wshDeclMap) {
|
||||||
|
methodDecl := wshDeclMap[key]
|
||||||
|
if methodDecl.CommandType == wshrpc.RpcType_ResponseStream {
|
||||||
|
gogen.GenMethod_ResponseStream(&buf, methodDecl)
|
||||||
|
} else if methodDecl.CommandType == wshrpc.RpcType_Call {
|
||||||
|
gogen.GenMethod_Call(&buf, methodDecl)
|
||||||
|
} else {
|
||||||
|
panic("unsupported command type " + methodDecl.CommandType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.WriteString("\n")
|
||||||
|
err := os.WriteFile(WshClientFileName, []byte(buf.String()), 0644)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateWaveObjMetaConsts() {
|
||||||
|
fmt.Fprintf(os.Stderr, "generating waveobj meta consts file to %s\n", WaveObjMetaConstsFileName)
|
||||||
|
var buf strings.Builder
|
||||||
|
gogen.GenerateBoilerplate(&buf, "waveobj", []string{})
|
||||||
|
gogen.GenerateMetaMapConsts(&buf, "MetaKey_", reflect.TypeOf(waveobj.MetaTSType{}))
|
||||||
|
buf.WriteString("\n")
|
||||||
|
err := os.WriteFile(WaveObjMetaConstsFileName, []byte(buf.String()), 0644)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateSettingsMetaConsts() {
|
||||||
|
fmt.Fprintf(os.Stderr, "generating settings meta consts file to %s\n", SettingsMetaConstsFileName)
|
||||||
|
var buf strings.Builder
|
||||||
|
gogen.GenerateBoilerplate(&buf, "wconfig", []string{})
|
||||||
|
gogen.GenerateMetaMapConsts(&buf, "ConfigKey_", reflect.TypeOf(wconfig.SettingsType{}))
|
||||||
|
buf.WriteString("\n")
|
||||||
|
err := os.WriteFile(SettingsMetaConstsFileName, []byte(buf.String()), 0644)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
GenerateWshClient()
|
||||||
|
GenerateWaveObjMetaConsts()
|
||||||
|
GenerateSettingsMetaConsts()
|
||||||
|
}
|
@ -1,86 +0,0 @@
|
|||||||
// Copyright 2024, Command Line Inc.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
|
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
func genMethod_ResponseStream(fd *os.File, methodDecl *wshrpc.WshRpcMethodDecl) {
|
|
||||||
fmt.Fprintf(fd, "// command %q, wshserver.%s\n", methodDecl.Command, methodDecl.MethodName)
|
|
||||||
var dataType string
|
|
||||||
dataVarName := "nil"
|
|
||||||
if methodDecl.CommandDataType != nil {
|
|
||||||
dataType = ", data " + methodDecl.CommandDataType.String()
|
|
||||||
dataVarName = "data"
|
|
||||||
}
|
|
||||||
respType := "any"
|
|
||||||
if methodDecl.DefaultResponseDataType != nil {
|
|
||||||
respType = methodDecl.DefaultResponseDataType.String()
|
|
||||||
}
|
|
||||||
fmt.Fprintf(fd, "func %s(w *wshutil.WshRpc%s, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[%s] {\n", methodDecl.MethodName, dataType, respType)
|
|
||||||
fmt.Fprintf(fd, " return sendRpcRequestResponseStreamHelper[%s](w, %q, %s, opts)\n", respType, methodDecl.Command, dataVarName)
|
|
||||||
fmt.Fprintf(fd, "}\n\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func genMethod_Call(fd *os.File, methodDecl *wshrpc.WshRpcMethodDecl) {
|
|
||||||
fmt.Fprintf(fd, "// command %q, wshserver.%s\n", methodDecl.Command, methodDecl.MethodName)
|
|
||||||
var dataType string
|
|
||||||
dataVarName := "nil"
|
|
||||||
if methodDecl.CommandDataType != nil {
|
|
||||||
dataType = ", data " + methodDecl.CommandDataType.String()
|
|
||||||
dataVarName = "data"
|
|
||||||
}
|
|
||||||
returnType := "error"
|
|
||||||
respName := "_"
|
|
||||||
tParamVal := "any"
|
|
||||||
if methodDecl.DefaultResponseDataType != nil {
|
|
||||||
returnType = "(" + methodDecl.DefaultResponseDataType.String() + ", error)"
|
|
||||||
respName = "resp"
|
|
||||||
tParamVal = methodDecl.DefaultResponseDataType.String()
|
|
||||||
}
|
|
||||||
fmt.Fprintf(fd, "func %s(w *wshutil.WshRpc%s, opts *wshrpc.RpcOpts) %s {\n", methodDecl.MethodName, dataType, returnType)
|
|
||||||
fmt.Fprintf(fd, " %s, err := sendRpcRequestCallHelper[%s](w, %q, %s, opts)\n", respName, tParamVal, methodDecl.Command, dataVarName)
|
|
||||||
if methodDecl.DefaultResponseDataType != nil {
|
|
||||||
fmt.Fprintf(fd, " return resp, err\n")
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(fd, " return err\n")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(fd, "}\n\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fd, err := os.Create("pkg/wshrpc/wshclient/wshclient.go")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer fd.Close()
|
|
||||||
fmt.Fprintf(os.Stderr, "generating wshclient file to %s\n", fd.Name())
|
|
||||||
fmt.Fprintf(fd, "// Copyright 2024, Command Line Inc.\n")
|
|
||||||
fmt.Fprintf(fd, "// SPDX-License-Identifier: Apache-2.0\n\n")
|
|
||||||
fmt.Fprintf(fd, "// generated by cmd/generatewshclient/main-generatewshclient.go\n\n")
|
|
||||||
fmt.Fprintf(fd, "package wshclient\n\n")
|
|
||||||
fmt.Fprintf(fd, "import (\n")
|
|
||||||
fmt.Fprintf(fd, " \"github.com/wavetermdev/thenextwave/pkg/wshutil\"\n")
|
|
||||||
fmt.Fprintf(fd, " \"github.com/wavetermdev/thenextwave/pkg/wshrpc\"\n")
|
|
||||||
fmt.Fprintf(fd, " \"github.com/wavetermdev/thenextwave/pkg/waveobj\"\n")
|
|
||||||
fmt.Fprintf(fd, ")\n\n")
|
|
||||||
|
|
||||||
wshDeclMap := wshrpc.GenerateWshCommandDeclMap()
|
|
||||||
for _, key := range utilfn.GetOrderedMapKeys(wshDeclMap) {
|
|
||||||
methodDecl := wshDeclMap[key]
|
|
||||||
if methodDecl.CommandType == wshrpc.RpcType_ResponseStream {
|
|
||||||
genMethod_ResponseStream(fd, methodDecl)
|
|
||||||
} else if methodDecl.CommandType == wshrpc.RpcType_Call {
|
|
||||||
genMethod_Call(fd, methodDecl)
|
|
||||||
} else {
|
|
||||||
panic("unsupported command type " + methodDecl.CommandType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Fprintf(fd, "\n")
|
|
||||||
}
|
|
@ -191,8 +191,8 @@ async function handleWSEvent(evtMsg: WSEventType) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const clientData = await services.ClientService.GetClientData();
|
const clientData = await services.ClientService.GetClientData();
|
||||||
const settings = await services.FileService.GetSettingsConfig();
|
const fullConfig = await services.FileService.GetFullConfig();
|
||||||
const newWin = createBrowserWindow(clientData.oid, windowData, settings);
|
const newWin = createBrowserWindow(clientData.oid, windowData, fullConfig);
|
||||||
await newWin.readyPromise;
|
await newWin.readyPromise;
|
||||||
newWin.show();
|
newWin.show();
|
||||||
} else if (evtMsg.eventtype == "electron:closewindow") {
|
} else if (evtMsg.eventtype == "electron:closewindow") {
|
||||||
@ -268,11 +268,7 @@ function shFrameNavHandler(event: Electron.Event<Electron.WebContentsWillFrameNa
|
|||||||
|
|
||||||
// note, this does not *show* the window.
|
// note, this does not *show* the window.
|
||||||
// to show, await win.readyPromise and then win.show()
|
// to show, await win.readyPromise and then win.show()
|
||||||
function createBrowserWindow(
|
function createBrowserWindow(clientId: string, waveWindow: WaveWindow, fullConfig: FullConfigType): WaveBrowserWindow {
|
||||||
clientId: string,
|
|
||||||
waveWindow: WaveWindow,
|
|
||||||
settings: SettingsConfigType
|
|
||||||
): WaveBrowserWindow {
|
|
||||||
let winWidth = waveWindow?.winsize?.width;
|
let winWidth = waveWindow?.winsize?.width;
|
||||||
let winHeight = waveWindow?.winsize?.height;
|
let winHeight = waveWindow?.winsize?.height;
|
||||||
let winPosX = waveWindow.pos.x;
|
let winPosX = waveWindow.pos.x;
|
||||||
@ -326,8 +322,9 @@ function createBrowserWindow(
|
|||||||
show: false,
|
show: false,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
};
|
};
|
||||||
const isTransparent = settings?.window?.transparent ?? false;
|
const settings = fullConfig?.settings;
|
||||||
const isBlur = !isTransparent && (settings?.window?.blur ?? false);
|
const isTransparent = settings?.["window:transparent"] ?? false;
|
||||||
|
const isBlur = !isTransparent && (settings?.["window:blur"] ?? false);
|
||||||
if (isTransparent) {
|
if (isTransparent) {
|
||||||
winOpts.transparent = true;
|
winOpts.transparent = true;
|
||||||
} else if (isBlur) {
|
} else if (isBlur) {
|
||||||
@ -582,8 +579,8 @@ if (unamePlatform !== "darwin") {
|
|||||||
async function createNewWaveWindow(): Promise<void> {
|
async function createNewWaveWindow(): Promise<void> {
|
||||||
const clientData = await services.ClientService.GetClientData();
|
const clientData = await services.ClientService.GetClientData();
|
||||||
const newWindow = await services.ClientService.MakeWindow();
|
const newWindow = await services.ClientService.MakeWindow();
|
||||||
const settings = await services.FileService.GetSettingsConfig();
|
const fullConfig = await services.FileService.GetFullConfig();
|
||||||
const newBrowserWindow = createBrowserWindow(clientData.oid, newWindow, settings);
|
const newBrowserWindow = createBrowserWindow(clientData.oid, newWindow, fullConfig);
|
||||||
newBrowserWindow.show();
|
newBrowserWindow.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,7 +697,7 @@ async function relaunchBrowserWindows(): Promise<void> {
|
|||||||
globalIsRelaunching = false;
|
globalIsRelaunching = false;
|
||||||
|
|
||||||
const clientData = await services.ClientService.GetClientData();
|
const clientData = await services.ClientService.GetClientData();
|
||||||
const settings = await services.FileService.GetSettingsConfig();
|
const fullConfig = await services.FileService.GetFullConfig();
|
||||||
const wins: WaveBrowserWindow[] = [];
|
const wins: WaveBrowserWindow[] = [];
|
||||||
for (const windowId of clientData.windowids.slice().reverse()) {
|
for (const windowId of clientData.windowids.slice().reverse()) {
|
||||||
const windowData: WaveWindow = (await services.ObjectService.GetObject("window:" + windowId)) as WaveWindow;
|
const windowData: WaveWindow = (await services.ObjectService.GetObject("window:" + windowId)) as WaveWindow;
|
||||||
@ -710,7 +707,7 @@ async function relaunchBrowserWindows(): Promise<void> {
|
|||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const win = createBrowserWindow(clientData.oid, windowData, settings);
|
const win = createBrowserWindow(clientData.oid, windowData, fullConfig);
|
||||||
wins.push(win);
|
wins.push(win);
|
||||||
}
|
}
|
||||||
for (const win of wins) {
|
for (const win of wins) {
|
||||||
|
@ -27,6 +27,10 @@ ipcMain.on("get-is-dev", (event) => {
|
|||||||
ipcMain.on("get-platform", (event, url) => {
|
ipcMain.on("get-platform", (event, url) => {
|
||||||
event.returnValue = unamePlatform;
|
event.returnValue = unamePlatform;
|
||||||
});
|
});
|
||||||
|
ipcMain.on("get-user-name", (event) => {
|
||||||
|
const userInfo = os.userInfo();
|
||||||
|
event.returnValue = userInfo.username;
|
||||||
|
});
|
||||||
|
|
||||||
// must match golang
|
// must match golang
|
||||||
function getWaveHomeDir() {
|
function getWaveHomeDir() {
|
||||||
|
@ -8,6 +8,7 @@ contextBridge.exposeInMainWorld("api", {
|
|||||||
getIsDev: () => ipcRenderer.sendSync("get-is-dev"),
|
getIsDev: () => ipcRenderer.sendSync("get-is-dev"),
|
||||||
getPlatform: () => ipcRenderer.sendSync("get-platform"),
|
getPlatform: () => ipcRenderer.sendSync("get-platform"),
|
||||||
getCursorPoint: () => ipcRenderer.sendSync("get-cursor-point"),
|
getCursorPoint: () => ipcRenderer.sendSync("get-cursor-point"),
|
||||||
|
getUserName: () => ipcRenderer.sendSync("get-user-name"),
|
||||||
openNewWindow: () => ipcRenderer.send("open-new-window"),
|
openNewWindow: () => ipcRenderer.send("open-new-window"),
|
||||||
showContextMenu: (menu, position) => ipcRenderer.send("contextmenu-show", menu, position),
|
showContextMenu: (menu, position) => ipcRenderer.send("contextmenu-show", menu, position),
|
||||||
onContextMenuClick: (callback) => ipcRenderer.on("contextmenu-click", (_event, id) => callback(id)),
|
onContextMenuClick: (callback) => ipcRenderer.on("contextmenu-click", (_event, id) => callback(id)),
|
||||||
|
@ -5,7 +5,7 @@ import { appHandleKeyDown, appHandleKeyUp } from "@/app/appkey";
|
|||||||
import { useWaveObjectValue } from "@/app/store/wos";
|
import { useWaveObjectValue } from "@/app/store/wos";
|
||||||
import { Workspace } from "@/app/workspace/workspace";
|
import { Workspace } from "@/app/workspace/workspace";
|
||||||
import { ContextMenuModel } from "@/store/contextmenu";
|
import { ContextMenuModel } from "@/store/contextmenu";
|
||||||
import { PLATFORM, WOS, atoms, getApi, globalStore } from "@/store/global";
|
import { PLATFORM, WOS, atoms, getApi, globalStore, useSettingsPrefixAtom } from "@/store/global";
|
||||||
import { getWebServerEndpoint } from "@/util/endpoints";
|
import { getWebServerEndpoint } from "@/util/endpoints";
|
||||||
import * as keyutil from "@/util/keyutil";
|
import * as keyutil from "@/util/keyutil";
|
||||||
import * as util from "@/util/util";
|
import * as util from "@/util/util";
|
||||||
@ -80,12 +80,13 @@ function handleContextMenu(e: React.MouseEvent<HTMLDivElement>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function AppSettingsUpdater() {
|
function AppSettingsUpdater() {
|
||||||
const settings = jotai.useAtomValue(atoms.settingsConfigAtom);
|
const windowSettings = useSettingsPrefixAtom("window");
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const isTransparentOrBlur = (settings?.window?.transparent || settings?.window?.blur) ?? false;
|
const isTransparentOrBlur =
|
||||||
const opacity = util.boundNumber(settings?.window?.opacity ?? 0.8, 0, 1);
|
(windowSettings?.["window:transparent"] || windowSettings?.["window:blur"]) ?? false;
|
||||||
let baseBgColor = settings?.window?.bgcolor;
|
const opacity = util.boundNumber(windowSettings?.["window:opacity"] ?? 0.8, 0, 1);
|
||||||
console.log("window settings", settings.window);
|
let baseBgColor = windowSettings?.["window:bgcolor"];
|
||||||
|
console.log("window settings", windowSettings);
|
||||||
if (isTransparentOrBlur) {
|
if (isTransparentOrBlur) {
|
||||||
document.body.classList.add("is-transparent");
|
document.body.classList.add("is-transparent");
|
||||||
const rootStyles = getComputedStyle(document.documentElement);
|
const rootStyles = getComputedStyle(document.documentElement);
|
||||||
@ -99,7 +100,7 @@ function AppSettingsUpdater() {
|
|||||||
document.body.classList.remove("is-transparent");
|
document.body.classList.remove("is-transparent");
|
||||||
document.body.style.opacity = null;
|
document.body.style.opacity = null;
|
||||||
}
|
}
|
||||||
}, [settings?.window]);
|
}, [windowSettings]);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
import { Button } from "@/app/element/button";
|
import { Button } from "@/app/element/button";
|
||||||
import { TypeAheadModal } from "@/app/modals/typeaheadmodal";
|
import { TypeAheadModal } from "@/app/modals/typeaheadmodal";
|
||||||
import { ContextMenuModel } from "@/app/store/contextmenu";
|
import { ContextMenuModel } from "@/app/store/contextmenu";
|
||||||
import { atoms, globalStore, useBlockAtom, WOS } from "@/app/store/global";
|
import { atoms, globalStore, useBlockAtom, useSettingsKeyAtom, WOS } from "@/app/store/global";
|
||||||
import * as services from "@/app/store/services";
|
import * as services from "@/app/store/services";
|
||||||
import { WshServer } from "@/app/store/wshserver";
|
import { WshServer } from "@/app/store/wshserver";
|
||||||
import { MagnifyIcon } from "@/element/magnify";
|
import { MagnifyIcon } from "@/element/magnify";
|
||||||
@ -132,7 +132,8 @@ const BlockFrame_Header = ({
|
|||||||
}: BlockFrameProps & { changeConnModalAtom: jotai.PrimitiveAtom<boolean> }) => {
|
}: BlockFrameProps & { changeConnModalAtom: jotai.PrimitiveAtom<boolean> }) => {
|
||||||
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", nodeModel.blockId));
|
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", nodeModel.blockId));
|
||||||
const viewName = util.useAtomValueSafe(viewModel.viewName) ?? blockViewToName(blockData?.meta?.view);
|
const viewName = util.useAtomValueSafe(viewModel.viewName) ?? blockViewToName(blockData?.meta?.view);
|
||||||
const settingsConfig = jotai.useAtomValue(atoms.settingsConfigAtom);
|
const showBlockIds = jotai.useAtomValue(useSettingsKeyAtom("blockheader:showblockids"));
|
||||||
|
const settingsConfig = jotai.useAtomValue(atoms.settingsAtom);
|
||||||
const viewIconUnion = util.useAtomValueSafe(viewModel.viewIcon) ?? blockViewToIcon(blockData?.meta?.view);
|
const viewIconUnion = util.useAtomValueSafe(viewModel.viewIcon) ?? blockViewToIcon(blockData?.meta?.view);
|
||||||
const preIconButton = util.useAtomValueSafe(viewModel.preIconButton);
|
const preIconButton = util.useAtomValueSafe(viewModel.preIconButton);
|
||||||
const headerTextUnion = util.useAtomValueSafe(viewModel.viewText);
|
const headerTextUnion = util.useAtomValueSafe(viewModel.viewText);
|
||||||
@ -190,9 +191,7 @@ const BlockFrame_Header = ({
|
|||||||
<div className="block-frame-default-header-iconview">
|
<div className="block-frame-default-header-iconview">
|
||||||
{viewIconElem}
|
{viewIconElem}
|
||||||
<div className="block-frame-view-type">{viewName}</div>
|
<div className="block-frame-view-type">{viewName}</div>
|
||||||
{settingsConfig?.blockheader?.showblockids && (
|
{showBlockIds && <div className="block-frame-blockid">[{nodeModel.blockId.substring(0, 8)}]</div>}
|
||||||
<div className="block-frame-blockid">[{nodeModel.blockId.substring(0, 8)}]</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="block-frame-textelems-wrapper">{headerTextElems}</div>
|
<div className="block-frame-textelems-wrapper">{headerTextElems}</div>
|
||||||
|
@ -135,31 +135,6 @@ export function getBlockHeaderIcon(blockIcon: string, blockData: Block): React.R
|
|||||||
return blockIconElem;
|
return blockIconElem;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBlockHeaderText(blockIcon: string, blockData: Block, settings: SettingsConfigType): React.ReactNode {
|
|
||||||
if (!blockData) {
|
|
||||||
return "no block data";
|
|
||||||
}
|
|
||||||
let blockIdStr = "";
|
|
||||||
if (settings?.blockheader?.showblockids) {
|
|
||||||
blockIdStr = ` [${blockData.oid.substring(0, 8)}]`;
|
|
||||||
}
|
|
||||||
let blockIconElem = getBlockHeaderIcon(blockIcon, blockData);
|
|
||||||
if (!util.isBlank(blockData?.meta?.title)) {
|
|
||||||
try {
|
|
||||||
const rtn = processTitleString(blockData.meta.title) ?? [];
|
|
||||||
return [blockIconElem, ...rtn, blockIdStr == "" ? null : blockIdStr];
|
|
||||||
} catch (e) {
|
|
||||||
console.error("error processing title", blockData.meta.title, e);
|
|
||||||
return [blockIconElem, blockData.meta.title + blockIdStr];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let viewString = blockData?.meta?.view;
|
|
||||||
if (blockData?.meta?.controller == "cmd") {
|
|
||||||
viewString = "cmd";
|
|
||||||
}
|
|
||||||
return [blockIconElem, viewString + blockIdStr];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const IconButton = React.memo(({ decl, className }: { decl: HeaderIconButton; className?: string }) => {
|
export const IconButton = React.memo(({ decl, className }: { decl: HeaderIconButton; className?: string }) => {
|
||||||
const buttonRef = React.useRef<HTMLDivElement>(null);
|
const buttonRef = React.useRef<HTMLDivElement>(null);
|
||||||
useLongClick(buttonRef, decl.click, decl.longClick);
|
useLongClick(buttonRef, decl.click, decl.longClick);
|
||||||
|
@ -96,7 +96,10 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
|
|||||||
}
|
}
|
||||||
return WOS.getObjectValue(WOS.makeORef("workspace", windowData.workspaceid), get);
|
return WOS.getObjectValue(WOS.makeORef("workspace", windowData.workspaceid), get);
|
||||||
});
|
});
|
||||||
const settingsConfigAtom = jotai.atom(null) as jotai.PrimitiveAtom<SettingsConfigType>;
|
const fullConfigAtom = jotai.atom(null) as jotai.PrimitiveAtom<FullConfigType>;
|
||||||
|
const settingsAtom = jotai.atom((get) => {
|
||||||
|
return get(fullConfigAtom)?.settings ?? {};
|
||||||
|
}) as jotai.Atom<SettingsType>;
|
||||||
const tabAtom: jotai.Atom<Tab> = jotai.atom((get) => {
|
const tabAtom: jotai.Atom<Tab> = jotai.atom((get) => {
|
||||||
const windowData = get(windowDataAtom);
|
const windowData = get(windowDataAtom);
|
||||||
if (windowData == null) {
|
if (windowData == null) {
|
||||||
@ -121,7 +124,7 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
|
|||||||
} catch (_) {
|
} catch (_) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
const reducedMotionPreferenceAtom = jotai.atom((get) => get(settingsConfigAtom).window.reducedmotion);
|
const reducedMotionPreferenceAtom = jotai.atom((get) => get(settingsAtom)?.["window:reducedmotion"]);
|
||||||
const typeAheadModalAtom = jotai.atom({});
|
const typeAheadModalAtom = jotai.atom({});
|
||||||
atoms = {
|
atoms = {
|
||||||
// initialized in wave.ts (will not be null inside of application)
|
// initialized in wave.ts (will not be null inside of application)
|
||||||
@ -131,7 +134,8 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
|
|||||||
client: clientAtom,
|
client: clientAtom,
|
||||||
waveWindow: windowDataAtom,
|
waveWindow: windowDataAtom,
|
||||||
workspace: workspaceAtom,
|
workspace: workspaceAtom,
|
||||||
settingsConfigAtom,
|
fullConfigAtom,
|
||||||
|
settingsAtom,
|
||||||
tabAtom,
|
tabAtom,
|
||||||
activeTabId: activeTabIdAtom,
|
activeTabId: activeTabIdAtom,
|
||||||
isFullScreen: isFullScreenAtom,
|
isFullScreen: isFullScreenAtom,
|
||||||
@ -271,19 +275,35 @@ function useBlockCache<T>(blockId: string, name: string, makeFn: () => T): T {
|
|||||||
|
|
||||||
const settingsAtomCache = new Map<string, jotai.Atom<any>>();
|
const settingsAtomCache = new Map<string, jotai.Atom<any>>();
|
||||||
|
|
||||||
function useSettingsAtom<T>(name: string, settingsFn: (settings: SettingsConfigType) => T): jotai.Atom<T> {
|
function useSettingsKeyAtom<T extends keyof SettingsType>(key: T): jotai.Atom<SettingsType[T]> {
|
||||||
let atom = settingsAtomCache.get(name);
|
let atom = settingsAtomCache.get(key) as jotai.Atom<SettingsType[T]>;
|
||||||
if (atom == null) {
|
if (atom == null) {
|
||||||
atom = jotai.atom((get) => {
|
atom = jotai.atom((get) => {
|
||||||
const settings = get(atoms.settingsConfigAtom);
|
const settings = get(atoms.settingsAtom);
|
||||||
if (settings == null) {
|
if (settings == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return settingsFn(settings);
|
return settings[key];
|
||||||
}) as jotai.Atom<T>;
|
});
|
||||||
settingsAtomCache.set(name, atom);
|
settingsAtomCache.set(key, atom);
|
||||||
}
|
}
|
||||||
return atom as jotai.Atom<T>;
|
return atom;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useSettingsPrefixAtom(prefix: string): jotai.Atom<SettingsType> {
|
||||||
|
// TODO: use a shallow equal here to make this more efficient
|
||||||
|
let atom = settingsAtomCache.get(prefix + ":");
|
||||||
|
if (atom == null) {
|
||||||
|
atom = jotai.atom((get) => {
|
||||||
|
const settings = get(atoms.settingsAtom);
|
||||||
|
if (settings == null) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return util.getPrefixedSettings(settings, prefix);
|
||||||
|
});
|
||||||
|
settingsAtomCache.set(prefix + ":", atom);
|
||||||
|
}
|
||||||
|
return atom;
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockAtomCache = new Map<string, Map<string, jotai.Atom<any>>>();
|
const blockAtomCache = new Map<string, Map<string, jotai.Atom<any>>>();
|
||||||
@ -337,7 +357,7 @@ function handleWSEventMessage(msg: WSEventType) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (msg.eventtype == "config") {
|
if (msg.eventtype == "config") {
|
||||||
globalStore.set(atoms.settingsConfigAtom, msg.data.settings);
|
globalStore.set(atoms.fullConfigAtom, (msg.data as WatcherUpdate).fullconfig);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (msg.eventtype == "userinput") {
|
if (msg.eventtype == "userinput") {
|
||||||
@ -474,8 +494,17 @@ function isDev() {
|
|||||||
return cachedIsDev;
|
return cachedIsDev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cachedUserName: string = null;
|
||||||
|
|
||||||
|
function getUserName(): string {
|
||||||
|
if (cachedUserName == null) {
|
||||||
|
cachedUserName = getApi().getUserName();
|
||||||
|
}
|
||||||
|
return cachedUserName;
|
||||||
|
}
|
||||||
|
|
||||||
async function openLink(uri: string) {
|
async function openLink(uri: string) {
|
||||||
if (globalStore.get(atoms.settingsConfigAtom)?.web?.openlinksinternally) {
|
if (globalStore.get(atoms.settingsAtom)?.["web:openlinksinternally"]) {
|
||||||
const blockDef: BlockDef = {
|
const blockDef: BlockDef = {
|
||||||
meta: {
|
meta: {
|
||||||
view: "web",
|
view: "web",
|
||||||
@ -563,6 +592,7 @@ export {
|
|||||||
getEventSubject,
|
getEventSubject,
|
||||||
getFileSubject,
|
getFileSubject,
|
||||||
getObjectId,
|
getObjectId,
|
||||||
|
getUserName,
|
||||||
getViewModel,
|
getViewModel,
|
||||||
globalStore,
|
globalStore,
|
||||||
globalWS,
|
globalWS,
|
||||||
@ -581,7 +611,8 @@ export {
|
|||||||
useBlockAtom,
|
useBlockAtom,
|
||||||
useBlockCache,
|
useBlockCache,
|
||||||
useBlockDataLoaded,
|
useBlockDataLoaded,
|
||||||
useSettingsAtom,
|
useSettingsKeyAtom,
|
||||||
|
useSettingsPrefixAtom,
|
||||||
waveEventSubscribe,
|
waveEventSubscribe,
|
||||||
waveEventUnsubscribe,
|
waveEventUnsubscribe,
|
||||||
WOS,
|
WOS,
|
||||||
|
@ -53,16 +53,12 @@ export const ClientService = new ClientServiceType();
|
|||||||
|
|
||||||
// fileservice.FileService (file)
|
// fileservice.FileService (file)
|
||||||
class FileServiceType {
|
class FileServiceType {
|
||||||
AddWidget(arg1: WidgetsConfigType): Promise<void> {
|
|
||||||
return WOS.callBackendService("file", "AddWidget", Array.from(arguments))
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete file
|
// delete file
|
||||||
DeleteFile(connection: string, path: string): Promise<void> {
|
DeleteFile(connection: string, path: string): Promise<void> {
|
||||||
return WOS.callBackendService("file", "DeleteFile", Array.from(arguments))
|
return WOS.callBackendService("file", "DeleteFile", Array.from(arguments))
|
||||||
}
|
}
|
||||||
GetSettingsConfig(): Promise<SettingsConfigType> {
|
GetFullConfig(): Promise<FullConfigType> {
|
||||||
return WOS.callBackendService("file", "GetSettingsConfig", Array.from(arguments))
|
return WOS.callBackendService("file", "GetFullConfig", Array.from(arguments))
|
||||||
}
|
}
|
||||||
GetWaveFile(arg1: string, arg2: string): Promise<any> {
|
GetWaveFile(arg1: string, arg2: string): Promise<any> {
|
||||||
return WOS.callBackendService("file", "GetWaveFile", Array.from(arguments))
|
return WOS.callBackendService("file", "GetWaveFile", Array.from(arguments))
|
||||||
@ -72,9 +68,6 @@ class FileServiceType {
|
|||||||
ReadFile(connection: string, path: string): Promise<FullFile> {
|
ReadFile(connection: string, path: string): Promise<FullFile> {
|
||||||
return WOS.callBackendService("file", "ReadFile", Array.from(arguments))
|
return WOS.callBackendService("file", "ReadFile", Array.from(arguments))
|
||||||
}
|
}
|
||||||
RemoveWidget(arg1: number): Promise<void> {
|
|
||||||
return WOS.callBackendService("file", "RemoveWidget", Array.from(arguments))
|
|
||||||
}
|
|
||||||
|
|
||||||
// save file
|
// save file
|
||||||
SaveFile(connection: string, path: string, data64: string): Promise<void> {
|
SaveFile(connection: string, path: string, data64: string): Promise<void> {
|
||||||
|
@ -139,33 +139,33 @@ const Tab = React.memo(
|
|||||||
function handleContextMenu(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
|
function handleContextMenu(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let menu: ContextMenuItem[] = [];
|
let menu: ContextMenuItem[] = [];
|
||||||
const settings = globalStore.get(atoms.settingsConfigAtom);
|
const fullConfig = globalStore.get(atoms.fullConfigAtom);
|
||||||
console.log("settings", settings);
|
|
||||||
const bgPresets: string[] = [];
|
const bgPresets: string[] = [];
|
||||||
for (const key in settings?.presets ?? {}) {
|
for (const key in fullConfig?.presets ?? {}) {
|
||||||
if (key.startsWith("bg@")) {
|
if (key.startsWith("bg@")) {
|
||||||
bgPresets.push(key);
|
bgPresets.push(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bgPresets.sort((a, b) => {
|
bgPresets.sort((a, b) => {
|
||||||
const aOrder = settings.presets[a]["display:order"] ?? 0;
|
const aOrder = fullConfig.presets[a]["display:order"] ?? 0;
|
||||||
const bOrder = settings.presets[b]["display:order"] ?? 0;
|
const bOrder = fullConfig.presets[b]["display:order"] ?? 0;
|
||||||
return aOrder - bOrder;
|
return aOrder - bOrder;
|
||||||
});
|
});
|
||||||
console.log("bgPresets", bgPresets);
|
|
||||||
menu.push({ label: "Copy TabId", click: () => navigator.clipboard.writeText(id) });
|
menu.push({ label: "Copy TabId", click: () => navigator.clipboard.writeText(id) });
|
||||||
menu.push({ type: "separator" });
|
menu.push({ type: "separator" });
|
||||||
if (bgPresets.length > 0) {
|
if (bgPresets.length > 0) {
|
||||||
const submenu: ContextMenuItem[] = [];
|
const submenu: ContextMenuItem[] = [];
|
||||||
const oref = WOS.makeORef("tab", id);
|
const oref = WOS.makeORef("tab", id);
|
||||||
for (const presetName of bgPresets) {
|
for (const presetName of bgPresets) {
|
||||||
const preset = settings.presets[presetName];
|
const preset = fullConfig.presets[presetName];
|
||||||
if (preset == null) {
|
if (preset == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
submenu.push({
|
submenu.push({
|
||||||
label: preset["display:name"] ?? presetName,
|
label: preset["display:name"] ?? presetName,
|
||||||
click: () => services.ObjectService.UpdateObjectMeta(oref, preset),
|
click: () => {
|
||||||
|
services.ObjectService.UpdateObjectMeta(oref, preset);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
menu.push({ label: "Backgrounds", type: "submenu", submenu });
|
menu.push({ label: "Backgrounds", type: "submenu", submenu });
|
||||||
|
@ -134,11 +134,11 @@ function DirectoryTable({
|
|||||||
setSelectedPath,
|
setSelectedPath,
|
||||||
setRefreshVersion,
|
setRefreshVersion,
|
||||||
}: DirectoryTableProps) {
|
}: DirectoryTableProps) {
|
||||||
const settings = jotai.useAtomValue(atoms.settingsConfigAtom);
|
const fullConfig = jotai.useAtomValue(atoms.fullConfigAtom);
|
||||||
const getIconFromMimeType = useCallback(
|
const getIconFromMimeType = useCallback(
|
||||||
(mimeType: string): string => {
|
(mimeType: string): string => {
|
||||||
while (mimeType.length > 0) {
|
while (mimeType.length > 0) {
|
||||||
let icon = settings.mimetypes?.[mimeType]?.icon ?? null;
|
let icon = fullConfig.mimetypes?.[mimeType]?.icon ?? null;
|
||||||
if (isIconValid(icon)) {
|
if (isIconValid(icon)) {
|
||||||
return `fa fa-solid fa-${icon} fa-fw`;
|
return `fa fa-solid fa-${icon} fa-fw`;
|
||||||
}
|
}
|
||||||
@ -146,14 +146,14 @@ function DirectoryTable({
|
|||||||
}
|
}
|
||||||
return "fa fa-solid fa-file fa-fw";
|
return "fa fa-solid fa-file fa-fw";
|
||||||
},
|
},
|
||||||
[settings.mimetypes]
|
[fullConfig.mimetypes]
|
||||||
);
|
);
|
||||||
const getIconColor = useCallback(
|
const getIconColor = useCallback(
|
||||||
(mimeType: string): string => {
|
(mimeType: string): string => {
|
||||||
let iconColor = settings.mimetypes?.[mimeType]?.color ?? "inherit";
|
let iconColor = fullConfig.mimetypes?.[mimeType]?.color ?? "inherit";
|
||||||
return iconColor;
|
return iconColor;
|
||||||
},
|
},
|
||||||
[settings.mimetypes]
|
[fullConfig.mimetypes]
|
||||||
);
|
);
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
() => [
|
() => [
|
||||||
@ -208,7 +208,7 @@ function DirectoryTable({
|
|||||||
}),
|
}),
|
||||||
columnHelper.accessor("path", {}),
|
columnHelper.accessor("path", {}),
|
||||||
],
|
],
|
||||||
[settings]
|
[fullConfig]
|
||||||
);
|
);
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import { WshServer } from "@/app/store/wshserver";
|
import { WshServer } from "@/app/store/wshserver";
|
||||||
import { VDomView } from "@/app/view/term/vdom";
|
import { VDomView } from "@/app/view/term/vdom";
|
||||||
import { WOS, atoms, getEventORefSubject, globalStore, useBlockAtom, useSettingsAtom } from "@/store/global";
|
import { WOS, atoms, getEventORefSubject, globalStore, useBlockAtom, useSettingsPrefixAtom } from "@/store/global";
|
||||||
import * as services from "@/store/services";
|
import * as services from "@/store/services";
|
||||||
import * as keyutil from "@/util/keyutil";
|
import * as keyutil from "@/util/keyutil";
|
||||||
import * as util from "@/util/util";
|
import * as util from "@/util/util";
|
||||||
@ -135,8 +135,8 @@ class TermViewModel {
|
|||||||
});
|
});
|
||||||
this.blockBg = jotai.atom((get) => {
|
this.blockBg = jotai.atom((get) => {
|
||||||
const blockData = get(this.blockAtom);
|
const blockData = get(this.blockAtom);
|
||||||
const settings = globalStore.get(atoms.settingsConfigAtom);
|
const fullConfig = get(atoms.fullConfigAtom);
|
||||||
const theme = computeTheme(settings, blockData?.meta?.["term:theme"]);
|
const theme = computeTheme(fullConfig, blockData?.meta?.["term:theme"]);
|
||||||
if (theme != null && theme.background != null) {
|
if (theme != null && theme.background != null) {
|
||||||
return { bg: theme.background };
|
return { bg: theme.background };
|
||||||
}
|
}
|
||||||
@ -203,9 +203,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
|||||||
const htmlElemFocusRef = React.useRef<HTMLInputElement>(null);
|
const htmlElemFocusRef = React.useRef<HTMLInputElement>(null);
|
||||||
model.htmlElemFocusRef = htmlElemFocusRef;
|
model.htmlElemFocusRef = htmlElemFocusRef;
|
||||||
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
||||||
const termSettingsAtom = useSettingsAtom<TerminalConfigType>("term", (settings: SettingsConfigType) => {
|
const termSettingsAtom = useSettingsPrefixAtom("term");
|
||||||
return settings?.term;
|
|
||||||
});
|
|
||||||
const termSettings = jotai.useAtomValue(termSettingsAtom);
|
const termSettings = jotai.useAtomValue(termSettingsAtom);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@ -240,8 +238,8 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const settings = globalStore.get(atoms.settingsConfigAtom);
|
const fullConfig = globalStore.get(atoms.fullConfigAtom);
|
||||||
const termTheme = computeTheme(settings, blockData?.meta?.["term:theme"]);
|
const termTheme = computeTheme(fullConfig, blockData?.meta?.["term:theme"]);
|
||||||
const themeCopy = { ...termTheme };
|
const themeCopy = { ...termTheme };
|
||||||
themeCopy.background = "#00000000";
|
themeCopy.background = "#00000000";
|
||||||
const termWrap = new TermWrap(
|
const termWrap = new TermWrap(
|
||||||
@ -249,8 +247,8 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
|||||||
connectElemRef.current,
|
connectElemRef.current,
|
||||||
{
|
{
|
||||||
theme: themeCopy,
|
theme: themeCopy,
|
||||||
fontSize: termSettings?.fontsize ?? 12,
|
fontSize: termSettings?.["term:fontsize"] ?? 12,
|
||||||
fontFamily: termSettings?.fontfamily ?? "Hack",
|
fontFamily: termSettings?.["term:fontfamily"] ?? "Hack",
|
||||||
drawBoldTextInBrightColors: false,
|
drawBoldTextInBrightColors: false,
|
||||||
fontWeight: "normal",
|
fontWeight: "normal",
|
||||||
fontWeightBold: "bold",
|
fontWeightBold: "bold",
|
||||||
@ -258,7 +256,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
keydownHandler: handleTerminalKeydown,
|
keydownHandler: handleTerminalKeydown,
|
||||||
useWebGl: !termSettings?.disablewebgl,
|
useWebGl: !termSettings?.["term:disablewebgl"],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
(window as any).term = termWrap;
|
(window as any).term = termWrap;
|
||||||
|
@ -13,7 +13,8 @@ interface TermThemeProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TermThemeUpdater = ({ blockId, termRef }: TermThemeProps) => {
|
const TermThemeUpdater = ({ blockId, termRef }: TermThemeProps) => {
|
||||||
const { termthemes } = useAtomValue(atoms.settingsConfigAtom);
|
const fullConfig = useAtomValue(atoms.fullConfigAtom);
|
||||||
|
const termthemes = fullConfig?.termthemes;
|
||||||
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
||||||
let defaultThemeName = "default-dark";
|
let defaultThemeName = "default-dark";
|
||||||
let themeName = blockData.meta?.["term:theme"] ?? "default-dark";
|
let themeName = blockData.meta?.["term:theme"] ?? "default-dark";
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
import * as util from "@/util/util";
|
import * as util from "@/util/util";
|
||||||
|
|
||||||
function computeTheme(settings: SettingsConfigType, themeName: string): TermThemeType {
|
function computeTheme(fullConfig: FullConfigType, themeName: string): TermThemeType {
|
||||||
let defaultThemeName = "default-dark";
|
let defaultThemeName = "default-dark";
|
||||||
themeName = themeName ?? "default-dark";
|
themeName = themeName ?? "default-dark";
|
||||||
const defaultTheme: TermThemeType = settings?.termthemes?.[defaultThemeName] || ({} as any);
|
const defaultTheme: TermThemeType = fullConfig?.termthemes?.[defaultThemeName] || ({} as any);
|
||||||
const theme: TermThemeType = settings?.termthemes?.[themeName] || ({} as any);
|
const theme: TermThemeType = fullConfig?.termthemes?.[themeName] || ({} as any);
|
||||||
const combinedTheme = { ...defaultTheme };
|
const combinedTheme = { ...defaultTheme };
|
||||||
for (const key in theme) {
|
for (const key in theme) {
|
||||||
if (!util.isBlank(theme[key])) {
|
if (!util.isBlank(theme[key])) {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import { Markdown } from "@/app/element/markdown";
|
import { Markdown } from "@/app/element/markdown";
|
||||||
import { TypingIndicator } from "@/app/element/typingindicator";
|
import { TypingIndicator } from "@/app/element/typingindicator";
|
||||||
import { WOS, atoms, fetchWaveFile, globalStore } from "@/store/global";
|
import { WOS, atoms, fetchWaveFile, getUserName, globalStore } from "@/store/global";
|
||||||
import * as services from "@/store/services";
|
import * as services from "@/store/services";
|
||||||
import { WshServer } from "@/store/wshserver";
|
import { WshServer } from "@/store/wshserver";
|
||||||
import * as jotai from "jotai";
|
import * as jotai from "jotai";
|
||||||
@ -107,7 +107,7 @@ export class WaveAiModel implements ViewModel {
|
|||||||
const viewTextChildren: HeaderElem[] = [
|
const viewTextChildren: HeaderElem[] = [
|
||||||
{
|
{
|
||||||
elemtype: "text",
|
elemtype: "text",
|
||||||
text: get(atoms.settingsConfigAtom).ai?.model ?? "gpt-3.5-turbo",
|
text: get(atoms.settingsAtom)["ai:model"] ?? "gpt-3.5-turbo",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
return viewTextChildren;
|
return viewTextChildren;
|
||||||
@ -152,18 +152,21 @@ export class WaveAiModel implements ViewModel {
|
|||||||
};
|
};
|
||||||
addMessage(newMessage);
|
addMessage(newMessage);
|
||||||
// send message to backend and get response
|
// send message to backend and get response
|
||||||
const settings = globalStore.get(atoms.settingsConfigAtom);
|
const settings = globalStore.get(atoms.settingsAtom);
|
||||||
const opts: OpenAIOptsType = {
|
const opts: OpenAIOptsType = {
|
||||||
model: settings.ai.model,
|
model: settings["ai:model"],
|
||||||
apitoken: settings.ai.apitoken,
|
apitoken: settings["ai:apitoken"],
|
||||||
maxtokens: settings.ai.maxtokens,
|
maxtokens: settings["ai:maxtokens"],
|
||||||
timeout: settings.ai.timeoutms / 1000,
|
timeout: settings["ai:timeoutms"] / 1000,
|
||||||
baseurl: settings.ai.baseurl,
|
baseurl: settings["ai:baseurl"],
|
||||||
};
|
};
|
||||||
const newPrompt: OpenAIPromptMessageType = {
|
const newPrompt: OpenAIPromptMessageType = {
|
||||||
role: "user",
|
role: "user",
|
||||||
content: text,
|
content: text,
|
||||||
};
|
};
|
||||||
|
if (newPrompt.name == "*username") {
|
||||||
|
newPrompt.name = getUserName();
|
||||||
|
}
|
||||||
let temp = async () => {
|
let temp = async () => {
|
||||||
const history = await this.fetchAiData();
|
const history = await this.fetchAiData();
|
||||||
const beMsg: OpenAiStreamRequest = {
|
const beMsg: OpenAiStreamRequest = {
|
||||||
|
@ -14,10 +14,28 @@ import "./workspace.less";
|
|||||||
|
|
||||||
const iconRegex = /^[a-z0-9-]+$/;
|
const iconRegex = /^[a-z0-9-]+$/;
|
||||||
|
|
||||||
|
function keyLen(obj: Object): number {
|
||||||
|
if (obj == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Object.keys(obj).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortByDisplayOrder(wmap: { [key: string]: WidgetConfigType }): WidgetConfigType[] {
|
||||||
|
if (wmap == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const wlist = Object.values(wmap);
|
||||||
|
wlist.sort((a, b) => {
|
||||||
|
return a["display:order"] - b["display:order"];
|
||||||
|
});
|
||||||
|
return wlist;
|
||||||
|
}
|
||||||
|
|
||||||
const Widgets = React.memo(() => {
|
const Widgets = React.memo(() => {
|
||||||
const settingsConfig = jotai.useAtomValue(atoms.settingsConfigAtom);
|
const fullConfig = jotai.useAtomValue(atoms.fullConfigAtom);
|
||||||
const newWidgetModalVisible = React.useState(false);
|
const newWidgetModalVisible = React.useState(false);
|
||||||
const helpWidget: WidgetsConfigType = {
|
const helpWidget: WidgetConfigType = {
|
||||||
icon: "circle-question",
|
icon: "circle-question",
|
||||||
label: "help",
|
label: "help",
|
||||||
blockdef: {
|
blockdef: {
|
||||||
@ -26,13 +44,17 @@ const Widgets = React.memo(() => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const showHelp = settingsConfig?.["widget:showhelp"] ?? true;
|
const showHelp = fullConfig?.settings?.["widget:showhelp"] ?? true;
|
||||||
const showDivider = settingsConfig?.defaultwidgets?.length > 0 && settingsConfig?.widgets?.length > 0;
|
const showDivider = keyLen(fullConfig?.defaultwidgets) > 0 && keyLen(fullConfig?.widgets) > 0;
|
||||||
|
const defaultWidgets = sortByDisplayOrder(fullConfig?.defaultwidgets);
|
||||||
|
const widgets = sortByDisplayOrder(fullConfig?.widgets);
|
||||||
return (
|
return (
|
||||||
<div className="workspace-widgets">
|
<div className="workspace-widgets">
|
||||||
{settingsConfig?.defaultwidgets?.map((data, idx) => <Widget key={`defwidget-${idx}`} widget={data} />)}
|
{defaultWidgets.map((data, idx) => (
|
||||||
|
<Widget key={`defwidget-${idx}`} widget={data} />
|
||||||
|
))}
|
||||||
{showDivider ? <div className="widget-divider" /> : null}
|
{showDivider ? <div className="widget-divider" /> : null}
|
||||||
{settingsConfig?.widgets?.map((data, idx) => <Widget key={`widget-${idx}`} widget={data} />)}
|
{widgets?.map((data, idx) => <Widget key={`widget-${idx}`} widget={data} />)}
|
||||||
{showHelp ? (
|
{showHelp ? (
|
||||||
<>
|
<>
|
||||||
<div className="widget-spacer" />
|
<div className="widget-spacer" />
|
||||||
@ -61,7 +83,7 @@ function getIconClass(icon: string): string {
|
|||||||
return `fa fa-solid fa-${icon} fa-fw`;
|
return `fa fa-solid fa-${icon} fa-fw`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Widget = React.memo(({ widget }: { widget: WidgetsConfigType }) => {
|
const Widget = React.memo(({ widget }: { widget: WidgetConfigType }) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="widget"
|
className="widget"
|
||||||
|
6
frontend/types/custom.d.ts
vendored
6
frontend/types/custom.d.ts
vendored
@ -12,7 +12,8 @@ declare global {
|
|||||||
uiContext: jotai.Atom<UIContext>; // driven from windowId, activetabid, etc.
|
uiContext: jotai.Atom<UIContext>; // driven from windowId, activetabid, etc.
|
||||||
waveWindow: jotai.Atom<WaveWindow>; // driven from WOS
|
waveWindow: jotai.Atom<WaveWindow>; // driven from WOS
|
||||||
workspace: jotai.Atom<Workspace>; // driven from WOS
|
workspace: jotai.Atom<Workspace>; // driven from WOS
|
||||||
settingsConfigAtom: jotai.PrimitiveAtom<SettingsConfigType>; // driven from WOS, settings -- updated via WebSocket
|
fullConfigAtom: jotai.PrimitiveAtom<FullConfigType>; // driven from WOS, settings -- updated via WebSocket
|
||||||
|
settingsAtom: jotai.Atom<SettingsType>; // derrived from fullConfig
|
||||||
tabAtom: jotai.Atom<Tab>; // driven from WOS
|
tabAtom: jotai.Atom<Tab>; // driven from WOS
|
||||||
activeTabId: jotai.Atom<string>; // derrived from windowDataAtom
|
activeTabId: jotai.Atom<string>; // derrived from windowDataAtom
|
||||||
isFullScreen: jotai.PrimitiveAtom<boolean>;
|
isFullScreen: jotai.PrimitiveAtom<boolean>;
|
||||||
@ -49,10 +50,9 @@ declare global {
|
|||||||
getAuthKey(): string;
|
getAuthKey(): string;
|
||||||
getIsDev(): boolean;
|
getIsDev(): boolean;
|
||||||
getCursorPoint: () => Electron.Point;
|
getCursorPoint: () => Electron.Point;
|
||||||
|
|
||||||
getPlatform: () => NodeJS.Platform;
|
getPlatform: () => NodeJS.Platform;
|
||||||
getEnv: (varName: string) => string;
|
getEnv: (varName: string) => string;
|
||||||
|
getUserName: () => string;
|
||||||
showContextMenu: (menu?: ElectronContextMenuItem[]) => void;
|
showContextMenu: (menu?: ElectronContextMenuItem[]) => void;
|
||||||
onContextMenuClick: (callback: (id: string) => void) => void;
|
onContextMenuClick: (callback: (id: string) => void) => void;
|
||||||
onNavigate: (callback: (url: string) => void) => void;
|
onNavigate: (callback: (url: string) => void) => void;
|
||||||
|
122
frontend/types/gotypes.d.ts
vendored
122
frontend/types/gotypes.d.ts
vendored
@ -5,22 +5,6 @@
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
||||||
// wconfig.AiConfigType
|
|
||||||
type AiConfigType = {
|
|
||||||
baseurl: string;
|
|
||||||
apitoken: string;
|
|
||||||
model: string;
|
|
||||||
maxtokens: number;
|
|
||||||
timeoutms: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
// wconfig.AutoUpdateOpts
|
|
||||||
type AutoUpdateOpts = {
|
|
||||||
enabled: boolean;
|
|
||||||
intervalms: number;
|
|
||||||
installonquit: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
// waveobj.Block
|
// waveobj.Block
|
||||||
type Block = WaveObj & {
|
type Block = WaveObj & {
|
||||||
blockdef: BlockDef;
|
blockdef: BlockDef;
|
||||||
@ -41,11 +25,6 @@ declare global {
|
|||||||
meta?: MetaType;
|
meta?: MetaType;
|
||||||
};
|
};
|
||||||
|
|
||||||
// wconfig.BlockHeaderOpts
|
|
||||||
type BlockHeaderOpts = {
|
|
||||||
showblockids: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
// webcmd.BlockInputWSCommand
|
// webcmd.BlockInputWSCommand
|
||||||
type BlockInputWSCommand = {
|
type BlockInputWSCommand = {
|
||||||
wscommand: "blockinput";
|
wscommand: "blockinput";
|
||||||
@ -157,6 +136,12 @@ declare global {
|
|||||||
meta: MetaType;
|
meta: MetaType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// wconfig.ConfigError
|
||||||
|
type ConfigError = {
|
||||||
|
file: string;
|
||||||
|
err: string;
|
||||||
|
};
|
||||||
|
|
||||||
// wshrpc.ConnStatus
|
// wshrpc.ConnStatus
|
||||||
type ConnStatus = {
|
type ConnStatus = {
|
||||||
status: string;
|
status: string;
|
||||||
@ -201,6 +186,17 @@ declare global {
|
|||||||
ijsonbudget?: number;
|
ijsonbudget?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// wconfig.FullConfigType
|
||||||
|
type FullConfigType = {
|
||||||
|
settings: SettingsType;
|
||||||
|
mimetypes: {[key: string]: MimeTypeConfigType};
|
||||||
|
defaultwidgets: {[key: string]: WidgetConfigType};
|
||||||
|
widgets: {[key: string]: WidgetConfigType};
|
||||||
|
presets: {[key: string]: MetaType};
|
||||||
|
termthemes: {[key: string]: TermThemeType};
|
||||||
|
configerrors: ConfigError[];
|
||||||
|
};
|
||||||
|
|
||||||
// fileservice.FullFile
|
// fileservice.FullFile
|
||||||
type FullFile = {
|
type FullFile = {
|
||||||
info: FileInfo;
|
info: FileInfo;
|
||||||
@ -235,6 +231,8 @@ declare global {
|
|||||||
connection?: string;
|
connection?: string;
|
||||||
history?: string[];
|
history?: string[];
|
||||||
"history:forward"?: string[];
|
"history:forward"?: string[];
|
||||||
|
"display:name"?: string;
|
||||||
|
"display:order"?: number;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
"icon:color"?: string;
|
"icon:color"?: string;
|
||||||
frame?: boolean;
|
frame?: boolean;
|
||||||
@ -363,21 +361,37 @@ declare global {
|
|||||||
termsize: TermSize;
|
termsize: TermSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
// wconfig.SettingsConfigType
|
// wconfig.SettingsType
|
||||||
type SettingsConfigType = {
|
type SettingsType = {
|
||||||
mimetypes: {[key: string]: MimeTypeConfigType};
|
"ai:*"?: boolean;
|
||||||
term: TerminalConfigType;
|
"ai:baseurl"?: string;
|
||||||
ai: AiConfigType;
|
"ai:apitoken"?: string;
|
||||||
defaultwidgets: WidgetsConfigType[];
|
"ai:name"?: string;
|
||||||
widgets: WidgetsConfigType[];
|
"ai:model"?: string;
|
||||||
"widget:showhelp": boolean;
|
"ai:maxtokens"?: number;
|
||||||
blockheader: BlockHeaderOpts;
|
"ai:timeoutms"?: number;
|
||||||
autoupdate: AutoUpdateOpts;
|
"term:*"?: boolean;
|
||||||
termthemes: {[key: string]: TermThemeType};
|
"term:fontsize"?: number;
|
||||||
window: WindowSettingsType;
|
"term:fontfamily"?: string;
|
||||||
web: WebConfigType;
|
"term:disablewebgl"?: boolean;
|
||||||
telemetry: TelemetrySettingsType;
|
"web:*"?: boolean;
|
||||||
presets?: {[key: string]: MetaType};
|
"web:openlinksinternally"?: boolean;
|
||||||
|
"blockheader:*"?: boolean;
|
||||||
|
"blockheader:showblockids"?: boolean;
|
||||||
|
"autoupdate:*"?: boolean;
|
||||||
|
"autoupdate:enabled"?: boolean;
|
||||||
|
"autoupdate:intervalms"?: number;
|
||||||
|
"autoupdate:installonquit"?: boolean;
|
||||||
|
"widget:*"?: boolean;
|
||||||
|
"widget:showhelp"?: boolean;
|
||||||
|
"window:*"?: boolean;
|
||||||
|
"window:transparent"?: boolean;
|
||||||
|
"window:blur"?: boolean;
|
||||||
|
"window:opacity"?: number;
|
||||||
|
"window:bgcolor"?: string;
|
||||||
|
"window:reducedmotion"?: boolean;
|
||||||
|
"telemetry:*"?: boolean;
|
||||||
|
"telemetry:enabled"?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// waveobj.StickerClickOptsType
|
// waveobj.StickerClickOptsType
|
||||||
@ -415,11 +429,6 @@ declare global {
|
|||||||
blockids: string[];
|
blockids: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
// wconfig.TelemetrySettingsType
|
|
||||||
type TelemetrySettingsType = {
|
|
||||||
enabled: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
// waveobj.TermSize
|
// waveobj.TermSize
|
||||||
type TermSize = {
|
type TermSize = {
|
||||||
rows: number;
|
rows: number;
|
||||||
@ -452,13 +461,6 @@ declare global {
|
|||||||
cursorAccent: string;
|
cursorAccent: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// wconfig.TerminalConfigType
|
|
||||||
type TerminalConfigType = {
|
|
||||||
fontsize?: number;
|
|
||||||
fontfamily?: string;
|
|
||||||
disablewebgl: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
// wshrpc.TimeSeriesData
|
// wshrpc.TimeSeriesData
|
||||||
type TimeSeriesData = {
|
type TimeSeriesData = {
|
||||||
ts: number;
|
ts: number;
|
||||||
@ -543,8 +545,7 @@ declare global {
|
|||||||
|
|
||||||
// wconfig.WatcherUpdate
|
// wconfig.WatcherUpdate
|
||||||
type WatcherUpdate = {
|
type WatcherUpdate = {
|
||||||
settings: SettingsConfigType;
|
fullconfig: FullConfigType;
|
||||||
error: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// wshrpc.WaveEvent
|
// wshrpc.WaveEvent
|
||||||
@ -599,11 +600,6 @@ declare global {
|
|||||||
args: any[];
|
args: any[];
|
||||||
};
|
};
|
||||||
|
|
||||||
// wconfig.WebConfigType
|
|
||||||
type WebConfigType = {
|
|
||||||
openlinksinternally: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
// service.WebReturnType
|
// service.WebReturnType
|
||||||
type WebReturnType = {
|
type WebReturnType = {
|
||||||
success?: boolean;
|
success?: boolean;
|
||||||
@ -612,9 +608,10 @@ declare global {
|
|||||||
updates?: WaveObjUpdate[];
|
updates?: WaveObjUpdate[];
|
||||||
};
|
};
|
||||||
|
|
||||||
// wconfig.WidgetsConfigType
|
// wconfig.WidgetConfigType
|
||||||
type WidgetsConfigType = {
|
type WidgetConfigType = {
|
||||||
icon: string;
|
"display:order"?: number;
|
||||||
|
icon?: string;
|
||||||
color?: string;
|
color?: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
@ -627,15 +624,6 @@ declare global {
|
|||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
// wconfig.WindowSettingsType
|
|
||||||
type WindowSettingsType = {
|
|
||||||
transparent: boolean;
|
|
||||||
blur: boolean;
|
|
||||||
opacity: number;
|
|
||||||
bgcolor: string;
|
|
||||||
reducedmotion: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
// waveobj.Workspace
|
// waveobj.Workspace
|
||||||
type Workspace = WaveObj & {
|
type Workspace = WaveObj & {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -242,6 +242,19 @@ function atomWithDebounce<T>(initialValue: T, delayMilliseconds = 500): AtomWith
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPrefixedSettings(settings: SettingsType, prefix: string): SettingsType {
|
||||||
|
const rtn: SettingsType = {};
|
||||||
|
if (settings == null || isBlank(prefix)) {
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
for (const key in settings) {
|
||||||
|
if (key == prefix || key.startsWith(prefix + ":")) {
|
||||||
|
rtn[key] = settings[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
atomWithDebounce,
|
atomWithDebounce,
|
||||||
atomWithThrottle,
|
atomWithThrottle,
|
||||||
@ -249,6 +262,7 @@ export {
|
|||||||
base64ToString,
|
base64ToString,
|
||||||
boundNumber,
|
boundNumber,
|
||||||
fireAndForget,
|
fireAndForget,
|
||||||
|
getPrefixedSettings,
|
||||||
getPromiseState,
|
getPromiseState,
|
||||||
getPromiseValue,
|
getPromiseValue,
|
||||||
isBlank,
|
isBlank,
|
||||||
|
@ -57,9 +57,9 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
initWS();
|
initWS();
|
||||||
await loadConnStatus();
|
await loadConnStatus();
|
||||||
subscribeToConnEvents();
|
subscribeToConnEvents();
|
||||||
const settings = await services.FileService.GetSettingsConfig();
|
const fullConfig = await services.FileService.GetFullConfig();
|
||||||
console.log("settings", settings);
|
console.log("fullconfig", fullConfig);
|
||||||
globalStore.set(atoms.settingsConfigAtom, settings);
|
globalStore.set(atoms.fullConfigAtom, fullConfig);
|
||||||
services.ObjectService.SetActiveTab(waveWindow.activetabid); // no need to wait
|
services.ObjectService.SetActiveTab(waveWindow.activetabid); // no need to wait
|
||||||
const reactElem = React.createElement(App, null, null);
|
const reactElem = React.createElement(App, null, null);
|
||||||
const elem = document.getElementById("main");
|
const elem = document.getElementById("main");
|
||||||
|
107
pkg/gogen/gogen.go
Normal file
107
pkg/gogen/gogen.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package gogen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateBoilerplate(buf *strings.Builder, pkgName string, imports []string) {
|
||||||
|
buf.WriteString("// Copyright 2024, Command Line Inc.\n")
|
||||||
|
buf.WriteString("// SPDX-License-Identifier: Apache-2.0\n")
|
||||||
|
buf.WriteString("\n// Generated Code. DO NOT EDIT.\n\n")
|
||||||
|
buf.WriteString(fmt.Sprintf("package %s\n\n", pkgName))
|
||||||
|
if len(imports) > 0 {
|
||||||
|
buf.WriteString("import (\n")
|
||||||
|
for _, imp := range imports {
|
||||||
|
buf.WriteString(fmt.Sprintf("\t%q\n", imp))
|
||||||
|
}
|
||||||
|
buf.WriteString(")\n\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBeforeColonPart(s string) string {
|
||||||
|
if colonIdx := strings.Index(s, ":"); colonIdx != -1 {
|
||||||
|
return s[:colonIdx]
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateMetaMapConsts(buf *strings.Builder, constPrefix string, rtype reflect.Type) {
|
||||||
|
buf.WriteString("const (\n")
|
||||||
|
var lastBeforeColon = ""
|
||||||
|
isFirst := true
|
||||||
|
for idx := 0; idx < rtype.NumField(); idx++ {
|
||||||
|
field := rtype.Field(idx)
|
||||||
|
if field.PkgPath != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fieldName := field.Name
|
||||||
|
jsonTag := field.Tag.Get("json")
|
||||||
|
if commaIdx := strings.Index(jsonTag, ","); commaIdx != -1 {
|
||||||
|
jsonTag = jsonTag[:commaIdx]
|
||||||
|
}
|
||||||
|
if jsonTag == "" {
|
||||||
|
jsonTag = fieldName
|
||||||
|
}
|
||||||
|
beforeColon := getBeforeColonPart(jsonTag)
|
||||||
|
if beforeColon != lastBeforeColon {
|
||||||
|
if !isFirst {
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
lastBeforeColon = beforeColon
|
||||||
|
}
|
||||||
|
cname := constPrefix + fieldName
|
||||||
|
buf.WriteString(fmt.Sprintf("\t%-40s = %q\n", cname, jsonTag))
|
||||||
|
isFirst = false
|
||||||
|
}
|
||||||
|
buf.WriteString(")\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenMethod_Call(buf *strings.Builder, methodDecl *wshrpc.WshRpcMethodDecl) {
|
||||||
|
fmt.Fprintf(buf, "// command %q, wshserver.%s\n", methodDecl.Command, methodDecl.MethodName)
|
||||||
|
var dataType string
|
||||||
|
dataVarName := "nil"
|
||||||
|
if methodDecl.CommandDataType != nil {
|
||||||
|
dataType = ", data " + methodDecl.CommandDataType.String()
|
||||||
|
dataVarName = "data"
|
||||||
|
}
|
||||||
|
returnType := "error"
|
||||||
|
respName := "_"
|
||||||
|
tParamVal := "any"
|
||||||
|
if methodDecl.DefaultResponseDataType != nil {
|
||||||
|
returnType = "(" + methodDecl.DefaultResponseDataType.String() + ", error)"
|
||||||
|
respName = "resp"
|
||||||
|
tParamVal = methodDecl.DefaultResponseDataType.String()
|
||||||
|
}
|
||||||
|
fmt.Fprintf(buf, "func %s(w *wshutil.WshRpc%s, opts *wshrpc.RpcOpts) %s {\n", methodDecl.MethodName, dataType, returnType)
|
||||||
|
fmt.Fprintf(buf, "\t%s, err := sendRpcRequestCallHelper[%s](w, %q, %s, opts)\n", respName, tParamVal, methodDecl.Command, dataVarName)
|
||||||
|
if methodDecl.DefaultResponseDataType != nil {
|
||||||
|
fmt.Fprintf(buf, "\treturn resp, err\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(buf, "\treturn err\n")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(buf, "}\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenMethod_ResponseStream(buf *strings.Builder, methodDecl *wshrpc.WshRpcMethodDecl) {
|
||||||
|
fmt.Fprintf(buf, "// command %q, wshserver.%s\n", methodDecl.Command, methodDecl.MethodName)
|
||||||
|
var dataType string
|
||||||
|
dataVarName := "nil"
|
||||||
|
if methodDecl.CommandDataType != nil {
|
||||||
|
dataType = ", data " + methodDecl.CommandDataType.String()
|
||||||
|
dataVarName = "data"
|
||||||
|
}
|
||||||
|
respType := "any"
|
||||||
|
if methodDecl.DefaultResponseDataType != nil {
|
||||||
|
respType = methodDecl.DefaultResponseDataType.String()
|
||||||
|
}
|
||||||
|
fmt.Fprintf(buf, "func %s(w *wshutil.WshRpc%s, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[%s] {\n", methodDecl.MethodName, dataType, respType)
|
||||||
|
fmt.Fprintf(buf, "\treturn sendRpcRequestResponseStreamHelper[%s](w, %q, %s, opts)\n", respType, methodDecl.Command, dataVarName)
|
||||||
|
fmt.Fprintf(buf, "}\n\n")
|
||||||
|
}
|
@ -153,17 +153,7 @@ func (fs *FileService) DeleteFile(connection string, path string) error {
|
|||||||
return wshclient.RemoteFileDeleteCommand(client, path, &wshrpc.RpcOpts{Route: connRoute})
|
return wshclient.RemoteFileDeleteCommand(client, path, &wshrpc.RpcOpts{Route: connRoute})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FileService) GetSettingsConfig() wconfig.SettingsConfigType {
|
func (fs *FileService) GetFullConfig() wconfig.FullConfigType {
|
||||||
watcher := wconfig.GetWatcher()
|
watcher := wconfig.GetWatcher()
|
||||||
return watcher.GetSettingsConfig()
|
return watcher.GetFullConfig()
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *FileService) AddWidget(newWidget wconfig.WidgetsConfigType) error {
|
|
||||||
watcher := wconfig.GetWatcher()
|
|
||||||
return watcher.AddWidget(newWidget)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *FileService) RemoveWidget(idx uint) error {
|
|
||||||
watcher := wconfig.GetWatcher()
|
|
||||||
return watcher.RmWidget(idx)
|
|
||||||
}
|
}
|
||||||
|
@ -74,11 +74,8 @@ func (tdata *TelemetryData) Scan(val interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IsTelemetryEnabled() bool {
|
func IsTelemetryEnabled() bool {
|
||||||
settings := wconfig.GetWatcher().GetSettingsConfig()
|
settings := wconfig.GetWatcher().GetFullConfig()
|
||||||
if settings.Telemetry == nil || settings.Telemetry.Enabled == nil {
|
return settings.Settings.TelemetryEnabled
|
||||||
return true
|
|
||||||
}
|
|
||||||
return *settings.Telemetry.Enabled
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsAllowedRenderer(renderer string) bool {
|
func IsAllowedRenderer(renderer string) bool {
|
||||||
|
@ -35,8 +35,7 @@ var ExtraTypes = []any{
|
|||||||
eventbus.WSFileEventData{},
|
eventbus.WSFileEventData{},
|
||||||
waveobj.LayoutActionData{},
|
waveobj.LayoutActionData{},
|
||||||
filestore.WaveFile{},
|
filestore.WaveFile{},
|
||||||
wconfig.SettingsConfigType{},
|
wconfig.FullConfigType{},
|
||||||
wconfig.TermThemesConfigType{},
|
|
||||||
wconfig.WatcherUpdate{},
|
wconfig.WatcherUpdate{},
|
||||||
wshutil.RpcMessage{},
|
wshutil.RpcMessage{},
|
||||||
wshrpc.WshServerCommandMeta{},
|
wshrpc.WshServerCommandMeta{},
|
||||||
|
59
pkg/waveobj/metaconsts.go
Normal file
59
pkg/waveobj/metaconsts.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Generated Code. DO NOT EDIT.
|
||||||
|
|
||||||
|
package waveobj
|
||||||
|
|
||||||
|
const (
|
||||||
|
MetaKey_View = "view"
|
||||||
|
|
||||||
|
MetaKey_Controller = "controller"
|
||||||
|
|
||||||
|
MetaKey_Title = "title"
|
||||||
|
|
||||||
|
MetaKey_File = "file"
|
||||||
|
|
||||||
|
MetaKey_Url = "url"
|
||||||
|
|
||||||
|
MetaKey_Connection = "connection"
|
||||||
|
|
||||||
|
MetaKey_History = "history"
|
||||||
|
MetaKey_HistoryForward = "history:forward"
|
||||||
|
|
||||||
|
MetaKey_DisplayName = "display:name"
|
||||||
|
MetaKey_DisplayOrder = "display:order"
|
||||||
|
|
||||||
|
MetaKey_Icon = "icon"
|
||||||
|
MetaKey_IconColor = "icon:color"
|
||||||
|
|
||||||
|
MetaKey_Frame = "frame"
|
||||||
|
MetaKey_FrameClear = "frame:*"
|
||||||
|
MetaKey_FrameBorderColor = "frame:bordercolor"
|
||||||
|
MetaKey_FrameBorderColor_Focused = "frame:bordercolor:focused"
|
||||||
|
|
||||||
|
MetaKey_Cmd = "cmd"
|
||||||
|
MetaKey_CmdClear = "cmd:*"
|
||||||
|
MetaKey_CmdInteractive = "cmd:interactive"
|
||||||
|
MetaKey_CmdLogin = "cmd:login"
|
||||||
|
MetaKey_CmdRunOnStart = "cmd:runonstart"
|
||||||
|
MetaKey_CmdClearOnStart = "cmd:clearonstart"
|
||||||
|
MetaKey_CmdClearOnRestart = "cmd:clearonrestart"
|
||||||
|
MetaKey_CmdEnv = "cmd:env"
|
||||||
|
MetaKey_CmdCwd = "cmd:cwd"
|
||||||
|
MetaKey_CmdNoWsh = "cmd:nowsh"
|
||||||
|
|
||||||
|
MetaKey_Bg = "bg"
|
||||||
|
MetaKey_BgClear = "bg:*"
|
||||||
|
MetaKey_BgOpacity = "bg:opacity"
|
||||||
|
MetaKey_BgBlendMode = "bg:blendmode"
|
||||||
|
|
||||||
|
MetaKey_TermClear = "term:*"
|
||||||
|
MetaKey_TermFontSize = "term:fontsize"
|
||||||
|
MetaKey_TermFontFamily = "term:fontfamily"
|
||||||
|
MetaKey_TermMode = "term:mode"
|
||||||
|
MetaKey_TermTheme = "term:theme"
|
||||||
|
|
||||||
|
MetaKey_Count = "count"
|
||||||
|
)
|
||||||
|
|
@ -9,51 +9,6 @@ import (
|
|||||||
|
|
||||||
const Entity_Any = "any"
|
const Entity_Any = "any"
|
||||||
|
|
||||||
// well known meta keys
|
|
||||||
// to add a new key, add it here and add it to MetaTSType (make sure the keys match)
|
|
||||||
// TODO: will code generate one side of this so we don't need to add the keys in two places
|
|
||||||
// will probably drive this off the meta decls so we can add more information and validate the keys/values
|
|
||||||
const (
|
|
||||||
MetaKey_DisplayName = "display:name" // special, does not get merged
|
|
||||||
MetaKey_DisplayOrder = "display:order" // special, does not get merged
|
|
||||||
|
|
||||||
MetaKey_View = "view"
|
|
||||||
MetaKey_Controller = "controller"
|
|
||||||
MetaKey_Title = "title"
|
|
||||||
MetaKey_File = "file"
|
|
||||||
MetaKey_Url = "url"
|
|
||||||
MetaKey_Connection = "connection"
|
|
||||||
MetaKey_History = "history" // stores an array of history items specific to the block
|
|
||||||
|
|
||||||
MetaKey_Icon = "icon"
|
|
||||||
MetaKey_IconColor = "icon:color"
|
|
||||||
|
|
||||||
MetaKey_Frame = "frame"
|
|
||||||
MetaKey_FrameBorderColor = "frame:bordercolor"
|
|
||||||
MetaKey_FrameBorderColor_Focused = "frame:bordercolor:focused"
|
|
||||||
|
|
||||||
MetaKey_Cmd = "cmd"
|
|
||||||
MetaKey_CmdInteractive = "cmd:interactive"
|
|
||||||
MetaKey_CmdLogin = "cmd:login"
|
|
||||||
MetaKey_CmdRunOnStart = "cmd:runonstart"
|
|
||||||
MetaKey_CmdClearOnStart = "cmd:clearonstart"
|
|
||||||
MetaKey_CmdClearOnRestart = "cmd:clearonrestart"
|
|
||||||
MetaKey_CmdEnv = "cmd:env"
|
|
||||||
MetaKey_CmdCwd = "cmd:cwd"
|
|
||||||
MetaKey_CmdNoWsh = "cmd:nowsh"
|
|
||||||
|
|
||||||
MetaKey_Bg = "bg"
|
|
||||||
MetaKey_BgClear = "bg:*"
|
|
||||||
MetaKey_BgOpacity = "bg:opacity"
|
|
||||||
MetaKey_BgBlendMode = "bg:blendmode"
|
|
||||||
|
|
||||||
MetaKey_TermFontSize = "term:fontsize"
|
|
||||||
MetaKey_TermFontFamily = "term:fontfamily"
|
|
||||||
MetaKey_TermMode = "term:mode"
|
|
||||||
MetaKey_TermTheme = "term:theme"
|
|
||||||
MetaKey_Count = "count" // temp for cpu plot. will remove later
|
|
||||||
)
|
|
||||||
|
|
||||||
// for typescript typing
|
// for typescript typing
|
||||||
type MetaTSType struct {
|
type MetaTSType struct {
|
||||||
// shared
|
// shared
|
||||||
@ -66,6 +21,9 @@ type MetaTSType struct {
|
|||||||
History []string `json:"history,omitempty"`
|
History []string `json:"history,omitempty"`
|
||||||
HistoryForward []string `json:"history:forward,omitempty"`
|
HistoryForward []string `json:"history:forward,omitempty"`
|
||||||
|
|
||||||
|
DisplayName string `json:"display:name,omitempty"`
|
||||||
|
DisplayOrder float64 `json:"display:order,omitempty"`
|
||||||
|
|
||||||
Icon string `json:"icon,omitempty"`
|
Icon string `json:"icon,omitempty"`
|
||||||
IconColor string `json:"icon:color,omitempty"`
|
IconColor string `json:"icon:color,omitempty"`
|
||||||
|
|
||||||
@ -118,7 +76,8 @@ type MetaPresetDecl struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// returns a clean copy of meta with mergeMeta merged in
|
// returns a clean copy of meta with mergeMeta merged in
|
||||||
func MergeMeta(meta MetaMapType, metaUpdate MetaMapType) MetaMapType {
|
// if mergeSpecial is false, then special keys will not be merged (like display:*)
|
||||||
|
func MergeMeta(meta MetaMapType, metaUpdate MetaMapType, mergeSpecial bool) MetaMapType {
|
||||||
rtn := make(MetaMapType)
|
rtn := make(MetaMapType)
|
||||||
for k, v := range meta {
|
for k, v := range meta {
|
||||||
rtn[k] = v
|
rtn[k] = v
|
||||||
@ -145,7 +104,7 @@ func MergeMeta(meta MetaMapType, metaUpdate MetaMapType) MetaMapType {
|
|||||||
}
|
}
|
||||||
// now deal with regular keys
|
// now deal with regular keys
|
||||||
for k, v := range metaUpdate {
|
for k, v := range metaUpdate {
|
||||||
if strings.HasPrefix(k, "display:") {
|
if !mergeSpecial && strings.HasPrefix(k, "display:") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(k, ":*") {
|
if strings.HasSuffix(k, ":*") {
|
||||||
|
9
pkg/wconfig/defaultconfig/defaultconfig.go
Normal file
9
pkg/wconfig/defaultconfig/defaultconfig.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package defaultconfig
|
||||||
|
|
||||||
|
import "embed"
|
||||||
|
|
||||||
|
//go:embed *.json
|
||||||
|
var ConfigFS embed.FS
|
55
pkg/wconfig/defaultconfig/defaultwidgets.json
Normal file
55
pkg/wconfig/defaultconfig/defaultwidgets.json
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"defwidget@terminal": {
|
||||||
|
"display:order": 1,
|
||||||
|
"icon": "square-terminal",
|
||||||
|
"label": "terminal",
|
||||||
|
"blockdef": {
|
||||||
|
"meta": {
|
||||||
|
"view": "term",
|
||||||
|
"controller": "shell"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defwidget@files": {
|
||||||
|
"display:order": 2,
|
||||||
|
"icon": "folder",
|
||||||
|
"label": "files",
|
||||||
|
"blockdef": {
|
||||||
|
"meta": {
|
||||||
|
"view": "preview",
|
||||||
|
"file": "~"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defwidget@web": {
|
||||||
|
"display:order": 3,
|
||||||
|
"icon": "globe",
|
||||||
|
"label": "web",
|
||||||
|
"blockdef": {
|
||||||
|
"meta": {
|
||||||
|
"view": "web",
|
||||||
|
"url": "https://waveterm.dev/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defwidget@ai": {
|
||||||
|
"display:order": 4,
|
||||||
|
"icon": "sparkles",
|
||||||
|
"label": "ai",
|
||||||
|
"blockdef": {
|
||||||
|
"meta": {
|
||||||
|
"view": "waveai"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defwidget@cpuplot": {
|
||||||
|
"display:order": 5,
|
||||||
|
"icon": "chart-line",
|
||||||
|
"label": "cpu",
|
||||||
|
"blockdef": {
|
||||||
|
"meta": {
|
||||||
|
"view": "cpuplot"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
pkg/wconfig/defaultconfig/mimetypes.json
Normal file
57
pkg/wconfig/defaultconfig/mimetypes.json
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"audio": {
|
||||||
|
"icon": "file-audio"
|
||||||
|
},
|
||||||
|
"application/pdf": {
|
||||||
|
"icon": "file-pdf"
|
||||||
|
},
|
||||||
|
"application/json": {
|
||||||
|
"icon": "file-lines"
|
||||||
|
},
|
||||||
|
"directory": {
|
||||||
|
"icon": "folder",
|
||||||
|
"color": "var(--term-bright-blue)"
|
||||||
|
},
|
||||||
|
"font": {
|
||||||
|
"icon": "book-font"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"icon": "file-image"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"icon": "file-lines"
|
||||||
|
},
|
||||||
|
"text/css": {
|
||||||
|
"icon": "css3-alt fa-brands"
|
||||||
|
},
|
||||||
|
"text/javascript": {
|
||||||
|
"icon": "js fa-brands"
|
||||||
|
},
|
||||||
|
"text/typescript": {
|
||||||
|
"icon": "js fa-brands"
|
||||||
|
},
|
||||||
|
"text/golang": {
|
||||||
|
"icon": "golang fa-brands"
|
||||||
|
},
|
||||||
|
"text/html": {
|
||||||
|
"icon": "html5 fa-brands"
|
||||||
|
},
|
||||||
|
"text/less": {
|
||||||
|
"icon": "less fa-brands"
|
||||||
|
},
|
||||||
|
"text/markdown": {
|
||||||
|
"icon": "markdown fa-brands"
|
||||||
|
},
|
||||||
|
"text/rust": {
|
||||||
|
"icon": "rust fa-brands"
|
||||||
|
},
|
||||||
|
"text/scss": {
|
||||||
|
"icon": "sass fa-brands"
|
||||||
|
},
|
||||||
|
"video": {
|
||||||
|
"icon": "file-video"
|
||||||
|
},
|
||||||
|
"text/csv": {
|
||||||
|
"icon": "file-csv"
|
||||||
|
}
|
||||||
|
}
|
32
pkg/wconfig/defaultconfig/presets.json
Normal file
32
pkg/wconfig/defaultconfig/presets.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"bg@default": {
|
||||||
|
"display:name": "Default",
|
||||||
|
"display:order": -1,
|
||||||
|
"bg:*": true
|
||||||
|
},
|
||||||
|
"bg@rainbow": {
|
||||||
|
"display:name": "Rainbow",
|
||||||
|
"display:order": 1,
|
||||||
|
"bg:*": true,
|
||||||
|
"bg": "linear-gradient( 226.4deg, rgba(255,26,1,1) 28.9%, rgba(254,155,1,1) 33%, rgba(255,241,0,1) 48.6%, rgba(34,218,1,1) 65.3%, rgba(0,141,254,1) 80.6%, rgba(113,63,254,1) 100.1% )",
|
||||||
|
"bg:opacity": 0.3
|
||||||
|
},
|
||||||
|
"bg@green": {
|
||||||
|
"display:name": "Green",
|
||||||
|
"bg:*": true,
|
||||||
|
"bg": "green",
|
||||||
|
"bg:opacity": 0.3
|
||||||
|
},
|
||||||
|
"bg@blue": {
|
||||||
|
"display:name": "Blue",
|
||||||
|
"bg:*": true,
|
||||||
|
"bg": "blue",
|
||||||
|
"bg:opacity": 0.3
|
||||||
|
},
|
||||||
|
"bg@red": {
|
||||||
|
"display:name": "Red",
|
||||||
|
"bg:*": true,
|
||||||
|
"bg": "red",
|
||||||
|
"bg:opacity": 0.3
|
||||||
|
}
|
||||||
|
}
|
8
pkg/wconfig/defaultconfig/settings.json
Normal file
8
pkg/wconfig/defaultconfig/settings.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"ai:model": "gpt-3.5-turbo",
|
||||||
|
"ai:maxtokens": 1000,
|
||||||
|
"ai:timeoutms": 10000,
|
||||||
|
"autoupdate:enabled": true,
|
||||||
|
"autoupdate:installonquit": true,
|
||||||
|
"autoupdate:intervalms": 3600000
|
||||||
|
}
|
74
pkg/wconfig/defaultconfig/termthemes.json
Normal file
74
pkg/wconfig/defaultconfig/termthemes.json
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"default-dark": {
|
||||||
|
"black": "#757575",
|
||||||
|
"red": "#cc685c",
|
||||||
|
"green": "#76c266",
|
||||||
|
"yellow": "#cbca9b",
|
||||||
|
"blue": "#85aacb",
|
||||||
|
"magenta": "#cc72ca",
|
||||||
|
"cyan": "#74a7cb",
|
||||||
|
"white": "#c1c1c1",
|
||||||
|
"brightBlack": "#727272",
|
||||||
|
"brightRed": "#cc9d97",
|
||||||
|
"brightGreen": "#a3dd97",
|
||||||
|
"brightYellow": "#cbcaaa",
|
||||||
|
"brightBlue": "#9ab6cb",
|
||||||
|
"brightMagenta": "#cc8ecb",
|
||||||
|
"brightCyan": "#b7b8cb",
|
||||||
|
"brightWhite": "#f0f0f0",
|
||||||
|
"gray": "#8b918a",
|
||||||
|
"cmdtext": "#f0f0f0",
|
||||||
|
"foreground": "#c1c1c1",
|
||||||
|
"selectionBackground": "",
|
||||||
|
"background": "#00000077",
|
||||||
|
"cursorAccent": ""
|
||||||
|
},
|
||||||
|
"dracula": {
|
||||||
|
"black": "#21222C",
|
||||||
|
"red": "#FF5555",
|
||||||
|
"green": "#50FA7B",
|
||||||
|
"yellow": "#F1FA8C",
|
||||||
|
"blue": "#BD93F9",
|
||||||
|
"magenta": "#FF79C6",
|
||||||
|
"cyan": "#8BE9FD",
|
||||||
|
"white": "#F8F8F2",
|
||||||
|
"brightBlack": "#6272A4",
|
||||||
|
"brightRed": "#FF6E6E",
|
||||||
|
"brightGreen": "#69FF94",
|
||||||
|
"brightYellow": "#FFFFA5",
|
||||||
|
"brightBlue": "#D6ACFF",
|
||||||
|
"brightMagenta": "#FF92DF",
|
||||||
|
"brightCyan": "#A4FFFF",
|
||||||
|
"brightWhite": "#FFFFFF",
|
||||||
|
"gray": "#6272A4",
|
||||||
|
"cmdtext": "#F8F8F2",
|
||||||
|
"foreground": "#F8F8F2",
|
||||||
|
"selectionBackground": "#44475a",
|
||||||
|
"background": "#282a36",
|
||||||
|
"cursorAccent": "#f8f8f2"
|
||||||
|
},
|
||||||
|
"campbell": {
|
||||||
|
"black": "#0C0C0C",
|
||||||
|
"red": "#C50F1F",
|
||||||
|
"green": "#13A10E",
|
||||||
|
"yellow": "#C19C00",
|
||||||
|
"blue": "#0037DA",
|
||||||
|
"magenta": "#881798",
|
||||||
|
"cyan": "#3A96DD",
|
||||||
|
"white": "#CCCCCC",
|
||||||
|
"brightBlack": "#767676",
|
||||||
|
"brightRed": "#E74856",
|
||||||
|
"brightGreen": "#16C60C",
|
||||||
|
"brightYellow": "#F9F1A5",
|
||||||
|
"brightBlue": "#3B78FF",
|
||||||
|
"brightMagenta": "#B4009E",
|
||||||
|
"brightCyan": "#61D6D6",
|
||||||
|
"brightWhite": "#F2F2F2",
|
||||||
|
"gray": "#767676",
|
||||||
|
"cmdtext": "#CCCCCC",
|
||||||
|
"foreground": "#CCCCCC",
|
||||||
|
"selectionBackground": "#3A96DD",
|
||||||
|
"background": "#0C0C0C",
|
||||||
|
"cursorAccent": "#CCCCCC"
|
||||||
|
}
|
||||||
|
}
|
@ -4,14 +4,9 @@
|
|||||||
package wconfig
|
package wconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
@ -22,97 +17,19 @@ import (
|
|||||||
const configDir = "config"
|
const configDir = "config"
|
||||||
|
|
||||||
var configDirAbsPath = filepath.Join(wavebase.GetWaveHomeDir(), configDir)
|
var configDirAbsPath = filepath.Join(wavebase.GetWaveHomeDir(), configDir)
|
||||||
var termThemesDirAbsPath = filepath.Join(configDirAbsPath, termThemesDir)
|
|
||||||
|
|
||||||
var instance *Watcher
|
var instance *Watcher
|
||||||
var once sync.Once
|
var once sync.Once
|
||||||
|
|
||||||
type Watcher struct {
|
type Watcher struct {
|
||||||
initialized bool
|
initialized bool
|
||||||
watcher *fsnotify.Watcher
|
watcher *fsnotify.Watcher
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
settingsData SettingsConfigType
|
fullConfig FullConfigType
|
||||||
}
|
}
|
||||||
|
|
||||||
type WatcherUpdate struct {
|
type WatcherUpdate struct {
|
||||||
Settings SettingsConfigType `json:"settings"`
|
FullConfig FullConfigType `json:"fullconfig"`
|
||||||
Error string `json:"error"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadFullSettings() (*SettingsConfigType, error) {
|
|
||||||
// first load settings.json
|
|
||||||
// then load themes
|
|
||||||
// then apply defaults
|
|
||||||
settings, err := readFileContents[SettingsConfigType](settingsAbsPath, false)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
themes, err := readThemes()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if settings.TermThemes == nil {
|
|
||||||
settings.TermThemes = make(map[string]TermThemeType)
|
|
||||||
}
|
|
||||||
for k, v := range themes {
|
|
||||||
settings.TermThemes[k] = v
|
|
||||||
}
|
|
||||||
applyDefaultSettings(settings)
|
|
||||||
return settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readThemes() (map[string]TermThemeType, error) {
|
|
||||||
files, err := os.ReadDir(termThemesDirAbsPath)
|
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error reading themes directory: %v", err)
|
|
||||||
}
|
|
||||||
themes := make(map[string]TermThemeType)
|
|
||||||
for _, file := range files {
|
|
||||||
if !file.IsDir() && filepath.Ext(file.Name()) == ".json" {
|
|
||||||
log.Printf("reading theme file %s\n", file.Name())
|
|
||||||
theme, err := readFileContents[TermThemeType](filepath.Join(termThemesDirAbsPath, file.Name()), true)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error reading theme file %s: %v", file.Name(), err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if theme == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
themeName := getThemeName(file.Name())
|
|
||||||
themes[themeName] = *theme
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return themes, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func readFileContents[T any](filePath string, nilOnNotExist bool) (*T, error) {
|
|
||||||
var content T
|
|
||||||
data, err := os.ReadFile(filePath)
|
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
|
||||||
if nilOnNotExist {
|
|
||||||
return nil, nil
|
|
||||||
} else {
|
|
||||||
return &content, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("could not read file %s: %v", filePath, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(data, &content); err != nil {
|
|
||||||
log.Printf("could not unmarshal file %s: %v", filePath, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &content, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isInDirectory(fileName, directory string) bool {
|
|
||||||
rel, err := filepath.Rel(directory, fileName)
|
|
||||||
return err == nil && !strings.HasPrefix(rel, "..")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWatcher returns the singleton instance of the Watcher
|
// GetWatcher returns the singleton instance of the Watcher
|
||||||
@ -124,52 +41,14 @@ func GetWatcher() *Watcher {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
instance = &Watcher{watcher: watcher}
|
instance = &Watcher{watcher: watcher}
|
||||||
if err := instance.addSettingsFile(settingsAbsPath); err != nil {
|
err = instance.watcher.Add(configDirAbsPath)
|
||||||
log.Printf("failed to add path %s to watcher: %v", settingsAbsPath, err)
|
if err != nil {
|
||||||
return
|
log.Printf("failed to add path %s to watcher: %v", configDirAbsPath, err)
|
||||||
}
|
|
||||||
if err := instance.addTermThemesDir(termThemesDirAbsPath); err != nil {
|
|
||||||
log.Printf("failed to add terminal themes path %s to watcher: %v", termThemesDirAbsPath, err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return instance
|
return instance
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) addSettingsFile(filePath string) error {
|
|
||||||
w.mutex.Lock()
|
|
||||||
defer w.mutex.Unlock()
|
|
||||||
|
|
||||||
dir := filepath.Dir(filePath)
|
|
||||||
err := os.MkdirAll(dir, 0751)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error creating config directory: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.watcher.Add(filePath)
|
|
||||||
log.Printf("started config watcher: %v\n", filePath)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) addTermThemesDir(dir string) error {
|
|
||||||
w.mutex.Lock()
|
|
||||||
defer w.mutex.Unlock()
|
|
||||||
|
|
||||||
_, err := os.Stat(dir)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
if err := os.MkdirAll(dir, 0751); err != nil {
|
|
||||||
return fmt.Errorf("error creating themes directory: %v", err)
|
|
||||||
}
|
|
||||||
} else if err != nil {
|
|
||||||
return fmt.Errorf("error accessing themes directory: %v", err)
|
|
||||||
}
|
|
||||||
if err := w.watcher.Add(dir); err != nil {
|
|
||||||
return fmt.Errorf("error adding themes directory to watcher: %v", err)
|
|
||||||
}
|
|
||||||
log.Printf("started termthemes watcher: %v\n", dir)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) Start() {
|
func (w *Watcher) Start() {
|
||||||
w.mutex.Lock()
|
w.mutex.Lock()
|
||||||
defer w.mutex.Unlock()
|
defer w.mutex.Unlock()
|
||||||
@ -198,13 +77,9 @@ func (w *Watcher) Start() {
|
|||||||
|
|
||||||
// for initial values, exit on first error
|
// for initial values, exit on first error
|
||||||
func (w *Watcher) sendInitialValues() error {
|
func (w *Watcher) sendInitialValues() error {
|
||||||
settings, err := LoadFullSettings()
|
w.fullConfig = ReadFullConfig()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.settingsData = *settings
|
|
||||||
message := WatcherUpdate{
|
message := WatcherUpdate{
|
||||||
Settings: w.settingsData,
|
FullConfig: w.fullConfig,
|
||||||
}
|
}
|
||||||
w.broadcast(message)
|
w.broadcast(message)
|
||||||
return nil
|
return nil
|
||||||
@ -226,17 +101,12 @@ func (w *Watcher) broadcast(message WatcherUpdate) {
|
|||||||
EventType: eventbus.WSEvent_Config,
|
EventType: eventbus.WSEvent_Config,
|
||||||
Data: message,
|
Data: message,
|
||||||
})
|
})
|
||||||
|
|
||||||
if message.Error != "" {
|
|
||||||
log.Printf("watcher: error processing update: %v. error: %s", message.Settings, message.Error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) GetSettingsConfig() SettingsConfigType {
|
func (w *Watcher) GetFullConfig() FullConfigType {
|
||||||
w.mutex.Lock()
|
w.mutex.Lock()
|
||||||
defer w.mutex.Unlock()
|
defer w.mutex.Unlock()
|
||||||
|
return w.fullConfig
|
||||||
return w.settingsData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) handleEvent(event fsnotify.Event) {
|
func (w *Watcher) handleEvent(event fsnotify.Event) {
|
||||||
@ -250,11 +120,7 @@ func (w *Watcher) handleEvent(event fsnotify.Event) {
|
|||||||
if !isValidSubSettingsFileName(fileName) {
|
if !isValidSubSettingsFileName(fileName) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if isInDirectory(fileName, termThemesDirAbsPath) {
|
w.handleSettingsFileEvent(event, fileName)
|
||||||
w.handleTermThemesEvent(event, fileName)
|
|
||||||
} else if filepath.Base(fileName) == filepath.Base(settingsAbsPath) {
|
|
||||||
w.handleSettingsFileEvent(event, fileName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var validFileRe = regexp.MustCompile(`^[a-zA-Z0-9_@.-]+\.json$`)
|
var validFileRe = regexp.MustCompile(`^[a-zA-Z0-9_@.-]+\.json$`)
|
||||||
@ -267,50 +133,8 @@ func isValidSubSettingsFileName(fileName string) bool {
|
|||||||
return validFileRe.MatchString(baseName)
|
return validFileRe.MatchString(baseName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) handleTermThemesEvent(event fsnotify.Event, fileName string) {
|
|
||||||
settings, err := LoadFullSettings()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error loading settings after term-themes event: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.settingsData = *settings
|
|
||||||
w.broadcast(WatcherUpdate{Settings: w.settingsData})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) handleSettingsFileEvent(event fsnotify.Event, fileName string) {
|
func (w *Watcher) handleSettingsFileEvent(event fsnotify.Event, fileName string) {
|
||||||
settings, err := LoadFullSettings()
|
fullConfig := ReadFullConfig()
|
||||||
if err != nil {
|
w.fullConfig = fullConfig
|
||||||
log.Printf("error loading settings after settings file event: %v", err)
|
w.broadcast(WatcherUpdate{FullConfig: w.fullConfig})
|
||||||
return
|
|
||||||
}
|
|
||||||
w.settingsData = *settings
|
|
||||||
w.broadcast(WatcherUpdate{Settings: w.settingsData})
|
|
||||||
}
|
|
||||||
|
|
||||||
func getThemeName(fileName string) string {
|
|
||||||
return strings.TrimSuffix(filepath.Base(fileName), filepath.Ext(fileName))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) AddWidget(newWidget WidgetsConfigType) error {
|
|
||||||
current := w.GetSettingsConfig()
|
|
||||||
current.Widgets = append(current.Widgets, newWidget)
|
|
||||||
update, err := json.Marshal(current)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
os.MkdirAll(filepath.Dir(settingsFile), 0751)
|
|
||||||
return os.WriteFile(settingsFile, update, 0644)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) RmWidget(idx uint) error {
|
|
||||||
current := w.GetSettingsConfig().Widgets
|
|
||||||
truncated := append(current[:idx], current[idx+1:]...)
|
|
||||||
update, err := json.Marshal(truncated)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
os.MkdirAll(filepath.Dir(settingsFile), 0751)
|
|
||||||
return os.WriteFile(settingsFile, update, 0644)
|
|
||||||
}
|
}
|
||||||
|
46
pkg/wconfig/metaconsts.go
Normal file
46
pkg/wconfig/metaconsts.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Generated Code. DO NOT EDIT.
|
||||||
|
|
||||||
|
package wconfig
|
||||||
|
|
||||||
|
const (
|
||||||
|
ConfigKey_AiClear = "ai:*"
|
||||||
|
ConfigKey_AiBaseURL = "ai:baseurl"
|
||||||
|
ConfigKey_AiApiToken = "ai:apitoken"
|
||||||
|
ConfigKey_AiName = "ai:name"
|
||||||
|
ConfigKey_AiModel = "ai:model"
|
||||||
|
ConfigKey_AiMaxTokens = "ai:maxtokens"
|
||||||
|
ConfigKey_AiTimeoutMs = "ai:timeoutms"
|
||||||
|
|
||||||
|
ConfigKey_TermClear = "term:*"
|
||||||
|
ConfigKey_TermFontSize = "term:fontsize"
|
||||||
|
ConfigKey_TermFontFamily = "term:fontfamily"
|
||||||
|
ConfigKey_TermDisableWebGl = "term:disablewebgl"
|
||||||
|
|
||||||
|
ConfigKey_WebClear = "web:*"
|
||||||
|
ConfigKey_WebOpenLinksInternally = "web:openlinksinternally"
|
||||||
|
|
||||||
|
ConfigKey_BlockHeaderClear = "blockheader:*"
|
||||||
|
ConfigKey_BlockHeaderShowBlockIds = "blockheader:showblockids"
|
||||||
|
|
||||||
|
ConfigKey_AutoUpdateClear = "autoupdate:*"
|
||||||
|
ConfigKey_AutoUpdateEnabled = "autoupdate:enabled"
|
||||||
|
ConfigKey_AutoUpdateIntervalMs = "autoupdate:intervalms"
|
||||||
|
ConfigKey_AutoUpdateInstallOnQuit = "autoupdate:installonquit"
|
||||||
|
|
||||||
|
ConfigKey_WidgetClear = "widget:*"
|
||||||
|
ConfigKey_WidgetShowHelp = "widget:showhelp"
|
||||||
|
|
||||||
|
ConfigKey_WindowClear = "window:*"
|
||||||
|
ConfigKey_WindowTransparent = "window:transparent"
|
||||||
|
ConfigKey_WindowBlur = "window:blur"
|
||||||
|
ConfigKey_WindowOpacity = "window:opacity"
|
||||||
|
ConfigKey_WindowBgColor = "window:bgcolor"
|
||||||
|
ConfigKey_WindowReducedMotion = "window:reducedmotion"
|
||||||
|
|
||||||
|
ConfigKey_TelemetryClear = "telemetry:*"
|
||||||
|
ConfigKey_TelemetryEnabled = "telemetry:enabled"
|
||||||
|
)
|
||||||
|
|
@ -4,40 +4,293 @@
|
|||||||
package wconfig
|
package wconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/util/utilfn"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wconfig/defaultconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
const termThemesDir = "terminal-themes"
|
const SettingsFile = "settings.json"
|
||||||
const settingsFile = "settings.json"
|
|
||||||
|
|
||||||
var settingsAbsPath = filepath.Join(configDirAbsPath, settingsFile)
|
type SettingsType struct {
|
||||||
|
AiClear bool `json:"ai:*,omitempty"`
|
||||||
|
AiBaseURL string `json:"ai:baseurl,omitempty"`
|
||||||
|
AiApiToken string `json:"ai:apitoken,omitempty"`
|
||||||
|
AiName string `json:"ai:name,omitempty"`
|
||||||
|
AiModel string `json:"ai:model,omitempty"`
|
||||||
|
AiMaxTokens int `json:"ai:maxtokens,omitempty"`
|
||||||
|
AiTimeoutMs int `json:"ai:timeoutms,omitempty"`
|
||||||
|
|
||||||
type WidgetsConfigType struct {
|
TermClear bool `json:"term:*,omitempty"`
|
||||||
Icon string `json:"icon"`
|
TermFontSize int `json:"term:fontsize,omitempty"`
|
||||||
Color string `json:"color,omitempty"`
|
TermFontFamily string `json:"term:fontfamily,omitempty"`
|
||||||
Label string `json:"label,omitempty"`
|
TermDisableWebGl bool `json:"term:disablewebgl,omitempty"`
|
||||||
Description string `json:"description,omitempty"`
|
|
||||||
BlockDef waveobj.BlockDef `json:"blockdef"`
|
WebClear bool `json:"web:*,omitempty"`
|
||||||
|
WebOpenLinksInternally bool `json:"web:openlinksinternally,omitempty"`
|
||||||
|
|
||||||
|
BlockHeaderClear bool `json:"blockheader:*,omitempty"`
|
||||||
|
BlockHeaderShowBlockIds bool `json:"blockheader:showblockids,omitempty"`
|
||||||
|
|
||||||
|
AutoUpdateClear bool `json:"autoupdate:*,omitempty"`
|
||||||
|
AutoUpdateEnabled bool `json:"autoupdate:enabled,omitempty"`
|
||||||
|
AutoUpdateIntervalMs int `json:"autoupdate:intervalms,omitempty"`
|
||||||
|
AutoUpdateInstallOnQuit bool `json:"autoupdate:installonquit,omitempty"`
|
||||||
|
|
||||||
|
WidgetClear bool `json:"widget:*,omitempty"`
|
||||||
|
WidgetShowHelp bool `json:"widget:showhelp,omitempty"`
|
||||||
|
|
||||||
|
WindowClear bool `json:"window:*,omitempty"`
|
||||||
|
WindowTransparent bool `json:"window:transparent,omitempty"`
|
||||||
|
WindowBlur bool `json:"window:blur,omitempty"`
|
||||||
|
WindowOpacity float64 `json:"window:opacity,omitempty"`
|
||||||
|
WindowBgColor string `json:"window:bgcolor,omitempty"`
|
||||||
|
WindowReducedMotion bool `json:"window:reducedmotion,omitempty"`
|
||||||
|
|
||||||
|
TelemetryClear bool `json:"telemetry:*,omitempty"`
|
||||||
|
TelemetryEnabled bool `json:"telemetry:enabled,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TerminalConfigType struct {
|
type ConfigError struct {
|
||||||
FontSize int `json:"fontsize,omitempty"`
|
File string `json:"file"`
|
||||||
FontFamily string `json:"fontfamily,omitempty"`
|
Err string `json:"err"`
|
||||||
DisableWebGl bool `json:"disablewebgl"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebConfigType struct {
|
type FullConfigType struct {
|
||||||
OpenLinksInternally bool `json:"openlinksinternally"`
|
Settings SettingsType `json:"settings" merge:"meta"`
|
||||||
|
MimeTypes map[string]MimeTypeConfigType `json:"mimetypes"`
|
||||||
|
DefaultWidgets map[string]WidgetConfigType `json:"defaultwidgets"`
|
||||||
|
Widgets map[string]WidgetConfigType `json:"widgets"`
|
||||||
|
Presets map[string]waveobj.MetaMapType `json:"presets"`
|
||||||
|
TermThemes map[string]TermThemeType `json:"termthemes"`
|
||||||
|
ConfigErrors []ConfigError `json:"configerrors" configfile:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AiConfigType struct {
|
var settingsAbsPath = filepath.Join(configDirAbsPath, SettingsFile)
|
||||||
BaseURL string `json:"baseurl"`
|
|
||||||
ApiToken string `json:"apitoken"`
|
func readConfigHelper(fileName string, barr []byte, readErr error) (waveobj.MetaMapType, []ConfigError) {
|
||||||
Model string `json:"model"`
|
var cerrs []ConfigError
|
||||||
MaxTokens uint32 `json:"maxtokens"`
|
if readErr != nil && !os.IsNotExist(readErr) {
|
||||||
TimeoutMs uint32 `json:"timeoutms"`
|
cerrs = append(cerrs, ConfigError{File: "defaults:" + fileName, Err: readErr.Error()})
|
||||||
|
}
|
||||||
|
if len(barr) == 0 {
|
||||||
|
return nil, cerrs
|
||||||
|
}
|
||||||
|
var rtn waveobj.MetaMapType
|
||||||
|
err := json.Unmarshal(barr, &rtn)
|
||||||
|
if err != nil {
|
||||||
|
cerrs = append(cerrs, ConfigError{File: "defaults:" + fileName, Err: err.Error()})
|
||||||
|
}
|
||||||
|
return rtn, cerrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadDefaultsConfigFile(fileName string) (waveobj.MetaMapType, []ConfigError) {
|
||||||
|
barr, readErr := defaultconfig.ConfigFS.ReadFile(fileName)
|
||||||
|
return readConfigHelper("defaults:"+fileName, barr, readErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadWaveHomeConfigFile(fileName string) (waveobj.MetaMapType, []ConfigError) {
|
||||||
|
fullFileName := filepath.Join(configDirAbsPath, fileName)
|
||||||
|
barr, err := os.ReadFile(fullFileName)
|
||||||
|
return readConfigHelper(fullFileName, barr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteWaveHomeConfigFile(fileName string, m waveobj.MetaMapType) error {
|
||||||
|
fullFileName := filepath.Join(configDirAbsPath, fileName)
|
||||||
|
barr, err := jsonMarshalConfigInOrder(m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return os.WriteFile(fullFileName, barr, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
// simple merge that overwrites
|
||||||
|
func mergeMetaMapSimple(m waveobj.MetaMapType, toMerge waveobj.MetaMapType) waveobj.MetaMapType {
|
||||||
|
if m == nil {
|
||||||
|
return toMerge
|
||||||
|
}
|
||||||
|
if toMerge == nil {
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
for k, v := range toMerge {
|
||||||
|
if v == nil {
|
||||||
|
delete(m, k)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
if len(m) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadConfigPart(partName string, simpleMerge bool) (waveobj.MetaMapType, []ConfigError) {
|
||||||
|
defConfig, cerrs1 := ReadDefaultsConfigFile(partName)
|
||||||
|
userConfig, cerrs2 := ReadWaveHomeConfigFile(partName)
|
||||||
|
allErrs := append(cerrs1, cerrs2...)
|
||||||
|
if simpleMerge {
|
||||||
|
return mergeMetaMapSimple(defConfig, userConfig), allErrs
|
||||||
|
} else {
|
||||||
|
return waveobj.MergeMeta(defConfig, userConfig, true), allErrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadFullConfig() FullConfigType {
|
||||||
|
var fullConfig FullConfigType
|
||||||
|
configRType := reflect.TypeOf(fullConfig)
|
||||||
|
configRVal := reflect.ValueOf(&fullConfig).Elem()
|
||||||
|
for fieldIdx := 0; fieldIdx < configRType.NumField(); fieldIdx++ {
|
||||||
|
field := configRType.Field(fieldIdx)
|
||||||
|
if field.PkgPath != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
configFile := field.Tag.Get("configfile")
|
||||||
|
if configFile == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
jsonTag := field.Tag.Get("json")
|
||||||
|
if jsonTag == "-" || jsonTag == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
simpleMerge := field.Tag.Get("merge") == ""
|
||||||
|
fileName := field.Tag.Get("json") + ".json"
|
||||||
|
configPart, cerrs := ReadConfigPart(fileName, simpleMerge)
|
||||||
|
fullConfig.ConfigErrors = append(fullConfig.ConfigErrors, cerrs...)
|
||||||
|
if configPart != nil {
|
||||||
|
fieldPtr := configRVal.Field(fieldIdx).Addr().Interface()
|
||||||
|
utilfn.ReUnmarshal(fieldPtr, configPart)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fullConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConfigKeyType(configKey string) reflect.Type {
|
||||||
|
ctype := reflect.TypeOf(SettingsType{})
|
||||||
|
for i := 0; i < ctype.NumField(); i++ {
|
||||||
|
field := ctype.Field(i)
|
||||||
|
if field.Tag.Get("json") == configKey {
|
||||||
|
return field.Type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConfigKeyNamespace(key string) string {
|
||||||
|
colonIdx := strings.Index(key, ":")
|
||||||
|
if colonIdx == -1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return key[:colonIdx]
|
||||||
|
}
|
||||||
|
|
||||||
|
func orderConfigKeys(m waveobj.MetaMapType) []string {
|
||||||
|
keys := make([]string, 0, len(m))
|
||||||
|
for k := range m {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Slice(keys, func(i, j int) bool {
|
||||||
|
k1 := keys[i]
|
||||||
|
k2 := keys[j]
|
||||||
|
k1ns := getConfigKeyNamespace(k1)
|
||||||
|
k2ns := getConfigKeyNamespace(k2)
|
||||||
|
if k1ns != k2ns {
|
||||||
|
return k1ns < k2ns
|
||||||
|
}
|
||||||
|
return k1 < k2
|
||||||
|
})
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
func reindentJson(barr []byte, indentStr string) []byte {
|
||||||
|
if len(barr) < 2 {
|
||||||
|
return barr
|
||||||
|
}
|
||||||
|
if barr[0] != '{' && barr[0] != '[' {
|
||||||
|
return barr
|
||||||
|
}
|
||||||
|
if bytes.Index(barr, []byte("\n")) == -1 {
|
||||||
|
return barr
|
||||||
|
}
|
||||||
|
outputLines := bytes.Split(barr, []byte("\n"))
|
||||||
|
for i, line := range outputLines {
|
||||||
|
if i == 0 || i == len(outputLines)-1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
outputLines[i] = append([]byte(indentStr), line...)
|
||||||
|
}
|
||||||
|
return bytes.Join(outputLines, []byte("\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonMarshalConfigInOrder(m waveobj.MetaMapType) ([]byte, error) {
|
||||||
|
if len(m) == 0 {
|
||||||
|
return []byte("{}"), nil
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
orderedKeys := orderConfigKeys(m)
|
||||||
|
buf.WriteString("{\n")
|
||||||
|
for idx, key := range orderedKeys {
|
||||||
|
val := m[key]
|
||||||
|
keyBarr, err := json.Marshal(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
valBarr, err := json.MarshalIndent(val, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
valBarr = reindentJson(valBarr, " ")
|
||||||
|
buf.WriteString(" ")
|
||||||
|
buf.Write(keyBarr)
|
||||||
|
buf.WriteString(": ")
|
||||||
|
buf.Write(valBarr)
|
||||||
|
if idx < len(orderedKeys)-1 {
|
||||||
|
buf.WriteString(",")
|
||||||
|
}
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
buf.WriteString("}")
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetBaseConfigValue(configKey string, val any) error {
|
||||||
|
ctype := getConfigKeyType(configKey)
|
||||||
|
if ctype == nil {
|
||||||
|
return fmt.Errorf("invalid config key: %s", configKey)
|
||||||
|
}
|
||||||
|
m, cerrs := ReadWaveHomeConfigFile(SettingsFile)
|
||||||
|
if len(cerrs) > 0 {
|
||||||
|
return fmt.Errorf("error reading config file: %v", cerrs[0])
|
||||||
|
}
|
||||||
|
if m == nil {
|
||||||
|
m = make(waveobj.MetaMapType)
|
||||||
|
}
|
||||||
|
if val == nil {
|
||||||
|
delete(m, configKey)
|
||||||
|
} else {
|
||||||
|
if reflect.TypeOf(val) != ctype {
|
||||||
|
return fmt.Errorf("invalid value type for %s: %T", configKey, val)
|
||||||
|
}
|
||||||
|
m[configKey] = val
|
||||||
|
}
|
||||||
|
return WriteWaveHomeConfigFile(SettingsFile, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WidgetConfigType struct {
|
||||||
|
DisplayOrder float64 `json:"display:order,omitempty"`
|
||||||
|
Icon string `json:"icon,omitempty"`
|
||||||
|
Color string `json:"color,omitempty"`
|
||||||
|
Label string `json:"label,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
BlockDef waveobj.BlockDef `json:"blockdef"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MimeTypeConfigType struct {
|
type MimeTypeConfigType struct {
|
||||||
@ -45,16 +298,6 @@ type MimeTypeConfigType struct {
|
|||||||
Color string `json:"color"`
|
Color string `json:"color"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockHeaderOpts struct {
|
|
||||||
ShowBlockIds bool `json:"showblockids"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AutoUpdateOpts struct {
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
IntervalMs uint32 `json:"intervalms"`
|
|
||||||
InstallOnQuit bool `json:"installonquit"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type TermThemeType struct {
|
type TermThemeType struct {
|
||||||
Black string `json:"black"`
|
Black string `json:"black"`
|
||||||
Red string `json:"red"`
|
Red string `json:"red"`
|
||||||
@ -79,275 +322,3 @@ type TermThemeType struct {
|
|||||||
Background string `json:"background"`
|
Background string `json:"background"`
|
||||||
CursorAccent string `json:"cursorAccent"`
|
CursorAccent string `json:"cursorAccent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TermThemesConfigType map[string]TermThemeType
|
|
||||||
|
|
||||||
// TODO add default term theme settings
|
|
||||||
|
|
||||||
// note we pointers so we preserve nulls
|
|
||||||
type WindowSettingsType struct {
|
|
||||||
Transparent *bool `json:"transparent"`
|
|
||||||
Blur *bool `json:"blur"`
|
|
||||||
Opacity *float64 `json:"opacity"`
|
|
||||||
BgColor *string `json:"bgcolor"`
|
|
||||||
ReducedMotion *bool `json:"reducedmotion"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type TelemetrySettingsType struct {
|
|
||||||
Enabled *bool `json:"enabled"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type SettingsConfigType struct {
|
|
||||||
MimeTypes map[string]MimeTypeConfigType `json:"mimetypes"`
|
|
||||||
Term TerminalConfigType `json:"term"`
|
|
||||||
Ai *AiConfigType `json:"ai"`
|
|
||||||
DefaultWidgets []WidgetsConfigType `json:"defaultwidgets"`
|
|
||||||
Widgets []WidgetsConfigType `json:"widgets"`
|
|
||||||
WidgetShowHelp *bool `json:"widget:showhelp"`
|
|
||||||
BlockHeader BlockHeaderOpts `json:"blockheader"`
|
|
||||||
AutoUpdate *AutoUpdateOpts `json:"autoupdate"`
|
|
||||||
TermThemes TermThemesConfigType `json:"termthemes"`
|
|
||||||
WindowSettings WindowSettingsType `json:"window"`
|
|
||||||
Web WebConfigType `json:"web"`
|
|
||||||
Telemetry *TelemetrySettingsType `json:"telemetry"`
|
|
||||||
Presets map[string]*waveobj.MetaMapType `json:"presets,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var DefaultTermDarkTheme = TermThemeType{
|
|
||||||
Black: "#757575",
|
|
||||||
Red: "#cc685c",
|
|
||||||
Green: "#76c266",
|
|
||||||
Yellow: "#cbca9b",
|
|
||||||
Blue: "#85aacb",
|
|
||||||
Magenta: "#cc72ca",
|
|
||||||
Cyan: "#74a7cb",
|
|
||||||
White: "#c1c1c1",
|
|
||||||
BrightBlack: "#727272",
|
|
||||||
BrightRed: "#cc9d97",
|
|
||||||
BrightGreen: "#a3dd97",
|
|
||||||
BrightYellow: "#cbcaaa",
|
|
||||||
BrightBlue: "#9ab6cb",
|
|
||||||
BrightMagenta: "#cc8ecb",
|
|
||||||
BrightCyan: "#b7b8cb",
|
|
||||||
BrightWhite: "#f0f0f0",
|
|
||||||
Gray: "#8b918a",
|
|
||||||
CmdText: "#f0f0f0",
|
|
||||||
Foreground: "#c1c1c1",
|
|
||||||
SelectionBackground: "",
|
|
||||||
Background: "#00000077",
|
|
||||||
CursorAccent: "",
|
|
||||||
}
|
|
||||||
|
|
||||||
var DraculaTheme = TermThemeType{
|
|
||||||
Black: "#21222C", // AnsiBlack
|
|
||||||
Red: "#FF5555", // AnsiRed
|
|
||||||
Green: "#50FA7B", // AnsiGreen
|
|
||||||
Yellow: "#F1FA8C", // AnsiYellow
|
|
||||||
Blue: "#BD93F9", // AnsiBlue
|
|
||||||
Magenta: "#FF79C6", // AnsiMagenta
|
|
||||||
Cyan: "#8BE9FD", // AnsiCyan
|
|
||||||
White: "#F8F8F2", // AnsiWhite
|
|
||||||
BrightBlack: "#6272A4", // AnsiBrightBlack
|
|
||||||
BrightRed: "#FF6E6E", // AnsiBrightRed
|
|
||||||
BrightGreen: "#69FF94", // AnsiBrightGreen
|
|
||||||
BrightYellow: "#FFFFA5", // AnsiBrightYellow
|
|
||||||
BrightBlue: "#D6ACFF", // AnsiBrightBlue
|
|
||||||
BrightMagenta: "#FF92DF", // AnsiBrightMagenta
|
|
||||||
BrightCyan: "#A4FFFF", // AnsiBrightCyan
|
|
||||||
BrightWhite: "#FFFFFF", // AnsiBrightWhite
|
|
||||||
Gray: "#6272A4", // Comment or closest approximation
|
|
||||||
CmdText: "#F8F8F2", // Foreground
|
|
||||||
Foreground: "#F8F8F2", // Foreground
|
|
||||||
SelectionBackground: "#44475a", // Selection
|
|
||||||
Background: "#282a36", // Background
|
|
||||||
CursorAccent: "#f8f8f2", // Foreground (used for cursor accent)
|
|
||||||
}
|
|
||||||
|
|
||||||
var CampbellTheme = TermThemeType{
|
|
||||||
Black: "#0C0C0C", // Black
|
|
||||||
Red: "#C50F1F", // Red
|
|
||||||
Green: "#13A10E", // Green
|
|
||||||
Yellow: "#C19C00", // Yellow
|
|
||||||
Blue: "#0037DA", // Blue
|
|
||||||
Magenta: "#881798", // Purple (used as Magenta)
|
|
||||||
Cyan: "#3A96DD", // Cyan
|
|
||||||
White: "#CCCCCC", // White
|
|
||||||
BrightBlack: "#767676", // BrightBlack
|
|
||||||
BrightRed: "#E74856", // BrightRed
|
|
||||||
BrightGreen: "#16C60C", // BrightGreen
|
|
||||||
BrightYellow: "#F9F1A5", // BrightYellow
|
|
||||||
BrightBlue: "#3B78FF", // BrightBlue
|
|
||||||
BrightMagenta: "#B4009E", // BrightPurple (used as BrightMagenta)
|
|
||||||
BrightCyan: "#61D6D6", // BrightCyan
|
|
||||||
BrightWhite: "#F2F2F2", // BrightWhite
|
|
||||||
Gray: "#767676", // BrightBlack or closest approximation
|
|
||||||
CmdText: "#CCCCCC", // Foreground
|
|
||||||
Foreground: "#CCCCCC", // Foreground
|
|
||||||
SelectionBackground: "#3A96DD", // Cyan (chosen for selection background)
|
|
||||||
Background: "#0C0C0C", // Background
|
|
||||||
CursorAccent: "#CCCCCC", // Foreground (used for cursor accent)
|
|
||||||
}
|
|
||||||
|
|
||||||
var BgDefaultPreset = waveobj.MetaMapType{
|
|
||||||
waveobj.MetaKey_DisplayName: "Default",
|
|
||||||
waveobj.MetaKey_DisplayOrder: -1,
|
|
||||||
waveobj.MetaKey_BgClear: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var BgRainbowPreset = waveobj.MetaMapType{
|
|
||||||
waveobj.MetaKey_DisplayName: "Rainbow",
|
|
||||||
waveobj.MetaKey_DisplayOrder: 1,
|
|
||||||
waveobj.MetaKey_BgClear: true,
|
|
||||||
waveobj.MetaKey_Bg: "linear-gradient( 226.4deg, rgba(255,26,1,1) 28.9%, rgba(254,155,1,1) 33%, rgba(255,241,0,1) 48.6%, rgba(34,218,1,1) 65.3%, rgba(0,141,254,1) 80.6%, rgba(113,63,254,1) 100.1% );",
|
|
||||||
waveobj.MetaKey_BgOpacity: 0.3,
|
|
||||||
}
|
|
||||||
|
|
||||||
var BgGreenPreset = waveobj.MetaMapType{
|
|
||||||
waveobj.MetaKey_DisplayName: "Green",
|
|
||||||
waveobj.MetaKey_BgClear: true,
|
|
||||||
waveobj.MetaKey_Bg: "green",
|
|
||||||
waveobj.MetaKey_BgOpacity: 0.3,
|
|
||||||
}
|
|
||||||
|
|
||||||
var BgBluePreset = waveobj.MetaMapType{
|
|
||||||
waveobj.MetaKey_DisplayName: "Blue",
|
|
||||||
waveobj.MetaKey_BgClear: true,
|
|
||||||
waveobj.MetaKey_Bg: "blue",
|
|
||||||
waveobj.MetaKey_BgOpacity: 0.3,
|
|
||||||
}
|
|
||||||
|
|
||||||
var BgRedPreset = waveobj.MetaMapType{
|
|
||||||
waveobj.MetaKey_DisplayName: "Red",
|
|
||||||
waveobj.MetaKey_BgClear: true,
|
|
||||||
waveobj.MetaKey_Bg: "red",
|
|
||||||
waveobj.MetaKey_BgOpacity: 0.3,
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyDefaultSettings(settings *SettingsConfigType) {
|
|
||||||
defaultMimeTypes := map[string]MimeTypeConfigType{
|
|
||||||
"audio": {Icon: "file-audio"},
|
|
||||||
"application/pdf": {Icon: "file-pdf"},
|
|
||||||
"application/json": {Icon: "file-lines"},
|
|
||||||
"directory": {Icon: "folder", Color: "var(--term-bright-blue)"},
|
|
||||||
"font": {Icon: "book-font"},
|
|
||||||
"image": {Icon: "file-image"},
|
|
||||||
"text": {Icon: "file-lines"},
|
|
||||||
"text/css": {Icon: "css3-alt fa-brands"},
|
|
||||||
"text/javascript": {Icon: "js fa-brands"},
|
|
||||||
"text/typescript": {Icon: "js fa-brands"},
|
|
||||||
"text/golang": {Icon: "golang fa-brands"},
|
|
||||||
"text/html": {Icon: "html5 fa-brands"},
|
|
||||||
"text/less": {Icon: "less fa-brands"},
|
|
||||||
"text/markdown": {Icon: "markdown fa-brands"},
|
|
||||||
"text/rust": {Icon: "rust fa-brands"},
|
|
||||||
"text/scss": {Icon: "sass fa-brands"},
|
|
||||||
"video": {Icon: "file-video"},
|
|
||||||
"text/csv": {Icon: "file-csv"},
|
|
||||||
}
|
|
||||||
if settings.MimeTypes == nil {
|
|
||||||
settings.MimeTypes = defaultMimeTypes
|
|
||||||
} else {
|
|
||||||
for k, v := range defaultMimeTypes {
|
|
||||||
if _, found := settings.MimeTypes[k]; !found {
|
|
||||||
settings.MimeTypes[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if settings.AutoUpdate == nil {
|
|
||||||
settings.AutoUpdate = &AutoUpdateOpts{
|
|
||||||
Enabled: true,
|
|
||||||
InstallOnQuit: true,
|
|
||||||
IntervalMs: 3600000,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if settings.Ai == nil {
|
|
||||||
settings.Ai = &AiConfigType{
|
|
||||||
Model: "gpt-3.5-turbo",
|
|
||||||
MaxTokens: 1000,
|
|
||||||
TimeoutMs: 10 * 1000,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
defaultWidgets := []WidgetsConfigType{
|
|
||||||
{
|
|
||||||
Icon: "square-terminal",
|
|
||||||
Label: "terminal",
|
|
||||||
BlockDef: waveobj.BlockDef{
|
|
||||||
Meta: map[string]any{
|
|
||||||
waveobj.MetaKey_View: "term",
|
|
||||||
waveobj.MetaKey_Controller: "shell",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Icon: "folder",
|
|
||||||
Label: "files",
|
|
||||||
BlockDef: waveobj.BlockDef{
|
|
||||||
Meta: map[string]any{
|
|
||||||
waveobj.MetaKey_View: "preview",
|
|
||||||
waveobj.MetaKey_File: "~",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Icon: "globe",
|
|
||||||
Label: "web",
|
|
||||||
BlockDef: waveobj.BlockDef{
|
|
||||||
Meta: map[string]any{
|
|
||||||
waveobj.MetaKey_View: "web",
|
|
||||||
waveobj.MetaKey_Url: "https://waveterm.dev/",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Icon: "sparkles",
|
|
||||||
Label: "waveai",
|
|
||||||
BlockDef: waveobj.BlockDef{
|
|
||||||
Meta: map[string]any{
|
|
||||||
waveobj.MetaKey_View: "waveai",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Icon: "chart-line",
|
|
||||||
Label: "cpu",
|
|
||||||
BlockDef: waveobj.BlockDef{
|
|
||||||
Meta: map[string]any{
|
|
||||||
waveobj.MetaKey_View: "cpuplot",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if settings.DefaultWidgets == nil {
|
|
||||||
settings.DefaultWidgets = defaultWidgets
|
|
||||||
}
|
|
||||||
if settings.TermThemes == nil {
|
|
||||||
settings.TermThemes = make(map[string]TermThemeType)
|
|
||||||
}
|
|
||||||
if _, found := settings.TermThemes["default-dark"]; !found {
|
|
||||||
settings.TermThemes["default-dark"] = DefaultTermDarkTheme
|
|
||||||
}
|
|
||||||
if _, found := settings.TermThemes["dracula"]; !found {
|
|
||||||
settings.TermThemes["dracula"] = DraculaTheme
|
|
||||||
}
|
|
||||||
if _, found := settings.TermThemes["campbell"]; !found {
|
|
||||||
settings.TermThemes["campbell"] = CampbellTheme
|
|
||||||
}
|
|
||||||
if settings.Presets == nil {
|
|
||||||
settings.Presets = make(map[string]*waveobj.MetaMapType)
|
|
||||||
}
|
|
||||||
if _, found := settings.Presets["bg@default"]; !found {
|
|
||||||
settings.Presets["bg@default"] = &BgDefaultPreset
|
|
||||||
}
|
|
||||||
if _, found := settings.Presets["bg@rainbow"]; !found {
|
|
||||||
settings.Presets["bg@rainbow"] = &BgRainbowPreset
|
|
||||||
}
|
|
||||||
if _, found := settings.Presets["bg@green"]; !found {
|
|
||||||
settings.Presets["bg@green"] = &BgGreenPreset
|
|
||||||
}
|
|
||||||
if _, found := settings.Presets["bg@blue"]; !found {
|
|
||||||
settings.Presets["bg@blue"] = &BgBluePreset
|
|
||||||
}
|
|
||||||
if _, found := settings.Presets["bg@red"]; !found {
|
|
||||||
settings.Presets["bg@red"] = &BgRedPreset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright 2024, Command Line Inc.
|
// Copyright 2024, Command Line Inc.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
// generated by cmd/generatewshclient/main-generatewshclient.go
|
// Generated Code. DO NOT EDIT.
|
||||||
|
|
||||||
package wshclient
|
package wshclient
|
||||||
|
|
||||||
@ -13,171 +13,171 @@ import (
|
|||||||
|
|
||||||
// command "announce", wshserver.AnnounceCommand
|
// command "announce", wshserver.AnnounceCommand
|
||||||
func AnnounceCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
func AnnounceCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "announce", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "announce", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "authenticate", wshserver.AuthenticateCommand
|
// command "authenticate", wshserver.AuthenticateCommand
|
||||||
func AuthenticateCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) (wshrpc.CommandAuthenticateRtnData, error) {
|
func AuthenticateCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) (wshrpc.CommandAuthenticateRtnData, error) {
|
||||||
resp, err := sendRpcRequestCallHelper[wshrpc.CommandAuthenticateRtnData](w, "authenticate", data, opts)
|
resp, err := sendRpcRequestCallHelper[wshrpc.CommandAuthenticateRtnData](w, "authenticate", data, opts)
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "controllerinput", wshserver.ControllerInputCommand
|
// command "controllerinput", wshserver.ControllerInputCommand
|
||||||
func ControllerInputCommand(w *wshutil.WshRpc, data wshrpc.CommandBlockInputData, opts *wshrpc.RpcOpts) error {
|
func ControllerInputCommand(w *wshutil.WshRpc, data wshrpc.CommandBlockInputData, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "controllerinput", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "controllerinput", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "controllerrestart", wshserver.ControllerRestartCommand
|
// command "controllerrestart", wshserver.ControllerRestartCommand
|
||||||
func ControllerRestartCommand(w *wshutil.WshRpc, data wshrpc.CommandBlockRestartData, opts *wshrpc.RpcOpts) error {
|
func ControllerRestartCommand(w *wshutil.WshRpc, data wshrpc.CommandBlockRestartData, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "controllerrestart", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "controllerrestart", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "createblock", wshserver.CreateBlockCommand
|
// command "createblock", wshserver.CreateBlockCommand
|
||||||
func CreateBlockCommand(w *wshutil.WshRpc, data wshrpc.CommandCreateBlockData, opts *wshrpc.RpcOpts) (waveobj.ORef, error) {
|
func CreateBlockCommand(w *wshutil.WshRpc, data wshrpc.CommandCreateBlockData, opts *wshrpc.RpcOpts) (waveobj.ORef, error) {
|
||||||
resp, err := sendRpcRequestCallHelper[waveobj.ORef](w, "createblock", data, opts)
|
resp, err := sendRpcRequestCallHelper[waveobj.ORef](w, "createblock", data, opts)
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "deleteblock", wshserver.DeleteBlockCommand
|
// command "deleteblock", wshserver.DeleteBlockCommand
|
||||||
func DeleteBlockCommand(w *wshutil.WshRpc, data wshrpc.CommandDeleteBlockData, opts *wshrpc.RpcOpts) error {
|
func DeleteBlockCommand(w *wshutil.WshRpc, data wshrpc.CommandDeleteBlockData, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "deleteblock", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "deleteblock", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "eventpublish", wshserver.EventPublishCommand
|
// command "eventpublish", wshserver.EventPublishCommand
|
||||||
func EventPublishCommand(w *wshutil.WshRpc, data wshrpc.WaveEvent, opts *wshrpc.RpcOpts) error {
|
func EventPublishCommand(w *wshutil.WshRpc, data wshrpc.WaveEvent, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "eventpublish", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "eventpublish", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "eventrecv", wshserver.EventRecvCommand
|
// command "eventrecv", wshserver.EventRecvCommand
|
||||||
func EventRecvCommand(w *wshutil.WshRpc, data wshrpc.WaveEvent, opts *wshrpc.RpcOpts) error {
|
func EventRecvCommand(w *wshutil.WshRpc, data wshrpc.WaveEvent, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "eventrecv", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "eventrecv", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "eventsub", wshserver.EventSubCommand
|
// command "eventsub", wshserver.EventSubCommand
|
||||||
func EventSubCommand(w *wshutil.WshRpc, data wshrpc.SubscriptionRequest, opts *wshrpc.RpcOpts) error {
|
func EventSubCommand(w *wshutil.WshRpc, data wshrpc.SubscriptionRequest, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "eventsub", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "eventsub", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "eventunsub", wshserver.EventUnsubCommand
|
// command "eventunsub", wshserver.EventUnsubCommand
|
||||||
func EventUnsubCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
func EventUnsubCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "eventunsub", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "eventunsub", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "eventunsuball", wshserver.EventUnsubAllCommand
|
// command "eventunsuball", wshserver.EventUnsubAllCommand
|
||||||
func EventUnsubAllCommand(w *wshutil.WshRpc, opts *wshrpc.RpcOpts) error {
|
func EventUnsubAllCommand(w *wshutil.WshRpc, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "eventunsuball", nil, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "eventunsuball", nil, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "fileappend", wshserver.FileAppendCommand
|
// command "fileappend", wshserver.FileAppendCommand
|
||||||
func FileAppendCommand(w *wshutil.WshRpc, data wshrpc.CommandFileData, opts *wshrpc.RpcOpts) error {
|
func FileAppendCommand(w *wshutil.WshRpc, data wshrpc.CommandFileData, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "fileappend", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "fileappend", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "fileappendijson", wshserver.FileAppendIJsonCommand
|
// command "fileappendijson", wshserver.FileAppendIJsonCommand
|
||||||
func FileAppendIJsonCommand(w *wshutil.WshRpc, data wshrpc.CommandAppendIJsonData, opts *wshrpc.RpcOpts) error {
|
func FileAppendIJsonCommand(w *wshutil.WshRpc, data wshrpc.CommandAppendIJsonData, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "fileappendijson", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "fileappendijson", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "fileread", wshserver.FileReadCommand
|
// command "fileread", wshserver.FileReadCommand
|
||||||
func FileReadCommand(w *wshutil.WshRpc, data wshrpc.CommandFileData, opts *wshrpc.RpcOpts) (string, error) {
|
func FileReadCommand(w *wshutil.WshRpc, data wshrpc.CommandFileData, opts *wshrpc.RpcOpts) (string, error) {
|
||||||
resp, err := sendRpcRequestCallHelper[string](w, "fileread", data, opts)
|
resp, err := sendRpcRequestCallHelper[string](w, "fileread", data, opts)
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "filewrite", wshserver.FileWriteCommand
|
// command "filewrite", wshserver.FileWriteCommand
|
||||||
func FileWriteCommand(w *wshutil.WshRpc, data wshrpc.CommandFileData, opts *wshrpc.RpcOpts) error {
|
func FileWriteCommand(w *wshutil.WshRpc, data wshrpc.CommandFileData, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "filewrite", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "filewrite", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "getmeta", wshserver.GetMetaCommand
|
// command "getmeta", wshserver.GetMetaCommand
|
||||||
func GetMetaCommand(w *wshutil.WshRpc, data wshrpc.CommandGetMetaData, opts *wshrpc.RpcOpts) (waveobj.MetaMapType, error) {
|
func GetMetaCommand(w *wshutil.WshRpc, data wshrpc.CommandGetMetaData, opts *wshrpc.RpcOpts) (waveobj.MetaMapType, error) {
|
||||||
resp, err := sendRpcRequestCallHelper[waveobj.MetaMapType](w, "getmeta", data, opts)
|
resp, err := sendRpcRequestCallHelper[waveobj.MetaMapType](w, "getmeta", data, opts)
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "message", wshserver.MessageCommand
|
// command "message", wshserver.MessageCommand
|
||||||
func MessageCommand(w *wshutil.WshRpc, data wshrpc.CommandMessageData, opts *wshrpc.RpcOpts) error {
|
func MessageCommand(w *wshutil.WshRpc, data wshrpc.CommandMessageData, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "message", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "message", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "remotefiledelete", wshserver.RemoteFileDeleteCommand
|
// command "remotefiledelete", wshserver.RemoteFileDeleteCommand
|
||||||
func RemoteFileDeleteCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
func RemoteFileDeleteCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "remotefiledelete", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "remotefiledelete", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "remotefileinfo", wshserver.RemoteFileInfoCommand
|
// command "remotefileinfo", wshserver.RemoteFileInfoCommand
|
||||||
func RemoteFileInfoCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) (*wshrpc.FileInfo, error) {
|
func RemoteFileInfoCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) (*wshrpc.FileInfo, error) {
|
||||||
resp, err := sendRpcRequestCallHelper[*wshrpc.FileInfo](w, "remotefileinfo", data, opts)
|
resp, err := sendRpcRequestCallHelper[*wshrpc.FileInfo](w, "remotefileinfo", data, opts)
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "remotestreamcpudata", wshserver.RemoteStreamCpuDataCommand
|
// command "remotestreamcpudata", wshserver.RemoteStreamCpuDataCommand
|
||||||
func RemoteStreamCpuDataCommand(w *wshutil.WshRpc, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[wshrpc.TimeSeriesData] {
|
func RemoteStreamCpuDataCommand(w *wshutil.WshRpc, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[wshrpc.TimeSeriesData] {
|
||||||
return sendRpcRequestResponseStreamHelper[wshrpc.TimeSeriesData](w, "remotestreamcpudata", nil, opts)
|
return sendRpcRequestResponseStreamHelper[wshrpc.TimeSeriesData](w, "remotestreamcpudata", nil, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "remotestreamfile", wshserver.RemoteStreamFileCommand
|
// command "remotestreamfile", wshserver.RemoteStreamFileCommand
|
||||||
func RemoteStreamFileCommand(w *wshutil.WshRpc, data wshrpc.CommandRemoteStreamFileData, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[wshrpc.CommandRemoteStreamFileRtnData] {
|
func RemoteStreamFileCommand(w *wshutil.WshRpc, data wshrpc.CommandRemoteStreamFileData, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[wshrpc.CommandRemoteStreamFileRtnData] {
|
||||||
return sendRpcRequestResponseStreamHelper[wshrpc.CommandRemoteStreamFileRtnData](w, "remotestreamfile", data, opts)
|
return sendRpcRequestResponseStreamHelper[wshrpc.CommandRemoteStreamFileRtnData](w, "remotestreamfile", data, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "remotewritefile", wshserver.RemoteWriteFileCommand
|
// command "remotewritefile", wshserver.RemoteWriteFileCommand
|
||||||
func RemoteWriteFileCommand(w *wshutil.WshRpc, data wshrpc.CommandRemoteWriteFileData, opts *wshrpc.RpcOpts) error {
|
func RemoteWriteFileCommand(w *wshutil.WshRpc, data wshrpc.CommandRemoteWriteFileData, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "remotewritefile", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "remotewritefile", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "resolveids", wshserver.ResolveIdsCommand
|
// command "resolveids", wshserver.ResolveIdsCommand
|
||||||
func ResolveIdsCommand(w *wshutil.WshRpc, data wshrpc.CommandResolveIdsData, opts *wshrpc.RpcOpts) (wshrpc.CommandResolveIdsRtnData, error) {
|
func ResolveIdsCommand(w *wshutil.WshRpc, data wshrpc.CommandResolveIdsData, opts *wshrpc.RpcOpts) (wshrpc.CommandResolveIdsRtnData, error) {
|
||||||
resp, err := sendRpcRequestCallHelper[wshrpc.CommandResolveIdsRtnData](w, "resolveids", data, opts)
|
resp, err := sendRpcRequestCallHelper[wshrpc.CommandResolveIdsRtnData](w, "resolveids", data, opts)
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "setmeta", wshserver.SetMetaCommand
|
// command "setmeta", wshserver.SetMetaCommand
|
||||||
func SetMetaCommand(w *wshutil.WshRpc, data wshrpc.CommandSetMetaData, opts *wshrpc.RpcOpts) error {
|
func SetMetaCommand(w *wshutil.WshRpc, data wshrpc.CommandSetMetaData, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "setmeta", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "setmeta", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "setview", wshserver.SetViewCommand
|
// command "setview", wshserver.SetViewCommand
|
||||||
func SetViewCommand(w *wshutil.WshRpc, data wshrpc.CommandBlockSetViewData, opts *wshrpc.RpcOpts) error {
|
func SetViewCommand(w *wshutil.WshRpc, data wshrpc.CommandBlockSetViewData, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "setview", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "setview", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "streamcpudata", wshserver.StreamCpuDataCommand
|
// command "streamcpudata", wshserver.StreamCpuDataCommand
|
||||||
func StreamCpuDataCommand(w *wshutil.WshRpc, data wshrpc.CpuDataRequest, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[wshrpc.TimeSeriesData] {
|
func StreamCpuDataCommand(w *wshutil.WshRpc, data wshrpc.CpuDataRequest, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[wshrpc.TimeSeriesData] {
|
||||||
return sendRpcRequestResponseStreamHelper[wshrpc.TimeSeriesData](w, "streamcpudata", data, opts)
|
return sendRpcRequestResponseStreamHelper[wshrpc.TimeSeriesData](w, "streamcpudata", data, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "streamtest", wshserver.StreamTestCommand
|
// command "streamtest", wshserver.StreamTestCommand
|
||||||
func StreamTestCommand(w *wshutil.WshRpc, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[int] {
|
func StreamTestCommand(w *wshutil.WshRpc, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[int] {
|
||||||
return sendRpcRequestResponseStreamHelper[int](w, "streamtest", nil, opts)
|
return sendRpcRequestResponseStreamHelper[int](w, "streamtest", nil, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "streamwaveai", wshserver.StreamWaveAiCommand
|
// command "streamwaveai", wshserver.StreamWaveAiCommand
|
||||||
func StreamWaveAiCommand(w *wshutil.WshRpc, data wshrpc.OpenAiStreamRequest, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType] {
|
func StreamWaveAiCommand(w *wshutil.WshRpc, data wshrpc.OpenAiStreamRequest, opts *wshrpc.RpcOpts) chan wshrpc.RespOrErrorUnion[wshrpc.OpenAIPacketType] {
|
||||||
return sendRpcRequestResponseStreamHelper[wshrpc.OpenAIPacketType](w, "streamwaveai", data, opts)
|
return sendRpcRequestResponseStreamHelper[wshrpc.OpenAIPacketType](w, "streamwaveai", data, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// command "test", wshserver.TestCommand
|
// command "test", wshserver.TestCommand
|
||||||
func TestCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
func TestCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "test", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "test", data, opts)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ func UpdateObjectMeta(ctx context.Context, oref waveobj.ORef, meta waveobj.MetaM
|
|||||||
if objMeta == nil {
|
if objMeta == nil {
|
||||||
objMeta = make(map[string]any)
|
objMeta = make(map[string]any)
|
||||||
}
|
}
|
||||||
newMeta := waveobj.MergeMeta(objMeta, meta)
|
newMeta := waveobj.MergeMeta(objMeta, meta, false)
|
||||||
waveobj.SetMeta(obj, newMeta)
|
waveobj.SetMeta(obj, newMeta)
|
||||||
DBUpdate(tx.Context(), obj)
|
DBUpdate(tx.Context(), obj)
|
||||||
return nil
|
return nil
|
||||||
|
Loading…
Reference in New Issue
Block a user