diff --git a/.gitignore b/.gitignore index 1a4595e..d1bc5ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ /target *.log +result +result-* +.direnv diff --git a/README.md b/README.md index 8a8c86b..2f936cd 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,30 @@ paru -S rmcl-bin paru -S rmcl-git ``` +### Nix + +```sh +nix run github:objz/rmcl +nix profile install github:objz/rmcl +``` + +a home manager module is also available. add the flake as an input and enable it: + +```nix +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + rmcl.url = "github:objz/rmcl"; + }; + + outputs = { rmcl, ... }: { + homeManagerModules.default = rmcl.homeManagerModules.default; + }; +} +``` + +see `flake.nix` for available options (`programs.rmcl.*`). + ### Cargo ```sh @@ -102,6 +126,7 @@ package managers: [![Homebrew tap](https://img.shields.io/badge/homebrew-objz%2Ftap-FBB040?style=for-the-badge&logo=homebrew)](https://github.com/objz/homebrew-tap) [![WinGet](https://img.shields.io/badge/winget-Objz.Rmcl-0078D4?style=for-the-badge&logo=windows11)](https://winstall.app/apps/Objz.Rmcl) [![Chocolatey](https://img.shields.io/chocolatey/v/rmcl?style=for-the-badge&logo=chocolatey)](https://community.chocolatey.org/packages/rmcl) +[![Nix](https://img.shields.io/badge/nix-5277C4?style=for-the-badge&logo=nixos)](https://github.com/objz/rmcl) aur: diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..f6166f0 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1781359544, + "narHash": "sha256-iUuzKQcyXvopYDDzFpMK5eQKP3WIJExYny2kJtbgUcE=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "9f11f828c213641c2369a9f1fa31fe31557e3156", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..0395ad6 --- /dev/null +++ b/flake.nix @@ -0,0 +1,240 @@ +{ + description = "rmcl: A fully featured Minecraft TUI launcher"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { + self, + nixpkgs, + flake-utils, + ... + }: + flake-utils.lib.eachDefaultSystem (system: let + pkgs = nixpkgs.legacyPackages.${system}; + in { + packages.default = pkgs.rustPlatform.buildRustPackage { + pname = "rmcl"; + version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.version; + src = pkgs.lib.cleanSource ./.; + cargoLock.lockFile = ./Cargo.lock; + nativeBuildInputs = [pkgs.jdk]; + + doCheck = false; + + meta = with pkgs.lib; { + description = "A fully featured Minecraft TUI launcher"; + homepage = "https://github.com/objz/rmcl"; + license = licenses.gpl3Only; + mainProgram = "rmcl"; + }; + }; + }) + // { + homeManagerModules.default = { + config, + lib, + pkgs, + ... + }: + with lib; let + cfg = config.programs.rmcl; + tomlFormat = pkgs.formats.toml {}; + filterNulls = filterAttrs (_: v: v != null); + nullStr = types.nullOr types.str; + nullUint = types.nullOr types.ints.unsigned; + pathsCfg = { + instances_dir = cfg.instancesDir; + meta_dir = cfg.metaDir; + java_path = cfg.javaPath; + }; + defaultsCfg = { + memory_min = cfg.memoryMin; + memory_max = cfg.memoryMax; + }; + uiCfg = { + error_auto_dismiss_ms = cfg.errorAutoDismissMs; + error_slide_start_ms = cfg.errorSlideStartMs; + error_fly_out_ms = cfg.errorFlyOutMs; + max_error_events = cfg.maxErrorEvents; + }; + in { + options.programs.rmcl = { + enable = mkEnableOption "rmcl: A fully featured Minecraft TUI launcher"; + + package = mkOption { + type = types.package; + default = self.packages.${pkgs.stdenv.hostPlatform.system}.default; + defaultText = literalExpression "self.packages.\${pkgs.stdenv.hostPlatform.system}.default"; + description = "The rmcl package to use."; + }; + + # -- config.toml: paths -- + instancesDir = mkOption { + type = nullStr; + default = null; + example = "~/games/minecraft/instances"; + description = '' + Where Minecraft instances are stored. + Default: ~/.local/share/rmcl/instances. + ''; + }; + + metaDir = mkOption { + type = nullStr; + default = null; + example = "~/games/minecraft/meta"; + description = '' + Metadata and cache directory. + Default: ~/.local/share/rmcl/meta. + ''; + }; + + javaPath = mkOption { + type = nullStr; + default = null; + example = "${pkgs.jdk}/bin/java"; + description = '' + Path to Java executable for launching Minecraft. + Default: falls back to JAVA_HOME. + ''; + }; + + # -- config.toml: defaults -- + memoryMin = mkOption { + type = nullStr; + default = null; + example = "512M"; + description = '' + Minimum Java heap size (Xms) for Minecraft instances. + Default: "512M". + ''; + }; + + memoryMax = mkOption { + type = nullStr; + default = null; + example = "4G"; + description = '' + Maximum Java heap size (Xmx) for Minecraft instances. + Default: "2G". + ''; + }; + + # -- config.toml: ui -- + errorAutoDismissMs = mkOption { + type = nullUint; + default = null; + example = 5000; + description = '' + How long (ms) an error toast stays visible before auto-dismissing. + Default: 5000. + ''; + }; + + errorSlideStartMs = mkOption { + type = nullUint; + default = null; + example = 3500; + description = '' + When (ms) the error toast begins sliding off screen. + Default: 3500. + ''; + }; + + errorFlyOutMs = mkOption { + type = nullUint; + default = null; + example = 300; + description = '' + Duration (ms) of the error toast fly-out animation. + Default: 300. + ''; + }; + + maxErrorEvents = mkOption { + type = nullUint; + default = null; + example = 50; + description = '' + Maximum number of error events retained in the log buffer. + Default: 50. + ''; + }; + + # -- theme.toml -- + theme = mkOption { + type = types.str; + default = "catppuccin"; + example = "dracula"; + description = '' + Base theme name (one of: catppuccin, dracula, nord, gruvbox, + one-dark, solarized, tailwind, tokyo-night, rose-pine, terminal) + or an absolute path to a custom theme file. + ''; + }; + + borderStyle = mkOption { + type = types.enum ["rounded" "plain" "double" "thick"]; + default = "rounded"; + description = "Widget border style."; + }; + + customTheme = mkOption { + type = types.attrs; + default = {}; + example = literalExpression '' + { + accent = "Red"; + text = "White"; + surface = { Rgb = [36 36 36]; }; + background = { Rgb = [30 30 30]; }; + } + ''; + description = '' + Color overrides applied on top of the base theme. + Each key is a color slot (accent, accent_dim, text, text_dim, + text_bright, success, error, warning, info, diff_added, + diff_removed, diff_context, border, surface, background). + Values are either a named color string ("Red", "White", etc.) + or an RGB inline table ({ Rgb = [R G B]; }). + ''; + }; + + # -- extra config.toml fields -- + extraConfig = mkOption { + type = tomlFormat.type; + default = {}; + example = literalExpression '' + { + general.debug = true; + } + ''; + description = '' + Additional config.toml settings merged into the generated file. + ''; + }; + }; + + config = mkIf cfg.enable { + home.packages = [cfg.package]; + + xdg.configFile."rmcl/config.toml".source = tomlFormat.generate "rmcl-config.toml" (recursiveUpdate { + paths = filterNulls pathsCfg; + defaults = filterNulls defaultsCfg; + ui = filterNulls uiCfg; + } cfg.extraConfig); + + xdg.configFile."rmcl/theme.toml".source = tomlFormat.generate "rmcl-theme.toml" ({ + inherit (cfg) theme; + border_style = cfg.borderStyle; + } + // optionalAttrs (cfg.customTheme != {}) { + custom = cfg.customTheme; + }); + }; + }; + }; +}