Initial commit

This commit is contained in:
Ulysse Cura 2025-10-28 01:16:13 +01:00
commit 14423a6dd1
3 changed files with 366 additions and 0 deletions

42
README.md Normal file
View File

@ -0,0 +1,42 @@
# CommandPrompt
## Description
This CommandPrompt is an *highly* customised prompt for bash
It show the time, user, current directory and an info.
The info is an icon if pwd is in the configured special folders (see more below).
However if pwd is in the directory or sub-directory of a project, it will find by probabilities
where the project root is and show the project's folder name.
It also detect the majority language in the current directory and displays an icon depending on it !
For the moment the supported language are :
- C
- C++
- Rust
- Go
- Python
- Java
- Ruby
- Javascript
- PHP
- C#
- HTML/CSS (considered same language)
## How to install
You can install this prompt by copying the file to any directory you want (for example ~/.config/bash/)
and calling with **source** the file at the end of your .bashrc or .profile depending on your system.
If your system is in a different language you can change the special folder names direcly at the beginning
of the file.
## Internal commands
This command prompt include 2 internal command that you can call manually if you want to
manipulate cache or debug the prompt.
These are :
- find_project_root_dir
- find_dir_majority_language
For more info call them with --help.

BIN
media/prompt showcase.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

324
prompt Normal file
View File

@ -0,0 +1,324 @@
#!/bin/env bash
# folder names, change it depending on your language
documents="Documents"
music="Music"
pictures="Pictures"
videos="Videos"
downloads="Downloads"
declare -A PROJECT_ROOT_CACHE
export FIND_PROJECT_ROOT_DEBUG=0
find_project_root() {
local args=${@}
local cache_key="cache_$(echo -n $PWD | md5sum | cut -d' ' -f1)"
# args detection
for arg in ${args}; do
if [[ "${arg:0:2}" = "--" ]]; then
arg="${arg:2}"
case "${arg}" in
"help")
echo -e "Usage : find_project_root [OPTION(S)]\n"
echo "Find the folder that could be a project root."
echo "It is automatically called by the prompt generator but you can call it if you want to access or modify the cache.\n"
echo "The result is stocked in the env variable PROJECT_ROOT. The exit value is 0 when project root found or 1 if not."
echo "Options :"
echo " --print-cache print project root cache"
echo " --clear-cache clear project root cache ; WARNING : the cache is wiped automatically in new bash instances."
echo " --toggle-debug toggle debug mode"
echo " --help display this help"
return 0 ;;
"print-cache")
for key in ${!PROJECT_ROOT_CACHE[@]}; do
echo "[${key}]=${PROJECT_ROOT_CACHE[$key]}"
done ;;
"clear-cache")
PROJECT_ROOT_CACHE=() ;;
"toggle-debug")
FIND_PROJECT_ROOT_DEBUG=$((! FIND_PROJECT_ROOT_DEBUG)) ;;
*)
echo -e "Error : unrecognised parameter : --${arg}\n Try typing --help" ;;
esac
else
echo -e "Error : unrecognised parameter : ${arg}\n Try typing --help"
fi
done
# search cache for existing data
if [[ -n "${PROJECT_ROOT_CACHE[$cache_key]}" ]]; then
if [[ "${PROJECT_ROOT_CACHE[$cache_key]}" != "." ]]; then
PROJECT_ROOT="${PROJECT_ROOT_CACHE[$cache_key]}"
return 0
fi
PROJECT_ROOT=""
return 1
fi
# estimate probability of root dir
local depth=0
local current_dir="$PWD"
local current_max_score=0
local current_dir_score=0
local project_root="."
while (( depth < 10 )) && [[ "${current_dir}" != "/" ]]; do
current_dir_score=0
# 100% root
for path in README.md README.rst README LICENSE \
Dockerfile docker-compose.yml \
.git; do
if [[ -e "${current_dir}/${path}" ]]; then
(( FIND_PROJECT_ROOT_DEBUG )) && echo "${path}"
((current_dir_score += 100))
fi
done
# 90% root
for path in CMakeLists.txt \
Cargo.toml Cargo.lock \
go.mod go.sum \
pyproject.toml \
pom.xml \
package.json \
.csproj .sln; do
if [[ -e "${current_dir}/${path}" ]]; then
(( FIND_PROJECT_ROOT_DEBUG )) && echo "${path}"
((current_dir_score += 90))
fi
done
# 75% root
for path in Makefile \
requirements.txt \
build.gradle \
Gemfile \
tsconfig.json \
composer.json \
.gitignore; do
if [[ -e "${current_dir}/${path}" ]]; then
(( FIND_PROJECT_ROOT_DEBUG )) && echo "${path}"
((current_dir_score += 75))
fi
done
# 50% root
for path in webpack.config.js vite.config.js babel.config.js .babelrc rollup.config.js \
lib include config scripts bin src third_party 3rd_party vendor \
.env .env.local \
.dockerignore; do
if [[ -e "${current_dir}/${path}" ]]; then
(( FIND_PROJECT_ROOT_DEBUG )) && echo "${path}"
((current_dir_score += 50))
fi
done
# 25% root
for path in configure \
Gopkg.toml \
Pipfile Pipfile.lock setup.py tox.ini .python-version \
build.xml settings.gradle \
packages.config \
Directory.Build.props \
.htmlhintrc .stylelintrc \
Gemfile.lock \
composer.lock \
Rakefile; do
if [[ -e "${current_dir}/${path}" ]]; then
(( FIND_PROJECT_ROOT_DEBUG )) && echo "${path}"
((current_dir_score += 25))
fi
done
if (( current_dir_score >= current_max_score )) && (( current_dir_score > 50 )); then
current_max_score=${current_dir_score}
project_root=${current_dir}
fi
(( FIND_PROJECT_ROOT_DEBUG )) && echo -e "${depth} : ${current_dir}\n score : ${current_dir_score}"
current_dir=$(dirname "$current_dir")
((depth++))
done
# save data to cache
PROJECT_ROOT_CACHE[${cache_key}]="${project_root}"
if [[ "${project_root}" != "." ]]; then
PROJECT_ROOT="${project_root}"
return 0
fi
PROJECT_ROOT=""
return 1
}
declare -A DIR_MAJORITY_LANGUAGE_CACHE
export FIND_DIR_MAJORITY_LANGUAGE_DEBUG=0
find_dir_majority_language() {
local args=${@}
local cache_key="cache_$(echo -n $PWD | md5sum | cut -d' ' -f1)"
# args detection
for arg in ${args}; do
if [[ "${arg:0:2}" = "--" ]]; then
arg="${arg:2}"
case "${arg}" in
"help")
echo -e "Usage : find_dir_majority_language [OPTION(S)]\n"
echo "Find the majoritary language in the current and sub-folders."
echo "It is automatically called by the prompt generator but you can call it if you want to access or modify the cache.\n"
echo "The result is stocked in the env variable DIR_MAJORITY_LANGUAGE. The exit value is 0 when project root found or 1 if not."
echo "Options :"
echo " --print-cache print majority language cache"
echo " --clear-cache clear majority language cache ; WARNING : the cache is wiped automatically in new bash instances."
echo " --toggle-debug toggle debug mode"
echo " --help display this help"
return 0 ;;
"print-cache")
for key in ${!DIR_MAJORITY_LANGUAGE_CACHE[@]}; do
echo "[${key}]=${DIR_MAJORITY_LANGUAGE_CACHE[$key]}"
done ;;
"clear-cache")
DIR_MAJORITY_LANGUAGE_CACHE=() ;;
"toggle-debug")
FIND_DIR_MAJORITY_LANGUAGE_DEBUG=$((! FIND_DIR_MAJORITY_LANGUAGE_DEBUG)) ;;
*)
echo -e "Error : unrecognised parameter : --${arg}\n Try typing --help" ;;
esac
else
echo -e "Error : unrecognised parameter : ${arg}\n Try typing --help"
fi
done
# search cache for existing data
if [[ -n "${DIR_MAJORITY_LANGUAGE_CACHE[$cache_key]}" ]]; then
DIR_MAJORITY_LANGUAGE="${DIR_MAJORITY_LANGUAGE_CACHE[$cache_key]}"
return
fi
# in case of equal quantity of per-language file, the majoritary language is arbitrary selected
local C=0 Cpp=0 Rust=0 Go=0 Python=0 Java=0 Ruby=0 Javascript=0 PHP=0 CS=0 HTMLCSS=0
local ext=""
for file in "$PWD"/*.* "$PWD"/*/*.* "$PWD"/*/*/*.*; do
#[[ -f "$file" ]] || continue
local ext="${file##*.}"
[[ "${ext}" = "${file}" ]] && continue
case "${ext}" in
c|h) ((C++)) ;;
cpp|cxx|cc|hpp|hxx|hh|h) ((Cpp++)) ;;
rs|rlib) ((Rust++)) ;;
go) ((Go++)) ;;
py|pyw|pyc|pyo) ((Python++)) ;;
java|class|jar|war) ((Java++)) ;;
rb|erb|rake) ((Ruby++)) ;;
js|jsx|ts|tsx|mjs|cjs) ((Javascript++)) ;;
php|phtml) ((PHP++)) ;;
cs|csproj|sln) ((CS++)) ;;
html|htm|css|scss|sass|less)((HTMLCSS++)) ;;
esac
done
if (( FIND_DIR_MAJORITY_LANGUAGE_DEBUG )); then
echo "C: ${C}"
echo "C++: ${Cpp}"
echo "Rust: ${Rust}"
echo "Go: ${Go}"
echo "Python: ${Python}"
echo "Java: ${Java}"
echo "Ruby: ${Ruby}"
echo "Javascript: ${Javascript}"
echo "PHP: ${PHP}"
echo "C#: ${CS}"
echo "HTML/CSS: ${HTMLCSS}"
fi
local max_count=0
DIR_MAJORITY_LANGUAGE=""
(( C > max_count )) && max_count=${C} && DIR_MAJORITY_LANGUAGE="C"
(( Cpp > max_count )) && max_count=${Cpp} && DIR_MAJORITY_LANGUAGE="C++"
(( Rust > max_count )) && max_count=${Rust} && DIR_MAJORITY_LANGUAGE="Rust"
(( Go > max_count )) && max_count=${Go} && DIR_MAJORITY_LANGUAGE="Go"
(( Python > max_count )) && max_count=${Python} && DIR_MAJORITY_LANGUAGE="Python"
(( Java > max_count )) && max_count=${Java} && DIR_MAJORITY_LANGUAGE="Java"
(( Ruby > max_count )) && max_count=${Ruby} && DIR_MAJORITY_LANGUAGE="Ruby"
(( Javascript > max_count )) && max_count=${Javascript} && DIR_MAJORITY_LANGUAGE="Javascript"
(( PHP > max_count )) && max_count=${PHP} && DIR_MAJORITY_LANGUAGE="PHP"
(( CS > max_count )) && max_count=${CS} && DIR_MAJORITY_LANGUAGE="C#"
(( HTMLCSS > max_count )) && max_count=${HTMLCSS} && DIR_MAJORITY_LANGUAGE="HTML/CSS"
# save data to cache
DIR_MAJORITY_LANGUAGE_CACHE[${cache_key}]="${DIR_MAJORITY_LANGUAGE}"
}
gen_prompt() {
local LAST_EXIT_CODE=$?
local HOUR="\[\033[0;31m\]╭─\[\033[7;47m\]\A"
local USER="\[\033[45m\]\[\033[1;27;30m\]\u\[\033[7m\]"
local FOLDER="\[\033[0;36m\]\[\033[1;7m\]\w"
local INFO=" "
if find_project_root; then
find_dir_majority_language
local language_icon="󰡯 "
case "$DIR_MAJORITY_LANGUAGE" in
"C") language_icon=" " ;;
"C++") language_icon=" " ;;
"Rust") language_icon=" " ;;
"Go") language_icon="󰟓 " ;;
"Python") language_icon=" " ;;
"Java") language_icon=" " ;;
"Ruby") language_icon=" " ;;
"Javascript") language_icon=" " ;;
"PHP") language_icon="󰌟 " ;;
"C#") language_icon="󰌛 " ;;
"HTML/CSS") language_icon=" " ;;
esac
INFO="${language_icon}$(basename "${PROJECT_ROOT}")"
elif [ "$HOME" = "$PWD" ]; then
INFO="󱂵 "
elif [ "$HOME/${documents}" = "$PWD" ]; then
INFO="󱧶 "
elif [ "$HOME/${music}" = "$PWD" ]; then
INFO="󱍙 "
elif [ "$HOME/${pictures}" = "$PWD" ]; then
INFO="󰉏 "
elif [ "$HOME/${videos}" = "$PWD" ]; then
INFO="󰉏 "
elif [ "$HOME/${downloads}" = "$PWD" ]; then
INFO="󰉍 "
elif [ "$HOME/.config" = "$PWD" ]; then
INFO="󱧼 "
elif [ "$HOME/.local" = "$PWD" ]; then
INFO="󰉌 "
elif mount | grep -q "$PWD"; then
INFO="󰉉 "
fi
INFO="\[\033[45m\]\[\033[1;27;30m\]${INFO}\[\033[7m\]\033[m"
local ARROW_COLOR="35"
(( ${LAST_EXIT_CODE} != 0 )) && ARROW_COLOR="32"
local USER_PROMPT="\[\033[31m\]╰─\[\033[${ARROW_COLOR}m\]\[\033[0m\]"
PS1="\n${HOUR} ${USER} ${FOLDER} ${INFO}\n${USER_PROMPT} "
}
PROMPT_COMMAND=gen_prompt