File: editor.py

package info (click to toggle)
python-vispy 0.15.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 8,868 kB
  • sloc: python: 59,799; javascript: 6,800; makefile: 69; sh: 6
file content (196 lines) | stat: -rw-r--r-- 7,047 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# -*- coding: utf-8 -*-
# vispy: testskip
# -----------------------------------------------------------------------------
# Copyright (c) Vispy Development Team. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
# -----------------------------------------------------------------------------
"""
# QScintilla editor
#
# Adapted from Eli Bendersky (eliben@gmail.com)
# This code is in the public domain
#
# API: http://pyqt.sourceforge.net/Docs/QScintilla2/classQsciScintilla.html
#
"""

import sys
import re
from PyQt5.QtCore import *  # noqa
from PyQt5.QtWidgets import *  # noqa


try:
    from PyQt5 import Qsci
    from PyQt5.Qsci import QsciScintilla
    HAVE_QSCI = True
except ImportError:
    HAVE_QSCI = False

if not HAVE_QSCI:
    # backup editor in case QScintilla is not available
    class Editor(QPlainTextEdit):
        def __init__(self, parent=None, language=None):
            QPlainTextEdit.__init__(self, parent)

        def setText(self, text):
            self.setPlainText(text)

        def text(self):
            return str(self.toPlainText()).encode('UTF-8')

        def __getattr__(self, name):
            return lambda: None

else:
    class Editor(QsciScintilla):
        ARROW_MARKER_NUM = 8

        def __init__(self, parent=None, language='Python'):
            super(Editor, self).__init__(parent)
            self.setIndentationsUseTabs(False)
            self.setIndentationWidth(4)

            # Set the default font
            font = QFont()
            font.setFamily('DejaVu Sans Mono')
            font.setFixedPitch(True)
            font.setPointSize(10)
            self.setFont(font)
            self.setMarginsFont(font)
            self.zoomIn()

            # Margin 0 is used for line numbers
            fontmetrics = QFontMetrics(font)
            self.setMarginsFont(font)
            self.setMarginWidth(0, fontmetrics.width("000") + 6)
            self.setMarginLineNumbers(0, True)
            self.setMarginsBackgroundColor(QColor("#cccccc"))

            self._marker = None
            # Clickable margin 1 for showing markers
            # self.setMarginSensitivity(1, True)
            # self.connect(self,
            #    SIGNAL('marginClicked(int, int, Qt::KeyboardModifiers)'),
            #    self.on_margin_clicked)
            self.markerDefine(QsciScintilla.RightArrow, self.ARROW_MARKER_NUM)
            self.setMarkerBackgroundColor(QColor("#ee1111"),
                                          self.ARROW_MARKER_NUM)

            # Brace matching: enable for a brace immediately before or after
            # the current position
            #
            self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

            # Current line visible with special background color
            self.setCaretLineVisible(True)
            self.setCaretLineBackgroundColor(QColor("#ffe4e4"))

            # Set Python lexer
            # Set style for Python comments (style number 1) to a fixed-width
            # courier.
            #
            lexer = getattr(Qsci, 'QsciLexer' + language)()
            lexer.setDefaultFont(font)
            self.setLexer(lexer)
            self.SendScintilla(QsciScintilla.SCI_STYLESETFONT, 1, 'Courier')

            # Don't want to see the horizontal scrollbar at all
            # Use raw message to Scintilla here (all messages are documented
            # here: http://www.scintilla.org/ScintillaDoc.html)
            self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)

            self.setWrapMode(QsciScintilla.WrapWord)

            self.setEolMode(QsciScintilla.EolUnix)
            # not too small
            # self.setMinimumSize(600, 450)

        def set_marker(self, line):
            self.clear_marker()
            self.markerAdd(line, self.ARROW_MARKER_NUM)
            self._marker = line

        def clear_marker(self):
            if self._marker is not None:
                self.markerDelete(self._marker, self.ARROW_MARKER_NUM)

        # def on_margin_clicked(self, nmargin, nline, modifiers):
            # Toggle marker for the line the margin was clicked on
            # if self.markersAtLine(nline) != 0:
                # self.markerDelete(nline, self.ARROW_MARKER_NUM)
            # else:
                # self.markerAdd(nline, self.ARROW_MARKER_NUM)

        def wheelEvent(self, ev):
            # Use ctrl+wheel to zoom in/out
            if Qt.ControlModifier & ev.modifiers():
                if ev.delta() > 0:
                    self.zoomIn()
                else:
                    self.zoomOut()
            else:
                return super(Editor, self).wheelEvent(ev)

        def keyPressEvent(self, ev):
            if int(Qt.ControlModifier & ev.modifiers()) > 0:
                if ev.key() == Qt.Key_Slash:
                    self.comment(True)
                    return
                elif ev.key() == Qt.Key_Question:
                    self.comment(False)
                    return
                elif (ev.key() == Qt.Key_Z and
                      Qt.ShiftModifier & ev.modifiers()):
                    self.redo()
                    return
                elif ev.key() == Qt.Key_Q:
                    sys.exit(0)
            return super(Editor, self).keyPressEvent(ev)

        def text(self):
            return str(super(Editor, self).text()).encode('UTF-8')

        def comment(self, comment=True):
            sel = self.getSelection()[:]
            text = self.text()
            lines = text.split('\n')
            if sel[0] == -1:
                # toggle for just this line
                row, col = self.getCursorPosition()
                line = lines[row]
                self.setSelection(row, 0, row, len(line))
                if comment:
                    line = '#' + line
                else:
                    line = line.replace("#", "", 1)
                self.replaceSelectedText(line)
                self.setCursorPosition(row, col+(1 if col > 0 else 0))
            else:
                block = lines[sel[0]:sel[2]]
                # make sure all lines have #
                new = []
                if comment:
                    for line in block:
                        new.append('#' + line)
                else:
                    for line in block:
                        if line.strip() == '':
                            new.append(line)
                            continue
                        if re.match(r'\s*\#', line) is None:
                            return
                        new.append(line.replace('#', '', 1))
                self.setSelection(sel[0], 0, sel[2], 0)
                self.replaceSelectedText('\n'.join(new) + '\n')
                # shift = 1 if comment else -1
                self.setSelection(sel[0], max(0, sel[1]), sel[2], sel[3])


if __name__ == "__main__":
    app = QApplication(sys.argv)
    editor = Editor()
    editor.show()
    editor.setText(open(sys.argv[0]).read())
    editor.resize(800, 800)
    app.exec_()