diff options
-rw-r--r-- | .github/workflows/pylint.yml | 2 | ||||
-rw-r--r-- | .github/workflows/python.yml | 4 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | doc/ranger.1 | 13 | ||||
-rw-r--r-- | doc/ranger.pod | 15 | ||||
-rw-r--r-- | ranger/core/runner.py | 6 | ||||
-rwxr-xr-x | ranger/data/scope.sh | 40 | ||||
-rw-r--r-- | ranger/ext/accumulator.py | 6 | ||||
-rw-r--r-- | ranger/gui/colorscheme.py | 5 | ||||
-rw-r--r-- | ranger/gui/widgets/browsercolumn.py | 41 | ||||
-rw-r--r-- | requirements.txt | 2 | ||||
-rw-r--r-- | tests/pylint/test_py2_compat.py | 6 |
13 files changed, 108 insertions, 39 deletions
diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index c15f8f64..474b087f 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -5,10 +5,12 @@ on: paths: - '.github/workflows/pylint.yml' - '**.py' + - 'requirements.txt' pull_request: paths: - '.github/workflows/pylint.yml' - '**.py' + - 'requirements.txt' jobs: test_pylint: diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index dc41318e..fe2c7e59 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -28,7 +28,9 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r requirements.txt + # We need to ignore PyLint because we can't install the one we need for + # Python 2.7 and 3.5 + pip install -r <(grep -v pylint requirements.txt) - name: Flake8 and test run: | make test_flake8 test_doctest test_other diff --git a/Makefile b/Makefile index 3479bb2d..568ebd42 100644 --- a/Makefile +++ b/Makefile @@ -135,13 +135,13 @@ test_other: test: test_py test_shellcheck @echo "$(bold)Finished testing: All tests passed!$(normal)" -doc/ranger.1: doc/ranger.pod README.md +doc/ranger.1: doc/ranger.pod pod2man --stderr --center='ranger manual' \ --date='$(NAME)-$(VERSION)' \ --release=$(shell date -u '+%Y-%m-%d') \ doc/ranger.pod doc/ranger.1 -doc/rifle.1: doc/rifle.pod README.md +doc/rifle.1: doc/rifle.pod pod2man --stderr --center='rifle manual' \ --date='$(NAME_RIFLE)-$(VERSION_RIFLE)' \ --release=$(shell date -u '+%Y-%m-%d') \ diff --git a/README.md b/README.md index 10bdcfb5..6598b655 100644 --- a/README.md +++ b/README.md @@ -106,8 +106,11 @@ For enhanced file previews (with `scope.sh`): * `mediainfo` or `exiftool` for viewing information about media files * `odt2txt` for OpenDocument text files (`odt`, `ods`, `odp` and `sxw`) * `python` or `jq` for JSON files +* `jupyter nbconvert` for Jupyter Notebooks * `fontimage` for font previews * `openscad` for 3D model previews (`stl`, `off`, `dxf`, `scad`, `csg`) +* `draw.io` for [draw.io](https://app.diagrams.net/) diagram previews + (`drawio` extension) Installing ---------- diff --git a/doc/ranger.1 b/doc/ranger.1 index 22c2adc6..cc166604 100644 --- a/doc/ranger.1 +++ b/doc/ranger.1 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "RANGER 1" -.TH RANGER 1 "ranger-1.9.3" "2022-02-27" "ranger manual" +.TH RANGER 1 "ranger-1.9.3" "2022-03-18" "ranger manual" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -318,11 +318,13 @@ are automatically used when available but completely optional. .IP "\-" 2 \&\f(CW\*(C`atool\*(C'\fR, \f(CW\*(C`bsdtar\*(C'\fR, \f(CW\*(C`unrar\*(C'\fR and/or \f(CW\*(C`7z\*(C'\fR to preview archives .IP "\-" 2 -\&\f(CW\*(C`bsdtar\*(C'\fR, \f(CW\*(C`tar\*(C'\fR, \f(CW\*(C`unrar\*(C'\fR, \f(CW\*(C`unzip\*(C'\fR and/or \f(CW\*(C`zipinfo\*(C'\fR (and \f(CW\*(C`sed\*(C'\fR) to preview archives as their first image +\&\f(CW\*(C`bsdtar\*(C'\fR, \f(CW\*(C`tar\*(C'\fR, \f(CW\*(C`unrar\*(C'\fR, \f(CW\*(C`unzip\*(C'\fR and/or \f(CW\*(C`zipinfo\*(C'\fR (and \f(CW\*(C`sed\*(C'\fR) to preview +archives as their first image .IP "\-" 2 \&\f(CW\*(C`lynx\*(C'\fR, \f(CW\*(C`w3m\*(C'\fR or \f(CW\*(C`elinks\*(C'\fR to preview html pages .IP "\-" 2 -\&\f(CW\*(C`pdftotext\*(C'\fR or \f(CW\*(C`mutool\*(C'\fR (and \f(CW\*(C`fmt\*(C'\fR) for textual pdf previews, \f(CW\*(C`pdftoppm\*(C'\fR to preview as image +\&\f(CW\*(C`pdftotext\*(C'\fR or \f(CW\*(C`mutool\*(C'\fR (and \f(CW\*(C`fmt\*(C'\fR) for textual pdf previews, \f(CW\*(C`pdftoppm\*(C'\fR to +preview as image .IP "\-" 2 \&\f(CW\*(C`djvutxt\*(C'\fR for textual DjVu previews, \f(CW\*(C`ddjvu\*(C'\fR to preview as image .IP "\-" 2 @@ -337,6 +339,11 @@ are automatically used when available but completely optional. \&\f(CW\*(C`python\*(C'\fR or \f(CW\*(C`jq\*(C'\fR for \s-1JSON\s0 files .IP "\-" 2 \&\f(CW\*(C`fontimage\*(C'\fR for font previews +.IP "\-" 2 +\&\f(CW\*(C`openscad\*(C'\fR for 3D model previews (stl, off, dxf, scad, csg) +.IP "\-" 2 +\&\f(CW\*(C`draw.io\*(C'\fR for draw.io <https://app.diagrams.net/> diagram previews (drawio +extension) .RE .RS 2 .RE diff --git a/doc/ranger.pod b/doc/ranger.pod index bc9f8e21..f3413856 100644 --- a/doc/ranger.pod +++ b/doc/ranger.pod @@ -254,7 +254,8 @@ C<atool>, C<bsdtar>, C<unrar> and/or C<7z> to preview archives =item - -C<bsdtar>, C<tar>, C<unrar>, C<unzip> and/or C<zipinfo> (and C<sed>) to preview archives as their first image +C<bsdtar>, C<tar>, C<unrar>, C<unzip> and/or C<zipinfo> (and C<sed>) to preview +archives as their first image =item - @@ -262,7 +263,8 @@ C<lynx>, C<w3m> or C<elinks> to preview html pages =item - -C<pdftotext> or C<mutool> (and C<fmt>) for textual pdf previews, C<pdftoppm> to preview as image +C<pdftotext> or C<mutool> (and C<fmt>) for textual pdf previews, C<pdftoppm> to +preview as image =item - @@ -292,6 +294,15 @@ C<python> or C<jq> for JSON files C<fontimage> for font previews +=item - + +C<openscad> for 3D model previews (stl, off, dxf, scad, csg) + +=item - + +C<draw.io> for draw.io L<https://app.diagrams.net/> diagram previews (drawio +extension) + =back =back diff --git a/ranger/core/runner.py b/ranger/core/runner.py index 1d2b91f7..c5ec697b 100644 --- a/ranger/core/runner.py +++ b/ranger/core/runner.py @@ -235,9 +235,11 @@ class Runner(object): # pylint: disable=too-few-public-methods if toggle_ui: self._activate_ui(False) + + error = None + process = None + try: - error = None - process = None self.fm.signal_emit('runner.execute.before', popen_kws=popen_kws, context=context) try: diff --git a/ranger/data/scope.sh b/ranger/data/scope.sh index 864e39ab..2e9983ee 100755 --- a/ranger/data/scope.sh +++ b/ranger/data/scope.sh @@ -108,7 +108,15 @@ handle_extension() { ;; ## JSON - json|ipynb) + json) + jq --color-output . "${FILE_PATH}" && exit 5 + python -m json.tool -- "${FILE_PATH}" && exit 5 + ;; + + ## Jupyter Notebooks + ipynb) + jupyter nbconvert --to markdown "${FILE_PATH}" --stdout | env COLORTERM=8bit bat --color=always --style=plain --language=markdown && exit 5 + jupyter nbconvert --to markdown "${FILE_PATH}" --stdout && exit 5 jq --color-output . "${FILE_PATH}" && exit 5 python -m json.tool -- "${FILE_PATH}" && exit 5 ;; @@ -262,19 +270,23 @@ handle_image() { # 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 + 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 + # ;; + drawio) + draw.io -x "${FILE_PATH}" -o "${IMAGE_CACHE_PATH}" \ + --width "${DEFAULT_SIZE%x*}" && exit 6 + exit 1;; + esac } handle_mime() { diff --git a/ranger/ext/accumulator.py b/ranger/ext/accumulator.py index a41db634..c34370d8 100644 --- a/ranger/ext/accumulator.py +++ b/ranger/ext/accumulator.py @@ -3,6 +3,8 @@ from __future__ import (absolute_import, division, print_function) +from abc import abstractmethod + from ranger.ext.direction import Direction @@ -90,8 +92,8 @@ class Accumulator(object): def sync_index(self, **kw): self.move_to_obj(self.pointed_obj, **kw) - @staticmethod - def get_list(): + @abstractmethod + def get_list(self): """OVERRIDE THIS""" return [] diff --git a/ranger/gui/colorscheme.py b/ranger/gui/colorscheme.py index 859773fb..22ff053f 100644 --- a/ranger/gui/colorscheme.py +++ b/ranger/gui/colorscheme.py @@ -27,6 +27,7 @@ set colorscheme yourschemename from __future__ import (absolute_import, division, print_function) import os.path +from abc import abstractmethod from curses import color_pair from io import open @@ -72,8 +73,8 @@ class ColorScheme(object): fg, bg, attr = self.get(*flatten(keys)) return attr | color_pair(get_color(fg, bg)) - @staticmethod - def use(_): + @abstractmethod + def use(self, context): """Use the colorscheme to determine the (fg, bg, attr) tuple. Override this method in your own colorscheme. diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py index 3d68f017..54149e0c 100644 --- a/ranger/gui/widgets/browsercolumn.py +++ b/ranger/gui/widgets/browsercolumn.py @@ -212,7 +212,7 @@ class BrowserColumn(Pager): # pylint: disable=too-many-instance-attributes def _format_line_number(self, linum_format, i, selected_i): line_number = i - if self.settings.line_numbers == 'relative': + if self.settings.line_numbers.lower() == 'relative': line_number = abs(selected_i - i) if not self.settings.relative_current_zero and line_number == 0: if self.settings.one_indexed: @@ -273,12 +273,29 @@ class BrowserColumn(Pager): # pylint: disable=too-many-instance-attributes copied = [f.path for f in self.fm.copy_buffer] + selected_i = self._get_index_of_selected_file() + # Set the size of the linum text field to the number of digits in the # visible files in directory. - linum_text_len = len(str(self.scroll_begin + self.hei)) + def nr_of_digits(number): + return len(str(number)) + + scroll_end = self.scroll_begin + min(self.hei, len(self.target)) - 1 + distance_to_top = selected_i - self.scroll_begin + distance_to_bottom = scroll_end - selected_i + one_indexed_offset = 1 if self.settings.one_indexed else 0 + + if self.settings.line_numbers.lower() == "relative": + linum_text_len = nr_of_digits(max(distance_to_top, + distance_to_bottom)) + if not self.settings.relative_current_zero: + linum_text_len = max(nr_of_digits(selected_i + + one_indexed_offset), + linum_text_len) + else: + linum_text_len = nr_of_digits(scroll_end + one_indexed_offset) linum_format = "{0:>" + str(linum_text_len) + "}" - selected_i = self._get_index_of_selected_file() for line in range(self.hei): i = line + self.scroll_begin @@ -307,12 +324,15 @@ class BrowserColumn(Pager): # pylint: disable=too-many-instance-attributes drawn.path in copied, tagged_marker, drawn.infostring, drawn.vcsstatus, drawn.vcsremotestatus, self.target.has_vcschild, self.fm.do_cut, current_linemode.name, metakey, active_pane, - self.settings.line_numbers) + self.settings.line_numbers.lower(), linum_text_len) # Check if current line has not already computed and cached if key in drawn.display_data: # Recompute line numbers because they can't be reliably cached. - if self.main_column and self.settings.line_numbers != 'false': + if ( + self.main_column + and self.settings.line_numbers.lower() != 'false' + ): line_number_text = self._format_line_number(linum_format, i, selected_i) @@ -337,7 +357,7 @@ class BrowserColumn(Pager): # pylint: disable=too-many-instance-attributes space = self.wid # line number field - if self.settings.line_numbers != 'false': + if self.settings.line_numbers.lower() != 'false': if self.main_column and space - linum_text_len > 2: line_number_text = self._format_line_number(linum_format, i, @@ -371,15 +391,16 @@ class BrowserColumn(Pager): # pylint: disable=too-many-instance-attributes try: infostringdata = current_linemode.infostring(drawn, metadata) if infostringdata: - infostring.append([" " + infostringdata + " ", + infostring.append([" " + infostringdata, ["infostring"]]) except NotImplementedError: infostring = self._draw_infostring_display(drawn, space) if infostring: infostringlen = self._total_len(infostring) if space - infostringlen > 2: - predisplay_right = infostring + predisplay_right - space -= infostringlen + sep = [[" ", []]] if predisplay_right else [] + predisplay_right = infostring + sep + predisplay_right + space -= infostringlen + len(sep) textstring = self._draw_text_display(text, space) textstringlen = self._total_len(textstring) @@ -445,7 +466,7 @@ class BrowserColumn(Pager): # pylint: disable=too-many-instance-attributes infostring_display = [] if self.display_infostring and drawn.infostring \ and self.settings.display_size_in_main_column: - infostring = str(drawn.infostring) + " " + infostring = str(drawn.infostring) if len(infostring) <= space: infostring_display.append([infostring, ['infostring']]) return infostring_display diff --git a/requirements.txt b/requirements.txt index fc51e82a..c24c4584 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ flake8 -pylint +pylint==2.13.9 # Newer versions drop the python3 port checker, which we need pytest diff --git a/tests/pylint/test_py2_compat.py b/tests/pylint/test_py2_compat.py index 33fc5681..ff13db7c 100644 --- a/tests/pylint/test_py2_compat.py +++ b/tests/pylint/test_py2_compat.py @@ -28,6 +28,7 @@ class TestPy2CompatibilityChecker(pylint.testutils.CheckerTestCase): node=oldstyle_class, confidence=HIGH, ), + ignore_position=True, ): self.checker.visit_classdef(oldstyle_class) @@ -60,6 +61,7 @@ class TestPy2CompatibilityChecker(pylint.testutils.CheckerTestCase): node=print_function_call, confidence=HIGH, ), + ignore_position=True, ): self.checker.visit_call(print_function_call) @@ -100,6 +102,7 @@ class TestPy2CompatibilityChecker(pylint.testutils.CheckerTestCase): node=early_print_function_call, confidence=HIGH, ), + ignore_position=True, ): self.checker.visit_call(early_print_function_call) @@ -117,6 +120,7 @@ class TestPy2CompatibilityChecker(pylint.testutils.CheckerTestCase): node=implicit_format_spec, confidence=HIGH, ), + ignore_position=True, ): self.checker.visit_call(implicit_format_spec) @@ -141,6 +145,7 @@ class TestPy2CompatibilityChecker(pylint.testutils.CheckerTestCase): node=with_Popen, confidence=HIGH, ), + ignore_position=True, ): self.checker.visit_with(with_subprocess_Popen) self.checker.visit_with(with_Popen) @@ -160,6 +165,7 @@ class TestPy2CompatibilityChecker(pylint.testutils.CheckerTestCase): node=f_string, confidence=HIGH, ), + ignore_position=True, ): self.checker.visit_joinedstr(f_string) with self.assertNoMessages(): |