]> glassweightruler.freedombox.rocks Git - xdg-ninja.git/blob - xdg-ninja.sh
Create Hyprland.json (#371)
[xdg-ninja.git] / xdg-ninja.sh
1 #!/usr/bin/env sh
2
3 has_command() {
4 command -v "$1" >/dev/null 2>/dev/null
5 return $?
6 }
7
8 auto_set_decoder() {
9 DECODER="cat"
10 if has_command glow; then
11 DECODER="glow -"
12 elif has_command batcat; then
13 DECODER="batcat -pp --decorations=always --color=always --language markdown"
14 printf "Markdown rendering will be done by bat. (Glow is recommended)\n"
15 elif has_command bat; then
16 DECODER="bat -pp --decorations=always --color=always --language markdown"
17 printf "Markdown rendering will be done by bat. (Glow is recommended)\n"
18 elif has_command pygmentize; then
19 DECODER="pygmentize -l markdown"
20 printf "Markdown rendering will be done by pygmentize. (Glow is recommended)\n"
21 elif has_command highlight; then
22 DECODER="highlight --out-format ansi --syntax markdown"
23 printf "Markdown rendering will be done by highlight. (Glow is recommended)\n"
24 else
25 printf "Install glow for easier reading & copy-paste.\n"
26 fi
27 }
28 auto_set_decoder
29
30 unalias -a
31
32 init_constants() {
33 FX_RESET="\033[0m"
34 FX_BOLD="\033[1m"
35 FX_ITALIC="\033[3m"
36
37 FG_RED="\033[31m"
38 FG_GREEN="\033[32m"
39 FG_YELLOW="\033[33m"
40 FG_CYAN="\033[36m"
41 FG_WHITE="\033[37m"
42
43 BG_MAGENTA="\033[45m"
44 }
45 init_constants
46
47 help() {
48 init_constants
49 HELPSTRING="""\
50
51
52 ${FG_WHITE}${BG_MAGENTA}${FX_BOLD}xdg-ninja${FX_RESET}
53
54 ${FX_BOLD}${FX_ITALIC}Check your \$HOME for unwanted files.${FX_RESET}
55
56 ────────────────────────────────────
57
58 ${FX_ITALIC}--help${FX_RESET} ${FX_BOLD}This help menu${FX_RESET}
59 ${FX_ITALIC}-h\033${FX_RESET}
60
61 ${FX_ITALIC}--no-skip-ok${FX_RESET} ${FX_BOLD}Display messages for all files checked (verbose)${FX_RESET}
62 ${FX_ITALIC}-v${FX_RESET}
63
64 ${FX_ITALIC}--skip-ok${FX_RESET} ${FX_BOLD}Don't display anything for files that do not exist (default)${FX_RESET}
65
66 ${FX_ITALIC}--skip-unsupported${FX_RESET} ${FX_BOLD}Don't display anything for files that do not have fixes available${FX_RESET}
67
68 """
69 printf "%b" "$HELPSTRING"
70 }
71
72 SKIP_OK=true
73 SKIP_UNSUPPORTED=false
74 for i in "$@"; do
75 if [ "$i" = "--help" ] || [ "$i" = "-h" ]; then
76 help
77 exit
78 elif [ "$i" = "--skip-ok" ]; then
79 SKIP_OK=true
80 elif [ "$i" = "--no-skip-ok" ]; then
81 SKIP_OK=false
82 elif [ "$i" = "--skip-unsupported" ]; then
83 SKIP_UNSUPPORTED=true
84 elif [ "$i" = "-v" ]; then
85 SKIP_OK=false
86 fi
87 done
88
89 if [ -z "${XDG_DATA_HOME}" ]; then
90 printf '%b%s%b\n' "${FX_BOLD}${FG_CYAN}" "The \$XDG_DATA_HOME environment variable is not set, make sure to add it to your shell's configuration before setting any of the other environment variables!" "${FX_RESET}"
91 printf "%b ⤷ The recommended value is: %b\$HOME/.local/share%b\n" "${FX_BOLD}${FG_CYAN}" "${FX_BOLD}${FX_ITALIC}" "${FX_RESET}"
92 fi
93 if [ -z "${XDG_CONFIG_HOME}" ]; then
94 printf '%b%s%b\n' "${FX_BOLD}${FG_CYAN}" "The \$XDG_CONFIG_HOME environment variable is not set, make sure to add it to your shell's configuration before setting any of the other environment variables!" "${FX_RESET}"
95 printf "%b ⤷ The recommended value is: %b\$HOME/.config%b\n" "${FX_BOLD}${FG_CYAN}" "${FX_BOLD}${FX_ITALIC}" "${FX_RESET}"
96 fi
97 if [ -z "${XDG_STATE_HOME}" ]; then
98 printf '%b%s%b\n' "${FX_BOLD}${FG_CYAN}" "The \$XDG_STATE_HOME environment variable is not set, make sure to add it to your shell's configuration before setting any of the other environment variables!" "${FX_RESET}"
99 printf "%b ⤷ The recommended value is: %b\$HOME/.local/state%b\n" "${FX_BOLD}${FG_CYAN}" "${FX_BOLD}${FX_ITALIC}" "${FX_RESET}"
100 fi
101 if [ -z "${XDG_CACHE_HOME}" ]; then
102 printf '%b%s%b\n' "${FX_BOLD}${FG_CYAN}" "The \$XDG_CACHE_HOME environment variable is not set, make sure to add it to your shell's configuration before setting any of the other environment variables!" "${FX_RESET}"
103 printf "%b ⤷ The recommended value is: %b\$HOME/.cache%b\n" "${FX_BOLD}${FG_CYAN}" "${FX_BOLD}${FX_ITALIC}" "${FX_RESET}"
104 fi
105 if [ -z "${XDG_RUNTIME_DIR}" ]; then
106 printf '%b%s%b\n' "${FX_BOLD}${FG_CYAN}" "The \$XDG_RUNTIME_DIR environment variable is not set, make sure to add it to your shell's configuration before setting any of the other environment variables!" "${FX_RESET}"
107 printf "%b ⤷ The recommended value is: %b/run/user/\$UID%b\n" "${FX_BOLD}${FG_CYAN}" "${FX_BOLD}${FX_ITALIC}" "${FX_RESET}"
108 fi
109
110 if ! command -v jq >/dev/null 2>/dev/null; then
111 printf "jq is needed to run this script, but it wasn't found. Please install it to be able to use this script.\n"
112 exit
113 fi
114
115 printf "\n"
116
117 # Function to expand environment variables in string
118 # https://stackoverflow.com/a/20316582/11110290
119 apply_shell_expansion() {
120 data="$1"
121 delimiter="__apply_shell_expansion_delimiter__"
122 command=$(printf "cat <<%s\n%s\n%s" "$delimiter" "$data" "$delimiter")
123 eval "$command"
124 }
125
126 # Function to check if a string contains shell pattern matching
127 has_pattern() {
128 case $1 in
129 *\** | *\?* | *\[*\]*)
130 return 0
131 ;;
132 *)
133 return 1
134 ;;
135 esac
136 }
137
138 # Returns the actual name of the given file that is on the user's disk
139 # This command applies shell pattern matching and return the actual filename
140 retrieve_existing_filename() {
141 FILE_PATH=$(apply_shell_expansion "$1")
142
143 # return filename if found, nothing else
144 if has_pattern "$FILE_PATH"; then
145 dir="$(dirname "$FILE_PATH")"
146 part="$(basename "$FILE_PATH")"
147 find "$dir" -maxdepth 1 -name "$part" -print -quit 2>/dev/null
148 else
149 if [ -e "$FILE_PATH" ]; then
150 printf "%s" "$FILE_PATH"
151 fi
152 fi
153 }
154
155 decode_string() {
156 printf "%s" "$1" | sed -e 's/\\n/\
157 /g' -e 's/\\\"/\"/g' -e '$ s/\n*$/\
158 \
159 /' # Replace \n with literal newline and \" with ", normalize number of trailing newlines to 2
160 }
161
162 # Counter to keep track of how many files can be moved
163 FIXABLE=0
164
165 # Function to handle the formatting of output
166 log() {
167 MODE="$1"
168 NAME="$2"
169 FILENAME="$3"
170 HELP="$4"
171
172 case "$MODE" in
173
174 ERR)
175 printf '[%b%s%b]: %b%s%b\n' "${FX_BOLD}${FG_RED}" "$NAME" "${FX_RESET}" "${FX_BOLD}${FX_ITALIC}" "$FILENAME" "${FX_RESET}"
176 FIXABLE=$((FIXABLE+1))
177 ;;
178
179 WARN)
180 [ "$SKIP_UNSUPPORTED" = false ] &&
181 printf '[%b%s%b]: %b%s%b\n' "${FX_BOLD}${FG_YELLOW}" "$NAME" "${FX_RESET}" "${FX_BOLD}${FX_ITALIC}" "$FILENAME" "${FX_RESET}"
182 ;;
183
184 INFO)
185 printf '[%b%s%b]: %b%s%b\n' "${FX_BOLD}${FG_CYAN}" "$NAME" "${FX_RESET}" "${FX_BOLD}${FX_ITALIC}" "$FILENAME" "${FX_RESET}"
186 ;;
187
188 SUCS)
189 [ "$SKIP_OK" = false ] &&
190 printf '[%b%s%b]: %b%s%b\n' "${FX_BOLD}${FG_GREEN}" "$NAME" "${FX_RESET}" "${FX_BOLD}${FX_ITALIC}" "$FILENAME" "${FX_RESET}"
191 ;;
192
193 HELP)
194 decode_string "$HELP" | PAGER="cat" $DECODER
195 ;;
196
197 esac
198 }
199
200 # Checks that the given file does not exist, otherwise outputs help
201 check_file() {
202 NAME="$1"
203 FILENAME="$2"
204 MOVABLE="$3"
205 HELP="$4"
206
207 file=$(retrieve_existing_filename "$FILENAME")
208
209 if [ "$file" ]; then
210 if [ "$MOVABLE" = true ]; then
211 log ERR "$NAME" "$file" "$HELP"
212 else
213 log WARN "$NAME" "$file" "$HELP"
214 fi
215 if [ "$HELP" ]; then
216 if [ "$MOVABLE" = true ] || [ "$SKIP_UNSUPPORTED" = false ]; then
217 log HELP "$NAME" "$file" "$HELP"
218 fi
219 else
220 log HELP "$NAME" "$file" "_No help available._"
221 fi
222 else
223 log SUCS "$NAME" "$file" "$HELP"
224 fi
225 }
226
227 # Reads files from programs/, calls check_file on each file specified for each program
228 do_check_programs() {
229 while IFS="
230 " read -r name; read -r filename; read -r movable; read -r help; do
231 check_file "$name" "$filename" "$movable" "$help"
232 done <<EOF
233 $(jq '.files[] as $file | .name, $file.path, $file.movable, $file.help' "$XN_PROGRAMS_DIR"/* | sed -e 's/^"//' -e 's/"$//')
234 EOF
235 # sed is to trim quotes
236 }
237
238 check_programs() {
239 printf "%bStarting to check your %b\$HOME%b.\n" "${FX_BOLD}${FX_ITALIC}" "${FG_CYAN}" "${FX_RESET}"
240 printf "\n"
241 do_check_programs
242 printf "%bDone checking your %b\$HOME.%b\n" "${FX_BOLD}${FX_ITALIC}" "${FG_CYAN}" "${FX_RESET}"
243 printf "\n"
244 printf "%bIf you have files in your %b\$HOME%b that shouldn't be there, but weren't recognised by xdg-ninja, please consider creating a configuration file for it and opening a pull request on github.%b\n" "${FX_ITALIC}" "${FG_CYAN}" "${FX_RESET}${FX_ITALIC}" "${FX_RESET}"
245 printf "\n"
246 }
247
248 [ "$XN_PROGRAMS_DIR" ] ||
249 XN_PROGRAMS_DIR="$(realpath "$0" | xargs dirname | sed 's:/bin$:/share/xdg-ninja:g')/programs"
250
251 check_programs
252 if [ $FIXABLE -gt 100 ]; then
253 exit 101
254 else
255 exit $FIXABLE
256 fi