~ubuntu-branches/debian/stretch/electrum/stretch

« back to all changes in this revision

Viewing changes to gui/qt_console.py

  • Committer: Package Import Robot
  • Author(s): Vasudev Kamath
  • Date: 2013-06-19 21:44:47 UTC
  • Revision ID: package-import@ubuntu.com-20130619214447-8n0u7ryn1ftu25w8
Tags: upstream-1.8
ImportĀ upstreamĀ versionĀ 1.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# source: http://stackoverflow.com/questions/2758159/how-to-embed-a-python-interpreter-in-a-pyqt-widget
 
2
 
 
3
import sys, os, re
 
4
import traceback, platform
 
5
from PyQt4 import QtCore
 
6
from PyQt4 import QtGui
 
7
from electrum import util
 
8
 
 
9
 
 
10
if platform.system() == 'Windows':
 
11
    MONOSPACE_FONT = 'Lucida Console'
 
12
elif platform.system() == 'Darwin':
 
13
    MONOSPACE_FONT = 'Monaco'
 
14
else:
 
15
    MONOSPACE_FONT = 'monospace'
 
16
 
 
17
 
 
18
class Console(QtGui.QPlainTextEdit):
 
19
    def __init__(self, prompt='>> ', startup_message='', parent=None):
 
20
        QtGui.QPlainTextEdit.__init__(self, parent)
 
21
 
 
22
        self.prompt = prompt
 
23
        self.history = []
 
24
        self.namespace = {}
 
25
        self.construct = []
 
26
 
 
27
        self.setGeometry(50, 75, 600, 400)
 
28
        self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere)
 
29
        self.setUndoRedoEnabled(False)
 
30
        self.document().setDefaultFont(QtGui.QFont(MONOSPACE_FONT, 10, QtGui.QFont.Normal))
 
31
        self.showMessage(startup_message)
 
32
 
 
33
        self.updateNamespace({'run':self.run_script})
 
34
        self.set_json(False)
 
35
 
 
36
    def set_json(self, b):
 
37
        self.is_json = b
 
38
    
 
39
    def run_script(self, filename):
 
40
        with open(filename) as f:
 
41
            script = f.read()
 
42
        result = eval(script, self.namespace, self.namespace)
 
43
 
 
44
 
 
45
 
 
46
    def updateNamespace(self, namespace):
 
47
        self.namespace.update(namespace)
 
48
 
 
49
    def showMessage(self, message):
 
50
        self.appendPlainText(message)
 
51
        self.newPrompt()
 
52
 
 
53
    def clear(self):
 
54
        self.setPlainText('')
 
55
        self.newPrompt()
 
56
 
 
57
    def newPrompt(self):
 
58
        if self.construct:
 
59
            prompt = '.' * len(self.prompt)
 
60
        else:
 
61
            prompt = self.prompt
 
62
 
 
63
        self.completions_pos = self.textCursor().position()
 
64
        self.completions_visible = False
 
65
 
 
66
        self.appendPlainText(prompt)
 
67
        self.moveCursor(QtGui.QTextCursor.End)
 
68
 
 
69
    def getCommand(self):
 
70
        doc = self.document()
 
71
        curr_line = unicode(doc.findBlockByLineNumber(doc.lineCount() - 1).text())
 
72
        curr_line = curr_line.rstrip()
 
73
        curr_line = curr_line[len(self.prompt):]
 
74
        return curr_line
 
75
 
 
76
    def setCommand(self, command):
 
77
        if self.getCommand() == command:
 
78
            return
 
79
 
 
80
        doc = self.document()
 
81
        curr_line = unicode(doc.findBlockByLineNumber(doc.lineCount() - 1).text())
 
82
        self.moveCursor(QtGui.QTextCursor.End)
 
83
        for i in range(len(curr_line) - len(self.prompt)):
 
84
            self.moveCursor(QtGui.QTextCursor.Left, QtGui.QTextCursor.KeepAnchor)
 
85
 
 
86
        self.textCursor().removeSelectedText()
 
87
        self.textCursor().insertText(command)
 
88
        self.moveCursor(QtGui.QTextCursor.End)
 
89
 
 
90
 
 
91
    def show_completions(self, completions):
 
92
        if self.completions_visible:
 
93
            self.hide_completions()
 
94
 
 
95
        c = self.textCursor()
 
96
        c.setPosition(self.completions_pos)
 
97
 
 
98
        completions = map(lambda x: x.split('.')[-1], completions)
 
99
        t = '\n' + ' '.join(completions)
 
100
        if len(t) > 500:
 
101
            t = t[:500] + '...'
 
102
        c.insertText(t)
 
103
        self.completions_end = c.position()
 
104
 
 
105
        self.moveCursor(QtGui.QTextCursor.End)
 
106
        self.completions_visible = True
 
107
        
 
108
 
 
109
    def hide_completions(self):
 
110
        if not self.completions_visible:
 
111
            return
 
112
        c = self.textCursor()
 
113
        c.setPosition(self.completions_pos)
 
114
        l = self.completions_end - self.completions_pos
 
115
        for x in range(l): c.deleteChar()
 
116
 
 
117
        self.moveCursor(QtGui.QTextCursor.End)
 
118
        self.completions_visible = False
 
119
 
 
120
 
 
121
    def getConstruct(self, command):
 
122
        if self.construct:
 
123
            prev_command = self.construct[-1]
 
124
            self.construct.append(command)
 
125
            if not prev_command and not command:
 
126
                ret_val = '\n'.join(self.construct)
 
127
                self.construct = []
 
128
                return ret_val
 
129
            else:
 
130
                return ''
 
131
        else:
 
132
            if command and command[-1] == (':'):
 
133
                self.construct.append(command)
 
134
                return ''
 
135
            else:
 
136
                return command
 
137
 
 
138
    def getHistory(self):
 
139
        return self.history
 
140
 
 
141
    def setHisory(self, history):
 
142
        self.history = history
 
143
 
 
144
    def addToHistory(self, command):
 
145
        if command and (not self.history or self.history[-1] != command):
 
146
            self.history.append(command)
 
147
        self.history_index = len(self.history)
 
148
 
 
149
    def getPrevHistoryEntry(self):
 
150
        if self.history:
 
151
            self.history_index = max(0, self.history_index - 1)
 
152
            return self.history[self.history_index]
 
153
        return ''
 
154
 
 
155
    def getNextHistoryEntry(self):
 
156
        if self.history:
 
157
            hist_len = len(self.history)
 
158
            self.history_index = min(hist_len, self.history_index + 1)
 
159
            if self.history_index < hist_len:
 
160
                return self.history[self.history_index]
 
161
        return ''
 
162
 
 
163
    def getCursorPosition(self):
 
164
        c = self.textCursor()
 
165
        return c.position() - c.block().position() - len(self.prompt)
 
166
 
 
167
    def setCursorPosition(self, position):
 
168
        self.moveCursor(QtGui.QTextCursor.StartOfLine)
 
169
        for i in range(len(self.prompt) + position):
 
170
            self.moveCursor(QtGui.QTextCursor.Right)
 
171
 
 
172
    def register_command(self, c, func):
 
173
        methods = { c: func}
 
174
        self.updateNamespace(methods)
 
175
        
 
176
 
 
177
    def runCommand(self):
 
178
        command = self.getCommand()
 
179
        self.addToHistory(command)
 
180
 
 
181
        command = self.getConstruct(command)
 
182
 
 
183
        if command:
 
184
            tmp_stdout = sys.stdout
 
185
 
 
186
            class stdoutProxy():
 
187
                def __init__(self, write_func):
 
188
                    self.write_func = write_func
 
189
                    self.skip = False
 
190
 
 
191
                def flush(self):
 
192
                    pass
 
193
 
 
194
                def write(self, text):
 
195
                    if not self.skip:
 
196
                        stripped_text = text.rstrip('\n')
 
197
                        self.write_func(stripped_text)
 
198
                        QtCore.QCoreApplication.processEvents()
 
199
                    self.skip = not self.skip
 
200
 
 
201
            if type(self.namespace.get(command)) == type(lambda:None):
 
202
                self.appendPlainText("'%s' is a function. Type '%s()' to use it in the Python console."%(command, command))
 
203
                self.newPrompt()
 
204
                return
 
205
 
 
206
            sys.stdout = stdoutProxy(self.appendPlainText)
 
207
            try:
 
208
                try:
 
209
                    result = eval(command, self.namespace, self.namespace)
 
210
                    if result != None:
 
211
                        if self.is_json:
 
212
                            util.print_json(result)
 
213
                        else:
 
214
                            self.appendPlainText(repr(result))
 
215
                except SyntaxError:
 
216
                    exec command in self.namespace
 
217
            except SystemExit:
 
218
                self.close()
 
219
            except:
 
220
                traceback_lines = traceback.format_exc().split('\n')
 
221
                # Remove traceback mentioning this file, and a linebreak
 
222
                for i in (3,2,1,-1):
 
223
                    traceback_lines.pop(i)
 
224
                self.appendPlainText('\n'.join(traceback_lines))
 
225
            sys.stdout = tmp_stdout
 
226
        self.newPrompt()
 
227
        self.set_json(False)
 
228
                    
 
229
 
 
230
    def keyPressEvent(self, event):
 
231
        if event.key() == QtCore.Qt.Key_Tab:
 
232
            self.completions()
 
233
            return
 
234
 
 
235
        self.hide_completions()
 
236
 
 
237
        if event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
 
238
            self.runCommand()
 
239
            return
 
240
        if event.key() == QtCore.Qt.Key_Home:
 
241
            self.setCursorPosition(0)
 
242
            return
 
243
        if event.key() == QtCore.Qt.Key_PageUp:
 
244
            return
 
245
        elif event.key() in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Backspace):
 
246
            if self.getCursorPosition() == 0:
 
247
                return
 
248
        elif event.key() == QtCore.Qt.Key_Up:
 
249
            self.setCommand(self.getPrevHistoryEntry())
 
250
            return
 
251
        elif event.key() == QtCore.Qt.Key_Down:
 
252
            self.setCommand(self.getNextHistoryEntry())
 
253
            return
 
254
        elif event.key() == QtCore.Qt.Key_L and event.modifiers() == QtCore.Qt.ControlModifier:
 
255
            self.clear()
 
256
 
 
257
        super(Console, self).keyPressEvent(event)
 
258
 
 
259
 
 
260
 
 
261
    def completions(self):
 
262
        cmd = self.getCommand()
 
263
        lastword = re.split(' |\(|\)',cmd)[-1]
 
264
        beginning = cmd[0:-len(lastword)]
 
265
 
 
266
        path = lastword.split('.')
 
267
        ns = self.namespace.keys()
 
268
 
 
269
        if len(path) == 1:
 
270
            ns = ns
 
271
            prefix = ''
 
272
        else:
 
273
            obj = self.namespace.get(path[0])
 
274
            prefix = path[0] + '.'
 
275
            ns = dir(obj)
 
276
            
 
277
 
 
278
        completions = []
 
279
        for x in ns:
 
280
            if x[0] == '_':continue
 
281
            xx = prefix + x
 
282
            if xx.startswith(lastword):
 
283
                completions.append(xx)
 
284
        completions.sort()
 
285
                
 
286
        if not completions:
 
287
            self.hide_completions()
 
288
        elif len(completions) == 1:
 
289
            self.hide_completions()
 
290
            self.setCommand(beginning + completions[0])
 
291
        else:
 
292
            # find common prefix
 
293
            p = os.path.commonprefix(completions)
 
294
            if len(p)>len(lastword):
 
295
                self.hide_completions()
 
296
                self.setCommand(beginning + p)
 
297
            else:
 
298
                self.show_completions(completions)
 
299
 
 
300
 
 
301
welcome_message = '''
 
302
   ---------------------------------------------------------------
 
303
     Welcome to a primitive Python interpreter.
 
304
   ---------------------------------------------------------------
 
305
'''
 
306
 
 
307
if __name__ == '__main__':
 
308
    app = QtGui.QApplication(sys.argv)
 
309
    console = Console(startup_message=welcome_message)
 
310
    console.updateNamespace({'myVar1' : app, 'myVar2' : 1234})
 
311
    console.show();
 
312
    sys.exit(app.exec_())