rp 0.1.1348__tar.gz → 0.1.1350__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rp-0.1.1348 → rp-0.1.1350}/.setup.py.un~ +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/PKG-INFO +1 -1
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/keys.py +5 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/lexers.py +1 -1
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/processors.py +291 -1
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/styles/base.py +17 -3
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/styles/defaults.py +6 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/styles/from_dict.py +41 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/styles/utils.py +11 -1
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/terminal/vt100_input.py +6 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/terminal/vt100_output.py +65 -3
- {rp-0.1.1348 → rp-0.1.1350}/rp/r.py +1493 -129
- rp-0.1.1350/rp/rp_ptpython/ast_selection.py +429 -0
- rp-0.1.1350/rp/rp_ptpython/async_analyzer_base.py +235 -0
- rp-0.1.1350/rp/rp_ptpython/async_jedi_highlighter.py +273 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/completer.py +36 -21
- rp-0.1.1350/rp/rp_ptpython/jedi_lexer.py +179 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/key_bindings.py +110 -2
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/layout.py +19 -2
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/python_input.py +94 -9
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/style.py +177 -25
- rp-0.1.1350/rp/rp_ptpython/treesitter_semantic.py +205 -0
- rp-0.1.1350/rp/version.py +1 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp.egg-info/PKG-INFO +1 -1
- {rp-0.1.1348 → rp-0.1.1350}/rp.egg-info/SOURCES.txt +3 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp.egg-info/requires.txt +1 -0
- {rp-0.1.1348 → rp-0.1.1350}/setup.py +1 -0
- rp-0.1.1350/version.py +1 -0
- rp-0.1.1348/rp/rp_ptpython/async_jedi_highlighter.py +0 -308
- rp-0.1.1348/rp/rp_ptpython/jedi_lexer.py +0 -129
- rp-0.1.1348/rp/version.py +0 -1
- rp-0.1.1348/version.py +0 -1
- {rp-0.1.1348 → rp-0.1.1350}/.gitignore +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/.idea/QuickPython.iml +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/.idea/QuickPython.time +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/.idea/encodings.xml +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/.idea/inspectionProfiles/Project_Default.xml +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/.idea/misc.xml +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/.idea/modules.xml +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/.idea/vcs.xml +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/.idea/workspace.xml +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/.publish.sh.un~ +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/.update_module_paths.py.un~ +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/LICENSE.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/README +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/Scrap +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/aoisdasd +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/increment_version.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/oijio +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/publish.sh +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/pyqtconsoletest.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/__main__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/documentation.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/Pyperclip.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/debug_comment.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/draw_code_minimap.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/graveyard.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/_compatibility.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/cache.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/file_io.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/grammar.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/normalizer.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/parser.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/pgen2/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/pgen2/generator.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/pgen2/grammar_parser.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/diff.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/errors.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/grammar26.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/grammar27.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/grammar310.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/grammar311.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/grammar312.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/grammar33.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/grammar34.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/grammar35.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/grammar36.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/grammar37.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/grammar38.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/grammar39.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/parser.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/pep8.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/prefix.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/token.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/tokenize.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/python/tree.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/tree.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/parso/utils.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/peepdis/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/peepdis/core.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/peepdis/datastructures.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/peepdis/legacy.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/peepdis/preferences.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/powerpoint_converter.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/profile_vim_plugins.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/bindings/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/bindings/flann_ctypes.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/exceptions.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/index.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/io/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/io/binary_dataset.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/io/dat_dataset.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/io/dataset.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/io/hdf5_dataset.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/io/npy_dataset.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/util/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyflann/util/weave_tools.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/__version__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/app.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/cli.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/cli_utils.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/config/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/config/config.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/config/config_error.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/config/config_parser.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/config/config_transformer.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/config/validators/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/config/validators/options.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/logging.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/model/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/model/autocomplete/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/model/autocomplete/autocomplete_listener.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/model/common/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/model/common/jsonpath/JSONPathLexer.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/model/common/jsonpath/JSONPathListener.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/model/common/jsonpath/JSONPathParser.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/model/common/jsonpath/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/model/io/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/model/io/datasource.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/model/model.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/service/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/service/client.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/service/dispatcher.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/common/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/common/popup.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/common/selectable_text.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/autocomplete_popup/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/autocomplete_popup/autocomplete_popup.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/autocomplete_popup/autocomplete_popup_keymapper.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/help_bar/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/help_bar/help_bar.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/help_page/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/help_page/detailed_help_page.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/json_browser/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/json_browser/json_browser.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/json_browser/json_browser_keymapper.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/query_bar/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/query_bar/query_bar.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/components/query_bar/query_bar_keymapper.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/array/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/array/array_end_node.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/array/array_end_widget.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/array/array_node.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/array/array_start_widget.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/array/array_unexpanded_widget.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/json_composite_end_node.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/json_composite_node.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/json_listbox.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/json_listwalker.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/json_simple_node.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/json_widget.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/node_factory.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/object/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/object/object_end_node.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/object/object_end_widget.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/object/object_node.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/object/object_start_widget.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/object/object_unexpanded_widget.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/primitive/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/primitive/base.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/primitive/boolean.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/primitive/generic.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/primitive/integer.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/primitive/null.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/primitive/numeric.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/primitive/string.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/json_lib/selector/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/keymapper/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/keymapper/abstract_component_keymapper.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/keymapper/keymapper.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/keymapper/keymapper_config.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/keymapper/keymapper_config_parser.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/theme/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/theme/theme.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/theme/theme_config.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/theme/theme_config_parser.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/view_config.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/view_frame.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pyfx/view/view_manager.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pynput_recorder.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pypi_inspection.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/pytorch_module_explorer.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/refactor/string_format/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/refactor/string_format/format_to_fstring_converter.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/refactor/string_format/fstring_converter.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/refactor/string_format/test_format_to_fstring_converter.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/refactor/string_format/test_fstring_converter.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/rp_black_macchiato.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/stamp_tensor.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/stdin_python_highlighter.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tetris/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tetris/__main__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tetris/graphics/graphics/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tetris/graphics/graphics/canvas.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tetris/graphics/graphics/colors.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tetris/graphics/graphics/console.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tetris/graphics/graphics/funcs.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tetris/graphics/graphics/nbinput.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tetris/graphics/graphics/shapes.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tetris/graphics/graphics/sprite.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tetris/letters.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tetris/tetrisShapes.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/timg/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/timg/__main__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/timg/argparser.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/timg/meta.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/timg/methods/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/timg/methods/ansi.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/timg/methods/ansi_methods.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/timg/methods/ascii.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/timg/methods/method.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/timg/methods/sixel.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/timg/renderer.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/torch_hooks.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/torch_tools.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tracetraptest.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/tweenline.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/libs/webeval_dataset.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/list_of_modules.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/application.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/auto_suggest.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/buffer.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/buffer_mapping.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/cache.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/clipboard/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/clipboard/base.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/clipboard/in_memory.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/clipboard/pyperclip.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/completion.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/completers/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/completers/base.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/completers/filesystem.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/completers/system.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/regular_languages/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/regular_languages/compiler.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/regular_languages/completion.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/regular_languages/lexer.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/regular_languages/regex_parser.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/regular_languages/validation.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/telnet/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/telnet/application.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/telnet/log.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/telnet/protocol.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/telnet/server.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/validators/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/contrib/validators/base.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/document.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/enums.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/eventloop/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/eventloop/asyncio_base.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/eventloop/asyncio_posix.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/eventloop/asyncio_win32.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/eventloop/base.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/eventloop/callbacks.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/eventloop/inputhook.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/eventloop/posix.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/eventloop/posix_utils.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/eventloop/select.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/eventloop/utils.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/eventloop/win32.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/filters/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/filters/base.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/filters/cli.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/filters/types.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/filters/utils.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/history.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/input.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/interface.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/bindings/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/bindings/basic.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/bindings/completion.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/bindings/emacs.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/bindings/named_commands.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/bindings/scroll.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/bindings/vi.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/defaults.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/digraphs.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/input_processor.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/manager.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/registry.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/key_binding/vi_state.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/containers.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/controls.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/dimension.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/margins.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/menus.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/mouse_handlers.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/prompt.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/screen.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/toolbars.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/untitled.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/layout/utils.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/mouse_events.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/output.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/reactive.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/renderer.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/search_state.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/selection.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/shortcuts.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/styles/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/styles/from_pygments.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/terminal/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/terminal/conemu_output.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/terminal/win32_input.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/terminal/win32_output.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/token.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/utils.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/validation.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/prompt_toolkit/win32_types.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/__main__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/bash_completer.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/completer_old.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/completion_ranker.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/completion_schema.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/completion_types.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/eventloop.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/filters.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/history_browser.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/ipython.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/jedi_highlighter.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/jedi_utils.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/patch_linecache.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/path_completer_utils.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/prompt_style.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/r_iterm_comm.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/repl.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/rp_ptpdb/__init__.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/rp_ptpdb/commands.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/rp_ptpdb/completers.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/rp_ptpdb/completion_hints.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/rp_ptpdb/grammar.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/rp_ptpdb/key_bindings.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/rp_ptpdb/layout.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/rp_ptpdb/style.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/rp_ptpdb/toolbars.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/testable_keybindings.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/utils.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/rp_ptpython/validator.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/ryan_vimrc.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp/web_evaluator.py +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp.egg-info/dependency_links.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp.egg-info/entry_points.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/rp.egg-info/top_level.txt +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/setup.cfg +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/untitled.c +0 -0
- {rp-0.1.1348 → rp-0.1.1350}/update_module_paths.py +0 -0
|
Binary file
|
|
@@ -67,6 +67,11 @@ class Keys(object):
|
|
|
67
67
|
ShiftDown = Key('<ShiftDown>')
|
|
68
68
|
ShiftRight = Key('<ShiftRight>')
|
|
69
69
|
|
|
70
|
+
AltShiftUp = Key('<AltShiftUp>')
|
|
71
|
+
AltShiftDown = Key('<AltShiftDown>')
|
|
72
|
+
AltShiftLeft = Key('<AltShiftLeft>')
|
|
73
|
+
AltShiftRight = Key('<AltShiftRight>')
|
|
74
|
+
|
|
70
75
|
Home = Key('<Home>')
|
|
71
76
|
End = Key('<End>')
|
|
72
77
|
Delete = Key('<Delete>')
|
|
@@ -244,7 +244,7 @@ class LazyBashLexer(LazyLexer):
|
|
|
244
244
|
import re
|
|
245
245
|
import rp
|
|
246
246
|
Name = shell.Name
|
|
247
|
-
commands = rp.get_system_commands() + ['!']
|
|
247
|
+
commands = rp.get_system_commands(use_cache=True) + ['!']
|
|
248
248
|
shell.BashLexer.tokens['basic'] += [(r'(^|!|\b)(' + '|'.join(re.escape(x) for x in commands) + r')(?=[\s)\`]|$)', Name.Function),]
|
|
249
249
|
|
|
250
250
|
|
|
@@ -21,9 +21,11 @@ from rp.prompt_toolkit.token import Token
|
|
|
21
21
|
|
|
22
22
|
from .utils import token_list_len, explode_tokens
|
|
23
23
|
|
|
24
|
-
import re
|
|
25
24
|
import keyword
|
|
26
25
|
|
|
26
|
+
# Only import when async analyzers are needed (avoid circular imports)
|
|
27
|
+
# from rp.rp_ptpython.async_analyzer_base import AsyncAnalyzerBase, build_line_map_difflib
|
|
28
|
+
|
|
27
29
|
__all__ = (
|
|
28
30
|
'Processor',
|
|
29
31
|
'Transformation',
|
|
@@ -44,6 +46,7 @@ __all__ = (
|
|
|
44
46
|
'ShowWhitespaceProcessor',
|
|
45
47
|
'HighlightWordOccurrencesProcessor',
|
|
46
48
|
'HighlightInjectedLanguageProcessor',
|
|
49
|
+
'SyntaxErrorProcessor',
|
|
47
50
|
)
|
|
48
51
|
|
|
49
52
|
|
|
@@ -966,3 +969,290 @@ class HighlightInjectedLanguageProcessor(Processor):
|
|
|
966
969
|
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
|
|
967
970
|
"""No transformation needed - lexer handles it."""
|
|
968
971
|
return Transformation(tokens)
|
|
972
|
+
|
|
973
|
+
from rp.rp_ptpython.async_analyzer_base import AsyncAnalyzerBase, build_line_map_difflib
|
|
974
|
+
|
|
975
|
+
|
|
976
|
+
class AsyncRuffChecker(AsyncAnalyzerBase):
|
|
977
|
+
"""
|
|
978
|
+
Background ruff checker using AsyncAnalyzerBase.
|
|
979
|
+
Runs ruff in background thread (debounced to 0.1s) to avoid blocking UI.
|
|
980
|
+
"""
|
|
981
|
+
def __init__(self, redraw_callback=None):
|
|
982
|
+
super().__init__(debounce_interval=0.1, redraw_callback=redraw_callback)
|
|
983
|
+
|
|
984
|
+
# Import subprocess tools
|
|
985
|
+
import json
|
|
986
|
+
import subprocess
|
|
987
|
+
import tempfile
|
|
988
|
+
from pathlib import Path
|
|
989
|
+
self.json = json
|
|
990
|
+
self.subprocess = subprocess
|
|
991
|
+
self.tempfile = tempfile
|
|
992
|
+
self.Path = Path
|
|
993
|
+
|
|
994
|
+
def _empty_results(self):
|
|
995
|
+
return {}
|
|
996
|
+
|
|
997
|
+
def _translate_results(self, old_code, new_code, old_diags):
|
|
998
|
+
"""Translate diagnostic line numbers using difflib."""
|
|
999
|
+
if not old_code or not old_diags:
|
|
1000
|
+
return {}
|
|
1001
|
+
|
|
1002
|
+
line_map = build_line_map_difflib(old_code, new_code)
|
|
1003
|
+
|
|
1004
|
+
# Translate diagnostics to new line numbers
|
|
1005
|
+
new_diags = {}
|
|
1006
|
+
for old_line, issues in old_diags.items():
|
|
1007
|
+
if old_line in line_map:
|
|
1008
|
+
new_line, _ = line_map[old_line]
|
|
1009
|
+
new_diags[new_line] = issues
|
|
1010
|
+
|
|
1011
|
+
return new_diags
|
|
1012
|
+
|
|
1013
|
+
def _analyze(self, text, known_names):
|
|
1014
|
+
"""Run ruff subprocess in background, filtering out F821 for known REPL variables."""
|
|
1015
|
+
# Write to temp file (no injection needed!)
|
|
1016
|
+
with self.tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
|
|
1017
|
+
f.write(text)
|
|
1018
|
+
temp_path = f.name
|
|
1019
|
+
|
|
1020
|
+
try:
|
|
1021
|
+
# Use temp dir for cache - faster (local storage) and avoids littering .ruff_cache everywhere
|
|
1022
|
+
import os
|
|
1023
|
+
import rp.r as r
|
|
1024
|
+
cache_dir = r._ruff_cache_dir
|
|
1025
|
+
os.makedirs(cache_dir, exist_ok=True)
|
|
1026
|
+
|
|
1027
|
+
result = self.subprocess.run(
|
|
1028
|
+
['ruff', 'check', '--output-format=json', '--cache-dir', cache_dir, temp_path],
|
|
1029
|
+
capture_output=True,
|
|
1030
|
+
text=True,
|
|
1031
|
+
timeout=2
|
|
1032
|
+
)
|
|
1033
|
+
|
|
1034
|
+
diagnostics = self.json.loads(result.stdout) if result.stdout else []
|
|
1035
|
+
|
|
1036
|
+
lines_with_issues = {}
|
|
1037
|
+
for diag in diagnostics:
|
|
1038
|
+
line_num = diag['location']['row']
|
|
1039
|
+
|
|
1040
|
+
# Filter out F821 (undefined name) for variables we know are in REPL scope
|
|
1041
|
+
if diag['code'] == 'F821' and known_names:
|
|
1042
|
+
# Extract variable name from message like "Undefined name `asdf`"
|
|
1043
|
+
import re
|
|
1044
|
+
match = re.search(r'Undefined name `([^`]+)`', diag['message'])
|
|
1045
|
+
if match and match.group(1) in known_names:
|
|
1046
|
+
continue # Skip this warning - variable is defined in REPL
|
|
1047
|
+
|
|
1048
|
+
col = diag['location']['column']
|
|
1049
|
+
end_col = diag.get('end_location', {}).get('column', col + 1)
|
|
1050
|
+
# Only E9XX codes are syntax errors (red); E1XX-E8XX are style violations (yellow)
|
|
1051
|
+
is_error = diag['code'] == 'invalid-syntax' or (diag['code'].startswith('E9') and len(diag['code']) >= 3)
|
|
1052
|
+
|
|
1053
|
+
if line_num not in lines_with_issues:
|
|
1054
|
+
lines_with_issues[line_num] = []
|
|
1055
|
+
|
|
1056
|
+
lines_with_issues[line_num].append({
|
|
1057
|
+
'col': col,
|
|
1058
|
+
'end_col': end_col,
|
|
1059
|
+
'message': diag['message'],
|
|
1060
|
+
'code': diag['code'],
|
|
1061
|
+
'is_error': is_error
|
|
1062
|
+
})
|
|
1063
|
+
|
|
1064
|
+
return lines_with_issues
|
|
1065
|
+
except:
|
|
1066
|
+
return {}
|
|
1067
|
+
finally:
|
|
1068
|
+
try:
|
|
1069
|
+
self.Path(temp_path).unlink()
|
|
1070
|
+
except:
|
|
1071
|
+
pass
|
|
1072
|
+
|
|
1073
|
+
def get_diagnostics(self, text, known_names=None):
|
|
1074
|
+
"""Get diagnostics, using cache with difflib translation."""
|
|
1075
|
+
known_names = known_names or set()
|
|
1076
|
+
return self.get_results(text, known_names)
|
|
1077
|
+
|
|
1078
|
+
|
|
1079
|
+
class AsyncShellcheckChecker(AsyncAnalyzerBase):
|
|
1080
|
+
"""
|
|
1081
|
+
Background shellcheck checker using AsyncAnalyzerBase.
|
|
1082
|
+
Runs shellcheck in background thread (debounced to 0.1s) to avoid blocking UI.
|
|
1083
|
+
"""
|
|
1084
|
+
def __init__(self, redraw_callback=None):
|
|
1085
|
+
super().__init__(debounce_interval=0.1, redraw_callback=redraw_callback)
|
|
1086
|
+
|
|
1087
|
+
# Import subprocess tools
|
|
1088
|
+
import json
|
|
1089
|
+
import subprocess
|
|
1090
|
+
import tempfile
|
|
1091
|
+
from pathlib import Path
|
|
1092
|
+
self.json = json
|
|
1093
|
+
self.subprocess = subprocess
|
|
1094
|
+
self.tempfile = tempfile
|
|
1095
|
+
self.Path = Path
|
|
1096
|
+
|
|
1097
|
+
def _empty_results(self):
|
|
1098
|
+
return {}
|
|
1099
|
+
|
|
1100
|
+
def _translate_results(self, old_code, new_code, old_diags):
|
|
1101
|
+
"""Translate diagnostic line numbers using difflib."""
|
|
1102
|
+
if not old_code or not old_diags:
|
|
1103
|
+
return {}
|
|
1104
|
+
|
|
1105
|
+
line_map = build_line_map_difflib(old_code, new_code)
|
|
1106
|
+
|
|
1107
|
+
# Translate diagnostics to new line numbers
|
|
1108
|
+
new_diags = {}
|
|
1109
|
+
for old_line, issues in old_diags.items():
|
|
1110
|
+
if old_line in line_map:
|
|
1111
|
+
new_line, _ = line_map[old_line]
|
|
1112
|
+
new_diags[new_line] = issues
|
|
1113
|
+
|
|
1114
|
+
return new_diags
|
|
1115
|
+
|
|
1116
|
+
def _analyze(self, text, known_names):
|
|
1117
|
+
"""Run shellcheck subprocess in background."""
|
|
1118
|
+
# Strip first ! character if present
|
|
1119
|
+
if text.startswith('!'):
|
|
1120
|
+
bash_text = text[1:]
|
|
1121
|
+
offset = 1
|
|
1122
|
+
else:
|
|
1123
|
+
bash_text = text
|
|
1124
|
+
offset = 0
|
|
1125
|
+
|
|
1126
|
+
# Write to temp file
|
|
1127
|
+
with self.tempfile.NamedTemporaryFile(mode='w', suffix='.sh', delete=False) as f:
|
|
1128
|
+
f.write(bash_text)
|
|
1129
|
+
temp_path = f.name
|
|
1130
|
+
|
|
1131
|
+
try:
|
|
1132
|
+
result = self.subprocess.run(
|
|
1133
|
+
['shellcheck', '--format=json', temp_path],
|
|
1134
|
+
capture_output=True,
|
|
1135
|
+
text=True,
|
|
1136
|
+
timeout=2
|
|
1137
|
+
)
|
|
1138
|
+
|
|
1139
|
+
diagnostics = self.json.loads(result.stdout) if result.stdout else []
|
|
1140
|
+
|
|
1141
|
+
lines_with_issues = {}
|
|
1142
|
+
for diag in diagnostics:
|
|
1143
|
+
line_num = diag['line']
|
|
1144
|
+
col = diag['column']
|
|
1145
|
+
end_col = diag.get('endColumn', col + 1)
|
|
1146
|
+
level = diag['level'] # error, warning, info, style
|
|
1147
|
+
is_error = level == 'error'
|
|
1148
|
+
|
|
1149
|
+
# Adjust column positions for first line to account for stripped !
|
|
1150
|
+
if line_num == 1 and offset > 0:
|
|
1151
|
+
col += offset
|
|
1152
|
+
end_col += offset
|
|
1153
|
+
|
|
1154
|
+
if line_num not in lines_with_issues:
|
|
1155
|
+
lines_with_issues[line_num] = []
|
|
1156
|
+
|
|
1157
|
+
lines_with_issues[line_num].append({
|
|
1158
|
+
'col': col,
|
|
1159
|
+
'end_col': end_col,
|
|
1160
|
+
'message': diag['message'],
|
|
1161
|
+
'code':"SC{0}".format(diag['code']),
|
|
1162
|
+
'is_error': is_error
|
|
1163
|
+
})
|
|
1164
|
+
|
|
1165
|
+
return lines_with_issues
|
|
1166
|
+
except:
|
|
1167
|
+
return {}
|
|
1168
|
+
finally:
|
|
1169
|
+
try:
|
|
1170
|
+
self.Path(temp_path).unlink()
|
|
1171
|
+
except:
|
|
1172
|
+
pass
|
|
1173
|
+
|
|
1174
|
+
def get_diagnostics(self, text, known_names=None):
|
|
1175
|
+
"""Get diagnostics, using cache with difflib translation."""
|
|
1176
|
+
return self.get_results(text, known_names or set())
|
|
1177
|
+
|
|
1178
|
+
|
|
1179
|
+
class SyntaxErrorProcessor(Processor):
|
|
1180
|
+
"""
|
|
1181
|
+
Processor that highlights syntax errors and warnings using ruff or shellcheck.
|
|
1182
|
+
|
|
1183
|
+
Applies Token.SyntaxError (with red undercurl) to syntax errors and
|
|
1184
|
+
Token.SyntaxWarning (with yellow undercurl) to warnings like unused imports.
|
|
1185
|
+
|
|
1186
|
+
Uses AsyncRuffChecker for Python code and AsyncShellcheckChecker for bash code (shell mode).
|
|
1187
|
+
Shell mode is detected when text starts with '!'.
|
|
1188
|
+
REPL-aware: injects known variables before linting to avoid false positives.
|
|
1189
|
+
"""
|
|
1190
|
+
|
|
1191
|
+
def __init__(self, python_input=None):
|
|
1192
|
+
self.python_input = python_input
|
|
1193
|
+
self._last_refresh_text = None
|
|
1194
|
+
|
|
1195
|
+
def apply_transformation(self, cli, document, lineno, source_to_display, tokens):
|
|
1196
|
+
# Trigger refresh once per render pass (not per line)
|
|
1197
|
+
if self.python_input and document.text != self._last_refresh_text:
|
|
1198
|
+
self._last_refresh_text = document.text
|
|
1199
|
+
self.python_input.refresh_analysis(document.text)
|
|
1200
|
+
|
|
1201
|
+
# Detect shell mode
|
|
1202
|
+
is_shell_mode = document.text.startswith('!')
|
|
1203
|
+
|
|
1204
|
+
# Get the appropriate checker based on mode
|
|
1205
|
+
if is_shell_mode:
|
|
1206
|
+
checker = self.python_input._shellcheck_checker if self.python_input else None
|
|
1207
|
+
else:
|
|
1208
|
+
checker = self.python_input._ruff_checker if self.python_input else None
|
|
1209
|
+
|
|
1210
|
+
if not checker:
|
|
1211
|
+
return Transformation(tokens)
|
|
1212
|
+
|
|
1213
|
+
# Set redraw callback once
|
|
1214
|
+
if not checker.redraw_callback:
|
|
1215
|
+
checker.redraw_callback = lambda: cli.request_redraw()
|
|
1216
|
+
|
|
1217
|
+
# Get current diagnostics
|
|
1218
|
+
with checker.lock:
|
|
1219
|
+
diagnostics = checker.cached_results
|
|
1220
|
+
|
|
1221
|
+
line_issues = diagnostics.get(lineno + 1, [])
|
|
1222
|
+
|
|
1223
|
+
if not line_issues:
|
|
1224
|
+
# No issues on this line
|
|
1225
|
+
return Transformation(tokens)
|
|
1226
|
+
|
|
1227
|
+
# Explode tokens into individual characters so we can apply styles per-character
|
|
1228
|
+
tokens = explode_tokens(tokens)
|
|
1229
|
+
|
|
1230
|
+
# Apply error/warning undercurls to affected characters
|
|
1231
|
+
for i, (token, char) in enumerate(tokens):
|
|
1232
|
+
col = i + 1 # Column is 1-indexed
|
|
1233
|
+
|
|
1234
|
+
# Check if this character position has any issues
|
|
1235
|
+
overlapping_issues = [
|
|
1236
|
+
issue for issue in line_issues
|
|
1237
|
+
if issue['col'] <= col < issue['end_col']
|
|
1238
|
+
]
|
|
1239
|
+
|
|
1240
|
+
if overlapping_issues:
|
|
1241
|
+
# Determine the most severe issue (error > warning > unused variable/import)
|
|
1242
|
+
is_error = any(issue['is_error'] for issue in overlapping_issues)
|
|
1243
|
+
is_unused_var = any(issue['code'] == 'F841' for issue in overlapping_issues)
|
|
1244
|
+
is_unused_import = any(issue['code'] == 'F401' for issue in overlapping_issues)
|
|
1245
|
+
|
|
1246
|
+
if is_error:
|
|
1247
|
+
error_token = Token.SyntaxError
|
|
1248
|
+
elif is_unused_var:
|
|
1249
|
+
error_token = Token.SyntaxWarning.UnusedVariable
|
|
1250
|
+
elif is_unused_import:
|
|
1251
|
+
error_token = Token.SyntaxWarning.UnusedImport
|
|
1252
|
+
else:
|
|
1253
|
+
error_token = Token.SyntaxWarning
|
|
1254
|
+
|
|
1255
|
+
# Combine original token with error token using ':' separator to preserve both styles
|
|
1256
|
+
tokens[i] = (token + (':', ) + error_token, char)
|
|
1257
|
+
|
|
1258
|
+
return Transformation(tokens)
|
|
@@ -17,7 +17,7 @@ __all__ = (
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
#: Style attributes.
|
|
20
|
-
Attrs = namedtuple('Attrs', 'color bgcolor bold underline italic blink reverse color_alpha bgcolor_alpha')
|
|
20
|
+
Attrs = namedtuple('Attrs', 'color bgcolor bold underline italic blink reverse color_alpha bgcolor_alpha undercurl underline_color faded fastblink hide strike overlined underdouble underdots underdash')
|
|
21
21
|
"""
|
|
22
22
|
:param color: Hexadecimal string. E.g. '000000' or Ansi color name: e.g. 'ansiblue'
|
|
23
23
|
:param bgcolor: Hexadecimal string. E.g. 'ffffff' or Ansi color name: e.g. 'ansired'
|
|
@@ -28,15 +28,29 @@ Attrs = namedtuple('Attrs', 'color bgcolor bold underline italic blink reverse c
|
|
|
28
28
|
:param reverse: Boolean
|
|
29
29
|
:param color_alpha: Float 0.0-1.0 for foreground color alpha (1.0 = opaque)
|
|
30
30
|
:param bgcolor_alpha: Float 0.0-1.0 for background color alpha (1.0 = opaque)
|
|
31
|
+
:param undercurl: Boolean - use curly underline instead of straight
|
|
32
|
+
:param underline_color: Hexadecimal string or ANSI color name for underline color (independent of text color)
|
|
33
|
+
:param faded: Boolean - dim/faint text (SGR 2)
|
|
34
|
+
:param fastblink: Boolean - rapid blink (SGR 6)
|
|
35
|
+
:param hide: Boolean - conceal/hide text (SGR 8)
|
|
36
|
+
:param strike: Boolean - strikethrough (SGR 9)
|
|
37
|
+
:param overlined: Boolean - overline (SGR 53)
|
|
38
|
+
:param underdouble: Boolean - double underline (SGR 4:2)
|
|
39
|
+
:param underdots: Boolean - dotted underline (SGR 4:4)
|
|
40
|
+
:param underdash: Boolean - dashed underline (SGR 4:5)
|
|
31
41
|
"""
|
|
32
42
|
|
|
33
43
|
#: The default `Attrs`.
|
|
34
44
|
DEFAULT_ATTRS = Attrs(color=None, bgcolor=None, bold=False, underline=False,
|
|
35
|
-
italic=False, blink=False, reverse=False, color_alpha=1.0, bgcolor_alpha=1.0
|
|
45
|
+
italic=False, blink=False, reverse=False, color_alpha=1.0, bgcolor_alpha=1.0,
|
|
46
|
+
undercurl=False, underline_color=None, faded=False, fastblink=False,
|
|
47
|
+
hide=False, strike=False, overlined=False, underdouble=False, underdots=False, underdash=False)
|
|
36
48
|
|
|
37
49
|
#: An `Attrs` with all attributes set to None (for style parsing)
|
|
38
50
|
NONE_ATTRS = Attrs(color=None, bgcolor=None, bold=None, underline=None,
|
|
39
|
-
italic=None, blink=None, reverse=None, color_alpha=1.0, bgcolor_alpha=1.0
|
|
51
|
+
italic=None, blink=None, reverse=None, color_alpha=1.0, bgcolor_alpha=1.0,
|
|
52
|
+
undercurl=None, underline_color=None, faded=None, fastblink=None,
|
|
53
|
+
hide=None, strike=None, overlined=None, underdouble=None, underdots=None, underdash=None)
|
|
40
54
|
|
|
41
55
|
|
|
42
56
|
#: ``Attrs.bgcolor/fgcolor`` can be in either 'ffffff' format, or can be any of
|
|
@@ -97,6 +97,12 @@ DEFAULT_STYLE_EXTENSIONS = {
|
|
|
97
97
|
# Language injection regions (e.g., """#!bash ... """)
|
|
98
98
|
Token.InjectedLanguage: 'noinherit bg:#0d2b0d',
|
|
99
99
|
|
|
100
|
+
# Syntax errors and warnings (with undercurl)
|
|
101
|
+
Token.SyntaxError: 'undercurl underline_color:#ff0000',
|
|
102
|
+
Token.SyntaxWarning: 'undercurl underline_color:#ffff00',
|
|
103
|
+
Token.SyntaxWarning.UnusedVariable: 'faded undercurl underline_color:#ffff00',
|
|
104
|
+
Token.SyntaxWarning.UnusedImport: 'faded undercurl underline_color:#ffff00',
|
|
105
|
+
|
|
100
106
|
# When Control-C has been pressed. Grayed.
|
|
101
107
|
Token.Aborted: '#888888',
|
|
102
108
|
|
|
@@ -120,6 +120,44 @@ def style_from_dict(style_dict, include_defaults=True):
|
|
|
120
120
|
attrs = attrs._replace(reverse=True)
|
|
121
121
|
elif part == 'noreverse':
|
|
122
122
|
attrs = attrs._replace(reverse=False)
|
|
123
|
+
elif part == 'undercurl':
|
|
124
|
+
attrs = attrs._replace(undercurl=True)
|
|
125
|
+
elif part == 'noundercurl':
|
|
126
|
+
attrs = attrs._replace(undercurl=False)
|
|
127
|
+
|
|
128
|
+
# Additional fansi-compatible styles
|
|
129
|
+
elif part in ('faded', 'dim'):
|
|
130
|
+
attrs = attrs._replace(faded=True)
|
|
131
|
+
elif part in ('nofaded', 'nodim'):
|
|
132
|
+
attrs = attrs._replace(faded=False)
|
|
133
|
+
elif part == 'fastblink':
|
|
134
|
+
attrs = attrs._replace(fastblink=True)
|
|
135
|
+
elif part == 'nofastblink':
|
|
136
|
+
attrs = attrs._replace(fastblink=False)
|
|
137
|
+
elif part == 'hide':
|
|
138
|
+
attrs = attrs._replace(hide=True)
|
|
139
|
+
elif part == 'nohide':
|
|
140
|
+
attrs = attrs._replace(hide=False)
|
|
141
|
+
elif part == 'strike':
|
|
142
|
+
attrs = attrs._replace(strike=True)
|
|
143
|
+
elif part == 'nostrike':
|
|
144
|
+
attrs = attrs._replace(strike=False)
|
|
145
|
+
elif part == 'overlined':
|
|
146
|
+
attrs = attrs._replace(overlined=True)
|
|
147
|
+
elif part == 'nooverlined':
|
|
148
|
+
attrs = attrs._replace(overlined=False)
|
|
149
|
+
elif part == 'underdouble':
|
|
150
|
+
attrs = attrs._replace(underdouble=True)
|
|
151
|
+
elif part == 'nounderdouble':
|
|
152
|
+
attrs = attrs._replace(underdouble=False)
|
|
153
|
+
elif part == 'underdots':
|
|
154
|
+
attrs = attrs._replace(underdots=True)
|
|
155
|
+
elif part == 'nounderdots':
|
|
156
|
+
attrs = attrs._replace(underdots=False)
|
|
157
|
+
elif part == 'underdash':
|
|
158
|
+
attrs = attrs._replace(underdash=True)
|
|
159
|
+
elif part == 'nounderdash':
|
|
160
|
+
attrs = attrs._replace(underdash=False)
|
|
123
161
|
|
|
124
162
|
# Pygments properties that we ignore.
|
|
125
163
|
elif part in ('roman', 'sans', 'mono'):
|
|
@@ -135,6 +173,9 @@ def style_from_dict(style_dict, include_defaults=True):
|
|
|
135
173
|
elif part.startswith('bg:'):
|
|
136
174
|
bgcolor, bgcolor_alpha = _colorformat(part[3:])
|
|
137
175
|
attrs = attrs._replace(bgcolor=bgcolor, bgcolor_alpha=bgcolor_alpha)
|
|
176
|
+
elif part.startswith('underline_color:'):
|
|
177
|
+
ucolor, _ = _colorformat(part[16:])
|
|
178
|
+
attrs = attrs._replace(underline_color=ucolor)
|
|
138
179
|
else:
|
|
139
180
|
color, color_alpha = _colorformat(part)
|
|
140
181
|
attrs = attrs._replace(color=color, color_alpha=color_alpha)
|
|
@@ -108,6 +108,16 @@ def merge_attrs(list_of_attrs):
|
|
|
108
108
|
blink=attr.blink if attr.blink is not None else result.blink,
|
|
109
109
|
reverse=attr.reverse if attr.reverse is not None else result.reverse,
|
|
110
110
|
color_alpha=new_color_alpha,
|
|
111
|
-
bgcolor_alpha=new_bgcolor_alpha
|
|
111
|
+
bgcolor_alpha=new_bgcolor_alpha,
|
|
112
|
+
undercurl=attr.undercurl if attr.undercurl is not None else result.undercurl,
|
|
113
|
+
underline_color=attr.underline_color if attr.underline_color is not None else result.underline_color,
|
|
114
|
+
faded=attr.faded if attr.faded is not None else result.faded,
|
|
115
|
+
fastblink=attr.fastblink if attr.fastblink is not None else result.fastblink,
|
|
116
|
+
hide=attr.hide if attr.hide is not None else result.hide,
|
|
117
|
+
strike=attr.strike if attr.strike is not None else result.strike,
|
|
118
|
+
overlined=attr.overlined if attr.overlined is not None else result.overlined,
|
|
119
|
+
underdouble=attr.underdouble if attr.underdouble is not None else result.underdouble,
|
|
120
|
+
underdots=attr.underdots if attr.underdots is not None else result.underdots,
|
|
121
|
+
underdash=attr.underdash if attr.underdash is not None else result.underdash)
|
|
112
122
|
|
|
113
123
|
return result
|
|
@@ -189,6 +189,12 @@ ANSI_SEQUENCES = {
|
|
|
189
189
|
'\x1b[1;3A': (Keys.Escape, Keys.Up),
|
|
190
190
|
'\x1b[1;3B': (Keys.Escape, Keys.Down),
|
|
191
191
|
|
|
192
|
+
# Alt+Shift+Arrow keys
|
|
193
|
+
'\x1b[1;4A': Keys.AltShiftUp,
|
|
194
|
+
'\x1b[1;4B': Keys.AltShiftDown,
|
|
195
|
+
'\x1b[1;4C': Keys.AltShiftRight,
|
|
196
|
+
'\x1b[1;4D': Keys.AltShiftLeft,
|
|
197
|
+
|
|
192
198
|
# Sequences generated by numpad 5. Not sure what it means. (It doesn't
|
|
193
199
|
# appear in 'infocmp'. Just ignore.
|
|
194
200
|
'\x1b[E': Keys.Ignore, # Xterm.
|
|
@@ -251,7 +251,7 @@ class _EscapeCodeCache(dict):
|
|
|
251
251
|
self.ansi_colors_only = to_simple_filter(ansi_colors_only)
|
|
252
252
|
|
|
253
253
|
def __missing__(self, attrs):
|
|
254
|
-
fgcolor, bgcolor, bold, underline, italic, blink, reverse, color_alpha, bgcolor_alpha = attrs
|
|
254
|
+
fgcolor, bgcolor, bold, underline, italic, blink, reverse, color_alpha, bgcolor_alpha, undercurl, underline_color, faded, fastblink, hide, strike, overlined, underdouble, underdots, underdash = attrs
|
|
255
255
|
# Note: color_alpha and bgcolor_alpha are already blended into fgcolor/bgcolor by merge_attrs()
|
|
256
256
|
parts = []
|
|
257
257
|
|
|
@@ -259,14 +259,41 @@ class _EscapeCodeCache(dict):
|
|
|
259
259
|
|
|
260
260
|
if bold:
|
|
261
261
|
parts.append('1')
|
|
262
|
+
if faded:
|
|
263
|
+
parts.append('2')
|
|
262
264
|
if italic:
|
|
263
265
|
parts.append('3')
|
|
264
266
|
if blink:
|
|
265
267
|
parts.append('5')
|
|
266
|
-
if
|
|
267
|
-
parts.append('
|
|
268
|
+
if fastblink:
|
|
269
|
+
parts.append('6')
|
|
268
270
|
if reverse:
|
|
269
271
|
parts.append('7')
|
|
272
|
+
if hide:
|
|
273
|
+
parts.append('8')
|
|
274
|
+
if strike:
|
|
275
|
+
parts.append('9')
|
|
276
|
+
if overlined:
|
|
277
|
+
parts.append('53')
|
|
278
|
+
|
|
279
|
+
# Handle underline styles (mutually exclusive with priority)
|
|
280
|
+
if undercurl:
|
|
281
|
+
parts.append('4:3') # Undercurl style
|
|
282
|
+
elif underdouble:
|
|
283
|
+
parts.append('4:2') # Double underline
|
|
284
|
+
elif underdots:
|
|
285
|
+
parts.append('4:4') # Dotted underline
|
|
286
|
+
elif underdash:
|
|
287
|
+
parts.append('4:5') # Dashed underline
|
|
288
|
+
elif underline:
|
|
289
|
+
parts.append('4') # Regular underline
|
|
290
|
+
|
|
291
|
+
# Add underline color if specified (for any underline style)
|
|
292
|
+
if underline_color is not None and (underline or undercurl or underdouble or underdots or underdash):
|
|
293
|
+
# Convert underline_color to ANSI 256 color code or RGB
|
|
294
|
+
ucolor_codes = self._color_to_underline_code(underline_color)
|
|
295
|
+
if ucolor_codes:
|
|
296
|
+
parts.extend(ucolor_codes)
|
|
270
297
|
|
|
271
298
|
if parts:
|
|
272
299
|
result = '\x1b[0;' + ';'.join(parts) + 'm'
|
|
@@ -341,6 +368,41 @@ class _EscapeCodeCache(dict):
|
|
|
341
368
|
|
|
342
369
|
return map(six.text_type, result)
|
|
343
370
|
|
|
371
|
+
def _color_to_underline_code(self, color):
|
|
372
|
+
"""
|
|
373
|
+
Convert a color to ANSI underline color code (58;5;X or 58;2;R;G;B).
|
|
374
|
+
|
|
375
|
+
:param color: Color as hex string or ANSI color name
|
|
376
|
+
:return: List of ANSI code parts for underline color
|
|
377
|
+
"""
|
|
378
|
+
if color is None:
|
|
379
|
+
return []
|
|
380
|
+
|
|
381
|
+
# Handle ANSI color names
|
|
382
|
+
ansi_underline_colors = {
|
|
383
|
+
'ansiblack': 0, 'ansired': 1, 'ansigreen': 2, 'ansiyellow': 3,
|
|
384
|
+
'ansiblue': 4, 'ansifuchsia': 5, 'ansiturquoise': 6, 'ansilightgray': 7,
|
|
385
|
+
'ansidarkgray': 8, 'ansidarkred': 9, 'ansidarkgreen': 10, 'ansibrown': 11,
|
|
386
|
+
'ansidarkblue': 12, 'ansipurple': 13, 'ansiteal': 14, 'ansiwhite': 15,
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if color in ansi_underline_colors:
|
|
390
|
+
return ['58', '5', str(ansi_underline_colors[color])]
|
|
391
|
+
|
|
392
|
+
# Handle hex RGB colors
|
|
393
|
+
try:
|
|
394
|
+
rgb = self._color_name_to_rgb(color)
|
|
395
|
+
r, g, b = rgb
|
|
396
|
+
|
|
397
|
+
# True colors
|
|
398
|
+
if self.true_color:
|
|
399
|
+
return ['58', '2', str(r), str(g), str(b)]
|
|
400
|
+
# 256 colors
|
|
401
|
+
else:
|
|
402
|
+
return ['58', '5', str(_256_colors[rgb])]
|
|
403
|
+
except (ValueError, KeyError):
|
|
404
|
+
return []
|
|
405
|
+
|
|
344
406
|
|
|
345
407
|
def _get_size(fileno):
|
|
346
408
|
# Thanks to fabric (fabfile.org), and
|