Skip to content

Commit

Permalink
Merge from 5.x: PR #20167
Browse files Browse the repository at this point in the history
Fixes #19958
  • Loading branch information
ccordoba12 committed Dec 8, 2022
2 parents bd43f60 + f43d8b8 commit e7b8745
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 31 deletions.
110 changes: 80 additions & 30 deletions spyder/plugins/editor/widgets/codeeditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ def __init__(self, parent=None):
self.format_on_save = False
self.format_eventloop = QEventLoop(None)
self.format_timer = QTimer(self)
self.__cursor_position_before_format = 0

# Mouse tracking
self.setMouseTracking(True)
Expand Down Expand Up @@ -1030,8 +1031,8 @@ def setup_editor(self,

self.set_strip_mode(strip_mode)

# --- Language Server Protocol methods -----------------------------------
# ------------------------------------------------------------------------
# ---- LSP: Basic methods
# -------------------------------------------------------------------------
@Slot(str, dict)
def handle_response(self, method, params):
if method in self.handler_registry:
Expand Down Expand Up @@ -1070,7 +1071,8 @@ def log_lsp_handle_errors(self, message):
else:
logger.error('%', 1, stack_info=True)

# ------------- LSP: Configuration and protocol start/end ----------------
# ---- LSP: Configuration and start/stop
# -------------------------------------------------------------------------
def start_completion_services(self):
"""Start completion services for this instance."""
self.completions_available = True
Expand Down Expand Up @@ -1171,7 +1173,8 @@ def document_did_open(self):
}
return params

# ------------- LSP: Symbols ---------------------------------------
# ---- LSP: Symbols
# -------------------------------------------------------------------------
@schedule_request(method=CompletionRequestTypes.DOCUMENT_SYMBOL)
def request_symbols(self):
"""Request document symbols."""
Expand All @@ -1198,7 +1201,8 @@ def process_symbols(self, params):
except Exception:
self.log_lsp_handle_errors("Error when processing symbols")

# ------------- LSP: Linting ---------------------------------------
# ---- LSP: Linting and didChange
# -------------------------------------------------------------------------
def _schedule_document_did_change(self):
"""Schedule a document update."""
self._document_server_needs_update = True
Expand Down Expand Up @@ -1411,7 +1415,8 @@ def _process_code_analysis(self, underline):
)
block.setUserData(data)

# ------------- LSP: Completion ---------------------------------------
# ---- LSP: Completion
# -------------------------------------------------------------------------
@schedule_request(method=CompletionRequestTypes.DOCUMENT_COMPLETION)
def do_completion(self, automatic=False):
"""Trigger completion."""
Expand Down Expand Up @@ -1547,7 +1552,8 @@ def handle_completion_item_resolution(self, response):
self.log_lsp_handle_errors(
"Error when handling completion item resolution")

# ------------- LSP: Signature Hints ------------------------------------
# ---- LSP: Signature Hints
# -------------------------------------------------------------------------
@schedule_request(method=CompletionRequestTypes.DOCUMENT_SIGNATURE)
def request_signature(self):
"""Ask for signature."""
Expand Down Expand Up @@ -1603,7 +1609,8 @@ def process_signatures(self, params):
except Exception:
self.log_lsp_handle_errors("Error when processing signature")

# ------------- LSP: Hover/Mouse ---------------------------------------
# ---- LSP: Hover/Cursor
# -------------------------------------------------------------------------
@schedule_request(method=CompletionRequestTypes.DOCUMENT_CURSOR_EVENT)
def request_cursor_event(self):
text = self.get_text_with_eol()
Expand Down Expand Up @@ -1667,7 +1674,8 @@ def handle_hover_response(self, contents):
except Exception:
self.log_lsp_handle_errors("Error when processing hover")

# ------------- LSP: Go To Definition ----------------------------
# ---- LSP: Go To Definition
# -------------------------------------------------------------------------
@Slot()
@schedule_request(method=CompletionRequestTypes.DOCUMENT_DEFINITION)
def go_to_definition_from_cursor(self, cursor=None):
Expand Down Expand Up @@ -1719,15 +1727,22 @@ def handle_go_to_definition(self, position):
self.log_lsp_handle_errors(
"Error when processing go to definition")

# ------------- LSP: Document/Selection formatting --------------------
# ---- LSP: Document/Selection formatting
# -------------------------------------------------------------------------
def format_document_or_range(self):
"""Format current document or selected text."""
# Save current cursor position to restore it after the current text has
# been replaced by the auto-formatted one.
self.__cursor_position_before_format = self.textCursor().position()

if self.has_selected_text() and self.range_formatting_enabled:
self.format_document_range()
else:
self.format_document()

@schedule_request(method=CompletionRequestTypes.DOCUMENT_FORMATTING)
def format_document(self):
"""Format current document."""
if not self.formatting_enabled:
return
if self.formatting_in_progress:
Expand Down Expand Up @@ -1760,6 +1775,7 @@ def format_document(self):

@schedule_request(method=CompletionRequestTypes.DOCUMENT_RANGE_FORMATTING)
def format_document_range(self):
"""Format selected text."""
if not self.range_formatting_enabled or not self.has_selected_text():
return
if self.formatting_in_progress:
Expand Down Expand Up @@ -1807,6 +1823,7 @@ def format_document_range(self):

@handles(CompletionRequestTypes.DOCUMENT_FORMATTING)
def handle_document_formatting(self, edits):
"""Handle document formatting response."""
try:
if self.formatting_in_progress:
self._apply_document_edits(edits)
Expand All @@ -1828,6 +1845,7 @@ def handle_document_formatting(self, edits):

@handles(CompletionRequestTypes.DOCUMENT_RANGE_FORMATTING)
def handle_document_range_formatting(self, edits):
"""Handle document range formatting response."""
try:
if self.formatting_in_progress:
self._apply_document_edits(edits)
Expand Down Expand Up @@ -1903,16 +1921,33 @@ def _apply_document_edits(self, edits):
if merged_text is not None:
# Restore eol chars after applying edits.
merged_text = merged_text.replace('\n', self.get_line_separator())

cursor = self.textCursor()

# Begin text insertion
cursor.beginEditBlock()

# Select current text
cursor.movePosition(QTextCursor.Start)
cursor.movePosition(QTextCursor.End,
QTextCursor.KeepAnchor)

# Insert formatted text in place of the previous one
cursor.insertText(merged_text)

# Don't run the lines below when testing because they give
# segfaults.
if not running_under_pytest():
# Restore previous cursor position and center it.
# Fixes spyder-ide/spyder#19958
cursor.setPosition(self.__cursor_position_before_format)
self.setTextCursor(cursor)
self.centerCursor()

# End text insertion
cursor.endEditBlock()

# ------------- LSP: Code folding ranges -------------------------------
# ---- LSP: Code folding
# -------------------------------------------------------------------------
def compute_whitespace(self, line):
tab_size = self.tab_stop_width_spaces
whitespace_regex = re.compile(r'(\s+).*')
Expand Down Expand Up @@ -2005,7 +2040,8 @@ def finish_code_folding(self):
line, column = self.get_cursor_line_column()
self.update_whitespace_count(line, column)

# ------------- LSP: Save/close file -----------------------------------
# ---- LSP: Save/close file
# -------------------------------------------------------------------------
@schedule_request(method=CompletionRequestTypes.DOCUMENT_DID_SAVE,
requires_response=False)
def notify_save(self):
Expand Down Expand Up @@ -2046,6 +2082,9 @@ def notify_close(self):
}
return params

# ---- Debug panel
# -------------------------------------------------------------------------
# ---- Set different attributes
# -------------------------------------------------------------------------
def set_folding_panel(self, folding):
"""Enable/disable folding panel."""
Expand Down Expand Up @@ -2435,7 +2474,8 @@ def delete(self):
self.setTextCursor(cursor)
self.remove_selected_text()

#------Find occurrences
# ---- Find occurrences
# -------------------------------------------------------------------------
def __find_first(self, text):
"""Find first occurrence: scan whole document"""
flags = QTextDocument.FindCaseSensitively|QTextDocument.FindWholeWords
Expand Down Expand Up @@ -2568,7 +2608,8 @@ def mark_occurrences(self):
self.occurrences.pop(-1)
self.sig_flags_changed.emit()

#-----highlight found results (find/replace widget)
# ---- Highlight found results
# -------------------------------------------------------------------------
def highlight_found_results(self, pattern, word=False, regexp=False,
case=False):
"""Highlight all found patterns"""
Expand Down Expand Up @@ -2682,7 +2723,8 @@ def select_lines(self, linenumber_pressed, linenumber_released):

self.setTextCursor(cursor)

# ----- Code bookmarks
# ---- Code bookmarks
# -------------------------------------------------------------------------
def add_bookmark(self, slot_num, line=None, column=None):
"""Add bookmark to current block's userData."""
if line is None:
Expand Down Expand Up @@ -2731,7 +2773,8 @@ def update_bookmarks(self):
"""Emit signal to update bookmarks."""
self.sig_bookmarks_changed.emit()

# -----Code introspection
# ---- Code introspection
# -------------------------------------------------------------------------
def show_completion_object_info(self, name, signature):
"""Trigger show completion info in Help Pane."""
force = True
Expand All @@ -2742,7 +2785,8 @@ def show_object_info(self):
"""Trigger a calltip"""
self.sig_show_object_info.emit(True)

# -----blank spaces
# ---- Blank spaces
# -------------------------------------------------------------------------
def set_blanks_enabled(self, state):
"""Toggle blanks visibility"""
self.blanks_enabled = state
Expand Down Expand Up @@ -2776,7 +2820,8 @@ def showEvent(self, event):
super(CodeEditor, self).showEvent(event)
self.panels.refresh()

#-----Misc.
# ---- Misc.
# -------------------------------------------------------------------------
def _apply_highlighter_color_scheme(self):
"""Apply color scheme from syntax highlighter to the editor"""
hl = self.highlighter
Expand Down Expand Up @@ -3043,9 +3088,8 @@ def redo(self):
self.is_redoing = False
self.skip_rstrip = False

# =========================================================================
# High-level editor features
# =========================================================================
# ---- High-level editor features
# -------------------------------------------------------------------------
@Slot()
def center_cursor_on_next_focus(self):
"""QPlainTextEdit's "centerCursor" requires the widget to be visible"""
Expand Down Expand Up @@ -3083,7 +3127,6 @@ def _set_completions_hint_idle(self):
self._completions_hint_idle = True
self.completion_widget.trigger_completion_hint()

# --- Hint for completions
def show_hint_for_completion(self, word, documentation, at_point):
"""Show hint for completion element."""
if self.completions_hint and self._completions_hint_idle:
Expand Down Expand Up @@ -3302,7 +3345,8 @@ def get_cell_count(self):
"""Get number of cells in document."""
return 1 + len(list(self.cell_list()))

#------Tasks management
# ---- Tasks management
# -------------------------------------------------------------------------
def go_to_next_todo(self):
"""Go to next todo and return new cursor position"""
block = self.textCursor().block()
Expand Down Expand Up @@ -3340,7 +3384,8 @@ def process_todo(self, todo_results):
block.setUserData(data)
self.sig_flags_changed.emit()

#------Comments/Indentation
# ---- Comments/Indentation
# -------------------------------------------------------------------------
def add_prefix(self, prefix):
"""Add prefix to current line or selected line(s)"""
cursor = self.textCursor()
Expand Down Expand Up @@ -4104,10 +4149,11 @@ def __in_block_comment(cursor):
cursor3.endEditBlock()
return True

#------Kill ring handlers
# ---- Kill ring handlers
# Taken from Jupyter's QtConsole
# Copyright (c) 2001-2015, IPython Development Team
# Copyright (c) 2015-, Jupyter Development Team
# -------------------------------------------------------------------------
def kill_line_end(self):
"""Kill the text on the current line from the cursor forward"""
cursor = self.textCursor()
Expand Down Expand Up @@ -4181,7 +4227,8 @@ def kill_next_word(self):
self._kill_ring.kill_cursor(cursor)
self.setTextCursor(cursor)

#------Autoinsertion of quotes/colons
# ---- Autoinsertion of quotes/colons
# -------------------------------------------------------------------------
def __get_current_color(self, cursor=None):
"""Get the syntax highlighting color for the current cursor position"""
if cursor is None:
Expand Down Expand Up @@ -4358,7 +4405,8 @@ def in_string(self, cursor=None, position=None):
else:
return False

# ------ Qt Event handlers
# ---- Qt Event handlers
# -------------------------------------------------------------------------
def setup_context_menu(self):
"""Setup context menu"""
self.undo_action = create_action(
Expand Down Expand Up @@ -5327,7 +5375,8 @@ def _restore_editor_cursor_and_selections(self):
self._last_hover_pattern_key = None
self._last_hover_pattern_text = None

#------ Drag and drop
# ---- Drag and drop
# -------------------------------------------------------------------------
def dragEnterEvent(self, event):
"""
Reimplemented Qt method.
Expand Down Expand Up @@ -5358,7 +5407,8 @@ def dropEvent(self, event):
logger.debug("Call TextEditBaseWidget dropEvent method")
TextEditBaseWidget.dropEvent(self, event)

#------ Paint event
# ---- Paint event
# -------------------------------------------------------------------------
def paintEvent(self, event):
"""Overrides paint event to update the list of visible blocks"""
self.update_visible_blocks(event)
Expand Down
13 changes: 12 additions & 1 deletion spyder/plugins/editor/widgets/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2395,8 +2395,11 @@ def __modify_stack_title(self):

def refresh(self, index=None):
"""Refresh tabwidget"""
logger.debug("Refresh EditorStack")

if index is None:
index = self.get_stack_index()

# Set current editor
if self.get_stack_count():
index = self.get_stack_index()
Expand All @@ -2412,8 +2415,10 @@ def refresh(self, index=None):
self.update_plugin_title.emit()
else:
editor = None

# Update the modification-state-dependent parameters
self.modification_changed()

# Update FindReplace binding
self.find_widget.set_editor(editor, refresh=False)

Expand All @@ -2427,21 +2432,27 @@ def modification_changed(self, state=None, index=None, editor_id=None):
for index, _finfo in enumerate(self.data):
if id(_finfo.editor) == editor_id:
break

# This must be done before refreshing save/save all actions:
# (otherwise Save/Save all actions will always be enabled)
self.opened_files_list_changed.emit()
# --

# Get index
if index is None:
index = self.get_stack_index()

if index == -1:
return

finfo = self.data[index]
if state is None:
state = finfo.editor.document().isModified() or finfo.newly_created
self.set_stack_title(index, state)

# Toggle save/save all actions state
self.save_action.setEnabled(state)
self.refresh_save_all_action.emit()

# Refreshing eol mode
eol_chars = finfo.editor.get_line_separator()
self.refresh_eol_chars(eol_chars)
Expand Down

0 comments on commit e7b8745

Please sign in to comment.