Logseq should respect %USERPROFILE% when saving config files

Currently, even if you set %USERPROFILE% to a different path (e.g. G:) , Logseq still uses the default value (in C:) to store json and edn files

It’s a little bit all over the place. Some settings are also stored in %APPDATA%/Logseq, some in the user profile’s .logseq subdirectory. I hope that it doesn’t construct the former path as C:\Users\${user_name}\AppData\Roaming, as Microsoft has warned again and again and again to never do, and rather call the system API SHGetKnownFolderPath.

I know that logseq is written in some dialect of Common Lisp, but it should be able to interface to C code somehow.

  • Win32 uses stdcall calling conventions.
  • NULL is a pointer-sized integer 0
  • SHGetKnownFolderPath() returns a 32-bit integer error code.
  • SUCCEEDED(x) expands to true-ish if the MSB of x is not set.
  • FOLDERID_... are const, 16-byte long opaque structures in rodata memory (GUIDs, in fact).

That’s all you guys need to know.

// Save as main.c, compile, link and run in VS dev environment command prompt:
// C:\...> cl /nologo main.c shell32.lib ole32.lib
// C:\...> .\main
// USERPROFILE='C:\Users\kkm'
// C:\...>

#include <shlobj.h>
#include <stdio.h>  // Only for the sample printf().
// Use one of:
//   FOLDERID_Profile        — The source of ground truth for %USERPROFILE%
//   FOLDERID_LocalAppData   — The same for %LOCALAPPDATA%
//   FOLDERID_RoamingAppData — The same for %APPDATA%
//
int main() {
  wchar_t *path_ptr = NULL;  // Allocated by SHGetKnownFolderPath.
  int ok = SUCCEEDED(SHGetKnownFolderPath(/* e.g., */&FOLDERID_Profile, 0, NULL, &path_ptr));
  if (ok) {
    printf("USERPROFILE='%S'", path_ptr);
    CoTaskMemFree(path_ptr);
  } else {
    // Something has gone horribly wrong, everyone seek shelter!!!
  }
  return 0;
}