1 """A (less & less) simple Python editor"""
19 _scriptuntitledcounter
= 1
20 _wordchars
= string
.letters
+ string
.digits
+ "_"
23 class Editor(W
.Window
):
25 def __init__(self
, path
= "", title
= ""):
26 defaultfontsettings
, defaulttabsettings
, defaultwindowsize
= geteditorprefs()
27 global _scriptuntitledcounter
32 self
.title
= "Untitled Script " + `_scriptuntitledcounter`
33 _scriptuntitledcounter
= _scriptuntitledcounter
+ 1
35 self
._creator
= W
._signature
36 elif os
.path
.exists(path
):
37 path
= resolvealiases(path
)
38 dir, name
= os
.path
.split(path
)
43 fss
= macfs
.FSSpec(path
)
44 self
._creator
, filetype
= fss
.GetCreatorType()
46 raise IOError, "file '%s' does not exist" % path
51 if string
.find(text
, '\r\n') >= 0:
57 change
= EasyDialogs
.AskYesNoCancel('³%s² contains %s-style line feeds. Change them to MacOS carriage returns?' % (self
.title
, sourceOS
), 1)
58 # bug: Cancel is treated as No
60 text
= string
.replace(text
, searchString
, '\r')
66 self
.readwindowsettings()
67 if self
.settings
.has_key("windowbounds"):
68 bounds
= self
.settings
["windowbounds"]
70 bounds
= defaultwindowsize
71 if self
.settings
.has_key("fontsettings"):
72 self
.fontsettings
= self
.settings
["fontsettings"]
74 self
.fontsettings
= defaultfontsettings
75 if self
.settings
.has_key("tabsize"):
77 self
.tabsettings
= (tabsize
, tabmode
) = self
.settings
["tabsize"]
79 self
.tabsettings
= defaulttabsettings
81 self
.tabsettings
= defaulttabsettings
83 W
.Window
.__init
__(self
, bounds
, self
.title
, minsize
= (330, 120), tabbable
= 0)
84 self
.setupwidgets(text
)
86 self
.editgroup
.editor
.changed
= 1
88 if self
.settings
.has_key("selection"):
89 selstart
, selend
= self
.settings
["selection"]
90 self
.setselection(selstart
, selend
)
94 self
._buf
= "" # for write method
97 if self
.settings
.has_key("run_as_main"):
98 self
.run_as_main
= self
.settings
["run_as_main"]
102 def readwindowsettings(self
):
104 resref
= Res
.OpenResFile(self
.path
)
108 Res
.UseResFile(resref
)
109 data
= Res
.Get1Resource('PyWS', 128)
110 self
.settings
= marshal
.loads(data
.data
)
113 Res
.CloseResFile(resref
)
115 def writewindowsettings(self
):
117 resref
= Res
.OpenResFile(self
.path
)
119 Res
.CreateResFile(self
.path
)
120 resref
= Res
.OpenResFile(self
.path
)
122 data
= Res
.Resource(marshal
.dumps(self
.settings
))
123 Res
.UseResFile(resref
)
125 temp
= Res
.Get1Resource('PyWS', 128)
126 temp
.RemoveResource()
129 data
.AddResource('PyWS', 128, "window settings")
131 Res
.UpdateResFile(resref
)
132 Res
.CloseResFile(resref
)
134 def getsettings(self
):
136 self
.settings
["windowbounds"] = self
.getbounds()
137 self
.settings
["selection"] = self
.getselection()
138 self
.settings
["fontsettings"] = self
.editgroup
.editor
.getfontsettings()
139 self
.settings
["tabsize"] = self
.editgroup
.editor
.gettabsettings()
140 self
.settings
["run_as_main"] = self
.run_as_main
143 return self
.editgroup
.editor
.get()
145 def getselection(self
):
146 return self
.editgroup
.editor
.ted
.WEGetSelection()
148 def setselection(self
, selstart
, selend
):
149 self
.editgroup
.editor
.setselection(selstart
, selend
)
151 def getfilename(self
):
154 return '<%s>' % self
.title
156 def setupwidgets(self
, text
):
159 self
.lastlineno
= None
162 self
.editgroup
= W
.Group((0, topbarheight
+ 1, 0, 0))
163 editor
= W
.PyEditor((0, 0, -15,-15), text
,
164 fontsettings
= self
.fontsettings
,
165 tabsettings
= self
.tabsettings
,
166 file = self
.getfilename())
169 self
.popfield
= ClassFinder((popfieldwidth
- 17, -15, 16, 16), [], self
.popselectline
)
170 self
.linefield
= W
.EditText((-1, -15, popfieldwidth
- 15, 16), inset
= (6, 1))
171 self
.editgroup
._barx
= W
.Scrollbar((popfieldwidth
- 2, -15, -14, 16), editor
.hscroll
, max = 32767)
172 self
.editgroup
._bary
= W
.Scrollbar((-15, 14, 16, -14), editor
.vscroll
, max = 32767)
173 self
.editgroup
.editor
= editor
# add editor *after* scrollbars
175 self
.editgroup
.optionsmenu
= W
.PopupMenu((-15, -1, 16, 16), [])
176 self
.editgroup
.optionsmenu
.bind('<click>', self
.makeoptionsmenu
)
178 self
.bevelbox
= W
.BevelBox((0, 0, 0, topbarheight
))
179 self
.hline
= W
.HorizontalLine((0, topbarheight
, 0, 0))
180 self
.infotext
= W
.TextBox((175, 6, -4, 14), backgroundcolor
= (0xe000, 0xe000, 0xe000))
181 self
.runbutton
= W
.Button((5, 4, 80, 16), "Run all", self
.run
)
182 self
.runselbutton
= W
.Button((90, 4, 80, 16), "Run selection", self
.runselection
)
185 editor
.bind("cmdr", self
.runbutton
.push
)
186 editor
.bind("enter", self
.runselbutton
.push
)
187 editor
.bind("cmdj", self
.domenu_gotoline
)
188 editor
.bind("cmdd", self
.domenu_toggledebugger
)
189 editor
.bind("<idle>", self
.updateselection
)
191 editor
.bind("cmde", searchengine
.setfindstring
)
192 editor
.bind("cmdf", searchengine
.show
)
193 editor
.bind("cmdg", searchengine
.findnext
)
194 editor
.bind("cmdshiftr", searchengine
.replace
)
195 editor
.bind("cmdt", searchengine
.replacefind
)
197 self
.linefield
.bind("return", self
.dolinefield
)
198 self
.linefield
.bind("enter", self
.dolinefield
)
199 self
.linefield
.bind("tab", self
.dolinefield
)
202 editor
.bind("<click>", self
.clickeditor
)
203 self
.linefield
.bind("<click>", self
.clicklinefield
)
205 def makeoptionsmenu(self
):
206 menuitems
= [('Font settingsŠ', self
.domenu_fontsettings
),
207 ("Save optionsŠ", self
.domenu_options
),
209 ('\0' + chr(self
.run_as_main
) + 'Run as __main__', self
.domenu_toggle_run_as_main
),
210 ('Modularize', self
.domenu_modularize
),
211 ('Browse namespaceŠ', self
.domenu_browsenamespace
),
214 menuitems
= menuitems
+ [('Disable profiler', self
.domenu_toggleprofiler
)]
216 menuitems
= menuitems
+ [('Enable profiler', self
.domenu_toggleprofiler
)]
217 if self
.editgroup
.editor
._debugger
:
218 menuitems
= menuitems
+ [('Disable debugger', self
.domenu_toggledebugger
),
219 ('Clear breakpoints', self
.domenu_clearbreakpoints
),
220 ('Edit breakpointsŠ', self
.domenu_editbreakpoints
)]
222 menuitems
= menuitems
+ [('Enable debugger', self
.domenu_toggledebugger
)]
223 self
.editgroup
.optionsmenu
.set(menuitems
)
225 def domenu_toggle_run_as_main(self
):
226 self
.run_as_main
= not self
.run_as_main
227 self
.editgroup
.editor
.selchanged
= 1
229 def showbreakpoints(self
, onoff
):
230 self
.editgroup
.editor
.showbreakpoints(onoff
)
231 self
.debugging
= onoff
233 def domenu_clearbreakpoints(self
, *args
):
234 self
.editgroup
.editor
.clearbreakpoints()
236 def domenu_editbreakpoints(self
, *args
):
237 self
.editgroup
.editor
.editbreakpoints()
239 def domenu_toggledebugger(self
, *args
):
240 if not self
.debugging
:
242 self
.debugging
= not self
.debugging
243 self
.editgroup
.editor
.togglebreakpoints()
245 def domenu_toggleprofiler(self
, *args
):
246 self
.profiling
= not self
.profiling
248 def domenu_browsenamespace(self
, *args
):
251 globals, file, modname
= self
.getenvironment()
254 PyBrowser
.Browser(globals, "Object browser: " + modname
)
256 def domenu_modularize(self
, *args
):
257 modname
= _filename_as_modname(self
.title
)
259 raise W
.AlertError
, 'Can¹t modularize ³%s²' % self
.title
260 run_as_main
= self
.run_as_main
263 self
.run_as_main
= run_as_main
269 if self
.globals and not sys
.modules
.has_key(modname
):
270 module
= imp
.new_module(modname
)
271 for attr
in self
.globals.keys():
272 setattr(module
,attr
,self
.globals[attr
])
273 sys
.modules
[modname
] = module
276 def domenu_fontsettings(self
, *args
):
278 fontsettings
= self
.editgroup
.editor
.getfontsettings()
279 tabsettings
= self
.editgroup
.editor
.gettabsettings()
280 settings
= FontSettings
.FontDialog(fontsettings
, tabsettings
)
282 fontsettings
, tabsettings
= settings
283 self
.editgroup
.editor
.setfontsettings(fontsettings
)
284 self
.editgroup
.editor
.settabsettings(tabsettings
)
286 def domenu_options(self
, *args
):
287 rv
= SaveOptions(self
._creator
)
289 self
.editgroup
.editor
.selchanged
= 1 # ouch...
292 def clicklinefield(self
):
293 if self
._currentwidget
<> self
.linefield
:
294 self
.linefield
.select(1)
295 self
.linefield
.selectall()
298 def clickeditor(self
):
299 if self
._currentwidget
<> self
.editgroup
.editor
:
303 def updateselection(self
, force
= 0):
304 sel
= min(self
.editgroup
.editor
.getselection())
305 lineno
= self
.editgroup
.editor
.offsettoline(sel
)
306 if lineno
<> self
.lastlineno
or force
:
307 self
.lastlineno
= lineno
308 self
.linefield
.set(str(lineno
+ 1))
309 self
.linefield
.selview()
311 def dolinefield(self
):
313 lineno
= string
.atoi(self
.linefield
.get()) - 1
314 if lineno
<> self
.lastlineno
:
315 self
.editgroup
.editor
.selectline(lineno
)
316 self
.updateselection(1)
318 self
.updateselection(1)
319 self
.editgroup
.editor
.select(1)
321 def setinfotext(self
):
322 if not hasattr(self
, 'infotext'):
325 self
.infotext
.set(self
.path
)
327 self
.infotext
.set("")
330 if self
.editgroup
.editor
.changed
:
333 Qd
.InitCursor() # XXX should be done by dialog
334 save
= EasyDialogs
.AskYesNoCancel('Save window ³%s² before closing?' % self
.title
, 1)
336 if self
.domenu_save():
340 self
.globals = None # XXX doesn't help... all globals leak :-(
343 def domenu_close(self
, *args
):
346 def domenu_save(self
, *args
):
348 # Will call us recursively
349 return self
.domenu_save_as()
350 data
= self
.editgroup
.editor
.get()
351 fp
= open(self
.path
, 'wb') # open file in binary mode, data has '\r' line-endings
354 fss
= macfs
.FSSpec(self
.path
)
355 fss
.SetCreatorType(self
._creator
, 'TEXT')
357 self
.writewindowsettings()
358 self
.editgroup
.editor
.changed
= 0
359 self
.editgroup
.editor
.selchanged
= 0
361 if linecache
.cache
.has_key(self
.path
):
362 del linecache
.cache
[self
.path
]
364 macostools
.touched(self
.path
)
366 def can_save(self
, menuitem
):
367 return self
.editgroup
.editor
.changed
or self
.editgroup
.editor
.selchanged
369 def domenu_save_as(self
, *args
):
370 fss
, ok
= macfs
.StandardPutFile('Save as:', self
.title
)
373 self
.showbreakpoints(0)
374 self
.path
= fss
.as_pathname()
376 self
.title
= os
.path
.split(self
.path
)[-1]
377 self
.wid
.SetWTitle(self
.title
)
379 self
.editgroup
.editor
.setfile(self
.getfilename())
380 app
= W
.getapplication()
381 app
.makeopenwindowsmenu()
382 if hasattr(app
, 'makescriptsmenu'):
383 app
= W
.getapplication()
384 fss
, fss_changed
= app
.scriptsfolder
.Resolve()
385 path
= fss
.as_pathname()
386 if path
== self
.path
[:len(path
)]:
387 W
.getapplication().makescriptsmenu()
389 def domenu_save_as_applet(self
, *args
):
393 # only have buildtools in Python >= 1.5.2
394 raise W
.AlertError
, "³Save as Applet² is only supported in\rPython 1.5.2 and up."
396 buildtools
.DEBUG
= 0 # ouch.
398 if self
.title
[-3:] == ".py":
399 destname
= self
.title
[:-3]
401 destname
= self
.title
+ ".applet"
402 fss
, ok
= macfs
.StandardPutFile('Save as Applet:', destname
)
406 destname
= fss
.as_pathname()
409 if filename
[-3:] == ".py":
410 rsrcname
= filename
[:-3] + '.rsrc'
412 rsrcname
= filename
+ '.rsrc'
414 filename
= self
.title
417 pytext
= self
.editgroup
.editor
.get()
418 pytext
= string
.split(pytext
, '\r')
419 pytext
= string
.join(pytext
, '\n') + '\n'
421 code
= compile(pytext
, filename
, "exec")
422 except (SyntaxError, EOFError):
423 raise buildtools
.BuildError
, "Syntax error in script %s" % `filename`
425 # Try removing the output file
430 template
= buildtools
.findtemplate()
431 buildtools
.process_common(template
, None, code
, rsrcname
, destname
, 0, 1)
433 def domenu_gotoline(self
, *args
):
434 self
.linefield
.selectall()
435 self
.linefield
.select(1)
436 self
.linefield
.selectall()
438 def domenu_selectline(self
, *args
):
439 self
.editgroup
.editor
.expandselection()
441 def domenu_find(self
, *args
):
444 def domenu_entersearchstring(self
, *args
):
445 searchengine
.setfindstring()
447 def domenu_replace(self
, *args
):
448 searchengine
.replace()
450 def domenu_findnext(self
, *args
):
451 searchengine
.findnext()
453 def domenu_replacefind(self
, *args
):
454 searchengine
.replacefind()
456 def domenu_run(self
, *args
):
457 self
.runbutton
.push()
459 def domenu_runselection(self
, *args
):
460 self
.runselbutton
.push()
466 pytext
= self
.editgroup
.editor
.get()
467 globals, file, modname
= self
.getenvironment()
468 self
.execstring(pytext
, globals, globals, file, modname
)
470 def runselection(self
):
473 def _runselection(self
):
474 globals, file, modname
= self
.getenvironment()
477 self
.editgroup
.editor
.expandselection()
479 # get lineno of first selected line
480 selstart
, selend
= self
.editgroup
.editor
.getselection()
481 selstart
, selend
= min(selstart
, selend
), max(selstart
, selend
)
482 selfirstline
= self
.editgroup
.editor
.offsettoline(selstart
)
483 alltext
= self
.editgroup
.editor
.get()
484 pytext
= alltext
[selstart
:selend
]
485 lines
= string
.split(pytext
, '\r')
486 indent
= getminindent(lines
)
489 alllines
= string
.split(alltext
, '\r')
490 identifieRE_match
= _identifieRE
.match
491 for i
in range(selfirstline
- 1, -1, -1):
493 if line
[:6] == 'class ':
494 classname
= string
.split(string
.strip(line
[6:]))[0]
495 classend
= identifieRE_match(classname
)
497 raise W
.AlertError
, 'Can¹t find a class.'
498 classname
= classname
[:classend
]
500 elif line
and line
[0] not in '\t#':
501 raise W
.AlertError
, 'Can¹t find a class.'
503 raise W
.AlertError
, 'Can¹t find a class.'
504 if globals.has_key(classname
):
505 locals = globals[classname
].__dict
__
507 raise W
.AlertError
, 'Can¹t find class ³%s².' % classname
508 # dedent to top level
509 for i
in range(len(lines
)):
510 lines
[i
] = lines
[i
][1:]
511 pytext
= string
.join(lines
, '\r')
513 raise W
.AlertError
, 'Can¹t run indented code.'
515 # add "newlines" to fool compile/exec:
516 # now a traceback will give the right line number
517 pytext
= selfirstline
* '\r' + pytext
518 self
.execstring(pytext
, globals, locals, file, modname
)
520 def execstring(self
, pytext
, globals, locals, file, modname
):
521 tracebackwindow
.hide()
523 W
.getapplication().refreshwindows()
527 dir = os
.path
.dirname(self
.path
)
528 savedir
= os
.getcwd()
530 sys
.path
.insert(0, dir)
534 execstring(pytext
, globals, locals, file, self
.debugging
,
535 modname
, self
.profiling
)
541 def getenvironment(self
):
544 dir = os
.path
.dirname(file)
545 # check if we're part of a package
547 while os
.path
.exists(os
.path
.join(dir, "__init__.py")):
548 dir, dirname
= os
.path
.split(dir)
549 modname
= dirname
+ '.' + modname
550 subname
= _filename_as_modname(self
.title
)
552 if subname
== "__init__":
553 # strip trailing period
554 modname
= modname
[:-1]
556 modname
= modname
+ subname
559 if sys
.modules
.has_key(modname
):
560 globals = sys
.modules
[modname
].__dict
__
563 globals = self
.globals
565 file = '<%s>' % self
.title
566 globals = self
.globals
568 return globals, file, modname
570 def write(self
, stuff
):
571 """for use as stdout"""
572 self
._buf
= self
._buf
+ stuff
573 if '\n' in self
._buf
:
577 stuff
= string
.split(self
._buf
, '\n')
578 stuff
= string
.join(stuff
, '\r')
579 end
= self
.editgroup
.editor
.ted
.WEGetTextLength()
580 self
.editgroup
.editor
.ted
.WESetSelection(end
, end
)
581 self
.editgroup
.editor
.ted
.WEInsert(stuff
, None, None)
582 self
.editgroup
.editor
.updatescrollbars()
585 #self.wid.SelectWindow()
587 def getclasslist(self
):
588 from string
import find
, strip
590 methodRE
= re
.compile(r
"\r[ \t]+def ")
591 findMethod
= methodRE
.search
592 editor
= self
.editgroup
.editor
600 if text
[:4] == 'def ':
601 append((pos
+ 4, functag
))
604 pos
= find(text
, '\rdef ', pos
+ 1)
607 append((pos
+ 5, functag
))
609 if text
[:6] == 'class ':
610 append((pos
+ 6, classtag
))
613 pos
= find(text
, '\rclass ', pos
+ 1)
616 append((pos
+ 7, classtag
))
619 m
= findMethod(text
, pos
+ 1)
623 #pos = find(text, '\r\tdef ', pos + 1)
624 append((m
.regs
[0][1], methodtag
))
627 methodlistappend
= None
628 offsetToLine
= editor
.ted
.WEOffsetToLine
629 getLineRange
= editor
.ted
.WEGetLineRange
630 append
= classlist
.append
631 identifieRE_match
= _identifieRE
.match
632 for pos
, tag
in list:
633 lineno
= offsetToLine(pos
)
634 lineStart
, lineEnd
= getLineRange(lineno
)
635 line
= strip(text
[pos
:lineEnd
])
636 line
= line
[:identifieRE_match(line
)]
638 append(("def " + line
, lineno
+ 1))
639 methodlistappend
= None
640 elif tag
is classtag
:
641 append(["class " + line
])
642 methodlistappend
= classlist
[-1].append
643 elif methodlistappend
and tag
is methodtag
:
644 methodlistappend(("def " + line
, lineno
+ 1))
647 def popselectline(self
, lineno
):
648 self
.editgroup
.editor
.selectline(lineno
- 1)
650 def selectline(self
, lineno
, charoffset
= 0):
651 self
.editgroup
.editor
.selectline(lineno
- 1, charoffset
)
655 def __init__(self
, creator
):
657 self
.w
= w
= W
.ModalDialog((240, 140), 'Save options')
659 w
.label
= W
.TextBox((8, 8, 80, 18), "File creator:")
660 w
.ide_radio
= W
.RadioButton((8, 22, 160, 18), "This application", radiobuttons
, self
.ide_hit
)
661 w
.interp_radio
= W
.RadioButton((8, 42, 160, 18), "Python Interpreter", radiobuttons
, self
.interp_hit
)
662 w
.other_radio
= W
.RadioButton((8, 62, 50, 18), "Other:", radiobuttons
)
663 w
.other_creator
= W
.EditText((62, 62, 40, 20), creator
, self
.otherselect
)
664 w
.cancelbutton
= W
.Button((-180, -30, 80, 16), "Cancel", self
.cancelbuttonhit
)
665 w
.okbutton
= W
.Button((-90, -30, 80, 16), "Done", self
.okbuttonhit
)
666 w
.setdefaultbutton(w
.okbutton
)
667 if creator
== 'Pyth':
668 w
.interp_radio
.set(1)
669 elif creator
== W
._signature
:
673 w
.bind("cmd.", w
.cancelbutton
.push
)
677 self
.w
.other_creator
.set(W
._signature
)
679 def interp_hit(self
):
680 self
.w
.other_creator
.set("Pyth")
682 def otherselect(self
, *args
):
683 sel_from
, sel_to
= self
.w
.other_creator
.getselection()
684 creator
= self
.w
.other_creator
.get()[:4]
685 creator
= creator
+ " " * (4 - len(creator
))
686 self
.w
.other_creator
.set(creator
)
687 self
.w
.other_creator
.setselection(sel_from
, sel_to
)
688 self
.w
.other_radio
.set(1)
690 def cancelbuttonhit(self
):
693 def okbuttonhit(self
):
694 self
.rv
= self
.w
.other_creator
.get()[:4]
698 def SaveOptions(creator
):
699 s
= _saveoptions(creator
)
703 def _escape(where
, what
) :
704 return string
.join(string
.split(where
, what
), '\\' + what
)
706 def _makewholewordpattern(word
):
707 # first, escape special regex chars
708 for esc
in "\\[].*^+$?":
709 word
= _escape(word
, esc
)
711 notwordcharspat
= '[^' + _wordchars
+ ']'
712 pattern
= '\(' + word
+ '\)'
713 if word
[0] in _wordchars
:
714 pattern
= notwordcharspat
+ pattern
715 if word
[-1] in _wordchars
:
716 pattern
= pattern
+ notwordcharspat
717 return regex
.compile(pattern
)
724 self
.parms
= { "find": "",
731 prefs
= MacPrefs
.GetPrefs(W
.getapplication().preffilepath
)
732 if prefs
.searchengine
:
733 self
.parms
["casesens"] = prefs
.searchengine
.casesens
734 self
.parms
["wrap"] = prefs
.searchengine
.wrap
735 self
.parms
["wholeword"] = prefs
.searchengine
.wholeword
740 self
.w
.wid
.ShowWindow()
741 self
.w
.wid
.SelectWindow()
742 self
.w
.find
.edit
.select(1)
743 self
.w
.find
.edit
.selectall()
745 self
.w
= W
.Dialog((420, 150), "Find")
747 self
.w
.find
= TitledEditText((10, 4, 300, 36), "Search for:")
748 self
.w
.replace
= TitledEditText((10, 100, 300, 36), "Replace with:")
750 self
.w
.boxes
= W
.Group((10, 50, 300, 40))
751 self
.w
.boxes
.casesens
= W
.CheckBox((0, 0, 100, 16), "Case sensitive")
752 self
.w
.boxes
.wholeword
= W
.CheckBox((0, 20, 100, 16), "Whole word")
753 self
.w
.boxes
.wrap
= W
.CheckBox((110, 0, 100, 16), "Wrap around")
755 self
.buttons
= [ ("Find", "cmdf", self
.find
),
756 ("Replace", "cmdr", self
.replace
),
757 ("Replace all", None, self
.replaceall
),
758 ("Don¹t find", "cmdd", self
.dont
),
759 ("Cancel", "cmd.", self
.cancel
)
761 for i
in range(len(self
.buttons
)):
762 bounds
= -90, 22 + i
* 24, 80, 16
763 title
, shortcut
, callback
= self
.buttons
[i
]
764 self
.w
[title
] = W
.Button(bounds
, title
, callback
)
766 self
.w
.bind(shortcut
, self
.w
[title
].push
)
767 self
.w
.setdefaultbutton(self
.w
["Don¹t find"])
768 self
.w
.find
.edit
.bind("<key>", self
.key
)
769 self
.w
.bind("<activate>", self
.activate
)
770 self
.w
.bind("<close>", self
.close
)
773 self
.w
.find
.edit
.select(1)
774 self
.w
.find
.edit
.selectall()
781 def key(self
, char
, modifiers
):
782 self
.w
.find
.edit
.key(char
, modifiers
)
786 def activate(self
, onoff
):
790 def checkbuttons(self
):
791 editor
= findeditor(self
)
793 if self
.w
.find
.get():
794 for title
, cmd
, call
in self
.buttons
[:-2]:
795 self
.w
[title
].enable(1)
796 self
.w
.setdefaultbutton(self
.w
["Find"])
798 for title
, cmd
, call
in self
.buttons
[:-2]:
799 self
.w
[title
].enable(0)
800 self
.w
.setdefaultbutton(self
.w
["Don¹t find"])
802 for title
, cmd
, call
in self
.buttons
[:-2]:
803 self
.w
[title
].enable(0)
804 self
.w
.setdefaultbutton(self
.w
["Don¹t find"])
807 self
.getparmsfromwindow()
812 editor
= findeditor(self
)
816 self
.getparmsfromwindow()
817 text
= editor
.getselectedtext()
818 find
= self
.parms
["find"]
819 if not self
.parms
["casesens"]:
820 find
= string
.lower(find
)
821 text
= string
.lower(text
)
824 editor
.insert(self
.parms
["replace"])
826 def replaceall(self
):
827 editor
= findeditor(self
)
831 self
.getparmsfromwindow()
833 find
= self
.parms
["find"]
837 replace
= self
.parms
["replace"]
838 replacelen
= len(replace
)
840 if not self
.parms
["casesens"]:
841 find
= string
.lower(find
)
842 text
= string
.lower(Text
)
849 if self
.parms
["wholeword"]:
850 wholewordRE
= _makewholewordpattern(find
)
851 wholewordRE
.search(text
, pos
)
853 pos
= wholewordRE
.regs
[1][0]
857 pos
= string
.find(text
, find
, pos
)
860 counter
= counter
+ 1
861 text
= text
[:pos
] + replace
+ text
[pos
+ findlen
:]
862 Text
= Text
[:pos
] + replace
+ Text
[pos
+ findlen
:]
863 pos
= pos
+ replacelen
870 editor
.selchanged
= 1
871 editor
.ted
.WEUseText(Res
.Resource(Text
))
872 editor
.ted
.WECalText()
874 Win
.InvalRect(editor
._bounds
)
875 #editor.ted.WEUpdate(self.w.wid.GetWindowPort().visRgn)
876 EasyDialogs
.Message("Replaced %d occurrences" % counter
)
879 self
.getparmsfromwindow()
882 def replacefind(self
):
886 def setfindstring(self
):
887 editor
= findeditor(self
)
890 find
= editor
.getselectedtext()
893 self
.parms
["find"] = find
895 self
.w
.find
.edit
.set(self
.parms
["find"])
896 self
.w
.find
.edit
.selectall()
899 editor
= findeditor(self
)
902 find
= self
.parms
["find"]
906 if not self
.parms
["casesens"]:
907 find
= string
.lower(find
)
908 text
= string
.lower(text
)
909 selstart
, selend
= editor
.getselection()
910 selstart
, selend
= min(selstart
, selend
), max(selstart
, selend
)
911 if self
.parms
["wholeword"]:
912 wholewordRE
= _makewholewordpattern(find
)
913 wholewordRE
.search(text
, selend
)
915 pos
= wholewordRE
.regs
[1][0]
919 pos
= string
.find(text
, find
, selend
)
921 editor
.setselection(pos
, pos
+ len(find
))
923 elif self
.parms
["wrap"]:
924 if self
.parms
["wholeword"]:
925 wholewordRE
.search(text
, 0)
927 pos
= wholewordRE
.regs
[1][0]
931 pos
= string
.find(text
, find
)
932 if selstart
> pos
>= 0:
933 editor
.setselection(pos
, pos
+ len(find
))
937 for key
, value
in self
.parms
.items():
939 self
.w
[key
].set(value
)
941 self
.w
.boxes
[key
].set(value
)
943 def getparmsfromwindow(self
):
946 for key
, value
in self
.parms
.items():
948 value
= self
.w
[key
].get()
950 value
= self
.w
.boxes
[key
].get()
951 self
.parms
[key
] = value
959 self
.w
.wid
.HideWindow()
962 def writeprefs(self
):
964 self
.getparmsfromwindow()
965 prefs
= MacPrefs
.GetPrefs(W
.getapplication().preffilepath
)
966 prefs
.searchengine
.casesens
= self
.parms
["casesens"]
967 prefs
.searchengine
.wrap
= self
.parms
["wrap"]
968 prefs
.searchengine
.wholeword
= self
.parms
["wholeword"]
972 class TitledEditText(W
.Group
):
974 def __init__(self
, possize
, title
, text
= ""):
975 W
.Group
.__init
__(self
, possize
)
976 self
.title
= W
.TextBox((0, 0, 0, 16), title
)
977 self
.edit
= W
.EditText((0, 16, 0, 0), text
)
979 def set(self
, value
):
983 return self
.edit
.get()
986 class ClassFinder(W
.PopupWidget
):
988 def click(self
, point
, modifiers
):
990 self
.set(self
._parentwindow
.getclasslist())
991 W
.PopupWidget
.click(self
, point
, modifiers
)
994 def getminindent(lines
):
997 stripped
= string
.strip(line
)
998 if not stripped
or stripped
[0] == '#':
1000 if indent
< 0 or line
[:indent
] <> indent
* '\t':
1010 return not not ord(Evt
.GetKeys()[7]) & 0x04
1013 def execstring(pytext
, globals, locals, filename
="<string>", debugging
=0,
1014 modname
="__main__", profiling
=0):
1016 import PyDebugger
, bdb
1017 BdbQuit
= bdb
.BdbQuit
1019 BdbQuit
= 'BdbQuitDummyException'
1020 pytext
= string
.split(pytext
, '\r')
1021 pytext
= string
.join(pytext
, '\n') + '\n'
1022 W
.SetCursor("watch")
1023 globals['__name__'] = modname
1024 globals['__file__'] = filename
1025 sys
.argv
= [filename
]
1027 code
= compile(pytext
, filename
, "exec")
1029 # XXXX BAAAADDD.... We let tracebackwindow decide to treat SyntaxError
1030 # special. That's wrong because THIS case is special (could be literal
1031 # overflow!) and SyntaxError could mean we need a traceback (syntax error
1032 # in imported module!!!
1033 tracebackwindow
.traceback(1, filename
)
1037 PyDebugger
.startfromhere()
1039 MacOS
.EnableAppswitch(0)
1042 import profile
, ProfileBrowser
1043 p
= profile
.Profile()
1046 p
.runctx(code
, globals, locals)
1050 stats
= pstats
.Stats(p
)
1051 ProfileBrowser
.ProfileBrowser(stats
)
1053 exec code
in globals, locals
1055 MacOS
.EnableAppswitch(-1)
1056 except W
.AlertError
, detail
:
1057 raise W
.AlertError
, detail
1058 except (KeyboardInterrupt, BdbQuit
):
1063 PyDebugger
.postmortem(sys
.exc_type
, sys
.exc_value
, sys
.exc_traceback
)
1066 tracebackwindow
.traceback(1, filename
)
1072 _identifieRE
= regex
.compile("[A-Za-z_][A-Za-z_0-9]*")
1074 def _filename_as_modname(fname
):
1075 if fname
[-3:] == '.py':
1076 modname
= fname
[:-3]
1077 if _identifieRE
.match(modname
) == len(modname
):
1078 return string
.join(string
.split(modname
, '.'), '_')
1080 def findeditor(topwindow
, fromtop
= 0):
1081 wid
= Win
.FrontWindow()
1083 if topwindow
.w
and wid
== topwindow
.w
.wid
:
1084 wid
= topwindow
.w
.wid
.GetNextWindow()
1087 app
= W
.getapplication()
1088 if app
._windows
.has_key(wid
): # KeyError otherwise can happen in RoboFog :-(
1089 window
= W
.getapplication()._windows
[wid
]
1092 if not isinstance(window
, Editor
):
1094 return window
.editgroup
.editor
1097 class _EditorDefaultSettings
:
1100 self
.template
= "%s, %d point"
1101 self
.fontsettings
, self
.tabsettings
, self
.windowsize
= geteditorprefs()
1102 self
.w
= W
.Dialog((328, 120), "Editor default settings")
1103 self
.w
.setfontbutton
= W
.Button((8, 8, 80, 16), "Set fontŠ", self
.dofont
)
1104 self
.w
.fonttext
= W
.TextBox((98, 10, -8, 14), self
.template
% (self
.fontsettings
[0], self
.fontsettings
[2]))
1106 self
.w
.picksizebutton
= W
.Button((8, 50, 80, 16), "Front window", self
.picksize
)
1107 self
.w
.xsizelabel
= W
.TextBox((98, 32, 40, 14), "Width:")
1108 self
.w
.ysizelabel
= W
.TextBox((148, 32, 40, 14), "Height:")
1109 self
.w
.xsize
= W
.EditText((98, 48, 40, 20), `self
.windowsize
[0]`
)
1110 self
.w
.ysize
= W
.EditText((148, 48, 40, 20), `self
.windowsize
[1]`
)
1112 self
.w
.cancelbutton
= W
.Button((-180, -26, 80, 16), "Cancel", self
.cancel
)
1113 self
.w
.okbutton
= W
.Button((-90, -26, 80, 16), "Done", self
.ok
)
1114 self
.w
.setdefaultbutton(self
.w
.okbutton
)
1115 self
.w
.bind('cmd.', self
.w
.cancelbutton
.push
)
1119 app
= W
.getapplication()
1120 editor
= findeditor(self
)
1121 if editor
is not None:
1122 width
, height
= editor
._parentwindow
._bounds
[2:]
1123 self
.w
.xsize
.set(`width`
)
1124 self
.w
.ysize
.set(`height`
)
1126 raise W
.AlertError
, "No edit window found"
1130 settings
= FontSettings
.FontDialog(self
.fontsettings
, self
.tabsettings
)
1132 self
.fontsettings
, self
.tabsettings
= settings
1133 sys
.exc_traceback
= None
1134 self
.w
.fonttext
.set(self
.template
% (self
.fontsettings
[0], self
.fontsettings
[2]))
1145 width
= string
.atoi(self
.w
.xsize
.get())
1147 self
.w
.xsize
.select(1)
1148 self
.w
.xsize
.selectall()
1149 raise W
.AlertError
, "Bad number for window width"
1151 height
= string
.atoi(self
.w
.ysize
.get())
1153 self
.w
.ysize
.select(1)
1154 self
.w
.ysize
.selectall()
1155 raise W
.AlertError
, "Bad number for window height"
1156 self
.windowsize
= width
, height
1157 seteditorprefs(self
.fontsettings
, self
.tabsettings
, self
.windowsize
)
1160 def geteditorprefs():
1162 prefs
= MacPrefs
.GetPrefs(W
.getapplication().preffilepath
)
1164 fontsettings
= prefs
.pyedit
.fontsettings
1165 tabsettings
= prefs
.pyedit
.tabsettings
1166 windowsize
= prefs
.pyedit
.windowsize
1168 fontsettings
= prefs
.pyedit
.fontsettings
= ("Python-Sans", 0, 9, (0, 0, 0))
1169 tabsettings
= prefs
.pyedit
.tabsettings
= (8, 1)
1170 windowsize
= prefs
.pyedit
.windowsize
= (500, 250)
1171 sys
.exc_traceback
= None
1172 return fontsettings
, tabsettings
, windowsize
1174 def seteditorprefs(fontsettings
, tabsettings
, windowsize
):
1176 prefs
= MacPrefs
.GetPrefs(W
.getapplication().preffilepath
)
1177 prefs
.pyedit
.fontsettings
= fontsettings
1178 prefs
.pyedit
.tabsettings
= tabsettings
1179 prefs
.pyedit
.windowsize
= windowsize
1182 _defaultSettingsEditor
= None
1184 def EditorDefaultSettings():
1185 global _defaultSettingsEditor
1186 if _defaultSettingsEditor
is None or not hasattr(_defaultSettingsEditor
, "w"):
1187 _defaultSettingsEditor
= _EditorDefaultSettings()
1189 _defaultSettingsEditor
.w
.select()
1191 def resolvealiases(path
):
1193 return macfs
.ResolveAliasFile(path
)[0].as_pathname()
1194 except (macfs
.error
, ValueError), (error
, str):
1197 dir, file = os
.path
.split(path
)
1198 return os
.path
.join(resolvealiases(dir), file)
1200 searchengine
= SearchEngine()
1201 tracebackwindow
= Wtraceback
.TraceBack()