diff --git a/src/windy/platforms/emscripten/emdefs.nim b/src/windy/platforms/emscripten/emdefs.nim index 0fa2987..f2e0b1e 100644 --- a/src/windy/platforms/emscripten/emdefs.nim +++ b/src/windy/platforms/emscripten/emdefs.nim @@ -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.} @@ -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 diff --git a/src/windy/platforms/emscripten/platform.nim b/src/windy/platforms/emscripten/platform.nim index 62b9d2f..51d877e 100644 --- a/src/windy/platforms/emscripten/platform.nim +++ b/src/windy/platforms/emscripten/platform.nim @@ -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 "" + 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) diff --git a/src/windy/platforms/linux/x11.nim b/src/windy/platforms/linux/x11.nim index 56c812b..a7e19a1 100644 --- a/src/windy/platforms/linux/x11.nim +++ b/src/windy/platforms/linux/x11.nim @@ -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] @@ -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/. + 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) diff --git a/src/windy/platforms/macos/platform.nim b/src/windy/platforms/macos/platform.nim index 6081c3c..1b1557e 100644 --- a/src/windy/platforms/macos/platform.nim +++ b/src/windy/platforms/macos/platform.nim @@ -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 @@ -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/. + 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"): diff --git a/src/windy/platforms/win32/platform.nim b/src/windy/platforms/win32/platform.nim index 37582c2..16029b3 100644 --- a/src/windy/platforms/win32/platform.nim +++ b/src/windy/platforms/win32/platform.nim @@ -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 @@ -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%\. + 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"):