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
26 changes: 26 additions & 0 deletions src/windy/platforms/emscripten/emdefs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,29 @@ EM_JS(void, set_cursor, (const char* cursor), {
const cursorUtf8 = UTF8ToString(cursor);
Module.canvas.style.cursor = cursorUtf8;
});

EM_JS(int, get_local_storage_length, (const char* key), {
const keyUtf8 = UTF8ToString(key);
const value = localStorage.getItem(keyUtf8);
if (value === null) return 1; // Only null terminator if not found
return lengthBytesUTF8(value) + 1; // Include null terminator
});

EM_JS(int, get_local_storage_into, (char* output, int maxLen, const char* key), {
const keyUtf8 = UTF8ToString(key);
const value = localStorage.getItem(keyUtf8);
if (value === null) {
if (maxLen > 0) output[0] = 0; // Null terminator only
return 1;
}
return stringToUTF8(value, output, maxLen);
});

EM_JS(void, set_local_storage, (const char* key, const char* value), {
const keyUtf8 = UTF8ToString(key);
const valueUtf8 = UTF8ToString(value);
localStorage.setItem(keyUtf8, valueUtf8);
});
""".}

proc get_window_width*(): cint {.importc.}
Expand All @@ -175,6 +198,9 @@ proc open_temp_text_file*(title, text: cstring) {.importc.}
proc open_url*(url: cstring) {.importc.}
proc setup_drag_drop_handlers_internal*(target: cstring, userData: pointer) {.importc.}
proc set_cursor*(cursor: cstring) {.importc.}
proc getLocalStorageLength*(key: cstring): cint {.importc: "get_local_storage_length".}
proc getLocalStorageInto*(output: cstring, maxLen: cint, key: cstring): cint {.importc: "get_local_storage_into".}
proc setLocalStorage*(key: cstring, value: cstring) {.importc: "set_local_storage".}

type
EMSCRIPTEN_RESULT* = cint
Expand Down
19 changes: 19 additions & 0 deletions src/windy/platforms/emscripten/platform.nim
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,25 @@ proc `onDownloadProgress=`*(handle: HttpRequestHandle, callback: HttpProgressCal
if state == nil: return
state.onDownloadProgress = callback

proc getConfigHome*(appName: string): string =
raise newException(Exception, "getConfigHome is not supported on emscripten")

proc getConfig*(appName: string, fileName: string): string =
## Returns the contents of a config file for the given app and filename from localStorage.
## Returns empty string if the config doesn't exist.
let key = appName & ":" & fileName
let length = getLocalStorageLength(key.cstring)
if length <= 1: # Only null terminator means no content
return ""
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if return "" is the best default behavior?

I don't really want to raise an error if there is no config.
this might be fine? or maybe we want to add a defaultConfig param?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its fine.

var buffer = newString(length - 1) # -1 for null terminator
discard getLocalStorageInto(buffer.cstring, length.cint, key.cstring)
result = buffer

proc setConfig*(appName: string, fileName: string, content: string) =
## Saves content to a config file for the given app and filename in localStorage.
let key = appName & ":" & fileName
setLocalStorage(key.cstring, content.cstring)

proc openTempTextFile*(title, text: string) =
## Open a new tab in the browser.
open_temp_text_file(title.cstring, text.cstring)
Expand Down
30 changes: 29 additions & 1 deletion src/windy/platforms/linux/x11.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import
std/[os, sequtils, sets, strformat, strutils, times, unicode, uri],
std/[os, sequtils, sets, strformat, strutils, times, unicode, uri, pathnorm],
../../[common, internal],
vmath, pixie,
x11/[glx, keysym, x, xevent, xlib, xcursor]
Expand Down Expand Up @@ -1327,6 +1327,34 @@ proc url*(window: Window): string =
## Url cannot be gotten on linux.
warn "Url cannot be gotten on linux"

proc getConfigHome*(appName: string): string =
## Returns the platform-appropriate user config directory for the given app name.
## For Linux: Honors XDG_CONFIG_HOME, defaults to ~/.config/<appName>.
let xdgConfigHome = getEnv("XDG_CONFIG_HOME")
if xdgConfigHome != "":
result = (xdgConfigHome / appName).normalizePath
else:
result = (getHomeDir() / ".config" / appName).normalizePath

proc getConfig*(appName: string, fileName: string): string =
## Returns the contents of a config file for the given app and filename.
## Returns empty string if the file doesn't exist.
let configDir = getConfigHome(appName)
let configPath = configDir / fileName
if fileExists(configPath):
result = readFile(configPath)
else:
result = ""

proc setConfig*(appName: string, fileName: string, content: string) =
## Saves content to a config file for the given app and filename.
## Creates the config directory if it doesn't exist.
let configDir = getConfigHome(appName)
if not dirExists(configDir):
createDir(configDir)
let configPath = configDir / fileName
writeFile(configPath, content)

proc openUrl*(url: string) =
## Open a URL in the default browser.
discard execShellCmd("xdg-open " & url)
Expand Down
26 changes: 25 additions & 1 deletion src/windy/platforms/macos/platform.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import
std/[os, times, unicode],
std/[os, times, unicode, pathnorm],
opengl, pixie/fileformats/png, pixie/images, utils, vmath,
../../[common, internal], macdefs

Expand Down Expand Up @@ -1094,6 +1094,30 @@ proc getScreens*(): seq[Screen] =
primary: i == 0
)

proc getConfigHome*(appName: string): string =
## Returns the platform-appropriate user config directory for the given app name.
## For macOS: Returns ~/Library/Application Support/<appName>.
result = (getHomeDir() / "Library" / "Application Support" / appName).normalizePath

proc getConfig*(appName: string, fileName: string): string =
## Returns the contents of a config file for the given app and filename.
## Returns empty string if the file doesn't exist.
let configDir = getConfigHome(appName)
let configPath = configDir / fileName
if fileExists(configPath):
result = readFile(configPath)
else:
result = ""

proc setConfig*(appName: string, fileName: string, content: string) =
## Saves content to a config file for the given app and filename.
## Creates the config directory if it doesn't exist.
let configDir = getConfigHome(appName)
if not dirExists(configDir):
createDir(configDir)
let configPath = configDir / fileName
writeFile(configPath, content)

proc openTempTextFile*(title, text: string) =
## Open a text file in the default text editor.
if not dirExists("tmp"):
Expand Down
26 changes: 25 additions & 1 deletion src/windy/platforms/win32/platform.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import
std/[os, times, unicode, strutils, tables],
std/[os, times, unicode, strutils, tables, pathnorm],
../../[common, internal], flatty/binny, pixie/fileformats/png,
pixie/fileformats/bmp, pixie/images,
urlly, utils, vmath, windefs, zippy
Expand Down Expand Up @@ -2492,6 +2492,30 @@ proc forceButtonReleased*(window: Window, button: Button) =
## This is used for simulating UI tests.
window.handleButtonRelease(button)

proc getConfigHome*(appName: string): string =
## Returns the platform-appropriate user config directory for the given app name.
## For Windows: Returns %APPDATA%\<appName>.
result = (getEnv("APPDATA") / appName).normalizePath

proc getConfig*(appName: string, fileName: string): string =
## Returns the contents of a config file for the given app and filename.
## Returns empty string if the file doesn't exist.
let configDir = getConfigHome(appName)
let configPath = configDir / fileName
if fileExists(configPath):
result = readFile(configPath)
else:
result = ""

proc setConfig*(appName: string, fileName: string, content: string) =
## Saves content to a config file for the given app and filename.
## Creates the config directory if it doesn't exist.
let configDir = getConfigHome(appName)
if not dirExists(configDir):
createDir(configDir)
let configPath = configDir / fileName
writeFile(configPath, content)

proc openTempTextFile*(title, text: string) =
## Open a text file in the default text editor.
if not dirExists("tmp"):
Expand Down