From 4a2f852f30d3e99a557cc5f3c00a1a05f923d4e4 Mon Sep 17 00:00:00 2001 From: quirinecker Date: Thu, 23 Oct 2025 20:14:05 +0200 Subject: [PATCH] updated flake. nix package now includes completions --- .gitignore | 1 + Cargo.toml | 7 -- build.rs | 23 ------- flake.lock | 77 +++++++++++++++++++++- flake.nix | 109 +++++++++++++++++++++----------- src/app/args/structure.rs | 20 ++++-- src/app/build/asciidoctor.rs | 57 ----------------- src/app/build/mod.rs | 8 +-- src/app/commands/completions.rs | 27 ++++---- src/app/mod.rs | 2 +- src/test/build/asciidoctor.rs | 37 ----------- 11 files changed, 177 insertions(+), 191 deletions(-) delete mode 100644 build.rs diff --git a/.gitignore b/.gitignore index 5426bf4..175f86c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ dist /docs res/test/docs/slides/revealjs res/test/result +result diff --git a/Cargo.toml b/Cargo.toml index c00552d..992d91e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,3 @@ -# Cargo.toml -build = "build.rs" - [package] name = "docki" version = "1.1.0" @@ -24,8 +21,4 @@ reqwest = { version = "0.11.14", features = ["blocking"] } text_io = "0.1.12" tokio = { version = "1.26.0", features = ["full"] } zip-extract = "0.1.1" - -[build-dependencies] -clap = { version = "4.1.8", features = ["derive"] } clap_complete = "4.1.4" - diff --git a/build.rs b/build.rs deleted file mode 100644 index c65eccf..0000000 --- a/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::io::Error; - -use clap::CommandFactory; -use clap_complete::{generate_to, shells::{Bash, Zsh, Fish}}; - -include!("src/app/args/structure.rs"); -include!("src/app/fs_util/mod.rs"); - -fn main() -> Result<(), Error> { - generate_completions() -} - -fn generate_completions() -> Result<(), Error> { - let mut command = Args::command(); - let home_path = env::var("HOME").expect("could not get home path"); - let out_dir = format!("{}/.docki/completions/", home_path); - create_dir_recursive(&out_dir); - generate_to(Bash, &mut command, "docki", &out_dir)?; - generate_to(Zsh, &mut command, "docki", &out_dir)?; - generate_to(Fish, &mut command, "docki", &out_dir)?; - Ok(()) -} - diff --git a/flake.lock b/flake.lock index 7577d8d..66c350c 100644 --- a/flake.lock +++ b/flake.lock @@ -1,6 +1,63 @@ { "nodes": { + "fenix": { + "inputs": { + "nixpkgs": [ + "naersk", + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1752475459, + "narHash": "sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU=", + "owner": "nix-community", + "repo": "fenix", + "rev": "bf0d6f70f4c9a9cf8845f992105652173f4b617f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "naersk": { + "inputs": { + "fenix": "fenix", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1752689277, + "narHash": "sha256-uldUBFkZe/E7qbvxa3mH1ItrWZyT6w1dBKJQF/3ZSsc=", + "owner": "nix-community", + "repo": "naersk", + "rev": "0e72363d0938b0208d6c646d10649164c43f4d64", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "naersk", + "type": "github" + } + }, "nixpkgs": { + "locked": { + "lastModified": 1752077645, + "narHash": "sha256-HM791ZQtXV93xtCY+ZxG1REzhQenSQO020cu6rHtAPk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "be9e214982e20b8310878ac2baa063a961c1bdf6", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { "locked": { "lastModified": 1760934318, "narHash": "sha256-/oUYsC0lUCBory65VK+UHqCCsCspbL1Vgfcf1KUYqVw=", @@ -18,10 +75,28 @@ }, "root": { "inputs": { - "nixpkgs": "nixpkgs", + "naersk": "naersk", + "nixpkgs": "nixpkgs_2", "systems": "systems" } }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1752428706, + "narHash": "sha256-EJcdxw3aXfP8Ex1Nm3s0awyH9egQvB2Gu+QEnJn2Sfg=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "591e3b7624be97e4443ea7b5542c191311aa141d", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, "systems": { "locked": { "lastModified": 1681028828, diff --git a/flake.nix b/flake.nix index 50d2aad..370edfd 100644 --- a/flake.nix +++ b/flake.nix @@ -12,29 +12,71 @@ nixpkgs, systems, naersk, + self, ... }: let eachSystem = f: nixpkgs.lib.genAttrs (import systems) (system: f nixpkgs.legacyPackages.${system}); - build_asciidoctor_revealjs = pkgs: pkgs.buildRubyGem { - gemName = "asciidoctor-revealjs"; - version = "5.2.0"; - source = { - type = "git"; - url = "https://rubygems.org/downloads/asciidoctor-revealjs-5.2.0.gem"; - sha256 = "sha256-NQSl5+ryyR3jf5YYkxT/sea/lNrZ1kbVyaJMZpG/auI="; + build_asciidoctor_revealjs = + pkgs: + pkgs.buildRubyGem { + gemName = "asciidoctor-revealjs"; + version = "5.2.0"; + source = { + type = "git"; + url = "https://rubygems.org/downloads/asciidoctor-revealjs-5.2.0.gem"; + sha256 = "sha256-NQSl5+ryyR3jf5YYkxT/sea/lNrZ1kbVyaJMZpG/auI="; + }; }; - }; - build_asciidoctor = pkgs: pkgs.buildRubyGem { - gemName = "asciidoctor"; - version = "2.0.25"; - source = { - type = "git"; - url = "https://rubygems.org/downloads/asciidoctor-2.0.25.gem"; - sha256 = "sha256-sG/oIrCRDU4l6g9WL+z8eUjpRuIi79lJSEnSfaQmfRk="; + build_asciidoctor = + pkgs: + pkgs.buildRubyGem { + gemName = "asciidoctor"; + version = "2.0.25"; + source = { + type = "git"; + url = "https://rubygems.org/downloads/asciidoctor-2.0.25.gem"; + sha256 = "sha256-sG/oIrCRDU4l6g9WL+z8eUjpRuIi79lJSEnSfaQmfRk="; + }; }; - }; + + build_docki = + { naerskLib, pkgs }: + let + runtimeDeps = with pkgs; [ + (ruby.withPackages ( + p: with p; [ + (build_asciidoctor_revealjs pkgs) + (build_asciidoctor pkgs) + bundler + ] + )) + ]; + in + naerskLib.buildPackage { + src = ./.; + buildInputs = [ + ]; + nativeBuildInputs = with pkgs; [ + pkg-config + openssl.dev + libiconv + makeWrapper + ]; + postInstall = '' + mkdir -p $out/share/bash-completion/completions + mkdir -p $out/share/zsh/site-functions + mkdir -p $out/share/fish/vendor_completions.d + + $out/bin/docki completions bash > $out/share/bash-completion/completions/docki + $out/bin/docki completions zsh > $out/share/zsh/site-functions/_docki + $out/bin/docki completions fish > $out/share/fish/vendor_completions.d/docki.fish + + wrapProgram $out/bin/docki --prefix PATH : ${pkgs.lib.makeBinPath runtimeDeps} + ''; + }; + in { devShells = eachSystem (pkgs: { @@ -56,36 +98,27 @@ )) ]; }; + + preview = pkgs.mkShell { + name = "docki-preview"; + buildInputs = [ + pkgs.zsh + pkgs.fish + pkgs.bash + self.packages.${pkgs.system}.default + ]; + }; }); packages = eachSystem ( pkgs: let naerskLib = pkgs.callPackage naersk { }; - runtimeDeps = with pkgs; [ - (ruby.withPackages ( - p: with p; [ - (build_asciidoctor_revealjs pkgs) - (build_asciidoctor pkgs) - bundler - ] - )) - ]; in { - default = naerskLib.buildPackage { - src = ./.; - buildInputs =[ - ]; - nativeBuildInputs = with pkgs; [ - pkg-config - openssl.dev - libiconv - makeWrapper - ]; - postInstall = '' - wrapProgram $out/bin/docki --prefix PATH : ${pkgs.lib.makeBinPath runtimeDeps} - ''; + default = build_docki { + naerskLib = naerskLib; + pkgs = pkgs; }; } ); diff --git a/src/app/args/structure.rs b/src/app/args/structure.rs index 39d213b..f01201a 100644 --- a/src/app/args/structure.rs +++ b/src/app/args/structure.rs @@ -3,7 +3,14 @@ use clap::{Parser, Subcommand}; #[derive(Parser)] pub struct Args { #[command(subcommand)] - pub command: CommandArg + pub command: CommandArg, +} + +#[derive(Subcommand)] +pub enum ShellArg { + Bash, + Fish, + Zsh, } #[derive(Subcommand)] @@ -16,10 +23,13 @@ pub enum CommandArg { InstallReveal, /// Starts a Webserver with the live preview of the Documentation Serve { - /// Port for the Live Server + /// Port for the Live Server #[arg(short, long)] - port: Option + port: Option, + }, + /// Generates completions for the desired shell + Completions { + #[command(subcommand)] + shell: ShellArg, }, - /// Information about the completions - Completions } diff --git a/src/app/build/asciidoctor.rs b/src/app/build/asciidoctor.rs index 8df079a..0f15ef6 100644 --- a/src/app/build/asciidoctor.rs +++ b/src/app/build/asciidoctor.rs @@ -1,7 +1,5 @@ use std::process; -use regex::Regex; - fn exec_command(command: &mut process::Command) -> Result<(), String> { let result = command.output(); @@ -31,7 +29,6 @@ fn asciidoctor_docs(in_path: &str, out_path: &str) -> process::Command { fn asciidoctor_slides(in_path: &str, out_path: &str) -> process::Command { let mut command = process::Command::new(format!("asciidoctor-revealjs")); - let out_dir = parent_path(out_path); let revealjs_path = "/slides/revealjs"; command @@ -43,60 +40,6 @@ fn asciidoctor_slides(in_path: &str, out_path: &str) -> process::Command { return command; } -fn parent_path(child_path: &str) -> String { - let split: Vec<&str> = child_path.split("/").collect(); - let slice = &split[..split.len() - 1]; - return slice.join("/"); -} - -pub fn path_between(from: String, to: String) -> String { - let from_segments = transform_input_to_clone_split(&from); - let to_segments = transform_input_to_clone_split(&to); - let last_matching_index = matching_from_start(&from_segments, &to_segments); - let number_of_backs = from_segments.len() - last_matching_index; - let mut path_between = path_back(number_of_backs); - let path_to_to_path = &to_segments[last_matching_index..]; - path_between.push_str(&path_to_to_path.join("/")); - return path_between; -} - -fn transform_input_to_clone_split(input: &String) -> Vec { - let regex = Regex::new(r"/$").unwrap(); - let first_transformation = input.clone().replace("./", ""); - return regex - .replace_all(&first_transformation, "") - .to_string() - .split("/") - .collect::>() - .iter() - .map(|s| s.to_string()) - .collect(); -} - -fn path_back(count: usize) -> String { - let mut path = "".to_string(); - - for _ in 0..count { - path.push_str("../"); - } - - return path; -} - -pub fn matching_from_start(from_segments: &Vec, to_segments: &Vec) -> usize { - for (index, from_segment) in from_segments.iter().enumerate() { - if let Some(to_segment) = to_segments.get(index) { - if from_segment != to_segment { - return index; - } - } else { - return index; - } - } - - return from_segments.len(); -} - pub fn build_doc(in_path: &str, out_path: &str) -> Result<(), String> { let mut command = asciidoctor_docs(in_path, out_path); return exec_command(&mut command); diff --git a/src/app/build/mod.rs b/src/app/build/mod.rs index 1950547..7071c99 100644 --- a/src/app/build/mod.rs +++ b/src/app/build/mod.rs @@ -6,10 +6,6 @@ use super::fs_util; pub mod asciidoctor; -pub trait Builder { - fn build(&self, in_path: &str, out_path: &str) -> Result<(), String>; -} - pub fn docki_build(in_path: &str) -> DockiBuildResult { let out_path = in_path.replace("/docs/", "/dist/"); let convert_out_path = out_path.replace(".adoc", ".html"); @@ -35,11 +31,11 @@ pub fn docki_build(in_path: &str) -> DockiBuildResult { } } -fn copy(in_path: &str, out_path: &str) -> Result<(), String> { +fn copy(in_path: &str, out_path: &str) -> Result<(), String> { fs_util::create_parent_dir_recursive(out_path); if let Err(err) = fs::copy(in_path, out_path) { - return Err(err.to_string()) + return Err(err.to_string()); } Ok(()) diff --git a/src/app/commands/completions.rs b/src/app/commands/completions.rs index dc4330b..fd7707f 100644 --- a/src/app/commands/completions.rs +++ b/src/app/commands/completions.rs @@ -1,21 +1,16 @@ -use colored::Colorize; +use std::io; -const INFO: &str = " -You can add completions for docki with the following methods. If you want the completions to be persistent add -them to a init file e.g. ~/.zshrc, ~/.bashrc, ~/.config/fish/config.fish. +use clap::CommandFactory; +use clap_complete::{generate, shells::{Bash, Fish, Zsh}}; -Get Fish Completions -source ~/.docki/completions/docki.fish +use crate::app::args::structure::{Args, ShellArg}; -Get Zsh Completions -source ~/.docki/completions/_docki +pub fn completions(shell: ShellArg) { + let mut command = Args::command(); -Get Bash Completions -source ~/.docki/completions/docki.bash -"; - -pub fn completions() { - println!(); - println!("{}", "Completions".blue().bold()); - println!("{}", INFO.bright_black()); + match shell { + ShellArg::Bash => generate(Bash, &mut command, "docki", &mut io::stdout()), + ShellArg::Fish => generate(Fish, &mut command, "docki", &mut io::stdout()), + ShellArg::Zsh => generate(Zsh, &mut command, "docki", &mut io::stdout()), + } } diff --git a/src/app/mod.rs b/src/app/mod.rs index c2c220f..0ba9bfb 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -27,7 +27,7 @@ impl App { CommandArg::Health => health(), CommandArg::InstallReveal => install_reveal().await, CommandArg::Serve { port } => serve(port).await, - CommandArg::Completions => completions() + CommandArg::Completions { shell } => completions(shell) }; } diff --git a/src/test/build/asciidoctor.rs b/src/test/build/asciidoctor.rs index 473efe6..e69de29 100644 --- a/src/test/build/asciidoctor.rs +++ b/src/test/build/asciidoctor.rs @@ -1,37 +0,0 @@ -use crate::app::build::asciidoctor; - -#[test] -fn last_matching_index_0() { - let vec1 = vec!["dings", "dings", "dingens"].iter().map(|s| s.to_string()).collect(); - let vec2 = vec!["dings", "dings", "dings"].iter().map(|s| s.to_string()).collect(); - - let last_maching = asciidoctor::matching_from_start(&vec1, &vec2); - assert_eq!(last_maching, 2); -} - -#[test] -fn last_matching_index_1() { - let vec1 = vec!["dings", "dings", "dingens", "dings", "dingens"].iter().map(|s| s.to_string()).collect(); - let vec2 = vec!["dings", "dings", "dingens", "dings"].iter().map(|s| s.to_string()).collect(); - - let last_maching = asciidoctor::matching_from_start(&vec1, &vec2); - assert_eq!(last_maching, 4); -} - -#[test] -fn path_between_0() { - let path1 = "./docs/dings"; - let path2 = "./dist/dings"; - - let path_between = asciidoctor::path_between(path1.to_string(), path2.to_string()); - assert_eq!(path_between, "../../dist/dings"); -} - -#[test] -fn path_between_1() { - let path1 = "./dist/slides/core/"; - let path2 = "./dist/slides/revealjs"; - - let path_between = asciidoctor::path_between(path1.to_string(), path2.to_string()); - assert_eq!(path_between, "../revealjs") -}