diff --git a/hm-modules/bar/noctalia/default.nix b/hm-modules/bar/noctalia/default.nix index 3dd3019..b896672 100644 --- a/hm-modules/bar/noctalia/default.nix +++ b/hm-modules/bar/noctalia/default.nix @@ -107,7 +107,7 @@ in widget = { clock = { - format = "{:%H:%M}"; + format = "{:%a %d %b, %H:%M}"; tooltip_format = "{:%A, %B %d, %Y}"; }; @@ -121,7 +121,7 @@ in ram = { type = "sysmon"; - stat = "memory_usage"; + stat = "ram_pct"; }; # Microphone — named volume widget with input device diff --git a/machines/fujin/main/default.nix b/machines/fujin/main/default.nix index 5b8348c..6e8cbe7 100644 --- a/machines/fujin/main/default.nix +++ b/machines/fujin/main/default.nix @@ -112,6 +112,11 @@ dov = { development.emacs.enable = true; + development.qoder = { + enable = true; + version = "1.19.2"; + hash = "sha256-/P3UStsRHKKWC1xET9SL23E0CUPxQ5DkmWFco+dH37A="; # nix store prefetch-file --json https://download.qoder.com/release/latest/qoder_amd64.deb | jq -r .hash + }; virtualisation.docker.enable = true; virtualisation.incus.enable = true; diff --git a/machines/fujin/main/dotfiles/.config/doom/config.el b/machines/fujin/main/dotfiles/.config/doom/config.el index c630e4f..3a39b55 100644 --- a/machines/fujin/main/dotfiles/.config/doom/config.el +++ b/machines/fujin/main/dotfiles/.config/doom/config.el @@ -42,6 +42,12 @@ ;; change `org-directory'. It must be set before org loads! (setq org-directory "~/org/") +;; Use bash, not nu, for non-interactive subprocesses (compile, shell-command, +;; lsp-mode installers). Nu doesn't unescape Emacs's POSIX-style backslash +;; escaping, which corrupts args like -Djdt.download.url=...?...=... . +;; vterm keeps using nu (see vterm-shell below). +(setq shell-file-name "/run/current-system/sw/bin/bash") + ;; Whenever you reconfigure a package, make sure to wrap your config in an ;; `after!' block, otherwise Doom's defaults may override your settings. E.g. diff --git a/modules/development/default.nix b/modules/development/default.nix index be8ed05..7dd9cbd 100644 --- a/modules/development/default.nix +++ b/modules/development/default.nix @@ -4,5 +4,7 @@ imports = [ ./nix-vscode-server ./emacs + ./qoder + ./android ]; } diff --git a/modules/development/qoder/default.nix b/modules/development/qoder/default.nix new file mode 100644 index 0000000..07939e1 --- /dev/null +++ b/modules/development/qoder/default.nix @@ -0,0 +1,92 @@ +{ + config, + lib, + pkgs, + ... +}: + +with lib; + +let + cfg = config.dov.development.qoder; + qoder = pkgs.callPackage ./package.nix { + inherit (cfg) + version + url + hash + extraFlags + ; + }; +in +{ + options.dov.development.qoder = { + enable = mkEnableOption "Qoder IDE (unfree, repackaged from the upstream .deb)"; + + version = mkOption { + type = types.str; + default = "1.19.2"; + description = '' + Label only — upstream publishes a rolling "latest" URL, so this is + just what the store path is called. Bump it together with `hash`. + ''; + }; + + url = mkOption { + type = types.str; + default = "https://download.qoder.com/release/latest/qoder_amd64.deb"; + description = "Upstream .deb to repackage."; + }; + + hash = mkOption { + type = types.str; + default = ""; + example = "sha256-0000000000000000000000000000000000000000000="; + description = '' + SRI hash of the .deb. Refresh whenever upstream ships a new build: + nix store prefetch-file --json | jq -r .hash + ''; + }; + + extraFlags = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "--disable-gpu-sandbox" ]; + description = "Extra Electron/Chromium flags appended to the wrapper."; + }; + + keyring = mkOption { + type = types.bool; + default = true; + description = '' + Enable gnome-keyring. Qoder is wrapped with + --password-store=gnome-libsecret; without a running secret service + the sign-in token is lost on every restart. + ''; + }; + }; + + config = mkIf cfg.enable (mkMerge [ + { + assertions = [ + { + assertion = cfg.hash != ""; + message = '' + dov.development.qoder.hash is empty. Prefetch the .deb first: + nix store prefetch-file --json ${cfg.url} | jq -r .hash + ''; + } + ]; + + environment.systemPackages = [ qoder ]; + } + + (mkIf cfg.keyring { + services.gnome.gnome-keyring.enable = true; + + # gnome-keyring enables gcr-ssh-agent by default, which asserts against + # programs.ssh.startAgent from dov.yubikey. We only want the secret + # service here — SSH keys stay with the OpenSSH agent. + services.gnome.gcr-ssh-agent.enable = false; + }) + ]); +} diff --git a/modules/development/qoder/package.nix b/modules/development/qoder/package.nix new file mode 100644 index 0000000..7d59e2d --- /dev/null +++ b/modules/development/qoder/package.nix @@ -0,0 +1,204 @@ +{ + lib, + stdenv, + fetchurl, + autoPatchelfHook, + makeWrapper, + wrapGAppsHook3, + zstd, + + alsa-lib, + at-spi2-atk, + at-spi2-core, + atk, + cairo, + cups, + dbus, + expat, + fontconfig, + freetype, + gdk-pixbuf, + glib, + gtk3, + krb5, + libdrm, + libgbm, + libglvnd, + libnotify, + libsecret, + libuuid, + libxkbcommon, + nspr, + nss, + pango, + systemd, + zlib, + + libx11, + libxcb, + libxcomposite, + libxcursor, + libxdamage, + libxext, + libxfixes, + libxi, + libxkbfile, + libxrandr, + libxrender, + libxscrnsaver, + libxshmfence, + libxtst, + + version, + url, + hash, + passwordStore ? "gnome-libsecret", + extraFlags ? [ ], +}: + +let + runtimeLibs = [ + alsa-lib + at-spi2-atk + at-spi2-core + atk + cairo + cups + dbus + expat + fontconfig + freetype + gdk-pixbuf + glib + gtk3 + krb5 + libdrm + libgbm + libglvnd + libnotify + libsecret + libuuid + libxkbcommon + nspr + nss + pango + zlib + (lib.getLib systemd) + + libx11 + libxcb + libxcomposite + libxcursor + libxdamage + libxext + libxfixes + libxi + libxkbfile + libxrandr + libxrender + libxscrnsaver + libxshmfence + libxtst + ]; +in +stdenv.mkDerivation (finalAttrs: { + pname = "qoder"; + inherit version; + + src = fetchurl { + inherit url hash; + name = "qoder-${version}_amd64.deb"; + }; + + nativeBuildInputs = [ + autoPatchelfHook + makeWrapper + wrapGAppsHook3 + zstd + ]; + + buildInputs = runtimeLibs; + + # dlopen'ed at runtime, so autoPatchelf can't see them in the ELF headers + runtimeDependencies = [ + (lib.getLib systemd) + libglvnd + libgbm + ]; + + dontConfigure = true; + dontBuild = true; + dontWrapGApps = true; # wrapped by hand in preFixup + + # `ar` comes from stdenv. --no-same-permissions keeps the setuid bit on + # chrome-sandbox from blowing up the build inside the nix sandbox. + unpackPhase = '' + runHook preUnpack + ar x $src + tar -xf data.tar.* --no-same-permissions --no-same-owner + runHook postUnpack + ''; + + installPhase = '' + runHook preInstall + mkdir -p $out/share/qoder $out/bin + + if [ -d usr/share/qoder ]; then + cp -r usr/share/qoder/. $out/share/qoder/ + elif [ -d opt/Qoder ]; then + cp -r opt/Qoder/. $out/share/qoder/ + elif [ -d opt/qoder ]; then + cp -r opt/qoder/. $out/share/qoder/ + else + echo "unexpected .deb layout:" >&2 + find . -maxdepth 3 -type d >&2 + exit 1 + fi + + for d in applications icons pixmaps; do + if [ -d "usr/share/$d" ]; then + mkdir -p "$out/share/$d" + cp -r "usr/share/$d/." "$out/share/$d/" + fi + done + + # Store paths can never be setuid — drop the helper, use --no-sandbox. + rm -f $out/share/qoder/chrome-sandbox + + if [ ! -x $out/share/qoder/qoder ]; then + echo "main binary not where expected:" >&2 + ls $out/share/qoder >&2 + exit 1 + fi + + for f in $out/share/applications/*.desktop; do + [ -e "$f" ] || continue + substituteInPlace "$f" \ + --replace-quiet "/usr/share/qoder/qoder" "$out/bin/qoder" \ + --replace-quiet "/opt/Qoder/qoder" "$out/bin/qoder" \ + --replace-quiet "/opt/qoder/qoder" "$out/bin/qoder" + done + + runHook postInstall + ''; + + # preFixup, not installPhase: gappsWrapperArgs is only populated by then. + preFixup = '' + makeWrapper $out/share/qoder/qoder $out/bin/qoder \ + "''${gappsWrapperArgs[@]}" \ + --prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath runtimeLibs}" \ + --set-default NIXOS_OZONE_WL 1 \ + --add-flags "--no-sandbox" \ + --add-flags "--password-store=${passwordStore}" \ + ${lib.optionalString (extraFlags != [ ]) ''--add-flags "${lib.escapeShellArgs extraFlags}"''} + ''; + + meta = { + description = "Qoder — agentic coding IDE, repackaged from the upstream .deb"; + homepage = "https://qoder.com"; + license = lib.licenses.unfree; + sourceProvenance = [ lib.sourceTypes.binaryNativeCode ]; + platforms = [ "x86_64-linux" ]; + mainProgram = "qoder"; + }; +})