A small, interactive command runner

Related tags

Command-line dotree
Overview

Dotree is a small interactive command runner. It wants to be a better home for your aliases and bash functions, especially those that you don't use that often, and an alternative to just.

Given a config file like this:

menu root {
	g: git
	m: misc
}

menu git {
	am: "amend" - "git commit --amend --no-edit"
	aam: "all amend" - "git commit -a --amend --no-edit"
	ca: "git commit -a"
	b: "git switch $(git branch | fzf)"
	w: cmd {
		vars output_dir, branch
		"add worktree" - "git worktree add -b $branch $output_dir"
	}
}

menu misc {
	mn: "mount-netdrives"
	un: "unmount-netdrives"
	cv: "connect-vpn"
}

it presents you with the options to execute the commands configured in the file by typing the configured key. For Example: with the given config file above, I could start dotree by typing dt (after it was installed), and then type gb while dotree is running to execute git switch $(git branch | fzf) in bash.

Alternativly you can also do that by entering dt gb. If you provide an argument, its characters will be processed as if you typed them when the program is running.

A command can either be declared as quick command, i.e. a string that contains bash code, optionally with another string and a - in front of it, to have a name displayed in place of the bash code, or as command via the cmd keyword, which allows for the additional definition of variables that will be queried and then passed as env vars to the bash invocation. To query the input, rustyline is used, and you have path completion and a history.

An alternate form of strings are protected strings: !"<content>"!, in which case you can use " freely within the string. and in case you even need !" in a string, you can add any characters between the ! and the ". The characters are not mirrored on the closing delimiter. So !ab"<content>"ab! is valid, but !ab"<content>"ba! is not.

For an example of a real world config, click here

Command Arguments

Commands can have arguments, which will be queried interactively, like this:

...
menu git {
	...
	w: cmd {
		vars output_dir, branch
		"add worktree" - "git worktree add -b $branch $output_dir"
	}
}

...

The values are exposed via environment variables to the callee. If you invoke dt with additional arguments, the additional arguments will be used as values for the vars. For example: dt gw fknorr/some-feature /tmp/worktree_dir.

Repeating Commands

You can configure dotree to continue after a command was executed, so that you can trigger the command again with a single keypress. This is usefull for example, if you want to change screen brightness when you don't have a keyboard with appropriate keys:

menu root {
	m: brightnessctl
}

menu brightnessctl {
	+: cmd {
		set repeat
		"brightnessctl set +10%"
	}
	-: cmd {
		set repeat
		 "brightnessctl set -10%"
	}
}

You can also add ignore_result as a config option, in which case dotree won't escape when the command has a non-zero exit code, like this:

menu brightnessctl {
...
	+: cmd {
		set repeat, ignore_result
		"brightnessctl set +10%"
	}
...

Naming Menus

You can also assign a different display name to a menu, like this:

menu "Worktree" git_worktree {
	...
}

Local mode

If you start dotree with -l, it will search for a dotree.dt file between the cwd and the file system root. If it finds one, it uses it instead of the normal config file, and changes the working directory before executing commands, to the containing directory. This way, you can use dotree as a more interactive version of just. I aliased dt -l to dtl

Default Shell

By default, dotree uses "bash -euo pipefail -c" as shell invocation on linux, or "cmd /c" on windows. The shell string is always appended as last argument. You can change the default shell by setting the environment variable DT_DEFAULT_SHELL or on a per file basis, by placing a shell directive as first element in the config file like this:

shell sh -c

menu root {
	g: git
	m: misc
}
...

It is also possible to change the shell for a command, by putting a shell directive into a command like this:

menu root {
	p: cmd {
		shell python -c
		"python hi" - !"print("hello from python")"!
	}
}

Alternative Config Path

By default, dotree looks at a file named dotree.dt in the XDG config dir, you can make it look somewhere else with the -c command line argument

Snippets

To share code between multiple commands, you can define snippets:

snippet shared_vars = !"
	a_var=a_value
	b_var=b_value
"!

menu root {
	e: $shared_vars + "echo $a_var"
}

A snippet can be referenced by its name prefixed with a $. You use them in the definition of commands or in the definition of snippets. The can occur in any order like this:

snippet vars = !"
FOO="foo"	
"!

snippet a_fn = " # we want a newline here
append_foo() { 
	echo $1 foo
}
" # and here, since strings are simpli concatenated, and bash needs those newlines
  # alternatively, we could use a ; in the command

menu root {
	e: $vars + "echo foo=$FOO" + $a_fn + "append_foo $FOO"
}
	

Installation

Download the appropriate binary for your platform (windows is untested) from the release page, or install via cargo: cargo install --git https://github.com/knorrfg/dotree.

Comments
  • How to have arbitrary number of arguments to a command?

    How to have arbitrary number of arguments to a command?

    Stupid example to illustrate:

    menu root {
        w: cmd {
            vars urls
            "Download URLs" - "wget ${urls}"
        }
    }
    

    Now I can download a single URL with dotree w FIRST_URL, more than one by quoting as a single argument dotree w 'FIRST_URL SECOND_URL', but that does not work with the interactive prompt.

    opened by desbma 4
  • Question: Best way to share code between aliases?

    Question: Best way to share code between aliases?

    Hi,

    I think this project idea is brillant, I have many aliases with short names and I sometimes have to look at the shell code to remember the exact letters.

    However I have a question, I usually organize aliases/functions with same target domain in dedicated files, and that allows sharing code. For example I have many aliases calling yt-dlp, to download video, stream audio, stream video, search and choose with a fzf menu which video to play, etc. Currently these aliases call private subfunctions, or use variables declared in the same file. This does not seem to be possible with dotree, unless I source a common shell file first for each command declaration, which is not ideal because it duplicates code between 2 different places.

    Is there a better way to share code between aliases ?

    Thanks

    opened by desbma 3
  • Config in `$XDG_CONFIG_HOME` not found.

    Config in `$XDG_CONFIG_HOME` not found.

    I have a working config $XDG_CONFIG_HOME/dotree.dt, but dt seems to be looking elsewhere.

    ❯ ls $XDG_CONFIG_HOME/dotree.dt && dt
    /Users/cnmne/.config/dotree.dt
    Expected config file at /Users/cnmne/Library/Application Support/dotree.dt, but couldn't find it. Please create one.
    

    I also tried using ~/.config/dotree/dotree.dt instead (which I know is not per the docs, but maybe more common elsewhere).

    Of course I can successfully use dt --conf-file ~/.config/dotree.dt as a workaround, which I'll be aliasing in the meantime. Alternatively I could make a link to Application Support.

    Also thanks for making this tool-- been looking for a just alternative; and a bonus: very hydraesque!

    Also... ~~first! 🥇~~ second? 🥈

    opened by citrusmunch 2
  • [Feature request] Default values for vars

    [Feature request] Default values for vars

    It would be nice to have default values that can be overriden if needed.

    Here are some syntax/usage suggestions

    menu http {
        test: {
            vars route="index", port=8080
            "make a test request" - "curl http://127.0.0.1:$port/$route"
        }
    }
    

    And the ui could look something like

    value for route ("index"): 
    value for port (8080):
    
    opened by nate-sys 1
  • Feature Request/Discussion: More verbose output option(s)

    Feature Request/Discussion: More verbose output option(s)

    Currently the output from a successful dt invocation is nothing besides whatever is being called. However, I've been finding that I'll run a command with some side effects and then looking back on my shell history/ouput I can't see what's been run already. Re-running a command (non-consecutively) is also not really possible.

    A workaround is to run e.g. dt xyz some_arg at the cost of needing to provide everything up front (non-interactive).

    At the simplest, I think it would be nice to be able to echo the final invocation after an interactive session:

    $ dt
    dt xyz some_arg
    
    output of doing z ...
    

    That should usually provide enough context and could also be copy-pasted. Additionally, a quiet/verbosity flag might also be useful in case people are piping output, for instance.

    Getting fancier:

    • the echo could be previewed as one traverses the tree while typing
    • printing the final "name" - "bash command" leaf that's run
    • a full-blown @ show/hide token in the config à la just; and maybe toggling that interactively too?
    • modifying shell history so re-running is more seamless than copy-pasting from scrollback

    I don't mean to introduce bloat (I'd likely turn to an emacs hydra if I needed all that), but I thought I'd include it since it's related and I had some fun brainstorming. The simplest solution alone would make a world of difference!

    I haven't touched rust in years, but maybe I'll make an excuse to pick it up again and toy around with some of this. Just wanted to put this all out there for discussion!

    opened by citrusmunch 1
  • Suggestion: file inclusion

    Suggestion: file inclusion

    I was thinking, as my configuration file is growing, and syntax support for this kind of file isn't great in my editor, that it would be nice to have file inclusion on the menu level. That way, I could develop new submenus independenly, and when finished, include them in the main configuration. Files would remain more managable as well. Lazy evaluation, as only evaluating the included file when it is effectively needed, could also be a consideration.

    Just a suggestion, it's already great as it is.

    opened by sleepyMonad 1
Releases(0.6.0)
Owner
Felix G. Knorr
Felix G. Knorr
comfy is a flexible command script manager / runner written in Rust

comfy is a cross-platform command script manager / runner tool, which allows you to run commands in the command line itself, but being these predefined in a portable and universal .comfy file.

daCoUSB 17 Nov 12, 2021
An interactive cheatsheet tool for the command-line

navi An interactive cheatsheet tool for the command-line. navi allows you to browse through cheatsheets (that you may write yourself or download from

Denis Isidoro 12.2k Dec 30, 2022
Coinlive is an interactive command line tool that displays live cryptocurrency prices.

Coinlive is an interactive command line tool that displays live cryptocurrency prices. It can also display simple historical price charts.

Mayer Analytics 9 Dec 7, 2022
ruborute is an interactive command-line tool to get asphyxia@sdvx gaming data.

ruborute Are you 暴龍天 ?. The ruborute is an interactive command-line tool to get asphyxia@sdvx gaming data. asphyxia-core/plugins: https://github.com/a

RinChanNOW! 9 Sep 28, 2022
Non-interactive nREPL client for shell scripts and command-line

nreplops-tool (nr) nreplops-tool (nr) is a non-interactive nREPL client designed to be used in shell scripts and on the command-line. Early α warning:

Matti Hänninen 3 Jul 1, 2022
A toolkit for building your own interactive command-line tools in Rust

promkit A toolkit for building your own interactive command-line tools in Rust, utilizing crossterm. Getting Started Put the package in your Cargo.tom

null 70 Dec 18, 2022
Small command-line tool to switch monitor inputs from command line

swmon Small command-line tool to switch monitor inputs from command line Installation git clone https://github.com/cr1901/swmon cargo install --path .

William D. Jones 5 Aug 20, 2022
Shellcode Runner/Injector in Rust using NTDLL functions directly with the ntapi Library

RustSCRunner Shellcode Runner/Injector in Rust using NTDLL functions directly with the ntapi Library. Surprisingly this is my first ever Rust project

null 86 Dec 18, 2021
A wayland native, highly customizable runner.

anyrun A wayland native krunner-like runner, made with customizability in mind. Features Style customizability with GTK+ CSS More info in Styling Can

null 18 Jan 22, 2023
A standalone Luau script runner 🌙

Lune ?? A standalone Luau script runner ?? Use the ergonomics and readability of Luau for your shell scripts ?? ⚙️ Installation The preferred way of i

Filip Tibell 13 Feb 2, 2023
ABQ is a universal test runner that runs test suites in parallel. It’s the best tool for splitting test suites into parallel jobs locally or on CI

?? abq.build   ?? @rwx_research   ?? discord   ?? documentation ABQ is a universal test runner that runs test suites in parallel. It’s the best tool f

RWX 13 Apr 7, 2023
Minimal, blazing fast Node.js script runner

nrr Minimal, blazing fast Node.js script runner. Why? nrr initializes and resolves scripts way faster than package managers. It achieves this by provi

Ryan Cao 3 Nov 17, 2023
Configurable, extensible, interactive line reader

linefeed linefeed is a configurable, concurrent, extensible, interactive input reader for Unix terminals and Windows console. API Documentation linefe

Murarth 176 Jan 3, 2023
Simple Interactive Terminal Todo App in Rust

todo-rs Simple Interactive Terminal Todo App in Rust Quick Start $ cargo run TODO Controls Keys Description k, j Move cursor up and down Shift+K, Shif

Tsoding 56 Dec 8, 2022
A Rust library for building interactive prompts

inquire is a library for building interactive prompts on terminals. Demo Source Usage Put this line in your Cargo.toml, under [dependencies]. inquire

Mikael Mello 426 Dec 26, 2022
An interactive shell environment for exploring the p2panda protocol

An interactive shell environment for exploring the p2panda protocol. Uses a mock node and clients to simulate network logic.

null 4 Dec 12, 2021
Native cross-platform full feature terminal-based sequence editor for git interactive rebase.

Native cross-platform full feature terminal-based sequence editor for git interactive rebase.

Tim Oram 1.2k Jan 2, 2023
Requestty - An easy-to-use collection of interactive cli prompts inspired by Inquirer.js.

Requestty requestty (request-tty) is an easy-to-use collection of interactive cli prompts inspired by Inquirer.js. Easy-to-use - The builder API and m

null 160 Dec 28, 2022
Terminal based, feature rich, interactive SQL tool

datafusion-tui (dft) DataFusion-tui provides a feature rich terminal application, built with tui-rs, for using DataFusion (and eventually Ballista). I

null 49 Dec 24, 2022