├── .flake8 ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── README.md ├── poetry.lock ├── pyproject.toml ├── ranger_tmux ├── __init__.py ├── __main__.py ├── cwd_sync.py ├── cwd_track.py ├── drop.py ├── dropdown.py ├── open_in_window.py ├── plugin.py ├── set_window_name.py ├── splits.py └── util.py └── scripts └── publish.py /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | select = B,B9,BLK,C4,D,DAR,E,F,I,S,TC,W 3 | ignore = E203,E501,W503,ANN101,ANN102,ANN204,S101,B010 4 | max-line-length = 88 5 | max-complexity = 10 6 | application-import-names = euporie,tests 7 | import-order-style = google 8 | docstring-convention = google 9 | docstring_style = google 10 | per-file-ignores = tests/*:S101 11 | strictness = short 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 98 | __pypackages__/ 99 | 100 | # Celery stuff 101 | celerybeat-schedule 102 | celerybeat.pid 103 | 104 | # SageMath parsed files 105 | *.sage.py 106 | 107 | # Environments 108 | .env 109 | .venv 110 | env/ 111 | venv/ 112 | ENV/ 113 | env.bak/ 114 | venv.bak/ 115 | 116 | # Spyder project settings 117 | .spyderproject 118 | .spyproject 119 | 120 | # Rope project settings 121 | .ropeproject 122 | 123 | # mkdocs documentation 124 | /site 125 | 126 | # mypy 127 | .mypy_cache/ 128 | .dmypy.json 129 | dmypy.json 130 | 131 | # Pyre type checker 132 | .pyre/ 133 | 134 | # pytype static type analyzer 135 | .pytype/ 136 | 137 | # Cython debug symbols 138 | cython_debug/ 139 | # Byte-compiled / optimized / DLL files 140 | __pycache__/ 141 | *.py[cod] 142 | *$py.class 143 | 144 | # C extensions 145 | *.so 146 | 147 | # Distribution / packaging 148 | .Python 149 | build/ 150 | develop-eggs/ 151 | dist/ 152 | downloads/ 153 | eggs/ 154 | .eggs/ 155 | lib/ 156 | lib64/ 157 | parts/ 158 | sdist/ 159 | var/ 160 | wheels/ 161 | share/python-wheels/ 162 | *.egg-info/ 163 | .installed.cfg 164 | *.egg 165 | MANIFEST 166 | 167 | # PyInstaller 168 | # Usually these files are written by a python script from a template 169 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 170 | *.manifest 171 | *.spec 172 | 173 | # Installer logs 174 | pip-log.txt 175 | pip-delete-this-directory.txt 176 | 177 | # Unit test / coverage reports 178 | htmlcov/ 179 | .tox/ 180 | .nox/ 181 | .coverage 182 | .coverage.* 183 | .cache 184 | nosetests.xml 185 | coverage.xml 186 | *.cover 187 | *.py,cover 188 | .hypothesis/ 189 | .pytest_cache/ 190 | cover/ 191 | 192 | # Translations 193 | *.mo 194 | *.pot 195 | 196 | # Django stuff: 197 | *.log 198 | local_settings.py 199 | db.sqlite3 200 | db.sqlite3-journal 201 | 202 | # Flask stuff: 203 | instance/ 204 | .webassets-cache 205 | 206 | # Scrapy stuff: 207 | .scrapy 208 | 209 | # Sphinx documentation 210 | docs/_build/ 211 | 212 | # PyBuilder 213 | .pybuilder/ 214 | target/ 215 | 216 | # Jupyter Notebook 217 | .ipynb_checkpoints 218 | 219 | # IPython 220 | profile_default/ 221 | ipython_config.py 222 | 223 | # pyenv 224 | # For a library or package, you might want to ignore these files since the code is 225 | # intended to run in multiple environments; otherwise, check them in: 226 | # .python-version 227 | 228 | # pipenv 229 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 230 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 231 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 232 | # install all needed dependencies. 233 | #Pipfile.lock 234 | 235 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 236 | __pypackages__/ 237 | 238 | # Celery stuff 239 | celerybeat-schedule 240 | celerybeat.pid 241 | 242 | # SageMath parsed files 243 | *.sage.py 244 | 245 | # Environments 246 | .env 247 | .venv 248 | env/ 249 | venv/ 250 | ENV/ 251 | env.bak/ 252 | venv.bak/ 253 | 254 | # Spyder project settings 255 | .spyderproject 256 | .spyproject 257 | 258 | # Rope project settings 259 | .ropeproject 260 | 261 | # mkdocs documentation 262 | /site 263 | 264 | # mypy 265 | .mypy_cache/ 266 | .dmypy.json 267 | dmypy.json 268 | 269 | # Pyre type checker 270 | .pyre/ 271 | 272 | # pytype static type analyzer 273 | .pytype/ 274 | 275 | # Cython debug symbols 276 | cython_debug/ 277 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v3.4.0 4 | hooks: 5 | - id: fix-byte-order-marker 6 | - id: fix-encoding-pragma 7 | - id: check-yaml 8 | - id: end-of-file-fixer 9 | - id: trailing-whitespace 10 | - repo: https://github.com/pre-commit/mirrors-prettier 11 | rev: v2.2.1 12 | hooks: 13 | - id: prettier 14 | - repo: local 15 | hooks: 16 | - id: black 17 | name: black 18 | entry: poetry run black 19 | language: system 20 | types: [python] 21 | - id: flake8 22 | name: flake8 23 | entry: poetry run flake8 24 | language: system 25 | types: [python] 26 | - id: isort 27 | name: isort 28 | entry: poetry run isort 29 | args: ["--profile", "black", "--filter-files"] 30 | language: system 31 | types: [python] 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Josiah Outram Halstead 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ranger-tmux 2 | 3 | Tmux integration for ranger 4 | 5 | ## Install 6 | 7 | To install this plugin, clone the respository into ranger's plugins folder, or install it with pip: 8 | 9 | ``` 10 | pip install ranger-tmux 11 | # Then run this to install the package as a ranger plugin: 12 | python -m ranger_tmux install 13 | ``` 14 | 15 | ## Features 16 | 17 | 18 | 19 | - Open files from ranger in a new tmux window or pane 20 | - Make your terminal track ranger's directory 21 | - Make ranger track your terminal's directory 22 | - Set tmux window title to show ranger is running 23 | - Drop down file-manager in your tmux session 24 | - Easily split a ranger pane to launch a shell in the current folder 25 | 26 | ### Other pane tracking & syncing 27 | 28 | This plugin enables syncing of the current working directory between ranger and other tmux panes in the same window. 29 | 30 | The pane to be used for syncing or tracking is determined in the following order: 31 | 32 | 1. A marked pane; 33 | 2. The currently selected pane; 34 | 3. The last selected pane; 35 | 4. The next pane. 36 | 37 | Ranger will only sync its working directory to another pane if the process running in another pane does not have any child processes. This prevents ranger typing `cd` commands if you have launched a text editor from the shell in the other pane. 38 | 39 | ### Drop-down ranger 40 | 41 | When installing the plugin, you will be asked if you want to install a key-binding in `~/.tmux.conf` for drop-down ranger. This allows you to toggle ranger in a drop-down tmux pane in the current window. This can be run manually by running `python -m ranger_tmux.drop` in a tmux session. 42 | 43 | The key binding can be installed by running `python -m ranger_tmux --tmux install`, or by running the `:install_tmux_dropdown_shortcut` command in ranger (or typing the `xh` shortcut). The default key-binding installed is `prefix, backspace`, but this can be changed by editing the lines added to `~/.tmux.conf`. 44 | 45 | ## Shortcut keys 46 | 47 | | Key Sequence | Command | 48 | | ------------ | --------------------------------------------------------------------------------- | 49 | | `xc` | Change the current working directory in the other pane to the directory in ranger | 50 | | `xd` | Change ranger's current directory to the directory of the other pane | 51 | | `xs` | Toggle syncing of ranger's current directory to the other pane | 52 | | `xt` | Toggle tracking of the other pane's working directory to tmux | 53 | | `xw` | Toggle opening files in a new tmux window | 54 | | `xi` | Toggle setting the tmux window's title to "ranger" when ranger is running | 55 | | `xe` | Open the selected file with rifle in a new tmux window | 56 | | `x\|` | Split ranger's current tmux pane vertially | 57 | | `x-` | Split ranger's current tmux pane horizontally | 58 | | `xh` | Adds the dropdown shortcut to `~/.tmux.conf` | 59 | 60 | ## Settings 61 | 62 | This plugin adds several settings to ranger: 63 | 64 | | Setting | Type | Default | Meaning | 65 | | ------------------------- | ----- | ------- | ---------------------------------------------------------------------------------------- | 66 | | `tmux_cwd_sync` | bool | False | When True, ranger's current directory is synced to the other pane | 67 | | `tmux_cwd_sync_now_focus` | bool | False | When True, the other pane will be focused after manually syncing it with ranger | 68 | | `tmux_cwd_track` | bool | False | When True, ranger's current directory tracks the other pane | 69 | | `tmux_cwd_track_interval` | float | 0.5 | Time between checks of the directory of the other pane when tracking | 70 | | `tmux_open_in_window` | bool | True | When True, files opened with ranger will open in a new tmux window | 71 | | `tmux_set_title` | bool | True | When True, the tmux window will be renamed to "ranger" when ranger is running | 72 | | `tmux_dropdown_percent` | int | 60 | The height of the pane created when the drop-down tmux key-binding is installed and used | 73 | | `tmux_dropdown_animate` | bool | True | When True, dropped-down ranger will grow / shrink when summoned | 74 | | `tmux_dropdown_duration` | float | 100 | Drop-down animation time in miliseconds | 75 | 76 | The default values can be modified by setting them in `~/.config/ranger/rc.conf`, e.g.: 77 | 78 | ``` 79 | set tmux_cwd_sync true 80 | set tmux_cwd_track true 81 | set tmux_set_title true 82 | set tmux_open_in_window true 83 | set tmux_dropdown_percent 60 84 | ``` 85 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "appdirs" 3 | version = "1.4.4" 4 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 5 | category = "dev" 6 | optional = false 7 | python-versions = "*" 8 | 9 | [[package]] 10 | name = "backports.functools-lru-cache" 11 | version = "1.6.4" 12 | description = "Backport of functools.lru_cache" 13 | category = "dev" 14 | optional = false 15 | python-versions = ">=2.6" 16 | 17 | [package.extras] 18 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] 19 | testing = ["pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-mypy", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-checkdocs (>=2.4)"] 20 | 21 | [[package]] 22 | name = "black" 23 | version = "20.8b1" 24 | description = "The uncompromising code formatter." 25 | category = "dev" 26 | optional = false 27 | python-versions = ">=3.6" 28 | 29 | [package.dependencies] 30 | appdirs = "*" 31 | click = ">=7.1.2" 32 | dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} 33 | mypy-extensions = ">=0.4.3" 34 | pathspec = ">=0.6,<1" 35 | regex = ">=2020.1.8" 36 | toml = ">=0.10.1" 37 | typed-ast = ">=1.4.0" 38 | typing-extensions = ">=3.7.4" 39 | 40 | [package.extras] 41 | colorama = ["colorama (>=0.4.3)"] 42 | d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] 43 | 44 | [[package]] 45 | name = "click" 46 | version = "8.0.3" 47 | description = "Composable command line interface toolkit" 48 | category = "dev" 49 | optional = false 50 | python-versions = ">=3.6" 51 | 52 | [package.dependencies] 53 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 54 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 55 | 56 | [[package]] 57 | name = "colorama" 58 | version = "0.4.4" 59 | description = "Cross-platform colored terminal text." 60 | category = "dev" 61 | optional = false 62 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 63 | 64 | [[package]] 65 | name = "configparser" 66 | version = "4.0.2" 67 | description = "Updated configparser from Python 3.7 for Python 2.6+." 68 | category = "main" 69 | optional = false 70 | python-versions = ">=2.6" 71 | 72 | [package.extras] 73 | docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] 74 | testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2)", "pytest-flake8", "pytest-black-multipy"] 75 | 76 | [[package]] 77 | name = "contextlib2" 78 | version = "0.6.0.post1" 79 | description = "Backports and enhancements for the contextlib module" 80 | category = "main" 81 | optional = false 82 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 83 | 84 | [[package]] 85 | name = "dataclasses" 86 | version = "0.8" 87 | description = "A backport of the dataclasses module for Python 3.6" 88 | category = "dev" 89 | optional = false 90 | python-versions = ">=3.6, <3.7" 91 | 92 | [[package]] 93 | name = "enum34" 94 | version = "1.1.10" 95 | description = "Python 3.4 Enum backported to 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4" 96 | category = "dev" 97 | optional = false 98 | python-versions = "*" 99 | 100 | [[package]] 101 | name = "flake8" 102 | version = "3.9.2" 103 | description = "the modular source code checker: pep8 pyflakes and co" 104 | category = "dev" 105 | optional = false 106 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 107 | 108 | [package.dependencies] 109 | configparser = {version = "*", markers = "python_version < \"3.2\""} 110 | enum34 = {version = "*", markers = "python_version < \"3.4\""} 111 | functools32 = {version = "*", markers = "python_version < \"3.2\""} 112 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 113 | mccabe = ">=0.6.0,<0.7.0" 114 | pycodestyle = ">=2.7.0,<2.8.0" 115 | pyflakes = ">=2.3.0,<2.4.0" 116 | typing = {version = "*", markers = "python_version < \"3.5\""} 117 | 118 | [[package]] 119 | name = "flake8-black" 120 | version = "0.2.3" 121 | description = "flake8 plugin to call black as a code style validator" 122 | category = "dev" 123 | optional = false 124 | python-versions = "*" 125 | 126 | [package.dependencies] 127 | black = "*" 128 | flake8 = ">=3.0.0" 129 | toml = "*" 130 | 131 | [[package]] 132 | name = "functools32" 133 | version = "3.2.3-2" 134 | description = "Backport of the functools module from Python 3.2.3 for use on 2.7 and PyPy." 135 | category = "dev" 136 | optional = false 137 | python-versions = "*" 138 | 139 | [[package]] 140 | name = "futures" 141 | version = "3.3.0" 142 | description = "Backport of the concurrent.futures package from Python 3" 143 | category = "dev" 144 | optional = false 145 | python-versions = ">=2.6, <3" 146 | 147 | [[package]] 148 | name = "importlib-metadata" 149 | version = "2.1.2" 150 | description = "Read metadata from Python packages" 151 | category = "main" 152 | optional = false 153 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 154 | 155 | [package.dependencies] 156 | configparser = {version = ">=3.5", markers = "python_version < \"3\""} 157 | contextlib2 = {version = "*", markers = "python_version < \"3\""} 158 | pathlib2 = {version = "*", markers = "python_version < \"3\""} 159 | zipp = ">=0.5" 160 | 161 | [package.extras] 162 | docs = ["sphinx", "rst.linker"] 163 | testing = ["packaging", "pep517", "unittest2", "importlib-resources (>=1.3)"] 164 | 165 | [[package]] 166 | name = "importlib-resources" 167 | version = "3.3.1" 168 | description = "Read resources from Python packages" 169 | category = "main" 170 | optional = false 171 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" 172 | 173 | [package.dependencies] 174 | contextlib2 = {version = "*", markers = "python_version < \"3\""} 175 | pathlib2 = {version = "*", markers = "python_version < \"3\""} 176 | singledispatch = {version = "*", markers = "python_version < \"3.4\""} 177 | typing = {version = "*", markers = "python_version < \"3.5\""} 178 | zipp = {version = ">=0.4", markers = "python_version < \"3.8\""} 179 | 180 | [package.extras] 181 | docs = ["sphinx", "rst.linker", "jaraco.packaging"] 182 | 183 | [[package]] 184 | name = "isort" 185 | version = "4.3.21" 186 | description = "A Python utility / library to sort Python imports." 187 | category = "dev" 188 | optional = false 189 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 190 | 191 | [package.dependencies] 192 | "backports.functools-lru-cache" = {version = "*", markers = "python_version < \"3.2\""} 193 | futures = {version = "*", markers = "python_version < \"3.2\""} 194 | 195 | [package.extras] 196 | pipfile = ["pipreqs", "requirementslib"] 197 | pyproject = ["toml"] 198 | requirements = ["pipreqs", "pip-api"] 199 | xdg_home = ["appdirs (>=1.4.0)"] 200 | 201 | [[package]] 202 | name = "mccabe" 203 | version = "0.6.1" 204 | description = "McCabe checker, plugin for flake8" 205 | category = "dev" 206 | optional = false 207 | python-versions = "*" 208 | 209 | [[package]] 210 | name = "mypy-extensions" 211 | version = "0.4.3" 212 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 213 | category = "dev" 214 | optional = false 215 | python-versions = "*" 216 | 217 | [[package]] 218 | name = "pathlib2" 219 | version = "2.3.6" 220 | description = "Object-oriented filesystem paths" 221 | category = "main" 222 | optional = false 223 | python-versions = "*" 224 | 225 | [package.dependencies] 226 | scandir = {version = "*", markers = "python_version < \"3.5\""} 227 | six = "*" 228 | 229 | [[package]] 230 | name = "pathspec" 231 | version = "0.9.0" 232 | description = "Utility library for gitignore style pattern matching of file paths." 233 | category = "dev" 234 | optional = false 235 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 236 | 237 | [[package]] 238 | name = "psutil" 239 | version = "5.8.0" 240 | description = "Cross-platform lib for process and system monitoring in Python." 241 | category = "main" 242 | optional = false 243 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 244 | 245 | [package.extras] 246 | test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"] 247 | 248 | [[package]] 249 | name = "pycodestyle" 250 | version = "2.7.0" 251 | description = "Python style guide checker" 252 | category = "dev" 253 | optional = false 254 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 255 | 256 | [[package]] 257 | name = "pyflakes" 258 | version = "2.3.1" 259 | description = "passive checker of Python programs" 260 | category = "dev" 261 | optional = false 262 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 263 | 264 | [[package]] 265 | name = "ranger-fm" 266 | version = "1.9.3" 267 | description = "Vim-like file manager" 268 | category = "main" 269 | optional = false 270 | python-versions = "*" 271 | 272 | [[package]] 273 | name = "regex" 274 | version = "2021.11.10" 275 | description = "Alternative regular expression module, to replace re." 276 | category = "dev" 277 | optional = false 278 | python-versions = "*" 279 | 280 | [[package]] 281 | name = "scandir" 282 | version = "1.10.0" 283 | description = "scandir, a better directory iterator and faster os.walk()" 284 | category = "main" 285 | optional = false 286 | python-versions = "*" 287 | 288 | [[package]] 289 | name = "singledispatch" 290 | version = "3.7.0" 291 | description = "Backport functools.singledispatch from Python 3.4 to Python 2.6-3.3." 292 | category = "main" 293 | optional = false 294 | python-versions = ">=2.6" 295 | 296 | [package.dependencies] 297 | six = "*" 298 | 299 | [package.extras] 300 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] 301 | testing = ["pytest (>=4.6)", "pytest-flake8", "pytest-cov", "pytest-black (>=0.3.7)", "unittest2", "pytest-checkdocs (>=2.4)"] 302 | 303 | [[package]] 304 | name = "six" 305 | version = "1.16.0" 306 | description = "Python 2 and 3 compatibility utilities" 307 | category = "main" 308 | optional = false 309 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 310 | 311 | [[package]] 312 | name = "toml" 313 | version = "0.10.2" 314 | description = "Python Library for Tom's Obvious, Minimal Language" 315 | category = "dev" 316 | optional = false 317 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 318 | 319 | [[package]] 320 | name = "typed-ast" 321 | version = "1.5.1" 322 | description = "a fork of Python 2 and 3 ast modules with type comment support" 323 | category = "dev" 324 | optional = false 325 | python-versions = ">=3.6" 326 | 327 | [[package]] 328 | name = "typing" 329 | version = "3.10.0.0" 330 | description = "Type Hints for Python" 331 | category = "main" 332 | optional = false 333 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <3.5" 334 | 335 | [[package]] 336 | name = "typing-extensions" 337 | version = "4.0.1" 338 | description = "Backported and Experimental Type Hints for Python 3.6+" 339 | category = "dev" 340 | optional = false 341 | python-versions = ">=3.6" 342 | 343 | [[package]] 344 | name = "zipp" 345 | version = "1.2.0" 346 | description = "Backport of pathlib-compatible object wrapper for zip files" 347 | category = "main" 348 | optional = false 349 | python-versions = ">=2.7" 350 | 351 | [package.dependencies] 352 | contextlib2 = {version = "*", markers = "python_version < \"3.4\""} 353 | 354 | [package.extras] 355 | docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] 356 | testing = ["pathlib2", "unittest2", "jaraco.itertools", "func-timeout"] 357 | 358 | [metadata] 359 | lock-version = "1.1" 360 | python-versions = ">=2.7 <3 || >=3.6" 361 | content-hash = "8e58d0b0056e011a6067fafee1167544b1a87f67cce5e7239e6692767ca75257" 362 | 363 | [metadata.files] 364 | appdirs = [ 365 | {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, 366 | {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, 367 | ] 368 | "backports.functools-lru-cache" = [ 369 | {file = "backports.functools_lru_cache-1.6.4-py2.py3-none-any.whl", hash = "sha256:dbead04b9daa817909ec64e8d2855fb78feafe0b901d4568758e3a60559d8978"}, 370 | {file = "backports.functools_lru_cache-1.6.4.tar.gz", hash = "sha256:d5ed2169378b67d3c545e5600d363a923b09c456dab1593914935a68ad478271"}, 371 | ] 372 | black = [ 373 | {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, 374 | ] 375 | click = [ 376 | {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, 377 | {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, 378 | ] 379 | colorama = [ 380 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 381 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 382 | ] 383 | configparser = [ 384 | {file = "configparser-4.0.2-py2.py3-none-any.whl", hash = "sha256:254c1d9c79f60c45dfde850850883d5aaa7f19a23f13561243a050d5a7c3fe4c"}, 385 | {file = "configparser-4.0.2.tar.gz", hash = "sha256:c7d282687a5308319bf3d2e7706e575c635b0a470342641c93bea0ea3b5331df"}, 386 | ] 387 | contextlib2 = [ 388 | {file = "contextlib2-0.6.0.post1-py2.py3-none-any.whl", hash = "sha256:3355078a159fbb44ee60ea80abd0d87b80b78c248643b49aa6d94673b413609b"}, 389 | {file = "contextlib2-0.6.0.post1.tar.gz", hash = "sha256:01f490098c18b19d2bd5bb5dc445b2054d2fa97f09a4280ba2c5f3c394c8162e"}, 390 | ] 391 | dataclasses = [ 392 | {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"}, 393 | {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"}, 394 | ] 395 | enum34 = [ 396 | {file = "enum34-1.1.10-py2-none-any.whl", hash = "sha256:a98a201d6de3f2ab3db284e70a33b0f896fbf35f8086594e8c9e74b909058d53"}, 397 | {file = "enum34-1.1.10-py3-none-any.whl", hash = "sha256:c3858660960c984d6ab0ebad691265180da2b43f07e061c0f8dca9ef3cffd328"}, 398 | {file = "enum34-1.1.10.tar.gz", hash = "sha256:cce6a7477ed816bd2542d03d53db9f0db935dd013b70f336a95c73979289f248"}, 399 | ] 400 | flake8 = [ 401 | {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, 402 | {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, 403 | ] 404 | flake8-black = [ 405 | {file = "flake8-black-0.2.3.tar.gz", hash = "sha256:c199844bc1b559d91195ebe8620216f21ed67f2cc1ff6884294c91a0d2492684"}, 406 | {file = "flake8_black-0.2.3-py3-none-any.whl", hash = "sha256:cc080ba5b3773b69ba102b6617a00cc4ecbad8914109690cfda4d565ea435d96"}, 407 | ] 408 | functools32 = [ 409 | {file = "functools32-3.2.3-2.tar.gz", hash = "sha256:f6253dfbe0538ad2e387bd8fdfd9293c925d63553f5813c4e587745416501e6d"}, 410 | {file = "functools32-3.2.3-2.zip", hash = "sha256:89d824aa6c358c421a234d7f9ee0bd75933a67c29588ce50aaa3acdf4d403fa0"}, 411 | ] 412 | futures = [ 413 | {file = "futures-3.3.0-py2-none-any.whl", hash = "sha256:49b3f5b064b6e3afc3316421a3f25f66c137ae88f068abbf72830170033c5e16"}, 414 | {file = "futures-3.3.0.tar.gz", hash = "sha256:7e033af76a5e35f58e56da7a91e687706faf4e7bdfb2cbc3f2cca6b9bcda9794"}, 415 | ] 416 | importlib-metadata = [ 417 | {file = "importlib_metadata-2.1.2-py2.py3-none-any.whl", hash = "sha256:cd6a92d78385dd145f5f233b3a6919acf5e8e43922aa9b9dbe78573e3540eb56"}, 418 | {file = "importlib_metadata-2.1.2.tar.gz", hash = "sha256:09db40742204610ef6826af16e49f0479d11d0d54687d0169ff7fddf8b3f557f"}, 419 | ] 420 | importlib-resources = [ 421 | {file = "importlib_resources-3.3.1-py2.py3-none-any.whl", hash = "sha256:42068585cc5e8c2bf0a17449817401102a5125cbfbb26bb0f43cde1568f6f2df"}, 422 | {file = "importlib_resources-3.3.1.tar.gz", hash = "sha256:0ed250dbd291947d1a298e89f39afcc477d5a6624770503034b72588601bcc05"}, 423 | ] 424 | isort = [ 425 | {file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"}, 426 | {file = "isort-4.3.21.tar.gz", hash = "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1"}, 427 | ] 428 | mccabe = [ 429 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 430 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 431 | ] 432 | mypy-extensions = [ 433 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 434 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 435 | ] 436 | pathlib2 = [ 437 | {file = "pathlib2-2.3.6-py2.py3-none-any.whl", hash = "sha256:3a130b266b3a36134dcc79c17b3c7ac9634f083825ca6ea9d8f557ee6195c9c8"}, 438 | {file = "pathlib2-2.3.6.tar.gz", hash = "sha256:7d8bcb5555003cdf4a8d2872c538faa3a0f5d20630cb360e518ca3b981795e5f"}, 439 | ] 440 | pathspec = [ 441 | {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, 442 | {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, 443 | ] 444 | psutil = [ 445 | {file = "psutil-5.8.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64"}, 446 | {file = "psutil-5.8.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0ae6f386d8d297177fd288be6e8d1afc05966878704dad9847719650e44fc49c"}, 447 | {file = "psutil-5.8.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:12d844996d6c2b1d3881cfa6fa201fd635971869a9da945cf6756105af73d2df"}, 448 | {file = "psutil-5.8.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:02b8292609b1f7fcb34173b25e48d0da8667bc85f81d7476584d889c6e0f2131"}, 449 | {file = "psutil-5.8.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6ffe81843131ee0ffa02c317186ed1e759a145267d54fdef1bc4ea5f5931ab60"}, 450 | {file = "psutil-5.8.0-cp27-none-win32.whl", hash = "sha256:ea313bb02e5e25224e518e4352af4bf5e062755160f77e4b1767dd5ccb65f876"}, 451 | {file = "psutil-5.8.0-cp27-none-win_amd64.whl", hash = "sha256:5da29e394bdedd9144c7331192e20c1f79283fb03b06e6abd3a8ae45ffecee65"}, 452 | {file = "psutil-5.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:74fb2557d1430fff18ff0d72613c5ca30c45cdbfcddd6a5773e9fc1fe9364be8"}, 453 | {file = "psutil-5.8.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:74f2d0be88db96ada78756cb3a3e1b107ce8ab79f65aa885f76d7664e56928f6"}, 454 | {file = "psutil-5.8.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:99de3e8739258b3c3e8669cb9757c9a861b2a25ad0955f8e53ac662d66de61ac"}, 455 | {file = "psutil-5.8.0-cp36-cp36m-win32.whl", hash = "sha256:36b3b6c9e2a34b7d7fbae330a85bf72c30b1c827a4366a07443fc4b6270449e2"}, 456 | {file = "psutil-5.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:52de075468cd394ac98c66f9ca33b2f54ae1d9bff1ef6b67a212ee8f639ec06d"}, 457 | {file = "psutil-5.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c6a5fd10ce6b6344e616cf01cc5b849fa8103fbb5ba507b6b2dee4c11e84c935"}, 458 | {file = "psutil-5.8.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:61f05864b42fedc0771d6d8e49c35f07efd209ade09a5afe6a5059e7bb7bf83d"}, 459 | {file = "psutil-5.8.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0dd4465a039d343925cdc29023bb6960ccf4e74a65ad53e768403746a9207023"}, 460 | {file = "psutil-5.8.0-cp37-cp37m-win32.whl", hash = "sha256:1bff0d07e76114ec24ee32e7f7f8d0c4b0514b3fae93e3d2aaafd65d22502394"}, 461 | {file = "psutil-5.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:fcc01e900c1d7bee2a37e5d6e4f9194760a93597c97fee89c4ae51701de03563"}, 462 | {file = "psutil-5.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6223d07a1ae93f86451d0198a0c361032c4c93ebd4bf6d25e2fb3edfad9571ef"}, 463 | {file = "psutil-5.8.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d225cd8319aa1d3c85bf195c4e07d17d3cd68636b8fc97e6cf198f782f99af28"}, 464 | {file = "psutil-5.8.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:28ff7c95293ae74bf1ca1a79e8805fcde005c18a122ca983abf676ea3466362b"}, 465 | {file = "psutil-5.8.0-cp38-cp38-win32.whl", hash = "sha256:ce8b867423291cb65cfc6d9c4955ee9bfc1e21fe03bb50e177f2b957f1c2469d"}, 466 | {file = "psutil-5.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:90f31c34d25b1b3ed6c40cdd34ff122b1887a825297c017e4cbd6796dd8b672d"}, 467 | {file = "psutil-5.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6323d5d845c2785efb20aded4726636546b26d3b577aded22492908f7c1bdda7"}, 468 | {file = "psutil-5.8.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:245b5509968ac0bd179287d91210cd3f37add77dad385ef238b275bad35fa1c4"}, 469 | {file = "psutil-5.8.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:90d4091c2d30ddd0a03e0b97e6a33a48628469b99585e2ad6bf21f17423b112b"}, 470 | {file = "psutil-5.8.0-cp39-cp39-win32.whl", hash = "sha256:ea372bcc129394485824ae3e3ddabe67dc0b118d262c568b4d2602a7070afdb0"}, 471 | {file = "psutil-5.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:f4634b033faf0d968bb9220dd1c793b897ab7f1189956e1aa9eae752527127d3"}, 472 | {file = "psutil-5.8.0.tar.gz", hash = "sha256:0c9ccb99ab76025f2f0bbecf341d4656e9c1351db8cc8a03ccd62e318ab4b5c6"}, 473 | ] 474 | pycodestyle = [ 475 | {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, 476 | {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, 477 | ] 478 | pyflakes = [ 479 | {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, 480 | {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, 481 | ] 482 | ranger-fm = [ 483 | {file = "ranger-fm-1.9.3.tar.gz", hash = "sha256:9476ed1971c641f4ba3dde1b8b80387f0216fcde3507426d06871f9d7189ac5e"}, 484 | ] 485 | regex = [ 486 | {file = "regex-2021.11.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf"}, 487 | {file = "regex-2021.11.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:416c5f1a188c91e3eb41e9c8787288e707f7d2ebe66e0a6563af280d9b68478f"}, 488 | {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0538c43565ee6e703d3a7c3bdfe4037a5209250e8502c98f20fea6f5fdf2965"}, 489 | {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee1227cf08b6716c85504aebc49ac827eb88fcc6e51564f010f11a406c0a667"}, 490 | {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6650f16365f1924d6014d2ea770bde8555b4a39dc9576abb95e3cd1ff0263b36"}, 491 | {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30ab804ea73972049b7a2a5c62d97687d69b5a60a67adca07eb73a0ddbc9e29f"}, 492 | {file = "regex-2021.11.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68a067c11463de2a37157930d8b153005085e42bcb7ad9ca562d77ba7d1404e0"}, 493 | {file = "regex-2021.11.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:162abfd74e88001d20cb73ceaffbfe601469923e875caf9118333b1a4aaafdc4"}, 494 | {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9ed0b1e5e0759d6b7f8e2f143894b2a7f3edd313f38cf44e1e15d360e11749b"}, 495 | {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:473e67837f786404570eae33c3b64a4b9635ae9f00145250851a1292f484c063"}, 496 | {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2fee3ed82a011184807d2127f1733b4f6b2ff6ec7151d83ef3477f3b96a13d03"}, 497 | {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d5fd67df77bab0d3f4ea1d7afca9ef15c2ee35dfb348c7b57ffb9782a6e4db6e"}, 498 | {file = "regex-2021.11.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5d408a642a5484b9b4d11dea15a489ea0928c7e410c7525cd892f4d04f2f617b"}, 499 | {file = "regex-2021.11.10-cp310-cp310-win32.whl", hash = "sha256:98ba568e8ae26beb726aeea2273053c717641933836568c2a0278a84987b2a1a"}, 500 | {file = "regex-2021.11.10-cp310-cp310-win_amd64.whl", hash = "sha256:780b48456a0f0ba4d390e8b5f7c661fdd218934388cde1a974010a965e200e12"}, 501 | {file = "regex-2021.11.10-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dba70f30fd81f8ce6d32ddeef37d91c8948e5d5a4c63242d16a2b2df8143aafc"}, 502 | {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1f54b9b4b6c53369f40028d2dd07a8c374583417ee6ec0ea304e710a20f80a0"}, 503 | {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbb9dc00e39f3e6c0ef48edee202f9520dafb233e8b51b06b8428cfcb92abd30"}, 504 | {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666abff54e474d28ff42756d94544cdfd42e2ee97065857413b72e8a2d6a6345"}, 505 | {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5537f71b6d646f7f5f340562ec4c77b6e1c915f8baae822ea0b7e46c1f09b733"}, 506 | {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2e07c6a26ed4bea91b897ee2b0835c21716d9a469a96c3e878dc5f8c55bb23"}, 507 | {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca5f18a75e1256ce07494e245cdb146f5a9267d3c702ebf9b65c7f8bd843431e"}, 508 | {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:74cbeac0451f27d4f50e6e8a8f3a52ca074b5e2da9f7b505c4201a57a8ed6286"}, 509 | {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:3598893bde43091ee5ca0a6ad20f08a0435e93a69255eeb5f81b85e81e329264"}, 510 | {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:50a7ddf3d131dc5633dccdb51417e2d1910d25cbcf842115a3a5893509140a3a"}, 511 | {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:61600a7ca4bcf78a96a68a27c2ae9389763b5b94b63943d5158f2a377e09d29a"}, 512 | {file = "regex-2021.11.10-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:563d5f9354e15e048465061509403f68424fef37d5add3064038c2511c8f5e00"}, 513 | {file = "regex-2021.11.10-cp36-cp36m-win32.whl", hash = "sha256:93a5051fcf5fad72de73b96f07d30bc29665697fb8ecdfbc474f3452c78adcf4"}, 514 | {file = "regex-2021.11.10-cp36-cp36m-win_amd64.whl", hash = "sha256:b483c9d00a565633c87abd0aaf27eb5016de23fed952e054ecc19ce32f6a9e7e"}, 515 | {file = "regex-2021.11.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fff55f3ce50a3ff63ec8e2a8d3dd924f1941b250b0aac3d3d42b687eeff07a8e"}, 516 | {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e32d2a2b02ccbef10145df9135751abea1f9f076e67a4e261b05f24b94219e36"}, 517 | {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53db2c6be8a2710b359bfd3d3aa17ba38f8aa72a82309a12ae99d3c0c3dcd74d"}, 518 | {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2207ae4f64ad3af399e2d30dde66f0b36ae5c3129b52885f1bffc2f05ec505c8"}, 519 | {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5ca078bb666c4a9d1287a379fe617a6dccd18c3e8a7e6c7e1eb8974330c626a"}, 520 | {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd33eb9bdcfbabab3459c9ee651d94c842bc8a05fabc95edf4ee0c15a072495e"}, 521 | {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05b7d6d7e64efe309972adab77fc2af8907bb93217ec60aa9fe12a0dad35874f"}, 522 | {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:42b50fa6666b0d50c30a990527127334d6b96dd969011e843e726a64011485da"}, 523 | {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6e1d2cc79e8dae442b3fa4a26c5794428b98f81389af90623ffcc650ce9f6732"}, 524 | {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:0416f7399e918c4b0e074a0f66e5191077ee2ca32a0f99d4c187a62beb47aa05"}, 525 | {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:ce298e3d0c65bd03fa65ffcc6db0e2b578e8f626d468db64fdf8457731052942"}, 526 | {file = "regex-2021.11.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dc07f021ee80510f3cd3af2cad5b6a3b3a10b057521d9e6aaeb621730d320c5a"}, 527 | {file = "regex-2021.11.10-cp37-cp37m-win32.whl", hash = "sha256:e71255ba42567d34a13c03968736c5d39bb4a97ce98188fafb27ce981115beec"}, 528 | {file = "regex-2021.11.10-cp37-cp37m-win_amd64.whl", hash = "sha256:07856afef5ffcc052e7eccf3213317fbb94e4a5cd8177a2caa69c980657b3cb4"}, 529 | {file = "regex-2021.11.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba05430e819e58544e840a68b03b28b6d328aff2e41579037e8bab7653b37d83"}, 530 | {file = "regex-2021.11.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7f301b11b9d214f83ddaf689181051e7f48905568b0c7017c04c06dfd065e244"}, 531 | {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aaa4e0705ef2b73dd8e36eeb4c868f80f8393f5f4d855e94025ce7ad8525f50"}, 532 | {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:788aef3549f1924d5c38263104dae7395bf020a42776d5ec5ea2b0d3d85d6646"}, 533 | {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8af619e3be812a2059b212064ea7a640aff0568d972cd1b9e920837469eb3cb"}, 534 | {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85bfa6a5413be0ee6c5c4a663668a2cad2cbecdee367630d097d7823041bdeec"}, 535 | {file = "regex-2021.11.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f23222527b307970e383433daec128d769ff778d9b29343fb3496472dc20dabe"}, 536 | {file = "regex-2021.11.10-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:da1a90c1ddb7531b1d5ff1e171b4ee61f6345119be7351104b67ff413843fe94"}, 537 | {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f5be7805e53dafe94d295399cfbe5227f39995a997f4fd8539bf3cbdc8f47ca8"}, 538 | {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a955b747d620a50408b7fdf948e04359d6e762ff8a85f5775d907ceced715129"}, 539 | {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:139a23d1f5d30db2cc6c7fd9c6d6497872a672db22c4ae1910be22d4f4b2068a"}, 540 | {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ca49e1ab99593438b204e00f3970e7a5f70d045267051dfa6b5f4304fcfa1dbf"}, 541 | {file = "regex-2021.11.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:96fc32c16ea6d60d3ca7f63397bff5c75c5a562f7db6dec7d412f7c4d2e78ec0"}, 542 | {file = "regex-2021.11.10-cp38-cp38-win32.whl", hash = "sha256:0617383e2fe465732af4509e61648b77cbe3aee68b6ac8c0b6fe934db90be5cc"}, 543 | {file = "regex-2021.11.10-cp38-cp38-win_amd64.whl", hash = "sha256:a3feefd5e95871872673b08636f96b61ebef62971eab044f5124fb4dea39919d"}, 544 | {file = "regex-2021.11.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7f325be2804246a75a4f45c72d4ce80d2443ab815063cdf70ee8fb2ca59ee1b"}, 545 | {file = "regex-2021.11.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:537ca6a3586931b16a85ac38c08cc48f10fc870a5b25e51794c74df843e9966d"}, 546 | {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eef2afb0fd1747f33f1ee3e209bce1ed582d1896b240ccc5e2697e3275f037c7"}, 547 | {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:432bd15d40ed835a51617521d60d0125867f7b88acf653e4ed994a1f8e4995dc"}, 548 | {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b43c2b8a330a490daaef5a47ab114935002b13b3f9dc5da56d5322ff218eeadb"}, 549 | {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:962b9a917dd7ceacbe5cd424556914cb0d636001e393b43dc886ba31d2a1e449"}, 550 | {file = "regex-2021.11.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa8c626d6441e2d04b6ee703ef2d1e17608ad44c7cb75258c09dd42bacdfc64b"}, 551 | {file = "regex-2021.11.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3c5fb32cc6077abad3bbf0323067636d93307c9fa93e072771cf9a64d1c0f3ef"}, 552 | {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cd410a1cbb2d297c67d8521759ab2ee3f1d66206d2e4328502a487589a2cb21b"}, 553 | {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e6096b0688e6e14af6a1b10eaad86b4ff17935c49aa774eac7c95a57a4e8c296"}, 554 | {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:529801a0d58809b60b3531ee804d3e3be4b412c94b5d267daa3de7fadef00f49"}, 555 | {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f594b96fe2e0821d026365f72ac7b4f0b487487fb3d4aaf10dd9d97d88a9737"}, 556 | {file = "regex-2021.11.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2409b5c9cef7054dde93a9803156b411b677affc84fca69e908b1cb2c540025d"}, 557 | {file = "regex-2021.11.10-cp39-cp39-win32.whl", hash = "sha256:3b5df18db1fccd66de15aa59c41e4f853b5df7550723d26aa6cb7f40e5d9da5a"}, 558 | {file = "regex-2021.11.10-cp39-cp39-win_amd64.whl", hash = "sha256:83ee89483672b11f8952b158640d0c0ff02dc43d9cb1b70c1564b49abe92ce29"}, 559 | {file = "regex-2021.11.10.tar.gz", hash = "sha256:f341ee2df0999bfdf7a95e448075effe0db212a59387de1a70690e4acb03d4c6"}, 560 | ] 561 | scandir = [ 562 | {file = "scandir-1.10.0-cp27-cp27m-win32.whl", hash = "sha256:92c85ac42f41ffdc35b6da57ed991575bdbe69db895507af88b9f499b701c188"}, 563 | {file = "scandir-1.10.0-cp27-cp27m-win_amd64.whl", hash = "sha256:cb925555f43060a1745d0a321cca94bcea927c50114b623d73179189a4e100ac"}, 564 | {file = "scandir-1.10.0-cp34-cp34m-win32.whl", hash = "sha256:2c712840c2e2ee8dfaf36034080108d30060d759c7b73a01a52251cc8989f11f"}, 565 | {file = "scandir-1.10.0-cp34-cp34m-win_amd64.whl", hash = "sha256:2586c94e907d99617887daed6c1d102b5ca28f1085f90446554abf1faf73123e"}, 566 | {file = "scandir-1.10.0-cp35-cp35m-win32.whl", hash = "sha256:2b8e3888b11abb2217a32af0766bc06b65cc4a928d8727828ee68af5a967fa6f"}, 567 | {file = "scandir-1.10.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8c5922863e44ffc00c5c693190648daa6d15e7c1207ed02d6f46a8dcc2869d32"}, 568 | {file = "scandir-1.10.0-cp36-cp36m-win32.whl", hash = "sha256:2ae41f43797ca0c11591c0c35f2f5875fa99f8797cb1a1fd440497ec0ae4b022"}, 569 | {file = "scandir-1.10.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7d2d7a06a252764061a020407b997dd036f7bd6a175a5ba2b345f0a357f0b3f4"}, 570 | {file = "scandir-1.10.0-cp37-cp37m-win32.whl", hash = "sha256:67f15b6f83e6507fdc6fca22fedf6ef8b334b399ca27c6b568cbfaa82a364173"}, 571 | {file = "scandir-1.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b24086f2375c4a094a6b51e78b4cf7ca16c721dcee2eddd7aa6494b42d6d519d"}, 572 | {file = "scandir-1.10.0.tar.gz", hash = "sha256:4d4631f6062e658e9007ab3149a9b914f3548cb38bfb021c64f39a025ce578ae"}, 573 | ] 574 | singledispatch = [ 575 | {file = "singledispatch-3.7.0-py2.py3-none-any.whl", hash = "sha256:bc77afa97c8a22596d6d4fc20f1b7bdd2b86edc2a65a4262bdd7cc3cc19aa989"}, 576 | {file = "singledispatch-3.7.0.tar.gz", hash = "sha256:c1a4d5c1da310c3fd8fccfb8d4e1cb7df076148fd5d858a819e37fffe44f3092"}, 577 | ] 578 | six = [ 579 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 580 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 581 | ] 582 | toml = [ 583 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 584 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 585 | ] 586 | typed-ast = [ 587 | {file = "typed_ast-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d8314c92414ce7481eee7ad42b353943679cf6f30237b5ecbf7d835519e1212"}, 588 | {file = "typed_ast-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b53ae5de5500529c76225d18eeb060efbcec90ad5e030713fe8dab0fb4531631"}, 589 | {file = "typed_ast-1.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:24058827d8f5d633f97223f5148a7d22628099a3d2efe06654ce872f46f07cdb"}, 590 | {file = "typed_ast-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:a6d495c1ef572519a7bac9534dbf6d94c40e5b6a608ef41136133377bba4aa08"}, 591 | {file = "typed_ast-1.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:de4ecae89c7d8b56169473e08f6bfd2df7f95015591f43126e4ea7865928677e"}, 592 | {file = "typed_ast-1.5.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:256115a5bc7ea9e665c6314ed6671ee2c08ca380f9d5f130bd4d2c1f5848d695"}, 593 | {file = "typed_ast-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:7c42707ab981b6cf4b73490c16e9d17fcd5227039720ca14abe415d39a173a30"}, 594 | {file = "typed_ast-1.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:71dcda943a471d826ea930dd449ac7e76db7be778fcd722deb63642bab32ea3f"}, 595 | {file = "typed_ast-1.5.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4f30a2bcd8e68adbb791ce1567fdb897357506f7ea6716f6bbdd3053ac4d9471"}, 596 | {file = "typed_ast-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ca9e8300d8ba0b66d140820cf463438c8e7b4cdc6fd710c059bfcfb1531d03fb"}, 597 | {file = "typed_ast-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9caaf2b440efb39ecbc45e2fabde809cbe56272719131a6318fd9bf08b58e2cb"}, 598 | {file = "typed_ast-1.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c9bcad65d66d594bffab8575f39420fe0ee96f66e23c4d927ebb4e24354ec1af"}, 599 | {file = "typed_ast-1.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:591bc04e507595887160ed7aa8d6785867fb86c5793911be79ccede61ae96f4d"}, 600 | {file = "typed_ast-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:a80d84f535642420dd17e16ae25bb46c7f4c16ee231105e7f3eb43976a89670a"}, 601 | {file = "typed_ast-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:38cf5c642fa808300bae1281460d4f9b7617cf864d4e383054a5ef336e344d32"}, 602 | {file = "typed_ast-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b6ab14c56bc9c7e3c30228a0a0b54b915b1579613f6e463ba6f4eb1382e7fd4"}, 603 | {file = "typed_ast-1.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2b8d7007f6280e36fa42652df47087ac7b0a7d7f09f9468f07792ba646aac2d"}, 604 | {file = "typed_ast-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:b6d17f37f6edd879141e64a5db17b67488cfeffeedad8c5cec0392305e9bc775"}, 605 | {file = "typed_ast-1.5.1.tar.gz", hash = "sha256:484137cab8ecf47e137260daa20bafbba5f4e3ec7fda1c1e69ab299b75fa81c5"}, 606 | ] 607 | typing = [ 608 | {file = "typing-3.10.0.0-py2-none-any.whl", hash = "sha256:c7219ef20c5fbf413b4567092adfc46fa6203cb8454eda33c3fc1afe1398a308"}, 609 | {file = "typing-3.10.0.0-py3-none-any.whl", hash = "sha256:12fbdfbe7d6cca1a42e485229afcb0b0c8259258cfb919b8a5e2a5c953742f89"}, 610 | {file = "typing-3.10.0.0.tar.gz", hash = "sha256:13b4ad211f54ddbf93e5901a9967b1e07720c1d1b78d596ac6a439641aa1b130"}, 611 | ] 612 | typing-extensions = [ 613 | {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, 614 | {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, 615 | ] 616 | zipp = [ 617 | {file = "zipp-1.2.0-py2.py3-none-any.whl", hash = "sha256:e0d9e63797e483a30d27e09fffd308c59a700d365ec34e93cc100844168bf921"}, 618 | {file = "zipp-1.2.0.tar.gz", hash = "sha256:c70410551488251b0fee67b460fb9a536af8d6f9f008ad10ac51f615b6a521b1"}, 619 | ] 620 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "ranger-tmux" 3 | version = "1.0.8" 4 | description = "Tmux integration for ranger" 5 | authors = ["Josiah Outram Halstead "] 6 | license = "MIT" 7 | readme = "README.md" 8 | homepage = "https://github.com/joouha/ranger_tmux" 9 | classifiers = [ 10 | "Environment :: Plugins", 11 | ] 12 | 13 | [tool.poetry.dependencies] 14 | python = ">=2.7 <3 || >=3.6" 15 | ranger-fm = "^1.9.3" 16 | psutil = "^5.8.0" 17 | pathlib2 = {version = "^2.3.6", python = ">2.7 <3"} 18 | importlib-resources = {version = ">=3.3.1", python = ">=2.7,<3.9"} 19 | importlib-metadata = {version = ">=2.1.2", python = ">=2.7,<3.8"} 20 | 21 | [tool.poetry.dev-dependencies] 22 | flake8 = "^3.9.2" 23 | black = {version = "^20.8b1", python = ">=3.6"} 24 | flake8-black = "^0.2.3" 25 | isort = ">=4.3.21" 26 | 27 | [build-system] 28 | requires = ["poetry-core>=1.0.0"] 29 | build-backend = "poetry.core.masonry.api" 30 | 31 | [tool.poetry.plugins."ranger.plugins"] 32 | "ranger_tmux" = "ranger_tmux.plugin" 33 | -------------------------------------------------------------------------------- /ranger_tmux/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """A tmux plugin for ranger, and ranger integration for tmux.""" 3 | __version__ = "1.0.8" 4 | -------------------------------------------------------------------------------- /ranger_tmux/__main__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import print_function 3 | 4 | import argparse 5 | import os 6 | import sys 7 | 8 | try: 9 | from pathlib import Path 10 | except ImportError: 11 | from pathlib2 import Path 12 | 13 | try: 14 | import importlib_resources 15 | except ImportError: 16 | import importlib.resources as importlib_resources 17 | 18 | TMUX_CONFIG = [ 19 | ["#-#-#", "start_of_ranger_tmux_config", "#-#-#"], 20 | [ 21 | "bind-key", 22 | "Bspace", 23 | "run-shell", 24 | "-b", 25 | "{} -m ranger_tmux.drop".format(sys.executable), 26 | ], 27 | # [ 28 | # "bind-key", 29 | # "Tab", 30 | # "split-pane", 31 | # "-hbf", 32 | # "-l", 33 | # "30", 34 | # f"{util.get_ranger_script()}" 35 | # ' --cmd="set tmux_cwd_track True"' 36 | # ' --cmd="set viewmode multipane"' 37 | # " --cmd=tmux_cwd_track_now", 38 | # ], 39 | ["#-#-#", "end_of_ranger_tmux_config", "#-#-#"], 40 | ] 41 | 42 | 43 | def tmux_keybindings(install=True): 44 | 45 | tmux_user_config_path = Path.home() / ".tmux.conf" 46 | tmux_config_lines = [ 47 | " ".join( 48 | [ 49 | # Quote command components if they contain spaces 50 | ("'{}'".format(cmd) if " " in cmd else str(cmd)) 51 | for cmd in line 52 | ] 53 | ) 54 | for line in TMUX_CONFIG 55 | ] 56 | new_lines = [] 57 | if tmux_user_config_path.exists(): 58 | # Read existing lines 59 | with open(str(tmux_user_config_path), "r") as f: 60 | old_lines = [x.strip() for x in f.readlines()] 61 | # Search for tmux_ranger config in tmux config 62 | start_line = len(old_lines) + 1 63 | for i, line in enumerate(old_lines): 64 | if line == tmux_config_lines[0]: 65 | start_line = i 66 | break 67 | end_line = start_line 68 | for i in range(start_line, len(old_lines)): 69 | if old_lines[i] == tmux_config_lines[-1]: 70 | end_line = i 71 | break 72 | # Merge in the new config 73 | new_lines += old_lines[:start_line] 74 | if install: 75 | new_lines += tmux_config_lines 76 | new_lines += old_lines[end_line + 1 :] 77 | else: 78 | # No config at all, just use ours 79 | new_lines += tmux_config_lines 80 | 81 | # Write the updated tmux configuration file 82 | with open(str(tmux_user_config_path), "w") as f: 83 | f.write("\n".join(new_lines) + "\n") 84 | 85 | return TMUX_CONFIG[1:-1] 86 | 87 | 88 | def confirm_choice(query, options=("y", "n")): 89 | while True: 90 | confirm = input("{} ({})\n".format(query, "/".join(options))) 91 | if confirm.lower() in options: 92 | return confirm 93 | else: 94 | print("Invalid Option. Please Enter a Valid Option.") 95 | 96 | 97 | def install(args): 98 | print("Installing ranger_tmux plugin") 99 | print("- Plugin installation located at `{}`".format(args.plugin_script_path)) 100 | if args.ranger_plugin_path.exists(): 101 | print("- Removing existing symlink") 102 | if args.ranger_plugin_path.exists(): 103 | args.ranger_plugin_path.unlink() 104 | print("- Creating symlink at `{}`".format(args.ranger_plugin_path)) 105 | args.plugin_script_path.parent.mkdir(parents=True, exist_ok=True) 106 | args.ranger_plugin_path.symlink_to(args.plugin_script_path) 107 | 108 | if args.tmux is None: 109 | tmux = ( 110 | confirm_choice( 111 | "Do you want to install a key-binding for" 112 | " drop-down ranger in `~/.tmux.conf`?", 113 | ("y", "n"), 114 | ) 115 | == "y" 116 | ) 117 | else: 118 | tmux = args.tmux 119 | if tmux: 120 | print("Installing tmux key-bindings") 121 | tmux_keybindings(install=True) 122 | 123 | print("Installation complete") 124 | 125 | 126 | def uninstall(args): 127 | print("Uninstalling ranger_tmux plugin") 128 | if args.ranger_plugin_path.exists(): 129 | print("- Removing existing symlink `{}`".format(args.ranger_plugin_path)) 130 | if args.ranger_plugin_path.exists(): 131 | args.ranger_plugin_path.unlink() 132 | 133 | if args.tmux: 134 | print("Uninstalling tmux key-bindings") 135 | tmux_keybindings(install=False) 136 | 137 | print("Uninstallation complete") 138 | 139 | 140 | def reinstall(args): 141 | uninstall(args) 142 | install(args) 143 | 144 | 145 | def main(): 146 | parser = argparse.ArgumentParser(description="Install ranger_tmux plugin") 147 | parser.add_argument( 148 | "--tmux", 149 | default=True, 150 | action="store_true", 151 | help="Install/uninstall key-bindings for tmux", 152 | ) 153 | parser.add_argument( 154 | "--no-tmux", 155 | dest="tmux", 156 | action="store_false", 157 | help="Install/uninstall key-bindings for tmux", 158 | ) 159 | subparsers = parser.add_subparsers( 160 | help="Command to run", dest="command" # , required=True 161 | ) 162 | parser_install = subparsers.add_parser("install", help="Install plugin") 163 | parser_install.set_defaults(func=install) 164 | parser_uninstall = subparsers.add_parser("uninstall", help="Unnstall plugin") 165 | parser_uninstall.set_defaults(func=uninstall) 166 | parser_reinstall = subparsers.add_parser("reinstall", help="Re-install plugin") 167 | parser_reinstall.set_defaults(func=reinstall) 168 | 169 | parser.add_argument( 170 | "--plugin_script_path", 171 | help=argparse.SUPPRESS, 172 | default=importlib_resources.files("ranger_tmux").joinpath("plugin.py"), 173 | ) 174 | parser.add_argument( 175 | "--ranger_plugin_path", 176 | help=argparse.SUPPRESS, 177 | default=Path( 178 | os.environ.get( 179 | "XDG_CONFIG_HOME", 180 | Path.home() / ".config", 181 | ) 182 | ) 183 | / "ranger" 184 | / "plugins" 185 | / "ranger_tmux.py", 186 | ) 187 | 188 | args = parser.parse_args() 189 | args.func(args) 190 | 191 | 192 | if __name__ == "__main__": 193 | main() 194 | -------------------------------------------------------------------------------- /ranger_tmux/cwd_sync.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Add options and commands for syncing panes to ranger's current working directory.""" 3 | 4 | from ranger.api.commands import Command 5 | 6 | from . import util 7 | 8 | SETTINGS = { 9 | "tmux_cwd_sync": {"key": "s", "type": bool}, 10 | "tmux_cwd_sync_now_focus": {"type": bool}, 11 | } 12 | 13 | 14 | class tmux_cwd_sync_now(Command): 15 | """Sync working directory of the "other" pane to match ranger's.""" 16 | 17 | ranger_pane = None 18 | 19 | def execute(self): 20 | """Executes the command.""" 21 | if self.ranger_pane: 22 | pane_id = util.select_shell_pane(self.ranger_pane) 23 | if pane_id: 24 | util.cd_pane(self.fm.thisdir.path, pane_id) 25 | if self.fm.settings.get("tmux_cwd_sync_now_focus", False): 26 | util.tmux("select-pane", "-t", pane_id) 27 | 28 | 29 | def tmux_cwd_sync_init(fm, setting, *args): 30 | """Allows ranger to sync it's cwd to the other tmux pane.""" 31 | fm.execute_console('map xc eval fm.execute_console("tmux_cwd_sync_now")') 32 | 33 | # Find pane with current instance of ranger in it 34 | ranger_pane = util.get_ranger_pane() 35 | tmux_cwd_sync_now.ranger_pane = ranger_pane 36 | 37 | non_local = {"cd_signal_handler": None} 38 | 39 | def cd_hook(signal): 40 | if "new" in signal: 41 | pane_id = util.select_shell_pane(ranger_pane) 42 | if pane_id: 43 | util.cd_pane(signal.new, pane_id) 44 | 45 | def setting_signal_handler(signal): 46 | if signal.value: 47 | non_local["cd_signal_handler"] = fm.signal_bind("cd", cd_hook) 48 | else: 49 | if non_local["cd_signal_handler"]: 50 | fm.signal_unbind(non_local["cd_signal_handler"]) 51 | 52 | fm.settings.signal_bind("setopt.{}".format(setting), setting_signal_handler) 53 | 54 | if fm.settings.__getitem__(setting): 55 | non_local["cd_signal_handler"] = fm.signal_bind("cd", cd_hook) 56 | -------------------------------------------------------------------------------- /ranger_tmux/cwd_track.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import time 3 | from threading import Thread 4 | 5 | from ranger.api.commands import Command 6 | 7 | from . import util 8 | 9 | SETTINGS = { 10 | "tmux_cwd_track": {"key": "t", "type": bool}, 11 | "tmux_cwd_track_interval": {"type": float, "default": 0.5}, 12 | } 13 | 14 | 15 | class tmux_cwd_track_now(Command): 16 | ranger_pane = None 17 | 18 | def execute(self): 19 | if self.ranger_pane: 20 | pane_id = util.select_shell_pane(self.ranger_pane) 21 | if pane_id: 22 | new_path = util.tmux( 23 | "display", "-p", "-t", pane_id, "-F", "#{pane_current_path}" 24 | ) 25 | if new_path != self.fm.thisdir.path: 26 | self.fm.cd(new_path) 27 | 28 | 29 | class MonitorPane(Thread): 30 | def __init__(self, fm, ranger_pane): 31 | Thread.__init__(self) 32 | self.daemon = True 33 | self.stopped = False 34 | self.fm = fm 35 | self.last_path = None 36 | self.ranger_pane = ranger_pane 37 | self.start() 38 | 39 | def run(self): 40 | while not self.stopped: 41 | pane_id = util.select_shell_pane(self.ranger_pane) 42 | if pane_id: 43 | new_path = util.tmux( 44 | "display", "-p", "-t", pane_id, "-F", "#{pane_current_path}" 45 | ) 46 | if self.last_path != new_path and new_path != self.fm.thisdir.path: 47 | self.fm.cd(new_path) 48 | self.last_path = new_path 49 | time.sleep(self.fm.settings.get("tmux_cwd_track_interval", 1)) 50 | 51 | 52 | def tmux_cwd_track_init(fm, setting, *args): 53 | """""" 54 | 55 | fm.execute_console('map xd eval fm.execute_console("tmux_cwd_track_now")') 56 | 57 | # Find pane with current instance of ranger in it 58 | ranger_pane = util.get_ranger_pane() 59 | tmux_cwd_track_now.ranger_pane = ranger_pane 60 | 61 | non_local = {"pane_monitor_thread": None} 62 | 63 | def enable(): 64 | non_local["pane_monitor_thread"] = MonitorPane(fm, ranger_pane) 65 | 66 | def disable(): 67 | if non_local["pane_monitor_thread"]: 68 | non_local["pane_monitor_thread"].stopped = True 69 | 70 | def setting_signal_handler(signal): 71 | if signal.value: 72 | enable() 73 | else: 74 | disable() 75 | 76 | fm.settings.signal_bind("setopt.{}".format(setting), setting_signal_handler) 77 | 78 | if fm.settings.__getitem__(setting): 79 | enable() 80 | -------------------------------------------------------------------------------- /ranger_tmux/drop.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Performs the drop-down action in tmux. 3 | 4 | Intended to be triggered by a keyboard-shortcut in tmux. 5 | """ 6 | import signal 7 | import sys 8 | import time 9 | 10 | import psutil 11 | import ranger 12 | from ranger.container.settings import Settings 13 | from ranger.core.fm import FM 14 | from ranger.core.main import parse_arguments 15 | from ranger.core.shared import FileManagerAware, SettingsAware 16 | 17 | from ranger_tmux import util 18 | 19 | 20 | def animated_resize(pane_id, target_perc, duration=200): 21 | """Animates the resizing a tmux pane.""" 22 | pane_height = int(util.tmux("display", "-t", "{top}", "-p", "#{pane_height}")) 23 | window_height = int(util.tmux("display", "-p", "#{window_height}")) 24 | target_height = int(target_perc / 100 * window_height) 25 | direction = pane_height < target_height 26 | lines = int(duration < 500) + 1 27 | frames = max(1, abs(pane_height - target_height) // lines - 1) 28 | timeout = duration / 1000 / frames 29 | for _ in range(frames): 30 | util.tmux("resize-pane", "-D" if direction else "-U", "-t", pane_id, lines) 31 | time.sleep(timeout) 32 | util.tmux("resize-pane", "-t", pane_id, "-y", f"{target_perc}%") 33 | 34 | 35 | def main(): 36 | """Launches ranger in a new pane, optionally driving pane animation.""" 37 | ranger_script_path = util.get_ranger_script() 38 | 39 | # Initiate ranger just enough to allow us to access the settings 40 | ranger.args = parse_arguments() 41 | fm = FM() 42 | SettingsAware.settings_set(Settings()) 43 | FileManagerAware.fm_set(fm) 44 | ranger.core.main.load_settings(fm, clean=False) 45 | 46 | # Check we're actually in tmux 47 | if not util.check_tmux(fm): 48 | sys.exit() 49 | 50 | # Check if we need to animate the drop 51 | animate = fm.settings.get("tmux_dropdown_animate") 52 | duration = fm.settings.get("tmux_dropdown_duration") 53 | 54 | pane_id, command, pid = util.tmux( 55 | "display", "-t", "{top}", "-p", "#{pane_id}|#{pane_start_command}|#{pane_pid}" 56 | ).split("|") 57 | 58 | # Ranger is open - we will close it 59 | if command == f"{sys.executable} {ranger_script_path} -- .": 60 | # Animate close if wanted 61 | if animate: 62 | animated_resize(pane_id, 0, duration) 63 | # Get a handel on ranger 64 | process = psutil.Process(int(pid)) 65 | # Send interupt to ranger to cancel any unfinished command entry 66 | process.send_signal(signal.SIGINT) 67 | # Ask ranger to quit nicely 68 | util.tmux("send-keys", "-t", pane_id, "Q") 69 | # Give range half a second to quit before vicously killing it 70 | dead, alive = psutil.wait_procs([process], timeout=0.5) 71 | for p in alive: 72 | p.kill() 73 | 74 | # Ranger is not open - we will open it 75 | else: 76 | # Load ranger pane height from ranger settings 77 | percent = fm.settings.get("tmux_dropdown_percent") 78 | # Make initial size smaller if we're going to animate 79 | initial_size = "1" if animate else f"{percent}%" 80 | # Get other pane folder 81 | pane_dir = util.tmux( 82 | "display-message", "-p", "-t", pane_id, "#{pane_current_path}" 83 | ) 84 | # Create a new ranger pane 85 | pane_id = util.tmux( 86 | "split-window", 87 | "-bfv", 88 | "-F", 89 | "#{pane_id}", 90 | "-c", 91 | pane_dir, 92 | "-t", 93 | "{top}", 94 | "-l", 95 | initial_size, 96 | sys.executable, 97 | ranger_script_path, 98 | "--", 99 | ".", 100 | ) 101 | # Animate open if wanted 102 | if animate: 103 | animated_resize(pane_id, percent, duration) 104 | 105 | 106 | if __name__ == "__main__": 107 | main() 108 | -------------------------------------------------------------------------------- /ranger_tmux/dropdown.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from ranger.api.commands import Command 3 | 4 | from ranger_tmux.__main__ import tmux_keybindings 5 | 6 | from . import util 7 | 8 | SETTINGS = { 9 | "tmux_dropdown_percent": {"type": int, "default": 60}, 10 | "tmux_dropdown_animate": {"type": bool, "default": True}, 11 | "tmux_dropdown_duration": {"type": int, "default": 100}, 12 | } 13 | 14 | 15 | class install_tmux_dropdown_shortcut(Command): 16 | def execute(self): 17 | def callback(answer): 18 | if answer == "y": 19 | tmux_cmds = tmux_keybindings(install=True) 20 | # Add shortcut to current session 21 | for cmd in tmux_cmds: 22 | util.tmux(*cmd) 23 | util.tmux("display", "Tmux shortcut for drop-down ranger installed") 24 | 25 | self.fm.ui.console.ask( 26 | "Are you sure you want to install the drop-down ranger key-binding in" 27 | " ~/.tmux.conf? (y/n)", 28 | callback, 29 | "yn", 30 | ) 31 | 32 | 33 | def init(fm, *args): 34 | fm.execute_console( 35 | 'map xh eval fm.execute_console("install_tmux_dropdown_shortcut")' 36 | ) 37 | -------------------------------------------------------------------------------- /ranger_tmux/open_in_window.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import ranger.api 3 | 4 | HOOK_INIT_OLD = ranger.api.hook_init 5 | 6 | SETTINGS = {"tmux_open_in_window": {"key": "w", "type": bool, "default": True}} 7 | 8 | 9 | def tmux_open_in_window_init(fm, setting, *args): 10 | """Monkey-patch rifle's preprocessing function. 11 | 12 | This re-writes rifle commands, causing them to run in a new tmux window. 13 | 14 | """ 15 | 16 | # Add shortcuts to open selected file in new window / pane 17 | fm.execute_console('map xo shell tmux new-window -a "rifle %f"') 18 | fm.execute_console('map xl shell tmux split-pane -h "rifle %f"') 19 | fm.execute_console('map xp shell tmux split-pane -v "rifle %f"') 20 | 21 | # Hook rifle's post-processing command 22 | old_postprocessing_command = fm.rifle.hook_command_postprocessing 23 | 24 | def new_postprocessing_command(command): 25 | if fm.settings.__getitem__(setting): 26 | command = command.replace('"', r"\"").replace("$", r"\$") 27 | command = 'tmux new-window -a "{}"'.format(command) 28 | return old_postprocessing_command(command) 29 | 30 | fm.rifle.hook_command_postprocessing = new_postprocessing_command 31 | -------------------------------------------------------------------------------- /ranger_tmux/plugin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import ranger.api 3 | from ranger.container.settings import ( 4 | ALLOWED_SETTINGS, 5 | SIGNAL_PRIORITY_SANITIZE, 6 | SIGNAL_PRIORITY_SYNC, 7 | ) 8 | 9 | from ranger_tmux import ( 10 | cwd_sync, 11 | cwd_track, 12 | dropdown, 13 | open_in_window, 14 | set_window_name, 15 | splits, 16 | util, 17 | ) 18 | from ranger_tmux.cwd_sync import tmux_cwd_sync_now # noqa F401 19 | from ranger_tmux.cwd_track import tmux_cwd_track_now # noqa F401 20 | from ranger_tmux.dropdown import install_tmux_dropdown_shortcut # noqa F401 21 | 22 | MODULES = [open_in_window, set_window_name, cwd_sync, cwd_track, dropdown, splits] 23 | 24 | HOOK_INIT_OLD = ranger.api.hook_init 25 | 26 | 27 | # Add settings to ranger when plugin is loaded 28 | # Adding these at import means the plugin's settings are available to ranger 29 | for mod in MODULES: 30 | if hasattr(mod, "SETTINGS"): 31 | for setting, info in mod.SETTINGS.items(): 32 | ALLOWED_SETTINGS[setting] = info.get("type", bool) 33 | value = info.get("default") 34 | if value: 35 | ranger.fm.settings._raw_set(setting, value) 36 | ranger.fm.settings.signal_bind( 37 | "setopt.{}".format(setting), 38 | ranger.fm.settings._sanitize, 39 | priority=SIGNAL_PRIORITY_SANITIZE, 40 | ) 41 | ranger.fm.settings.signal_bind( 42 | "setopt.{}".format(setting), 43 | ranger.fm.settings._raw_set_with_signal, 44 | priority=SIGNAL_PRIORITY_SYNC, 45 | ) 46 | 47 | 48 | def hook_init(fm): 49 | 50 | # Add ranger_tmux hooks if we are in a tmux session 51 | if util.check_tmux(fm): 52 | 53 | # Load all modules 54 | for mod in MODULES: 55 | # Add key-bindings for module 56 | if hasattr(mod, "SETTINGS"): 57 | for setting, info in mod.SETTINGS.items(): 58 | if hasattr(mod, "{}_init".format(setting)): 59 | getattr(mod, "{}_init".format(setting))(fm, setting, MODULES) 60 | key = info.get("key") 61 | if key: 62 | fm.execute_console("map x{} set {}!".format(key, setting)) 63 | if hasattr(mod, "init"): 64 | mod.init(fm, MODULES) 65 | 66 | return HOOK_INIT_OLD(fm) 67 | 68 | 69 | ranger.api.hook_init = hook_init 70 | -------------------------------------------------------------------------------- /ranger_tmux/set_window_name.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import atexit 3 | 4 | from . import util 5 | 6 | SETTINGS = {"tmux_set_title": {"key": "i", "type": bool, "default": True}} 7 | 8 | 9 | def set_tmux_window_title(msg): 10 | """Set tmux's window format""" 11 | util.tmux("set-option", "-p", "automatic-rename-format", msg) 12 | 13 | 14 | def tmux_set_title_init(fm, setting, *args): 15 | 16 | # Save tmux's original title format 17 | original_format = util.tmux("show-options", "-gv", "automatic-rename-format") 18 | 19 | def enable(): 20 | # Set window name to "ranger" on this panel 21 | set_tmux_window_title("ranger") 22 | # Reset title at exit 23 | atexit.register(disable) 24 | 25 | def disable(): 26 | set_tmux_window_title(original_format) 27 | if hasattr(atexit, "unregister"): 28 | atexit.unregister(disable) 29 | else: 30 | # Python 2 version of above 31 | for i, handler in enumerate(atexit._exithandlers): 32 | if handler == (disable, (), {}): 33 | del atexit._exithandlers[i] 34 | 35 | def setting_signal_handler(signal): 36 | if signal.value: 37 | enable() 38 | else: 39 | disable() 40 | 41 | setting = list(SETTINGS.keys())[0] 42 | fm.settings.signal_bind("setopt.{}".format(setting), setting_signal_handler) 43 | 44 | if fm.settings.__getitem__(setting): 45 | enable() 46 | -------------------------------------------------------------------------------- /ranger_tmux/splits.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | def init(fm, *args): 5 | """Extra tmux key-bindings to splt tmux windows.""" 6 | fm.execute_console("map x- shell tmux split-window -v -c %d") 7 | fm.execute_console("map x| shell tmux split-window -h -c %d") 8 | -------------------------------------------------------------------------------- /ranger_tmux/util.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | import shutil 4 | import signal 5 | from subprocess import CalledProcessError, check_output 6 | 7 | try: 8 | import importlib_metadata 9 | except ImportError: 10 | import importlib.metadata as importlib_metadata 11 | 12 | 13 | def get_ranger_script(): 14 | scripts = importlib_metadata.files("ranger-fm") 15 | if scripts is not None: 16 | ranger_script_paths = [path for path in scripts if path.name == "ranger"] 17 | if ranger_script_paths: 18 | return ranger_script_paths[0].locate().resolve() 19 | return shutil.which("ranger") 20 | 21 | 22 | def check_tmux(fm): 23 | # TODO chcek tmux is in path too 24 | tmuxed = os.environ.get("TMUX") 25 | if not tmuxed: 26 | fm.notify("Not running in tmux session, ranger_tmux is disabled") 27 | return tmuxed 28 | 29 | 30 | def tmux(*args): 31 | try: 32 | return check_output(["tmux"] + list(map(str, args))).decode("utf8").strip() 33 | except CalledProcessError: 34 | return 35 | 36 | 37 | def get_ranger_pane(): 38 | import psutil 39 | 40 | # Find pane with current instance of ranger in 41 | ranger_pid = os.getpid() 42 | panes = tmux("list-panes", "-aF", "#{pane_pid},#{pane_id}") 43 | if panes: 44 | panes = { 45 | int(pid): pane_id.strip() 46 | for pid, pane_id in [info.split(",") for info in panes.split("\n")] 47 | } 48 | for pid, pane_id in panes.items(): 49 | if ranger_pid == pid or ranger_pid in [ 50 | x.pid for x in psutil.Process(pid).children(recursive=True) 51 | ]: 52 | return pane_id 53 | 54 | 55 | def select_shell_pane(ranger_pane): 56 | 57 | # Panes can move windows, so check this every time 58 | ranger_window = tmux("display", "-t", ranger_pane, "-p", "#{window_id}") 59 | 60 | # Get all panes in this window 61 | window_panes = tmux("list-panes", "-F", "#{pane_id}", "-t", ranger_window).split( 62 | "\n" 63 | ) 64 | other_panes = set(window_panes) - set(ranger_pane) 65 | 66 | if not other_panes: 67 | return 68 | 69 | # Check for a marked pane in this window 70 | marks = tmux("display", "-p", "-F", "#{window_flags}", "-t", ranger_pane) 71 | has_marked_pane = "M" in marks # marks' values can be `#!~*-MZ` 72 | if has_marked_pane: 73 | pane = tmux("display", "-p", "-t", "{marked}", "#{pane_id}") 74 | if pane in other_panes and pane != ranger_pane: 75 | return pane 76 | 77 | pane = tmux("display", "-p", "#{pane_id}") 78 | if pane in other_panes and pane != ranger_pane: 79 | return pane 80 | 81 | pane = tmux("display", "-p", "-t", "{last}", "#{pane_id}") 82 | if pane in other_panes and pane != ranger_pane: 83 | return pane 84 | 85 | pane = tmux("display", "-p", "-t", "{next}", "#{pane_id}") 86 | if pane in other_panes and pane != ranger_pane: 87 | return pane 88 | 89 | if other_panes: 90 | return list(sorted(other_panes))[0] 91 | 92 | 93 | def cd_pane(path, pane_id): 94 | import psutil 95 | 96 | pane_process = psutil.Process( 97 | int(tmux("display", "-p", "-t", pane_id, "-F", "#{pane_pid}")) 98 | ) 99 | with pane_process.oneshot(): 100 | if not pane_process.children(): 101 | if pane_process.cwd() != str(path): 102 | pane_process.send_signal(signal.SIGINT) 103 | tmux("send-keys", "-t", pane_id, ' cd "{}"'.format(path), "Enter") 104 | -------------------------------------------------------------------------------- /scripts/publish.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Publishes a new releases of ranger-tmux.""" 3 | from pathlib import Path 4 | 5 | from poetry_publish.publish import poetry_publish # type: ignore 6 | 7 | import ranger_tmux 8 | 9 | 10 | def publish() -> "None": 11 | """Publishes a new releasse of euporie to pypi.org.""" 12 | poetry_publish( 13 | package_root=Path(ranger_tmux.__file__).parent.parent, 14 | version=ranger_tmux.__version__, 15 | ) 16 | 17 | 18 | if __name__ == "__main__": 19 | publish() 20 | --------------------------------------------------------------------------------