Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 36 additions & 25 deletions docs/docs/config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -95,34 +95,34 @@ wsh editconfig
| window:dimensions | string | set the default dimensions for new windows using the format "WIDTHxHEIGHT" (e.g. "1920x1080"). when a new window is created, these dimensions will be automatically applied. The width and height values should be specified in pixels. |
| telemetry:enabled | bool | set to enable/disable telemetry |

For reference, this is the current default configuration (v0.10.4):
For reference, this is the current default configuration (v0.11.5):

```json
{
"ai:preset": "ai@global",
"ai:model": "gpt-4o-mini",
"ai:maxtokens": 2048,
"ai:timeoutms": 60000,
"app:defaultnewblock": "term",
"autoupdate:enabled": true,
"autoupdate:installonquit": true,
"autoupdate:intervalms": 3600000,
"conn:askbeforewshinstall": true,
"conn:wshenabled": true,
"editor:minimapenabled": true,
"web:defaulturl": "https://github.com/wavetermdev/waveterm",
"web:defaultsearch": "https://www.google.com/search?q={query}",
"window:tilegapsize": 3,
"window:maxtabcachesize": 10,
"window:nativetitlebar": true,
"window:magnifiedblockopacity": 0.6,
"window:magnifiedblocksize": 0.9,
"window:magnifiedblockblurprimarypx": 10,
"window:magnifiedblockblursecondarypx": 2,
"window:confirmclose": true,
"window:savelastwindow": true,
"telemetry:enabled": true,
"term:copyonselect": true
"ai:preset": "ai@global",
"ai:model": "gpt-4o-mini",
"ai:maxtokens": 2048,
"ai:timeoutms": 60000,
"app:defaultnewblock": "term",
"autoupdate:enabled": true,
"autoupdate:installonquit": true,
"autoupdate:intervalms": 3600000,
"conn:askbeforewshinstall": true,
"conn:wshenabled": true,
"editor:minimapenabled": true,
"web:defaulturl": "https://github.com/wavetermdev/waveterm",
"web:defaultsearch": "https://www.google.com/search?q={query}",
"window:tilegapsize": 3,
"window:maxtabcachesize": 10,
"window:nativetitlebar": true,
"window:magnifiedblockopacity": 0.6,
"window:magnifiedblocksize": 0.9,
"window:magnifiedblockblurprimarypx": 10,
"window:magnifiedblockblursecondarypx": 2,
"window:confirmclose": true,
"window:savelastwindow": true,
"telemetry:enabled": true,
"term:copyonselect": true
}
```

Expand All @@ -134,6 +134,17 @@ files as well: `termthemes.json`, `presets.json`, and `widgets.json`.

:::

## Environment Variable Resolution

To avoid putting secrets directly in config files, Wave supports environment variable resolution using `$ENV:VARIABLE_NAME` or `$ENV:VARIABLE_NAME:fallback` syntax. This works for any string value in any config file (settings.json, presets.json, ai.json, etc.).

```json
{
"ai:apitoken": "$ENV:OPENAI_APIKEY",
"ai:baseurl": "$ENV:AI_BASEURL:https://api.openai.com/v1"
}
```

## WebBookmarks Configuration

WebBookmarks allows you to store and manage web links with customizable display preferences. The bookmarks are stored in a JSON file (`bookmarks.json`) as a key-value map where the key (`id`) is an arbitrary identifier for the bookmark. By convention, you should start your ids with "bookmark@". In the web widget, you can pull up your bookmarks using <Kbd k="Cmd:o"/>
Expand Down
65 changes: 65 additions & 0 deletions pkg/wconfig/settingsconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,65 @@ func isTrailingCommaError(barr []byte, offset int) bool {
return false
}

func resolveEnvReplacements(m waveobj.MetaMapType) {
if m == nil {
return
}

for key, value := range m {
switch v := value.(type) {
case string:
if resolved, ok := resolveEnvValue(v); ok {
m[key] = resolved
}
case map[string]interface{}:
resolveEnvReplacements(waveobj.MetaMapType(v))
case []interface{}:
resolveEnvArray(v)
}
}
}

func resolveEnvArray(arr []interface{}) {
for i, value := range arr {
switch v := value.(type) {
case string:
if resolved, ok := resolveEnvValue(v); ok {
arr[i] = resolved
}
case map[string]interface{}:
resolveEnvReplacements(waveobj.MetaMapType(v))
case []interface{}:
resolveEnvArray(v)
}
}
}

func resolveEnvValue(value string) (string, bool) {
if !strings.HasPrefix(value, "$ENV:") {
return "", false
}

envSpec := value[5:] // Remove "$ENV:" prefix
parts := strings.SplitN(envSpec, ":", 2)
envVar := parts[0]
var fallback string
if len(parts) > 1 {
fallback = parts[1]
}

// Get the environment variable value
if envValue, exists := os.LookupEnv(envVar); exists {
return envValue, true
}

// Return fallback if provided, otherwise return empty string
if fallback != "" {
return fallback, true
}
return "", true
}

func readConfigHelper(fileName string, barr []byte, readErr error) (waveobj.MetaMapType, []ConfigError) {
var cerrs []ConfigError
if readErr != nil && !os.IsNotExist(readErr) {
Expand All @@ -353,6 +412,12 @@ func readConfigHelper(fileName string, barr []byte, readErr error) (waveobj.Meta
}
cerrs = append(cerrs, ConfigError{File: fileName, Err: err.Error()})
}

// Resolve environment variable replacements
if rtn != nil {
resolveEnvReplacements(rtn)
}

return rtn, cerrs
}

Expand Down
Loading