1 """A (less & less) simple Python editor"""
10 from Carbon
import Win
11 from Carbon
import Res
12 from Carbon
import Evt
20 if hasattr(Win
, "FrontNonFloatingWindow"):
21 MyFrontWindow
= Win
.FrontNonFloatingWindow
23 MyFrontWindow
= Win
.FrontWindow
31 haveThreading
= Wthreading
.haveThreading
33 _scriptuntitledcounter
= 1
34 _wordchars
= string
.ascii_letters
+ string
.digits
+ "_"
37 runButtonLabels
= ["Run all", "Stop!"]
38 runSelButtonLabels
= ["Run selection", "Pause!", "Resume"]
41 class Editor(W
.Window
):
43 def __init__(self
, path
= "", title
= ""):
44 defaultfontsettings
, defaulttabsettings
, defaultwindowsize
= geteditorprefs()
45 global _scriptuntitledcounter
50 self
.title
= "Untitled Script " + `_scriptuntitledcounter`
51 _scriptuntitledcounter
= _scriptuntitledcounter
+ 1
53 self
._creator
= W
._signature
54 elif os
.path
.exists(path
):
55 path
= resolvealiases(path
)
56 dir, name
= os
.path
.split(path
)
61 fss
= macfs
.FSSpec(path
)
62 self
._creator
, filetype
= fss
.GetCreatorType()
64 raise IOError, "file '%s' does not exist" % path
69 if string
.find(text
, '\r\n') >= 0:
75 change
= EasyDialogs
.AskYesNoCancel('"%s" contains %s-style line feeds. '
76 'Change them to MacOS carriage returns?' % (self
.title
, sourceOS
), 1)
77 # bug: Cancel is treated as No
79 text
= string
.replace(text
, searchString
, '\r')
85 self
.readwindowsettings()
86 if self
.settings
.has_key("windowbounds"):
87 bounds
= self
.settings
["windowbounds"]
89 bounds
= defaultwindowsize
90 if self
.settings
.has_key("fontsettings"):
91 self
.fontsettings
= self
.settings
["fontsettings"]
93 self
.fontsettings
= defaultfontsettings
94 if self
.settings
.has_key("tabsize"):
96 self
.tabsettings
= (tabsize
, tabmode
) = self
.settings
["tabsize"]
98 self
.tabsettings
= defaulttabsettings
100 self
.tabsettings
= defaulttabsettings
102 W
.Window
.__init
__(self
, bounds
, self
.title
, minsize
= (330, 120), tabbable
= 0)
103 self
.setupwidgets(text
)
105 self
.editgroup
.editor
.textchanged()
107 if self
.settings
.has_key("selection"):
108 selstart
, selend
= self
.settings
["selection"]
109 self
.setselection(selstart
, selend
)
113 self
._buf
= "" # for write method
116 if self
.settings
.has_key("run_as_main"):
117 self
.run_as_main
= self
.settings
["run_as_main"]
120 if self
.settings
.has_key("run_with_interpreter"):
121 self
.run_with_interpreter
= self
.settings
["run_with_interpreter"]
123 self
.run_with_interpreter
= 0
124 self
._threadstate
= (0, 0)
127 def readwindowsettings(self
):
129 resref
= Res
.FSpOpenResFile(self
.path
, 1)
133 Res
.UseResFile(resref
)
134 data
= Res
.Get1Resource('PyWS', 128)
135 self
.settings
= marshal
.loads(data
.data
)
138 Res
.CloseResFile(resref
)
140 def writewindowsettings(self
):
142 resref
= Res
.FSpOpenResFile(self
.path
, 3)
144 Res
.FSpCreateResFile(self
.path
, self
._creator
, 'TEXT', MACFS
.smAllScripts
)
145 resref
= Res
.FSpOpenResFile(self
.path
, 3)
147 data
= Res
.Resource(marshal
.dumps(self
.settings
))
148 Res
.UseResFile(resref
)
150 temp
= Res
.Get1Resource('PyWS', 128)
151 temp
.RemoveResource()
154 data
.AddResource('PyWS', 128, "window settings")
156 Res
.UpdateResFile(resref
)
157 Res
.CloseResFile(resref
)
159 def getsettings(self
):
161 self
.settings
["windowbounds"] = self
.getbounds()
162 self
.settings
["selection"] = self
.getselection()
163 self
.settings
["fontsettings"] = self
.editgroup
.editor
.getfontsettings()
164 self
.settings
["tabsize"] = self
.editgroup
.editor
.gettabsettings()
165 self
.settings
["run_as_main"] = self
.run_as_main
166 self
.settings
["run_with_interpreter"] = self
.run_with_interpreter
169 return self
.editgroup
.editor
.get()
171 def getselection(self
):
172 return self
.editgroup
.editor
.ted
.WEGetSelection()
174 def setselection(self
, selstart
, selend
):
175 self
.editgroup
.editor
.setselection(selstart
, selend
)
177 def getfilename(self
):
180 return '<%s>' % self
.title
182 def setupwidgets(self
, text
):
185 self
.lastlineno
= None
188 self
.editgroup
= W
.Group((0, topbarheight
+ 1, 0, 0))
189 editor
= W
.PyEditor((0, 0, -15,-15), text
,
190 fontsettings
= self
.fontsettings
,
191 tabsettings
= self
.tabsettings
,
192 file = self
.getfilename())
195 self
.popfield
= ClassFinder((popfieldwidth
- 17, -15, 16, 16), [], self
.popselectline
)
196 self
.linefield
= W
.EditText((-1, -15, popfieldwidth
- 15, 16), inset
= (6, 1))
197 self
.editgroup
._barx
= W
.Scrollbar((popfieldwidth
- 2, -15, -14, 16), editor
.hscroll
, max = 32767)
198 self
.editgroup
._bary
= W
.Scrollbar((-15, 14, 16, -14), editor
.vscroll
, max = 32767)
199 self
.editgroup
.editor
= editor
# add editor *after* scrollbars
201 self
.editgroup
.optionsmenu
= W
.PopupMenu((-15, -1, 16, 16), [])
202 self
.editgroup
.optionsmenu
.bind('<click>', self
.makeoptionsmenu
)
204 self
.bevelbox
= W
.BevelBox((0, 0, 0, topbarheight
))
205 self
.hline
= W
.HorizontalLine((0, topbarheight
, 0, 0))
206 self
.infotext
= W
.TextBox((175, 6, -4, 14), backgroundcolor
= (0xe000, 0xe000, 0xe000))
207 self
.runbutton
= W
.BevelButton((6, 4, 80, 16), runButtonLabels
[0], self
.run
)
208 self
.runselbutton
= W
.BevelButton((90, 4, 80, 16), runSelButtonLabels
[0], self
.runselection
)
211 editor
.bind("cmdr", self
.runbutton
.push
)
212 editor
.bind("enter", self
.runselbutton
.push
)
213 editor
.bind("cmdj", self
.domenu_gotoline
)
214 editor
.bind("cmdd", self
.domenu_toggledebugger
)
215 editor
.bind("<idle>", self
.updateselection
)
217 editor
.bind("cmde", searchengine
.setfindstring
)
218 editor
.bind("cmdf", searchengine
.show
)
219 editor
.bind("cmdg", searchengine
.findnext
)
220 editor
.bind("cmdshiftr", searchengine
.replace
)
221 editor
.bind("cmdt", searchengine
.replacefind
)
223 self
.linefield
.bind("return", self
.dolinefield
)
224 self
.linefield
.bind("enter", self
.dolinefield
)
225 self
.linefield
.bind("tab", self
.dolinefield
)
228 editor
.bind("<click>", self
.clickeditor
)
229 self
.linefield
.bind("<click>", self
.clicklinefield
)
231 def makeoptionsmenu(self
):
232 menuitems
= [('Font settings\xc9', self
.domenu_fontsettings
),
233 ("Save options\xc9", self
.domenu_options
),
235 ('\0' + chr(self
.run_as_main
) + 'Run as __main__', self
.domenu_toggle_run_as_main
),
236 #('\0' + chr(self.run_with_interpreter) + 'Run with Interpreter', self.domenu_toggle_run_with_interpreter),
238 ('Modularize', self
.domenu_modularize
),
239 ('Browse namespace\xc9', self
.domenu_browsenamespace
),
242 menuitems
= menuitems
+ [('Disable profiler', self
.domenu_toggleprofiler
)]
244 menuitems
= menuitems
+ [('Enable profiler', self
.domenu_toggleprofiler
)]
245 if self
.editgroup
.editor
._debugger
:
246 menuitems
= menuitems
+ [('Disable debugger', self
.domenu_toggledebugger
),
247 ('Clear breakpoints', self
.domenu_clearbreakpoints
),
248 ('Edit breakpoints\xc9', self
.domenu_editbreakpoints
)]
250 menuitems
= menuitems
+ [('Enable debugger', self
.domenu_toggledebugger
)]
251 self
.editgroup
.optionsmenu
.set(menuitems
)
253 def domenu_toggle_run_as_main(self
):
254 self
.run_as_main
= not self
.run_as_main
255 self
.run_with_interpreter
= 0
256 self
.editgroup
.editor
.selectionchanged()
258 def domenu_toggle_run_with_interpreter(self
):
259 self
.run_with_interpreter
= not self
.run_with_interpreter
261 self
.editgroup
.editor
.selectionchanged()
263 def showbreakpoints(self
, onoff
):
264 self
.editgroup
.editor
.showbreakpoints(onoff
)
265 self
.debugging
= onoff
267 def domenu_clearbreakpoints(self
, *args
):
268 self
.editgroup
.editor
.clearbreakpoints()
270 def domenu_editbreakpoints(self
, *args
):
271 self
.editgroup
.editor
.editbreakpoints()
273 def domenu_toggledebugger(self
, *args
):
274 if not self
.debugging
:
276 self
.debugging
= not self
.debugging
277 self
.editgroup
.editor
.togglebreakpoints()
279 def domenu_toggleprofiler(self
, *args
):
280 self
.profiling
= not self
.profiling
282 def domenu_browsenamespace(self
, *args
):
285 globals, file, modname
= self
.getenvironment()
288 PyBrowser
.Browser(globals, "Object browser: " + modname
)
290 def domenu_modularize(self
, *args
):
291 modname
= _filename_as_modname(self
.title
)
293 raise W
.AlertError
, "Can't modularize \"%s\"" % self
.title
294 run_as_main
= self
.run_as_main
297 self
.run_as_main
= run_as_main
303 if self
.globals and not sys
.modules
.has_key(modname
):
304 module
= imp
.new_module(modname
)
305 for attr
in self
.globals.keys():
306 setattr(module
,attr
,self
.globals[attr
])
307 sys
.modules
[modname
] = module
310 def domenu_fontsettings(self
, *args
):
312 fontsettings
= self
.editgroup
.editor
.getfontsettings()
313 tabsettings
= self
.editgroup
.editor
.gettabsettings()
314 settings
= FontSettings
.FontDialog(fontsettings
, tabsettings
)
316 fontsettings
, tabsettings
= settings
317 self
.editgroup
.editor
.setfontsettings(fontsettings
)
318 self
.editgroup
.editor
.settabsettings(tabsettings
)
320 def domenu_options(self
, *args
):
321 rv
= SaveOptions(self
._creator
)
323 self
.editgroup
.editor
.selectionchanged() # ouch...
326 def clicklinefield(self
):
327 if self
._currentwidget
<> self
.linefield
:
328 self
.linefield
.select(1)
329 self
.linefield
.selectall()
332 def clickeditor(self
):
333 if self
._currentwidget
<> self
.editgroup
.editor
:
337 def updateselection(self
, force
= 0):
338 sel
= min(self
.editgroup
.editor
.getselection())
339 lineno
= self
.editgroup
.editor
.offsettoline(sel
)
340 if lineno
<> self
.lastlineno
or force
:
341 self
.lastlineno
= lineno
342 self
.linefield
.set(str(lineno
+ 1))
343 self
.linefield
.selview()
345 def dolinefield(self
):
347 lineno
= string
.atoi(self
.linefield
.get()) - 1
348 if lineno
<> self
.lastlineno
:
349 self
.editgroup
.editor
.selectline(lineno
)
350 self
.updateselection(1)
352 self
.updateselection(1)
353 self
.editgroup
.editor
.select(1)
355 def setinfotext(self
):
356 if not hasattr(self
, 'infotext'):
359 self
.infotext
.set(self
.path
)
361 self
.infotext
.set("")
364 if self
.editgroup
.editor
.changed
:
366 from Carbon
import Qd
368 save
= EasyDialogs
.AskYesNoCancel('Save window "%s" before closing?' % self
.title
,
369 default
=1, no
="Don\xd5t save")
371 if self
.domenu_save():
378 def domenu_close(self
, *args
):
381 def domenu_save(self
, *args
):
383 # Will call us recursively
384 return self
.domenu_save_as()
385 data
= self
.editgroup
.editor
.get()
386 fp
= open(self
.path
, 'wb') # open file in binary mode, data has '\r' line-endings
389 fss
= macfs
.FSSpec(self
.path
)
390 fss
.SetCreatorType(self
._creator
, 'TEXT')
392 self
.writewindowsettings()
393 self
.editgroup
.editor
.changed
= 0
394 self
.editgroup
.editor
.selchanged
= 0
396 if linecache
.cache
.has_key(self
.path
):
397 del linecache
.cache
[self
.path
]
399 macostools
.touched(self
.path
)
401 def can_save(self
, menuitem
):
402 return self
.editgroup
.editor
.changed
or self
.editgroup
.editor
.selchanged
404 def domenu_save_as(self
, *args
):
405 fss
, ok
= macfs
.StandardPutFile('Save as:', self
.title
)
408 self
.showbreakpoints(0)
409 self
.path
= fss
.as_pathname()
411 self
.title
= os
.path
.split(self
.path
)[-1]
412 self
.wid
.SetWTitle(self
.title
)
414 self
.editgroup
.editor
.setfile(self
.getfilename())
415 app
= W
.getapplication()
416 app
.makeopenwindowsmenu()
417 if hasattr(app
, 'makescriptsmenu'):
418 app
= W
.getapplication()
419 fss
, fss_changed
= app
.scriptsfolder
.Resolve()
420 path
= fss
.as_pathname()
421 if path
== self
.path
[:len(path
)]:
422 W
.getapplication().makescriptsmenu()
424 def domenu_save_as_applet(self
, *args
):
427 buildtools
.DEBUG
= 0 # ouch.
429 if self
.title
[-3:] == ".py":
430 destname
= self
.title
[:-3]
432 destname
= self
.title
+ ".applet"
433 fss
, ok
= macfs
.StandardPutFile('Save as Applet:', destname
)
437 destname
= fss
.as_pathname()
440 if filename
[-3:] == ".py":
441 rsrcname
= filename
[:-3] + '.rsrc'
443 rsrcname
= filename
+ '.rsrc'
445 filename
= self
.title
448 pytext
= self
.editgroup
.editor
.get()
449 pytext
= string
.split(pytext
, '\r')
450 pytext
= string
.join(pytext
, '\n') + '\n'
452 code
= compile(pytext
, filename
, "exec")
453 except (SyntaxError, EOFError):
454 raise buildtools
.BuildError
, "Syntax error in script %s" % `filename`
456 # Try removing the output file
461 template
= buildtools
.findtemplate()
462 buildtools
.process_common(template
, None, code
, rsrcname
, destname
, 0, 1)
464 def domenu_gotoline(self
, *args
):
465 self
.linefield
.selectall()
466 self
.linefield
.select(1)
467 self
.linefield
.selectall()
469 def domenu_selectline(self
, *args
):
470 self
.editgroup
.editor
.expandselection()
472 def domenu_find(self
, *args
):
475 def domenu_entersearchstring(self
, *args
):
476 searchengine
.setfindstring()
478 def domenu_replace(self
, *args
):
479 searchengine
.replace()
481 def domenu_findnext(self
, *args
):
482 searchengine
.findnext()
484 def domenu_replacefind(self
, *args
):
485 searchengine
.replacefind()
487 def domenu_run(self
, *args
):
488 self
.runbutton
.push()
490 def domenu_runselection(self
, *args
):
491 self
.runselbutton
.push()
494 if self
._threadstate
== (0, 0):
497 lock
= Wthreading
.Lock()
499 self
._thread
.postException(KeyboardInterrupt)
500 if self
._thread
.isBlocked():
505 if self
.run_with_interpreter
:
506 if self
.editgroup
.editor
.changed
:
508 import Qd
; Qd
.InitCursor()
509 save
= EasyDialogs
.AskYesNoCancel('Save "%s" before running?' % self
.title
, 1)
511 if self
.domenu_save():
516 raise W
.AlertError
, "Can't run unsaved file"
517 self
._run
_with
_interpreter
()
519 pytext
= self
.editgroup
.editor
.get()
520 globals, file, modname
= self
.getenvironment()
521 self
.execstring(pytext
, globals, globals, file, modname
)
523 def _run_with_interpreter(self
):
524 interp_path
= os
.path
.join(sys
.exec_prefix
, "PythonInterpreter")
525 if not os
.path
.exists(interp_path
):
526 raise W
.AlertError
, "Can't find interpreter"
530 def runselection(self
):
531 if self
._threadstate
== (0, 0):
533 elif self
._threadstate
== (1, 1):
535 self
.setthreadstate((1, 2))
536 elif self
._threadstate
== (1, 2):
538 self
.setthreadstate((1, 1))
540 def _runselection(self
):
541 if self
.run_with_interpreter
:
542 raise W
.AlertError
, "Can't run selection with Interpreter"
543 globals, file, modname
= self
.getenvironment()
546 self
.editgroup
.editor
.expandselection()
548 # get lineno of first selected line
549 selstart
, selend
= self
.editgroup
.editor
.getselection()
550 selstart
, selend
= min(selstart
, selend
), max(selstart
, selend
)
551 selfirstline
= self
.editgroup
.editor
.offsettoline(selstart
)
552 alltext
= self
.editgroup
.editor
.get()
553 pytext
= alltext
[selstart
:selend
]
554 lines
= string
.split(pytext
, '\r')
555 indent
= getminindent(lines
)
558 alllines
= string
.split(alltext
, '\r')
559 for i
in range(selfirstline
- 1, -1, -1):
561 if line
[:6] == 'class ':
562 classname
= string
.split(string
.strip(line
[6:]))[0]
563 classend
= identifieRE_match(classname
)
565 raise W
.AlertError
, "Can't find a class."
566 classname
= classname
[:classend
]
568 elif line
and line
[0] not in '\t#':
569 raise W
.AlertError
, "Can't find a class."
571 raise W
.AlertError
, "Can't find a class."
572 if globals.has_key(classname
):
573 klass
= globals[classname
]
575 raise W
.AlertError
, "Can't find class \"%s\"." % classname
577 pytext
= ("class %s:\n" % classname
) + pytext
578 selfirstline
= selfirstline
- 1
580 raise W
.AlertError
, "Can't run indented code."
582 # add "newlines" to fool compile/exec:
583 # now a traceback will give the right line number
584 pytext
= selfirstline
* '\r' + pytext
585 self
.execstring(pytext
, globals, locals, file, modname
)
586 if indent
== 1 and globals[classname
] is not klass
:
587 # update the class in place
588 klass
.__dict
__.update(globals[classname
].__dict
__)
589 globals[classname
] = klass
591 def setthreadstate(self
, state
):
592 oldstate
= self
._threadstate
593 if oldstate
[0] <> state
[0]:
594 self
.runbutton
.settitle(runButtonLabels
[state
[0]])
595 if oldstate
[1] <> state
[1]:
596 self
.runselbutton
.settitle(runSelButtonLabels
[state
[1]])
597 self
._threadstate
= state
599 def _exec_threadwrapper(self
, *args
, **kwargs
):
600 apply(execstring
, args
, kwargs
)
601 self
.setthreadstate((0, 0))
604 def execstring(self
, pytext
, globals, locals, file, modname
):
605 tracebackwindow
.hide()
607 W
.getapplication().refreshwindows()
611 dir = os
.path
.dirname(self
.path
)
612 savedir
= os
.getcwd()
614 sys
.path
.insert(0, dir)
619 self
._thread
= Wthreading
.Thread(os
.path
.basename(file),
620 self
._exec
_threadwrapper
, pytext
, globals, locals, file, self
.debugging
,
621 modname
, self
.profiling
)
622 self
.setthreadstate((1, 1))
625 execstring(pytext
, globals, locals, file, self
.debugging
,
626 modname
, self
.profiling
)
632 def getenvironment(self
):
635 dir = os
.path
.dirname(file)
636 # check if we're part of a package
638 while os
.path
.exists(os
.path
.join(dir, "__init__.py")):
639 dir, dirname
= os
.path
.split(dir)
640 modname
= dirname
+ '.' + modname
641 subname
= _filename_as_modname(self
.title
)
643 return self
.globals, file, None
645 if subname
== "__init__":
646 # strip trailing period
647 modname
= modname
[:-1]
649 modname
= modname
+ subname
652 if sys
.modules
.has_key(modname
):
653 globals = sys
.modules
[modname
].__dict
__
656 globals = self
.globals
659 file = '<%s>' % self
.title
660 globals = self
.globals
662 return globals, file, modname
664 def write(self
, stuff
):
665 """for use as stdout"""
666 self
._buf
= self
._buf
+ stuff
667 if '\n' in self
._buf
:
671 stuff
= string
.split(self
._buf
, '\n')
672 stuff
= string
.join(stuff
, '\r')
673 end
= self
.editgroup
.editor
.ted
.WEGetTextLength()
674 self
.editgroup
.editor
.ted
.WESetSelection(end
, end
)
675 self
.editgroup
.editor
.ted
.WEInsert(stuff
, None, None)
676 self
.editgroup
.editor
.updatescrollbars()
679 #self.wid.SelectWindow()
681 def getclasslist(self
):
682 from string
import find
, strip
683 methodRE
= re
.compile(r
"\r[ \t]+def ")
684 findMethod
= methodRE
.search
685 editor
= self
.editgroup
.editor
693 if text
[:4] == 'def ':
694 append((pos
+ 4, functag
))
697 pos
= find(text
, '\rdef ', pos
+ 1)
700 append((pos
+ 5, functag
))
702 if text
[:6] == 'class ':
703 append((pos
+ 6, classtag
))
706 pos
= find(text
, '\rclass ', pos
+ 1)
709 append((pos
+ 7, classtag
))
712 m
= findMethod(text
, pos
+ 1)
716 #pos = find(text, '\r\tdef ', pos + 1)
717 append((m
.regs
[0][1], methodtag
))
720 methodlistappend
= None
721 offsetToLine
= editor
.ted
.WEOffsetToLine
722 getLineRange
= editor
.ted
.WEGetLineRange
723 append
= classlist
.append
724 for pos
, tag
in list:
725 lineno
= offsetToLine(pos
)
726 lineStart
, lineEnd
= getLineRange(lineno
)
727 line
= strip(text
[pos
:lineEnd
])
728 line
= line
[:identifieRE_match(line
)]
730 append(("def " + line
, lineno
+ 1))
731 methodlistappend
= None
732 elif tag
is classtag
:
733 append(["class " + line
])
734 methodlistappend
= classlist
[-1].append
735 elif methodlistappend
and tag
is methodtag
:
736 methodlistappend(("def " + line
, lineno
+ 1))
739 def popselectline(self
, lineno
):
740 self
.editgroup
.editor
.selectline(lineno
- 1)
742 def selectline(self
, lineno
, charoffset
= 0):
743 self
.editgroup
.editor
.selectline(lineno
- 1, charoffset
)
747 def __init__(self
, creator
):
749 self
.w
= w
= W
.ModalDialog((240, 140), 'Save options')
751 w
.label
= W
.TextBox((8, 8, 80, 18), "File creator:")
752 w
.ide_radio
= W
.RadioButton((8, 22, 160, 18), "This application", radiobuttons
, self
.ide_hit
)
753 w
.interp_radio
= W
.RadioButton((8, 42, 160, 18), "Python Interpreter", radiobuttons
, self
.interp_hit
)
754 w
.other_radio
= W
.RadioButton((8, 62, 50, 18), "Other:", radiobuttons
)
755 w
.other_creator
= W
.EditText((62, 62, 40, 20), creator
, self
.otherselect
)
756 w
.cancelbutton
= W
.Button((-180, -30, 80, 16), "Cancel", self
.cancelbuttonhit
)
757 w
.okbutton
= W
.Button((-90, -30, 80, 16), "Done", self
.okbuttonhit
)
758 w
.setdefaultbutton(w
.okbutton
)
759 if creator
== 'Pyth':
760 w
.interp_radio
.set(1)
761 elif creator
== W
._signature
:
765 w
.bind("cmd.", w
.cancelbutton
.push
)
769 self
.w
.other_creator
.set(W
._signature
)
771 def interp_hit(self
):
772 self
.w
.other_creator
.set("Pyth")
774 def otherselect(self
, *args
):
775 sel_from
, sel_to
= self
.w
.other_creator
.getselection()
776 creator
= self
.w
.other_creator
.get()[:4]
777 creator
= creator
+ " " * (4 - len(creator
))
778 self
.w
.other_creator
.set(creator
)
779 self
.w
.other_creator
.setselection(sel_from
, sel_to
)
780 self
.w
.other_radio
.set(1)
782 def cancelbuttonhit(self
):
785 def okbuttonhit(self
):
786 self
.rv
= self
.w
.other_creator
.get()[:4]
790 def SaveOptions(creator
):
791 s
= _saveoptions(creator
)
795 def _escape(where
, what
) :
796 return string
.join(string
.split(where
, what
), '\\' + what
)
798 def _makewholewordpattern(word
):
799 # first, escape special regex chars
800 for esc
in "\\[]()|.*^+$?":
801 word
= _escape(word
, esc
)
802 notwordcharspat
= '[^' + _wordchars
+ ']'
803 pattern
= '(' + word
+ ')'
804 if word
[0] in _wordchars
:
805 pattern
= notwordcharspat
+ pattern
806 if word
[-1] in _wordchars
:
807 pattern
= pattern
+ notwordcharspat
808 return re
.compile(pattern
)
816 self
.parms
= { "find": "",
823 prefs
= MacPrefs
.GetPrefs(W
.getapplication().preffilepath
)
824 if prefs
.searchengine
:
825 self
.parms
["casesens"] = prefs
.searchengine
.casesens
826 self
.parms
["wrap"] = prefs
.searchengine
.wrap
827 self
.parms
["wholeword"] = prefs
.searchengine
.wholeword
832 self
.w
.wid
.ShowWindow()
833 self
.w
.wid
.SelectWindow()
834 self
.w
.find
.edit
.select(1)
835 self
.w
.find
.edit
.selectall()
837 self
.w
= W
.Dialog((420, 150), "Find")
839 self
.w
.find
= TitledEditText((10, 4, 300, 36), "Search for:")
840 self
.w
.replace
= TitledEditText((10, 100, 300, 36), "Replace with:")
842 self
.w
.boxes
= W
.Group((10, 50, 300, 40))
843 self
.w
.boxes
.casesens
= W
.CheckBox((0, 0, 100, 16), "Case sensitive")
844 self
.w
.boxes
.wholeword
= W
.CheckBox((0, 20, 100, 16), "Whole word")
845 self
.w
.boxes
.wrap
= W
.CheckBox((110, 0, 100, 16), "Wrap around")
847 self
.buttons
= [ ("Find", "cmdf", self
.find
),
848 ("Replace", "cmdr", self
.replace
),
849 ("Replace all", None, self
.replaceall
),
850 ("Don't find", "cmdd", self
.dont
),
851 ("Cancel", "cmd.", self
.cancel
)
853 for i
in range(len(self
.buttons
)):
854 bounds
= -90, 22 + i
* 24, 80, 16
855 title
, shortcut
, callback
= self
.buttons
[i
]
856 self
.w
[title
] = W
.Button(bounds
, title
, callback
)
858 self
.w
.bind(shortcut
, self
.w
[title
].push
)
859 self
.w
.setdefaultbutton(self
.w
["Don't find"])
860 self
.w
.find
.edit
.bind("<key>", self
.key
)
861 self
.w
.bind("<activate>", self
.activate
)
862 self
.w
.bind("<close>", self
.close
)
865 self
.w
.find
.edit
.select(1)
866 self
.w
.find
.edit
.selectall()
873 def key(self
, char
, modifiers
):
874 self
.w
.find
.edit
.key(char
, modifiers
)
878 def activate(self
, onoff
):
882 def checkbuttons(self
):
883 editor
= findeditor(self
)
885 if self
.w
.find
.get():
886 for title
, cmd
, call
in self
.buttons
[:-2]:
887 self
.w
[title
].enable(1)
888 self
.w
.setdefaultbutton(self
.w
["Find"])
890 for title
, cmd
, call
in self
.buttons
[:-2]:
891 self
.w
[title
].enable(0)
892 self
.w
.setdefaultbutton(self
.w
["Don't find"])
894 for title
, cmd
, call
in self
.buttons
[:-2]:
895 self
.w
[title
].enable(0)
896 self
.w
.setdefaultbutton(self
.w
["Don't find"])
899 self
.getparmsfromwindow()
904 editor
= findeditor(self
)
908 self
.getparmsfromwindow()
909 text
= editor
.getselectedtext()
910 find
= self
.parms
["find"]
911 if not self
.parms
["casesens"]:
912 find
= string
.lower(find
)
913 text
= string
.lower(text
)
916 editor
.insert(self
.parms
["replace"])
918 def replaceall(self
):
919 editor
= findeditor(self
)
923 self
.getparmsfromwindow()
925 find
= self
.parms
["find"]
929 replace
= self
.parms
["replace"]
930 replacelen
= len(replace
)
932 if not self
.parms
["casesens"]:
933 find
= string
.lower(find
)
934 text
= string
.lower(Text
)
941 if self
.parms
["wholeword"]:
942 wholewordRE
= _makewholewordpattern(find
)
943 match
= wholewordRE
.search(text
, pos
)
949 pos
= string
.find(text
, find
, pos
)
952 counter
= counter
+ 1
953 text
= text
[:pos
] + replace
+ text
[pos
+ findlen
:]
954 Text
= Text
[:pos
] + replace
+ Text
[pos
+ findlen
:]
955 pos
= pos
+ replacelen
960 from Carbon
import Res
962 editor
.selectionchanged()
963 editor
.ted
.WEUseText(Res
.Resource(Text
))
964 editor
.ted
.WECalText()
966 editor
.GetWindow().InvalWindowRect(editor
._bounds
)
967 #editor.ted.WEUpdate(self.w.wid.GetWindowPort().visRgn)
968 EasyDialogs
.Message("Replaced %d occurrences" % counter
)
971 self
.getparmsfromwindow()
974 def replacefind(self
):
978 def setfindstring(self
):
979 editor
= findeditor(self
)
982 find
= editor
.getselectedtext()
985 self
.parms
["find"] = find
987 self
.w
.find
.edit
.set(self
.parms
["find"])
988 self
.w
.find
.edit
.selectall()
991 editor
= findeditor(self
)
994 find
= self
.parms
["find"]
998 if not self
.parms
["casesens"]:
999 find
= string
.lower(find
)
1000 text
= string
.lower(text
)
1001 selstart
, selend
= editor
.getselection()
1002 selstart
, selend
= min(selstart
, selend
), max(selstart
, selend
)
1003 if self
.parms
["wholeword"]:
1004 wholewordRE
= _makewholewordpattern(find
)
1005 match
= wholewordRE
.search(text
, selend
)
1007 pos
= match
.start(1)
1011 pos
= string
.find(text
, find
, selend
)
1013 editor
.setselection(pos
, pos
+ len(find
))
1015 elif self
.parms
["wrap"]:
1016 if self
.parms
["wholeword"]:
1017 match
= wholewordRE
.search(text
, 0)
1019 pos
= match
.start(1)
1023 pos
= string
.find(text
, find
)
1024 if selstart
> pos
>= 0:
1025 editor
.setselection(pos
, pos
+ len(find
))
1029 for key
, value
in self
.parms
.items():
1031 self
.w
[key
].set(value
)
1033 self
.w
.boxes
[key
].set(value
)
1035 def getparmsfromwindow(self
):
1038 for key
, value
in self
.parms
.items():
1040 value
= self
.w
[key
].get()
1042 value
= self
.w
.boxes
[key
].get()
1043 self
.parms
[key
] = value
1051 self
.w
.wid
.HideWindow()
1054 def writeprefs(self
):
1056 self
.getparmsfromwindow()
1057 prefs
= MacPrefs
.GetPrefs(W
.getapplication().preffilepath
)
1058 prefs
.searchengine
.casesens
= self
.parms
["casesens"]
1059 prefs
.searchengine
.wrap
= self
.parms
["wrap"]
1060 prefs
.searchengine
.wholeword
= self
.parms
["wholeword"]
1064 class TitledEditText(W
.Group
):
1066 def __init__(self
, possize
, title
, text
= ""):
1067 W
.Group
.__init
__(self
, possize
)
1068 self
.title
= W
.TextBox((0, 0, 0, 16), title
)
1069 self
.edit
= W
.EditText((0, 16, 0, 0), text
)
1071 def set(self
, value
):
1072 self
.edit
.set(value
)
1075 return self
.edit
.get()
1078 class ClassFinder(W
.PopupWidget
):
1080 def click(self
, point
, modifiers
):
1081 W
.SetCursor("watch")
1082 self
.set(self
._parentwindow
.getclasslist())
1083 W
.PopupWidget
.click(self
, point
, modifiers
)
1086 def getminindent(lines
):
1089 stripped
= string
.strip(line
)
1090 if not stripped
or stripped
[0] == '#':
1092 if indent
< 0 or line
[:indent
] <> indent
* '\t':
1102 return not not ord(Evt
.GetKeys()[7]) & 0x04
1105 def execstring(pytext
, globals, locals, filename
="<string>", debugging
=0,
1106 modname
="__main__", profiling
=0):
1108 import PyDebugger
, bdb
1109 BdbQuit
= bdb
.BdbQuit
1111 BdbQuit
= 'BdbQuitDummyException'
1112 pytext
= string
.split(pytext
, '\r')
1113 pytext
= string
.join(pytext
, '\n') + '\n'
1114 W
.SetCursor("watch")
1115 globals['__name__'] = modname
1116 globals['__file__'] = filename
1117 sys
.argv
= [filename
]
1119 code
= compile(pytext
, filename
, "exec")
1121 # XXXX BAAAADDD.... We let tracebackwindow decide to treat SyntaxError
1122 # special. That's wrong because THIS case is special (could be literal
1123 # overflow!) and SyntaxError could mean we need a traceback (syntax error
1124 # in imported module!!!
1125 tracebackwindow
.traceback(1, filename
)
1130 lock
= Wthreading
.Lock()
1132 PyDebugger
.startfromhere()
1135 PyDebugger
.startfromhere()
1136 elif not haveThreading
:
1137 if hasattr(MacOS
, 'EnableAppswitch'):
1138 MacOS
.EnableAppswitch(0)
1141 import profile
, ProfileBrowser
1142 p
= profile
.Profile()
1145 p
.runctx(code
, globals, locals)
1149 stats
= pstats
.Stats(p
)
1150 ProfileBrowser
.ProfileBrowser(stats
)
1152 exec code
in globals, locals
1154 if not haveThreading
:
1155 if hasattr(MacOS
, 'EnableAppswitch'):
1156 MacOS
.EnableAppswitch(-1)
1157 except W
.AlertError
, detail
:
1158 raise W
.AlertError
, detail
1159 except (KeyboardInterrupt, BdbQuit
):
1161 except SystemExit, arg
:
1163 sys
.stderr
.write("Script exited with status code: %s\n" % repr(arg
.code
))
1167 lock
= Wthreading
.Lock()
1171 PyDebugger
.postmortem(sys
.exc_type
, sys
.exc_value
, sys
.exc_traceback
)
1174 tracebackwindow
.traceback(1, filename
)
1182 _identifieRE
= re
.compile(r
"[A-Za-z_][A-Za-z_0-9]*")
1184 def identifieRE_match(str):
1185 match
= _identifieRE
.match(str)
1190 def _filename_as_modname(fname
):
1191 if fname
[-3:] == '.py':
1192 modname
= fname
[:-3]
1193 match
= _identifieRE
.match(modname
)
1194 if match
and match
.start() == 0 and match
.end() == len(modname
):
1195 return string
.join(string
.split(modname
, '.'), '_')
1197 def findeditor(topwindow
, fromtop
= 0):
1198 wid
= MyFrontWindow()
1200 if topwindow
.w
and wid
== topwindow
.w
.wid
:
1201 wid
= topwindow
.w
.wid
.GetNextWindow()
1204 app
= W
.getapplication()
1205 if app
._windows
.has_key(wid
): # KeyError otherwise can happen in RoboFog :-(
1206 window
= W
.getapplication()._windows
[wid
]
1209 if not isinstance(window
, Editor
):
1211 return window
.editgroup
.editor
1214 class _EditorDefaultSettings
:
1217 self
.template
= "%s, %d point"
1218 self
.fontsettings
, self
.tabsettings
, self
.windowsize
= geteditorprefs()
1219 self
.w
= W
.Dialog((328, 120), "Editor default settings")
1220 self
.w
.setfontbutton
= W
.Button((8, 8, 80, 16), "Set font\xc9", self
.dofont
)
1221 self
.w
.fonttext
= W
.TextBox((98, 10, -8, 14), self
.template
% (self
.fontsettings
[0], self
.fontsettings
[2]))
1223 self
.w
.picksizebutton
= W
.Button((8, 50, 80, 16), "Front window", self
.picksize
)
1224 self
.w
.xsizelabel
= W
.TextBox((98, 32, 40, 14), "Width:")
1225 self
.w
.ysizelabel
= W
.TextBox((148, 32, 40, 14), "Height:")
1226 self
.w
.xsize
= W
.EditText((98, 48, 40, 20), `self
.windowsize
[0]`
)
1227 self
.w
.ysize
= W
.EditText((148, 48, 40, 20), `self
.windowsize
[1]`
)
1229 self
.w
.cancelbutton
= W
.Button((-180, -26, 80, 16), "Cancel", self
.cancel
)
1230 self
.w
.okbutton
= W
.Button((-90, -26, 80, 16), "Done", self
.ok
)
1231 self
.w
.setdefaultbutton(self
.w
.okbutton
)
1232 self
.w
.bind('cmd.', self
.w
.cancelbutton
.push
)
1236 app
= W
.getapplication()
1237 editor
= findeditor(self
)
1238 if editor
is not None:
1239 width
, height
= editor
._parentwindow
._bounds
[2:]
1240 self
.w
.xsize
.set(`width`
)
1241 self
.w
.ysize
.set(`height`
)
1243 raise W
.AlertError
, "No edit window found"
1247 settings
= FontSettings
.FontDialog(self
.fontsettings
, self
.tabsettings
)
1249 self
.fontsettings
, self
.tabsettings
= settings
1250 sys
.exc_traceback
= None
1251 self
.w
.fonttext
.set(self
.template
% (self
.fontsettings
[0], self
.fontsettings
[2]))
1262 width
= string
.atoi(self
.w
.xsize
.get())
1264 self
.w
.xsize
.select(1)
1265 self
.w
.xsize
.selectall()
1266 raise W
.AlertError
, "Bad number for window width"
1268 height
= string
.atoi(self
.w
.ysize
.get())
1270 self
.w
.ysize
.select(1)
1271 self
.w
.ysize
.selectall()
1272 raise W
.AlertError
, "Bad number for window height"
1273 self
.windowsize
= width
, height
1274 seteditorprefs(self
.fontsettings
, self
.tabsettings
, self
.windowsize
)
1277 def geteditorprefs():
1279 prefs
= MacPrefs
.GetPrefs(W
.getapplication().preffilepath
)
1281 fontsettings
= prefs
.pyedit
.fontsettings
1282 tabsettings
= prefs
.pyedit
.tabsettings
1283 windowsize
= prefs
.pyedit
.windowsize
1285 fontsettings
= prefs
.pyedit
.fontsettings
= ("Geneva", 0, 10, (0, 0, 0))
1286 tabsettings
= prefs
.pyedit
.tabsettings
= (8, 1)
1287 windowsize
= prefs
.pyedit
.windowsize
= (500, 250)
1288 sys
.exc_traceback
= None
1289 return fontsettings
, tabsettings
, windowsize
1291 def seteditorprefs(fontsettings
, tabsettings
, windowsize
):
1293 prefs
= MacPrefs
.GetPrefs(W
.getapplication().preffilepath
)
1294 prefs
.pyedit
.fontsettings
= fontsettings
1295 prefs
.pyedit
.tabsettings
= tabsettings
1296 prefs
.pyedit
.windowsize
= windowsize
1299 _defaultSettingsEditor
= None
1301 def EditorDefaultSettings():
1302 global _defaultSettingsEditor
1303 if _defaultSettingsEditor
is None or not hasattr(_defaultSettingsEditor
, "w"):
1304 _defaultSettingsEditor
= _EditorDefaultSettings()
1306 _defaultSettingsEditor
.w
.select()
1308 def resolvealiases(path
):
1310 return macfs
.ResolveAliasFile(path
)[0].as_pathname()
1311 except (macfs
.error
, ValueError), (error
, str):
1314 dir, file = os
.path
.split(path
)
1315 return os
.path
.join(resolvealiases(dir), file)
1317 searchengine
= SearchEngine()
1318 tracebackwindow
= Wtraceback
.TraceBack()