From ef993ecb3198fbf93b3d91b6f2e82a4040e38585 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Fri, 7 Jan 2022 14:04:41 -0500 Subject: [PATCH 1/4] Add a function to detect the eol chars used in a text --- pylsp/_utils.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pylsp/_utils.py b/pylsp/_utils.py index 9ac30cfc..2a0a5b25 100644 --- a/pylsp/_utils.py +++ b/pylsp/_utils.py @@ -12,6 +12,9 @@ JEDI_VERSION = jedi.__version__ +# Eol chars accepted by the LSP protocol +EOL_CHARS = ['\r\n', '\r', '\n'] + log = logging.getLogger(__name__) @@ -220,3 +223,13 @@ def is_process_alive(pid): return e.errno == errno.EPERM else: return True + + +def get_eol_chars(text): + """Get EOL chars used in text.""" + for eol_chars in EOL_CHARS: + if text.find(eol_chars) > -1: + break + else: + return None + return eol_chars From 79979f56a12483cb4e3694151ab6572cc094b19c Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Fri, 7 Jan 2022 14:37:43 -0500 Subject: [PATCH 2/4] Fix autopep8 and yapf formatting with CR line endings --- pylsp/plugins/autopep8_format.py | 19 +++++++++++++++++-- pylsp/plugins/yapf_format.py | 17 ++++++++++++++++- test/plugins/test_autopep8_format.py | 7 +++++++ test/plugins/test_yapf_format.py | 7 +++++++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/pylsp/plugins/autopep8_format.py b/pylsp/plugins/autopep8_format.py index f62443f6..8915fb72 100644 --- a/pylsp/plugins/autopep8_format.py +++ b/pylsp/plugins/autopep8_format.py @@ -2,9 +2,12 @@ # Copyright 2021- Python Language Server Contributors. import logging + import pycodestyle from autopep8 import fix_code, continued_indentation as autopep8_c_i + from pylsp import hookimpl +from pylsp._utils import get_eol_chars log = logging.getLogger(__name__) @@ -38,15 +41,27 @@ def _format(config, document, line_range=None): del pycodestyle._checks['logical_line'][pycodestyle.continued_indentation] pycodestyle.register_check(autopep8_c_i) - new_source = fix_code(document.source, options=options) + # Autopep8 doesn't work with CR line endings, so we replace them by '\n' + # and restore them below. + replace_cr = False + source = document.source + eol_chars = get_eol_chars(source) + if eol_chars == '\r': + replace_cr = True + source = source.replace('\r', '\n') + + new_source = fix_code(source, options=options) # Switch it back del pycodestyle._checks['logical_line'][autopep8_c_i] pycodestyle.register_check(pycodestyle.continued_indentation) - if new_source == document.source: + if new_source == source: return [] + if replace_cr: + new_source = new_source.replace('\n', '\r') + # I'm too lazy at the moment to parse diffs into TextEdit items # So let's just return the entire file... return [{ diff --git a/pylsp/plugins/yapf_format.py b/pylsp/plugins/yapf_format.py index 6728007b..1c90f965 100644 --- a/pylsp/plugins/yapf_format.py +++ b/pylsp/plugins/yapf_format.py @@ -3,9 +3,12 @@ import logging import os + from yapf.yapflib import file_resources from yapf.yapflib.yapf_api import FormatCode + from pylsp import hookimpl +from pylsp._utils import get_eol_chars log = logging.getLogger(__name__) @@ -34,8 +37,17 @@ def pylsp_format_range(document, range): # pylint: disable=redefined-builtin def _format(document, lines=None): + # Yapf doesn't work with CR line endings, so we replace them by '\n' + # and restore them below. + replace_cr = False + source = document.source + eol_chars = get_eol_chars(source) + if eol_chars == '\r': + replace_cr = True + source = source.replace('\r', '\n') + new_source, changed = FormatCode( - document.source, + source, lines=lines, filename=document.filename, style_config=file_resources.GetDefaultStyleForDir( @@ -46,6 +58,9 @@ def _format(document, lines=None): if not changed: return [] + if replace_cr: + new_source = new_source.replace('\n', '\r') + # I'm too lazy at the moment to parse diffs into TextEdit items # So let's just return the entire file... return [{ diff --git a/test/plugins/test_autopep8_format.py b/test/plugins/test_autopep8_format.py index cfb7bb60..1e790aaa 100644 --- a/test/plugins/test_autopep8_format.py +++ b/test/plugins/test_autopep8_format.py @@ -71,3 +71,10 @@ def test_hanging_indentation(config, workspace): assert len(res) == 1 assert res[0]['newText'] == CORRECT_INDENTED_DOC + + +def test_cr_line_endings(config, workspace): + doc = Document(DOC_URI, workspace, 'import os;import sys\r\rdict(a=1)') + res = pylsp_format_document(config, doc) + + assert res[0]['newText'] == 'import os\rimport sys\r\rdict(a=1)\r' diff --git a/test/plugins/test_yapf_format.py b/test/plugins/test_yapf_format.py index 90410432..4346985c 100644 --- a/test/plugins/test_yapf_format.py +++ b/test/plugins/test_yapf_format.py @@ -58,3 +58,10 @@ def test_config_file(tmpdir, workspace): # A was split on multiple lines because of column_limit from config file assert pylsp_format_document(doc)[0]['newText'] == "A = [\n 'h', 'w',\n 'a'\n]\n\nB = ['h', 'w']\n" + + +def test_cr_line_endings(workspace): + doc = Document(DOC_URI, workspace, 'import os;import sys\r\rdict(a=1)') + res = pylsp_format_document(doc) + + assert res[0]['newText'] == 'import os\rimport sys\r\rdict(a=1)\r' From 7c86ad7ca9c08f76349a488781d6428f139ee45e Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 8 Jan 2022 13:52:55 -0500 Subject: [PATCH 3/4] Improve performance of get_eol_chars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: MichaƂ Krassowski <5832902+krassowski@users.noreply.github.com> --- pylsp/_utils.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pylsp/_utils.py b/pylsp/_utils.py index 2a0a5b25..35217897 100644 --- a/pylsp/_utils.py +++ b/pylsp/_utils.py @@ -225,11 +225,13 @@ def is_process_alive(pid): return True +import re + +EOL_REGEX = re.compile(f'({"|".join(EOL_CHARS)})') + def get_eol_chars(text): """Get EOL chars used in text.""" - for eol_chars in EOL_CHARS: - if text.find(eol_chars) > -1: - break - else: - return None - return eol_chars + match = EOL_REGEX.search(text) + if match: + return match.group(0) + return None From 8bc1a20d910c6e3bb948fa104907504d5997e08f Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 8 Jan 2022 13:55:57 -0500 Subject: [PATCH 4/4] Fix style issues --- pylsp/_utils.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pylsp/_utils.py b/pylsp/_utils.py index 35217897..0732067a 100644 --- a/pylsp/_utils.py +++ b/pylsp/_utils.py @@ -6,6 +6,7 @@ import logging import os import pathlib +import re import threading import jedi @@ -14,6 +15,7 @@ # Eol chars accepted by the LSP protocol EOL_CHARS = ['\r\n', '\r', '\n'] +EOL_REGEX = re.compile(f'({"|".join(EOL_CHARS)})') log = logging.getLogger(__name__) @@ -225,10 +227,6 @@ def is_process_alive(pid): return True -import re - -EOL_REGEX = re.compile(f'({"|".join(EOL_CHARS)})') - def get_eol_chars(text): """Get EOL chars used in text.""" match = EOL_REGEX.search(text)