1 """Provides an interactive Python console which can be run from within NVDA.
2 To use, call L{initialize} to create a singleton instance of the console GUI. This can then be accessed externally as L{consoleUI}.
3 """
4
5 import __builtin__
6 import os
7 import code
8 import sys
9 import pydoc
10 import wx
11 from baseObject import AutoPropertyObject
12 import speech
13 import queueHandler
14 import api
15 import gui
16 from logHandler import log
17 import braille
18
20 """
21 Emulation of the 'help' command found in the Python interactive shell.
22 """
23
24 _reprMessage=_("Type help(object) to get help about object.")
25
28
30 return pydoc.help(*args,**kwargs)
31
33 """
34 An object that can be used as an exit command that can close the console or print a friendly message for its repr.
35 """
36
38 self._exitFunc = exitFunc
39
40 _reprMessage=_("Type exit() to exit the console")
43
46
47
48 consoleUI = None
49
51 """An interactive Python console for NVDA which directs output to supplied functions.
52 This is necessary for a Python console with input/output other than stdin/stdout/stderr.
53 Input is always received via the L{push} method.
54 This console handles redirection of stdout and stderr and prevents clobbering of the gettext "_" builtin.
55 The console's namespace is populated with useful modules
56 and can be updated with a snapshot of NVDA's state using L{updateNamespaceSnapshotVars}.
57 """
58
59 - def __init__(self, outputFunc, setPromptFunc, exitFunc, echoFunc=None, **kwargs):
60 self._output = outputFunc
61 self._echo = echoFunc
62 self._setPrompt = setPromptFunc
63
64
65
66
67 exitCmd = ExitConsoleCommand(exitFunc)
68 self.namespace = {
69 "help": HelpCommand(),
70 "exit": exitCmd,
71 "quit": exitCmd,
72 "sys": sys,
73 "os": os,
74 "wx": wx,
75 "log": log,
76 "api": api,
77 "queueHandler": queueHandler,
78 "speech": speech,
79 "braille": braille,
80 }
81
82
83 self._namespaceSnapshotVars = None
84
85
86 code.InteractiveConsole.__init__(self, locals=self.namespace, **kwargs)
87 self.prompt = ">>>"
88
90 self._prompt = prompt
91 self._setPrompt(prompt)
92
95
98
99 - def push(self, line):
100 if self._echo:
101 self._echo("%s %s\n" % (self.prompt, line))
102
103 stdout, stderr = sys.stdout, sys.stderr
104 sys.stdout = sys.stderr = self
105
106 saved_ = __builtin__._
107 more = code.InteractiveConsole.push(self, line)
108 sys.stdout, sys.stderr = stdout, stderr
109 __builtin__._ = saved_
110 self.prompt = "..." if more else ">>>"
111 return more
112
114 """Update the console namespace with a snapshot of NVDA's current state.
115 This creates/updates variables for the current focus, navigator object, etc.
116 """
117 self._namespaceSnapshotVars = {
118 "focus": api.getFocusObject(),
119
120 "focusAnc": list(api.getFocusAncestors()),
121 "fdl": api.getFocusDifferenceLevel(),
122 "fg": api.getForegroundObject(),
123 "nav": api.getNavigatorObject(),
124 "review":api.getReviewPosition(),
125 "mouse": api.getMouseObject(),
126 "brlRegions": braille.handler.buffer.regions,
127 }
128 self.namespace.update(self._namespaceSnapshotVars)
129
131 """Remove the variables from the console namespace containing the last snapshot of NVDA's state.
132 This removes the variables added by L{updateNamespaceSnapshotVars}.
133 """
134 if not self._namespaceSnapshotVars:
135 return
136 for key in self._namespaceSnapshotVars:
137 try:
138 del self.namespace[key]
139 except KeyError:
140 pass
141 self._namespaceSnapshotVars = None
142
144 """The NVDA Python console GUI.
145 """
146
148 super(ConsoleUI, self).__init__(parent, wx.ID_ANY, _("NVDA Python Console"))
149 self.Bind(wx.EVT_ACTIVATE, self.onActivate)
150 self.Bind(wx.EVT_CLOSE, self.onClose)
151 mainSizer = wx.BoxSizer(wx.VERTICAL)
152 self.outputCtrl = wx.TextCtrl(self, wx.ID_ANY, size=(500, 500), style=wx.TE_MULTILINE | wx.TE_READONLY|wx.TE_RICH)
153 self.outputCtrl.Bind(wx.EVT_CHAR, self.onOutputChar)
154 mainSizer.Add(self.outputCtrl, proportion=2, flag=wx.EXPAND)
155 inputSizer = wx.BoxSizer(wx.HORIZONTAL)
156 self.promptLabel = wx.StaticText(self, wx.ID_ANY)
157 inputSizer.Add(self.promptLabel, flag=wx.EXPAND)
158 self.inputCtrl = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_DONTWRAP | wx.TE_PROCESS_TAB)
159 self.inputCtrl.Bind(wx.EVT_CHAR, self.onInputChar)
160 inputSizer.Add(self.inputCtrl, proportion=1, flag=wx.EXPAND)
161 mainSizer.Add(inputSizer, proportion=1, flag=wx.EXPAND)
162 self.SetSizer(mainSizer)
163 mainSizer.Fit(self)
164
165 self.console = PythonConsole(outputFunc=self.output, echoFunc=self.echo, setPromptFunc=self.setPrompt, exitFunc=self.Close)
166
167 self.inputHistory = [""]
168 self.inputHistoryPos = 0
169
171 if evt.GetActive():
172 self.inputCtrl.SetFocus()
173 evt.Skip()
174
178
183
184 - def echo(self, data):
185 self.outputCtrl.write(data)
186
190
192 data = self.inputCtrl.GetValue()
193 self.console.push(data)
194 if data:
195
196 if len(self.inputHistory) > 1 and self.inputHistory[-2] == data:
197
198 del self.inputHistory[-1]
199 else:
200
201 self.inputHistory[-1] = data
202
203 self.inputHistory.append("")
204 self.inputHistoryPos = len(self.inputHistory) - 1
205 self.inputCtrl.ChangeValue("")
206
207 - def historyMove(self, movement):
208 newIndex = self.inputHistoryPos + movement
209 if not (0 <= newIndex < len(self.inputHistory)):
210
211 return False
212
213 self.inputHistory[self.inputHistoryPos] = self.inputCtrl.GetValue()
214 self.inputHistoryPos = newIndex
215 self.inputCtrl.ChangeValue(self.inputHistory[newIndex])
216 self.inputCtrl.SetInsertionPointEnd()
217 return True
218
234
236 key = evt.GetKeyCode()
237 if key == wx.WXK_F6:
238 self.inputCtrl.SetFocus()
239 return
240 elif key == wx.WXK_ESCAPE:
241 self.Close()
242 evt.Skip()
243
245 """Initialize the NVDA Python console GUI.
246 This creates a singleton instance of the console GUI. This is accessible as L{consoleUI}. This may be manipulated externally.
247 """
248 global consoleUI
249 consoleUI = ConsoleUI(gui.mainFrame)
250
252 """Activate the console GUI.
253 This shows the GUI and brings it to the foreground if possible.
254 @precondition: L{initialize} has been called.
255 """
256 global consoleUI
257 consoleUI.Raise()
258
259
260
261
262 consoleUI.Maximize()
263 consoleUI.Show()
264