From 0622b039cc0d628fa44f3f1f5c2665d7f2050d7e Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Sat, 18 Sep 2021 14:33:43 -0700 Subject: [PATCH 1/4] * Add jellyfish package which provides optimized algorithms for textdistance * Change algorithm from jaccard to hamming * 1000x performance improvement for code folding and indent guides --- binder/environment.yml | 1 + requirements/conda.txt | 1 + setup.py | 1 + spyder/dependencies.py | 5 +++++ spyder/plugins/editor/panels/utils.py | 2 +- 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/binder/environment.yml b/binder/environment.yml index 6e8ecd0b1d6..5ce8931ca5d 100644 --- a/binder/environment.yml +++ b/binder/environment.yml @@ -15,6 +15,7 @@ dependencies: - intervaltree >=3.0.2 - ipython >=7.6.0 - jedi >=0.17.2,<0.19.0 +- jellyfish >=0.7 - jsonschema >=3.2.0 - keyring >=17.0.0 - nbconvert >=4.0 diff --git a/requirements/conda.txt b/requirements/conda.txt index f159accc689..93a0b15132f 100644 --- a/requirements/conda.txt +++ b/requirements/conda.txt @@ -11,6 +11,7 @@ diff-match-patch >=20181111 intervaltree >=3.0.2 IPython >=7.6.0 jedi >=0.17.2,<0.19.0 +jellyfish >=0.7 jsonschema >=3.2.0 keyring >=17.0.0 nbconvert >=4.0 diff --git a/setup.py b/setup.py index c45817dfe6b..f81c314df28 100644 --- a/setup.py +++ b/setup.py @@ -210,6 +210,7 @@ def run(self): 'intervaltree>=3.0.2', 'ipython>=7.6.0', 'jedi>=0.17.2,<0.19.0', + 'jellyfish>=0.7', 'jsonschema>=3.2.0', 'keyring>=17.0.0', 'nbconvert>=4.0', diff --git a/spyder/dependencies.py b/spyder/dependencies.py index 8e3af788e6d..0fd2a70f775 100644 --- a/spyder/dependencies.py +++ b/spyder/dependencies.py @@ -41,6 +41,7 @@ INTERVALTREE_REQVER = None if is_pynsist() else '>=3.0.2' IPYTHON_REQVER = ">=7.6.0" JEDI_REQVER = '>=0.17.2;<0.19.0' +JELLYFISH_REQVER = '>=0.7' JSONSCHEMA_REQVER = '>=3.2.0' KEYRING_REQVER = '>=17.0.0' NBCONVERT_REQVER = '>=4.0' @@ -127,6 +128,10 @@ 'package_name': "jedi", 'features': _("Main backend for the Python Language Server"), 'required_version': JEDI_REQVER}, + {'modname': "jellyfish", + 'package_name': "jellyfish", + 'features': _("Optimize algorithms for textdistance"), + 'required_version': JELLYFISH_REQVER}, {'modname': 'jsonschema', 'package_name': 'jsonschema', 'features': _('Verify if snippets files are valid'), diff --git a/spyder/plugins/editor/panels/utils.py b/spyder/plugins/editor/panels/utils.py index aff64782e2e..9f058b25f4a 100644 --- a/spyder/plugins/editor/panels/utils.py +++ b/spyder/plugins/editor/panels/utils.py @@ -157,7 +157,7 @@ def merge_folding(ranges, current_tree, root): while deleted_entry is not None and changed_entry is not None: deleted_entry_i = deleted_entry.data changed_entry_i = changed_entry.data - dist = textdistance.jaccard.normalized_similarity( + dist = textdistance.hamming.normalized_similarity( deleted_entry_i.text, changed_entry_i.text) if dist >= 0.80: From 80b9d450595ce80ea2c21c0aaaeffa8c0c20def9 Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Sat, 18 Sep 2021 15:11:45 -0700 Subject: [PATCH 2/4] * Set single timeout for syncing symbols and folding --- spyder/plugins/editor/widgets/codeeditor.py | 35 +++------------------ spyder/plugins/editor/widgets/editor.py | 1 - 2 files changed, 5 insertions(+), 31 deletions(-) diff --git a/spyder/plugins/editor/widgets/codeeditor.py b/spyder/plugins/editor/widgets/codeeditor.py index 05fe95e9eb9..a453d194e0e 100644 --- a/spyder/plugins/editor/widgets/codeeditor.py +++ b/spyder/plugins/editor/widgets/codeeditor.py @@ -134,14 +134,8 @@ class CodeEditor(TextEditBaseWidget): UPDATE_DECORATIONS_TIMEOUT = 500 # milliseconds # Timeouts (in milliseconds) to sychronize symbols and folding after - # linting results arrive, according to the number of lines in the file. - SYNC_SYMBOLS_AND_FOLDING_TIMEOUTS = { - # Lines: Timeout - 500: 350, - 1500: 800, - 2500: 1200, - 6500: 1800 - } + # linting results arrive + SYNC_SYMBOLS_AND_FOLDING_TIMEOUT = 500 # milliseconds # Custom signal to be emitted upon completion of the editor's paintEvent painted = Signal(QPaintEvent) @@ -310,10 +304,10 @@ def __init__(self, parent=None): # See: process_diagnostics self._timer_sync_symbols_and_folding = QTimer(self) self._timer_sync_symbols_and_folding.setSingleShot(True) + self._timer_sync_symbols_and_folding.setInterval( + self.SYNC_SYMBOLS_AND_FOLDING_TIMEOUT) self._timer_sync_symbols_and_folding.timeout.connect( self.sync_symbols_and_folding) - self.blockCountChanged.connect( - self.set_sync_symbols_and_folding_timeout) # Goto uri self._last_hover_pattern_key = None @@ -1182,25 +1176,6 @@ def process_diagnostics(self, params): # Process results (runs in a thread) self.process_code_analysis(params['params']) - def set_sync_symbols_and_folding_timeout(self): - """ - Set timeout to sync symbols and folding according to the file - size. - """ - current_lines = self.get_line_count() - timeout = None - - for lines in self.SYNC_SYMBOLS_AND_FOLDING_TIMEOUTS.keys(): - if (current_lines // lines) == 0: - timeout = self.SYNC_SYMBOLS_AND_FOLDING_TIMEOUTS[lines] - break - - if not timeout: - timeouts = self.SYNC_SYMBOLS_AND_FOLDING_TIMEOUTS.values() - timeout = list(timeouts)[-1] - - self._timer_sync_symbols_and_folding.setInterval(timeout) - def sync_symbols_and_folding(self): """ Synchronize symbols and folding after linting results arrive. @@ -2880,7 +2855,7 @@ def paste(self): if indentations: max_dedent = min(indentations) lines_adjustment = max(lines_adjustment, -max_dedent) - + # Get new text remaining_lines = [ self.adjust_indentation(line, lines_adjustment) diff --git a/spyder/plugins/editor/widgets/editor.py b/spyder/plugins/editor/widgets/editor.py index eefc83c3402..8025e02c031 100644 --- a/spyder/plugins/editor/widgets/editor.py +++ b/spyder/plugins/editor/widgets/editor.py @@ -2632,7 +2632,6 @@ def load(self, filename, set_current=True, add_where='end', self.set_os_eol_chars(index) self.is_analysis_done = False self.analyze_script(index) - finfo.editor.set_sync_symbols_and_folding_timeout() return finfo def set_os_eol_chars(self, index=None, osname=None): From 4719770dc88912d76e2387f3a265341ceb9c58b8 Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Mon, 27 Sep 2021 08:28:01 -0700 Subject: [PATCH 3/4] * Address review comment --- spyder/dependencies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spyder/dependencies.py b/spyder/dependencies.py index 0fd2a70f775..61576fd8242 100644 --- a/spyder/dependencies.py +++ b/spyder/dependencies.py @@ -130,7 +130,7 @@ 'required_version': JEDI_REQVER}, {'modname': "jellyfish", 'package_name': "jellyfish", - 'features': _("Optimize algorithms for textdistance"), + 'features': _("Optimize algorithms for folding"), 'required_version': JELLYFISH_REQVER}, {'modname': 'jsonschema', 'package_name': 'jsonschema', From 410ef6c060be4da753b756982e2842967d4b6169 Mon Sep 17 00:00:00 2001 From: Ryan Clary Date: Mon, 27 Sep 2021 08:47:00 -0700 Subject: [PATCH 4/4] Revert "* Set single timeout for syncing symbols and folding" This reverts commit ab9bd39785bf3947e9df592a8030348e90442c57. --- spyder/plugins/editor/widgets/codeeditor.py | 35 ++++++++++++++++++--- spyder/plugins/editor/widgets/editor.py | 1 + 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/spyder/plugins/editor/widgets/codeeditor.py b/spyder/plugins/editor/widgets/codeeditor.py index a453d194e0e..05fe95e9eb9 100644 --- a/spyder/plugins/editor/widgets/codeeditor.py +++ b/spyder/plugins/editor/widgets/codeeditor.py @@ -134,8 +134,14 @@ class CodeEditor(TextEditBaseWidget): UPDATE_DECORATIONS_TIMEOUT = 500 # milliseconds # Timeouts (in milliseconds) to sychronize symbols and folding after - # linting results arrive - SYNC_SYMBOLS_AND_FOLDING_TIMEOUT = 500 # milliseconds + # linting results arrive, according to the number of lines in the file. + SYNC_SYMBOLS_AND_FOLDING_TIMEOUTS = { + # Lines: Timeout + 500: 350, + 1500: 800, + 2500: 1200, + 6500: 1800 + } # Custom signal to be emitted upon completion of the editor's paintEvent painted = Signal(QPaintEvent) @@ -304,10 +310,10 @@ def __init__(self, parent=None): # See: process_diagnostics self._timer_sync_symbols_and_folding = QTimer(self) self._timer_sync_symbols_and_folding.setSingleShot(True) - self._timer_sync_symbols_and_folding.setInterval( - self.SYNC_SYMBOLS_AND_FOLDING_TIMEOUT) self._timer_sync_symbols_and_folding.timeout.connect( self.sync_symbols_and_folding) + self.blockCountChanged.connect( + self.set_sync_symbols_and_folding_timeout) # Goto uri self._last_hover_pattern_key = None @@ -1176,6 +1182,25 @@ def process_diagnostics(self, params): # Process results (runs in a thread) self.process_code_analysis(params['params']) + def set_sync_symbols_and_folding_timeout(self): + """ + Set timeout to sync symbols and folding according to the file + size. + """ + current_lines = self.get_line_count() + timeout = None + + for lines in self.SYNC_SYMBOLS_AND_FOLDING_TIMEOUTS.keys(): + if (current_lines // lines) == 0: + timeout = self.SYNC_SYMBOLS_AND_FOLDING_TIMEOUTS[lines] + break + + if not timeout: + timeouts = self.SYNC_SYMBOLS_AND_FOLDING_TIMEOUTS.values() + timeout = list(timeouts)[-1] + + self._timer_sync_symbols_and_folding.setInterval(timeout) + def sync_symbols_and_folding(self): """ Synchronize symbols and folding after linting results arrive. @@ -2855,7 +2880,7 @@ def paste(self): if indentations: max_dedent = min(indentations) lines_adjustment = max(lines_adjustment, -max_dedent) - + # Get new text remaining_lines = [ self.adjust_indentation(line, lines_adjustment) diff --git a/spyder/plugins/editor/widgets/editor.py b/spyder/plugins/editor/widgets/editor.py index 8025e02c031..eefc83c3402 100644 --- a/spyder/plugins/editor/widgets/editor.py +++ b/spyder/plugins/editor/widgets/editor.py @@ -2632,6 +2632,7 @@ def load(self, filename, set_current=True, add_where='end', self.set_os_eol_chars(index) self.is_analysis_done = False self.analyze_script(index) + finfo.editor.set_sync_symbols_and_folding_timeout() return finfo def set_os_eol_chars(self, index=None, osname=None):