From 719a83584fe54eed56df3878c12b6c47a54f06e2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 21 Nov 2014 14:39:13 +0530 Subject: [PATCH] Move the python editing key handling into the python smarts module so that it is available for all text edit instances --- .../gui2/tweak_book/editor/smart/python.py | 92 +++++++++++++++++++ src/calibre/gui2/tweak_book/editor/text.py | 7 +- .../gui2/tweak_book/function_replace.py | 79 +--------------- 3 files changed, 98 insertions(+), 80 deletions(-) create mode 100644 src/calibre/gui2/tweak_book/editor/smart/python.py diff --git a/src/calibre/gui2/tweak_book/editor/smart/python.py b/src/calibre/gui2/tweak_book/editor/smart/python.py new file mode 100644 index 0000000000..f785484644 --- /dev/null +++ b/src/calibre/gui2/tweak_book/editor/smart/python.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +from __future__ import (unicode_literals, division, absolute_import, + print_function) + +__license__ = 'GPL v3' +__copyright__ = '2014, Kovid Goyal ' + +import re + +from PyQt5.Qt import Qt + +from calibre.gui2.tweak_book.editor.smart import NullSmarts + +def get_text_before_cursor(editor): + cursor = editor.textCursor() + cursor.clearSelection() + cursor.movePosition(cursor.StartOfLine, cursor.KeepAnchor) + text = cursor.selectedText() + return cursor, text + +def expand_tabs(text): + return text.replace('\t', ' '*4) + +def get_leading_whitespace_on_line(editor, previous=False): + cursor = editor.textCursor() + block = cursor.block() + if previous: + block = block.previous() + if block.isValid(): + text = block.text() + ntext = text.lstrip() + return expand_tabs(text[:len(text)-len(ntext)]) + return '' + +class Smarts(NullSmarts): + + def handle_key_press(self, ev, editor): + key = ev.key() + + if key == Qt.Key_Tab: + cursor, text = get_text_before_cursor(editor) + if not text.lstrip(): + # cursor is preceded by whitespace + text = expand_tabs(text) + spclen = len(text) - (len(text) % 4) + 4 + cursor.insertText(' ' * spclen) + editor.setTextCursor(cursor) + else: + cursor = editor.textCursor() + cursor.insertText(' ' * 4) + editor.setTextCursor(cursor) + return True + + elif key == Qt.Key_Backspace: + cursor, text = get_text_before_cursor(editor) + if text and not text.lstrip(): + # cursor is preceded by whitespace + text = expand_tabs(text) + spclen = max(0, len(text) - (len(text) % 4) - 4) + cursor.insertText(' ' * spclen) + editor.setTextCursor(cursor) + return True + + elif key in (Qt.Key_Enter, Qt.Key_Return): + ls = get_leading_whitespace_on_line(editor) + cursor = editor.textCursor() + line = cursor.block().text() + if line.rstrip().endswith(':'): + ls += ' ' * 4 + elif re.match(r'\s+(continue|break|return|pass)(\s|$)', line) is not None: + ls = ls[:-4] + cursor.insertText('\n' + ls) + editor.setTextCursor(cursor) + return True + + elif key == Qt.Key_Colon: + cursor, text = get_text_before_cursor(editor) + if re.match(r'\s+(else|elif|except)(\(|\s|$)', text) is not None: + ls = get_leading_whitespace_on_line(editor) + pls = get_leading_whitespace_on_line(editor, previous=True) + if ls and ls >= pls: + ls = ls[:-4] + text = ls + text.lstrip() + ':' + cursor.insertText(text) + editor.setTextCursor(cursor) + return True + +if __name__ == '__main__': + import os + from calibre.gui2.tweak_book.editor.widget import launch_editor + launch_editor(os.path.abspath(__file__), syntax='python') diff --git a/src/calibre/gui2/tweak_book/editor/text.py b/src/calibre/gui2/tweak_book/editor/text.py index 1653ac26d6..e5d2517cb9 100644 --- a/src/calibre/gui2/tweak_book/editor/text.py +++ b/src/calibre/gui2/tweak_book/editor/text.py @@ -139,6 +139,7 @@ class TextEdit(PlainTextEdit): self.gutter_width = 0 self.expected_geometry = expected_geometry self.saved_matches = {} + self.syntax = None self.smarts = NullSmarts(self) self.current_cursor_line = None self.current_search_mark = None @@ -151,7 +152,6 @@ class TextEdit(PlainTextEdit): self.cursorPositionChanged.connect(self.highlight_cursor_line) self.blockCountChanged[int].connect(self.update_line_number_area_width) self.updateRequest.connect(self.update_line_number_area) - self.syntax = None @dynamic_property def is_modified(self): @@ -173,7 +173,8 @@ class TextEdit(PlainTextEdit): self.apply_theme(theme) w = self.fontMetrics() self.space_width = w.width(' ') - self.setTabStopWidth(prefs['editor_tab_stop_width'] * self.space_width) + tw = 4 if self.syntax == 'python' else prefs['editor_tab_stop_width'] + self.setTabStopWidth(tw * self.space_width) if dictionaries_changed: self.highlighter.rehighlight() @@ -223,6 +224,8 @@ class TextEdit(PlainTextEdit): if process_template and QPlainTextEdit.find(self, '%CURSOR%'): c = self.textCursor() c.insertText('') + if syntax == 'python': + self.setTabStopWidth(4 * self.space_width) def change_document_name(self, newname): self.highlighter.doc_name = newname diff --git a/src/calibre/gui2/tweak_book/function_replace.py b/src/calibre/gui2/tweak_book/function_replace.py index 32fefc051d..984bacbd55 100644 --- a/src/calibre/gui2/tweak_book/function_replace.py +++ b/src/calibre/gui2/tweak_book/function_replace.py @@ -198,83 +198,6 @@ class FunctionBox(EditWithComplete): menu.addAction(_('Show saved searches'), self.show_saved_searches.emit) menu.exec_(event.globalPos()) -class PythonEdit(TextEdit): - - def apply_settings(self, *args, **kwargs): - TextEdit.apply_settings(self, *args, **kwargs) - self.setTabStopWidth(4 * self.space_width) - - def keyPressEvent(self, ev): - key = ev.key() - - def expand_tabs(text): - return text.replace('\t', ' '*4) - - def get_text_before_cursor(): - cursor = self.textCursor() - cursor.clearSelection() - cursor.movePosition(cursor.StartOfLine, cursor.KeepAnchor) - text = cursor.selectedText() - return cursor, text - - def get_leading_whitespace_on_line(previous=False): - cursor = self.textCursor() - block = cursor.block() - if previous: - block = block.previous() - if block.isValid(): - text = block.text() - ntext = text.lstrip() - return expand_tabs(text[:len(text)-len(ntext)]) - return '' - - if key == Qt.Key_Tab: - cursor, text = get_text_before_cursor() - if not text.lstrip(): - # cursor is preceded by whitespace - text = expand_tabs(text) - spclen = len(text) - (len(text) % 4) + 4 - cursor.insertText(' ' * spclen) - self.setTextCursor(cursor) - return - else: - cursor = self.textCursor() - cursor.insertText(' ' * 4) - self.setTextCursor(cursor) - elif key == Qt.Key_Backspace: - cursor, text = get_text_before_cursor() - if text and not text.lstrip(): - # cursor is preceded by whitespace - text = expand_tabs(text) - spclen = max(0, len(text) - (len(text) % 4) - 4) - cursor.insertText(' ' * spclen) - self.setTextCursor(cursor) - return - elif key in (Qt.Key_Enter, Qt.Key_Return): - ls = get_leading_whitespace_on_line() - cursor = self.textCursor() - line = cursor.block().text() - if line.rstrip().endswith(':'): - ls += ' ' * 4 - elif re.match(r'\s+(continue|break|return|pass)(\s|$)', line) is not None: - ls = ls[:-4] - cursor.insertText('\n' + ls) - self.setTextCursor(cursor) - return - elif key == Qt.Key_Colon: - cursor, text = get_text_before_cursor() - if re.match(r'\s+(else|elif|except)(\(|\s|$)', text) is not None: - ls = get_leading_whitespace_on_line() - pls = get_leading_whitespace_on_line(previous=True) - if ls and ls >= pls: - ls = ls[:-4] - text = ls + text.lstrip() + ':' - cursor.insertText(text) - self.setTextCursor(cursor) - return - - TextEdit.keyPressEvent(self, ev) - class FunctionEditor(Dialog): def __init__(self, func_name='', parent=None): @@ -293,7 +216,7 @@ class FunctionEditor(Dialog): h.addWidget(fb, stretch=10) self.la3 = la = QLabel(_('&Code:')) - self.source_code = PythonEdit(self) + self.source_code = TextEdit(self) self.source_code.load_text('', 'python') la.setBuddy(self.source_code) l.addWidget(la), l.addWidget(self.source_code)