diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/EXTENSIONS.md b/EXTENSIONS.md new file mode 100644 index 0000000..4a7f978 --- /dev/null +++ b/EXTENSIONS.md @@ -0,0 +1,225 @@ +# tifmx - extend tifm to your liking +we call the extension framework bundled with tifm, `tifmx`, short for `tiny file manager extensions` (creative naming!). + +tifmx automatically loads extensions placed in the `extensions` folder, allowing you to drop in extensions to add them in. + +it also provides a couple of functions for tifm to adapt its behaviour to your extension. + +## guide +here we will create a very simple greeter extension to show you how easy it is to write an extension for tifm. + +### init event +we'll start by creating a `greeter.sh` file in the `extensions` folder.
+then, we'll listen for the `init` event which is called when the extension is loaded.
+events are function definitions of this format: `ext_name.event_name`. tifmx automatically figures out the extension's name by reading the file name, so we will create our init event like this: +```bash +greeter.init() { + # code here +} +``` +then, we will simply print "Hello, $USERNAME!" to the console: +```bash +greeter.init() { + echo "Hello, $USERNAME!" +} +``` +you can test it out by launching tifm now. + +### simple command +simple commands are when you press a key and a function gets executed. we'll bind our `h` key to say `Hey all!` when it is pressed. + +we'll first start by defining our function. it can be named anything, because we will bind it using its name later; we'll call it `greet_all`: +```sh +greeter.init() { + echo "Hello, $USERNAME!" +} + +# NEW +greet_all() { + echo "Hey all!" +} +``` +awesome. but now, if you reload tifm and press the `h` key, you will get an error. this is because we haven't told tifm to listen to the key. + +we will need to use the `tifmx.bind` command to create a binding and link it to our function. you create a binding this way: +```sh +tifmx.bind char func +``` +so to bind our new `greet_all` function to the `h` key: +```sh +tifmx.bind h greet_all +``` +now your file should look like this: +```sh +greeter.init() { + echo "Hello, $USERNAME!" +} + +greet_all() { + echo "Hey all!" +} +# NEW +tifmx.bind h greet_all +``` +you can now reload tifm and press `h` to see a nice greeting! + +### long command +long commands are when you press a key to access a group, and then press another key to run a sub command. examples include `rd` (remove directory) and `nf` (new file). + +we'll make two commands: `gu` to greet the user and `gw` to greet the world. we can do this using the `tifmx.add_long` and `tifmx.bind_sub` commands. you create a binding this way: +```sh +tifmx.add_long char1 +tifmx.bind_sub char1 char2 func +# you can add infinite subcommands to a group +``` +we have already defined a function that greets the user: `greeter.init`, so in our case we can use it. but we'll create a greet world function first: +```sh +greeter.init() { + echo "Hello, $USERNAME!" +} + +greet_all() { + echo "Hey all!" +} +tifmx.bind h greet_all + +# NEW +greet_world() { + echo "Hello, world!" +} +``` + +and now we'll create our long command: +```sh +greeter.init() { + echo "Hello, $USERNAME!" +} + +greet_all() { + echo "Hey all!" +} +tifmx.bind h greet_all + +greet_world() { + echo "Hello, world!" +} +# NEW +tifmx.add_long g +tifmx.bind_sub g u greeter.init +tifmx.bind_sub g w greet_world +``` +you can now reload and test your long command out! + +## documentation +extensions have access to everything defined in the configuration file and pretty much every aspect of tifm. +### events +events are functions defined in your extension that get called when a specific action happens inside of tifm. you define them this way: `extension.event` where extension is the name of your extension file (without `.sh`) and `event` is the name of your event. see below for all available events. +> **Note:** parameters are passed without name and are accessible via `$1`, `$2` and so on, or `"${@[n]}"` where `n` is a number. +#### `extension.init()` +called when your extension is loaded. + +#### `extension.display()` (provided you're using the default `__TIFM_DISPLAY` in `config.sh`) +called when the display (top part of the command input) is displayed. whatever it echoes last will be added as a widget in the display. + +example: quick clock extension: +```sh +# file: extensions/clock.sh +clock.display() { + # display clock + echo -e "$CYAN$(date +"%H:%M")$NORMAL" +} +``` + +#### `extension.nav(directory)` +called when the user changes directories, at the very end of the `N` command. + +parameters: +* `directory`: the directory the user travelled to + +#### `extension.edit(file)` +called when the user edits a file, at the very end of the `e` command. + +parameters: +* `file`: the file the user edited + +#### `extension.copy(from, to)` +called when the user copies a file, at the very end of the `c` command. + +parameters: +* `from`: the file the user copied +* `to`: the location the file was copied to + +#### `extension.move(from, to)` +called when the user moves a file, at the very end of the `m` command. + +parameters: +* `from`: the file the user moved +* `to`: the location the file was moved to + +#### `extension.mkdir(dir)` / `extension.mkfile(file)` +called when the user creates a directory/file, at the very end of the `n(d/f)` command. + +parameters (`mkdir`): +* `dir`: the directory the user created + +parameters (`mkfile`): +* `file`: the file the user created + +#### `extension.rmdir(dir)` / `extension.rmfile(file)` +called when the user deletes a directory/file, at the very end of the `r(d/f)` command. + +parameters (`rmdir`): +* `dir`: the directory the user deleted + +parameters (`rmfile`): +* `file`: the file the user deleted + +#### `extension.fperms(item, permissions)` +called when the user changes the permissions of a file, at the very end of the `P` command. + +parameters: +* `item`: the file or directory for which the permissions were modified +* `permissions`: the permission arguments given to the file (in chmod format) + +### functions +you have access to multiple functions that change the behaviour of tifm. +#### `tifmx.bind(char, func)` +tells tifm to listen to when `char` is pressed, and in that case call `func`. +example: +```sh +go_home() { # navigate to the home directory + cd ~ +} +tifmx.bind "~" go_home +``` + +#### `tifmx.add_long(char)` +tells tifm to listen to when `char` is pressed, and in that case wait for another keypress and find a command associated to that combination. must be used with `tifmx.bind_sub(char1, char2, func)`. + +#### `tifmx.bind_sub(char1, char2, func)` +tells tifmx to associate the combination `char1 + char2` to call `func`. +example: +```sh +go_home() { + cd ~ +} +go_parent() { + cd .. +} +tifmx.add_long "~" +tifmx.bind_sub "~" "~" go_home # pressing ~ then ~ will return home +tifmx.bind_sub "~" "<" go_parent # pressing ~ then < will return to the parent directory +``` + +#### `tifmx.add_help(char, helpstring)` +adds a custom line in the `?` command to show the usage of your custom command. +example: +```sh +go_home() { + cd ~ +} +tifmx.bind "~" go_home +tifmx.add_help "~" "return to the parent directory" +# will show like this: +# ~ - return to the parent directory +``` \ No newline at end of file diff --git a/README.md b/README.md index 6958c80..9edb319 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,3 @@ -# linfm -Some sort of File Manager, made in the bash interpreter - -![Available on Paque](https://media.discordapp.net/attachments/655093392187064360/994649858810052668/InstallOnPaque.png) - -Package name: linfm +# tifm +a really **ti**ny **f**ile **m**anager +mostly meant for personal use and contribution to the parent project diff --git a/config.sh b/config.sh new file mode 100644 index 0000000..2c3d23b --- /dev/null +++ b/config.sh @@ -0,0 +1,31 @@ +__TIFM_PAGER="less" # [p]eek command +__TIFM_EDITOR="nano" # [e]dit command +__ANGLE_UP_RIGHT="╭" +__ANGLE_UP_LEFT="╮" +__ANGLE_DOWN_RIGHT="╰" +__ANGLE_DOWN_LEFT="╯" +__VBAR="│" +__TIFM_DECO_COLOUR="$CYAN" +__TIFM_CONFIRM_RETURN=true +__TIFM_DISPLAY() { + local stat="" + if [ "$STATUS" == "0" ]; then + stat="${GREEN}✔$NORMAL" + else + stat="${RED}✘ $STATUS$NORMAL" + fi + local string="$GREEN$BRIGHT$PWD$NORMAL $stat " + # for each extension, if it has a display function, call it + for ext_name in "${tifm_extensions[@]}"; do + if type "$ext_name".display &> /dev/null; then + string="$string$( "$ext_name".display )$NORMAL " + fi + done + echo "$string" +} +__TIFM_LS_COLOUR_FILE="$BLUE" +__TIFM_LS_COLOUR_DIRECTORY="$LIME_YELLOW" +__TIFM_PROMPT() { + user=$(whoami) + echo "$CYAN$user>" +} \ No newline at end of file diff --git a/extension_ignore b/extension_ignore new file mode 100644 index 0000000..e69de29 diff --git a/extensions/clock.sh b/extensions/clock.sh new file mode 100644 index 0000000..ae414f6 --- /dev/null +++ b/extensions/clock.sh @@ -0,0 +1,4 @@ +clock.display() { + # display clock + echo -e "$CYAN$(date +"%H:%M")$NORMAL" +} \ No newline at end of file diff --git a/extensions/git.sh b/extensions/git.sh new file mode 100644 index 0000000..1650472 --- /dev/null +++ b/extensions/git.sh @@ -0,0 +1,130 @@ +# git.sh +# adds git support to tifm + +__tifmgit_in_repo=false +is_git_repo() { + # check if current directory is a git repo + git rev-parse --is-inside-work-tree &> /dev/null +} + +git.init() { + # check if current directory is a git repo + if is_git_repo; then + __tifmgit_in_repo=true + fi +} + +git.nav() { + if is_git_repo; then + __tifmgit_in_repo=true + fi +} + +git.display() { + # display git status + if $__tifmgit_in_repo; then + local branch=$(git rev-parse --abbrev-ref HEAD) + local gstatus=$(git status --porcelain) + # remove leading and trailing spaces + gstatus=$(echo "$gstatus" | sed 's/^ *//g;s/ *$//g') + # remove leading and trailing newlines + gstatus=$(echo "$gstatus" | sed 's/^\n//g;s/\n$//g') + if [[ -z "$gstatus" ]]; then + gstatus=0 + else + # replace with count + gstatus=$(echo "$gstatus" | wc -l) + fi + local modif="modif" + # if modif > 1, replace with "modifs" + if [[ "$gstatus" -gt 1 ]]; then + modif="modifs" + fi + echo "$BRIGHT$YELLOW(git branch $branch - status: $gstatus $modif)$NORMAL" + fi +} + +git_pull() { + # pull from remote + git pull +} +git_push() { + # push to remote + git push +} +git_status() { + # display git status + if $__tifmgit_in_repo; then + local branch=$(git rev-parse --abbrev-ref HEAD) + local gstatus=$(git status --porcelain) + # colouring + # M file -> ${BLUE}M${NORMAL}file + gstatus=$(echo "$gstatus" | sed "s/ M /${BLUE}M${NORMAL} /g") + # A file -> ${GREEN}A${NORMAL}file + gstatus=$(echo "$gstatus" | sed "s/ A /${GREEN}A${NORMAL} /g") + # D file -> ${RED}D${NORMAL}file + gstatus=$(echo "$gstatus" | sed "s/ D /${RED}D${NORMAL} /g") + # R file -> ${YELLOW}R${NORMAL}file + gstatus=$(echo "$gstatus" | sed "s/ R /${YELLOW}R${NORMAL} /g") + # C file -> ${LIME_YELLOW}C${NORMAL}file + gstatus=$(echo "$gstatus" | sed "s/ C /${LIME_YELLOW}C${NORMAL} /g") + # U file -> ${POWDER_BLUE}U${NORMAL}file + gstatus=$(echo "$gstatus" | sed "s/ U /${POWDER_BLUE}U${NORMAL} /g") + # ? file -> ${MAGENTA}?${NORMAL}file + gstatus=$(echo "$gstatus" | sed "s/ ? /${MAGENTA}?${NORMAL} /g") + # ! file -> ${CYAN}!${NORMAL}file + gstatus=$(echo "$gstatus" | sed "s/ ! /${CYAN}!${NORMAL} /g") + # if gstatus is empty, replace it with "nothing to commit" + if [ -z "$gstatus" ]; then + gstatus="nothing to commit" + fi + echo -e "$BRIGHT${YELLOW}git branch $branch$NORMAL\n$gstatus" + fi +} +git_add() { + # add all files to git + git add . +} +git_commit() { + # commit all files to git + read -p "Commit message: " message + git commit -m "$message" +} +git_diff() { + # show diff between current and previous commit + git diff +} +git_log() { + # show log of all commits + git log +} +git_log_last() { + # show log of last commit + git log -1 +} +git_full() { # pull, add, commit, push + git_pull + git_add + git_commit + git_push +} +git_view_remote() { + git remote -v +} +git_clone() { + read -p "Git URL: " url + git clone "$url" +} +tifmx.add_long G # for global git commands +tifmx.bind_sub G C git_clone +tifmx.bind_sub G p git_pull +tifmx.bind_sub G P git_push +tifmx.bind_sub G s git_status +tifmx.bind_sub G a git_add +tifmx.bind_sub G c git_commit +tifmx.bind_sub G d git_diff +tifmx.bind_sub G l git_log +tifmx.bind_sub G L git_log_last +tifmx.bind_sub G "*" git_full +tifmx.bind_sub G r git_view_remote +tifmx.add_help G "git commands integration ([C]lone, [p]ull, [P]ush, [s]tatus, [a]dd, [c]ommit, [d]iff, [l]og, [L]og last, [*]full, [r]emote)" \ No newline at end of file diff --git a/installer.sh b/installer.sh new file mode 100644 index 0000000..b23dcbf --- /dev/null +++ b/installer.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# TIFM installer script +# run by using {sudo curl -sL https://raw.githubusercontent.com/Rexxt/tifm/master/installer.sh | bash} + +# make sure git is installed +if ! type git &> /dev/null; then + echo "git is not installed" + exit 1 +fi + +git clone "https://github.com/Rexxt/tifm.git" +rm tifm/installer.sh +mkdir -p ~/tifm +mv tifm ~ +echo "where should we install tifm?" +echo "1) /usr/local/bin" +echo "2) /usr/bin" +read -p "> " -n 1 -r reply +echo +case "$reply" in + 1) + echo "installing to /usr/local/bin" + sudo touch /usr/local/bin/tifm + echo "~/tifm/main.sh" > /usr/local/bin/tifm + sudo chmod +x ~/tifm/main.sh + sudo chmod +x /usr/local/bin/tifm + ;; + 2) + echo "installing to /usr/bin" + sudo touch /usr/bin/tifm + echo "~/tifm/main.sh" > /usr/bin/tifm + sudo chmod +x ~/tifm/main.sh + sudo chmod +x /usr/bin/tifm + ;; + *) + echo "invalid option" + exit 1 + ;; +esac +# check if tifm command is in path +if ! type tifm &> /dev/null; then + echo "tifm is not in path... this is most likely a problem on our side." + exit 1 +else + echo "tifm is installed and usable!" +fi diff --git a/main.sh b/main.sh index f7c1be1..576a5b4 100644 --- a/main.sh +++ b/main.sh @@ -1,124 +1,444 @@ #!/bin/env bash -clear -echo " -┌─────────────────────────────────────────────────┐ -│ %#### │ -│ ######### │ -│ @@@###@@# LinFM │ -│ @@@@@@@@@ A file manager, in your command line. │ -│ Made with <3 by [I> (Icycoide) │ -└─────────────────────────────────────────────────┘ -" -sleep 3 -echo "Loading contents from " $PWD"..." +declare -a -x tifm_extensions +declare -A -x tifm_extensions_commands +declare -a -x tifm_extensions_commands_list +declare -A -x tifm_extensions_commands_help +declare -a -x tifm_extensions_longcommands +declare -A -x tifm_extensions_subcommands +tifmx.bind() { + tifm_extensions_commands["$1"]="$2" +} +tifmx.add_long() { + tifm_extensions_longcommands+=("$1") +} +tifmx.bind_sub() { + tifm_extensions_subcommands["$1$2"]="$3" +} +tifmx.add_help() { + tifm_extensions_commands_list+=("$1") + tifm_extensions_commands_help["$1"]="$2" +} +# consts +__TIFM_VERSION="0.2.1" +BLACK=$(tput setaf 0) +RED=$(tput setaf 1) +GREEN=$(tput setaf 2) +YELLOW=$(tput setaf 3) +LIME_YELLOW=$(tput setaf 190) +POWDER_BLUE=$(tput setaf 153) +BLUE=$(tput setaf 4) +MAGENTA=$(tput setaf 5) +CYAN=$(tput setaf 6) +WHITE=$(tput setaf 7) +BRIGHT=$(tput bold) +NORMAL=$(tput sgr0) +BLINK=$(tput blink) +REVERSE=$(tput smso) +UNDERLINE=$(tput smul) +DIM=$(tput dim) +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" + +init() { + # vars + STATUS=0 + # config + source "$SCRIPT_DIR/config.sh" + # load extensions + tput sc + printf "Loading extensions... " + load_extensions + printf "Done.\n" +} + +load_extensions() { + local count=0 + # check how many files are in the extensions directory + local files=$(ls -1 "$SCRIPT_DIR/extensions" | wc -l) + for extension in "$SCRIPT_DIR/extensions/"*".sh"; do + # if there is no save folder, create it + if [ ! -d "$SCRIPT_DIR/save" ]; then + mkdir "$SCRIPT_DIR/save" + fi + local ext_name=$(basename "$extension" | cut -d. -f1) + # if the name is in the extension_ignore file, skip it + if grep -q "$ext_name" "$SCRIPT_DIR/extension_ignore"; then + continue + fi + source "$extension" + # add only the name of the extension to the array (ex: extensions/git.sh -> git) + tifm_extensions+=("$ext_name") + count=$((count + 1)) + # percentage of completion + local percent=$((count / files * 100)) + tput rc + printf "Loading extensions... $count/$files ($percent%%)\n" + # if function $ext_name.init exists, call it + if type "$ext_name".init &> /dev/null; then + "$ext_name".init + fi + done +} -clear main() { - echo "┌─ Waiting for action at" $PWD - read -p "└─linfm> " lfm_ans - case "$lfm_ans" in - SetDir) - echo "Select a directory to go to." - read lfm_setdir - cd $lfm_setdir - main - ;; - Open) - echo "Choose a file to open." - read lfm_setfile - xdg-open $lfm_setfile - main - ;; - Copy) - echo "Choose the file and the location you would like to copy it to." - read lfm_setfile - cp $lfm_setfile - main - ;; - MoveFile) - echo "Choose the file and the new location you would like to move it to, with both of them being separated with a space." - read lfm_setfile - mv $lfm_setfile - main - ;; - Index) - ls -a - main - ;; - CreateFolder) - echo "Please put in the name of the folder you would like to create." - read lfm_setdir - mkdir $lfm_setdir - main - ;; - DeleteFile) - echo "Select the file you would like to delete. (Without confirmation.) To cancel, just press enter without typing in anything." - read lfm_setfile - rm $lfm_setfile - main - ;; - DeleteFolder) - echo "Select the folder you would like to delete. (Without confirmation.) To cancel, just press enter without typing in anything." - read lfm_setdir - rm -rf $lfm_setdir - main - ;; - TouchFile) - echo "Choose the name of the file..." - read lfm_setfile - touch $lfm_setfile - main - ;; - PermSet) - echo "Choose a file or folder to change the permission" - read lfm_setany - echo "Choose the arguments from 'chmod' to set as permission for the file or folder. (Read the manual for chmod for more info)" - read lfm_setperm - chmod $lfm_setperm $lfm_setany - main - ;; - CmdLine) - /bin/sh - main - ;; - Help) - echo " - List of commands: - SetDir - -Goes to a folder - Open - -Opens a file - MoveFile - -Moves/Renames a file - Copy - -Copies a file to a location - Index - -Shows the list of files inside the directory - CreateFolder - -Creates a folder - DeleteFile - -Deletes a File - DeleteFolder - -Deletes folder - TouchFile - -Creates new file - PermSet - -Sets permissions for a specific file or folder - CmdLine - -Switches to command line mode, run 'exit' to exit. - Exit - -That exits out of LinFM." - main - ;; - Exit) - clear - exit - ;; - *) - echo "Unrecognized command. Type 'Help' for a list of commands." - main - ;; - esac + echo "$__TIFM_DECO_COLOUR$__ANGLE_UP_RIGHT $(__TIFM_DISPLAY)$NORMAL" + while read file; do + __color="$__TIFM_LS_COLOUR_FILE" + __post="" + __icon="🗎" + if [ -d "$file" ]; then + __color="$__TIFM_LS_COLOUR_DIRECTORY" + __post="/" + __icon="␣" + fi + echo "$__TIFM_DECO_COLOUR$__VBAR$__color $__icon $file$__post$NORMAL" + done < <(ls -a) + read -n 1 -p "$__TIFM_DECO_COLOUR$__ANGLE_DOWN_RIGHT $(__TIFM_PROMPT) $YELLOW" ans + + if [[ "$ans" != "n" ]] && [[ "$ans" != "r" ]] && [[ "$ans" != ";" ]] && [[ ! "${tifm_extensions_longcommands[*]}" =~ "$ans" ]]; then + echo "" + fi + printf "$NORMAL" + + # command execution + case "$ans" in + N) + echo "Select a directory to go to (leave blank to cancel)." + read -p "nav:: " tifm_dir + if [[ "$tifm_dir" == "" ]]; then + echo "Cancelled." + return + else + cd $tifm_dir + # for every extension, if it has a function called name.nav, call it + for ext_name in "${tifm_extensions[@]}"; do + if type "$ext_name".nav &> /dev/null; then + "$ext_name".nav "$tifm_dir" + fi + done + fi + ;; + o) + echo "Choose a file to open (leave blank to cancel)." + read -p "file:: " tifm_file + if [[ "$tifm_file" == "" ]]; then + echo "Cancelled." + return + else + xdg-open $tifm_file + fi + ;; + p) + echo "Choose a file to view (leave blank to cancel)." + read -p "file:: " tifm_file + if [[ "$tifm_file" == "" ]]; then + echo "Cancelled." + return + else + $__TIFM_PAGER $tifm_file + fi + ;; + e) + echo "Choose a file to edit (leave blank to cancel)." + read -p "file:: " tifm_file + if [[ "$tifm_file" == "" ]]; then + echo "Cancelled." + return + else + $__TIFM_EDITOR $tifm_file + fi + # for every extension, if it has a function called name.edit, call it + for ext_name in "${tifm_extensions[@]}"; do + if type "$ext_name".edit &> /dev/null; then + "$ext_name".edit "$tifm_file" + fi + done + ;; + c) + echo "Choose the file and the location you would like to copy it to (leave blank to cancel)." + read -p "from:: " tifm_file_from + if [[ "$tifm_file_from" == "" ]]; then + echo "Cancelled." + return + fi + read -p "to:: " tifm_file_to + if [[ "$tifm_file_to" == "" ]]; then + echo "Cancelled." + return + fi + cp "$tifm_file_from" "$tifm_file_to" + # for every extension, if it has a function called name.copy, call it + for ext_name in "${tifm_extensions[@]}"; do + if type "$ext_name".copy &> /dev/null; then + "$ext_name".copy "$tifm_file_from" "$tifm_file_to" + fi + done + ;; + m) + echo "Choose the file and the new location you would like to move it to." + read -p "from:: " tifm_file_from + if [[ "$tifm_file_from" == "" ]]; then + echo "Cancelled." + return + fi + read -p "to:: " tifm_file_to + if [[ "$tifm_file_to" == "" ]]; then + echo "Cancelled." + return + fi + mv "$tifm_file_from" "$tifm_file_to" + # for every extension, if it has a function called name.move, call it + for ext_name in "${tifm_extensions[@]}"; do + if type "$ext_name".move &> /dev/null; then + "$ext_name".move "$tifm_file_from" "$tifm_file_to" + fi + done + ;; + i) + echo "Choose the directory to inspect (leave blank to cancel)." + read -p "dir:: " tifm_dir + if [[ "$tifm_dir" == "" ]]; then + echo "Cancelled." + return + else + ls -l $tifm_dir | $__TIFM_PAGER + fi + ;; + n) + read -n 1 tifm_type + echo "" + case "$tifm_type" in + d) + echo "Choose the directory you would like to create (leave blank to cancel)." + read -p "name:: " tifm_dir_name + if [[ "$tifm_dir_name" == "" ]]; then + echo "Cancelled." + return + fi + mkdir "$tifm_dir_name" + # for every extension, if it has a function called name.mkdir, call it + for ext_name in "${tifm_extensions[@]}"; do + if type "$ext_name".mkdir &> /dev/null; then + "$ext_name".mkdir "$tifm_dir_name" + fi + done + ;; + f) + echo "Choose the file you would like to create (leave blank to cancel)." + read -p "name:: " tifm_file_name + if [[ "$tifm_file_name" == "" ]]; then + echo "Cancelled." + return + fi + touch "$tifm_file_name" + # for every extension, if it has a function called name.mkfile, call it + for ext_name in "${tifm_extensions[@]}"; do + if type "$ext_name".mkfile &> /dev/null; then + "$ext_name".mkfile "$tifm_file_name" + fi + done + ;; + *) + echo "Invalid type ([d]irectory/[f]ile)." + ;; + esac + ;; + r) + read -n 1 tifm_type + echo "" + case "$tifm_type" in + d) + echo "Choose the directory you would like to remove (leave blank to cancel)." + read -p "name:: " tifm_dir_name + if [[ "$tifm_dir_name" == "" ]]; then + echo "Cancelled." + return + fi + rm -rf "$tifm_dir_name" + # for every extension, if it has a function called name.rmdir, call it + for ext_name in "${tifm_extensions[@]}"; do + if type "$ext_name".rmdir &> /dev/null; then + "$ext_name".rmdir "$tifm_dir_name" + fi + done + ;; + f) + echo "Choose the file you would like to remove (leave blank to cancel)." + read -p "name:: " tifm_file_name + if [[ "$tifm_file_name" == "" ]]; then + echo "Cancelled." + return + fi + rm "$tifm_file_name" + # for every extension, if it has a function called name.rmfile, call it + for ext_name in "${tifm_extensions[@]}"; do + if type "$ext_name".rmfile &> /dev/null; then + "$ext_name".rmfile "$tifm_file_name" + fi + done + ;; + *) + echo "Invalid type ([d]irectory/[f]ile)." + ;; + esac + ;; + P) + echo "Choose a file or folder to change the permission (leave blank to cancel)." + read -p "item:: " tifm_select + if [[ "$tifm_select" == "" ]]; then + echo "Cancelled." + return + fi + echo "Choose the arguments from 'chmod' to set as permission for the file or folder (leave blank to cancel). (Read the manual for chmod for more info)" + read -p "perm:: " tifm_perm + if [[ "$tifm_perm" == "" ]]; then + echo "Cancelled." + return + fi + chmod $tifm_perm $tifm_select + # for every extension, if it has a function called name.fperms, call it + for ext_name in "${tifm_extensions[@]}"; do + if type "$ext_name".fperms &> /dev/null; then + "$ext_name".fperms "$tifm_select" "$tifm_perm" + fi + done + ;; + t) + /bin/bash + ;; + ";") + read -n 1 tifm_sub + echo "" + case "$tifm_sub" in + c) + # open config + $__TIFM_EDITOR "$SCRIPT_DIR/config.sh" + # reload config + source "$SCRIPT_DIR/config.sh" + ;; + e) + # open extension menu + local all_extensions=() + for extension in "$SCRIPT_DIR/extensions/"*".sh"; do + local ext_name=$(basename "$extension" .sh) + # if the extension name is in the extension_ignore file, ignore it + all_extensions+=("$ext_name") + done + display_extensions() { + clear + # display all extensions + echo "Extensions:" + for extension in "${all_extensions[@]}"; do + # if not in the ignored extensions list, display with a green checkmark + local grepped=$(grep "$extension" "$SCRIPT_DIR/extension_ignore") + if [[ -z "$grepped" ]]; then + echo -e " $GREEN✔$NORMAL $extension" + else + echo -e " $RED✘$NORMAL $extension" + fi + done + } + local executing=true + while $executing; do + display_extensions + echo "" + echo "type the name of an extension to toggle it, or type 'q' to quit." + read -p "extension:: " tifm_extension + if [[ "$tifm_extension" == "q" ]]; then + executing=false + continue + fi + # if the extension is ignored, unignore it + if [[ -n $(grep "$tifm_extension" "$SCRIPT_DIR/extension_ignore") ]]; then + sed -i "/$tifm_extension/d" "$SCRIPT_DIR/extension_ignore" + # remove from the ignored extensions list + local index=0 + for ext in "${ignored_extensions[@]}"; do + if [[ "$ext" == "$tifm_extension" ]]; then + unset ignored_extensions[$index] + fi + ((index++)) + done + else + # if the extension is not ignored, ignore it + echo "$tifm_extension" >> "$SCRIPT_DIR/extension_ignore" + fi + done + ;; + *) + echo "Invalid subcommand." + ;; + esac + ;; + "?") + echo "${LIME_YELLOW}List of native commands:$NORMAL +N - Goes to a folder +o - Opens a file +p - View file (uses 'less' by default - change in config.sh) +e - edit a file (uses 'nano' by default - change in config.sh) +m - Moves/Renames a file +c - Copies a file to a location +i - Inspects a directory (ls -l) and pipes it to the selected pager ('less' by default - change in config.sh) +n(f/d) - Creates a file or directory +r(f/d) - Removes a file or directory +P - Sets permissions for a specific file or folder +t - Switches to command line mode, run 'exit' to exit. +;(c/e) - Open [c]onfig file, [e]xtension menu +Q - Quits the program" + if [[ ! -z "${tifm_extensions[@]}" ]]; then + echo "${LIME_YELLOW}List of commands defined by extensions [${tifm_extensions[@]}]:$NORMAL" + for cmd in "${tifm_extensions_commands_list[@]}"; do + echo "$cmd - ${tifm_extensions_commands_help[$cmd]}" + done + fi + ;; + Q) + clear + exit + ;; + "") + # do nothing + ;; + *) + if [[ ! -z "${tifm_extensions_commands[$ans]}" ]]; then + eval "${tifm_extensions_commands[$ans]}" + elif [[ "${tifm_extensions_longcommands[*]}" =~ "$ans" ]]; then + read -n 1 tifm_subcommand + echo "" + if [[ ! -z "${tifm_extensions_subcommands[$ans$tifm_subcommand]}" ]]; then + eval "${tifm_extensions_subcommands[$ans$tifm_subcommand]}" + else + echo "Invalid subcommand." + fi + else + echo "Unrecognized command. Type '?' for a list of commands." + fi + ;; + esac + STATUS=$? } -main +( + clear + init + echo "$__TIFM_DECO_COLOUR$__ANGLE_UP_RIGHT$GREEN tifm $__TIFM_VERSION$NORMAL +$__TIFM_DECO_COLOUR$__VBAR$NORMAL $BLUE${UNDERLINE}https://github.com/Rexxt/tifm$NORMAL +$__TIFM_DECO_COLOUR$__VBAR$NORMAL $RED$REVERSE/!\\ you are running a bleeding edge version of tifm. $NORMAL +$__TIFM_DECO_COLOUR$__VBAR$NORMAL $RED$REVERSE if you encounter any bugs, report them on github.$NORMAL +$__TIFM_DECO_COLOUR$__ANGLE_DOWN_RIGHT$NORMAL strike '?' for help" + echo "" + while true; do + main + if "$__TIFM_CONFIRM_RETURN"; then + # wait for user to agree to return to the file view + echo + echo "${BRIGHT}${RED}press q to return to file view${NORMAL}" + key="" + while [ ! "$key" == "q" ]; do + read -n 1 key + done + clear + else + echo + fi + done +)