diff --git a/Cargo.lock b/Cargo.lock index 19c2e0e..ec1d454 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,7 +158,7 @@ dependencies = [ [[package]] name = "crane" -version = "0.2.0" +version = "0.3.0" dependencies = [ "anyhow", "clap", @@ -175,7 +175,7 @@ dependencies = [ [[package]] name = "crane_bricks" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", "env_logger", diff --git a/README.md b/README.md index a5da0dc..845aef3 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,108 @@ -# crane 🏗️ +
+

crane 🏗️

-Easily add bricks (files or snippets) to your projects. +Create, use and share easily reusable bootstrap packages called bricks. +
+
+ +⭐ Consider starring this repo – your support motivates me a lot! ⭐ + +
+ + Crates.io Version + + + Crates.io Total Downloads + + + GitHub Repo stars + +
+
+Setup + ~  +FAQ + ~  +Documentation +
-🧱 A brick is an instruction. It can be a file that gets added, a command that + + +
+ +Crane is a CLI tool that allows you to create *bricks* that you can later add to any project. + +A brick is an instruction. It can be a file that gets added, a command that executes or lines getting replaced in a target file. -> 🚧 crane is currently being worked on :D -> Some features that are already documented don't work yet -> and everything could change until a stable release! +## Examples + +### License brick + +Instead of having to look up and copy your desired license from the web, you can create a brick out of it and then run `crane add some-license`. + +### Language specific bricks + +You can create multiple bricks and combine them behind an alias. + +This way, you can easily bootstrap new projects! + +```shell +$ cargo new my_project && cd my_project +# ... +$ crane add rust +→ Executing 4 bricks + • mit + • serde + • rustfmt + • rustauthor +# ... +``` + +## Getting Started + +Install the CLI using cargo (more options coming soon!) + +```shell +cargo install crane +``` + +and set up shell completions (not required): + +
+ZSH + +```shell +# ~/.zshrc +eval "$(crane completion zsh)" +``` + +
+ +
+Bash + +```shell +# ~/.bashrc +eval "$(crane completion bash)" +``` + +
+ +
+Fish + +```shell +# ~/.config/fish/config.fish +crane completion fish | source +``` + +
+ +## Issues & Contributions + +Feel free to open an issue or a PR. Help is always appreciated! -## ToDo +--- -- [ ] Regex support -- [ ] Path support -- [ ] Improve readme -- [ ] Variables support - - [ ] Input variables (ask for variable or command or something) +made with <3 by [timothebot](https://github.com/timothebot) diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 78f0619..63b6863 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -1,6 +1,8 @@ # Summary - [Introduction](./intro.md) +- [Set Up](./setup.md) +- [Frequently Asked Questions](./faq.md) # User Guide diff --git a/book/src/faq.md b/book/src/faq.md new file mode 100644 index 0000000..e5b802b --- /dev/null +++ b/book/src/faq.md @@ -0,0 +1,3 @@ +# Frequently Asked Questions + +Feel free to open an issue with any questions. Common questions will then be added here! diff --git a/book/src/setup.md b/book/src/setup.md new file mode 100644 index 0000000..be31eb5 --- /dev/null +++ b/book/src/setup.md @@ -0,0 +1,32 @@ +# Setup + +Install the CLI using cargo (more options coming soon!) + +```shell +cargo install crane +``` + +## Shell Completions (optional) + +Set up shell completions: + +### ZSH + +```shell +# ~/.zshrc +eval "$(crane completion zsh)" +``` + +### Bash + +```shell +# ~/.bashrc +eval "$(crane completion bash)" +``` + +### Fish + +```shell +# ~/.config/fish/config.fish +crane completion fish | source +``` diff --git a/crane/Cargo.toml b/crane/Cargo.toml index 47822ac..77c105c 100644 --- a/crane/Cargo.toml +++ b/crane/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "crane" description = "Easily add bricks (files or snippets) to your projects!" -version = "0.2.0" +version = "0.3.0" edition = "2024" license = "MIT" readme = "../README.md" @@ -13,11 +13,15 @@ keywords = ["cli", "tool", "utility"] serde = { version = "1.0", features = ["derive"] } toml = "0.9.6" clap = { version = "4.5.47", features = ["derive"] } +clap-verbosity = "2.1.0" fuzzy-matcher = "0.3.7" anyhow = "1.0.99" -clap-verbosity = "2.1.0" env_logger = "0.11.8" log = "0.4.28" -crane_bricks = { path = "../crane_bricks/", version = "0.1.0"} +crane_bricks = { path = "../crane_bricks/", version = "0.2.0" } colog = "1.4.0" colored = "3.0.0" + +[profile.release] +codegen-units = 1 +lto = true diff --git a/crane/src/cmd/commands.rs b/crane/src/cmd/commands.rs index 26902b8..7a7eef5 100644 --- a/crane/src/cmd/commands.rs +++ b/crane/src/cmd/commands.rs @@ -3,6 +3,8 @@ use std::path::PathBuf; use clap::{Parser, Subcommand, ValueHint}; use clap_verbosity::{InfoLevel, Verbosity}; +use crate::shell::Shell; + #[derive(Debug, Parser)] #[command(version, about, long_about = None)] pub struct CraneCli { @@ -17,6 +19,7 @@ pub struct CraneCli { pub enum CraneCommand { Add(Add), List(List), + Completion(Completion), } /// Add a brick to your directory @@ -35,9 +38,18 @@ pub struct Add { pub dry_run: bool, } +#[derive(Debug, Parser)] +pub struct Completion { + #[clap(required = true)] + pub shell: Shell, +} + /// List all available bricks #[derive(Debug, Parser, Clone)] pub struct List { #[arg(short, long, value_hint=ValueHint::DirPath, value_terminator=",")] pub brick_dirs: Option>, + + #[arg(long)] + pub no_format: bool, } diff --git a/crane/src/cmd/completion.rs b/crane/src/cmd/completion.rs new file mode 100644 index 0000000..1d668ed --- /dev/null +++ b/crane/src/cmd/completion.rs @@ -0,0 +1,7 @@ +use crate::cmd::{Completion, Run}; + +impl Run for Completion { + fn run(&self) { + println!("{}", self.shell); + } +} diff --git a/crane/src/cmd/list.rs b/crane/src/cmd/list.rs index c2a8704..da5026f 100644 --- a/crane/src/cmd/list.rs +++ b/crane/src/cmd/list.rs @@ -20,6 +20,18 @@ impl Run for List { &config.brick_dirs().to_vec() }; + if self.no_format { + for brick_dir in brick_dirs { + for brick in bricks_in_dir(brick_dir) { + println!("{}", brick.name()); + } + } + for alias in config.alias() { + println!("{}", alias.name()); + } + return; + } + let alias_mapped = map_aliases(config.alias()); for brick_dir in brick_dirs { diff --git a/crane/src/cmd/mod.rs b/crane/src/cmd/mod.rs index b87c666..dfb253f 100644 --- a/crane/src/cmd/mod.rs +++ b/crane/src/cmd/mod.rs @@ -1,5 +1,6 @@ mod add; mod commands; +mod completion; mod list; pub use crate::cmd::commands::*; @@ -13,6 +14,7 @@ impl Run for CraneCli { match &self.command { CraneCommand::Add(cmd) => cmd.run(), CraneCommand::List(cmd) => cmd.run(), + CraneCommand::Completion(cmd) => cmd.run(), } } } diff --git a/crane/src/main.rs b/crane/src/main.rs index 5666ab9..653e742 100644 --- a/crane/src/main.rs +++ b/crane/src/main.rs @@ -5,6 +5,7 @@ use crate::cmd::{CraneCli, Run}; mod cmd; mod config; mod logging; +mod shell; fn main() { let cli = CraneCli::parse(); diff --git a/crane/src/shell.rs b/crane/src/shell.rs new file mode 100644 index 0000000..4418545 --- /dev/null +++ b/crane/src/shell.rs @@ -0,0 +1,72 @@ +use std::fmt::Display; + +use clap::ValueEnum; + +#[derive(ValueEnum, Debug, Clone, Copy)] +pub enum Shell { + Bash, + Zsh, + Fish, +} + +impl Display for Shell { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!( + f, + "{}", + match self { + Shell::Bash => + r#" +# START generated crane shell config +_crane() { + local cur + cur="${COMP_WORDS[COMP_CWORD]}" + local subcommands="list add completions" + if [[ $COMP_CWORD -eq 1 ]]; then + COMPREPLY=( $(compgen -W "$subcommands" -- "$cur") ) + return + fi + if [[ ${COMP_WORDS[1]} == add ]]; then + local items + items="$(crane list --no-format 2>/dev/null)" + COMPREPLY=( $(compgen -W "$items" -- "$cur") ) + return + fi +} +complete -F _crane crane +# END generated crane shell config"#, + Shell::Zsh => + r#" +# START generated crane shell config +_crane() { + local -a subcmds add_args + subcmds=( + 'add:Add bricks' + 'list:List bricks' + 'completions:Generate shell completions' + ) + if (( CURRENT == 2 )); then + _describe 'subcommand' subcmds + return + fi + case $words[2] in + add) + _arguments "*:argument:($(crane list --no-format))" + ;; + esac +} +compdef _crane crane +# END generated crane shell config"#, + Shell::Fish => + r#" +# START generated crane shell config +complete -c crane -f -n '__fish_use_subcommand' -a list -d 'List bricks' +complete -c crane -f -n '__fish_use_subcommand' -a add -d 'Add bricks' +complete -c crane -f -n '__fish_use_subcommand' -a completions -d 'Generate shell completions' +complete -c crane -f -n '__fish_seen_subcommand_from add' \ + -a '(crane list --no-format 2>/dev/null)' +# END generated crane shell config"#, + } + ) + } +} diff --git a/crane_bricks/Cargo.toml b/crane_bricks/Cargo.toml index b374a85..417ae6a 100644 --- a/crane_bricks/Cargo.toml +++ b/crane_bricks/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "crane_bricks" description = "Execute bricks" -version = "0.1.0" +version = "0.2.0" edition = "2024" license = "MIT" repository = "https://github.com/timothebot/crane"