mirror of
https://github.com/zkldi/Tachi.git
synced 2026-09-22 23:18:05 +03:00
feat: Dev Container (#1149)
* temporary dvctr * start of work * fix: timeouts in windows * fish? * feat: better, working stuff * refactor: rename database-seeds to seeds/ * better * fdsaf * feat: don't let our container get owned by root * fix: better user handling * feat: falling asleep at my desk i yield to you what i have done * feat: autoadminify * docs: denote trickshot * feat: open in browser on launch * better seeds workings... * fix: dont kill shell * docs: mention dev/debs * fix: whoops * fix: make seeds load within the century * feat: rest of the containerisation * feat: new alias * style: fix linter errors * fix: bad call * fix: better justfile
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "Tachi",
|
||||
"dockerComposeFile": [
|
||||
"../docker-compose-dev.yml"
|
||||
],
|
||||
"service": "tachi-dev",
|
||||
"workspaceFolder": "/tachi",
|
||||
"postAttachCommand": "./dev/bootstrap.sh",
|
||||
"updateRemoteUserUID": true,
|
||||
"containerUser": "tachi",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"[typescriptreact]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
}
|
||||
},
|
||||
"extensions": [
|
||||
"dbaeumer.vscode-eslint"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,5 +5,5 @@ node_modules
|
||||
**/.tsbuildinfo
|
||||
|
||||
# Extracted data from iidx merge script
|
||||
database-seeds/scripts/rerunners/iidx/iidx-mdb-parse/ifs-output
|
||||
database-seeds/scripts/rerunners/iidx/iidx-mdb-parse/logs
|
||||
seeds/scripts/rerunners/iidx/iidx-mdb-parse/ifs-output
|
||||
seeds/scripts/rerunners/iidx/iidx-mdb-parse/logs
|
||||
@@ -1,17 +1,17 @@
|
||||
name: Database-Seeds CI/CD
|
||||
name: Seeds CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
paths:
|
||||
- "database-seeds/**"
|
||||
- "seeds/**"
|
||||
- "common/**"
|
||||
pull_request:
|
||||
branches:
|
||||
- "main"
|
||||
paths:
|
||||
- "database-seeds/**"
|
||||
- "seeds/**"
|
||||
- "common/**"
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -32,10 +32,10 @@ jobs:
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm --filter tachi-database-seeds-scripts... --filter . install
|
||||
run: pnpm --filter tachi-seeds-scripts... --filter . install
|
||||
|
||||
- name: Run Tests
|
||||
run: pnpm --filter tachi-database-seeds-scripts test
|
||||
run: pnpm --filter tachi-seeds-scripts test
|
||||
env:
|
||||
NODE_ENV: "test"
|
||||
deploy:
|
||||
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"ms-vscode-remote.remote-containers"
|
||||
]
|
||||
}
|
||||
Vendored
+1
-2
@@ -5,6 +5,5 @@
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
# Yes, I've made an entire docker container just to run a bash script
|
||||
# instead of rewriting the script in a ~~real~~ cross-platform scripting language.
|
||||
# This docker container **depends** on an external volume being mounted
|
||||
# (see how it's used in docker-compose-dev.yml)
|
||||
# and *intentionally* mutates state outside of its container.
|
||||
|
||||
# I really do not care.
|
||||
# Want it better? Do it yourself.
|
||||
FROM node:20 AS base
|
||||
|
||||
RUN npm install --silent -g pnpm@8.15.6
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
CMD ["bash", "_scripts/bootstrap.sh"]
|
||||
@@ -0,0 +1,55 @@
|
||||
# For use via `devcontainer.json`. The docker-compose-dev file sets some other
|
||||
# important variables.
|
||||
|
||||
# we use ubuntu because 'just' isn't available on debian 13
|
||||
# haha.. haha...
|
||||
FROM ubuntu:24.10
|
||||
|
||||
WORKDIR /tachi
|
||||
|
||||
RUN apt update
|
||||
|
||||
# essentials
|
||||
RUN apt install -y git npm locales sudo
|
||||
|
||||
# setup locales
|
||||
# https://stackoverflow.com/questions/28405902/how-to-set-the-locale-inside-a-debian-ubuntu-docker-container
|
||||
RUN echo 'en_US.UTF-8' > /etc/locale.gen && locale-gen
|
||||
ENV LANG en_US.UTF-8
|
||||
ENV LANGUAGE en_US:en
|
||||
ENV LC_ALL en_US.UTF-8
|
||||
|
||||
# nodeisms
|
||||
RUN npm install --silent -g pnpm@8.15.6
|
||||
|
||||
# docs pythonisms
|
||||
RUN apt install -y python-is-python3 pip mkdocs mkdocs-material
|
||||
|
||||
# https://github.com/python-babel/babel/issues/990
|
||||
# it wouldn't be python without needing absurd global state manipulation to fix
|
||||
# an incoherent error message
|
||||
RUN rm -f /etc/localtime && ln -s /usr/share/zoneinfo/Etc/UTC /etc/localtime
|
||||
|
||||
# Fix locale issue perl repeatedly complains about
|
||||
RUN echo "LC_ALL=en_US.UTF-8\nLANG=en_US.UTF-8" > /etc/default/locale
|
||||
|
||||
# nice to haves
|
||||
RUN apt install -y gh fish just fzf curl wget parallel neovim fd-find bat
|
||||
|
||||
# `fd` is called `find-fd` on ubuntu. Awesome.
|
||||
RUN ln -s $(which fdfind) /usr/bin/fd
|
||||
|
||||
# rename ubuntu user to tachi and give them sudo
|
||||
RUN usermod -l tachi ubuntu && \
|
||||
usermod -d /home/tachi -m tachi && \
|
||||
echo "tachi ALL = NOPASSWD : ALL" >> /etc/sudoers
|
||||
|
||||
# Docker volumes are mounted as root UNLESS the folder already exists inside the host
|
||||
# and has non-root ownership. This is the only way to declare a volume in docker has
|
||||
# non-root ownership. Unbelievably obscure.
|
||||
RUN mkdir node_modules && \
|
||||
mkdir .pnpm-store && \
|
||||
chown tachi:1000 node_modules .pnpm-store
|
||||
|
||||
# keep container alive indefinitely
|
||||
CMD ["/bin/fish"]
|
||||
@@ -1,26 +0,0 @@
|
||||
# no alpine here as we want bash + general nice-to-haves
|
||||
FROM node:20 AS base
|
||||
|
||||
RUN npm install --silent -g pnpm@8.15.6
|
||||
|
||||
FROM base AS build
|
||||
WORKDIR /app
|
||||
|
||||
COPY pnpm-lock.yaml .
|
||||
COPY patches ./patches
|
||||
|
||||
RUN pnpm fetch
|
||||
|
||||
COPY database-seeds ./database-seeds
|
||||
COPY common ./common
|
||||
COPY *.json *.yaml ./
|
||||
|
||||
RUN pnpm --filter tachi-common... --filter . install --offline --frozen-lockfile
|
||||
RUN pnpm --filter tachi-database-seeds-scripts... --filter . install --offline --frozen-lockfile
|
||||
|
||||
WORKDIR /app/database-seeds
|
||||
|
||||
# keep container alive indefinitely
|
||||
# we just have this container so db-seeds maintainers have a nice "context"
|
||||
# to work with
|
||||
CMD ["tail", "-f", "/dev/null"]
|
||||
@@ -0,0 +1,48 @@
|
||||
mod seeds
|
||||
mod server
|
||||
mod client
|
||||
mod docs
|
||||
|
||||
[private]
|
||||
interactive:
|
||||
-@just --choose
|
||||
|
||||
# Run the frontend and backend for Tachi.
|
||||
#
|
||||
# This is the main command you want to use to start up tachi. Go for it!
|
||||
start:
|
||||
parallel --lb ::: 'FORCE_COLOR=1 just server start' 'FORCE_COLOR=1 just client start'
|
||||
|
||||
# test everything
|
||||
test:
|
||||
just server test
|
||||
just client test
|
||||
just seeds test
|
||||
|
||||
latest_dataset := "2024-05"
|
||||
# Load the latest Kamaitachi dataset. This is put in the "anon-kamai" database.
|
||||
load-kamai-dataset:
|
||||
wget -O- https://cdn-kamai.tachi.ac/datasets/{{latest_dataset}}.dump | mongorestore --uri='mongodb://mongo' --gzip --archive
|
||||
|
||||
echo "Successfully loaded. You should change 'server/conf.json5' to use anon-kamai as the database."
|
||||
|
||||
# Load the latest Bokutachi dataset. This is put in the "anon-boku" database.
|
||||
load-boku-dataset:
|
||||
wget -O- https://cdn-boku.tachi.ac/datasets/{{latest_dataset}}.dump | mongorestore --uri='mongodb://mongo' --gzip --archive
|
||||
|
||||
echo "Successfully loaded. You should change 'server/conf.json5' to use anon-boku as the database."
|
||||
|
||||
# Check that the data in MongoDB makes any sense.
|
||||
validate-db:
|
||||
cd server/ && pnpm validate-database
|
||||
|
||||
# reload the shell setup
|
||||
setup-fish:
|
||||
@fish dev/setup.fish
|
||||
|
||||
@exec fish
|
||||
|
||||
# force a re-bootstrap
|
||||
bootstrap:
|
||||
-@rm I_HAVE_BOOTSTRAPPED_OK
|
||||
./dev/bootstrap.sh
|
||||
@@ -28,13 +28,28 @@ Check the [Documentation](https://docs.tachi.ac/contributing/setup) for how to s
|
||||
|
||||
You can then check the component-specific guides to see how to run those components and contribute back!
|
||||
|
||||
## Quick Setup For Nerds
|
||||
## Quick Setup For Experienced Programmers
|
||||
|
||||
Already know what you're doing?
|
||||
Install VSCode and use the dev container extension.
|
||||
This is my the supported way of working and will ensure you have the correct versions of everything.
|
||||
|
||||
Install docker + docker-compose and use `./run.sh start` or `./run.bat start` to start Tachi.
|
||||
### Unsupported stuff
|
||||
|
||||
Other commands you might want to execute are included inside the `run` file.
|
||||
Tachi is intended to be developed inside a container. This ensures that you have the correct version of MongoDB, Redis, Typescript and all that jazz.
|
||||
|
||||
VSCode has excellent native support for dev containers, and as such this is the only method of local development we officially support.
|
||||
|
||||
Over the years we have had a *lot* of issues with people having subtle variations on their system (or on windows). Given the contributor-centricity of Tachi, it's untenable to expect every contributor to be an expert with local dev setup.
|
||||
|
||||
The devcontainer provides us with the most simple, consistent experience, and allows us to put nice-to-haves inside the user's shell.
|
||||
|
||||
That said, if you're ardently against using VSCode or Docker...
|
||||
|
||||
**DO NOT REPORT ISSUES TO ME IF YOU DO THIS**
|
||||
|
||||
You can run the docker-compose file and `dev/boostrap.sh` inside the container yourself. Work inside the container.
|
||||
|
||||
Alternatively if you want to work outside of docker you're on your own. Figure out the correct versions for everything (npm, pnpm, mongo, redis, ts-node...) and `dev/bootstrap.sh`.
|
||||
|
||||
## Repository Info
|
||||
|
||||
@@ -48,7 +63,7 @@ The client and the server are fairly decoupled. Someone could trivially create t
|
||||
|
||||
This contains all of our API calls, and interfaces with our database, and powers the actual score import engine.
|
||||
|
||||
- `database-seeds/`, Which is a git-tracked set of data to be synced with Tachi. (unlicense)
|
||||
- `seeds/`, Which is a git-tracked set of data to be synced with Tachi. (unlicense)
|
||||
|
||||
**This is the source of truth for the songs, charts, and more on the site!**
|
||||
By submitting PRs to this, you can fix bugs on the website, add new charts, and more.
|
||||
|
||||
@@ -20,7 +20,7 @@ for kind in "kamai" "boku"; do
|
||||
|
||||
mongodump --archive --port=$remote_port --db=$kind | mongorestore --archive --nsFrom="$kind.*" --nsTo="anon-$kind.*"
|
||||
|
||||
pnpm ts-node src/scripts/anonymise-db 127.0.0.1:27017/anon-$kind
|
||||
ts-node src/scripts/anonymise-db 127.0.0.1:27017/anon-$kind
|
||||
|
||||
TCHIS_CONF_LOCATION=$kind.dataset.conf.json5 pnpm set-indexes
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[private]
|
||||
interactive:
|
||||
-@cd ../ && just
|
||||
|
||||
# Run the client interactively. Changes made to files will trigger reloads.
|
||||
start:
|
||||
pnpm dev
|
||||
|
||||
# Test that the client passes typechecking and linting.
|
||||
test:
|
||||
pnpm typecheck
|
||||
pnpm lint
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"license": "AGPL3",
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
"dev": "vite --open",
|
||||
"build": "vite build",
|
||||
"lint": "eslint src",
|
||||
"lint-fix": "eslint src --fix",
|
||||
|
||||
@@ -271,9 +271,9 @@ function RevSelector({
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (collection) {
|
||||
params.set("path", `database-seeds/collections/${collection}`);
|
||||
params.set("path", `seeds/collections/${collection}`);
|
||||
} else {
|
||||
params.set("path", "database-seeds/collections");
|
||||
params.set("path", "seeds/collections");
|
||||
}
|
||||
|
||||
const res = await fetch(
|
||||
|
||||
@@ -36,25 +36,26 @@ try {
|
||||
}
|
||||
</style>
|
||||
<div class="box">
|
||||
<h1>Failed to connect!</h1>
|
||||
<div>Welp. Looks like we're down. Sorry about that.</div>
|
||||
<div>Chances are, this is just a temporary outage and will be fixed soon.</div>
|
||||
<div style="font-size: 1.25rem; margin-top: 1rem; margin-bottom: 1rem;">
|
||||
Please be patient, <a href="https://github.com/zkrising/Tachi">Tachi is maintained by a very small team.</a>
|
||||
</div>
|
||||
<div>An error message can be found in the console. (<code>Ctrl-Shift-I</code>)</div>
|
||||
|
||||
${
|
||||
process.env.VITE_IS_LOCAL_DEV
|
||||
? `
|
||||
<hr />
|
||||
<div><b>You're in local development mode.</b>
|
||||
<h1><b>Couldn't connect to the server.</b></h1>
|
||||
<h3>You are in local development mode.</h3>
|
||||
<ul style="font-size: 2rem;">
|
||||
<li>Have you accepted the HTTPS certificates for <a href="${ToAPIURL(
|
||||
"/status"
|
||||
)}">the server?</a>. If not, the site won't load.</li>
|
||||
</ul>
|
||||
`
|
||||
: ""
|
||||
: `<h1>Failed to connect!</h1>
|
||||
<div>Welp. Looks like we're down. Sorry about that.</div>
|
||||
<div>Chances are, this is just a temporary outage and will be fixed soon.</div>
|
||||
<div style="font-size: 1.25rem; margin-top: 1rem; margin-bottom: 1rem;">
|
||||
Please be patient, <a href="https://github.com/zkrising/Tachi">Tachi is maintained by a very small team.</a>
|
||||
</div>
|
||||
<div>An error message can be found in the console. (<code>Ctrl-Shift-I</code>)</div>`
|
||||
}
|
||||
</div>
|
||||
`);
|
||||
|
||||
@@ -30,7 +30,7 @@ import { CreateQuestMap, Dedupe, JSONAttributeDiff, JSONCompare } from "./misc";
|
||||
import { ValueGetterOrHybrid } from "./ztable/search";
|
||||
|
||||
/**
|
||||
* Given a repo and a reference return the status of database-seeds/collections
|
||||
* Given a repo and a reference return the status of seeds/collections
|
||||
* as of that commit.
|
||||
*
|
||||
* If "WORKING_DIRECTORY" is passed as a ref, and the repository is local, this will
|
||||
@@ -63,7 +63,7 @@ export async function LoadSeeds(repo: string, ref: string): Promise<Partial<AllD
|
||||
const res = await fetch(
|
||||
`https://raw.githubusercontent.com/${repo.substring(
|
||||
"GitHub:".length
|
||||
)}/${ref}/database-seeds/collections/${file}`
|
||||
)}/${ref}/seeds/collections/${file}`
|
||||
);
|
||||
|
||||
if (res.status === 404) {
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
throw new Error(`This script doesn't work at the moment. Use mongoexp.sh.`);
|
||||
|
||||
const monk = require("monk");
|
||||
const { Command } = require("commander");
|
||||
const { StaticConfig } = require("tachi-common");
|
||||
const logger = require("./logger");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const DeterministicCollectionSort = require("./deterministic-collection-sort");
|
||||
const { RemoveUnderscoreID } = require("./remove-_id");
|
||||
|
||||
const program = new Command();
|
||||
program
|
||||
.option("-c, --connection <127.0.0.1:27017/my_database>")
|
||||
.option("-t, --useTabs")
|
||||
.option("-a, --all")
|
||||
.argument("[collection]");
|
||||
|
||||
program.parse(process.argv);
|
||||
const options = program.opts();
|
||||
|
||||
if (!options.connection) {
|
||||
throw new Error(`Please specify a database connection string with -c or --connection.`);
|
||||
}
|
||||
|
||||
// This will blow up horrifically if the connection URL is malformed.
|
||||
// Just don't do that, I guess!
|
||||
const db = monk(options.connection);
|
||||
|
||||
const collectionsDir = path.join(__dirname, "../collections");
|
||||
|
||||
const collections = [];
|
||||
|
||||
if (options.all) {
|
||||
collections.push("folders", "tables");
|
||||
collections.push(...StaticConfig.allSupportedGames.map((e) => `songs-${e}`));
|
||||
collections.push(...StaticConfig.allSupportedGames.map((e) => `charts-${e}`));
|
||||
} else if (program.args[0]) {
|
||||
collections.push(program.args[0]);
|
||||
}
|
||||
|
||||
// Add the songs-{game} and charts-{game} collections.
|
||||
|
||||
(async () => {
|
||||
logger.info(`Exporting ${collections.length} collections.`);
|
||||
|
||||
for (const collection of collections) {
|
||||
logger.info(`Exporting ${collection}.`);
|
||||
|
||||
await ExportCollection(collection);
|
||||
}
|
||||
|
||||
RemoveUnderscoreID();
|
||||
|
||||
DeterministicCollectionSort();
|
||||
|
||||
logger.info(`Done!`);
|
||||
|
||||
process.exit(0);
|
||||
})();
|
||||
|
||||
async function ExportCollection(collection) {
|
||||
const data = await db.get(collection).find({});
|
||||
logger.info(`Got ${data.length} documents.`);
|
||||
|
||||
const pt = path.join(collectionsDir, `${collection}.json`);
|
||||
fs.writeFileSync(pt, JSON.stringify(data, null, options.useTabs ? "\t" : undefined));
|
||||
|
||||
logger.info(`Wrote to ${pt}.`);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#! /bin/bash
|
||||
|
||||
# Exports data from a mongodb instance back to the collections
|
||||
# folder.
|
||||
# Useful for backporting updates, or something.
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
if [ -z "$1" ] || [ -z "$2" ]; then
|
||||
echo "Usage: mongoexp.sh <collection> <dbname>"
|
||||
exit
|
||||
fi
|
||||
|
||||
mongoexport -d "$2" -c "$1" --jsonArray > ../collections/"$1".json
|
||||
|
||||
node remove-_id.js
|
||||
node deterministic-collection-sort.js
|
||||
@@ -1,19 +0,0 @@
|
||||
const { IterateCollections } = require("./util");
|
||||
|
||||
function RemoveUnderscoreID() {
|
||||
IterateCollections((data) => {
|
||||
for (const d of data) {
|
||||
delete d._id;
|
||||
}
|
||||
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
RemoveUnderscoreID();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
RemoveUnderscoreID,
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
# Tachi Dev Stuff
|
||||
|
||||
Various stuff related to your local tachi dev container. These are mostly novelties,
|
||||
like having a pretty shell and good completions.
|
||||
@@ -0,0 +1,9 @@
|
||||
# define new permanent aliases here...
|
||||
|
||||
defnew g=git
|
||||
defnew gp=git push
|
||||
defnew gsw=git switch
|
||||
defnew gswc=git switch -c
|
||||
defnew gsm=git switch main
|
||||
defnew gl=git pull
|
||||
defnew rr="exec fish"
|
||||
@@ -1,20 +1,23 @@
|
||||
#! /bin/bash
|
||||
#!/bin/bash
|
||||
# moves example .env files, generates certificates, etc.
|
||||
|
||||
set -eox pipefail
|
||||
set -eo pipefail
|
||||
|
||||
|
||||
# https://stackoverflow.com/questions/59895/how-can-i-get-the-directory-where-a-bash-script-is-located-from-within-the-scrip
|
||||
# if you actually think bash is a good programming language you are
|
||||
# *straight up delusional*
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
cd "$SCRIPT_DIR";
|
||||
cd ..;
|
||||
|
||||
if [ -e I_HAVE_BOOTSTRAPPED_OK ]; then
|
||||
echo "Already bootstrapped."
|
||||
exit 0
|
||||
fi
|
||||
function installLocalDebs {
|
||||
for file in /tachi/dev/deb/*.deb; do
|
||||
sudo apt install -f -y "$file";
|
||||
done
|
||||
}
|
||||
|
||||
function setupShell {
|
||||
echo "Setting up fish..."
|
||||
fish dev/setup.fish
|
||||
}
|
||||
|
||||
function mvExampleFiles {
|
||||
echo "Moving example config files into usable places..."
|
||||
@@ -55,16 +58,14 @@ function pnpmInstall {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pnpm fetch
|
||||
pnpm install
|
||||
|
||||
# install ts-node aswell so people can use that inside enter-seeds.
|
||||
#
|
||||
# forcibly install this to /usr/local/bin because otherwise pnpm needs
|
||||
# a bunch of other env vars and needs to modify .bashrc and all that jazz
|
||||
#
|
||||
# we're installing a global binary; it should go in a global binary place
|
||||
# and this just works. sweet
|
||||
PNPM_HOME=/usr/local/bin pnpm install ts-node -g
|
||||
# This requires quite a bit of ceremony as pnpm wants to install to PNPM_HOME
|
||||
PATH=$PATH:~/.local/pnpm
|
||||
PNPM_HOME=~/.local/pnpm pnpm install ts-node -g
|
||||
|
||||
echo "Installed dependencies."
|
||||
}
|
||||
@@ -87,17 +88,26 @@ function syncDatabaseWithSeeds {
|
||||
(
|
||||
cd server
|
||||
|
||||
pnpm run sync-database-local
|
||||
pnpm run load-seeds
|
||||
)
|
||||
|
||||
echo "Synced."
|
||||
}
|
||||
|
||||
# always setup the shell
|
||||
setupShell
|
||||
|
||||
if [ -e I_HAVE_BOOTSTRAPPED_OK ]; then
|
||||
echo "Already bootstrapped."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mvExampleFiles
|
||||
selfSignHTTPS
|
||||
pnpmInstall
|
||||
setIndexes
|
||||
syncDatabaseWithSeeds
|
||||
installLocalDebs
|
||||
|
||||
echo "Bootstrap Complete."
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
MongoDB tools aren't available in apt. I want to have mongodb-database-tools inside the container.
|
||||
|
||||
I don't like having `curl | sh` inside containers, so I've saved the file to the repo.
|
||||
|
||||
Any `.deb` file in here will be installed inside the container.
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
for file in /tachi/dev/deb/*.deb; do
|
||||
apt install -y "$file"
|
||||
done
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
Copyright © Jorge Bucaran <<https://jorgebucaran.com>>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,193 @@
|
||||
# Fisher
|
||||
|
||||
> A plugin manager for [Fish](https://fishshell.com)—your friendly interactive shell. [Snag fresh plugins!](https://github.com/jorgebucaran/awsm.fish#readme)
|
||||
|
||||
Take control of functions, completions, bindings, and snippets from the command line. Unleash your shell's true potential, perfect your prompt, and craft repeatable configurations across different systems effortlessly. Fisher's zero impact on shell startup keeps your shell zippy and responsive. No gimmicks, just smooth sailing!
|
||||
|
||||
- Fisher is 100% pure-Fish, making it easy to contribute or modify
|
||||
- Scorching fast concurrent plugin downloads that'll make you question reality
|
||||
- Zero configuration needed—we're not kidding!
|
||||
- Oh My Fish! plugins supported too
|
||||
|
||||
> #### ☝️ [Upgrading from Fisher `3.x` or older? Strap in and read this!](https://github.com/jorgebucaran/fisher/issues/652)
|
||||
|
||||
## Installation
|
||||
|
||||
```console
|
||||
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
|
||||
Fisher lets you install, update, and remove plugins like a boss. Revel in Fish's [tab completion](https://fishshell.com/docs/current/index.html#completion) and rich syntax highlighting while you're at it.
|
||||
|
||||
### Installing plugins
|
||||
|
||||
To install plugins, use the `install` command and point it to the GitHub repository.
|
||||
|
||||
```console
|
||||
fisher install jorgebucaran/nvm.fish
|
||||
```
|
||||
|
||||
> Wanna install from GitLab? No problemo—just prepend `gitlab.com/` to the plugin path.
|
||||
|
||||
You can also snag a specific version of a plugin by adding an `@` symbol after the plugin name, followed by a tag, branch, or [commit](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefcommit-ishacommit-ishalsocommittish).
|
||||
|
||||
```console
|
||||
fisher install IlanCosman/tide@v5
|
||||
```
|
||||
|
||||
And hey, you can install plugins from a local directory too!
|
||||
|
||||
```console
|
||||
fisher install ~/path/to/plugin
|
||||
```
|
||||
|
||||
> Heads up! Fisher expands plugins into your Fish configuration directory by default, overwriting existing files. If that's not your jam, set `$fisher_path` to your preferred location and put it in your function path ([#640](https://github.com/jorgebucaran/fisher/issues/640)).
|
||||
|
||||
### Listing plugins
|
||||
|
||||
Use the `list` command to see all your shiny installed plugins.
|
||||
|
||||
```console
|
||||
$ fisher list
|
||||
jorgebucaran/fisher
|
||||
ilancosman/tide@v5
|
||||
jorgebucaran/nvm.fish
|
||||
/home/jb/path/to/plugin
|
||||
```
|
||||
|
||||
The `list` command also plays nice with regular expressions for filtering the output.
|
||||
|
||||
```console
|
||||
$ fisher list \^/
|
||||
/home/jb/path/to/plugin
|
||||
```
|
||||
|
||||
### Updating plugins
|
||||
|
||||
`update` command to the rescue! It updates one or more plugins to their latest and greatest version.
|
||||
|
||||
```console
|
||||
fisher update jorgebucaran/fisher
|
||||
```
|
||||
|
||||
> Just type `fisher update` to update everything in one fell swoop.
|
||||
|
||||
### Removing plugins
|
||||
|
||||
Say goodbye to installed plugins with the `remove` command.
|
||||
|
||||
```console
|
||||
fisher remove jorgebucaran/nvm.fish
|
||||
```
|
||||
|
||||
Feeling destructive? Wipe out everything, including Fisher itself.
|
||||
|
||||
```console
|
||||
fisher list | fisher remove
|
||||
```
|
||||
|
||||
## Using your `fish_plugins` file
|
||||
|
||||
Whenever you install or remove a plugin from the command line, Fisher jots down all the installed plugins in `$__fish_config_dir/fish_plugins`. Add this file to your dotfiles or version control to easily share your configuration across different systems.
|
||||
|
||||
You can also edit this file and run `fisher update` to commit changes like a pro:
|
||||
|
||||
```console
|
||||
$EDITOR $__fish_config_dir/fish_plugins
|
||||
```
|
||||
|
||||
```diff
|
||||
jorgebucaran/fisher
|
||||
ilancosman/tide@v5
|
||||
jorgebucaran/nvm.fish
|
||||
+ PatrickF1/fzf.fish
|
||||
- /home/jb/path/to/plugin
|
||||
```
|
||||
|
||||
```console
|
||||
fisher update
|
||||
```
|
||||
|
||||
This will install **PatrickF1**/**fzf.fish**, remove /**home**/**jb**/**path**/**to**/**plugin**, and update everything else.
|
||||
|
||||
## Creating a plugin
|
||||
|
||||
Plugins can include any number of files in `functions`, `conf.d`, and `completions` directories. Most plugins are just a single function or a [configuration snippet](https://fishshell.com/docs/current/index.html#configuration). Behold the anatomy of a typical plugin:
|
||||
|
||||
<pre>
|
||||
<b>flipper</b>
|
||||
├── <b>completions</b>
|
||||
│ └── flipper.fish
|
||||
├── <b>conf.d</b>
|
||||
│ └── flipper.fish
|
||||
└── <b>functions</b>
|
||||
└── flipper.fish
|
||||
</pre>
|
||||
|
||||
Non `.fish` files and directories inside these locations will be copied to `$fisher_path` under `functions`, `conf.d`, or `completions` respectively.
|
||||
|
||||
### Event system
|
||||
|
||||
Fish [events](https://fishshell.com/docs/current/cmds/emit.html) notify plugins when they're being installed, updated, or removed.
|
||||
|
||||
> Keep in mind, `--on-event` functions must be loaded when their event is emitted. So, place your event handlers in the `conf.d` directory.
|
||||
|
||||
```fish
|
||||
# Defined in flipper/conf.d/flipper.fish
|
||||
|
||||
function _flipper_install --on-event flipper_install
|
||||
# Set universal variables, create bindings, and other initialization logic.
|
||||
end
|
||||
|
||||
function _flipper_update --on-event flipper_update
|
||||
# Migrate resources, print warnings, and other update logic.
|
||||
end
|
||||
|
||||
function _flipper_uninstall --on-event flipper_uninstall
|
||||
# Erase "private" functions, variables, bindings, and other uninstall logic.
|
||||
end
|
||||
```
|
||||
|
||||
## Creating a theme
|
||||
|
||||
A theme is like any other Fish plugin, but with a `.theme` file in the `themes` directory. Themes were introduced in [Fish `3.4`](https://github.com/fish-shell/fish-shell/releases/tag/3.4.0) and work with the `fish_config` builtin. A theme can also have files in `functions`, `conf.d`, or `completions` if necessary. Check out what a typical theme plugin looks like:
|
||||
|
||||
<pre>
|
||||
<b>gills</b>
|
||||
├── <b>conf.d</b>
|
||||
│ └── gills.fish
|
||||
└── <b>themes</b>
|
||||
└── gills.theme
|
||||
</pre>
|
||||
|
||||
### Using `$fisher_path` with themes
|
||||
|
||||
If you customize `$fisher_path` to use a directory other than `$__fish_config_dir`, your themes won't be available via `fish_config`. That's because Fish expects your themes to be in `$__fish_config_dir/themes`, not `$fisher_path/themes`. This isn't configurable in Fish yet, but there's [a request to add that feature](https://github.com/fish-shell/fish-shell/issues/9456).
|
||||
|
||||
Fear not! You can easily solve this by symlinking Fisher's `themes` directory into your Fish config. First, backup any existing themes directory.
|
||||
|
||||
```console
|
||||
mv $__fish_config_dir/themes $__fish_config_dir/themes.bak
|
||||
```
|
||||
|
||||
Next, create a symlink for Fisher's themes directory.
|
||||
|
||||
```console
|
||||
ln -s $fisher_path/themes $__fish_config_dir/themes
|
||||
```
|
||||
|
||||
Want to use theme plugins and maintain your own local themes? You can do that too ([#708](https://github.com/jorgebucaran/fisher/issues/708)).
|
||||
|
||||
## Discoverability
|
||||
|
||||
While Fisher doesn't rely on a central plugin repository, discovering new plugins doesn't have to feel like navigating uncharted waters. To boost your plugin's visibility and make it easier for users to find, [add relevant topics to your repository](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics#adding-topics-to-your-repository) using [`fish-plugin`](https://github.com/topics/fish-plugin). By doing so, you're not only contributing to the Fisher community but also enabling users to explore new plugins and enhance their Fish shell experience. Don't let plugin discovery be a fishy business, tag your plugins today!
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
Fisher started its journey in 2016 by [@jorgebucaran](https://github.com/jorgebucaran) as a shell configuration manager for Fish. Along the way, many helped shape it into what it is today. [Oh My Fish](https://github.com/oh-my-fish/oh-my-fish) paved the way as the first popular Fish framework. [@jethrokuan](https://github.com/jethrokuan) provided crucial support during the early years. [@PatrickF1](https://github.com/PatrickF1)'s candid feedback proved invaluable time and again. Bootstrapping Fisher was originally [@IlanCosman](https://github.com/IlanCosman)'s brilliant idea. Thank you to all our contributors! <3
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE.md)
|
||||
@@ -0,0 +1,240 @@
|
||||
function fisher --argument-names cmd --description "A plugin manager for Fish"
|
||||
set --query fisher_path || set --local fisher_path $__fish_config_dir
|
||||
set --local fisher_version 4.4.4
|
||||
set --local fish_plugins $__fish_config_dir/fish_plugins
|
||||
|
||||
switch "$cmd"
|
||||
case -v --version
|
||||
echo "fisher, version $fisher_version"
|
||||
case "" -h --help
|
||||
echo "Usage: fisher install <plugins...> Install plugins"
|
||||
echo " fisher remove <plugins...> Remove installed plugins"
|
||||
echo " fisher update <plugins...> Update installed plugins"
|
||||
echo " fisher update Update all installed plugins"
|
||||
echo " fisher list [<regex>] List installed plugins matching regex"
|
||||
echo "Options:"
|
||||
echo " -v, --version Print version"
|
||||
echo " -h, --help Print this help message"
|
||||
echo "Variables:"
|
||||
echo " \$fisher_path Plugin installation path. Default: $__fish_config_dir" | string replace --regex -- $HOME \~
|
||||
case ls list
|
||||
string match --entire --regex -- "$argv[2]" $_fisher_plugins
|
||||
case install update remove
|
||||
isatty || read --local --null --array stdin && set --append argv $stdin
|
||||
|
||||
set --local install_plugins
|
||||
set --local update_plugins
|
||||
set --local remove_plugins
|
||||
set --local arg_plugins $argv[2..-1]
|
||||
set --local old_plugins $_fisher_plugins
|
||||
set --local new_plugins
|
||||
|
||||
test -e $fish_plugins && set --local file_plugins (string match --regex -- '^[^\s]+$' <$fish_plugins)
|
||||
|
||||
if ! set --query argv[2]
|
||||
if test "$cmd" != update
|
||||
echo "fisher: Not enough arguments for command: \"$cmd\"" >&2 && return 1
|
||||
else if ! set --query file_plugins
|
||||
echo "fisher: \"$fish_plugins\" file not found: \"$cmd\"" >&2 && return 1
|
||||
end
|
||||
set arg_plugins $file_plugins
|
||||
end
|
||||
|
||||
for plugin in $arg_plugins
|
||||
set plugin (test -e "$plugin" && realpath $plugin || string lower -- $plugin)
|
||||
contains -- "$plugin" $new_plugins || set --append new_plugins $plugin
|
||||
end
|
||||
|
||||
if set --query argv[2]
|
||||
for plugin in $new_plugins
|
||||
if contains -- "$plugin" $old_plugins
|
||||
test "$cmd" = remove &&
|
||||
set --append remove_plugins $plugin ||
|
||||
set --append update_plugins $plugin
|
||||
else if test "$cmd" = install
|
||||
set --append install_plugins $plugin
|
||||
else
|
||||
echo "fisher: Plugin not installed: \"$plugin\"" >&2 && return 1
|
||||
end
|
||||
end
|
||||
else
|
||||
for plugin in $new_plugins
|
||||
contains -- "$plugin" $old_plugins &&
|
||||
set --append update_plugins $plugin ||
|
||||
set --append install_plugins $plugin
|
||||
end
|
||||
|
||||
for plugin in $old_plugins
|
||||
contains -- "$plugin" $new_plugins || set --append remove_plugins $plugin
|
||||
end
|
||||
end
|
||||
|
||||
set --local pid_list
|
||||
set --local source_plugins
|
||||
set --local fetch_plugins $update_plugins $install_plugins
|
||||
set --local fish_path (status fish-path)
|
||||
|
||||
echo (set_color --bold)fisher $cmd version $fisher_version(set_color normal)
|
||||
|
||||
for plugin in $fetch_plugins
|
||||
set --local source (command mktemp -d)
|
||||
set --append source_plugins $source
|
||||
|
||||
command mkdir -p $source/{completions,conf.d,themes,functions}
|
||||
|
||||
$fish_path --command "
|
||||
if test -e $plugin
|
||||
command cp -Rf $plugin/* $source
|
||||
else
|
||||
set temp (command mktemp -d)
|
||||
set repo (string split -- \@ $plugin) || set repo[2] HEAD
|
||||
|
||||
if set path (string replace --regex -- '^(https://)?gitlab.com/' '' \$repo[1])
|
||||
set name (string split -- / \$path)[-1]
|
||||
set url https://gitlab.com/\$path/-/archive/\$repo[2]/\$name-\$repo[2].tar.gz
|
||||
else
|
||||
set url https://api.github.com/repos/\$repo[1]/tarball/\$repo[2]
|
||||
end
|
||||
|
||||
echo Fetching (set_color --underline)\$url(set_color normal)
|
||||
|
||||
if command curl -q --silent -L \$url | command tar -xzC \$temp -f - 2>/dev/null
|
||||
command cp -Rf \$temp/*/* $source
|
||||
else
|
||||
echo fisher: Invalid plugin name or host unavailable: \\\"$plugin\\\" >&2
|
||||
command rm -rf $source
|
||||
end
|
||||
|
||||
command rm -rf \$temp
|
||||
end
|
||||
|
||||
set files $source/* && string match --quiet --regex -- .+\.fish\\\$ \$files
|
||||
" &
|
||||
|
||||
set --append pid_list (jobs --last --pid)
|
||||
end
|
||||
|
||||
wait $pid_list 2>/dev/null
|
||||
|
||||
for plugin in $fetch_plugins
|
||||
if set --local source $source_plugins[(contains --index -- "$plugin" $fetch_plugins)] && test ! -e $source
|
||||
if set --local index (contains --index -- "$plugin" $install_plugins)
|
||||
set --erase install_plugins[$index]
|
||||
else
|
||||
set --erase update_plugins[(contains --index -- "$plugin" $update_plugins)]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for plugin in $update_plugins $remove_plugins
|
||||
if set --local index (contains --index -- "$plugin" $_fisher_plugins)
|
||||
set --local plugin_files_var _fisher_(string escape --style=var -- $plugin)_files
|
||||
|
||||
if contains -- "$plugin" $remove_plugins
|
||||
for name in (string replace --filter --regex -- '.+/conf\.d/([^/]+)\.fish$' '$1' $$plugin_files_var)
|
||||
emit {$name}_uninstall
|
||||
end
|
||||
printf "%s\n" Removing\ (set_color red --bold)$plugin(set_color normal) " "$$plugin_files_var | string replace -- \~ ~
|
||||
set --erase _fisher_plugins[$index]
|
||||
end
|
||||
|
||||
command rm -rf (string replace -- \~ ~ $$plugin_files_var)
|
||||
|
||||
functions --erase (string replace --filter --regex -- '.+/functions/([^/]+)\.fish$' '$1' $$plugin_files_var)
|
||||
|
||||
for name in (string replace --filter --regex -- '.+/completions/([^/]+)\.fish$' '$1' $$plugin_files_var)
|
||||
complete --erase --command $name
|
||||
end
|
||||
|
||||
set --erase $plugin_files_var
|
||||
end
|
||||
end
|
||||
|
||||
if set --query update_plugins[1] || set --query install_plugins[1]
|
||||
command mkdir -p $fisher_path/{functions,themes,conf.d,completions}
|
||||
end
|
||||
|
||||
for plugin in $update_plugins $install_plugins
|
||||
set --local source $source_plugins[(contains --index -- "$plugin" $fetch_plugins)]
|
||||
set --local files $source/{functions,themes,conf.d,completions}/*
|
||||
|
||||
if set --local index (contains --index -- $plugin $install_plugins)
|
||||
set --local user_files $fisher_path/{functions,themes,conf.d,completions}/*
|
||||
set --local conflict_files
|
||||
|
||||
for file in (string replace -- $source/ $fisher_path/ $files)
|
||||
contains -- $file $user_files && set --append conflict_files $file
|
||||
end
|
||||
|
||||
if set --query conflict_files[1] && set --erase install_plugins[$index]
|
||||
echo -s "fisher: Cannot install \"$plugin\": please remove or move conflicting files first:" \n" "$conflict_files >&2
|
||||
continue
|
||||
end
|
||||
end
|
||||
|
||||
for file in (string replace -- $source/ "" $files)
|
||||
command cp -RLf $source/$file $fisher_path/$file
|
||||
end
|
||||
|
||||
set --local plugin_files_var _fisher_(string escape --style=var -- $plugin)_files
|
||||
|
||||
set --query files[1] && set --universal $plugin_files_var (string replace -- $source $fisher_path $files | string replace -- ~ \~)
|
||||
|
||||
contains -- $plugin $_fisher_plugins || set --universal --append _fisher_plugins $plugin
|
||||
contains -- $plugin $install_plugins && set --local event install || set --local event update
|
||||
|
||||
printf "%s\n" Installing\ (set_color --bold)$plugin(set_color normal) " "$$plugin_files_var | string replace -- \~ ~
|
||||
|
||||
for file in (string match --regex -- '.+/[^/]+\.fish$' $$plugin_files_var | string replace -- \~ ~)
|
||||
source $file
|
||||
if set --local name (string replace --regex -- '.+conf\.d/([^/]+)\.fish$' '$1' $file)
|
||||
emit {$name}_$event
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
command rm -rf $source_plugins
|
||||
|
||||
if set --query _fisher_plugins[1]
|
||||
set --local commit_plugins
|
||||
|
||||
for plugin in $file_plugins
|
||||
contains -- (string lower -- $plugin) (string lower -- $_fisher_plugins) && set --append commit_plugins $plugin
|
||||
end
|
||||
|
||||
for plugin in $_fisher_plugins
|
||||
contains -- (string lower -- $plugin) (string lower -- $commit_plugins) || set --append commit_plugins $plugin
|
||||
end
|
||||
|
||||
printf "%s\n" $commit_plugins >$fish_plugins
|
||||
else
|
||||
set --erase _fisher_plugins
|
||||
command rm -f $fish_plugins
|
||||
end
|
||||
|
||||
set --local total (count $install_plugins) (count $update_plugins) (count $remove_plugins)
|
||||
|
||||
test "$total" != "0 0 0" && echo (string join ", " (
|
||||
test $total[1] = 0 || echo "Installed $total[1]") (
|
||||
test $total[2] = 0 || echo "Updated $total[2]") (
|
||||
test $total[3] = 0 || echo "Removed $total[3]")
|
||||
) plugin/s
|
||||
case \*
|
||||
echo "fisher: Unknown command: \"$cmd\"" >&2 && return 1
|
||||
end
|
||||
end
|
||||
|
||||
if ! set --query _fisher_upgraded_to_4_4
|
||||
set --universal _fisher_upgraded_to_4_4
|
||||
if functions --query _fisher_list
|
||||
set --query XDG_DATA_HOME[1] || set --local XDG_DATA_HOME ~/.local/share
|
||||
command rm -rf $XDG_DATA_HOME/fisher
|
||||
functions --erase _fisher_{list,plugin_parse}
|
||||
fisher update >/dev/null 2>/dev/null
|
||||
else
|
||||
for var in (set --names | string match --entire --regex '^_fisher_.+_files$')
|
||||
set $var (string replace -- ~ \~ $$var)
|
||||
end
|
||||
functions --erase _fisher_fish_postexec
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2017-2021 Wenxuan Zhang <wenxuangm@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the “Software”), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,376 @@
|
||||
<h1 align="center">💤 forgit</h1>
|
||||
<p align="center">
|
||||
<em>Utility tool for using git interactively. Powered by <a href="https://github.com/junegunn/fzf">junegunn/fzf</a>.</em>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/wfxr/forgit/actions">
|
||||
<img src="https://github.com/wfxr/forgit/workflows/ci/badge.svg"/>
|
||||
</a>
|
||||
<a href="https://wfxr.mit-license.org/2017">
|
||||
<img src="https://img.shields.io/badge/License-MIT-brightgreen.svg"/>
|
||||
</a>
|
||||
<a href="https://img.shields.io/badge/Shell-Bash%20%7C%20Zsh%20%7C%20Fish-blue">
|
||||
<img src="https://img.shields.io/badge/Shell-Bash%20%7C%20Zsh%20%7C%20Fish-blue"/>
|
||||
</a>
|
||||
<a href="https://github.com/unixorn/awesome-zsh-plugins">
|
||||
<img src="https://img.shields.io/badge/Awesome-zsh--plugins-d07cd0?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABVklEQVRIS+3VvWpVURDF8d9CRAJapBAfwWCt+FEJthIUUcEm2NgIYiOxsrCwULCwktjYKSgYLfQF1JjCNvoMNhYRCwOO7HAiVw055yoBizvN3nBmrf8+M7PZsc2RbfY3AfRWeNMSVdUlHEzS1t6oqvt4n+TB78l/AKpqHrdwLcndXndU1WXcw50k10c1PwFV1fa3cQVzSR4PMd/IqaoLeIj2N1eTfG/f1gFVtQMLOI+zSV6NYz4COYFneIGLSdZSVbvwCMdxMsnbvzEfgRzCSyzjXAO8xlHcxMq/mI9oD+AGlhqgxjD93OVOD9TUuICdXd++/VeAVewecKKv2NPlfcHUAM1qK9FTnBmQvJjkdDfWzzE7QPOkAfZiEce2ECzhVJJPHWAfGuTwFpo365pO0NYjmEFr5Eas4SPeJfll2rqb38Z7/yaaD+0eNM3kPejt86REvSX6AamgdXkgoxLxAAAAAElFTkSuQmCC"/>
|
||||
</a>
|
||||
<a href="https://github.com/pre-commit/pre-commit">
|
||||
<img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white" alt="pre-commit" />
|
||||
</a>
|
||||
<a href="https://github.com/wfxr/forgit/graphs/contributors">
|
||||
<img src="https://img.shields.io/github/contributors/wfxr/forgit" alt="Contributors"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
This tool is designed to help you use git more efficiently.
|
||||
It's **lightweight** and **easy to use**.
|
||||
|
||||
# 📥 Installation
|
||||
|
||||
*Make sure you have [`fzf`](https://github.com/junegunn/fzf) installed.*
|
||||
|
||||
``` zsh
|
||||
# for zplug
|
||||
zplug 'wfxr/forgit'
|
||||
|
||||
# for zgen
|
||||
zgen load 'wfxr/forgit'
|
||||
|
||||
# for antigen
|
||||
antigen bundle 'wfxr/forgit'
|
||||
|
||||
# for fisher (requires fisher v4.4.3 or higher)
|
||||
fisher install wfxr/forgit
|
||||
|
||||
# for omf
|
||||
omf install https://github.com/wfxr/forgit
|
||||
|
||||
# for zinit
|
||||
zinit load wfxr/forgit
|
||||
|
||||
# for oh-my-zsh
|
||||
git clone https://github.com/wfxr/forgit.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/forgit
|
||||
|
||||
# manually
|
||||
# Clone the repository and source it in your shell's rc file or put bin/git-forgit into your $PATH
|
||||
```
|
||||
|
||||
## Homebrew
|
||||
|
||||
To install using brew
|
||||
```sh
|
||||
brew install forgit
|
||||
```
|
||||
|
||||
Then add the following to your shell's config file:
|
||||
```sh
|
||||
# Fish:
|
||||
# ~/.config/fish/config.fish:
|
||||
[ -f $HOMEBREW_PREFIX/share/forgit/forgit.plugin.fish ]; and source $HOMEBREW_PREFIX/share/forgit/forgit.plugin.fish
|
||||
|
||||
# Zsh:
|
||||
# ~/.zshrc:
|
||||
[ -f $HOMEBREW_PREFIX/share/forgit/forgit.plugin.zsh ] && source $HOMEBREW_PREFIX/share/forgit/forgit.plugin.zsh
|
||||
|
||||
# Bash:
|
||||
# ~/.bashrc:
|
||||
[ -f $HOMEBREW_PREFIX/share/forgit/forgit.plugin.sh ] && source $HOMEBREW_PREFIX/share/forgit/forgit.plugin.sh
|
||||
```
|
||||
|
||||
## Fig
|
||||
|
||||
[Fig](https://fig.io) adds apps, shortcuts, and autocomplete to your existing terminal.
|
||||
|
||||
Install `forgit` in just one click.
|
||||
|
||||
[](https://fig.io/plugins/other/forgit)
|
||||
|
||||
## Arch User Repository
|
||||
|
||||
[AUR](https://wiki.archlinux.org/title/Arch_User_Repository) packages, maintained by the developers of forgit, are available. Install the [forgit](https://aur.archlinux.org/packages/forgit) package for the latest release or [forgit-git](https://aur.archlinux.org/packages/forgit-git) to stay up to date with the latest commits from the master branch of this repository.
|
||||
|
||||
# 📝 Features
|
||||
|
||||
- **Interactive `git add` selector** (`ga`)
|
||||
|
||||

|
||||
|
||||
- **Interactive `git log` viewer** (`glo`)
|
||||
|
||||

|
||||
|
||||
*The log graph can be disabled by option `FORGIT_LOG_GRAPH_ENABLE` (see discuss in [issue #71](https://github.com/wfxr/forgit/issues/71)).*
|
||||
|
||||
- **Interactive `.gitignore` generator** (`gi`)
|
||||
|
||||

|
||||
|
||||
- **Interactive `git diff` viewer** (`gd`)
|
||||
|
||||
- **Interactive `git reset HEAD <file>` selector** (`grh`)
|
||||
|
||||
- **Interactive `git checkout <file>` selector** (`gcf`)
|
||||
|
||||
- **Interactive `git checkout <branch>` selector** (`gcb`)
|
||||
|
||||
- **Interactive `git branch -D <branch>` selector** (`gbd`)
|
||||
|
||||
- **Interactive `git checkout <tag>` selector** (`gct`)
|
||||
|
||||
- **Interactive `git checkout <commit>` selector** (`gco`)
|
||||
|
||||
- **Interactive `git revert <commit>` selector** (`grc`)
|
||||
|
||||
- **Interactive `git stash` viewer** (`gss`)
|
||||
|
||||
- **Interactive `git stash push` selector** (`gsp`)
|
||||
|
||||
- **Interactive `git clean` selector** (`gclean`)
|
||||
|
||||
- **Interactive `git cherry-pick` selector** (`gcp`)
|
||||
|
||||
- **Interactive `git rebase -i` selector** (`grb`)
|
||||
|
||||
- **Interactive `git blame` selector** (`gbl`)
|
||||
|
||||
- **Interactive `git commit --fixup && git rebase -i --autosquash` selector** (`gfu`)
|
||||
|
||||
# ⌨ Keybindings
|
||||
|
||||
| Key | Action |
|
||||
| :-------------------------------------------: | ------------------------------------------- |
|
||||
| <kbd>Enter</kbd> | Confirm |
|
||||
| <kbd>Tab</kbd> | Toggle mark and move down |
|
||||
| <kbd>Shift</kbd> - <kbd>Tab</kbd> | Toggle mark and move up |
|
||||
| <kbd>?</kbd> | Toggle preview window |
|
||||
| <kbd>Alt</kbd> - <kbd>W</kbd> | Toggle preview wrap |
|
||||
| <kbd>Ctrl</kbd> - <kbd>S</kbd> | Toggle sort |
|
||||
| <kbd>Ctrl</kbd> - <kbd>R</kbd> | Toggle selection |
|
||||
| <kbd>Ctrl</kbd> - <kbd>Y</kbd> | Copy commit hash/stash ID* |
|
||||
| <kbd>Ctrl</kbd> - <kbd>K</kbd> / <kbd>P</kbd> | Selection move up |
|
||||
| <kbd>Ctrl</kbd> - <kbd>J</kbd> / <kbd>N</kbd> | Selection move down |
|
||||
| <kbd>Alt</kbd> - <kbd>K</kbd> / <kbd>P</kbd> | Preview move up |
|
||||
| <kbd>Alt</kbd> - <kbd>J</kbd> / <kbd>N</kbd> | Preview move down |
|
||||
| <kbd>Alt</kbd> - <kbd>E</kbd> | Open file in default editor (when possible) |
|
||||
|
||||
\* Available when the selection contains a commit hash or a stash ID.
|
||||
For Linux users `FORGIT_COPY_CMD` should be set to make copy work. Example: `FORGIT_COPY_CMD='xclip -selection clipboard'`.
|
||||
|
||||
# ⚙ Options
|
||||
|
||||
Options can be set via environment variables. They have to be **exported** in
|
||||
order to be recognized by `forgit`.
|
||||
|
||||
For instance, if you want to order branches in `gcb` by the last committed date you could:
|
||||
|
||||
```shell
|
||||
export FORGIT_CHECKOUT_BRANCH_BRANCH_GIT_OPTS='--sort=-committerdate'
|
||||
```
|
||||
|
||||
## shell aliases
|
||||
|
||||
You can change the default aliases by defining these variables below.
|
||||
(To disable all aliases, Set the `FORGIT_NO_ALIASES` flag.)
|
||||
|
||||
``` bash
|
||||
forgit_log=glo
|
||||
forgit_diff=gd
|
||||
forgit_add=ga
|
||||
forgit_reset_head=grh
|
||||
forgit_ignore=gi
|
||||
forgit_checkout_file=gcf
|
||||
forgit_checkout_branch=gcb
|
||||
forgit_branch_delete=gbd
|
||||
forgit_checkout_tag=gct
|
||||
forgit_checkout_commit=gco
|
||||
forgit_revert_commit=grc
|
||||
forgit_clean=gclean
|
||||
forgit_stash_show=gss
|
||||
forgit_stash_push=gsp
|
||||
forgit_cherry_pick=gcp
|
||||
forgit_rebase=grb
|
||||
forgit_blame=gbl
|
||||
forgit_fixup=gfu
|
||||
```
|
||||
|
||||
## git integration
|
||||
|
||||
You can use forgit as a sub-command of git by making `git-forgit` available in `$PATH`:
|
||||
|
||||
```sh
|
||||
# after `forgit` was loaded
|
||||
PATH="$PATH:$FORGIT_INSTALL_DIR/bin"
|
||||
```
|
||||
|
||||
*Some plugin managers can help do this.*
|
||||
|
||||
Then, any forgit command will be a sub-command of git:
|
||||
|
||||
```cmd
|
||||
git forgit log
|
||||
git forgit add
|
||||
git forgit diff
|
||||
```
|
||||
|
||||
Optionally you can add [aliases in git](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases):
|
||||
|
||||
```sh
|
||||
git config --global alias.cf 'forgit checkout_file'
|
||||
```
|
||||
|
||||
And use forgit functions via a git alias:
|
||||
|
||||
```sh
|
||||
git cf
|
||||
```
|
||||
|
||||
## git options
|
||||
|
||||
If you want to customize `git`'s behavior within forgit there is a dedicated variable for each forgit command.
|
||||
These are passed to the according `git` calls.
|
||||
|
||||
| Command | Option |
|
||||
| -------- | --------------------------------------------------------------------------- |
|
||||
| `ga` | `FORGIT_ADD_GIT_OPTS` |
|
||||
| `glo` | `FORGIT_LOG_GIT_OPTS` |
|
||||
| `gd` | `FORGIT_DIFF_GIT_OPTS` |
|
||||
| `grh` | `FORGIT_RESET_HEAD_GIT_OPTS` |
|
||||
| `gcf` | `FORGIT_CHECKOUT_FILE_GIT_OPTS` |
|
||||
| `gcb` | `FORGIT_CHECKOUT_BRANCH_GIT_OPTS`, `FORGIT_CHECKOUT_BRANCH_BRANCH_GIT_OPTS` |
|
||||
| `gbd` | `FORGIT_BRANCH_DELETE_GIT_OPTS` |
|
||||
| `gct` | `FORGIT_CHECKOUT_TAG_GIT_OPTS` |
|
||||
| `gco` | `FORGIT_CHECKOUT_COMMIT_GIT_OPTS` |
|
||||
| `grc` | `FORGIT_REVERT_COMMIT_GIT_OPTS` |
|
||||
| `gss` | `FORGIT_STASH_SHOW_GIT_OPTS` |
|
||||
| `gsp` | `FORGIT_STASH_PUSH_GIT_OPTS` |
|
||||
| `gclean` | `FORGIT_CLEAN_GIT_OPTS` |
|
||||
| `grb` | `FORGIT_REBASE_GIT_OPTS` |
|
||||
| `gbl` | `FORGIT_BLAME_GIT_OPTS` |
|
||||
| `gfu` | `FORGIT_FIXUP_GIT_OPTS` |
|
||||
| `gcp` | `FORGIT_CHERRY_PICK_GIT_OPTS` |
|
||||
|
||||
## pagers
|
||||
|
||||
Forgit will use the default configured pager from git (`core.pager`,
|
||||
`pager.show`, `pager.diff`) but can be altered with the following environment
|
||||
variables:
|
||||
|
||||
| Use case | Option | Fallbacks to |
|
||||
| ------------ | ------------------- | --------------------------------------------- |
|
||||
| common pager | `FORGIT_PAGER` | `git config core.pager` _or_ `cat` |
|
||||
| pager on `git show` | `FORGIT_SHOW_PAGER` | `git config pager.show` _or_ `$FORGIT_PAGER` |
|
||||
| pager on `git diff` | `FORGIT_DIFF_PAGER` | `git config pager.diff` _or_ `$FORGIT_PAGER` |
|
||||
| pager on `git blame` | `FORGIT_BLAME_PAGER` | `git config pager.blame` _or_ `$FORGIT_PAGER` |
|
||||
| pager on `gitignore` | `FORGIT_IGNORE_PAGER` | `bat -l gitignore --color always` _or_ `cat` |
|
||||
| git log format | `FORGIT_GLO_FORMAT` | `%C(auto)%h%d %s %C(black)%C(bold)%cr%reset` |
|
||||
|
||||
## fzf options
|
||||
|
||||
You can add default fzf options for `forgit`, including keybindings, layout, etc.
|
||||
(No need to repeat the options already defined in `FZF_DEFAULT_OPTS`)
|
||||
|
||||
``` bash
|
||||
export FORGIT_FZF_DEFAULT_OPTS="
|
||||
--exact
|
||||
--border
|
||||
--cycle
|
||||
--reverse
|
||||
--height '80%'
|
||||
"
|
||||
```
|
||||
|
||||
Customizing fzf options for each command individually is also supported:
|
||||
|
||||
| Command | Option |
|
||||
|----------|-----------------------------------|
|
||||
| `ga` | `FORGIT_ADD_FZF_OPTS` |
|
||||
| `glo` | `FORGIT_LOG_FZF_OPTS` |
|
||||
| `gi` | `FORGIT_IGNORE_FZF_OPTS` |
|
||||
| `gd` | `FORGIT_DIFF_FZF_OPTS` |
|
||||
| `grh` | `FORGIT_RESET_HEAD_FZF_OPTS` |
|
||||
| `gcf` | `FORGIT_CHECKOUT_FILE_FZF_OPTS` |
|
||||
| `gcb` | `FORGIT_CHECKOUT_BRANCH_FZF_OPTS` |
|
||||
| `gbd` | `FORGIT_BRANCH_DELETE_FZF_OPTS` |
|
||||
| `gct` | `FORGIT_CHECKOUT_TAG_FZF_OPTS` |
|
||||
| `gco` | `FORGIT_CHECKOUT_COMMIT_FZF_OPTS` |
|
||||
| `grc` | `FORGIT_REVERT_COMMIT_FZF_OPTS` |
|
||||
| `gss` | `FORGIT_STASH_FZF_OPTS` |
|
||||
| `gsp` | `FORGIT_STASH_PUSH_FZF_OPTS` |
|
||||
| `gclean` | `FORGIT_CLEAN_FZF_OPTS` |
|
||||
| `grb` | `FORGIT_REBASE_FZF_OPTS` |
|
||||
| `gbl` | `FORGIT_BLAME_FZF_OPTS` |
|
||||
| `gfu` | `FORGIT_FIXUP_FZF_OPTS` |
|
||||
| `gcp` | `FORGIT_CHERRY_PICK_FZF_OPTS` |
|
||||
|
||||
Complete loading order of fzf options is:
|
||||
|
||||
1. `FZF_DEFAULT_OPTS` (fzf global)
|
||||
2. `FORGIT_FZF_DEFAULT_OPTS` (forgit global)
|
||||
3. `FORGIT_CMD_FZF_OPTS` (command specific)
|
||||
|
||||
Examples:
|
||||
|
||||
- `ctrl-d` to drop the selected stash but do not quit fzf (`gss` specific).
|
||||
|
||||
```sh
|
||||
export FORGIT_STASH_FZF_OPTS='
|
||||
--bind="ctrl-d:reload(git stash drop $(cut -d: -f1 <<<{}) 1>/dev/null && git stash list)"
|
||||
'
|
||||
```
|
||||
|
||||
- `ctrl-e` to view the logs in a vim buffer (`glo` specific).
|
||||
|
||||
```sh
|
||||
export FORGIT_LOG_FZF_OPTS='
|
||||
--bind="ctrl-e:execute(echo {} |grep -Eo [a-f0-9]+ |head -1 |xargs git show |vim -)"
|
||||
'
|
||||
```
|
||||
|
||||
## other options
|
||||
|
||||
| Option | Description | Default |
|
||||
|-----------------------------|-------------------------------------------|-----------------------------------------------|
|
||||
| `FORGIT_LOG_FORMAT` | git log format | `%C(auto)%h%d %s %C(black)%C(bold)%cr%Creset` |
|
||||
| `FORGIT_PREVIEW_CONTEXT` | lines of diff context in preview mode | 3 |
|
||||
| `FORGIT_FULLSCREEN_CONTEXT` | lines of diff context in full-screen mode | 10 |
|
||||
| `FORGIT_DIR_VIEW` | command used to preview directories | `tree` if available, otherwise `find` |
|
||||
|
||||
# 📦 Optional dependencies
|
||||
|
||||
- [`delta`](https://github.com/dandavison/delta) / [`diff-so-fancy`](https://github.com/so-fancy/diff-so-fancy): For better human-readable diffs.
|
||||
|
||||
- [`bat`](https://github.com/sharkdp/bat.git): Syntax highlighting for `gitignore`.
|
||||
|
||||
- [`emoji-cli`](https://github.com/wfxr/emoji-cli): Emoji support for `git log`.
|
||||
|
||||
# Completions
|
||||
|
||||
## Bash
|
||||
|
||||
- Put [`completions/git-forgit.bash`](https://github.com/wfxr/forgit/blob/master/completions/git-forgit.bash) in
|
||||
`~/.local/share/bash-completion/completions` to have bash tab completion for `git forgit` and configured git aliases.
|
||||
- Source [`completions/git-forgit.bash`](https://github.com/wfxr/forgit/blob/master/completions/git-forgit.bash) explicitly to have
|
||||
bash tab completion for forgit shell functions and aliases (e.g., `gcb <tab>` completes branches).
|
||||
|
||||
## Zsh
|
||||
|
||||
- Put [`completions/_git-forgit`](completions/_git-forgit) in a directory in your `$fpath` (e.g., `/usr/share/zsh/site-functions`) to have zsh tab completion for `git forgit` and configured git aliases, as well as shell command aliases, such as `forgit::add` and `ga`
|
||||
|
||||
If you're having issues after updating, and commands such as `forgit::add` or aliases `ga` aren't working, remove your completions cache and restart your shell.
|
||||
|
||||
```zsh
|
||||
> rm ~/.zcompdump
|
||||
> zsh
|
||||
```
|
||||
|
||||
# 💡 Tips
|
||||
|
||||
- Most of the commands accept optional arguments (e.g., `glo develop`, `glo f738479..188a849b -- main.go`, `gco master`).
|
||||
- `gd` supports specifying revision(e.g., `gd HEAD~`, `gd v1.0 README.md`).
|
||||
- Call `gi` with arguments to get the wanted `.gitignore` contents directly(e.g., `gi cmake c++`).
|
||||
|
||||
# 📃 License
|
||||
|
||||
[MIT](https://wfxr.mit-license.org/2017) (c) Wenxuan Zhang
|
||||
Executable
+1044
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
#
|
||||
# forgit completions for fish plugin
|
||||
#
|
||||
# Place this file inside your <fish_config_dir>/completions/ directory.
|
||||
# It's usually located at ~/.config/fish/completions/. The file is lazily
|
||||
# sourced when git-forgit command or forgit subcommand of git is invoked.
|
||||
|
||||
function __fish_forgit_needs_subcommand
|
||||
for subcmd in add blame branch_delete checkout_branch checkout_commit checkout_file checkout_tag \
|
||||
cherry_pick cherry_pick_from_branch clean diff fixup ignore log rebase reset_head revert_commit \
|
||||
stash_show stash_push
|
||||
if contains -- $subcmd (commandline -opc)
|
||||
return 1
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
# Load helper functions in git completion file
|
||||
not functions -q __fish_git && source $__fish_data_dir/completions/git.fish
|
||||
|
||||
# No file completion by default
|
||||
complete -c git-forgit -x
|
||||
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a add -d 'git add selector'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a blame -d 'git blame viewer'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a branch_delete -d 'git branch deletion selector'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a checkout_branch -d 'git checkout branch selector'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a checkout_commit -d 'git checkout commit selector'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a checkout_file -d 'git checkout-file selector'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a checkout_tag -d 'git checkout tag selector'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a cherry_pick -d 'git cherry-picking'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a cherry_pick_from_branch -d 'git cherry-picking with interactive branch selection'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a clean -d 'git clean selector'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a diff -d 'git diff viewer'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a fixup -d 'git fixup'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a ignore -d 'git ignore generator'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a log -d 'git commit viewer'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a rebase -d 'git rebase'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a reset_head -d 'git reset HEAD (unstage) selector'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a revert_commit -d 'git revert commit selector'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a stash_show -d 'git stash viewer'
|
||||
complete -c git-forgit -n __fish_forgit_needs_subcommand -a stash_push -d 'git stash push selector'
|
||||
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from add' -a "(complete -C 'git add ')"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from branch_delete' -a "(__fish_git_local_branches)"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from checkout_branch' -a "(complete -C 'git switch ')"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from checkout_commit' -a "(__fish_git_commits)"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from checkout_file' -a "(__fish_git_files modified)"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from checkout_tag' -a "(__fish_git_tags)" -d Tag
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from cherry_pick' -a "(complete -C 'git cherry-pick ')"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from clean' -a "(__fish_git_files untracked ignored)"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from fixup' -a "(__fish_git_local_branches)"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from log' -a "(complete -C 'git log ')"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from rebase' -a "(complete -C 'git rebase ')"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from reset_head' -a "(__fish_git_files all-staged)"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from revert_commit' -a "(__fish_git_commits)"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from stash_show' -a "(__fish_git_complete_stashes)"
|
||||
complete -c git-forgit -n '__fish_seen_subcommand_from stash_push' -a "(__fish_git_files modified deleted modified-staged-deleted)"
|
||||
@@ -0,0 +1,53 @@
|
||||
# MIT (c) Chris Apple
|
||||
|
||||
set -l install_dir (dirname (status dirname))
|
||||
set -x FORGIT_INSTALL_DIR "$install_dir/conf.d"
|
||||
set -x FORGIT "$FORGIT_INSTALL_DIR/bin/git-forgit"
|
||||
if not test -e "$FORGIT"
|
||||
set -x FORGIT_INSTALL_DIR "$install_dir/vendor_conf.d"
|
||||
set -x FORGIT "$FORGIT_INSTALL_DIR/bin/git-forgit"
|
||||
end
|
||||
|
||||
function forgit::warn
|
||||
printf "%b[Warn]%b %s\n" '\e[0;33m' '\e[0m' "$argv" >&2
|
||||
end
|
||||
|
||||
# backwards compatibility:
|
||||
# export all user-defined FORGIT variables to make them available in git-forgit
|
||||
set unexported_vars 0
|
||||
set | awk -F ' ' '{ print $1 }' | grep FORGIT_ | while read var
|
||||
if not set -x | grep -q "^$var\b"
|
||||
if test $unexported_vars = 0
|
||||
forgit::warn "Config options have to be exported in future versions of forgit."
|
||||
forgit::warn "Please update your config accordingly:"
|
||||
end
|
||||
forgit::warn " set -x $var \"$$var\""
|
||||
set unexported_vars (math $unexported_vars + 1)
|
||||
set -x $var $$var
|
||||
end
|
||||
end
|
||||
|
||||
# alias `git-forgit` to the full-path of the command
|
||||
alias git-forgit "$FORGIT"
|
||||
|
||||
# register abbreviations
|
||||
if test -z "$FORGIT_NO_ALIASES"
|
||||
abbr -a -- (string collect $forgit_add; or string collect "ga") git-forgit add
|
||||
abbr -a -- (string collect $forgit_reset_head; or string collect "grh") git-forgit reset_head
|
||||
abbr -a -- (string collect $forgit_log; or string collect "glo") git-forgit log
|
||||
abbr -a -- (string collect $forgit_diff; or string collect "gd") git-forgit diff
|
||||
abbr -a -- (string collect $forgit_ignore; or string collect "gi") git-forgit ignore
|
||||
abbr -a -- (string collect $forgit_checkout_file; or string collect "gcf") git-forgit checkout_file
|
||||
abbr -a -- (string collect $forgit_checkout_branch; or string collect "gcb") git-forgit checkout_branch
|
||||
abbr -a -- (string collect $forgit_branch_delete; or string collect "gbd") git-forgit branch_delete
|
||||
abbr -a -- (string collect $forgit_clean; or string collect "gclean") git-forgit clean
|
||||
abbr -a -- (string collect $forgit_stash_show; or string collect "gss") git-forgit stash_show
|
||||
abbr -a -- (string collect $forgit_stash_push; or string collect "gsp") git-forgit stash_push
|
||||
abbr -a -- (string collect $forgit_cherry_pick; or string collect "gcp") git-forgit cherry_pick_from_branch
|
||||
abbr -a -- (string collect $forgit_rebase; or string collect "grb") git-forgit rebase
|
||||
abbr -a -- (string collect $forgit_fixup; or string collect "gfu") git-forgit fixup
|
||||
abbr -a -- (string collect $forgit_checkout_commit; or string collect "gco") git-forgit checkout_commit
|
||||
abbr -a -- (string collect $forgit_revert_commit; or string collect "grc") git-forgit revert_commit
|
||||
abbr -a -- (string collect $forgit_blame; or string collect "gbl") git-forgit blame
|
||||
abbr -a -- (string collect $forgit_checkout_tag; or string collect "gct") git-forgit checkout_tag
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
# MIT License
|
||||
|
||||
Copyright © `2020` `Patrick`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,220 @@
|
||||
<div align="center">
|
||||
|
||||
# fzf.fish 🔍🐟
|
||||
|
||||
[![latest release badge][]](https://github.com/patrickf1/fzf.fish/releases)
|
||||
[![build status badge][]](https://github.com/patrickf1/fzf.fish/actions)
|
||||
[![awesome badge][]](https://git.io/awsm.fish)
|
||||
|
||||
</div>
|
||||
|
||||
Augment your [Fish][] command line with mnemonic key bindings to efficiently find what you need using [fzf][].
|
||||
|
||||
https://user-images.githubusercontent.com/1967248/197308919-51d04602-2d5f-46aa-a96e-6cf1617e3067.mov
|
||||
|
||||
## Search commands
|
||||
|
||||
Use `fzf.fish` to interactively find and insert file paths, git commit hashes, and other entities into your command line. <kbd>Tab</kbd> to select multiple entries. If you trigger a search while your cursor is on a word, that word will be used to seed the fzf query and will be replaced by your selection. All searches include a preview of the entity hovered over to help you find what you're looking for.
|
||||
|
||||
### 📁 Search Directory
|
||||
|
||||

|
||||
|
||||
- **Fzf input:** recursive listing of current directory's non-hidden files
|
||||
- **Output:** relative paths of selected files
|
||||
- **Key binding and mnemonic:** <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F</kbd> (`F` for file)
|
||||
- **Preview window:** file with syntax highlighting, directory contents, or file type
|
||||
- **Remarks**
|
||||
- directories are inserted with a trailing `/`, so if you select exactly one directory, you can immediately hit <kbd>ENTER</kbd> to [cd into it][cd docs]
|
||||
- if the current token is a directory with a trailing slash (e.g. `.config/<CURSOR>`), then that directory is searched instead
|
||||
- [ignores files that are also ignored by git](#fd-gi)
|
||||
|
||||
### 🪵 Search Git Log
|
||||
|
||||

|
||||
|
||||
- **Fzf input:** the current repository's formatted `git log`
|
||||
- **Output:** hashes of selected commits
|
||||
- **Key binding and mnemonic:** <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>L</kbd> (`L` for log)
|
||||
- **Preview window:** commit message and diff
|
||||
|
||||
### 📝 Search Git Status
|
||||
|
||||

|
||||
|
||||
- **Fzf input:** the current repository's `git status`
|
||||
- **Output:** relative paths of selected lines
|
||||
- **Key binding and mnemonic:** <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>S</kbd> (`S` for status)
|
||||
- **Preview window:** the git diff of the file
|
||||
|
||||
### 📜 Search History
|
||||
|
||||

|
||||
|
||||
- **Fzf input:** Fish's command history
|
||||
- **Output:** selected commands
|
||||
- **Key binding and mnemonic:** <kbd>Ctrl</kbd>+<kbd>R</kbd> (`R` for reverse-i-search)
|
||||
- **Preview window:** the entire command with Fish syntax highlighting
|
||||
|
||||
### 🖥️ Search Processes
|
||||
|
||||

|
||||
|
||||
- **Fzf input:** the pid and command of all running processes, outputted by `ps`
|
||||
- **Output:** pids of selected processes
|
||||
- **Key binding and mnemonic:** <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>P</kbd> (`P` for process)
|
||||
- **Preview window:** the CPU usage, memory usage, start time, and other information about the process
|
||||
|
||||
### 💲 Search Variables
|
||||
|
||||

|
||||
|
||||
- **Fzf input:** all the shell variables currently [in scope][var scope]
|
||||
- **Output:** selected shell variables
|
||||
- **Key binding and mnemonic:** <kbd>Ctrl</kbd>+<kbd>V</kbd> (`V` for variable)
|
||||
- **Preview window:** the variable's scope info and values
|
||||
- `$history` is excluded for technical reasons so use [Search History](#-search-history) instead to inspect it
|
||||
|
||||
## Installation
|
||||
|
||||
First, install a proper version of these CLI dependencies:
|
||||
|
||||
| CLI | Minimum version required | Description |
|
||||
| -------- | ------------------------ | --------------------------------------- |
|
||||
| [fish][] | 3.4.0 | a modern shell |
|
||||
| [fzf][] | 0.33.0 | fuzzy finder that powers this plugin |
|
||||
| [fd][] | 8.5.0 | faster, colorized alternative to `find` |
|
||||
| [bat][] | 0.16.0 | smarter `cat` with syntax highlighting |
|
||||
|
||||
[fd][] and [bat][] only need to be installed if you will use [Search Directory][].
|
||||
|
||||
Next, because `fzf.fish` is incompatible with other fzf plugins, [check for and remove these two common alternatives](https://github.com/PatrickF1/fzf.fish/wiki/Uninstalling-other-fzf-plugins).
|
||||
|
||||
Finally, install this plugin with [Fisher][].
|
||||
|
||||
> `fzf.fish` can be installed manually or with other plugin managers but only Fisher is officially supported.
|
||||
|
||||
```fish
|
||||
fisher install PatrickF1/fzf.fish
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Customize key bindings
|
||||
|
||||
`fzf.fish` includes an ergonomic function for configuring its key bindings. Read [its documentation](/functions/_fzf_configure_bindings_help.fish):
|
||||
|
||||
```fish
|
||||
fzf_configure_bindings --help
|
||||
```
|
||||
|
||||
Call `fzf_configure_bindings` in your `config.fish` in order to persist your custom bindings.
|
||||
|
||||
### Change fzf options for all commands
|
||||
|
||||
fzf supports global default options via the [FZF_DEFAULT_OPTS and FZF_DEFAULT_OPTS_FILE](https://github.com/junegunn/fzf#environment-variables) environment variables. If neither are set, `fzf.fish` sets its own [default opts whenever it executes fzf](functions/_fzf_wrapper.fish).
|
||||
|
||||
### Change fzf options for a specific command
|
||||
|
||||
Each command's fzf options can be configured via a variable:
|
||||
|
||||
| Command | Variable |
|
||||
| ----------------- | --------------------- |
|
||||
| Search Directory | `fzf_directory_opts` |
|
||||
| Search Git Log | `fzf_git_log_opts` |
|
||||
| Search Git Status | `fzf_git_status_opts` |
|
||||
| Search History | `fzf_history_opts` |
|
||||
| Search Processes | `fzf_processes_opts` |
|
||||
| Search Variables | `fzf_variables_opts` |
|
||||
|
||||
The value of each variable is appended last to fzf's options list. Because fzf uses the last instance of an option if it is specified multiple times, custom options take precedence. Custom fzf options unlock a variety of augmentations:
|
||||
|
||||
- add [fzf key bindings](https://www.mankier.com/1/fzf#Key/Event_Bindings) to [open files in Vim](https://github.com/PatrickF1/fzf.fish/pull/273)
|
||||
- adjust the preview command or window
|
||||
- [re-populate fzf's input list on demand](https://github.com/junegunn/fzf/issues/1750)
|
||||
- change the [search mode](https://github.com/junegunn/fzf#search-syntax)
|
||||
|
||||
Find more ideas and tips in the [Cookbook](https://github.com/PatrickF1/fzf.fish/wiki/Cookbook).
|
||||
|
||||
### Change how Search Directory previews directories and regular files
|
||||
|
||||
[Search Directory][], by default, executes `ls` to preview directories and `bat` to preview [regular files](https://stackoverflow.com/questions/6858452).
|
||||
|
||||
To use your own directory preview command, set it in `fzf_preview_dir_cmd`:
|
||||
|
||||
```fish
|
||||
set fzf_preview_dir_cmd eza --all --color=always
|
||||
```
|
||||
|
||||
And to use your own file preview command, set it in `fzf_preview_file_cmd`:
|
||||
|
||||
```fish
|
||||
set fzf_preview_file_cmd cat -n
|
||||
```
|
||||
|
||||
Omit the target path for both variables as `fzf.fish` will itself [specify the argument to preview](functions/_fzf_preview_file.fish).
|
||||
|
||||
### Change what files are listed by Search Directory
|
||||
|
||||
To pass custom options to `fd` when [Search Directory][] executes it to populate the list of files, set them in `fzf_fd_opts`:
|
||||
|
||||
```fish
|
||||
set fzf_fd_opts --hidden --max-depth 5
|
||||
```
|
||||
|
||||
<a id='fd-gi'></a>By default, `fd` hides files listed in `.gitignore`. You can disable this behavior by adding the `--no-ignore` flag to `fzf_fd_opts`.
|
||||
|
||||
### Change Search Git Log's commit formatting
|
||||
|
||||
[Search Git Log][] executes `git log --format` to format the list of commits. To use your own [commit log format](https://git-scm.com/docs/git-log#Documentation/git-log.txt-emnem), set it in `fzf_git_log_format`. For example, this shows the hash and subject for each commit:
|
||||
|
||||
```fish
|
||||
set fzf_git_log_format "%H %s"
|
||||
```
|
||||
|
||||
The format must be one line per commit and the hash must be the first field, or else Search Git Log will fail to determine which commits you selected.
|
||||
|
||||
### Integrate with a diff highlighter
|
||||
|
||||
To pipe the git diff previews from [Search Git Log][] and [Search Git Status][] through a highlighter tool (e.g. [delta](https://github.com/dandavison/delta) or [diff-so-fancy](https://github.com/so-fancy/diff-so-fancy)), set a command invoking the highlighter in `fzf_diff_highlighter`. It should not pipe its output to a pager:
|
||||
|
||||
```fish
|
||||
# width=20 so delta decorations don't wrap around small fzf preview pane
|
||||
set fzf_diff_highlighter delta --paging=never --width=20
|
||||
# Or, if using DFS
|
||||
set fzf_diff_highlighter diff-so-fancy
|
||||
```
|
||||
|
||||
### Change Search History's date time format
|
||||
|
||||
[Search History][] shows the date time each command was executed. To change how its formatted, set your [strftime format string](https://devhints.io/strftime) in `fzf_history_time_format`. For example, this shows the date time as DD-MM-YY:
|
||||
|
||||
```fish
|
||||
set fzf_history_time_format %d-%m-%y
|
||||
```
|
||||
|
||||
Do not to include the vertical box-drawing character `│` (not to be confused with the pipe character `|`) as it is relied on to delineate the date time from the command.
|
||||
|
||||
## Further reading
|
||||
|
||||
Find answers to these questions and more in the [project Wiki](https://github.com/PatrickF1/fzf.fish/wiki):
|
||||
|
||||
- How does `fzf.fish` [compare](https://github.com/PatrickF1/fzf.fish/wiki/Prior-Art) to other popular fzf plugins for Fish?
|
||||
- Why isn't this [command working](https://github.com/PatrickF1/fzf.fish/wiki/Troubleshooting)?
|
||||
- How can I [customize](https://github.com/PatrickF1/fzf.fish/wiki/Cookbook) this command?
|
||||
- How can I [contribute](https://github.com/PatrickF1/fzf.fish/wiki/Contributing) to this plugin?
|
||||
|
||||
[awesome badge]: https://awesome.re/mentioned-badge.svg
|
||||
[bat]: https://github.com/sharkdp/bat
|
||||
[build status badge]: https://img.shields.io/github/actions/workflow/status/PatrickF1/fzf.fish/continuous_integration.yml?branch=main
|
||||
[cd docs]: https://fishshell.com/docs/current/cmds/cd.html
|
||||
[fd]: https://github.com/sharkdp/fd
|
||||
[fish]: https://fishshell.com
|
||||
[fisher]: https://github.com/jorgebucaran/fisher
|
||||
[fzf]: https://github.com/junegunn/fzf
|
||||
[latest release badge]: https://img.shields.io/github/v/release/patrickf1/fzf.fish
|
||||
[search directory]: #-search-directory
|
||||
[search git log]: #-search-git-log
|
||||
[search git status]: #-search-git-status
|
||||
[search history]: #-search-history
|
||||
[var scope]: https://fishshell.com/docs/current/#variable-scope
|
||||
@@ -0,0 +1,8 @@
|
||||
complete fzf_configure_bindings --no-files
|
||||
complete fzf_configure_bindings --long help --short h --description "Print help" --condition "not __fish_seen_argument --help -h"
|
||||
complete fzf_configure_bindings --long directory --description "Change the key binding for Search Directory" --condition "not __fish_seen_argument --directory"
|
||||
complete fzf_configure_bindings --long git_log --description "Change the key binding for Search Git Log" --condition "not __fish_seen_argument --git_log"
|
||||
complete fzf_configure_bindings --long git_status --description "Change the key binding for Search Git Status" --condition "not __fish_seen_argument --git_status"
|
||||
complete fzf_configure_bindings --long history --description "Change the key binding for Search History" --condition "not __fish_seen_argument --history"
|
||||
complete fzf_configure_bindings --long processes --description "Change the key binding for Search Processes" --condition "not __fish_seen_argument --processes"
|
||||
complete fzf_configure_bindings --long variables --description "Change the key binding for Search Variables" --condition "not __fish_seen_argument --variables"
|
||||
@@ -0,0 +1,28 @@
|
||||
# fzf.fish is only meant to be used in interactive mode. If not in interactive mode and not in CI, skip the config to speed up shell startup
|
||||
if not status is-interactive && test "$CI" != true
|
||||
exit
|
||||
end
|
||||
|
||||
# Because of scoping rules, to capture the shell variables exactly as they are, we must read
|
||||
# them before even executing _fzf_search_variables. We use psub to store the
|
||||
# variables' info in temporary files and pass in the filenames as arguments.
|
||||
# This variable is global so that it can be referenced by fzf_configure_bindings and in tests
|
||||
set --global _fzf_search_vars_command '_fzf_search_variables (set --show | psub) (set --names | psub)'
|
||||
|
||||
|
||||
# Install the default bindings, which are mnemonic and minimally conflict with fish's preset bindings
|
||||
fzf_configure_bindings
|
||||
|
||||
# Doesn't erase autoloaded _fzf_* functions because they are not easily accessible once key bindings are erased
|
||||
function _fzf_uninstall --on-event fzf_uninstall
|
||||
_fzf_uninstall_bindings
|
||||
|
||||
set --erase _fzf_search_vars_command
|
||||
functions --erase _fzf_uninstall _fzf_migration_message _fzf_uninstall_bindings fzf_configure_bindings
|
||||
complete --erase fzf_configure_bindings
|
||||
|
||||
set_color cyan
|
||||
echo "fzf.fish uninstalled."
|
||||
echo "You may need to manually remove fzf_configure_bindings from your config.fish if you were using custom key bindings."
|
||||
set_color normal
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
function _fzf_configure_bindings_help --description "Prints the help message for fzf_configure_bindings."
|
||||
echo "\
|
||||
USAGE:
|
||||
fzf_configure_bindings [--COMMAND=[KEY_SEQUENCE]...]
|
||||
|
||||
DESCRIPTION
|
||||
fzf_configure_bindings installs key bindings for fzf.fish's commands and erases any bindings it
|
||||
previously installed. It installs bindings for both default and insert modes. fzf.fish executes
|
||||
it without options on fish startup to install the out-of-the-box key bindings.
|
||||
|
||||
By default, commands are bound to a mnemonic key sequence, shown below. Each command's binding
|
||||
can be configured using a namesake corresponding option:
|
||||
COMMAND | DEFAULT KEY SEQUENCE | CORRESPONDING OPTION
|
||||
Search Directory | Ctrl+Alt+F (F for file) | --directory
|
||||
Search Git Log | Ctrl+Alt+L (L for log) | --git_log
|
||||
Search Git Status | Ctrl+Alt+S (S for status) | --git_status
|
||||
Search History | Ctrl+R (R for reverse) | --history
|
||||
Search Processes | Ctrl+Alt+P (P for process) | --processes
|
||||
Search Variables | Ctrl+V (V for variable) | --variables
|
||||
Override a command's binding by specifying its corresponding option with the desired key
|
||||
sequence. Disable a command's binding by specifying its corresponding option with no value.
|
||||
|
||||
Because fzf_configure_bindings erases bindings it previously installed, it can be cleanly
|
||||
executed multiple times. Once the desired fzf_configure_bindings command has been found, add it
|
||||
to your config.fish in order to persist the customized bindings.
|
||||
|
||||
In terms of validation, fzf_configure_bindings fails if passed unknown options. It expects an
|
||||
equals sign between an option's name and value. However, it does not validate key sequences.
|
||||
|
||||
Pass -h or --help to print this help message and exit.
|
||||
|
||||
EXAMPLES
|
||||
Default bindings but bind Search Directory to Ctrl+F and Search Variables to Ctrl+Alt+V
|
||||
\$ fzf_configure_bindings --directory=\cf --variables=\e\cv
|
||||
Default bindings but disable Search History
|
||||
\$ fzf_configure_bindings --history=
|
||||
An agglomeration of different options
|
||||
\$ fzf_configure_bindings --git_status=\cg --history=\ch --variables= --processes=
|
||||
|
||||
SEE Also
|
||||
To learn more about fish key bindings, see bind(1) and fish_key_reader(1).
|
||||
"
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
# helper function for _fzf_search_variables
|
||||
function _fzf_extract_var_info --argument-names variable_name set_show_output --description "Extract and reformat lines pertaining to \$variable_name from \$set_show_output."
|
||||
# Extract only the lines about the variable, all of which begin with either
|
||||
# $variable_name: ...or... $variable_name[
|
||||
string match --regex "^\\\$$variable_name(?::|\[).*" <$set_show_output |
|
||||
|
||||
# Strip the variable name prefix, including ": " for scope info lines
|
||||
string replace --regex "^\\\$$variable_name(?:: )?" '' |
|
||||
|
||||
# Distill the lines of values, replacing...
|
||||
# [1]: |value|
|
||||
# ...with...
|
||||
# [1] value
|
||||
string replace --regex ": \|(.*)\|" ' $1'
|
||||
end
|
||||
@@ -0,0 +1,49 @@
|
||||
# helper for _fzf_search_git_status
|
||||
# arg should be a line from git status --short, e.g.
|
||||
# MM functions/_fzf_preview_changed_file.fish
|
||||
# D README.md
|
||||
# R LICENSE -> "New License"
|
||||
function _fzf_preview_changed_file --argument-names path_status --description "Show the git diff of the given file."
|
||||
# remove quotes because they'll be interpreted literally by git diff
|
||||
# no need to requote when referencing $path because fish does not perform word splitting
|
||||
# https://fishshell.com/docs/current/fish_for_bash_users.html
|
||||
set -f path (string unescape (string sub --start 4 $path_status))
|
||||
# first letter of short format shows index, second letter shows working tree
|
||||
# https://git-scm.com/docs/git-status/2.35.0#_short_format
|
||||
set -f index_status (string sub --length 1 $path_status)
|
||||
set -f working_tree_status (string sub --start 2 --length 1 $path_status)
|
||||
|
||||
set -f diff_opts --color=always
|
||||
|
||||
if test $index_status = '?'
|
||||
_fzf_report_diff_type Untracked
|
||||
_fzf_preview_file $path
|
||||
else if contains {$index_status}$working_tree_status DD AU UD UA DU AA UU
|
||||
# Unmerged statuses taken directly from git status help's short format table
|
||||
# Unmerged statuses are mutually exclusive with other statuses, so if we see
|
||||
# these, then safe to assume the path is unmerged
|
||||
_fzf_report_diff_type Unmerged
|
||||
git diff $diff_opts -- $path
|
||||
else
|
||||
if test $index_status != ' '
|
||||
_fzf_report_diff_type Staged
|
||||
|
||||
# renames are only detected in the index, never working tree, so only need to test for it here
|
||||
# https://stackoverflow.com/questions/73954214
|
||||
if test $index_status = R
|
||||
# diff the post-rename path with the original path, otherwise the diff will show the entire file as being added
|
||||
set -f orig_and_new_path (string split --max 1 -- ' -> ' $path)
|
||||
git diff --staged $diff_opts -- $orig_and_new_path[1] $orig_and_new_path[2]
|
||||
# path currently has the form of "original -> current", so we need to correct it before it's used below
|
||||
set path $orig_and_new_path[2]
|
||||
else
|
||||
git diff --staged $diff_opts -- $path
|
||||
end
|
||||
end
|
||||
|
||||
if test $working_tree_status != ' '
|
||||
_fzf_report_diff_type Unstaged
|
||||
git diff $diff_opts -- $path
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
# helper function for _fzf_search_directory and _fzf_search_git_status
|
||||
function _fzf_preview_file --description "Print a preview for the given file based on its file type."
|
||||
# because there's no way to guarantee that _fzf_search_directory passes the path to _fzf_preview_file
|
||||
# as one argument, we collect all the arguments into one single variable and treat that as the path
|
||||
set -f file_path $argv
|
||||
|
||||
if test -L "$file_path" # symlink
|
||||
# notify user and recurse on the target of the symlink, which can be any of these file types
|
||||
set -l target_path (realpath "$file_path")
|
||||
|
||||
set_color yellow
|
||||
echo "'$file_path' is a symlink to '$target_path'."
|
||||
set_color normal
|
||||
|
||||
_fzf_preview_file "$target_path"
|
||||
else if test -f "$file_path" # regular file
|
||||
if set --query fzf_preview_file_cmd
|
||||
# need to escape quotes to make sure eval receives file_path as a single arg
|
||||
eval "$fzf_preview_file_cmd '$file_path'"
|
||||
else
|
||||
bat --style=numbers --color=always "$file_path"
|
||||
end
|
||||
else if test -d "$file_path" # directory
|
||||
if set --query fzf_preview_dir_cmd
|
||||
# see above
|
||||
eval "$fzf_preview_dir_cmd '$file_path'"
|
||||
else
|
||||
# -A list hidden files as well, except for . and ..
|
||||
# -F helps classify files by appending symbols after the file name
|
||||
command ls -A -F "$file_path"
|
||||
end
|
||||
else if test -c "$file_path"
|
||||
_fzf_report_file_type "$file_path" "character device file"
|
||||
else if test -b "$file_path"
|
||||
_fzf_report_file_type "$file_path" "block device file"
|
||||
else if test -S "$file_path"
|
||||
_fzf_report_file_type "$file_path" socket
|
||||
else if test -p "$file_path"
|
||||
_fzf_report_file_type "$file_path" "named pipe"
|
||||
else
|
||||
echo "$file_path doesn't exist." >&2
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,18 @@
|
||||
# helper for _fzf_preview_changed_file
|
||||
# prints out something like
|
||||
# ╭────────╮
|
||||
# │ Staged │
|
||||
# ╰────────╯
|
||||
function _fzf_report_diff_type --argument-names diff_type --description "Print a distinct colored header meant to preface a git patch."
|
||||
# number of "-" to draw is the length of the string to box + 2 for padding
|
||||
set -f repeat_count (math 2 + (string length $diff_type))
|
||||
set -f line (string repeat --count $repeat_count ─)
|
||||
set -f top_border ╭$line╮
|
||||
set -f btm_border ╰$line╯
|
||||
|
||||
set_color yellow
|
||||
echo $top_border
|
||||
echo "│ $diff_type │"
|
||||
echo $btm_border
|
||||
set_color normal
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
# helper function for _fzf_preview_file
|
||||
function _fzf_report_file_type --argument-names file_path file_type --description "Explain the file type for a file."
|
||||
set_color red
|
||||
echo "Cannot preview '$file_path': it is a $file_type."
|
||||
set_color normal
|
||||
end
|
||||
@@ -0,0 +1,33 @@
|
||||
function _fzf_search_directory --description "Search the current directory. Replace the current token with the selected file paths."
|
||||
# Directly use fd binary to avoid output buffering delay caused by a fd alias, if any.
|
||||
# Debian-based distros install fd as fdfind and the fd package is something else, so
|
||||
# check for fdfind first. Fall back to "fd" for a clear error message.
|
||||
set -f fd_cmd (command -v fdfind || command -v fd || echo "fd")
|
||||
set -f --append fd_cmd --color=always $fzf_fd_opts
|
||||
|
||||
set -f fzf_arguments --multi --ansi $fzf_directory_opts
|
||||
set -f token (commandline --current-token)
|
||||
# expand any variables or leading tilde (~) in the token
|
||||
set -f expanded_token (eval echo -- $token)
|
||||
# unescape token because it's already quoted so backslashes will mess up the path
|
||||
set -f unescaped_exp_token (string unescape -- $expanded_token)
|
||||
|
||||
# If the current token is a directory and has a trailing slash,
|
||||
# then use it as fd's base directory.
|
||||
if string match --quiet -- "*/" $unescaped_exp_token && test -d "$unescaped_exp_token"
|
||||
set --append fd_cmd --base-directory=$unescaped_exp_token
|
||||
# use the directory name as fzf's prompt to indicate the search is limited to that directory
|
||||
set --prepend fzf_arguments --prompt="Directory $unescaped_exp_token> " --preview="_fzf_preview_file $expanded_token{}"
|
||||
set -f file_paths_selected $unescaped_exp_token($fd_cmd 2>/dev/null | _fzf_wrapper $fzf_arguments)
|
||||
else
|
||||
set --prepend fzf_arguments --prompt="Directory> " --query="$unescaped_exp_token" --preview='_fzf_preview_file {}'
|
||||
set -f file_paths_selected ($fd_cmd 2>/dev/null | _fzf_wrapper $fzf_arguments)
|
||||
end
|
||||
|
||||
|
||||
if test $status -eq 0
|
||||
commandline --current-token --replace -- (string escape -- $file_paths_selected | string join ' ')
|
||||
end
|
||||
|
||||
commandline --function repaint
|
||||
end
|
||||
@@ -0,0 +1,36 @@
|
||||
function _fzf_search_git_log --description "Search the output of git log and preview commits. Replace the current token with the selected commit hash."
|
||||
if not git rev-parse --git-dir >/dev/null 2>&1
|
||||
echo '_fzf_search_git_log: Not in a git repository.' >&2
|
||||
else
|
||||
if not set --query fzf_git_log_format
|
||||
# %h gives you the abbreviated commit hash, which is useful for saving screen space, but we will have to expand it later below
|
||||
set -f fzf_git_log_format '%C(bold blue)%h%C(reset) - %C(cyan)%ad%C(reset) %C(yellow)%d%C(reset) %C(normal)%s%C(reset) %C(dim normal)[%an]%C(reset)'
|
||||
end
|
||||
|
||||
set -f preview_cmd 'git show --color=always --stat --patch {1}'
|
||||
if set --query fzf_diff_highlighter
|
||||
set preview_cmd "$preview_cmd | $fzf_diff_highlighter"
|
||||
end
|
||||
|
||||
set -f selected_log_lines (
|
||||
git log --no-show-signature --color=always --format=format:$fzf_git_log_format --date=short | \
|
||||
_fzf_wrapper --ansi \
|
||||
--multi \
|
||||
--scheme=history \
|
||||
--prompt="Git Log> " \
|
||||
--preview=$preview_cmd \
|
||||
--query=(commandline --current-token) \
|
||||
$fzf_git_log_opts
|
||||
)
|
||||
if test $status -eq 0
|
||||
for line in $selected_log_lines
|
||||
set -f abbreviated_commit_hash (string split --field 1 " " $line)
|
||||
set -f full_commit_hash (git rev-parse $abbreviated_commit_hash)
|
||||
set -f --append commit_hashes $full_commit_hash
|
||||
end
|
||||
commandline --current-token --replace (string join ' ' $commit_hashes)
|
||||
end
|
||||
end
|
||||
|
||||
commandline --function repaint
|
||||
end
|
||||
@@ -0,0 +1,41 @@
|
||||
function _fzf_search_git_status --description "Search the output of git status. Replace the current token with the selected file paths."
|
||||
if not git rev-parse --git-dir >/dev/null 2>&1
|
||||
echo '_fzf_search_git_status: Not in a git repository.' >&2
|
||||
else
|
||||
set -f preview_cmd '_fzf_preview_changed_file {}'
|
||||
if set --query fzf_diff_highlighter
|
||||
set preview_cmd "$preview_cmd | $fzf_diff_highlighter"
|
||||
end
|
||||
|
||||
set -f selected_paths (
|
||||
# Pass configuration color.status=always to force status to use colors even though output is sent to a pipe
|
||||
git -c color.status=always status --short |
|
||||
_fzf_wrapper --ansi \
|
||||
--multi \
|
||||
--prompt="Git Status> " \
|
||||
--query=(commandline --current-token) \
|
||||
--preview=$preview_cmd \
|
||||
--nth="2.." \
|
||||
$fzf_git_status_opts
|
||||
)
|
||||
if test $status -eq 0
|
||||
# git status --short automatically escapes the paths of most files for us so not going to bother trying to handle
|
||||
# the few edges cases of weird file names that should be extremely rare (e.g. "this;needs;escaping")
|
||||
set -f cleaned_paths
|
||||
|
||||
for path in $selected_paths
|
||||
if test (string sub --length 1 $path) = R
|
||||
# path has been renamed and looks like "R LICENSE -> LICENSE.md"
|
||||
# extract the path to use from after the arrow
|
||||
set --append cleaned_paths (string split -- "-> " $path)[-1]
|
||||
else
|
||||
set --append cleaned_paths (string sub --start=4 $path)
|
||||
end
|
||||
end
|
||||
|
||||
commandline --current-token --replace -- (string join ' ' $cleaned_paths)
|
||||
end
|
||||
end
|
||||
|
||||
commandline --function repaint
|
||||
end
|
||||
@@ -0,0 +1,39 @@
|
||||
function _fzf_search_history --description "Search command history. Replace the command line with the selected command."
|
||||
# history merge incorporates history changes from other fish sessions
|
||||
# it errors out if called in private mode
|
||||
if test -z "$fish_private_mode"
|
||||
builtin history merge
|
||||
end
|
||||
|
||||
if not set --query fzf_history_time_format
|
||||
# Reference https://devhints.io/strftime to understand strftime format symbols
|
||||
set -f fzf_history_time_format "%m-%d %H:%M:%S"
|
||||
end
|
||||
|
||||
# Delinate time from command in history entries using the vertical box drawing char (U+2502).
|
||||
# Then, to get raw command from history entries, delete everything up to it. The ? on regex is
|
||||
# necessary to make regex non-greedy so it won't match into commands containing the char.
|
||||
set -f time_prefix_regex '^.*? │ '
|
||||
# Delinate commands throughout pipeline using null rather than newlines because commands can be multi-line
|
||||
set -f commands_selected (
|
||||
builtin history --null --show-time="$fzf_history_time_format │ " |
|
||||
_fzf_wrapper --read0 \
|
||||
--print0 \
|
||||
--multi \
|
||||
--scheme=history \
|
||||
--prompt="History> " \
|
||||
--query=(commandline) \
|
||||
--preview="string replace --regex '$time_prefix_regex' '' -- {} | fish_indent --ansi" \
|
||||
--preview-window="bottom:3:wrap" \
|
||||
$fzf_history_opts |
|
||||
string split0 |
|
||||
# remove timestamps from commands selected
|
||||
string replace --regex $time_prefix_regex ''
|
||||
)
|
||||
|
||||
if test $status -eq 0
|
||||
commandline --replace -- $commands_selected
|
||||
end
|
||||
|
||||
commandline --function repaint
|
||||
end
|
||||
@@ -0,0 +1,32 @@
|
||||
function _fzf_search_processes --description "Search all running processes. Replace the current token with the pid of the selected process."
|
||||
# Directly use ps command because it is often aliased to a different command entirely
|
||||
# or with options that dirty the search results and preview output
|
||||
set -f ps_cmd (command -v ps || echo "ps")
|
||||
# use all caps to be consistent with ps default format
|
||||
# snake_case because ps doesn't seem to allow spaces in the field names
|
||||
set -f ps_preview_fmt (string join ',' 'pid' 'ppid=PARENT' 'user' '%cpu' 'rss=RSS_IN_KB' 'start=START_TIME' 'command')
|
||||
set -f processes_selected (
|
||||
$ps_cmd -A -opid,command | \
|
||||
_fzf_wrapper --multi \
|
||||
--prompt="Processes> " \
|
||||
--query (commandline --current-token) \
|
||||
--ansi \
|
||||
# first line outputted by ps is a header, so we need to mark it as so
|
||||
--header-lines=1 \
|
||||
# ps uses exit code 1 if the process was not found, in which case show an message explaining so
|
||||
--preview="$ps_cmd -o '$ps_preview_fmt' -p {1} || echo 'Cannot preview {1} because it exited.'" \
|
||||
--preview-window="bottom:4:wrap" \
|
||||
$fzf_processes_opts
|
||||
)
|
||||
|
||||
if test $status -eq 0
|
||||
for process in $processes_selected
|
||||
set -f --append pids_selected (string split --no-empty --field=1 -- " " $process)
|
||||
end
|
||||
|
||||
# string join to replace the newlines outputted by string split with spaces
|
||||
commandline --current-token --replace -- (string join ' ' $pids_selected)
|
||||
end
|
||||
|
||||
commandline --function repaint
|
||||
end
|
||||
@@ -0,0 +1,47 @@
|
||||
# This function expects the following two arguments:
|
||||
# argument 1 = output of (set --show | psub), i.e. a file with the scope info and values of all variables
|
||||
# argument 2 = output of (set --names | psub), i.e. a file with all variable names
|
||||
function _fzf_search_variables --argument-names set_show_output set_names_output --description "Search and preview shell variables. Replace the current token with the selected variable."
|
||||
if test -z "$set_names_output"
|
||||
printf '%s\n' '_fzf_search_variables requires 2 arguments.' >&2
|
||||
|
||||
commandline --function repaint
|
||||
return 22 # 22 means invalid argument in POSIX
|
||||
end
|
||||
|
||||
# Exclude the history variable from being piped into fzf because
|
||||
# 1. it's not included in $set_names_output
|
||||
# 2. it tends to be a very large value => increases computation time
|
||||
# 3._fzf_search_history is a much better way to examine history anyway
|
||||
set -f all_variable_names (string match --invert history <$set_names_output)
|
||||
|
||||
set -f current_token (commandline --current-token)
|
||||
# Use the current token to pre-populate fzf's query. If the current token begins
|
||||
# with a $, remove it from the query so that it will better match the variable names
|
||||
set -f cleaned_curr_token (string replace -- '$' '' $current_token)
|
||||
|
||||
set -f variable_names_selected (
|
||||
printf '%s\n' $all_variable_names |
|
||||
_fzf_wrapper --preview "_fzf_extract_var_info {} $set_show_output" \
|
||||
--prompt="Variables> " \
|
||||
--preview-window="wrap" \
|
||||
--multi \
|
||||
--query=$cleaned_curr_token \
|
||||
$fzf_variables_opts
|
||||
)
|
||||
|
||||
if test $status -eq 0
|
||||
# If the current token begins with a $, do not overwrite the $ when
|
||||
# replacing the current token with the selected variable.
|
||||
# Uses brace expansion to prepend $ to each variable name.
|
||||
commandline --current-token --replace (
|
||||
if string match --quiet -- '$*' $current_token
|
||||
string join " " \${$variable_names_selected}
|
||||
else
|
||||
string join " " $variable_names_selected
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
commandline --function repaint
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
function _fzf_wrapper --description "Prepares some environment variables before executing fzf."
|
||||
# Make sure fzf uses fish to execute preview commands, some of which
|
||||
# are autoloaded fish functions so don't exist in other shells.
|
||||
# Use --function so that it doesn't clobber SHELL outside this function.
|
||||
set -f --export SHELL (command --search fish)
|
||||
|
||||
# If neither FZF_DEFAULT_OPTS nor FZF_DEFAULT_OPTS_FILE are set, then set some sane defaults.
|
||||
# See https://github.com/junegunn/fzf#environment-variables
|
||||
set --query FZF_DEFAULT_OPTS FZF_DEFAULT_OPTS_FILE
|
||||
if test $status -eq 2
|
||||
# cycle allows jumping between the first and last results, making scrolling faster
|
||||
# layout=reverse lists results top to bottom, mimicking the familiar layouts of git log, history, and env
|
||||
# border shows where the fzf window begins and ends
|
||||
# height=90% leaves space to see the current command and some scrollback, maintaining context of work
|
||||
# preview-window=wrap wraps long lines in the preview window, making reading easier
|
||||
# marker=* makes the multi-select marker more distinguishable from the pointer (since both default to >)
|
||||
set --export FZF_DEFAULT_OPTS '--cycle --layout=reverse --border --height=90% --preview-window=wrap --marker="*"'
|
||||
end
|
||||
|
||||
fzf $argv
|
||||
end
|
||||
@@ -0,0 +1,46 @@
|
||||
# Always installs bindings for insert and default mode for simplicity and b/c it has almost no side-effect
|
||||
# https://gitter.im/fish-shell/fish-shell?at=60a55915ee77a74d685fa6b1
|
||||
function fzf_configure_bindings --description "Installs the default key bindings for fzf.fish with user overrides passed as options."
|
||||
# no need to install bindings if not in interactive mode or running tests
|
||||
status is-interactive || test "$CI" = true; or return
|
||||
|
||||
set -f options_spec h/help 'directory=?' 'git_log=?' 'git_status=?' 'history=?' 'processes=?' 'variables=?'
|
||||
argparse --max-args=0 --ignore-unknown $options_spec -- $argv 2>/dev/null
|
||||
if test $status -ne 0
|
||||
echo "Invalid option or a positional argument was provided." >&2
|
||||
_fzf_configure_bindings_help
|
||||
return 22
|
||||
else if set --query _flag_help
|
||||
_fzf_configure_bindings_help
|
||||
return
|
||||
else
|
||||
# Initialize with default key sequences and then override or disable them based on flags
|
||||
# index 1 = directory, 2 = git_log, 3 = git_status, 4 = history, 5 = processes, 6 = variables
|
||||
set -f key_sequences \e\cf \e\cl \e\cs \cr \e\cp \cv # \c = control, \e = escape
|
||||
set --query _flag_directory && set key_sequences[1] "$_flag_directory"
|
||||
set --query _flag_git_log && set key_sequences[2] "$_flag_git_log"
|
||||
set --query _flag_git_status && set key_sequences[3] "$_flag_git_status"
|
||||
set --query _flag_history && set key_sequences[4] "$_flag_history"
|
||||
set --query _flag_processes && set key_sequences[5] "$_flag_processes"
|
||||
set --query _flag_variables && set key_sequences[6] "$_flag_variables"
|
||||
|
||||
# If fzf bindings already exists, uninstall it first for a clean slate
|
||||
if functions --query _fzf_uninstall_bindings
|
||||
_fzf_uninstall_bindings
|
||||
end
|
||||
|
||||
for mode in default insert
|
||||
test -n $key_sequences[1] && bind --mode $mode $key_sequences[1] _fzf_search_directory
|
||||
test -n $key_sequences[2] && bind --mode $mode $key_sequences[2] _fzf_search_git_log
|
||||
test -n $key_sequences[3] && bind --mode $mode $key_sequences[3] _fzf_search_git_status
|
||||
test -n $key_sequences[4] && bind --mode $mode $key_sequences[4] _fzf_search_history
|
||||
test -n $key_sequences[5] && bind --mode $mode $key_sequences[5] _fzf_search_processes
|
||||
test -n $key_sequences[6] && bind --mode $mode $key_sequences[6] "$_fzf_search_vars_command"
|
||||
end
|
||||
|
||||
function _fzf_uninstall_bindings --inherit-variable key_sequences
|
||||
bind --erase -- $key_sequences
|
||||
bind --erase --mode insert -- $key_sequences
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
# MIT License
|
||||
|
||||
Copyright © `2020` `Ilan Cosman`
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,13 @@
|
||||
complete tide --no-files
|
||||
|
||||
set -l subcommands bug-report configure reload
|
||||
|
||||
complete tide -x -n __fish_use_subcommand -a bug-report -d "Print info for use in bug reports"
|
||||
complete tide -x -n __fish_use_subcommand -a configure -d "Run the configuration wizard"
|
||||
complete tide -x -n __fish_use_subcommand -a reload -d "Reload tide configuration"
|
||||
|
||||
complete tide -x -n "not __fish_seen_subcommand_from $subcommands" -s h -l help -d "Print help message"
|
||||
complete tide -x -n "not __fish_seen_subcommand_from $subcommands" -s v -l version -d "Print tide version"
|
||||
|
||||
complete tide -x -n '__fish_seen_subcommand_from bug-report' -l clean -d "Run clean Fish instance and install Tide"
|
||||
complete tide -x -n '__fish_seen_subcommand_from bug-report' -l verbose -d "Print full Tide configuration"
|
||||
@@ -0,0 +1,44 @@
|
||||
function _tide_init_install --on-event _tide_init_install
|
||||
set -U VIRTUAL_ENV_DISABLE_PROMPT true
|
||||
|
||||
source (functions --details _tide_sub_configure)
|
||||
_load_config lean
|
||||
_tide_finish
|
||||
|
||||
if status is-interactive
|
||||
tide bug-report --check || sleep 4
|
||||
|
||||
if contains ilancosman/tide (string lower $_fisher_plugins)
|
||||
set_color bryellow
|
||||
echo "ilancosman/tide is a development branch. Please install from a release tag:"
|
||||
_tide_fish_colorize "fisher install ilancosman/tide@v6"
|
||||
sleep 3
|
||||
end
|
||||
|
||||
switch (read --prompt-str="Configure tide prompt? [Y/n] " | string lower)
|
||||
case y ye yes ''
|
||||
tide configure
|
||||
case '*'
|
||||
echo -s \n 'Run ' (_tide_fish_colorize "tide configure") ' to customize your prompt.'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function _tide_init_update --on-event _tide_init_update
|
||||
# Warn users who install from main branch
|
||||
if contains ilancosman/tide (string lower $_fisher_plugins)
|
||||
set_color bryellow
|
||||
echo "ilancosman/tide is a development branch. Please install from a release tag:"
|
||||
_tide_fish_colorize "fisher install ilancosman/tide@v6"
|
||||
sleep 3
|
||||
end
|
||||
|
||||
# Set (disable) the new jobs variable
|
||||
set -q tide_jobs_number_threshold || set -U tide_jobs_number_threshold 1000
|
||||
end
|
||||
|
||||
function _tide_init_uninstall --on-event _tide_init_uninstall
|
||||
set -e VIRTUAL_ENV_DISABLE_PROMPT
|
||||
set -e (set -U --names | string match --entire -r '^_?tide')
|
||||
functions --erase (functions --all | string match --entire -r '^_?tide')
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
function _tide_1_line_prompt
|
||||
set -g add_prefix
|
||||
_tide_side=left for item in $_tide_left_items
|
||||
_tide_item_$item
|
||||
end
|
||||
set_color $prev_bg_color -b normal
|
||||
echo $tide_left_prompt_suffix
|
||||
|
||||
set -g add_prefix
|
||||
_tide_side=right for item in $_tide_right_items
|
||||
_tide_item_$item
|
||||
end
|
||||
set_color $prev_bg_color -b normal
|
||||
echo $tide_right_prompt_suffix
|
||||
end
|
||||
|
||||
function _tide_item_pwd
|
||||
_tide_print_item pwd @PWD@
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
function _tide_2_line_prompt
|
||||
set -g add_prefix
|
||||
_tide_side=left for item in $_tide_left_items
|
||||
_tide_item_$item
|
||||
end
|
||||
if not set -e add_prefix
|
||||
set_color $prev_bg_color -b normal
|
||||
echo $tide_left_prompt_suffix
|
||||
end
|
||||
|
||||
echo
|
||||
|
||||
set -g add_prefix
|
||||
_tide_side=right for item in $_tide_right_items
|
||||
_tide_item_$item
|
||||
end
|
||||
if not set -e add_prefix
|
||||
set_color $prev_bg_color -b normal
|
||||
echo $tide_right_prompt_suffix
|
||||
end
|
||||
end
|
||||
|
||||
function _tide_item_pwd
|
||||
_tide_print_item pwd @PWD@
|
||||
end
|
||||
|
||||
function _tide_item_newline
|
||||
set_color $prev_bg_color -b normal
|
||||
v=tide_"$_tide_side"_prompt_suffix echo $$v
|
||||
set -g add_prefix
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
function _tide_cache_variables
|
||||
# Same-color-separator color
|
||||
set_color $tide_prompt_color_separator_same_color | read -gx _tide_color_separator_same_color
|
||||
|
||||
# git
|
||||
contains git $_tide_left_items $_tide_right_items && set_color $tide_git_color_branch | read -gx _tide_location_color
|
||||
|
||||
# private_mode
|
||||
if contains private_mode $_tide_left_items $_tide_right_items && test -n "$fish_private_mode"
|
||||
set -gx _tide_private_mode
|
||||
else
|
||||
set -e _tide_private_mode
|
||||
end
|
||||
|
||||
# item padding
|
||||
test "$tide_prompt_pad_items" = true && set -gx _tide_pad ' ' || set -e _tide_pad
|
||||
end
|
||||
@@ -0,0 +1,76 @@
|
||||
# Outputs icon, color, bg_color
|
||||
function _tide_detect_os
|
||||
set -lx defaultColor 080808 CED7CF
|
||||
switch (uname | string lower)
|
||||
case darwin
|
||||
printf %s\n D6D6D6 333333 # from apple.com header
|
||||
case freebsd openbsd dragonfly
|
||||
printf %s\n FFFFFF AB2B28 # https://freebsdfoundation.org/about-us/about-the-foundation/project/
|
||||
case 'cygwin*' 'mingw*_nt*' 'msys_nt*'
|
||||
printf %s\n FFFFFF 00CCFF # https://answers.microsoft.com/en-us/windows/forum/all/what-is-the-official-windows-8-blue-rgb-or-hex/fd57144b-f69b-42d8-8c21-6ca911646e44
|
||||
case linux
|
||||
if test (uname -o) = Android
|
||||
# https://developer.android.com/distribute/marketing-tools/brand-guidelines
|
||||
printf %s\n 3DDC84 3C3F41 # fg is from above link, bg is from Android Studio default dark theme
|
||||
else
|
||||
_tide_detect_os_linux_cases /etc/os-release ID ||
|
||||
_tide_detect_os_linux_cases /etc/os-release ID_LIKE ||
|
||||
_tide_detect_os_linux_cases /etc/lsb-release DISTRIB_ID ||
|
||||
printf %s\n $defaultColor
|
||||
end
|
||||
case '*'
|
||||
echo -ns '?'
|
||||
end
|
||||
end
|
||||
|
||||
function _tide_detect_os_linux_cases -a file key
|
||||
test -e $file || return
|
||||
set -l split_file (string split '=' <$file)
|
||||
set -l key_index (contains --index $key $split_file) || return
|
||||
set -l value (string trim --chars='"' $split_file[(math $key_index + 1)])
|
||||
|
||||
# Anything which would have pure white background has been changed to D4D4D4
|
||||
# It was just too bright otherwise
|
||||
switch (string lower $value)
|
||||
case alpine
|
||||
printf %s\n FFFFFF 0D597F # from alpine logo
|
||||
case arch
|
||||
printf %s\n 1793D1 4D4D4D # from arch wiki header
|
||||
case centos
|
||||
printf %s\n 000000 D4D4D4 # https://wiki.centos.org/ArtWork/Brand/Logo, monochromatic
|
||||
case debian
|
||||
printf %s\n C70036 D4D4D4 # from debian logo https://www.debian.org/logos/openlogo-nd-100.png
|
||||
case devuan
|
||||
printf %s\n $defaultColor # logo is monochromatic
|
||||
case elementary
|
||||
printf %s\n 000000 D4D4D4 # https://elementary.io/brand, encouraged to be monochromatic
|
||||
case fedora
|
||||
printf %s\n FFFFFF 294172 # from logo https://fedoraproject.org/w/uploads/2/2d/Logo_fedoralogo.png
|
||||
case gentoo
|
||||
printf %s\n FFFFFF 54487A # https://wiki.gentoo.org/wiki/Project:Artwork/Colors
|
||||
case mageia
|
||||
printf %s\n FFFFFF 262F45 # https://wiki.mageia.org/en/Artwork_guidelines
|
||||
case manjaro
|
||||
printf %s\n FFFFFF 35BF5C # from https://gitlab.manjaro.org/artwork/branding/logo/-/blob/master/logo.svg
|
||||
case mint linuxmint
|
||||
printf %s\n FFFFFF 69B53F # extracted from https://linuxmint.com/web/img/favicon.ico
|
||||
case nixos
|
||||
printf %s\n FFFFFF 5277C3 # https://github.com/NixOS/nixos-artwork/tree/master/logo
|
||||
case opensuse-leap opensuse-tumbleweed opensuse-microos
|
||||
printf %s\n 73BA25 173f4f # https://en.opensuse.org/openSUSE:Artwork_brand
|
||||
case raspbian
|
||||
printf %s\n FFFFFF A22846 # https://static.raspberrypi.org/files/Raspberry_Pi_Visual_Guidelines_2020.pdf
|
||||
case rhel
|
||||
printf %s\n EE0000 000000 # https://www.redhat.com/en/about/brand/standards/color
|
||||
case sabayon
|
||||
printf %s\n $defaultColor # Can't find colors, and they are rebranding anyway
|
||||
case slackware
|
||||
printf %s\n $defaultColor # Doesn't really have a logo, and the colors are too close to PWD blue anyway
|
||||
case ubuntu
|
||||
printf %s\n E95420 D4D4D4 # https://design.ubuntu.com/brand/
|
||||
case void
|
||||
printf %s\n FFFFFF 478061 # from https://alpha.de.repo.voidlinux.org/logos/void.svg
|
||||
case '*'
|
||||
return 1
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
function _tide_find_and_remove -a name list --no-scope-shadowing
|
||||
contains --index $name $$list | read -l index && set -e "$list"[$index]
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
function _tide_fish_colorize
|
||||
if command -q fish_indent
|
||||
echo -ns "$argv" | fish_indent --ansi
|
||||
else
|
||||
echo -ns "$argv"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
function _tide_item_aws
|
||||
# AWS_PROFILE overrides AWS_DEFAULT_PROFILE, AWS_REGION overrides AWS_DEFAULT_REGION
|
||||
set -q AWS_PROFILE && set -l AWS_DEFAULT_PROFILE $AWS_PROFILE
|
||||
set -q AWS_REGION && set -l AWS_DEFAULT_REGION $AWS_REGION
|
||||
|
||||
if test -n "$AWS_DEFAULT_PROFILE" && test -n "$AWS_DEFAULT_REGION"
|
||||
_tide_print_item aws $tide_aws_icon' ' "$AWS_DEFAULT_PROFILE/$AWS_DEFAULT_REGION"
|
||||
else if test -n "$AWS_DEFAULT_PROFILE$AWS_DEFAULT_REGION"
|
||||
_tide_print_item aws $tide_aws_icon' ' "$AWS_DEFAULT_PROFILE$AWS_DEFAULT_REGION"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
function _tide_item_bun
|
||||
if path is $_tide_parent_dirs/bun.lockb
|
||||
bun --version | string match -qr "(?<v>.*)"
|
||||
_tide_print_item bun $tide_bun_icon' ' $v
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
function _tide_item_character
|
||||
test $_tide_status = 0 && set_color $tide_character_color || set_color $tide_character_color_failure
|
||||
|
||||
set -q add_prefix || echo -ns ' '
|
||||
|
||||
test "$fish_key_bindings" = fish_default_key_bindings && echo -ns $tide_character_icon ||
|
||||
switch $fish_bind_mode
|
||||
case insert
|
||||
echo -ns $tide_character_icon
|
||||
case default
|
||||
echo -ns $tide_character_vi_icon_default
|
||||
case replace replace_one
|
||||
echo -ns $tide_character_vi_icon_replace
|
||||
case visual
|
||||
echo -ns $tide_character_vi_icon_visual
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,12 @@
|
||||
function _tide_item_cmd_duration
|
||||
test $CMD_DURATION -gt $tide_cmd_duration_threshold && t=(
|
||||
math -s0 "$CMD_DURATION/3600000" # Hours
|
||||
math -s0 "$CMD_DURATION/60000"%60 # Minutes
|
||||
math -s$tide_cmd_duration_decimals "$CMD_DURATION/1000"%60) if test $t[1] != 0
|
||||
_tide_print_item cmd_duration $tide_cmd_duration_icon' ' "$t[1]h $t[2]m $t[3]s"
|
||||
else if test $t[2] != 0
|
||||
_tide_print_item cmd_duration $tide_cmd_duration_icon' ' "$t[2]m $t[3]s"
|
||||
else
|
||||
_tide_print_item cmd_duration $tide_cmd_duration_icon' ' "$t[3]s"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
function _tide_item_context
|
||||
if set -q SSH_TTY
|
||||
set -fx tide_context_color $tide_context_color_ssh
|
||||
else if test "$EUID" = 0
|
||||
set -fx tide_context_color $tide_context_color_root
|
||||
else if test "$tide_context_always_display" = true
|
||||
set -fx tide_context_color $tide_context_color_default
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
string match -qr "^(?<h>(\.?[^\.]*){0,$tide_context_hostname_parts})" @$hostname
|
||||
_tide_print_item context $USER$h
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
function _tide_item_crystal
|
||||
if path is $_tide_parent_dirs/shard.yml
|
||||
crystal --version | string match -qr "(?<v>[\d.]+)"
|
||||
_tide_print_item crystal $tide_crystal_icon' ' $v
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
function _tide_item_direnv
|
||||
set -q DIRENV_DIR || return
|
||||
direnv status | string match -q 'Found RC allowed false' &&
|
||||
set -lx tide_direnv_color $tide_direnv_color_denied &&
|
||||
set -lx tide_direnv_bg_color $tide_direnv_bg_color_denied
|
||||
_tide_print_item direnv $tide_direnv_icon
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
function _tide_item_distrobox
|
||||
test -e /etc/profile.d/distrobox_profile.sh && test -e /run/.containerenv &&
|
||||
_tide_print_item distrobox $tide_distrobox_icon' ' (string match -rg 'name="(.*)"' </run/.containerenv)
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
function _tide_item_docker
|
||||
docker context inspect --format '{{.Name}}' | read -l context
|
||||
contains -- "$context" $tide_docker_default_contexts ||
|
||||
_tide_print_item docker $tide_docker_icon' ' $context
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
function _tide_item_elixir
|
||||
path is $_tide_parent_dirs/mix.exs &&
|
||||
_tide_print_item elixir $tide_elixir_icon' ' (elixir --short-version)
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
function _tide_item_gcloud
|
||||
set -q CLOUDSDK_CONFIG || set -l CLOUDSDK_CONFIG ~/.config/gcloud
|
||||
path is $CLOUDSDK_CONFIG/active_config &&
|
||||
read -l config <$CLOUDSDK_CONFIG/active_config &&
|
||||
path is $CLOUDSDK_CONFIG/configurations/config_$config &&
|
||||
string match -qr '^\s*project\s*=\s*(?<project>.*)' <$CLOUDSDK_CONFIG/configurations/config_$config &&
|
||||
_tide_print_item gcloud $tide_gcloud_icon' ' $project
|
||||
end
|
||||
@@ -0,0 +1,72 @@
|
||||
function _tide_item_git
|
||||
if git branch --show-current 2>/dev/null | string shorten -"$tide_git_truncation_strategy"m$tide_git_truncation_length | read -l location
|
||||
git rev-parse --git-dir --is-inside-git-dir | read -fL gdir in_gdir
|
||||
set location $_tide_location_color$location
|
||||
else if test $pipestatus[1] != 0
|
||||
return
|
||||
else if git tag --points-at HEAD | string shorten -"$tide_git_truncation_strategy"m$tide_git_truncation_length | read location
|
||||
git rev-parse --git-dir --is-inside-git-dir | read -fL gdir in_gdir
|
||||
set location '#'$_tide_location_color$location
|
||||
else
|
||||
git rev-parse --git-dir --is-inside-git-dir --short HEAD | read -fL gdir in_gdir location
|
||||
set location @$_tide_location_color$location
|
||||
end
|
||||
|
||||
# Operation
|
||||
if test -d $gdir/rebase-merge
|
||||
# Turn ANY into ALL, via double negation
|
||||
if not path is -v $gdir/rebase-merge/{msgnum,end}
|
||||
read -f step <$gdir/rebase-merge/msgnum
|
||||
read -f total_steps <$gdir/rebase-merge/end
|
||||
end
|
||||
test -f $gdir/rebase-merge/interactive && set -f operation rebase-i || set -f operation rebase-m
|
||||
else if test -d $gdir/rebase-apply
|
||||
if not path is -v $gdir/rebase-apply/{next,last}
|
||||
read -f step <$gdir/rebase-apply/next
|
||||
read -f total_steps <$gdir/rebase-apply/last
|
||||
end
|
||||
if test -f $gdir/rebase-apply/rebasing
|
||||
set -f operation rebase
|
||||
else if test -f $gdir/rebase-apply/applying
|
||||
set -f operation am
|
||||
else
|
||||
set -f operation am/rebase
|
||||
end
|
||||
else if test -f $gdir/MERGE_HEAD
|
||||
set -f operation merge
|
||||
else if test -f $gdir/CHERRY_PICK_HEAD
|
||||
set -f operation cherry-pick
|
||||
else if test -f $gdir/REVERT_HEAD
|
||||
set -f operation revert
|
||||
else if test -f $gdir/BISECT_LOG
|
||||
set -f operation bisect
|
||||
end
|
||||
|
||||
# Git status/stash + Upstream behind/ahead
|
||||
test $in_gdir = true && set -l _set_dir_opt -C $gdir/..
|
||||
# Suppress errors in case we are in a bare repo or there is no upstream
|
||||
set -l stat (git $_set_dir_opt --no-optional-locks status --porcelain 2>/dev/null)
|
||||
string match -qr '(0|(?<stash>.*))\n(0|(?<conflicted>.*))\n(0|(?<staged>.*))
|
||||
(0|(?<dirty>.*))\n(0|(?<untracked>.*))(\n(0|(?<behind>.*))\t(0|(?<ahead>.*)))?' \
|
||||
"$(git $_set_dir_opt stash list 2>/dev/null | count
|
||||
string match -r ^UU $stat | count
|
||||
string match -r ^[ADMR] $stat | count
|
||||
string match -r ^.[ADMR] $stat | count
|
||||
string match -r '^\?\?' $stat | count
|
||||
git rev-list --count --left-right @{upstream}...HEAD 2>/dev/null)"
|
||||
|
||||
if test -n "$operation$conflicted"
|
||||
set -g tide_git_bg_color $tide_git_bg_color_urgent
|
||||
else if test -n "$staged$dirty$untracked"
|
||||
set -g tide_git_bg_color $tide_git_bg_color_unstable
|
||||
end
|
||||
|
||||
_tide_print_item git $_tide_location_color$tide_git_icon' ' (set_color white; echo -ns $location
|
||||
set_color $tide_git_color_operation; echo -ns ' '$operation ' '$step/$total_steps
|
||||
set_color $tide_git_color_upstream; echo -ns ' ⇣'$behind ' ⇡'$ahead
|
||||
set_color $tide_git_color_stash; echo -ns ' *'$stash
|
||||
set_color $tide_git_color_conflicted; echo -ns ' ~'$conflicted
|
||||
set_color $tide_git_color_staged; echo -ns ' +'$staged
|
||||
set_color $tide_git_color_dirty; echo -ns ' !'$dirty
|
||||
set_color $tide_git_color_untracked; echo -ns ' ?'$untracked)
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
function _tide_item_go
|
||||
if path is $_tide_parent_dirs/go.mod
|
||||
go version | string match -qr "(?<v>[\d.]+)"
|
||||
_tide_print_item go $tide_go_icon' ' $v
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
function _tide_item_java
|
||||
if path is $_tide_parent_dirs/pom.xml
|
||||
java -version &| string match -qr "(?<v>[\d.]+)"
|
||||
_tide_print_item java $tide_java_icon' ' $v
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
function _tide_item_jobs
|
||||
set -q _tide_jobs && if test $_tide_jobs -ge $tide_jobs_number_threshold
|
||||
_tide_print_item jobs $tide_jobs_icon' ' $_tide_jobs
|
||||
else
|
||||
_tide_print_item jobs $tide_jobs_icon
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
function _tide_item_kubectl
|
||||
kubectl config view --minify --output 'jsonpath={.current-context}/{..namespace}' 2>/dev/null | read -l context &&
|
||||
_tide_print_item kubectl $tide_kubectl_icon' ' (string replace -r '/(|default)$' '' $context)
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
function _tide_item_nix_shell
|
||||
set -q IN_NIX_SHELL && _tide_print_item nix_shell $tide_nix_shell_icon' ' $IN_NIX_SHELL
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
function _tide_item_node
|
||||
if path is $_tide_parent_dirs/package.json
|
||||
node --version | string match -qr "v(?<v>.*)"
|
||||
_tide_print_item node $tide_node_icon' ' $v
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
function _tide_item_os
|
||||
_tide_print_item os $tide_os_icon
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
function _tide_item_php
|
||||
if path is $_tide_parent_dirs/composer.json
|
||||
php --version | string match -qr "(?<v>[\d.]+)"
|
||||
_tide_print_item php $tide_php_icon' ' $v
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
function _tide_item_private_mode
|
||||
set -q _tide_private_mode && _tide_print_item private_mode $tide_private_mode_icon
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
function _tide_item_pulumi
|
||||
if path filter $_tide_parent_dirs/Pulumi.yaml | read -l yaml_path
|
||||
if command -q sha1sum
|
||||
echo -n "$yaml_path" | sha1sum | string match -qr "(?<path_hash>.{40})"
|
||||
else if command -q shasum
|
||||
echo -n "$yaml_path" | shasum | string match -qr "(?<path_hash>.{40})"
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
string match -qr 'name: *(?<project_name>.*)' <$yaml_path
|
||||
set -l workspace_file "$HOME/.pulumi/workspaces/$project_name-$path_hash-workspace.json"
|
||||
|
||||
if test -e $workspace_file
|
||||
string match -qr '"stack": *"(?<stack>.*)"' <$workspace_file
|
||||
_tide_print_item pulumi $tide_pulumi_icon' ' $stack
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
function _tide_item_python
|
||||
if test -n "$VIRTUAL_ENV"
|
||||
if command -q python3
|
||||
python3 --version | string match -qr "(?<v>[\d.]+)"
|
||||
else
|
||||
python --version | string match -qr "(?<v>[\d.]+)"
|
||||
end
|
||||
string match -qr "^.*/(?<dir>.*)/(?<base>.*)" $VIRTUAL_ENV
|
||||
# pipenv $VIRTUAL_ENV looks like /home/ilan/.local/share/virtualenvs/pipenv_project-EwRYuc3l
|
||||
# Detect whether we are using pipenv by looking for 'virtualenvs'. If so, remove the hash at the end.
|
||||
if test "$dir" = virtualenvs
|
||||
string match -qr "(?<base>.*)-.*" $base
|
||||
_tide_print_item python $tide_python_icon' ' "$v ($base)"
|
||||
else if contains -- "$base" virtualenv venv .venv env # avoid generic names
|
||||
_tide_print_item python $tide_python_icon' ' "$v ($dir)"
|
||||
else
|
||||
_tide_print_item python $tide_python_icon' ' "$v ($base)"
|
||||
end
|
||||
else if path is .python-version Pipfile __init__.py pyproject.toml requirements.txt setup.py
|
||||
if command -q python3
|
||||
python3 --version | string match -qr "(?<v>[\d.]+)"
|
||||
else
|
||||
python --version | string match -qr "(?<v>[\d.]+)"
|
||||
end
|
||||
_tide_print_item python $tide_python_icon' ' $v
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
function _tide_item_ruby
|
||||
if path is $_tide_parent_dirs/{*.gemspec,Gemfile,Rakefile,.ruby-version}
|
||||
ruby --version | string match -qr "(?<v>[\d.]+)"
|
||||
_tide_print_item ruby $tide_ruby_icon' ' $v
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
function _tide_item_rustc
|
||||
if path is $_tide_parent_dirs/Cargo.toml
|
||||
rustc --version | string match -qr "(?<v>[\d.]+)"
|
||||
_tide_print_item rustc $tide_rustc_icon' ' $v
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
function _tide_item_shlvl
|
||||
# Non-interactive shells do not increment SHLVL, so we don't need to subtract 1
|
||||
test $SHLVL -gt $tide_shlvl_threshold && _tide_print_item shlvl $tide_shlvl_icon' ' $SHLVL
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
function _tide_item_status
|
||||
if string match -qv 0 $_tide_pipestatus # If there is a failure anywhere in the pipestatus
|
||||
if test "$_tide_pipestatus" = 1 # If simple failure
|
||||
contains character $_tide_left_items || tide_status_bg_color=$tide_status_bg_color_failure \
|
||||
tide_status_color=$tide_status_color_failure _tide_print_item status $tide_status_icon_failure' ' 1
|
||||
else
|
||||
fish_status_to_signal $_tide_pipestatus | string replace SIG '' | string join '|' | read -l out
|
||||
test $_tide_status = 0 && _tide_print_item status $tide_status_icon' ' $out ||
|
||||
tide_status_bg_color=$tide_status_bg_color_failure tide_status_color=$tide_status_color_failure \
|
||||
_tide_print_item status $tide_status_icon_failure' ' $out
|
||||
end
|
||||
else if not contains character $_tide_left_items
|
||||
_tide_print_item status $tide_status_icon
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
function _tide_item_terraform
|
||||
path is $_tide_parent_dirs/.terraform &&
|
||||
terraform workspace show | string match -v default | read -l w &&
|
||||
_tide_print_item terraform $tide_terraform_icon' ' $w
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
function _tide_item_time
|
||||
_tide_print_item time (date +$tide_time_format)
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
function _tide_item_toolbox
|
||||
test -e /run/.toolboxenv &&
|
||||
_tide_print_item toolbox $tide_toolbox_icon' ' (string match -rg 'name="(.*)"' </run/.containerenv)
|
||||
end
|
||||
@@ -0,0 +1,16 @@
|
||||
function _tide_item_vi_mode
|
||||
test "$fish_key_bindings" != fish_default_key_bindings && switch $fish_bind_mode
|
||||
case default
|
||||
tide_vi_mode_bg_color=$tide_vi_mode_bg_color_default tide_vi_mode_color=$tide_vi_mode_color_default \
|
||||
_tide_print_item vi_mode $tide_vi_mode_icon_default
|
||||
case insert
|
||||
tide_vi_mode_bg_color=$tide_vi_mode_bg_color_insert tide_vi_mode_color=$tide_vi_mode_color_insert \
|
||||
_tide_print_item vi_mode $tide_vi_mode_icon_insert
|
||||
case replace replace_one
|
||||
tide_vi_mode_bg_color=$tide_vi_mode_bg_color_replace tide_vi_mode_color=$tide_vi_mode_color_replace \
|
||||
_tide_print_item vi_mode $tide_vi_mode_icon_replace
|
||||
case visual
|
||||
tide_vi_mode_bg_color=$tide_vi_mode_bg_color_visual tide_vi_mode_color=$tide_vi_mode_color_visual \
|
||||
_tide_print_item vi_mode $tide_vi_mode_icon_visual
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
function _tide_item_zig
|
||||
if path is $_tide_parent_dirs/build.zig
|
||||
zig version | string match -qr "(?<v>[\d.]+(-dev)?)"
|
||||
_tide_print_item zig $tide_zig_icon' ' $v
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
function _tide_parent_dirs --on-variable PWD
|
||||
set -g _tide_parent_dirs (string escape (
|
||||
for dir in (string split / -- $PWD)
|
||||
set -la parts $dir
|
||||
string join / -- $parts
|
||||
end))
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
function _tide_print_item -a item
|
||||
v=tide_"$item"_bg_color set -f item_bg_color $$v
|
||||
|
||||
if set -e add_prefix
|
||||
set_color $item_bg_color -b normal
|
||||
v=tide_"$_tide_side"_prompt_prefix echo -ns $$v
|
||||
else if test "$item_bg_color" = "$prev_bg_color"
|
||||
v=tide_"$_tide_side"_prompt_separator_same_color echo -ns $_tide_color_separator_same_color$$v
|
||||
else if test $_tide_side = left
|
||||
set_color $prev_bg_color -b $item_bg_color
|
||||
echo -ns $tide_left_prompt_separator_diff_color
|
||||
else
|
||||
set_color $item_bg_color -b $prev_bg_color
|
||||
echo -ns $tide_right_prompt_separator_diff_color
|
||||
end
|
||||
|
||||
v=tide_"$item"_color set_color $$v -b $item_bg_color
|
||||
|
||||
echo -ns $_tide_pad $argv[2..] $_tide_pad
|
||||
|
||||
set -g prev_bg_color $item_bg_color
|
||||
end
|
||||
@@ -0,0 +1,42 @@
|
||||
set_color -o $tide_pwd_color_anchors | read -l color_anchors
|
||||
set_color $tide_pwd_color_truncated_dirs | read -l color_truncated
|
||||
set -l reset_to_color_dirs (set_color normal -b $tide_pwd_bg_color; set_color $tide_pwd_color_dirs)
|
||||
|
||||
set -l unwritable_icon $tide_pwd_icon_unwritable' '
|
||||
set -l home_icon $tide_pwd_icon_home' '
|
||||
set -l pwd_icon $tide_pwd_icon' '
|
||||
|
||||
eval "function _tide_pwd
|
||||
if set -l split_pwd (string replace -r '^$HOME' '~' -- \$PWD | string split /)
|
||||
test -w . && set -f split_output \"$pwd_icon\$split_pwd[1]\" \$split_pwd[2..] ||
|
||||
set -f split_output \"$unwritable_icon\$split_pwd[1]\" \$split_pwd[2..]
|
||||
set split_output[-1] \"$color_anchors\$split_output[-1]$reset_to_color_dirs\"
|
||||
else
|
||||
set -f split_output \"$home_icon$color_anchors~\"
|
||||
end
|
||||
|
||||
string join / -- \$split_output | string length -V | read -g _tide_pwd_len
|
||||
|
||||
i=1 for dir_section in \$split_pwd[2..-2]
|
||||
string join -- / \$split_pwd[..\$i] | string replace '~' $HOME | read -l parent_dir # Uses i before increment
|
||||
|
||||
math \$i+1 | read i
|
||||
|
||||
if path is \$parent_dir/\$dir_section/\$tide_pwd_markers
|
||||
set split_output[\$i] \"$color_anchors\$dir_section$reset_to_color_dirs\"
|
||||
else if test \$_tide_pwd_len -gt \$dist_btwn_sides
|
||||
string match -qr \"(?<trunc>\..|.)\" \$dir_section
|
||||
|
||||
set -l glob \$parent_dir/\$trunc*/
|
||||
set -e glob[(contains -i \$parent_dir/\$dir_section/ \$glob)] # This is faster than inverse string match
|
||||
|
||||
while string match -qr \"^\$parent_dir/\$(string escape --style=regex \$trunc)\" \$glob &&
|
||||
string match -qr \"(?<trunc>\$(string escape --style=regex \$trunc).)\" \$dir_section
|
||||
end
|
||||
test -n \"\$trunc\" && set split_output[\$i] \"$color_truncated\$trunc$reset_to_color_dirs\" &&
|
||||
string join / \$split_output | string length -V | read _tide_pwd_len
|
||||
end
|
||||
end
|
||||
|
||||
string join -- / \"$reset_to_color_dirs\$split_output[1]\" \$split_output[2..]
|
||||
end"
|
||||
@@ -0,0 +1,25 @@
|
||||
function _tide_remove_unusable_items
|
||||
# Remove tool-specific items for tools the machine doesn't have installed
|
||||
set -l removed_items
|
||||
for item in aws bun crystal direnv distrobox docker elixir gcloud git go java kubectl nix_shell node php pulumi python ruby rustc terraform toolbox zig
|
||||
contains $item $tide_left_prompt_items $tide_right_prompt_items || continue
|
||||
|
||||
set -l cli_names $item
|
||||
switch $item
|
||||
case distrobox # there is no 'distrobox' command inside the container
|
||||
set cli_names distrobox-export # 'distrobox-export' and 'distrobox-host-exec' are available
|
||||
case nix_shell
|
||||
set cli_names nix nix-shell
|
||||
case python
|
||||
set cli_names python python3
|
||||
end
|
||||
type --query $cli_names || set -a removed_items $item
|
||||
end
|
||||
|
||||
set -U _tide_left_items (for item in $tide_left_prompt_items
|
||||
contains $item $removed_items || echo $item
|
||||
end)
|
||||
set -U _tide_right_items (for item in $tide_right_prompt_items
|
||||
contains $item $removed_items || echo $item
|
||||
end)
|
||||
end
|
||||
@@ -0,0 +1,73 @@
|
||||
function _tide_sub_bug-report
|
||||
argparse c/clean v/verbose check -- $argv
|
||||
|
||||
set -l fish_path (status fish-path)
|
||||
|
||||
if set -q _flag_clean
|
||||
HOME=(mktemp -d) $fish_path --init-command "curl --silent \
|
||||
https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish |
|
||||
source && fisher install ilancosman/tide@v6"
|
||||
else if set -q _flag_verbose
|
||||
set --long | string match -r "^_?tide.*" | # Get only tide variables
|
||||
string match -r --invert "^_tide_prompt_var.*" # Remove _tide_prompt_var
|
||||
else
|
||||
$fish_path --version | string match -qr "fish, version (?<fish_version>.*)"
|
||||
_tide_check_version Fish fish-shell/fish-shell "(?<v>[\d.]+)" $fish_version || return
|
||||
|
||||
tide --version | string match -qr "tide, version (?<tide_version>.*)"
|
||||
_tide_check_version Tide IlanCosman/tide "v(?<v>[\d.]+)" $tide_version || return
|
||||
|
||||
if command --query git
|
||||
test (path sort (git --version) "git version 2.22.0")[1] = "git version 2.22.0"
|
||||
_tide_check_condition \
|
||||
"Your git version is too old." \
|
||||
"Tide requires at least version 2.22." \
|
||||
"Please update before submitting a bug report." || return
|
||||
end
|
||||
|
||||
# Check that omf is not installed
|
||||
not functions --query omf
|
||||
_tide_check_condition \
|
||||
"Tide does not work with oh-my-fish installed." \
|
||||
"Please uninstall it before submitting a bug report." || return
|
||||
|
||||
if not set -q _flag_check
|
||||
$fish_path -ic "time $fish_path -c exit" 2>|
|
||||
string match -rg "Executed in(.*)fish" |
|
||||
string trim | read -l fish_startup_time
|
||||
|
||||
read -l --prompt-str "What operating system are you using? (e.g Ubuntu 20.04): " os
|
||||
read -l --prompt-str "What terminal emulator are you using? (e.g Kitty): " terminal_emulator
|
||||
|
||||
printf '%b\n' "\nPlease copy the following information into the issue:\n" \
|
||||
"fish version: $fish_version" \
|
||||
"tide version: $tide_version" \
|
||||
"term: $TERM" \
|
||||
"os: $os" \
|
||||
"terminal emulator: $terminal_emulator" \
|
||||
"fish startup: $fish_startup_time" \
|
||||
"fisher plugins: $_fisher_plugins"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function _tide_check_version -a program_name repo_name regex_to_get_v installed_version
|
||||
curl -sL https://github.com/$repo_name/releases/latest |
|
||||
string match -qr "https://github.com/$repo_name/releases/tag/$regex_to_get_v"
|
||||
|
||||
string match -qr "^$v" "$installed_version" # Allow git versions, e.g 3.3.1-701-gceade1629
|
||||
_tide_check_condition \
|
||||
"Your $program_name version is out of date." \
|
||||
"The latest is $v. You have $installed_version." \
|
||||
"Please update before submitting a bug report."
|
||||
end
|
||||
|
||||
function _tide_check_condition
|
||||
if test "$status" != 0
|
||||
set_color red
|
||||
printf '%s\n' $argv
|
||||
set_color normal
|
||||
return 1
|
||||
end
|
||||
return 0
|
||||
end
|
||||
@@ -0,0 +1,156 @@
|
||||
set -g _tide_color_dark_blue 0087AF
|
||||
set -g _tide_color_dark_green 5FAF00
|
||||
set -g _tide_color_gold D7AF00
|
||||
set -g _tide_color_green 5FD700
|
||||
set -g _tide_color_light_blue 00AFFF
|
||||
|
||||
# Create an empty fake function for each item
|
||||
for func in _fake(functions --all | string match --entire _tide_item)
|
||||
function $func
|
||||
end
|
||||
end
|
||||
|
||||
for file in (status dirname)/tide/configure/{choices, functions}/**.fish
|
||||
source $file
|
||||
end
|
||||
|
||||
function _tide_sub_configure
|
||||
set -l choices (path basename (status dirname)/tide/configure/choices/**.fish | path change-extension '')
|
||||
argparse auto $choices= -- $argv
|
||||
|
||||
for var in (set -l --names | string match -e _flag)
|
||||
set -x $var $$var
|
||||
end
|
||||
|
||||
if set -q _flag_auto
|
||||
set -fx _flag_finish 'Overwrite your current tide config'
|
||||
else if test $COLUMNS -lt 55 -o $LINES -lt 21
|
||||
echo 'Terminal size too small; must be at least 55 x 21'
|
||||
return 1
|
||||
end
|
||||
|
||||
_tide_detect_os | read -g --line os_branding_icon os_branding_color os_branding_bg_color
|
||||
|
||||
set -g fake_columns $COLUMNS
|
||||
test $fake_columns -gt 90 && set fake_columns 90
|
||||
set -g fake_lines $LINES
|
||||
|
||||
set -g _tide_selected_option
|
||||
_next_choice all/style
|
||||
end
|
||||
|
||||
function _next_choice -a nextChoice
|
||||
set -q _tide_selected_option || return 0
|
||||
set -l cmd (string split '/' $nextChoice)[2]
|
||||
$cmd
|
||||
end
|
||||
|
||||
function _tide_title -a text
|
||||
set -q _flag_auto && return
|
||||
|
||||
command -q clear && clear
|
||||
set_color -o
|
||||
string pad --width (math --scale=0 "$fake_columns/2" + (string length $text)/2) $text
|
||||
set_color normal
|
||||
|
||||
set -g _tide_configure_first_option_after_title
|
||||
end
|
||||
|
||||
function _tide_option -a symbol text
|
||||
set -ga _tide_symbol_list $symbol
|
||||
set -ga _tide_option_list $text
|
||||
|
||||
if not set -q _flag_auto
|
||||
set -g _tide_configure_first_prompt_after_option
|
||||
|
||||
set_color -o
|
||||
set -e _tide_configure_first_option_after_title || echo
|
||||
echo "($symbol) $text"
|
||||
set_color normal
|
||||
end
|
||||
end
|
||||
|
||||
function _tide_menu -a func
|
||||
if set -q _flag_auto
|
||||
set -l flag_var_name _flag_$func
|
||||
set -g _tide_selected_option $$flag_var_name
|
||||
|
||||
if test -z "$_tide_selected_option"
|
||||
echo "Missing input for choice '$func'"
|
||||
_tide_exit_configure
|
||||
else if not contains $_tide_selected_option $_tide_option_list
|
||||
echo "Invalid input '$_tide_selected_option' for choice '$func'"
|
||||
_tide_exit_configure
|
||||
else
|
||||
set -e _tide_symbol_list
|
||||
set -e _tide_option_list
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
argparse no-restart -- $argv # Add no-restart option for first menu
|
||||
|
||||
echo
|
||||
if not set -q _flag_no_restart
|
||||
set -f r r
|
||||
echo '(r) Restart from the beginning'
|
||||
end
|
||||
echo '(q) Quit and do nothing'\n
|
||||
|
||||
while read --nchars 1 --prompt-str \
|
||||
"$(set_color -o)Choice [$(string join '/' $_tide_symbol_list $r q)] $(set_color normal)" input
|
||||
switch $input
|
||||
case r
|
||||
set -q _flag_no_restart && continue
|
||||
set -e _tide_symbol_list
|
||||
set -e _tide_option_list
|
||||
_next_choice all/style
|
||||
break
|
||||
case q
|
||||
_tide_exit_configure
|
||||
set -e _tide_symbol_list
|
||||
set -e _tide_option_list
|
||||
command -q clear && clear
|
||||
break
|
||||
case $_tide_symbol_list
|
||||
set -g _tide_selected_option $_tide_option_list[(contains -i $input $_tide_symbol_list)]
|
||||
test "$func" != finish &&
|
||||
set -a _tide_configure_current_options --$func=(string escape $_tide_selected_option)
|
||||
set -e _tide_symbol_list
|
||||
set -e _tide_option_list
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function _tide_display_prompt
|
||||
set -q _flag_auto && return
|
||||
|
||||
_fake_tide_cache_variables
|
||||
set -l prompt (_fake_tide_prompt)
|
||||
|
||||
set -l bottom_left_prompt_string_length (string length --visible $prompt[-1])
|
||||
set -l right_prompt_string (string pad --width (math $fake_columns-$bottom_left_prompt_string_length) $prompt[1])
|
||||
set -l prompt[-1] "$prompt[-1]$right_prompt_string"
|
||||
|
||||
if set -q _configure_transient
|
||||
if contains newline $fake_tide_left_prompt_items
|
||||
string unescape $prompt[3..]
|
||||
else
|
||||
_fake_tide_item_character
|
||||
echo
|
||||
end
|
||||
else
|
||||
if not set -q _tide_configure_first_prompt_after_option
|
||||
test "$fake_tide_prompt_add_newline_before" = true && echo
|
||||
end
|
||||
string unescape $prompt[2..]
|
||||
end
|
||||
|
||||
set -e _tide_configure_first_prompt_after_option
|
||||
set_color normal
|
||||
end
|
||||
|
||||
function _tide_exit_configure
|
||||
set -e _tide_selected_option # Skip through all switch and _next_choice
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
function _tide_sub_reload
|
||||
source (functions --details fish_prompt)
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
# Disable default vi prompt
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user