def _on_key_pressed(self, event): """ Override key press to select the current scope if the user wants to deleted a folded scope (without selecting it). """ delete_request = event.key() in [Qt.Key_Backspace, Qt.Key_Delete] if event.text() or delete_request: cursor = self.editor.textCursor() if cursor.hasSelection(): # change selection to encompass the whole scope. positions_to_check = cursor.selectionStart( ), cursor.selectionEnd() else: positions_to_check = (cursor.position(), ) for pos in positions_to_check: block = self.editor.document().findBlock(pos) th = TextBlockHelper() if th.is_fold_trigger(block) and th.is_collapsed(block): self.toggle_fold_trigger(block) if delete_request and cursor.hasSelection(): scope = FoldScope(self.find_parent_scope(block)) tc = TextHelper( self.editor).select_lines(*scope.get_range()) if tc.selectionStart() > cursor.selectionStart(): start = cursor.selectionStart() else: start = tc.selectionStart() if tc.selectionEnd() < cursor.selectionEnd(): end = cursor.selectionEnd() else: end = tc.selectionEnd() tc.setPosition(start) tc.setPosition(end, tc.KeepAnchor) self.editor.setTextCursor(tc)
def mouseMoveEvent(self, event): """ Detect mouser over indicator and highlight the current scope in the editor (up and down decoration arround the foldable text when the mouse is over an indicator). :param event: event """ super(FoldingPanel, self).mouseMoveEvent(event) th = TextHelper(self.editor) line = th.line_nbr_from_position(event.pos().y()) if line >= 0: block = self.editor.document().findBlockByNumber(line) block = self.find_parent_scope(block) line_number = block.blockNumber() if line_number in self.folding_regions: if self._mouse_over_line is None: # mouse enter fold scope QApplication.setOverrideCursor( QCursor(Qt.PointingHandCursor)) if (self._mouse_over_line != block.blockNumber() and self._mouse_over_line is not None): # fold scope changed, a previous block was highlighter so # we quickly update our highlighting self._mouse_over_line = block.blockNumber() try: self._highlight_block(block) except KeyError: # Catching the KeyError above is necessary to avoid # issue spyder-ide/spyder#13230. pass else: # same fold scope, request highlight self._mouse_over_line = block.blockNumber() try: self._highlight_runner.request_job( self._highlight_block, block) except KeyError: # Catching the KeyError above is necessary to avoid # issue spyder-ide/spyder#11291. pass self._highight_block = block else: # no fold scope to highlight, cancel any pending requests self._highlight_runner.cancel_requests() self._mouse_over_line = None QApplication.restoreOverrideCursor() self.repaint()
def find(self, changed=True, forward=True, rehighlight=True, start_highlight_timer=False, multiline_replace_check=True): """Call the find function""" # When several lines are selected in the editor and replace box is # activated, dynamic search is deactivated to prevent changing the # selection. Otherwise we show matching items. if multiline_replace_check and self.replace_widgets[0].isVisible(): sel_text = self.editor.get_selected_text() if len(to_text_string(sel_text).splitlines()) > 1: return None text = self.search_text.currentText() if len(text) == 0: self.search_text.lineEdit().setStyleSheet("") if not self.is_code_editor: # Clears the selection for WebEngine self.editor.find_text('') self.change_number_matches() return None else: case = self.case_button.isChecked() word = self.words_button.isChecked() regexp = self.re_button.isChecked() found = self.editor.find_text(text, changed, forward, case=case, word=word, regexp=regexp) stylesheet = self.STYLE[found] tooltip = self.TOOLTIP[found] if not found and regexp: error_msg = regexp_error_msg(text) if error_msg: # special styling for regexp errors stylesheet = self.STYLE['regexp_error'] tooltip = self.TOOLTIP['regexp_error'] + ': ' + error_msg self.search_text.lineEdit().setStyleSheet(stylesheet) self.search_text.setToolTip(tooltip) if self.is_code_editor and found: cursor = QTextCursor(self.editor.textCursor()) TextHelper(self.editor).unfold_if_colapsed(cursor) if rehighlight or not self.editor.found_results: self.highlight_timer.stop() if start_highlight_timer: self.highlight_timer.start() else: self.highlight_matches() else: self.clear_matches() number_matches = self.editor.get_number_matches(text, case=case, regexp=regexp, word=word) if hasattr(self.editor, 'get_match_number'): match_number = self.editor.get_match_number(text, case=case, regexp=regexp, word=word) else: match_number = 0 self.change_number_matches(current_match=match_number, total_matches=number_matches) return found
def test_close_brackets(qtbot, editor_close_brackets, text, expected_text, cursor_column): """Test insertion of brackets.""" editor = editor_close_brackets qtbot.keyClicks(editor, text) assert editor.toPlainText() == expected_text assert cursor_column == TextHelper(editor).current_column_nbr()
def _on_key_pressed(self, event): """ Override key press to select the current scope if the user wants to deleted a folded scope (without selecting it). """ delete_request = event.key() in {Qt.Key_Delete, Qt.Key_Backspace} cursor = self.editor.textCursor() if cursor.hasSelection(): if event.key() == Qt.Key_Return: delete_request = True if event.text() or delete_request: self._key_pressed = True if cursor.hasSelection(): # change selection to encompass the whole scope. positions_to_check = (cursor.selectionStart(), cursor.selectionEnd()) else: positions_to_check = (cursor.position(), ) for pos in positions_to_check: block = self.editor.document().findBlock(pos) start_line = block.blockNumber() + 2 if (start_line in self.folding_regions and self.folding_status[start_line]): end_line = self.folding_regions[start_line] if delete_request and cursor.hasSelection(): tc = TextHelper(self.editor).select_lines( start_line, end_line) if tc.selectionStart() > cursor.selectionStart(): start = cursor.selectionStart() else: start = tc.selectionStart() if tc.selectionEnd() < cursor.selectionEnd(): end = cursor.selectionEnd() else: end = tc.selectionEnd() tc.setPosition(start) tc.setPosition(end, tc.KeepAnchor) self.editor.setTextCursor(tc) self._key_pressed = False
def _draw_fold_region_background(self, block, painter): """ Draw the fold region when the mouse is over and non collapsed indicator. :param top: Top position :param block: Current block. :param painter: QPainter """ th = TextHelper(self.editor) start = block.blockNumber() end = self.folding_regions[start] if start > 0: top = th.line_pos_from_number(start) else: top = 0 bottom = th.line_pos_from_number(end) h = bottom - top if h == 0: h = self.sizeHint().height() w = self.sizeHint().width() self._draw_rect(QRectF(0, top, w, h), painter)
def _draw_fold_region_background(self, block, painter): """ Draw the fold region when the mouse is over and non collapsed indicator. :param top: Top position :param block: Current block. :param painter: QPainter """ r = FoldScope(block) th = TextHelper(self.editor) start, end = r.get_range(ignore_blank_lines=True) if start > 0: top = th.line_pos_from_number(start) else: top = 0 bottom = th.line_pos_from_number(end + 1) h = bottom - top if h == 0: h = self.sizeHint().height() w = self.sizeHint().width() self._draw_rect(QRectF(0, top, w, h), painter)
def test_nested_brackets(qtbot, editor_close_brackets, text, expected_text, cursor_column): """ Test completion of brackets inside brackets and before commas, colons and semi-colons. """ editor = editor_close_brackets qtbot.keyClicks(editor, text) editor.move_cursor(-1) qtbot.keyClicks(editor, '(') assert editor.toPlainText() == expected_text assert cursor_column == TextHelper(editor).current_column_nbr()
def test_trailing_text(qtbot, editor_close_quotes, text, expected_text, cursor_column): """ Test insertion of extra quotes inside brackets and before commas, colons and semi-colons. """ editor = editor_close_quotes qtbot.keyClicks(editor, text) editor.move_cursor(-1) qtbot.keyClicks(editor, '"') assert editor.toPlainText() == expected_text assert cursor_column == TextHelper(editor).current_column_nbr()
def mouseMoveEvent(self, event): """ Detect mouser over indicator and highlight the current scope in the editor (up and down decoration arround the foldable text when the mouse is over an indicator). :param event: event """ super(FoldingPanel, self).mouseMoveEvent(event) th = TextHelper(self.editor) line = th.line_nbr_from_position(event.pos().y()) if line >= 0: block = FoldScope.find_parent_scope( self.editor.document().findBlockByNumber(line - 1)) if TextBlockHelper.is_fold_trigger(block): if self._mouse_over_line is None: # mouse enter fold scope QApplication.setOverrideCursor( QCursor(Qt.PointingHandCursor)) if self._mouse_over_line != block.blockNumber() and \ self._mouse_over_line is not None: # fold scope changed, a previous block was highlighter so # we quickly update our highlighting self._mouse_over_line = block.blockNumber() self._highlight_block(block) else: # same fold scope, request highlight self._mouse_over_line = block.blockNumber() self._highlight_runner.request_job(self._highlight_block, block) self._highight_block = block else: # no fold scope to highlight, cancel any pending requests self._highlight_runner.cancel_requests() self._mouse_over_line = None QApplication.restoreOverrideCursor() self.repaint()
def _refresh_editor_and_scrollbars(self): """ Refrehes editor content and scollbars. We generate a fake resize event to refresh scroll bar. We have the same problem as described here: http://www.qtcentre.org/threads/44803 and we apply the same solution (don't worry, there is no visual effect, the editor does not grow up at all, even with a value = 500) """ TextHelper(self.editor).mark_whole_doc_dirty() self.editor.repaint() s = self.editor.size() s.setWidth(s.width() + 1) self.editor.resizeEvent(QResizeEvent(self.editor.size(), s))