mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Move the python editing key handling into the python smarts module so that it is available for all text edit instances
This commit is contained in:
parent
d68ecaf264
commit
719a83584f
92
src/calibre/gui2/tweak_book/editor/smart/python.py
Normal file
92
src/calibre/gui2/tweak_book/editor/smart/python.py
Normal file
@ -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 <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
|
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')
|
@ -139,6 +139,7 @@ class TextEdit(PlainTextEdit):
|
|||||||
self.gutter_width = 0
|
self.gutter_width = 0
|
||||||
self.expected_geometry = expected_geometry
|
self.expected_geometry = expected_geometry
|
||||||
self.saved_matches = {}
|
self.saved_matches = {}
|
||||||
|
self.syntax = None
|
||||||
self.smarts = NullSmarts(self)
|
self.smarts = NullSmarts(self)
|
||||||
self.current_cursor_line = None
|
self.current_cursor_line = None
|
||||||
self.current_search_mark = None
|
self.current_search_mark = None
|
||||||
@ -151,7 +152,6 @@ class TextEdit(PlainTextEdit):
|
|||||||
self.cursorPositionChanged.connect(self.highlight_cursor_line)
|
self.cursorPositionChanged.connect(self.highlight_cursor_line)
|
||||||
self.blockCountChanged[int].connect(self.update_line_number_area_width)
|
self.blockCountChanged[int].connect(self.update_line_number_area_width)
|
||||||
self.updateRequest.connect(self.update_line_number_area)
|
self.updateRequest.connect(self.update_line_number_area)
|
||||||
self.syntax = None
|
|
||||||
|
|
||||||
@dynamic_property
|
@dynamic_property
|
||||||
def is_modified(self):
|
def is_modified(self):
|
||||||
@ -173,7 +173,8 @@ class TextEdit(PlainTextEdit):
|
|||||||
self.apply_theme(theme)
|
self.apply_theme(theme)
|
||||||
w = self.fontMetrics()
|
w = self.fontMetrics()
|
||||||
self.space_width = w.width(' ')
|
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:
|
if dictionaries_changed:
|
||||||
self.highlighter.rehighlight()
|
self.highlighter.rehighlight()
|
||||||
|
|
||||||
@ -223,6 +224,8 @@ class TextEdit(PlainTextEdit):
|
|||||||
if process_template and QPlainTextEdit.find(self, '%CURSOR%'):
|
if process_template and QPlainTextEdit.find(self, '%CURSOR%'):
|
||||||
c = self.textCursor()
|
c = self.textCursor()
|
||||||
c.insertText('')
|
c.insertText('')
|
||||||
|
if syntax == 'python':
|
||||||
|
self.setTabStopWidth(4 * self.space_width)
|
||||||
|
|
||||||
def change_document_name(self, newname):
|
def change_document_name(self, newname):
|
||||||
self.highlighter.doc_name = newname
|
self.highlighter.doc_name = newname
|
||||||
|
@ -198,83 +198,6 @@ class FunctionBox(EditWithComplete):
|
|||||||
menu.addAction(_('Show saved searches'), self.show_saved_searches.emit)
|
menu.addAction(_('Show saved searches'), self.show_saved_searches.emit)
|
||||||
menu.exec_(event.globalPos())
|
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):
|
class FunctionEditor(Dialog):
|
||||||
|
|
||||||
def __init__(self, func_name='', parent=None):
|
def __init__(self, func_name='', parent=None):
|
||||||
@ -293,7 +216,7 @@ class FunctionEditor(Dialog):
|
|||||||
h.addWidget(fb, stretch=10)
|
h.addWidget(fb, stretch=10)
|
||||||
|
|
||||||
self.la3 = la = QLabel(_('&Code:'))
|
self.la3 = la = QLabel(_('&Code:'))
|
||||||
self.source_code = PythonEdit(self)
|
self.source_code = TextEdit(self)
|
||||||
self.source_code.load_text('', 'python')
|
self.source_code.load_text('', 'python')
|
||||||
la.setBuddy(self.source_code)
|
la.setBuddy(self.source_code)
|
||||||
l.addWidget(la), l.addWidget(self.source_code)
|
l.addWidget(la), l.addWidget(self.source_code)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user