diff options
| author | spl3g <spleefer6@yandex.ru> | 2023-12-31 15:08:06 +0300 |
|---|---|---|
| committer | spl3g <spleefer6@yandex.ru> | 2025-05-01 14:56:39 +0300 |
| commit | b8a5c62b112859f463a53ac97b43f7f8cdc544a9 (patch) | |
| tree | 8b320bc9631fbd60ffe4b701e6afee148bb2313a /home-manager/general/programs/ranger | |
| parent | 7db487dba2262af7b7822d110122ff496070ca92 (diff) | |
uhm
Diffstat (limited to 'home-manager/general/programs/ranger')
19 files changed, 1264 insertions, 0 deletions
diff --git a/home-manager/general/programs/ranger/commands.py b/home-manager/general/programs/ranger/commands.py new file mode 100644 index 0000000..a41d42f --- /dev/null +++ b/home-manager/general/programs/ranger/commands.py @@ -0,0 +1,183 @@ +from ranger.api.commands import Command +from ranger.container.file import File +from ranger.ext.get_executables import get_executables +from collections import deque +import os +import subprocess + +# fd search + + +class fd_search(Command): + """ + :fd_search [-d<depth>] <query> + Executes "fd -d<depth> <query>" in the current directory and focuses the + first match. <depth> defaults to 1, i.e. only the contents of the current + directory. + + See https://github.com/sharkdp/fd + """ + + SEARCH_RESULTS = deque() + + def execute(self): + import re + import subprocess + from ranger.ext.get_executables import get_executables + + self.SEARCH_RESULTS.clear() + + if "fdfind" in get_executables(): + fd = "fdfind" + elif "fd" in get_executables(): + fd = "fd" + else: + self.fm.notify("Couldn't find fd in the PATH.", bad=True) + return + + if self.arg(1): + if self.arg(1)[:2] == "-d": + depth = self.arg(1) + target = self.rest(2) + else: + depth = "-d1" + target = self.rest(1) + else: + self.fm.notify(":fd_search needs a query.", bad=True) + return + + hidden = "--hidden" if self.fm.settings.show_hidden else "" + exclude = "--no-ignore-vcs --exclude '.git' --exclude '*.py[co]' --exclude '__pycache__'" + command = "{} --follow {} {} {} --print0 {}".format( + fd, depth, hidden, exclude, target + ) + fd = self.fm.execute_command( + command, universal_newlines=True, stdout=subprocess.PIPE + ) + stdout, _ = fd.communicate() + + if fd.returncode == 0: + results = filter(None, stdout.split("\0")) + if not self.fm.settings.show_hidden and self.fm.settings.hidden_filter: + hidden_filter = re.compile(self.fm.settings.hidden_filter) + results = filter( + lambda res: not hidden_filter.search(os.path.basename(res)), results + ) + results = map( + lambda res: os.path.abspath(os.path.join(self.fm.thisdir.path, res)), + results, + ) + self.SEARCH_RESULTS.extend(sorted(results, key=str.lower)) + if len(self.SEARCH_RESULTS) > 0: + self.fm.notify( + "Found {} result{}.".format( + len(self.SEARCH_RESULTS), + ("s" if len(self.SEARCH_RESULTS) > 1 else ""), + ) + ) + self.fm.select_file(self.SEARCH_RESULTS[0]) + else: + self.fm.notify("No results found.") + + +class fd_next(Command): + """ + :fd_next + Selects the next match from the last :fd_search. + """ + + def execute(self): + if len(fd_search.SEARCH_RESULTS) > 1: + fd_search.SEARCH_RESULTS.rotate(-1) # rotate left + self.fm.select_file(fd_search.SEARCH_RESULTS[0]) + elif len(fd_search.SEARCH_RESULTS) == 1: + self.fm.select_file(fd_search.SEARCH_RESULTS[0]) + + +class fd_prev(Command): + """ + :fd_prev + Selects the next match from the last :fd_search. + """ + + def execute(self): + if len(fd_search.SEARCH_RESULTS) > 1: + fd_search.SEARCH_RESULTS.rotate(1) # rotate right + self.fm.select_file(fd_search.SEARCH_RESULTS[0]) + elif len(fd_search.SEARCH_RESULTS) == 1: + self.fm.select_file(fd_search.SEARCH_RESULTS[0]) + + +# yank content +class YankContentWl(Command): + def execute(self): + if "wl-copy" not in get_executables(): + self.fm.notify("wl-clipboard is not found.", bad=True) + return + + arg = self.rest(1) + if arg: + if not os.path.isfile(arg): + self.fm.notify("{} is not a file".format(arg)) + return + file = File(arg) + else: + file = self.fm.thisfile + if not file.is_file: + self.fm.notify("{} is not a file".format(file.relative_path)) + return + if file.is_binary or file.image: + subprocess.check_call("wl-copy" + " < " + file.path, shell=True) + else: + self.fm.notify( + "{} is not an image file or a text file".format(file.relative_path) + ) + + +import os +import subprocess +from ranger.api.commands import Command +from ranger.container.file import File +from ranger.ext.get_executables import get_executables + + +class YankContent(Command): + """ + Copy the content of image file and text file with xclip + """ + + def execute(self): + if "xclip" not in get_executables(): + self.fm.notify("xclip is not found.", bad=True) + return + + arg = self.rest(1) + if arg: + if not os.path.isfile(arg): + self.fm.notify("{} is not a file.".format(arg)) + return + file = File(arg) + else: + file = self.fm.thisfile + if not file.is_file: + self.fm.notify("{} is not a file.".format(file.relative_path)) + return + + relative_path = file.relative_path + cmd = ["xclip", "-selection", "clipboard"] + if not file.is_binary(): + with open(file.path, "rb") as fd: + subprocess.check_call(cmd, stdin=fd) + elif file.image: + cmd += ["-t", file.mimetype, file.path] + subprocess.check_call(cmd) + self.fm.notify( + "Content of {} is copied to x clipboard".format(relative_path) + ) + else: + self.fm.notify( + "{} is not an image file or a text file.".format(relative_path) + ) + + def tab(self, tabnum): + return self._tab_directory_content() diff --git a/home-manager/general/programs/ranger/default.nix b/home-manager/general/programs/ranger/default.nix new file mode 100644 index 0000000..4dbced5 --- /dev/null +++ b/home-manager/general/programs/ranger/default.nix @@ -0,0 +1,11 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ ranger wl-clipboard ]; + xdg.configFile = { + "ranger/rc.conf".text = builtins.readFile ./rc.conf; + "ranger/rifle.conf".text = builtins.readFile ./rifle.conf; + "ranger/scope.sh".text = builtins.readFile ./scope.sh; + "ranger/commands.py".source = ./commands.py; + "ranger/plugins".source = ./plugins; + }; +} diff --git a/home-manager/general/programs/ranger/default.nix~ b/home-manager/general/programs/ranger/default.nix~ new file mode 100644 index 0000000..ea1b298 --- /dev/null +++ b/home-manager/general/programs/ranger/default.nix~ @@ -0,0 +1,7 @@ +{ pkgs, ... }: +let + "ranger/rc.conf".text = builtins.readFile ./rc.conf; + "ranger/rifle.conf".text = builtins.readFile ./rifle.conf; + "ranger/scope.sh".text = builtins.readFile ./scope.sh; + "ranger/commands.py".source = ./commands.py; + "ranger/plugins".source = ./plugins; diff --git a/home-manager/general/programs/ranger/plugins/__init__.py b/home-manager/general/programs/ranger/plugins/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/__init__.py diff --git a/home-manager/general/programs/ranger/plugins/__pycache__/__init__.cpython-310.pyc b/home-manager/general/programs/ranger/plugins/__pycache__/__init__.cpython-310.pyc Binary files differnew file mode 100644 index 0000000..1a26aa3 --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/__pycache__/__init__.cpython-310.pyc diff --git a/home-manager/general/programs/ranger/plugins/__pycache__/__init__.cpython-311.pyc b/home-manager/general/programs/ranger/plugins/__pycache__/__init__.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..87b2e7f --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/__pycache__/__init__.cpython-311.pyc diff --git a/home-manager/general/programs/ranger/plugins/__pycache__/fd.cpython-311.pyc b/home-manager/general/programs/ranger/plugins/__pycache__/fd.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..146af23 --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/__pycache__/fd.cpython-311.pyc diff --git a/home-manager/general/programs/ranger/plugins/__pycache__/quit_cd_wd.cpython-310.pyc b/home-manager/general/programs/ranger/plugins/__pycache__/quit_cd_wd.cpython-310.pyc Binary files differnew file mode 100644 index 0000000..49d1db9 --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/__pycache__/quit_cd_wd.cpython-310.pyc diff --git a/home-manager/general/programs/ranger/plugins/__pycache__/quit_cd_wd.cpython-311.pyc b/home-manager/general/programs/ranger/plugins/__pycache__/quit_cd_wd.cpython-311.pyc Binary files differnew file mode 100644 index 0000000..7b3ac1c --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/__pycache__/quit_cd_wd.cpython-311.pyc diff --git a/home-manager/general/programs/ranger/plugins/quit_cd_wd.py b/home-manager/general/programs/ranger/plugins/quit_cd_wd.py new file mode 100644 index 0000000..e47837f --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/quit_cd_wd.py @@ -0,0 +1,38 @@ +import ranger.api +from ranger.api.commands import * +import os + +def save_wd(command): + with open(os.path.expanduser('~/.ranger_quit_cd_wd'), 'w') as f: + f.write(command.fm.thisdir.path); + +class quit_cd_wd(Command): + """:chdir to working directory of ranger after quiting on ranger. + + """ + def _exit_no_work(self): + if self.fm.loader.has_work(): + self.fm.notify('Not quitting: Tasks in progress: Use `quit!` to force quit') + else: + self.fm.exit() + + def execute(self): + if len(self.fm.tabs) >= 2: + self.fm.tab_close() + else: + save_wd(self) + self._exit_no_work() + +class quitall_cd_wd(Command): + """:chdir to working directory of ranger after quitalling on ranger. + + """ + def _exit_no_work(self): + if self.fm.loader.has_work(): + self.fm.notify('Not quitting: Tasks in progress: Use `quitall!` to force quit') + else: + self.fm.exit() + + def execute(self): + save_wd(self) + self._exit_no_work() diff --git a/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/.gitignore b/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/.gitignore new file mode 100644 index 0000000..846dc44 --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/.gitignore @@ -0,0 +1,132 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# Pycharm +.idea diff --git a/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/LICENSE b/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/LICENSE new file mode 100644 index 0000000..bd840f1 --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 MuXiu1997 + +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. diff --git a/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/README.md b/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/README.md new file mode 100644 index 0000000..6a65e17 --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/README.md @@ -0,0 +1,47 @@ +# ranger-fzf-filter +This is a plugin for [`ranger`](https://github.com/ranger/ranger) that add a fuzzy filter. It depends on [`fzf`](https://github.com/junegunn/fzf) + +https://user-images.githubusercontent.com/49554020/173509108-dc3edca4-8949-4026-a3ca-0ba8dac9bbce.mp4 + + +## Install + +For ranger >= 1.9.3, use Git to clone this repository into your `~/.config/ranger/plugins` folder. For example: + +```sh +git clone git@github.com:MuXiu1997/ranger-fzf-filter.git ~/.config/ranger/plugins/ranger_fzf_filter +``` + +**Legacy Install** + +For ranger versions older than 1.9.3, or to install without Git, download `__init__.py` to your `~/.config/ranger/plugins` directory. For example: + +```shell +mkdir -p ~/.config/ranger/plugins +wget -O ~/.config/ranger/plugins/ranger_fzf_filter.py https://raw.githubusercontent.com/MuXiu1997/ranger-fzf-filter/main/__init__.py +``` + + + +## Usage + +Command: + +- `:fzf_filter [query]`: filtering files with fzf, see this [search syntax](https://github.com/junegunn/fzf#search-syntax) + + + +## Keyboard Shortcut + +Add a binding to your `~/.config/ranger/rc.conf` file to quickly use `:fzf_filter`: + +``` +map f console fzf_filter%space +``` + + + +## License + +[MIT](LICENSE) + diff --git a/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/__init__.py b/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/__init__.py new file mode 100644 index 0000000..b5d5b46 --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/__init__.py @@ -0,0 +1,35 @@ +import ranger.api +import ranger.container.directory +# noinspection PyUnresolvedReferences +from .command import fzf_filter, KEY_FZF_FILTER + +# region overwrite hook_init +HOOK_INIT_OLD = ranger.api.hook_init + + +def hook_init(fm): + def clear_fzf_filter(signal): + if fm.settings.clear_filters_on_dir_change and signal.previous: + signal.previous.__dict__[KEY_FZF_FILTER] = None + signal.previous.refilter() + + fm.signal_bind('cd', clear_fzf_filter) + return HOOK_INIT_OLD(fm) + + +ranger.api.hook_init = hook_init +# endregion overwrite hook_init + +# region overwrite accept_file +ACCEPT_FILE_OLD = ranger.container.directory.accept_file + + +def accept_file(fobj, filters): + _fzf_filter = fobj.fm.thisdir.__dict__.get(KEY_FZF_FILTER, None) + if _fzf_filter: + filters.append(_fzf_filter) + return ACCEPT_FILE_OLD(fobj, filters) + + +ranger.container.directory.accept_file = accept_file +# endregion overwrite accept_file diff --git a/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/command.py b/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/command.py new file mode 100644 index 0000000..92aee83 --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/command.py @@ -0,0 +1,59 @@ +import ranger.api.commands +from .filter import FzfFilter + +# noinspection PyUnreachableCode +# This is done to enhance auto-completion and inference in the editor. +if False: + import ranger.core.fm + +KEY_FZF_FILTER = 'fzf_filter' + + +# noinspection PyPep8Naming,PyUnresolvedReferences +class fzf_filter(ranger.api.commands.Command): + """ + :fzf_filter <query> + + This command allows you to use fzf fuzzy search to filter files and directories in the ranger. + """ + + def execute(self): + fm = self.fm # type: ranger.core.fm.FM + # Check if a filter is already set + _filter = fm.thisdir.__dict__.get(KEY_FZF_FILTER, None) + if isinstance(_filter, FzfFilter): + # If a filter is set, just update the query + _filter.set_query(self._get_query()) + else: + # If no filter is set, build a new one + fm.thisdir.__dict__[KEY_FZF_FILTER] = self._build_filter() + + fm.thisdir.refilter() + if self.quickly_executed: + fm.open_console(self.line) + + def cancel(self): + fm = self.fm # type: ranger.core.fm.FM + fm.thisdir.__dict__[KEY_FZF_FILTER] = None + fm.thisdir.refilter() + + def quick(self): + return True + + def _get_query(self): + """ + Get the search query. + + Returns: + str: The search query. + """ + return self.rest(1) + + def _build_filter(self): + """ + Build a new FzfFilter. + + Returns: + FzfFilter: A new FzfFilter object with the current directory and search query. + """ + return FzfFilter(self.fm.thisdir, self._get_query()) diff --git a/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/filter.py b/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/filter.py new file mode 100644 index 0000000..3d12756 --- /dev/null +++ b/home-manager/general/programs/ranger/plugins/ranger_fzf_filter/filter.py @@ -0,0 +1,84 @@ +import os.path +import subprocess + + +class FzfFilter: + """ + A filter class for FZF fuzzy search. + + Attributes: + thisdir (ranger.container.directory.Directory): The current directory. + query (str): The search query. + source (list[str]): List of relative paths of all files in the current directory. + result (list[str]): The result of fzf search. + """ + + def __init__(self, thisdir, query): + """ + Initialize the FzfFilter class. + + Args: + thisdir (ranger.container.directory.Directory): The current directory. + query (str): The search query. + """ + self.thisdir = thisdir + self.files_all = thisdir.files_all + + self.query = query + + self.source = [] + self.recalc_source() + + self.result = [] + self.recalc_result() + + def recalc_source(self): + """ + Recalculate the source list based on the files in the current directory. + """ + self.source = [f.relative_path for f in self.thisdir.files_all] + + def recalc_result(self): + """ + Recalculate the result list by executing the fzf command. + """ + cmd = subprocess.Popen( + ['fzf', '-f', self.query], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + stdout, _ = cmd.communicate('\n'.join(self.source).encode('utf-8')) + self.result = stdout.decode('utf-8').strip().splitlines() + + def set_query(self, query): + """ + Update the query and recalculate the result list. + + Args: + query (str): The new search query. + """ + self.query = query + self.recalc_result() + + def __call__(self, fobj): + """ + Perform the actual filtering. + + Args: + fobj (ranger.container.file.File | ranger.container.directory.Directory): The file or directory to check. + + Returns: + bool: True if the file or directory is in the result list, False otherwise. + """ + # Check if the files in the current directory have changed, and if so, recalculate source and result + if self.thisdir.files_all is not self.files_all: + self.files_all = self.thisdir.files_all + self.recalc_source() + self.recalc_result() + + # Ensure the relative path start of the file or directory is in the current directory + if os.path.relpath(fobj.path, fobj.relative_path) != '.': + return True + + # Check if the relative path of the file or directory is in the result list + return fobj.relative_path in self.result diff --git a/home-manager/general/programs/ranger/rc.conf b/home-manager/general/programs/ranger/rc.conf new file mode 100644 index 0000000..271d239 --- /dev/null +++ b/home-manager/general/programs/ranger/rc.conf @@ -0,0 +1,12 @@ +map f console fzf_filter%space +map x quit_cd_wd +map X quitall_cd_wd +map <alt>/ console fd_search -d5%space +map <alt>n fd_next +map <alt>p fd_prev +map e shell dragon -x %p & +map yc YankContent +set preview_images true +set preview_images_method kitty +set use_preview_script True +map gj cd /run/media/jerpo/ diff --git a/home-manager/general/programs/ranger/rifle.conf b/home-manager/general/programs/ranger/rifle.conf new file mode 100644 index 0000000..3b565af --- /dev/null +++ b/home-manager/general/programs/ranger/rifle.conf @@ -0,0 +1,284 @@ +# vim: ft=cfg +# +# This is the configuration file of "rifle", ranger's file executor/opener. +# Each line consists of conditions and a command. For each line the conditions +# are checked and if they are met, the respective command is run. +# +# Syntax: +# <condition1> , <condition2> , ... = command +# +# The command can contain these environment variables: +# $1-$9 | The n-th selected file +# $@ | All selected files +# +# If you use the special command "ask", rifle will ask you what program to run. +# +# Prefixing a condition with "!" will negate its result. +# These conditions are currently supported: +# match <regexp> | The regexp matches $1 +# ext <regexp> | The regexp matches the extension of $1 +# mime <regexp> | The regexp matches the mime type of $1 +# name <regexp> | The regexp matches the basename of $1 +# path <regexp> | The regexp matches the absolute path of $1 +# has <program> | The program is installed (i.e. located in $PATH) +# env <variable> | The environment variable "variable" is non-empty +# file | $1 is a file +# directory | $1 is a directory +# number <n> | change the number of this command to n +# terminal | stdin, stderr and stdout are connected to a terminal +# X | A graphical environment is available (darwin, Xorg, or Wayland) +# +# There are also pseudo-conditions which have a "side effect": +# flag <flags> | Change how the program is run. See below. +# label <label> | Assign a label or name to the command so it can +# | be started with :open_with <label> in ranger +# | or `rifle -p <label>` in the standalone executable. +# else | Always true. +# +# Flags are single characters which slightly transform the command: +# f | Fork the program, make it run in the background. +# | New command = setsid $command >& /dev/null & +# r | Execute the command with root permissions +# | New command = sudo $command +# t | Run the program in a new terminal. If $TERMCMD is not defined, +# | rifle will attempt to extract it from $TERM. +# | New command = $TERMCMD -e $command +# Note: The "New command" serves only as an illustration, the exact +# implementation may differ. +# Note: When using rifle in ranger, there is an additional flag "c" for +# only running the current file even if you have marked multiple files. + +#------------------------------------------- +# Websites +#------------------------------------------- +# Rarely installed browsers get higher priority; It is assumed that if you +# install a rare browser, you probably use it. Firefox/konqueror/w3m on the +# other hand are often only installed as fallback browsers. +ext x?html?, has surf, X, flag f = surf -- file://"$1" +ext x?html?, has vimprobable, X, flag f = vimprobable -- "$@" +ext x?html?, has vimprobable2, X, flag f = vimprobable2 -- "$@" +ext x?html?, has qutebrowser, X, flag f = qutebrowser -- "$@" +ext x?html?, has dwb, X, flag f = dwb -- "$@" +ext x?html?, has jumanji, X, flag f = jumanji -- "$@" +ext x?html?, has luakit, X, flag f = luakit -- "$@" +ext x?html?, has uzbl, X, flag f = uzbl -- "$@" +ext x?html?, has uzbl-tabbed, X, flag f = uzbl-tabbed -- "$@" +ext x?html?, has uzbl-browser, X, flag f = uzbl-browser -- "$@" +ext x?html?, has uzbl-core, X, flag f = uzbl-core -- "$@" +ext x?html?, has midori, X, flag f = midori -- "$@" +ext x?html?, has opera, X, flag f = opera -- "$@" +ext x?html?, has firefox, X, flag f = firefox -- "$@" +ext x?html?, has seamonkey, X, flag f = seamonkey -- "$@" +ext x?html?, has iceweasel, X, flag f = iceweasel -- "$@" +ext x?html?, has chromium-browser, X, flag f = chromium-browser -- "$@" +ext x?html?, has chromium, X, flag f = chromium -- "$@" +ext x?html?, has google-chrome, X, flag f = google-chrome -- "$@" +ext x?html?, has epiphany, X, flag f = epiphany -- "$@" +ext x?html?, has konqueror, X, flag f = konqueror -- "$@" +ext x?html?, has elinks, terminal = elinks "$@" +ext x?html?, has links2, terminal = links2 "$@" +ext x?html?, has links, terminal = links "$@" +ext x?html?, has lynx, terminal = lynx -- "$@" +ext x?html?, has w3m, terminal = w3m "$@" + +#------------------------------------------- +# Misc +#------------------------------------------- +# Define the "editor" for text files as first action +mime ^text, label editor = ${VISUAL:-$EDITOR} -- "$@" +mime ^text, label pager = "$PAGER" -- "$@" +!mime ^text, label editor, ext xml|json|csv|tex|py|pl|rb|js|sh|php = ${VISUAL:-$EDITOR} -- "$@" +!mime ^text, label pager, ext xml|json|csv|tex|py|pl|rb|js|sh|php = "$PAGER" -- "$@" + +ext 1 = man "$1" +ext s[wmf]c, has zsnes, X = zsnes "$1" +ext s[wmf]c, has snes9x-gtk,X = snes9x-gtk "$1" +ext nes, has fceux, X = fceux "$1" +ext exe = wine "$1" +name ^[mM]akefile$ = make + +#-------------------------------------------- +# Scripts +#------------------------------------------- +ext py = python -- "$1" +ext pl = perl -- "$1" +ext rb = ruby -- "$1" +ext js = node -- "$1" +ext sh = sh -- "$1" +ext php = php -- "$1" + +#-------------------------------------------- +# Audio without X +#------------------------------------------- +mime ^audio|ogg$, terminal, has mpv = mpv -- "$@" +mime ^audio|ogg$, terminal, has mplayer2 = mplayer2 -- "$@" +mime ^audio|ogg$, terminal, has mplayer = mplayer -- "$@" +ext midi?, terminal, has wildmidi = wildmidi -- "$@" + +#-------------------------------------------- +# Video/Audio with a GUI +#------------------------------------------- +mime ^video|audio, has gmplayer, X, flag f = gmplayer -- "$@" +mime ^video|audio, has smplayer, X, flag f = smplayer "$@" +mime ^video, has mpv, X, flag f = mpv -- "$@" +mime ^video, has mpv, X, flag f = mpv --fs -- "$@" +mime ^video, has mplayer2, X, flag f = mplayer2 -- "$@" +mime ^video, has mplayer2, X, flag f = mplayer2 -fs -- "$@" +mime ^video, has mplayer, X, flag f = mplayer -- "$@" +mime ^video, has mplayer, X, flag f = mplayer -fs -- "$@" +mime ^video|audio, has vlc, X, flag f = vlc -- "$@" +mime ^video|audio, has totem, X, flag f = totem -- "$@" +mime ^video|audio, has totem, X, flag f = totem --fullscreen -- "$@" + +#-------------------------------------------- +# Video without X +#------------------------------------------- +mime ^video, terminal, !X, has mpv = mpv -- "$@" +mime ^video, terminal, !X, has mplayer2 = mplayer2 -- "$@" +mime ^video, terminal, !X, has mplayer = mplayer -- "$@" + +#------------------------------------------- +# Documents +#------------------------------------------- +ext pdf, has llpp, X, flag f = llpp "$@" +ext pdf, has zathura, X, flag f = zathura -- "$@" +ext pdf, has mupdf, X, flag f = mupdf "$@" +ext pdf, has mupdf-x11,X, flag f = mupdf-x11 "$@" +ext pdf, has apvlv, X, flag f = apvlv -- "$@" +ext pdf, has xpdf, X, flag f = xpdf -- "$@" +ext pdf, has evince, X, flag f = evince -- "$@" +ext pdf, has atril, X, flag f = atril -- "$@" +ext pdf, has okular, X, flag f = okular -- "$@" +ext pdf, has epdfview, X, flag f = epdfview -- "$@" +ext pdf, has qpdfview, X, flag f = qpdfview "$@" +ext pdf, has open, X, flag f = open "$@" + +ext docx?, has catdoc, terminal = catdoc -- "$@" | "$PAGER" + +ext sxc|xlsx?|xlt|xlw|gnm|gnumeric, has gnumeric, X, flag f = gnumeric -- "$@" +ext sxc|xlsx?|xlt|xlw|gnm|gnumeric, has kspread, X, flag f = kspread -- "$@" +ext pptx?|od[dfgpst]|docx?|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has libreoffice, X, flag f = libreoffice "$@" +ext pptx?|od[dfgpst]|docx?|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has soffice, X, flag f = soffice "$@" +ext pptx?|od[dfgpst]|docx?|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has ooffice, X, flag f = ooffice "$@" + +ext djvu, has zathura,X, flag f = zathura -- "$@" +ext djvu, has evince, X, flag f = evince -- "$@" +ext djvu, has atril, X, flag f = atril -- "$@" +ext djvu, has djview, X, flag f = djview -- "$@" + +ext epub, has ebook-viewer, X, flag f = ebook-viewer -- "$@" +ext epub, has zathura, X, flag f = zathura -- "$@" +ext epub, has mupdf, X, flag f = mupdf -- "$@" +ext mobi, has ebook-viewer, X, flag f = ebook-viewer -- "$@" + +ext cbr, has zathura, X, flag f = zathura -- "$@" +ext cbz, has zathura, X, flag f = zathura -- "$@" + +#------------------------------------------- +# Images +#------------------------------------------- +mime ^image/svg, has inkscape, X, flag f = inkscape -- "$@" +mime ^image/svg, has display, X, flag f = display -- "$@" + +mime ^image, has geeqie, X, flag f = geeqie -- "$@" +mime ^image, has imv, X, flag f = imv -- "$@" +mime ^image, has pqiv, X, flag f = pqiv -- "$@" +mime ^image, has sxiv, X, flag f = sxiv -- "$@" +mime ^image, has feh, X, flag f = feh -- "$@" +mime ^image, has mirage, X, flag f = mirage -- "$@" +mime ^image, has ristretto, X, flag f = ristretto "$@" +mime ^image, has eog, X, flag f = eog -- "$@" +mime ^image, has eom, X, flag f = eom -- "$@" +mime ^image, has nomacs, X, flag f = nomacs -- "$@" +mime ^image, has gpicview, X, flag f = gpicview -- "$@" +mime ^image, has gwenview, X, flag f = gwenview -- "$@" +mime ^image, has gimp, X, flag f = gimp -- "$@" +ext xcf, X, flag f = gimp -- "$@" + +#------------------------------------------- +# Archives +#------------------------------------------- + +# avoid password prompt by providing empty password +ext 7z, has 7z = 7z -p l "$@" | "$PAGER" +# This requires atool +ext ace|ar|arc|bz2?|cab|cpio|cpt|deb|dgc|dmg|gz, has atool = atool --list --each -- "$@" | "$PAGER" +ext iso|jar|msi|pkg|rar|shar|tar|tgz|xar|xpi|xz|zip, has atool = atool --list --each -- "$@" | "$PAGER" +ext 7z|ace|ar|arc|bz2?|cab|cpio|cpt|deb|dgc|dmg|gz, has atool = atool --extract --each -- "$@" +ext iso|jar|msi|pkg|rar|shar|tar|tgz|xar|xpi|xz|zip, has atool = atool --extract --each -- "$@" + +# Listing and extracting archives without atool: +ext tar|gz|bz2|xz, has tar = tar vvtf "$1" | "$PAGER" +ext tar|gz|bz2|xz, has tar = for file in "$@"; do tar vvxf "$file"; done +ext bz2, has bzip2 = for file in "$@"; do bzip2 -dk "$file"; done +ext zip, has unzip = unzip -l "$1" | less +ext zip, has unzip = for file in "$@"; do unzip -d "${file%.*}" "$file"; done +ext ace, has unace = unace l "$1" | less +ext ace, has unace = for file in "$@"; do unace e "$file"; done +ext rar, has unrar = unrar l "$1" | less +ext rar, has unrar = for file in "$@"; do unrar x "$file"; done + +#------------------------------------------- +# Fonts +#------------------------------------------- +mime ^font, has fontforge, X, flag f = fontforge "$@" + +#------------------------------------------- +# Flag t fallback terminals +#------------------------------------------- +# Rarely installed terminal emulators get higher priority; It is assumed that +# if you install a rare terminal emulator, you probably use it. +# gnome-terminal/konsole/xterm on the other hand are often installed as part of +# a desktop environment or as fallback terminal emulators. +mime ^ranger/x-terminal-emulator, has terminology = terminology -e "$@" +mime ^ranger/x-terminal-emulator, has kitty = kitty -- "$@" +mime ^ranger/x-terminal-emulator, has alacritty = alacritty -e "$@" +mime ^ranger/x-terminal-emulator, has sakura = sakura -e "$@" +mime ^ranger/x-terminal-emulator, has lilyterm = lilyterm -e "$@" +#mime ^ranger/x-terminal-emulator, has cool-retro-term = cool-retro-term -e "$@" +mime ^ranger/x-terminal-emulator, has termite = termite -x '"$@"' +#mime ^ranger/x-terminal-emulator, has yakuake = yakuake -e "$@" +mime ^ranger/x-terminal-emulator, has guake = guake -ne "$@" +mime ^ranger/x-terminal-emulator, has tilda = tilda -c "$@" +mime ^ranger/x-terminal-emulator, has st = st -e "$@" +mime ^ranger/x-terminal-emulator, has terminator = terminator -x "$@" +mime ^ranger/x-terminal-emulator, has urxvt = urxvt -e "$@" +mime ^ranger/x-terminal-emulator, has pantheon-terminal = pantheon-terminal -e "$@" +mime ^ranger/x-terminal-emulator, has lxterminal = lxterminal -e "$@" +mime ^ranger/x-terminal-emulator, has mate-terminal = mate-terminal -x "$@" +mime ^ranger/x-terminal-emulator, has xfce4-terminal = xfce4-terminal -x "$@" +mime ^ranger/x-terminal-emulator, has konsole = konsole -e "$@" +mime ^ranger/x-terminal-emulator, has gnome-terminal = gnome-terminal -- "$@" +mime ^ranger/x-terminal-emulator, has xterm = xterm -e "$@" + +#------------------------------------------- +# Misc +#------------------------------------------- +label wallpaper, number 11, mime ^image, has feh, X = feh --bg-scale "$1" +label wallpaper, number 12, mime ^image, has feh, X = feh --bg-tile "$1" +label wallpaper, number 13, mime ^image, has feh, X = feh --bg-center "$1" +label wallpaper, number 14, mime ^image, has feh, X = feh --bg-fill "$1" + +#------------------------------------------- +# Generic file openers +#------------------------------------------- +label open, has xdg-open = xdg-open -- "$@" +label open, has open = open -- "$@" + +# Define the editor for non-text files + pager as last action + !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php = ask +label editor, !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php = ${VISUAL:-$EDITOR} -- "$@" +label pager, !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php = "$PAGER" -- "$@" + + +###################################################################### +# The actions below are left so low down in this file on purpose, so # +# they are never triggered accidentally. # +###################################################################### + +# Execute a file as program/script. +mime application/x-executable = "$1" + +# Move the file to trash using trash-cli. +label trash, has trash-put = trash-put -- "$@" +label trash = mkdir -p -- ${XDG_DATA_DIR:-$HOME/.ranger}/ranger-trash; mv -- "$@" ${XDG_DATA_DIR:-$HOME/.ranger}/ranger-trash diff --git a/home-manager/general/programs/ranger/scope.sh b/home-manager/general/programs/ranger/scope.sh new file mode 100755 index 0000000..f9c7648 --- /dev/null +++ b/home-manager/general/programs/ranger/scope.sh @@ -0,0 +1,351 @@ +#!/usr/bin/env bash + +set -o noclobber -o noglob -o nounset -o pipefail +IFS=$'\n' + +## If the option `use_preview_script` is set to `true`, +## then this script will be called and its output will be displayed in ranger. +## ANSI color codes are supported. +## STDIN is disabled, so interactive scripts won't work properly + +## This script is considered a configuration file and must be updated manually. +## It will be left untouched if you upgrade ranger. + +## Because of some automated testing we do on the script #'s for comments need +## to be doubled up. Code that is commented out, because it's an alternative for +## example, gets only one #. + +## Meanings of exit codes: +## code | meaning | action of ranger +## -----+------------+------------------------------------------- +## 0 | success | Display stdout as preview +## 1 | no preview | Display no preview at all +## 2 | plain text | Display the plain content of the file +## 3 | fix width | Don't reload when width changes +## 4 | fix height | Don't reload when height changes +## 5 | fix both | Don't ever reload +## 6 | image | Display the image `$IMAGE_CACHE_PATH` points to as an image preview +## 7 | image | Display the file directly as an image + +## Script arguments +FILE_PATH="${1}" # Full path of the highlighted file +PV_WIDTH="${2}" # Width of the preview pane (number of fitting characters) +## shellcheck disable=SC2034 # PV_HEIGHT is provided for convenience and unused +PV_HEIGHT="${3}" # Height of the preview pane (number of fitting characters) +IMAGE_CACHE_PATH="${4}" # Full path that should be used to cache image preview +PV_IMAGE_ENABLED="${5}" # 'True' if image previews are enabled, 'False' otherwise. + +FILE_EXTENSION="${FILE_PATH##*.}" +FILE_EXTENSION_LOWER="$(printf "%s" "${FILE_EXTENSION}" | tr '[:upper:]' '[:lower:]')" + +## Settings +HIGHLIGHT_SIZE_MAX=262143 # 256KiB +HIGHLIGHT_TABWIDTH=${HIGHLIGHT_TABWIDTH:-8} +HIGHLIGHT_STYLE=${HIGHLIGHT_STYLE:-pablo} +HIGHLIGHT_OPTIONS="--replace-tabs=${HIGHLIGHT_TABWIDTH} --style=${HIGHLIGHT_STYLE} ${HIGHLIGHT_OPTIONS:-}" +PYGMENTIZE_STYLE=${PYGMENTIZE_STYLE:-autumn} +OPENSCAD_IMGSIZE=${RNGR_OPENSCAD_IMGSIZE:-1000,1000} +OPENSCAD_COLORSCHEME=${RNGR_OPENSCAD_COLORSCHEME:-Tomorrow Night} + +handle_extension() { + case "${FILE_EXTENSION_LOWER}" in + ## Archive + a|ace|alz|arc|arj|bz|bz2|cab|cpio|deb|gz|jar|lha|lz|lzh|lzma|lzo|\ + rpm|rz|t7z|tar|tbz|tbz2|tgz|tlz|txz|tZ|tzo|war|xpi|xz|Z|zip) + atool --list -- "${FILE_PATH}" && exit 5 + bsdtar --list --file "${FILE_PATH}" && exit 5 + exit 1;; + rar) + ## Avoid password prompt by providing empty password + unrar lt -p- -- "${FILE_PATH}" && exit 5 + exit 1;; + 7z) + ## Avoid password prompt by providing empty password + 7z l -p -- "${FILE_PATH}" && exit 5 + exit 1;; + + ## PDF + pdf) + ## Preview as text conversion + pdftotext -l 10 -nopgbrk -q -- "${FILE_PATH}" - | \ + fmt -w "${PV_WIDTH}" && exit 5 + mutool draw -F txt -i -- "${FILE_PATH}" 1-10 | \ + fmt -w "${PV_WIDTH}" && exit 5 + exiftool "${FILE_PATH}" && exit 5 + exit 1;; + + ## BitTorrent + torrent) + transmission-show -- "${FILE_PATH}" && exit 5 + exit 1;; + + ## OpenDocument + odt|ods|odp|sxw) + ## Preview as text conversion + odt2txt "${FILE_PATH}" && exit 5 + ## Preview as markdown conversion + pandoc -s -t markdown -- "${FILE_PATH}" && exit 5 + exit 1;; + + ## XLSX + xlsx) + ## Preview as csv conversion + ## Uses: https://github.com/dilshod/xlsx2csv + xlsx2csv -- "${FILE_PATH}" && exit 5 + exit 1;; + + ## HTML + htm|html|xhtml) + ## Preview as text conversion + w3m -dump "${FILE_PATH}" && exit 5 + lynx -dump -- "${FILE_PATH}" && exit 5 + elinks -dump "${FILE_PATH}" && exit 5 + pandoc -s -t markdown -- "${FILE_PATH}" && exit 5 + ;; + + ## JSON + json) + jq --color-output . "${FILE_PATH}" && exit 5 + python -m json.tool -- "${FILE_PATH}" && exit 5 + ;; + + ## Direct Stream Digital/Transfer (DSDIFF) and wavpack aren't detected + ## by file(1). + dff|dsf|wv|wvc) + mediainfo "${FILE_PATH}" && exit 5 + exiftool "${FILE_PATH}" && exit 5 + ;; # Continue with next handler on failure + esac +} + +handle_image() { + ## Size of the preview if there are multiple options or it has to be + ## rendered from vector graphics. If the conversion program allows + ## specifying only one dimension while keeping the aspect ratio, the width + ## will be used. + local DEFAULT_SIZE="1920x1080" + + local mimetype="${1}" + case "${mimetype}" in + ## SVG + # image/svg+xml|image/svg) + # convert -- "${FILE_PATH}" "${IMAGE_CACHE_PATH}" && exit 6 + # exit 1;; + + ## DjVu + # image/vnd.djvu) + # ddjvu -format=tiff -quality=90 -page=1 -size="${DEFAULT_SIZE}" \ + # - "${IMAGE_CACHE_PATH}" < "${FILE_PATH}" \ + # && exit 6 || exit 1;; + + ## Image + image/*) + local orientation + orientation="$( identify -format '%[EXIF:Orientation]\n' -- "${FILE_PATH}" )" + ## If orientation data is present and the image actually + ## needs rotating ("1" means no rotation)... + if [[ -n "$orientation" && "$orientation" != 1 ]]; then + ## ...auto-rotate the image according to the EXIF data. + convert -- "${FILE_PATH}" -auto-orient "${IMAGE_CACHE_PATH}" && exit 6 + fi + kitty +kitten icat "${IMAGE_CACHE_PATH}" + + ## `w3mimgdisplay` will be called for all images (unless overriden + ## as above), but might fail for unsupported types. + exit 7;; + + ## Video + video/*) + # Thumbnail + ffmpegthumbnailer -i "${FILE_PATH}" -o "${IMAGE_CACHE_PATH}" -s 0 && exit 6 + exit 1;; + + ## PDF + application/pdf) + pdftoppm -f 1 -l 1 \ + -scale-to-x "${DEFAULT_SIZE%x*}" \ + -scale-to-y -1 \ + -singlefile \ + -jpeg -tiffcompression jpeg \ + -- "${FILE_PATH}" "${IMAGE_CACHE_PATH%.*}" \ + && exit 6 || exit 1;; + + + ## ePub, MOBI, FB2 (using Calibre) + application/epub+zip|application/x-mobipocket-ebook|\ + application/x-fictionbook+xml) + # ePub (using https://github.com/marianosimone/epub-thumbnailer) + epub-thumbnailer "${FILE_PATH}" "${IMAGE_CACHE_PATH}" \ + "${DEFAULT_SIZE%x*}" && exit 6 + ebook-meta --get-cover="${IMAGE_CACHE_PATH}" -- "${FILE_PATH}" \ + >/dev/null && exit 6 + exit 1;; + + ## Font + application/font*|application/*opentype) + preview_png="/tmp/$(basename "${IMAGE_CACHE_PATH%.*}").png" + if fontimage -o "${preview_png}" \ + --pixelsize "120" \ + --fontname \ + --pixelsize "80" \ + --text " ABCDEFGHIJKLMNOPQRSTUVWXYZ " \ + --text " abcdefghijklmnopqrstuvwxyz " \ + --text " 0123456789.:,;(*!?') ff fl fi ffi ffl " \ + --text " The quick brown fox jumps over the lazy dog. " \ + "${FILE_PATH}"; + then + convert -- "${preview_png}" "${IMAGE_CACHE_PATH}" \ + && rm "${preview_png}" \ + && exit 6 + else + exit 1 + fi + ;; + + ## Preview archives using the first image inside. + ## (Very useful for comic book collections for example.) + # application/zip|application/x-rar|application/x-7z-compressed|\ + # application/x-xz|application/x-bzip2|application/x-gzip|application/x-tar) + # local fn=""; local fe="" + # local zip=""; local rar=""; local tar=""; local bsd="" + # case "${mimetype}" in + # application/zip) zip=1 ;; + # application/x-rar) rar=1 ;; + # application/x-7z-compressed) ;; + # *) tar=1 ;; + # esac + # { [ "$tar" ] && fn=$(tar --list --file "${FILE_PATH}"); } || \ + # { fn=$(bsdtar --list --file "${FILE_PATH}") && bsd=1 && tar=""; } || \ + # { [ "$rar" ] && fn=$(unrar lb -p- -- "${FILE_PATH}"); } || \ + # { [ "$zip" ] && fn=$(zipinfo -1 -- "${FILE_PATH}"); } || return + # + # fn=$(echo "$fn" | python -c "import sys; import mimetypes as m; \ + # [ print(l, end='') for l in sys.stdin if \ + # (m.guess_type(l[:-1])[0] or '').startswith('image/') ]" |\ + # sort -V | head -n 1) + # [ "$fn" = "" ] && return + # [ "$bsd" ] && fn=$(printf '%b' "$fn") + # + # [ "$tar" ] && tar --extract --to-stdout \ + # --file "${FILE_PATH}" -- "$fn" > "${IMAGE_CACHE_PATH}" && exit 6 + # fe=$(echo -n "$fn" | sed 's/[][*?\]/\\\0/g') + # [ "$bsd" ] && bsdtar --extract --to-stdout \ + # --file "${FILE_PATH}" -- "$fe" > "${IMAGE_CACHE_PATH}" && exit 6 + # [ "$bsd" ] || [ "$tar" ] && rm -- "${IMAGE_CACHE_PATH}" + # [ "$rar" ] && unrar p -p- -inul -- "${FILE_PATH}" "$fn" > \ + # "${IMAGE_CACHE_PATH}" && exit 6 + # [ "$zip" ] && unzip -pP "" -- "${FILE_PATH}" "$fe" > \ + # "${IMAGE_CACHE_PATH}" && exit 6 + # [ "$rar" ] || [ "$zip" ] && rm -- "${IMAGE_CACHE_PATH}" + # ;; + esac + + # openscad_image() { + # TMPPNG="$(mktemp -t XXXXXX.png)" + # openscad --colorscheme="${OPENSCAD_COLORSCHEME}" \ + # --imgsize="${OPENSCAD_IMGSIZE/x/,}" \ + # -o "${TMPPNG}" "${1}" + # mv "${TMPPNG}" "${IMAGE_CACHE_PATH}" + # } + + # case "${FILE_EXTENSION_LOWER}" in + # ## 3D models + # ## OpenSCAD only supports png image output, and ${IMAGE_CACHE_PATH} + # ## is hardcoded as jpeg. So we make a tempfile.png and just + # ## move/rename it to jpg. This works because image libraries are + # ## smart enough to handle it. + # csg|scad) + # openscad_image "${FILE_PATH}" && exit 6 + # ;; + # 3mf|amf|dxf|off|stl) + # openscad_image <(echo "import(\"${FILE_PATH}\");") && exit 6 + # ;; + # esac +} + +handle_mime() { + local mimetype="${1}" + case "${mimetype}" in + ## RTF and DOC + text/rtf|*msword) + ## Preview as text conversion + ## note: catdoc does not always work for .doc files + ## catdoc: http://www.wagner.pp.ru/~vitus/software/catdoc/ + catdoc -- "${FILE_PATH}" && exit 5 + exit 1;; + + ## DOCX, ePub, FB2 (using markdown) + ## You might want to remove "|epub" and/or "|fb2" below if you have + ## uncommented other methods to preview those formats + *wordprocessingml.document|*/epub+zip|*/x-fictionbook+xml) + ## Preview as markdown conversion + pandoc -s -t markdown -- "${FILE_PATH}" && exit 5 + exit 1;; + + ## XLS + *ms-excel) + ## Preview as csv conversion + ## xls2csv comes with catdoc: + ## http://www.wagner.pp.ru/~vitus/software/catdoc/ + xls2csv -- "${FILE_PATH}" && exit 5 + exit 1;; + + ## Text + text/* | */xml) + ## Syntax highlight + if [[ "$( stat --printf='%s' -- "${FILE_PATH}" )" -gt "${HIGHLIGHT_SIZE_MAX}" ]]; then + exit 2 + fi + if [[ "$( tput colors )" -ge 256 ]]; then + local pygmentize_format='terminal256' + local highlight_format='xterm256' + else + local pygmentize_format='terminal' + local highlight_format='ansi' + fi + env HIGHLIGHT_OPTIONS="${HIGHLIGHT_OPTIONS}" highlight \ + --out-format="${highlight_format}" \ + --force -- "${FILE_PATH}" && exit 5 + env COLORTERM=8bit bat --color=always --style="plain" \ + -- "${FILE_PATH}" && exit 5 + pygmentize -f "${pygmentize_format}" -O "style=${PYGMENTIZE_STYLE}"\ + -- "${FILE_PATH}" && exit 5 + exit 2;; + + ## DjVu + image/vnd.djvu) + ## Preview as text conversion (requires djvulibre) + djvutxt "${FILE_PATH}" | fmt -w "${PV_WIDTH}" && exit 5 + exiftool "${FILE_PATH}" && exit 5 + exit 1;; + + ## Image + image/*) + ## Preview as text conversion + # img2txt --gamma=0.6 --width="${PV_WIDTH}" -- "${FILE_PATH}" && exit 4 + exiftool "${FILE_PATH}" && exit 5 + exit 1;; + + ## Video and audio + video/* | audio/*) + mediainfo "${FILE_PATH}" && exit 5 + exiftool "${FILE_PATH}" && exit 5 + exit 1;; + esac +} + +handle_fallback() { + echo '----- File Type Classification -----' && file --dereference --brief -- "${FILE_PATH}" && exit 5 + exit 1 +} + + +MIMETYPE="$( file --dereference --brief --mime-type -- "${FILE_PATH}" )" +if [[ "${PV_IMAGE_ENABLED}" == 'True' ]]; then + handle_image "${MIMETYPE}" +fi +handle_extension +handle_mime "${MIMETYPE}" +handle_fallback + +exit 1 |
