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