Project Level Shortcuts (pls) is a command-line tool designed to streamline your workflow by allowing you to create, manage, and execute custom aliases for frequently used commands. Say goodbye to messy bash profiles, and say hello to pls! ๐ฆ
Run your most frequently used commands with ease, e.g. pls test
to run tests, pls godot
to open your Godot project and editor, pls open-here
to open the current directory in your file manager, and whatever else you can think of!
-
Install
For advanced users, here's a quick guide to get
pls
working on your system.# cd to directory that should house the pls script cd /path/to/pls/dir # download and make executable curl -sS https://raw.githubusercontent.com/codevogel/pls/main/release/pls > pls && chmod +x pls # add pls to your PATH echo 'export PATH="$PATH:/path/to/pls/dir"' >> ~/.bashrc
-
Try in Docker
If you want to try
pls
without installing it on your own system first, you can use the following commands:# cd to directory that should house the Dockerfile cd ./pls-test # download the Dockerfile curl -sS https://raw.githubusercontent.com/codevogel/pls/main/docker/Dockerfile > Dockerfile # build and run the Docker container docker build -t plsbuntu . --no-cache docker run -it plsbuntu
- Quick Start
- What is pls and why do I want pls?
- Getting started
- Command overview
- Execute commands in the main shell
- File format
- Command cache
- Configuration
- Roadmap
- Contributing
pls
allows you to store your aliases in pls
files. You can either define system-wide aliases in a global
file, or place project-specific aliases in a local
file, e.g., in the root of your project directory. The pls
file (by default named .pls.yml
) contains a list of aliases and their corresponding commands. When you run pls <alias>
, the command associated with that alias is executed. Aliases from a local
, project-specific context take precedence over aliases from the global
, system-wide context, allowing you to reuse the same alias in different contexts. For example, if you have two projects that use different testing frameworks, pls
allows you to just run pls test
in either directory, reducing the need to remember framework-specific commands.
pls
supports single-line and multi-line commands, as well as parameterized commands. Additionally, it caches the commands you run, and warns you when an alias points to an uncached command. This lets you be sure that you are only running the commands that you expect.
โWhy would I use pls
?
- Organized alias management: Instead of cluttering your shell profile with numerous aliases,
pls
lets you keep them organized in separate files, making it easier to manage and maintain your shortcuts. - Context-aware aliases:
pls
allows you to have project-specific aliases that override global ones, enabling you to reuse common alias names (like "test") across different projects with varying implementations. - Command cache verification: The command caching feature warns you when you're about to run a new or modified command, helping prevent accidental execution of potentially harmful commands.
- Portability and synchronization: Easily sync your aliases between different machines (e.g., work and home computers) by managing your
.pls.yml
files. - Fuzzy command picker: The built-in alias picker (with optional
fzf
integration) makes it easy to find and execute aliases without remembering exact names. - Parameterized commands:
pls
supports parameterized commands, allowing you to pass arguments to your aliases. - Works with bash:
pls
is a lightweight shell script that works with any shell that supports bash syntax.
โHow does it work under the hood?
If you execute an alias,pls
will first query the global
context (which is the file that lives at $PLS_GLOBAL
). It then searches for the closest file that matches $PLS_FILENAME
that lives in the current, or any of the parent directories (excluding $PLS_GLOBAL
file). If it finds any conflicts (aliases that appear in both the global
and local
context), the command from the local
file is picked. It then verifies whether this exact command has been ran before, taking into account the alias, the file which it is stored in, and the exact command contents. If the command is new, was moved to a different location, or has changed since the last execution, pls
will prompt you to confirm the execution of the command. This is to prevent accidental execution of potentially harmful commands.
This is a quick guide to get pls
working on your system. ๐ง๐ฆ
First, make sure you have the dependencies installed, then proceed to the instructions below.
yq
(tested withv4.44.2
) - A lightweight and portable command-line YAML processor. (Installation instructions)- Optional:
fzf
- A command-line fuzzy finder. (Installation instructions)
โน๏ธ Note:
fzf
is completely optional. It is used only for thepick_alias
command, which uses a fallback picker if you don't havefzf
installed.
-
Download the
pls
script and extract it to a directory on yourPATH
(or add it to yourPATH
in step 2).- using
curl
:curl -O https://raw.githubusercontent.com/codevogel/pls/main/release/pls
- using
wget
:wget https://raw.githubusercontent.com/codevogel/pls/main/release/pls
- Clone this repository and copy the
release/pls
script. - Download the
pls
script from here manually.
- using
-
Add the
pls
script to yourPATH
.- If your shell is
bash
:echo 'export PATH="$PATH:/path/to/dir"' >> ~/.bashrc
- If your shell is
zsh
:echo 'export PATH="$PATH:/path/to/dir"' >> ~/.zshrc
- If your shell is something else, do the equivalent of the above.
- If your shell is
-
Optionally, add support for running the commands in your main shell process. See the Use in main shell section for more information.
-
Test the installation by running
pls --help
.
-
To get started with
pls
, add your first alias. There are two approaches:- Create a
.pls.yml
file and manually add the following contents (see 'File format' if you want to expand on it further):commands: - alias: "hello" command: "echo 'Hello, World!'"
- Add an alias using the
pls add
command:pls hello --add --command "echo 'Hello, World!'" --scope local
โน๏ธ Note: As
pls
supports combining flags, this is a shorter equivalent of the above command:pls hello -ac "echo 'Hello, World!'" -s local
- Create a
-
To execute the alias, run
pls hello
. You should first be prompted to confirm that you indeed want to run this command. Entery
orY
and pressReturn
.โน๏ธ Note: When you execute the alias another time,
pls
will have cached usage of the command, and you will not be prompted until the command (or location of the file) changes.โฏ ./pls hello Alias 'hello' was found in '/home/codevogel/work/pls/.pls.yml', but this command seems new. echo 'Hello, World!' Are you sure you want to invoke the above command? [y/n] y Hello, World! โฏ ./pls hello Hello, World!
โน๏ธ Note: When you add the -p flag, the command will be printed instead of executed. This is useful if you want to run the command in your main shell process, or want to pipe the command to run in a different shell.
-
You can also leave out the alias, and
pls
will launch an interactive picker that lets you choose from a list of available aliases. Try it now, just runpls
!
To keep the syntax for using pls
as short as possible, and because we want to keep the namespace for aliases clean of commands, pls
uses just a single root command: pls
. This command can be followed by an alias, command arguments, or flags.
pls [alias] [command_args] [flags]
This is an overview of the flags that trigger pls
to perform alternative operations (instead of the default operation: executing an alias). Each of these operation flags conflict with one another: you can only use one at a time.
Operation | Shorthand | Needs Flags | Optional Flags | Description |
---|---|---|---|---|
--add |
-a |
--command --scope |
--force |
Adds a new alias for a --command <command> to the pls file at a given --scope <[g]lobal, [l]ocal, [h]ere> .Use with --force to overwrite the alias if it exists. |
--delete |
-d |
--scope |
Delete the alias from the pls file at given--scope <[g]lobal, [l]ocal, [h]ere> . |
|
--list |
-l |
--scope --print |
List all aliases available in the current directory. Or, list aliases only from --scope <[g]lobal, [l]ocal, [a]ll> .Use with --print to print the command associated with each alias. |
These are the flags that do not represent operations. Some of them are used to provide additional information to operations, or to modify the behavior of the root command.
Flag | Needs argument | Used with | Description |
---|---|---|---|
--command |
yes | --add |
Supplies a command to associate with the alias in the --add operation. Pass the command as a string, newline characters ('\n') are allowed. |
--scope |
yes | --add --delete --list |
The selected scope for --add , --delete , and --list operations. Allowed scopes are [g]lobal, [l]ocal, [a]ll, [h]ere. The 'all' scope is exclusive to --list . The 'here' scope is excluded from --list . |
--print |
root command--list |
Prints the command instead of executing it when used with root command. Useful for piping to other commands or shells. Or, if used in conjunction with --list , it additionally prints the command for each alias. |
|
--force |
--add |
Overwrite the alias if it already exists when using the --add operation. |
|
--clear-cache |
Before doing anything, clears the cache of all commands that have been run with pls. | ||
--help |
Show the help. | ||
--version |
Show the version number. |
View EXAMPLES.md
(here) to see some examples of how to use commands that pls
provides.
If you want pls
to execute the command in your main shell process, and your shell is bash
, then you can simply add .
or source
in front of your pls
command:
# Executes 'cd ~/work/godot/' in the main shell process
. pls godot
You could setup an alias for this in your .bashrc
:
alias plz=". pls"
If your main shell is not bash
, you can still use pls
in your main shell process. Just know that the command will be executed in a bash subshell. If you want to execute the command in your main shell process, you can make use of the -p
flag and eval
. Here is an example for zsh
, in which we set up a function plz
that executes the command in the main shell process:
We create a zsh
function at ~/.zshfuncs/plz
cmd="$(pls "$1" -p)"
execute_command() { # Use a function so we can use parameterized commands as well
eval "$cmd"
}
execute_command ${@:2}
Then we load it in our .zshrc
:
# Load the zsh function 'plz'
echo 'fpath=(~/.zshfuncs "${fpath[@]}")' >> ~/.zshrc
echo 'autoload -Uz plz' >> ~/.zshrc
Now say we have the following in our .pls.yml
file:
commands:
- alias: go
command: cd $1 && ls -al
We can use plz
in our zsh
shell:
plz go ~/work/godot/ # cd's to ~/work/godot/ and lists the contents
Here is a real-world example of how I load my development environment for a Godot project. In my global .pls.yml
I have setup the following alias:
- alias: godot
command: |
wezterm start --always-new-process -- bash -c "cd ~/work/godot/projects/tit-versus-tat && nvim .; exec zsh" &
disown
Godot_v4.2.2-stable_linux.x86_64 -e --path ~/work/godot/projects/tit-versus-tat/ --single-window &
disown
exit
Now, whenever I sit down to work on my game, I just run plz godot
and my project loads up, along with launching a new terminal with nvim
open in the project directory.
pls
uses YAML files to store aliases. YAML is a human-readable data serialization format that is easy to read and write, which should make adding commands a pretty straight-forward experience. An example of a properly formatted .pls.yml
file is shown here:
commands:
- alias: my-alias
command: echo "hello from my-alias!"
- alias: my-multiline-command
command: |
echo "echo!"
echo "... echo!"
- alias: work
command: cd ~/some/really/long/path/to/my/directory/work
- alias: greet me
command: |
echo "Hello, my name is $1!"
A few points of interest here:
- The
commands
key should be the only root key of the YAML file, and must always be present. (This means that at minimum, apls
file should containcommands:
) - The
commands
key contains an array of objects (which may be empty), and can hold:- An
alias
key that contains a single-line string representing the alias you want to use. (Spaces and symbols are allowed, but discouraged.) - The
command
key that contains either a single-line or multi-line string containing the command you want to execute. Multi-line commands must be preceded by a|
or|-
character and indented. - The
command
key can also contain a parameterized command, where$1
,$2
, etc. are replaced with the arguments passed to the alias.
- An
โน๏ธ Don't worry too much about remembering all this - if you break any of these rules, you should get an error when running
pls
, pointing you in the right direction to correct the formatting.
Each time you execute an alias, pls
stores:
- The alias that was executed
- The exact command that was executed
- The path to the file where the alias was found
This allows pls
to warn you when you try to execute an alias that points to a different command than the one you have previously executed. This is especially useful when you are working on a project with multiple collaborators (maybe someone has changed one of the aliases), or when you have multiple aliases with the same name in different directories.
โน๏ธ If you want to be informed about the contents of the command, regardless of it being cached already, or if you want to turn off the warning altogether, see the
PLS_ALWAYS_VERIFY
andPLS_ENABLE_CACHE_CHECK
environment variables in the Configuration section.
To clear the cache, you can run pls clear_cache
.
pls
can be configured using a .plsrc
file, which is stored at the environment variable $PLS_RC
. If you have not set $PLS_RC
, then it will be created at $HOME/.config/pls/.plsrc
by default, including the default values listed in the table below:
Variable | Description | Default Value |
---|---|---|
PLS_FILENAME |
The name of the data file that pls looks for. |
.pls.yml |
PLS_GLOBAL |
The path to the global pls file (system-wide) |
$HOME/$PLS_FILENAME |
PLS_ENABLE_CACHE_CHECK |
If set to true , pls will check the cache for the command before executing it. |
true |
PLS_ALWAYS_VERIFY |
If set to true , pls will always prompt you to confirm the execution of the command, even if PLS_ENABLE_CACHE_CHECK is false |
false |
PLS_ENABLE_FZF |
If set to true , pls will use fzf as the picker (given that you have it installed). |
N/A |
PLS_DIR |
The directory where internal pls files are stored. Not recommended to place this in /tmp/ as that would delete the cache on reboot. |
$HOME/local/.share/pls |
Make sure each of these variables is on a new line in the .plsrc
file, and that you are not missing any. If in doubt, you can always delete the .plsrc
file and pls
will recreate it with the default values.
- Add support for single-line commands
- Add support for multi-line commands
- Add support for parameterized commands
- Add context-aware aliases
- Add command cache verification
- List available aliases
- Add alias picker
- Add
.rc
file - Use
pls
with flags, preventing commands from taking up alias namespace. - What else would you like to see? Let us know by opening an issue!
Please refer to the CONTRIBUTING.md file for more information on how to contribute to this project.