]> git.saurik.com Git - wxWidgets.git/blame - wxPython/wx/py/shell.py
added missing default value for wxEventLoopManual::Exit() parameter
[wxWidgets.git] / wxPython / wx / py / shell.py
CommitLineData
d14a1e28
RD
1"""Shell is an interactive text control in which a user types in
2commands to be sent to the interpreter. This particular shell is
3based on wxPython's wxStyledTextCtrl.
1fded56b 4
d14a1e28 5Sponsored by Orbtech - Your source for Python programming expertise."""
1fded56b 6
d14a1e28
RD
7__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
8__cvsid__ = "$Id$"
9__revision__ = "$Revision$"[11:-2]
10
d14a1e28
RD
11import wx
12from wx import stc
13
14import keyword
15import os
16import sys
17import time
18
19from buffer import Buffer
20import dispatcher
21import editwindow
22import frame
23from pseudo import PseudoFileIn
24from pseudo import PseudoFileOut
25from pseudo import PseudoFileErr
26from version import VERSION
27
d14a1e28
RD
28sys.ps3 = '<-- ' # Input prompt.
29
30NAVKEYS = (wx.WXK_END, wx.WXK_LEFT, wx.WXK_RIGHT,
31 wx.WXK_UP, wx.WXK_DOWN, wx.WXK_PRIOR, wx.WXK_NEXT)
32
33
02b800ce 34class ShellFrame(frame.Frame, frame.ShellFrameMixin):
d14a1e28
RD
35 """Frame containing the shell component."""
36
37 name = 'Shell Frame'
38 revision = __revision__
39
40 def __init__(self, parent=None, id=-1, title='PyShell',
41 pos=wx.DefaultPosition, size=wx.DefaultSize,
42 style=wx.DEFAULT_FRAME_STYLE, locals=None,
02b800ce
RD
43 InterpClass=None,
44 config=None, dataDir=None,
45 *args, **kwds):
d14a1e28
RD
46 """Create ShellFrame instance."""
47 frame.Frame.__init__(self, parent, id, title, pos, size, style)
02b800ce
RD
48 frame.ShellFrameMixin.__init__(self, config, dataDir)
49
50 if size == wx.DefaultSize:
51 self.SetSize((750, 525))
52
d14a1e28 53 intro = 'PyShell %s - The Flakiest Python Shell' % VERSION
d14a1e28
RD
54 self.SetStatusText(intro.replace('\n', ', '))
55 self.shell = Shell(parent=self, id=-1, introText=intro,
56 locals=locals, InterpClass=InterpClass,
02b800ce
RD
57 startupScript=self.startupScript,
58 execStartupScript=self.execStartupScript,
d14a1e28 59 *args, **kwds)
02b800ce 60
d14a1e28
RD
61 # Override the shell so that status messages go to the status bar.
62 self.shell.setStatusText = self.SetStatusText
63
02b800ce
RD
64 self.shell.SetFocus()
65 self.LoadSettings()
66
67
d14a1e28
RD
68 def OnClose(self, event):
69 """Event handler for closing."""
70 # This isn't working the way I want, but I'll leave it for now.
71 if self.shell.waiting:
72 if event.CanVeto():
73 event.Veto(True)
74 else:
02b800ce 75 self.SaveSettings()
d14a1e28
RD
76 self.shell.destroy()
77 self.Destroy()
78
79 def OnAbout(self, event):
80 """Display an About window."""
81 title = 'About PyShell'
82 text = 'PyShell %s\n\n' % VERSION + \
83 'Yet another Python shell, only flakier.\n\n' + \
84 'Half-baked by Patrick K. O\'Brien,\n' + \
85 'the other half is still in the oven.\n\n' + \
86 'Shell Revision: %s\n' % self.shell.revision + \
87 'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
f2f8a5fc 88 'Platform: %s\n' % sys.platform + \
d14a1e28
RD
89 'Python Version: %s\n' % sys.version.split()[0] + \
90 'wxPython Version: %s\n' % wx.VERSION_STRING + \
f2f8a5fc 91 ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
d14a1e28
RD
92 dialog = wx.MessageDialog(self, text, title,
93 wx.OK | wx.ICON_INFORMATION)
94 dialog.ShowModal()
95 dialog.Destroy()
96
97
02b800ce
RD
98 def LoadSettings(self):
99 if self.config is not None:
100 frame.ShellFrameMixin.LoadSettings(self)
101 frame.Frame.LoadSettings(self, self.config)
102 self.shell.LoadSettings(self.config)
d14a1e28 103
02b800ce
RD
104 def SaveSettings(self):
105 if self.config is not None:
106 frame.ShellFrameMixin.SaveSettings(self)
107 if self.autoSaveSettings:
108 frame.Frame.SaveSettings(self, self.config)
109 self.shell.SaveSettings(self.config)
d14a1e28 110
02b800ce
RD
111 def DoSaveSettings(self):
112 if self.config is not None:
113 self.SaveSettings()
114 self.config.Flush()
115
d14a1e28 116
02b800ce
RD
117
118
119HELP_TEXT = """\
d14a1e28
RD
120* Key bindings:
121Home Go to the beginning of the command or line.
122Shift+Home Select to the beginning of the command or line.
123Shift+End Select to the end of the line.
124End Go to the end of the line.
125Ctrl+C Copy selected text, removing prompts.
126Ctrl+Shift+C Copy selected text, retaining prompts.
02b800ce 127Alt+C Copy to the clipboard, including prefixed prompts.
d14a1e28
RD
128Ctrl+X Cut selected text.
129Ctrl+V Paste from clipboard.
130Ctrl+Shift+V Paste and run multiple commands from clipboard.
131Ctrl+Up Arrow Retrieve Previous History item.
132Alt+P Retrieve Previous History item.
133Ctrl+Down Arrow Retrieve Next History item.
134Alt+N Retrieve Next History item.
135Shift+Up Arrow Insert Previous History item.
136Shift+Down Arrow Insert Next History item.
137F8 Command-completion of History item.
138 (Type a few characters of a previous command and press F8.)
139Ctrl+Enter Insert new line into multiline command.
140Ctrl+] Increase font size.
141Ctrl+[ Decrease font size.
142Ctrl+= Default font size.
02b800ce
RD
143Ctrl-Space Show Auto Completion.
144Ctrl-Alt-Space Show Call Tip.
145Alt+Shift+C Clear Screen.
146Shift+Enter Complete Text from History.
147Ctrl+F Search (backwards) TODO: regexp-wholeWords-...
148Ctrl+G Search next
149Ctrl+H "hide" lines containing selection / "unhide"
150F12 on/off "free-edit" mode
d14a1e28
RD
151"""
152
02b800ce
RD
153class ShellFacade:
154 """Simplified interface to all shell-related functionality.
155
156 This is a semi-transparent facade, in that all attributes of other
157 are accessible, even though only some are visible to the user."""
158
159 name = 'Shell Interface'
160 revision = __revision__
161
162 def __init__(self, other):
163 """Create a ShellFacade instance."""
164 d = self.__dict__
165 d['other'] = other
166 d['helpText'] = HELP_TEXT
167
d14a1e28
RD
168 def help(self):
169 """Display some useful information about how to use the shell."""
170 self.write(self.helpText)
171
172 def __getattr__(self, name):
173 if hasattr(self.other, name):
174 return getattr(self.other, name)
175 else:
176 raise AttributeError, name
177
178 def __setattr__(self, name, value):
179 if self.__dict__.has_key(name):
180 self.__dict__[name] = value
181 elif hasattr(self.other, name):
182 setattr(self.other, name, value)
183 else:
184 raise AttributeError, name
185
186 def _getAttributeNames(self):
187 """Return list of magic attributes to extend introspection."""
188 list = [
189 'about',
190 'ask',
191 'autoCallTip',
192 'autoComplete',
d351525a 193 'autoCompleteAutoHide',
d14a1e28
RD
194 'autoCompleteCaseInsensitive',
195 'autoCompleteIncludeDouble',
196 'autoCompleteIncludeMagic',
197 'autoCompleteIncludeSingle',
02b800ce 198 'callTipInsert',
d14a1e28
RD
199 'clear',
200 'pause',
201 'prompt',
202 'quit',
203 'redirectStderr',
204 'redirectStdin',
205 'redirectStdout',
206 'run',
207 'runfile',
208 'wrap',
209 'zoom',
210 ]
211 list.sort()
212 return list
213
214
02b800ce 215
d14a1e28
RD
216class Shell(editwindow.EditWindow):
217 """Shell based on StyledTextCtrl."""
218
219 name = 'Shell'
220 revision = __revision__
221
222 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
223 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
02b800ce
RD
224 introText='', locals=None, InterpClass=None,
225 startupScript=None, execStartupScript=True,
226 *args, **kwds):
d14a1e28
RD
227 """Create Shell instance."""
228 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
229 self.wrap()
230 if locals is None:
a47c63ba
PB
231 import __main__
232 locals = __main__.__dict__
02b800ce 233
d14a1e28
RD
234 # Grab these so they can be restored by self.redirect* methods.
235 self.stdin = sys.stdin
236 self.stdout = sys.stdout
237 self.stderr = sys.stderr
02b800ce 238
d14a1e28
RD
239 # Import a default interpreter class if one isn't provided.
240 if InterpClass == None:
241 from interpreter import Interpreter
242 else:
243 Interpreter = InterpClass
02b800ce 244
d14a1e28
RD
245 # Create a replacement for stdin.
246 self.reader = PseudoFileIn(self.readline, self.readlines)
247 self.reader.input = ''
248 self.reader.isreading = False
02b800ce 249
d14a1e28
RD
250 # Set up the interpreter.
251 self.interp = Interpreter(locals=locals,
252 rawin=self.raw_input,
253 stdin=self.reader,
254 stdout=PseudoFileOut(self.writeOut),
255 stderr=PseudoFileErr(self.writeErr),
256 *args, **kwds)
02b800ce 257
d14a1e28
RD
258 # Set up the buffer.
259 self.buffer = Buffer()
02b800ce 260
d14a1e28
RD
261 # Find out for which keycodes the interpreter will autocomplete.
262 self.autoCompleteKeys = self.interp.getAutoCompleteKeys()
02b800ce 263
d14a1e28
RD
264 # Keep track of the last non-continuation prompt positions.
265 self.promptPosStart = 0
266 self.promptPosEnd = 0
02b800ce 267
d14a1e28
RD
268 # Keep track of multi-line commands.
269 self.more = False
02b800ce 270
d14a1e28
RD
271 # Create the command history. Commands are added into the
272 # front of the list (ie. at index 0) as they are entered.
273 # self.historyIndex is the current position in the history; it
274 # gets incremented as you retrieve the previous command,
275 # decremented as you retrieve the next, and reset when you hit
276 # Enter. self.historyIndex == -1 means you're on the current
277 # command, not in the history.
278 self.history = []
279 self.historyIndex = -1
02b800ce
RD
280
281 #seb add mode for "free edit"
282 self.noteMode = 0
283 self.MarkerDefine(0,stc.STC_MARK_ROUNDRECT) # marker for hidden
284 self.searchTxt = ""
285
d14a1e28 286 # Assign handlers for keyboard events.
02b800ce
RD
287 self.Bind(wx.EVT_CHAR, self.OnChar)
288 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
289
d14a1e28
RD
290 # Assign handler for idle time.
291 self.waiting = False
02b800ce
RD
292 self.Bind(wx.EVT_IDLE, self.OnIdle)
293
d14a1e28
RD
294 # Display the introductory banner information.
295 self.showIntro(introText)
02b800ce 296
d14a1e28
RD
297 # Assign some pseudo keywords to the interpreter's namespace.
298 self.setBuiltinKeywords()
02b800ce 299
d14a1e28
RD
300 # Add 'shell' to the interpreter's local namespace.
301 self.setLocalShell()
02b800ce
RD
302
303 ## NOTE: See note at bottom of this file...
304 ## #seb: File drag and drop
305 ## self.SetDropTarget( FileDropTarget(self) )
306
d14a1e28
RD
307 # Do this last so the user has complete control over their
308 # environment. They can override anything they want.
02b800ce
RD
309 if execStartupScript:
310 if startupScript is None:
311 startupScript = os.environ.get('PYTHONSTARTUP')
312 self.execStartupScript(startupScript)
313 else:
314 self.prompt()
315
d14a1e28
RD
316 wx.CallAfter(self.ScrollToLine, 0)
317
02b800ce
RD
318
319
d14a1e28
RD
320 def destroy(self):
321 del self.interp
322
323 def setFocus(self):
324 """Set focus to the shell."""
325 self.SetFocus()
326
327 def OnIdle(self, event):
328 """Free the CPU to do other things."""
329 if self.waiting:
330 time.sleep(0.05)
331 event.Skip()
332
333 def showIntro(self, text=''):
334 """Display introductory text in the shell."""
335 if text:
336 if not text.endswith(os.linesep):
337 text += os.linesep
338 self.write(text)
339 try:
340 self.write(self.interp.introText)
341 except AttributeError:
342 pass
343
344 def setBuiltinKeywords(self):
345 """Create pseudo keywords as part of builtins.
346
347 This sets `close`, `exit` and `quit` to a helpful string.
348 """
349 import __builtin__
350 __builtin__.close = __builtin__.exit = __builtin__.quit = \
351 'Click on the close button to leave the application.'
352
02b800ce 353
d14a1e28
RD
354 def quit(self):
355 """Quit the application."""
d14a1e28 356 # XXX Good enough for now but later we want to send a close event.
d14a1e28
RD
357 # In the close event handler we can make sure they want to
358 # quit. Other applications, like PythonCard, may choose to
359 # hide rather than quit so we should just post the event and
360 # let the surrounding app decide what it wants to do.
361 self.write('Click on the close button to leave the application.')
362
02b800ce 363
d14a1e28
RD
364 def setLocalShell(self):
365 """Add 'shell' to locals as reference to ShellFacade instance."""
366 self.interp.locals['shell'] = ShellFacade(other=self)
367
02b800ce 368
d14a1e28
RD
369 def execStartupScript(self, startupScript):
370 """Execute the user's PYTHONSTARTUP script if they have one."""
371 if startupScript and os.path.isfile(startupScript):
372 text = 'Startup script executed: ' + startupScript
373 self.push('print %r; execfile(%r)' % (text, startupScript))
02b800ce 374 self.interp.startupScript = startupScript
d14a1e28
RD
375 else:
376 self.push('')
377
02b800ce 378
d14a1e28
RD
379 def about(self):
380 """Display information about Py."""
381 text = """
382Author: %r
383Py Version: %s
384Py Shell Revision: %s
385Py Interpreter Revision: %s
386Python Version: %s
387wxPython Version: %s
02b800ce 388wxPython PlatformInfo: %s
d14a1e28
RD
389Platform: %s""" % \
390 (__author__, VERSION, self.revision, self.interp.revision,
02b800ce
RD
391 sys.version.split()[0], wx.VERSION_STRING, str(wx.PlatformInfo),
392 sys.platform)
d14a1e28
RD
393 self.write(text.strip())
394
02b800ce 395
d14a1e28
RD
396 def OnChar(self, event):
397 """Keypress event handler.
398
399 Only receives an event if OnKeyDown calls event.Skip() for the
400 corresponding event."""
401
02b800ce
RD
402 if self.noteMode:
403 event.Skip()
404 return
405
d14a1e28
RD
406 # Prevent modification of previously submitted
407 # commands/responses.
408 if not self.CanEdit():
409 return
410 key = event.KeyCode()
411 currpos = self.GetCurrentPos()
412 stoppos = self.promptPosEnd
413 # Return (Enter) needs to be ignored in this handler.
414 if key == wx.WXK_RETURN:
415 pass
416 elif key in self.autoCompleteKeys:
417 # Usually the dot (period) key activates auto completion.
418 # Get the command between the prompt and the cursor. Add
419 # the autocomplete character to the end of the command.
420 if self.AutoCompActive():
421 self.AutoCompCancel()
422 command = self.GetTextRange(stoppos, currpos) + chr(key)
423 self.write(chr(key))
424 if self.autoComplete:
425 self.autoCompleteShow(command)
426 elif key == ord('('):
427 # The left paren activates a call tip and cancels an
428 # active auto completion.
429 if self.AutoCompActive():
430 self.AutoCompCancel()
431 # Get the command between the prompt and the cursor. Add
432 # the '(' to the end of the command.
433 self.ReplaceSelection('')
434 command = self.GetTextRange(stoppos, currpos) + '('
435 self.write('(')
02b800ce 436 self.autoCallTipShow(command, self.GetCurrentPos() == self.GetTextLength())
d14a1e28
RD
437 else:
438 # Allow the normal event handling to take place.
439 event.Skip()
440
02b800ce 441
d14a1e28
RD
442 def OnKeyDown(self, event):
443 """Key down event handler."""
444
445 key = event.KeyCode()
446 # If the auto-complete window is up let it do its thing.
447 if self.AutoCompActive():
448 event.Skip()
449 return
486afba9 450
d14a1e28
RD
451 # Prevent modification of previously submitted
452 # commands/responses.
453 controlDown = event.ControlDown()
454 altDown = event.AltDown()
455 shiftDown = event.ShiftDown()
456 currpos = self.GetCurrentPos()
457 endpos = self.GetTextLength()
458 selecting = self.GetSelectionStart() != self.GetSelectionEnd()
02b800ce 459
486afba9 460 if controlDown and shiftDown and key in (ord('F'), ord('f')):
02b800ce
RD
461 li = self.GetCurrentLine()
462 m = self.MarkerGet(li)
463 if m & 1<<0:
464 startP = self.PositionFromLine(li)
465 self.MarkerDelete(li, 0)
466 maxli = self.GetLineCount()
467 li += 1 # li stayed visible as header-line
468 li0 = li
469 while li<maxli and self.GetLineVisible(li) == 0:
470 li += 1
471 endP = self.GetLineEndPosition(li-1)
472 self.ShowLines(li0, li-1)
473 self.SetSelection( startP, endP ) # select reappearing text to allow "hide again"
474 return
475 startP,endP = self.GetSelection()
476 endP-=1
477 startL,endL = self.LineFromPosition(startP), self.LineFromPosition(endP)
478
479 if endL == self.LineFromPosition(self.promptPosEnd): # never hide last prompt
480 endL -= 1
481
482 m = self.MarkerGet(startL)
483 self.MarkerAdd(startL, 0)
484 self.HideLines(startL+1,endL)
485 self.SetCurrentPos( startP ) # to ensure caret stays visible !
486
487 if key == wx.WXK_F12: #seb
488 if self.noteMode:
489 # self.promptPosStart not used anyway - or ?
490 self.promptPosEnd = self.PositionFromLine( self.GetLineCount()-1 ) + len(str(sys.ps1))
491 self.GotoLine(self.GetLineCount())
492 self.GotoPos(self.promptPosEnd)
493 self.prompt() #make sure we have a prompt
494 self.SetCaretForeground("black")
495 self.SetCaretWidth(1) #default
496 self.SetCaretPeriod(500) #default
497 else:
498 self.SetCaretForeground("red")
499 self.SetCaretWidth(4)
500 self.SetCaretPeriod(0) #steady
501
502 self.noteMode = not self.noteMode
503 return
504 if self.noteMode:
505 event.Skip()
506 return
507
d14a1e28
RD
508 # Return (Enter) is used to submit a command to the
509 # interpreter.
02b800ce 510 if (not controlDown and not shiftDown and not altDown) and key == wx.WXK_RETURN:
d14a1e28
RD
511 if self.CallTipActive():
512 self.CallTipCancel()
513 self.processLine()
486afba9
RD
514
515 # Complete Text (from already typed words)
02b800ce
RD
516 elif shiftDown and key == wx.WXK_RETURN:
517 self.OnShowCompHistory()
486afba9
RD
518
519 # Ctrl+Return (Ctrl+Enter) is used to insert a line break.
d14a1e28
RD
520 elif controlDown and key == wx.WXK_RETURN:
521 if self.CallTipActive():
522 self.CallTipCancel()
523 if currpos == endpos:
524 self.processLine()
525 else:
526 self.insertLineBreak()
486afba9 527
d14a1e28
RD
528 # Let Ctrl-Alt-* get handled normally.
529 elif controlDown and altDown:
530 event.Skip()
486afba9 531
d14a1e28
RD
532 # Clear the current, unexecuted command.
533 elif key == wx.WXK_ESCAPE:
534 if self.CallTipActive():
535 event.Skip()
536 else:
537 self.clearCommand()
486afba9 538
d14a1e28 539 # Increase font size.
486afba9 540 elif controlDown and key in (ord(']'), wx.WXK_NUMPAD_ADD):
d14a1e28 541 dispatcher.send(signal='FontIncrease')
486afba9 542
d14a1e28 543 # Decrease font size.
486afba9 544 elif controlDown and key in (ord('['), wx.WXK_NUMPAD_SUBTRACT):
d14a1e28 545 dispatcher.send(signal='FontDecrease')
486afba9 546
d14a1e28 547 # Default font size.
486afba9 548 elif controlDown and key in (ord('='), wx.WXK_NUMPAD_DIVIDE):
d14a1e28 549 dispatcher.send(signal='FontDefault')
486afba9 550
d14a1e28
RD
551 # Cut to the clipboard.
552 elif (controlDown and key in (ord('X'), ord('x'))) \
486afba9 553 or (shiftDown and key == wx.WXK_DELETE):
d14a1e28 554 self.Cut()
486afba9 555
d14a1e28
RD
556 # Copy to the clipboard.
557 elif controlDown and not shiftDown \
486afba9 558 and key in (ord('C'), ord('c'), wx.WXK_INSERT):
d14a1e28 559 self.Copy()
486afba9 560
d14a1e28
RD
561 # Copy to the clipboard, including prompts.
562 elif controlDown and shiftDown \
486afba9 563 and key in (ord('C'), ord('c'), wx.WXK_INSERT):
d14a1e28 564 self.CopyWithPrompts()
486afba9 565
d14a1e28
RD
566 # Copy to the clipboard, including prefixed prompts.
567 elif altDown and not controlDown \
486afba9 568 and key in (ord('C'), ord('c'), wx.WXK_INSERT):
d14a1e28 569 self.CopyWithPromptsPrefixed()
486afba9 570
d14a1e28
RD
571 # Home needs to be aware of the prompt.
572 elif key == wx.WXK_HOME:
573 home = self.promptPosEnd
574 if currpos > home:
575 self.SetCurrentPos(home)
576 if not selecting and not shiftDown:
577 self.SetAnchor(home)
578 self.EnsureCaretVisible()
579 else:
580 event.Skip()
486afba9 581
d14a1e28
RD
582 #
583 # The following handlers modify text, so we need to see if
584 # there is a selection that includes text prior to the prompt.
585 #
586 # Don't modify a selection with text prior to the prompt.
587 elif selecting and key not in NAVKEYS and not self.CanEdit():
588 pass
486afba9 589
d14a1e28
RD
590 # Paste from the clipboard.
591 elif (controlDown and not shiftDown and key in (ord('V'), ord('v'))) \
592 or (shiftDown and not controlDown and key == wx.WXK_INSERT):
593 self.Paste()
486afba9
RD
594
595 # manually invoke AutoComplete and Calltips
02b800ce 596 elif controlDown and key == wx.WXK_SPACE:
486afba9
RD
597 self.OnCallTipAutoCompleteManually(shiftDown)
598
d14a1e28
RD
599 # Paste from the clipboard, run commands.
600 elif controlDown and shiftDown and key in (ord('V'), ord('v')):
601 self.PasteAndRun()
486afba9 602
d14a1e28
RD
603 # Replace with the previous command from the history buffer.
604 elif (controlDown and key == wx.WXK_UP) \
605 or (altDown and key in (ord('P'), ord('p'))):
606 self.OnHistoryReplace(step=+1)
486afba9 607
d14a1e28
RD
608 # Replace with the next command from the history buffer.
609 elif (controlDown and key == wx.WXK_DOWN) \
610 or (altDown and key in (ord('N'), ord('n'))):
611 self.OnHistoryReplace(step=-1)
486afba9 612
d14a1e28
RD
613 # Insert the previous command from the history buffer.
614 elif (shiftDown and key == wx.WXK_UP) and self.CanEdit():
615 self.OnHistoryInsert(step=+1)
486afba9 616
d14a1e28
RD
617 # Insert the next command from the history buffer.
618 elif (shiftDown and key == wx.WXK_DOWN) and self.CanEdit():
619 self.OnHistoryInsert(step=-1)
486afba9 620
d14a1e28
RD
621 # Search up the history for the text in front of the cursor.
622 elif key == wx.WXK_F8:
623 self.OnHistorySearch()
486afba9 624
d14a1e28
RD
625 # Don't backspace over the latest non-continuation prompt.
626 elif key == wx.WXK_BACK:
627 if selecting and self.CanEdit():
628 event.Skip()
629 elif currpos > self.promptPosEnd:
630 event.Skip()
486afba9 631
d14a1e28
RD
632 # Only allow these keys after the latest prompt.
633 elif key in (wx.WXK_TAB, wx.WXK_DELETE):
634 if self.CanEdit():
635 event.Skip()
486afba9 636
d14a1e28
RD
637 # Don't toggle between insert mode and overwrite mode.
638 elif key == wx.WXK_INSERT:
639 pass
486afba9 640
d14a1e28
RD
641 # Don't allow line deletion.
642 elif controlDown and key in (ord('L'), ord('l')):
643 pass
486afba9 644
d14a1e28
RD
645 # Don't allow line transposition.
646 elif controlDown and key in (ord('T'), ord('t')):
647 pass
486afba9 648
d14a1e28
RD
649 # Basic navigation keys should work anywhere.
650 elif key in NAVKEYS:
651 event.Skip()
486afba9 652
d14a1e28
RD
653 # Protect the readonly portion of the shell.
654 elif not self.CanEdit():
655 pass
486afba9 656
d14a1e28
RD
657 else:
658 event.Skip()
659
486afba9 660
02b800ce
RD
661 def OnShowCompHistory(self):
662 """Show possible autocompletion Words from already typed words."""
663
664 #copy from history
665 his = self.history[:]
666
667 #put together in one string
668 joined = " ".join (his)
669 import re
670
671 #sort out only "good" words
672 newlist = re.split("[ \.\[\]=}(\)\,0-9\"]", joined)
673
674 #length > 1 (mix out "trash")
675 thlist = []
676 for i in newlist:
677 if len (i) > 1:
678 thlist.append (i)
679
680 #unique (no duplicate words
681 #oneliner from german python forum => unique list
682 unlist = [thlist[i] for i in xrange(len(thlist)) if thlist[i] not in thlist[:i]]
683
684 #sort lowercase
685 unlist.sort(lambda a, b: cmp(a.lower(), b.lower()))
686
687 #this is more convenient, isn't it?
688 self.AutoCompSetIgnoreCase(True)
689
690 #join again together in a string
691 stringlist = " ".join(unlist)
692
693 #pos von 0 noch ausrechnen
694
695 #how big is the offset?
696 cpos = self.GetCurrentPos() - 1
697 while chr (self.GetCharAt (cpos)).isalnum():
698 cpos -= 1
699
700 #the most important part
701 self.AutoCompShow(self.GetCurrentPos() - cpos -1, stringlist)
702
703
d14a1e28
RD
704 def clearCommand(self):
705 """Delete the current, unexecuted command."""
706 startpos = self.promptPosEnd
707 endpos = self.GetTextLength()
708 self.SetSelection(startpos, endpos)
709 self.ReplaceSelection('')
710 self.more = False
711
712 def OnHistoryReplace(self, step):
713 """Replace with the previous/next command from the history buffer."""
714 self.clearCommand()
715 self.replaceFromHistory(step)
716
717 def replaceFromHistory(self, step):
718 """Replace selection with command from the history buffer."""
719 ps2 = str(sys.ps2)
720 self.ReplaceSelection('')
721 newindex = self.historyIndex + step
722 if -1 <= newindex <= len(self.history):
723 self.historyIndex = newindex
724 if 0 <= newindex <= len(self.history)-1:
725 command = self.history[self.historyIndex]
726 command = command.replace('\n', os.linesep + ps2)
727 self.ReplaceSelection(command)
728
729 def OnHistoryInsert(self, step):
730 """Insert the previous/next command from the history buffer."""
731 if not self.CanEdit():
732 return
733 startpos = self.GetCurrentPos()
734 self.replaceFromHistory(step)
735 endpos = self.GetCurrentPos()
736 self.SetSelection(endpos, startpos)
737
738 def OnHistorySearch(self):
739 """Search up the history buffer for the text in front of the cursor."""
740 if not self.CanEdit():
741 return
742 startpos = self.GetCurrentPos()
743 # The text up to the cursor is what we search for.
744 numCharsAfterCursor = self.GetTextLength() - startpos
745 searchText = self.getCommand(rstrip=False)
746 if numCharsAfterCursor > 0:
747 searchText = searchText[:-numCharsAfterCursor]
748 if not searchText:
749 return
750 # Search upwards from the current history position and loop
751 # back to the beginning if we don't find anything.
752 if (self.historyIndex <= -1) \
753 or (self.historyIndex >= len(self.history)-2):
754 searchOrder = range(len(self.history))
755 else:
756 searchOrder = range(self.historyIndex+1, len(self.history)) + \
757 range(self.historyIndex)
758 for i in searchOrder:
759 command = self.history[i]
760 if command[:len(searchText)] == searchText:
761 # Replace the current selection with the one we found.
762 self.ReplaceSelection(command[len(searchText):])
763 endpos = self.GetCurrentPos()
764 self.SetSelection(endpos, startpos)
765 # We've now warped into middle of the history.
766 self.historyIndex = i
767 break
768
769 def setStatusText(self, text):
770 """Display status information."""
771
772 # This method will likely be replaced by the enclosing app to
773 # do something more interesting, like write to a status bar.
774 print text
775
776 def insertLineBreak(self):
777 """Insert a new line break."""
778 if self.CanEdit():
779 self.write(os.linesep)
780 self.more = True
781 self.prompt()
782
783 def processLine(self):
784 """Process the line of text at which the user hit Enter."""
785
786 # The user hit ENTER and we need to decide what to do. They
787 # could be sitting on any line in the shell.
788
789 thepos = self.GetCurrentPos()
790 startpos = self.promptPosEnd
791 endpos = self.GetTextLength()
792 ps2 = str(sys.ps2)
793 # If they hit RETURN inside the current command, execute the
794 # command.
795 if self.CanEdit():
796 self.SetCurrentPos(endpos)
797 self.interp.more = False
798 command = self.GetTextRange(startpos, endpos)
799 lines = command.split(os.linesep + ps2)
800 lines = [line.rstrip() for line in lines]
801 command = '\n'.join(lines)
802 if self.reader.isreading:
803 if not command:
804 # Match the behavior of the standard Python shell
805 # when the user hits return without entering a
806 # value.
807 command = '\n'
808 self.reader.input = command
809 self.write(os.linesep)
810 else:
811 self.push(command)
02b800ce 812 wx.FutureCall(1, self.EnsureCaretVisible)
d14a1e28
RD
813 # Or replace the current command with the other command.
814 else:
815 # If the line contains a command (even an invalid one).
816 if self.getCommand(rstrip=False):
817 command = self.getMultilineCommand()
818 self.clearCommand()
819 self.write(command)
820 # Otherwise, put the cursor back where we started.
821 else:
822 self.SetCurrentPos(thepos)
823 self.SetAnchor(thepos)
824
825 def getMultilineCommand(self, rstrip=True):
826 """Extract a multi-line command from the editor.
827
828 The command may not necessarily be valid Python syntax."""
829 # XXX Need to extract real prompts here. Need to keep track of
830 # the prompt every time a command is issued.
831 ps1 = str(sys.ps1)
832 ps1size = len(ps1)
833 ps2 = str(sys.ps2)
834 ps2size = len(ps2)
835 # This is a total hack job, but it works.
836 text = self.GetCurLine()[0]
837 line = self.GetCurrentLine()
838 while text[:ps2size] == ps2 and line > 0:
839 line -= 1
840 self.GotoLine(line)
841 text = self.GetCurLine()[0]
842 if text[:ps1size] == ps1:
843 line = self.GetCurrentLine()
844 self.GotoLine(line)
845 startpos = self.GetCurrentPos() + ps1size
846 line += 1
847 self.GotoLine(line)
848 while self.GetCurLine()[0][:ps2size] == ps2:
849 line += 1
850 self.GotoLine(line)
851 stoppos = self.GetCurrentPos()
852 command = self.GetTextRange(startpos, stoppos)
853 command = command.replace(os.linesep + ps2, '\n')
854 command = command.rstrip()
855 command = command.replace('\n', os.linesep + ps2)
856 else:
857 command = ''
858 if rstrip:
859 command = command.rstrip()
860 return command
861
862 def getCommand(self, text=None, rstrip=True):
863 """Extract a command from text which may include a shell prompt.
864
865 The command may not necessarily be valid Python syntax."""
866 if not text:
867 text = self.GetCurLine()[0]
868 # Strip the prompt off the front leaving just the command.
869 command = self.lstripPrompt(text)
870 if command == text:
871 command = '' # Real commands have prompts.
872 if rstrip:
873 command = command.rstrip()
874 return command
875
876 def lstripPrompt(self, text):
877 """Return text without a leading prompt."""
878 ps1 = str(sys.ps1)
879 ps1size = len(ps1)
880 ps2 = str(sys.ps2)
881 ps2size = len(ps2)
882 # Strip the prompt off the front of text.
883 if text[:ps1size] == ps1:
884 text = text[ps1size:]
885 elif text[:ps2size] == ps2:
886 text = text[ps2size:]
887 return text
888
02b800ce 889 def push(self, command, silent = False):
d14a1e28 890 """Send command to the interpreter for execution."""
02b800ce
RD
891 if not silent:
892 self.write(os.linesep)
d14a1e28
RD
893 busy = wx.BusyCursor()
894 self.waiting = True
895 self.more = self.interp.push(command)
896 self.waiting = False
897 del busy
898 if not self.more:
899 self.addHistory(command.rstrip())
02b800ce
RD
900 if not silent:
901 self.prompt()
d14a1e28
RD
902
903 def addHistory(self, command):
904 """Add command to the command history."""
905 # Reset the history position.
906 self.historyIndex = -1
907 # Insert this command into the history, unless it's a blank
908 # line or the same as the last command.
909 if command != '' \
910 and (len(self.history) == 0 or command != self.history[0]):
911 self.history.insert(0, command)
912
913 def write(self, text):
914 """Display text in the shell.
915
916 Replace line endings with OS-specific endings."""
917 text = self.fixLineEndings(text)
918 self.AddText(text)
919 self.EnsureCaretVisible()
920
921 def fixLineEndings(self, text):
922 """Return text with line endings replaced by OS-specific endings."""
923 lines = text.split('\r\n')
924 for l in range(len(lines)):
925 chunks = lines[l].split('\r')
926 for c in range(len(chunks)):
927 chunks[c] = os.linesep.join(chunks[c].split('\n'))
928 lines[l] = os.linesep.join(chunks)
929 text = os.linesep.join(lines)
930 return text
931
932 def prompt(self):
933 """Display proper prompt for the context: ps1, ps2 or ps3.
934
935 If this is a continuation line, autoindent as necessary."""
936 isreading = self.reader.isreading
937 skip = False
938 if isreading:
939 prompt = str(sys.ps3)
940 elif self.more:
941 prompt = str(sys.ps2)
942 else:
943 prompt = str(sys.ps1)
944 pos = self.GetCurLine()[1]
945 if pos > 0:
946 if isreading:
947 skip = True
948 else:
949 self.write(os.linesep)
950 if not self.more:
951 self.promptPosStart = self.GetCurrentPos()
952 if not skip:
953 self.write(prompt)
954 if not self.more:
955 self.promptPosEnd = self.GetCurrentPos()
956 # Keep the undo feature from undoing previous responses.
957 self.EmptyUndoBuffer()
958 # XXX Add some autoindent magic here if more.
959 if self.more:
960 self.write(' '*4) # Temporary hack indentation.
961 self.EnsureCaretVisible()
962 self.ScrollToColumn(0)
963
964 def readline(self):
965 """Replacement for stdin.readline()."""
966 input = ''
967 reader = self.reader
968 reader.isreading = True
969 self.prompt()
970 try:
971 while not reader.input:
972 wx.YieldIfNeeded()
973 input = reader.input
974 finally:
975 reader.input = ''
976 reader.isreading = False
977 input = str(input) # In case of Unicode.
978 return input
979
980 def readlines(self):
981 """Replacement for stdin.readlines()."""
982 lines = []
983 while lines[-1:] != ['\n']:
984 lines.append(self.readline())
985 return lines
986
987 def raw_input(self, prompt=''):
988 """Return string based on user input."""
989 if prompt:
990 self.write(prompt)
991 return self.readline()
992
993 def ask(self, prompt='Please enter your response:'):
994 """Get response from the user using a dialog box."""
995 dialog = wx.TextEntryDialog(None, prompt,
996 'Input Dialog (Raw)', '')
997 try:
998 if dialog.ShowModal() == wx.ID_OK:
999 text = dialog.GetValue()
1000 return text
1001 finally:
1002 dialog.Destroy()
1003 return ''
1004
1005 def pause(self):
1006 """Halt execution pending a response from the user."""
1007 self.ask('Press enter to continue:')
1008
1009 def clear(self):
1010 """Delete all text from the shell."""
1011 self.ClearAll()
1012
1013 def run(self, command, prompt=True, verbose=True):
1014 """Execute command as if it was typed in directly.
1015 >>> shell.run('print "this"')
1016 >>> print "this"
1017 this
1018 >>>
1019 """
1020 # Go to the very bottom of the text.
1021 endpos = self.GetTextLength()
1022 self.SetCurrentPos(endpos)
1023 command = command.rstrip()
1024 if prompt: self.prompt()
1025 if verbose: self.write(command)
1026 self.push(command)
1027
1028 def runfile(self, filename):
1029 """Execute all commands in file as if they were typed into the
1030 shell."""
1031 file = open(filename)
1032 try:
1033 self.prompt()
1034 for command in file.readlines():
1035 if command[:6] == 'shell.':
1036 # Run shell methods silently.
1037 self.run(command, prompt=False, verbose=False)
1038 else:
1039 self.run(command, prompt=False, verbose=True)
1040 finally:
1041 file.close()
1042
02b800ce 1043 def autoCompleteShow(self, command, offset = 0):
d14a1e28 1044 """Display auto-completion popup list."""
d351525a
PB
1045 self.AutoCompSetAutoHide(self.autoCompleteAutoHide)
1046 self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
d14a1e28
RD
1047 list = self.interp.getAutoCompleteList(command,
1048 includeMagic=self.autoCompleteIncludeMagic,
1049 includeSingle=self.autoCompleteIncludeSingle,
1050 includeDouble=self.autoCompleteIncludeDouble)
1051 if list:
1052 options = ' '.join(list)
02b800ce 1053 #offset = 0
d14a1e28
RD
1054 self.AutoCompShow(offset, options)
1055
02b800ce 1056 def autoCallTipShow(self, command, insertcalltip = True, forceCallTip = False):
d14a1e28
RD
1057 """Display argument spec and docstring in a popup window."""
1058 if self.CallTipActive():
1059 self.CallTipCancel()
1060 (name, argspec, tip) = self.interp.getCallTip(command)
1061 if tip:
1062 dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
02b800ce 1063 if not self.autoCallTip and not forceCallTip:
d14a1e28 1064 return
02b800ce 1065 if argspec and insertcalltip and self.callTipInsert:
d14a1e28
RD
1066 startpos = self.GetCurrentPos()
1067 self.write(argspec + ')')
1068 endpos = self.GetCurrentPos()
1069 self.SetSelection(endpos, startpos)
1070 if tip:
1071 curpos = self.GetCurrentPos()
1072 tippos = curpos - (len(name) + 1)
1073 fallback = curpos - self.GetColumn(curpos)
1074 # In case there isn't enough room, only go back to the
1075 # fallback.
1076 tippos = max(tippos, fallback)
1077 self.CallTipShow(tippos, tip)
02b800ce
RD
1078
1079 def OnCallTipAutoCompleteManually (self, shiftDown):
1080 """AutoComplete and Calltips manually."""
1081 if self.AutoCompActive():
1082 self.AutoCompCancel()
1083 currpos = self.GetCurrentPos()
1084 stoppos = self.promptPosEnd
1085
1086 cpos = currpos
1087 #go back until '.' is found
1088 pointavailpos = -1
1089 while cpos >= stoppos:
1090 if self.GetCharAt(cpos) == ord ('.'):
1091 pointavailpos = cpos
1092 break
1093 cpos -= 1
1094
1095 #word from non whitespace until '.'
1096 if pointavailpos != -1:
1097 #look backward for first whitespace char
1098 textbehind = self.GetTextRange (pointavailpos + 1, currpos)
1099 pointavailpos += 1
1100
1101 if not shiftDown:
1102 #call AutoComplete
1103 stoppos = self.promptPosEnd
1104 textbefore = self.GetTextRange(stoppos, pointavailpos)
1105 self.autoCompleteShow(textbefore, len (textbehind))
1106 else:
1107 #call CallTips
1108 cpos = pointavailpos
1109 begpos = -1
1110 while cpos > stoppos:
1111 if chr(self.GetCharAt(cpos)).isspace():
1112 begpos = cpos
1113 break
1114 cpos -= 1
1115 if begpos == -1:
1116 begpos = cpos
1117 ctips = self.GetTextRange (begpos, currpos)
1118 ctindex = ctips.find ('(')
1119 if ctindex != -1 and not self.CallTipActive():
1120 #insert calltip, if current pos is '(', otherwise show it only
095315e2
RD
1121 self.autoCallTipShow(ctips[:ctindex + 1],
1122 self.GetCharAt(currpos - 1) == ord('(') and self.GetCurrentPos() == self.GetTextLength(),
02b800ce
RD
1123 True)
1124
d14a1e28
RD
1125
1126 def writeOut(self, text):
1127 """Replacement for stdout."""
1128 self.write(text)
1129
1130 def writeErr(self, text):
1131 """Replacement for stderr."""
1132 self.write(text)
1133
1134 def redirectStdin(self, redirect=True):
1135 """If redirect is true then sys.stdin will come from the shell."""
1136 if redirect:
1137 sys.stdin = self.reader
1138 else:
1139 sys.stdin = self.stdin
1140
1141 def redirectStdout(self, redirect=True):
1142 """If redirect is true then sys.stdout will go to the shell."""
1143 if redirect:
1144 sys.stdout = PseudoFileOut(self.writeOut)
1145 else:
1146 sys.stdout = self.stdout
1147
1148 def redirectStderr(self, redirect=True):
1149 """If redirect is true then sys.stderr will go to the shell."""
1150 if redirect:
1151 sys.stderr = PseudoFileErr(self.writeErr)
1152 else:
1153 sys.stderr = self.stderr
1154
1155 def CanCut(self):
1156 """Return true if text is selected and can be cut."""
1157 if self.GetSelectionStart() != self.GetSelectionEnd() \
1158 and self.GetSelectionStart() >= self.promptPosEnd \
1159 and self.GetSelectionEnd() >= self.promptPosEnd:
1160 return True
1161 else:
1162 return False
1163
1164 def CanPaste(self):
1165 """Return true if a paste should succeed."""
1166 if self.CanEdit() and editwindow.EditWindow.CanPaste(self):
1167 return True
1168 else:
1169 return False
1170
1171 def CanEdit(self):
1172 """Return true if editing should succeed."""
1173 if self.GetSelectionStart() != self.GetSelectionEnd():
1174 if self.GetSelectionStart() >= self.promptPosEnd \
1175 and self.GetSelectionEnd() >= self.promptPosEnd:
1176 return True
1177 else:
1178 return False
1179 else:
1180 return self.GetCurrentPos() >= self.promptPosEnd
1181
1182 def Cut(self):
1183 """Remove selection and place it on the clipboard."""
1184 if self.CanCut() and self.CanCopy():
1185 if self.AutoCompActive():
1186 self.AutoCompCancel()
1187 if self.CallTipActive():
1188 self.CallTipCancel()
1189 self.Copy()
1190 self.ReplaceSelection('')
1191
1192 def Copy(self):
1193 """Copy selection and place it on the clipboard."""
1194 if self.CanCopy():
1195 ps1 = str(sys.ps1)
1196 ps2 = str(sys.ps2)
1197 command = self.GetSelectedText()
1198 command = command.replace(os.linesep + ps2, os.linesep)
1199 command = command.replace(os.linesep + ps1, os.linesep)
1200 command = self.lstripPrompt(text=command)
1201 data = wx.TextDataObject(command)
1202 self._clip(data)
1203
1204 def CopyWithPrompts(self):
1205 """Copy selection, including prompts, and place it on the clipboard."""
1206 if self.CanCopy():
1207 command = self.GetSelectedText()
1208 data = wx.TextDataObject(command)
1209 self._clip(data)
1210
1211 def CopyWithPromptsPrefixed(self):
1212 """Copy selection, including prompts prefixed with four
1213 spaces, and place it on the clipboard."""
1214 if self.CanCopy():
1215 command = self.GetSelectedText()
1216 spaces = ' ' * 4
1217 command = spaces + command.replace(os.linesep,
1218 os.linesep + spaces)
1219 data = wx.TextDataObject(command)
1220 self._clip(data)
1221
1222 def _clip(self, data):
1223 if wx.TheClipboard.Open():
1224 wx.TheClipboard.UsePrimarySelection(False)
1225 wx.TheClipboard.SetData(data)
1226 wx.TheClipboard.Flush()
1227 wx.TheClipboard.Close()
1228
1229 def Paste(self):
1230 """Replace selection with clipboard contents."""
1231 if self.CanPaste() and wx.TheClipboard.Open():
1232 ps2 = str(sys.ps2)
1233 if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
1234 data = wx.TextDataObject()
1235 if wx.TheClipboard.GetData(data):
1236 self.ReplaceSelection('')
1237 command = data.GetText()
1238 command = command.rstrip()
1239 command = self.fixLineEndings(command)
1240 command = self.lstripPrompt(text=command)
1241 command = command.replace(os.linesep + ps2, '\n')
1242 command = command.replace(os.linesep, '\n')
1243 command = command.replace('\n', os.linesep + ps2)
1244 self.write(command)
1245 wx.TheClipboard.Close()
1246
095315e2 1247
d14a1e28
RD
1248 def PasteAndRun(self):
1249 """Replace selection with clipboard contents, run commands."""
095315e2 1250 text = ''
d14a1e28 1251 if wx.TheClipboard.Open():
d14a1e28
RD
1252 if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
1253 data = wx.TextDataObject()
1254 if wx.TheClipboard.GetData(data):
d14a1e28 1255 text = data.GetText()
d14a1e28 1256 wx.TheClipboard.Close()
095315e2
RD
1257 if text:
1258 self.Execute(text)
1259
1260
1261 def Execute(self, text):
1262 """Replace selection with text and run commands."""
1263 ps1 = str(sys.ps1)
1264 ps2 = str(sys.ps2)
1265 endpos = self.GetTextLength()
1266 self.SetCurrentPos(endpos)
1267 startpos = self.promptPosEnd
1268 self.SetSelection(startpos, endpos)
1269 self.ReplaceSelection('')
1270 text = text.lstrip()
1271 text = self.fixLineEndings(text)
1272 text = self.lstripPrompt(text)
1273 text = text.replace(os.linesep + ps1, '\n')
1274 text = text.replace(os.linesep + ps2, '\n')
1275 text = text.replace(os.linesep, '\n')
1276 lines = text.split('\n')
1277 commands = []
1278 command = ''
1279 for line in lines:
1280 if line.strip() == ps2.strip():
1281 # If we are pasting from something like a
1282 # web page that drops the trailing space
1283 # from the ps2 prompt of a blank line.
1284 line = ''
1285 lstrip = line.lstrip()
1286 if line.strip() != '' and lstrip == line and \
1287 lstrip[:4] not in ['else','elif'] and \
1288 lstrip[:6] != 'except':
1289 # New command.
1290 if command:
1291 # Add the previous command to the list.
1292 commands.append(command)
1293 # Start a new command, which may be multiline.
1294 command = line
1295 else:
1296 # Multiline command. Add to the command.
1297 command += '\n'
1298 command += line
1299 commands.append(command)
1300 for command in commands:
1301 command = command.replace('\n', os.linesep + ps2)
1302 self.write(command)
1303 self.processLine()
1304
d14a1e28
RD
1305
1306 def wrap(self, wrap=True):
1307 """Sets whether text is word wrapped."""
1308 try:
1309 self.SetWrapMode(wrap)
1310 except AttributeError:
1311 return 'Wrapping is not available in this version.'
1312
1313 def zoom(self, points=0):
1314 """Set the zoom level.
1315
1316 This number of points is added to the size of all fonts. It
1317 may be positive to magnify or negative to reduce."""
1318 self.SetZoom(points)
02b800ce
RD
1319
1320
1321
1322 def LoadSettings(self, config):
1323 self.autoComplete = config.ReadBool('Options/AutoComplete', True)
1324 self.autoCompleteIncludeMagic = config.ReadBool('Options/AutoCompleteIncludeMagic', True)
1325 self.autoCompleteIncludeSingle = config.ReadBool('Options/AutoCompleteIncludeSingle', True)
1326 self.autoCompleteIncludeDouble = config.ReadBool('Options/AutoCompleteIncludeDouble', True)
1327
1328 self.autoCallTip = config.ReadBool('Options/AutoCallTip', True)
1329 self.callTipInsert = config.ReadBool('Options/CallTipInsert', True)
1330 self.SetWrapMode(config.ReadBool('View/WrapMode', True))
1331
1332 useAA = config.ReadBool('Options/UseAntiAliasing', self.GetUseAntiAliasing())
1333 self.SetUseAntiAliasing(useAA)
1334 self.lineNumbers = config.ReadBool('View/ShowLineNumbers', True)
1335 self.setDisplayLineNumbers (self.lineNumbers)
1336 zoom = config.ReadInt('View/Zoom/Shell', -99)
1337 if zoom != -99:
1338 self.SetZoom(zoom)
1339
1340
1341
1342 def SaveSettings(self, config):
1343 config.WriteBool('Options/AutoComplete', self.autoComplete)
1344 config.WriteBool('Options/AutoCompleteIncludeMagic', self.autoCompleteIncludeMagic)
1345 config.WriteBool('Options/AutoCompleteIncludeSingle', self.autoCompleteIncludeSingle)
1346 config.WriteBool('Options/AutoCompleteIncludeDouble', self.autoCompleteIncludeDouble)
1347 config.WriteBool('Options/AutoCallTip', self.autoCallTip)
1348 config.WriteBool('Options/CallTipInsert', self.callTipInsert)
1349 config.WriteBool('Options/UseAntiAliasing', self.GetUseAntiAliasing())
1350 config.WriteBool('View/WrapMode', self.GetWrapMode())
1351 config.WriteBool('View/ShowLineNumbers', self.lineNumbers)
1352 config.WriteInt('View/Zoom/Shell', self.GetZoom())
1353
1354
1355
1356## NOTE: The DnD of file names is disabled until I can figure out how
1357## best to still allow DnD of text.
1358
1359
1360## #seb : File drag and drop
1361## class FileDropTarget(wx.FileDropTarget):
1362## def __init__(self, obj):
1363## wx.FileDropTarget.__init__(self)
1364## self.obj = obj
1365## def OnDropFiles(self, x, y, filenames):
1366## if len(filenames) == 1:
1367## txt = 'r\"%s\"' % filenames[0]
1368## else:
1369## txt = '( '
1370## for f in filenames:
1371## txt += 'r\"%s\" , ' % f
1372## txt += ')'
1373## self.obj.AppendText(txt)
1374## pos = self.obj.GetCurrentPos()
1375## self.obj.SetCurrentPos( pos )
1376## self.obj.SetSelection( pos, pos )
1377
1378
1379
1380## class TextAndFileDropTarget(wx.DropTarget):
1381## def __init__(self, shell):
1382## wx.DropTarget.__init__(self)
1383## self.shell = shell
1384## self.compdo = wx.DataObjectComposite()
1385## self.textdo = wx.TextDataObject()
1386## self.filedo = wx.FileDataObject()
1387## self.compdo.Add(self.textdo)
1388## self.compdo.Add(self.filedo, True)
1389
1390## self.SetDataObject(self.compdo)
1391
1392## def OnDrop(self, x, y):
1393## return True
1394
1395## def OnData(self, x, y, result):
1396## self.GetData()
1397## if self.textdo.GetTextLength() > 1:
1398## text = self.textdo.GetText()
1399## # *** Do somethign with the dragged text here...
1400## self.textdo.SetText('')
1401## else:
1402## filenames = str(self.filename.GetFilenames())
1403## if len(filenames) == 1:
1404## txt = 'r\"%s\"' % filenames[0]
1405## else:
1406## txt = '( '
1407## for f in filenames:
1408## txt += 'r\"%s\" , ' % f
1409## txt += ')'
1410## self.shell.AppendText(txt)
1411## pos = self.shell.GetCurrentPos()
1412## self.shell.SetCurrentPos( pos )
1413## self.shell.SetSelection( pos, pos )
1414
1415## return result
1416