ANN: peppy-0.7.1 with automatic function menu based on fold explorer

0 views
Skip to first unread message

Rob McMullen

unread,
Nov 13, 2007, 9:51:04 PM11/13/07
to pyx...@googlegroups.com
It would be nice if we could update the tree view of Stani's fold
explorer to automatically update as changes are made to the stc. I
spent a little time on this (see attached), but all the
FoldExplorerMixin does in provide a way to recompute the fold
hierarchy from a non-zero starting point.

What's needed is some way to insert and delete tree nodes while
keeping the previous expansion state of the tree. Not a trivial
problem.

In peppy-0.7.1, I instead use the fold explorer to generate a menubar
hierarchy (ala emacs' function-menu) on demand. So, this way, I don't
have to keep track of the state of the fold explorer in the TreeCtrl,
which is the much harder problem.

Other features since 0.7.0:

* Added function menu using the fold explorer backend
* Paths in python trackbacks are now clickable
* Added Buffer List mode ala emacs
* Alternate method to code plugins to allow on-demand loading (e.g.
prevents loading numpy until hyperspectral image mode is first used)
* fixed reindent code for more corner cases
* added some default mac keybindings
* added reindent code from IDLE
* added ChangeLog mode
* added mouse wheel settings (scroll by lines/page)
* Added fill-paragraph
* Icons now bundled in iconmap.py for distribution
* Added font configuration in preferences
* spaces now allowed in pathnames when running scripts

http://www.flipturn.org/peppy

Fill paragraph and the reindent code borrowed from IDLE work really
well in python mode. BTW, I still intend to write up a description of
how I integrated the IDLE reindent code with the StyledTextCtrl...

Rob

foldExplorer.py

Don Dwiggins

unread,
Nov 14, 2007, 2:00:45 PM11/14/07
to pyx...@googlegroups.com
OK, I updated my SVN working copy and tried peppy. (peppy told me to
update my version of setuptools, which wasn't a problem.) FIrst, I
tried to edit make-doc.py (just to see how it would go editing a Python
file).

When I positioned the cursor at the end of any line of the file and hit
Return, I got the following:
Traceback (most recent call last):
File "c:\Dwig\Sandbox\peppy\peppy\frame.py", line 359, in OnKeyPressed
self.keys.process(evt)
File "c:\Dwig\Sandbox\peppy\peppy\lib\wxemacskeybindings.py", line
598, in process
function(evt)
File "c:\Dwig\Sandbox\peppy\peppy\menu.py", line 192, in __call__
self.action(0, number)
File "c:\Dwig\Sandbox\peppy\peppy\mainmenu.py", line 508, in action
self.mode.stc.electricReturn()
File "c:\Dwig\Sandbox\peppy\peppy\fundamental.py", line 104, in
electricReturn
ind = self.findIndent(linenum + 1)
File "c:\Dwig\Sandbox\peppy\peppy\plugins\python_mode.py", line 323,
in findIndent
bod = y.find_good_parse_start(build_char_in_string_func(self, start))
File "c:\ProgramFiles\Python24\lib\idlelib\PyParse.py", line 159, in
find_good_parse_start
ps1 = '\n' + sys.ps1
AttributeError: 'module' object has no attribute 'ps1'

I opened a new file, set the mode to Python, and started entering
stuff. When I entered "def foo(bar):", I got the same traceback as soon
as I typed the colon.

At this point, I exited peppy, and got:
Traceback (most recent call last):
File
"C:\ProgramFiles\Python24\lib\site-packages\wx-2.8-msw-ansi\wx\_core.py",
line 14087, in <lambda>
lambda event: event.callable(*event.args, **event.kw) )
File "c:\Dwig\Sandbox\peppy\peppy\frame.py", line 674, in switchMode
mode=self.getActiveMajorMode()
File "c:\Dwig\Sandbox\peppy\peppy\frame.py", line 480, in
getActiveMajorMode
major=self.tabs.getCurrent()
File "c:\Dwig\Sandbox\peppy\peppy\frame.py", line 169, in getCurrent
return self.GetPage(index)
File
"c:\ProgramFiles\Python24\lib\site-packages\wx-2.8-msw-ansi\wx\aui.py",
line 1404, in GetPage
return _aui.AuiNotebook_GetPage(*args, **kwargs)
wx._core.PyAssertionError: C++ assertion "page_idx <
m_tabs.GetPageCount()" failed at ..\..\src\aui\auibook.cpp(2872) in
wxAuiNotebook::GetPage()
Traceback (most recent call last):
File
"C:\ProgramFiles\Python24\lib\site-packages\wx-2.8-msw-ansi\wx\_core.py",
line 14087, in <lambda>
lambda event: event.callable(*event.args, **event.kw) )
File "c:\Dwig\Sandbox\peppy\peppy\frame.py", line 674, in switchMode
mode=self.getActiveMajorMode()
File "c:\Dwig\Sandbox\peppy\peppy\frame.py", line 480, in
getActiveMajorMode
major=self.tabs.getCurrent()
File "c:\Dwig\Sandbox\peppy\peppy\frame.py", line 169, in getCurrent
return self.GetPage(index)
File
"c:\ProgramFiles\Python24\lib\site-packages\wx-2.8-msw-ansi\wx\aui.py",
line 1404, in GetPage
return _aui.AuiNotebook_GetPage(*args, **kwargs)
wx._core.PyAssertionError: C++ assertion "page_idx <
m_tabs.GetPageCount()" failed at ..\..\src\aui\auibook.cpp(2872) in
wxAuiNotebook::GetPage()
Traceback (most recent call last):
File "c:\Dwig\Sandbox\peppy\peppy\frame.py", line 356, in OnClose
wx.GetApp().quit()
File "c:\Dwig\Sandbox\peppy\peppy\main.py", line 698, in quit
doit=self.quitHook()
File "c:\Dwig\Sandbox\peppy\peppy\main.py", line 712, in quitHook
if not BufferList.promptUnsaved():
File "c:\Dwig\Sandbox\peppy\peppy\buffers.py", line 59, in promptUnsaved
dlg.Destroy()
File
"C:\ProgramFiles\Python24\lib\site-packages\wx-2.8-msw-ansi\wx\_core.py",
line 14033, in __getattr__
raise PyDeadObjectError(self.attrStr % self._name)
wx._core.PyDeadObjectError: The C++ part of the QuitDialog object has
been deleted, attribute access no longer allowed.

BTW, I'm running wx 2.8.3.0 on py 2.4.3.

I'm willing to dig deeper if this information isn't enough to give you
an "aha!".

--

Don Dwiggins
Advanced Publishing Technology

Rob McMullen

unread,
Nov 14, 2007, 2:31:11 PM11/14/07
to pyx...@googlegroups.com
Don,

Thanks for trying it.

> When I positioned the cursor at the end of any line of the file and hit
> Return, I got the following:

> File "c:\ProgramFiles\Python24\lib\idlelib\PyParse.py", line 159, in


> find_good_parse_start
> ps1 = '\n' + sys.ps1
> AttributeError: 'module' object has no attribute 'ps1'

Ah. It looks like I'll need to distribute PyParse with peppy instead
of relying on the python library version. Apparently the python 2.5
version (which I had been testing on) is different from the 2.4
version.

The fix is in svn now, where I now distribute the 2.5 version of
PyParse with peppy.

As for the other issue, I thought it might have been a problem with
the 2.8.3 version of AUI, but you've run peppy before and haven't hit
this problem... Hmmm.

> File
> "c:\ProgramFiles\Python24\lib\site-packages\wx-2.8-msw-ansi\wx\aui.py",
> line 1404, in GetPage
> return _aui.AuiNotebook_GetPage(*args, **kwargs)
> wx._core.PyAssertionError: C++ assertion "page_idx <
> m_tabs.GetPageCount()" failed at ..\..\src\aui\auibook.cpp(2872) in
> wxAuiNotebook::GetPage()

It seems to indicate that a notebook page didn't get registered with
the notebook itself. Maybe the earlier exception caused it? Let me
know if it still happens when the PyParse fix has been included. At
the very least, I'm missing a try/except block in there somewhere.

Thanks,

Rob

Don Dwiggins

unread,
Nov 14, 2007, 3:11:43 PM11/14/07
to pyx...@googlegroups.com
Your changes fixed the first traceback problem; here's what I'm seeing now:

- Auto-indentation is working pretty well in Python mode, with one
exception: when the cursor is at the end of an existing "def ..." line,
hitting Enter doesn't indent. It works fine when typing a new one, however.

- If I use the Buffers menu to visit a different buffer instead of the
Python one I'm editing, then go back to the Python buffer, the major
mode is set back to Fundamental. (This only happens with an unsaved new
buffer; once I save it to a file, the mode comes back properly after
switching buffers.)


- If I close a buffer containing a file, then re-open the file, it gets
put into a buffer with a "<n>" suffix, as though there were still
another buffer around with the file's name. This is minor, but could
get mildly annoying during a long session.

- On closing peppy, I'm still getting the same traceback I reported
before. (By the way, the shell prompt doesn't return after this;
something's holding the python process open. When I give it a BREAK
signal, the process closes and the prompt comes back -- this also
happened before.)

On balance, it's starting to look usable; I'll try it again when I have
to edit a "real" file, and have time to be careful with it.

Rob McMullen

unread,
Nov 14, 2007, 4:15:48 PM11/14/07
to pyx...@googlegroups.com
On Nov 14, 2007 12:11 PM, Don Dwiggins <d...@dondwiggins.net> wrote:
> - Auto-indentation is working pretty well in Python mode, with one
> exception: when the cursor is at the end of an existing "def ..." line,
> hitting Enter doesn't indent. It works fine when typing a new one, however.

I've noticed a similar problem, but for me it only happens rarely and
I've never been able to duplicate it consistently. Does it always
fail for you? If you have a test file shows the problem, would you
mind forwarding it to me?

> - If I use the Buffers menu to visit a different buffer instead of the
> Python one I'm editing, then go back to the Python buffer, the major
> mode is set back to Fundamental. (This only happens with an unsaved new
> buffer; once I save it to a file, the mode comes back properly after
> switching buffers.)

Yep, I see that. I should set the default major mode of a new file to
the new major mode when its major mode is explicitly set by the user.

> - If I close a buffer containing a file, then re-open the file, it gets
> put into a buffer with a "<n>" suffix, as though there were still
> another buffer around with the file's name. This is minor, but could
> get mildly annoying during a long session.

I copied this behavior directly from XEmacs. I actually find it a bit
annoying myself, so maybe after all the buffers of a particular name
are deleted, I'll reset the count to zero.

> - On closing peppy, I'm still getting the same traceback I reported
> before. (By the way, the shell prompt doesn't return after this;
> something's holding the python process open. When I give it a BREAK
> signal, the process closes and the prompt comes back -- this also
> happened before.)

There's a thread that's not getting cleaned up. I put a sys.exit in
the code, but because of the exception you're seeing, the sys.exit
doesn't get called. The real solution is to find out what's causing
that exception (athough after that I need to figure out why that
thread doesn't get shut down).

> On balance, it's starting to look usable; I'll try it again when I have
> to edit a "real" file, and have time to be careful with it.

Thanks, I appreciate the bug reports.

Rob

Don Dwiggins

unread,
Nov 14, 2007, 4:41:08 PM11/14/07
to pyx...@googlegroups.com
Rob McMullen wrote:
> On Nov 14, 2007 12:11 PM, Don Dwiggins <d...@dondwiggins.net> wrote:
>
>> - Auto-indentation is working pretty well in Python mode, with one
>> exception: when the cursor is at the end of an existing "def ..." line,
>> hitting Enter doesn't indent. It works fine when typing a new one, however.
>>
>
> I've noticed a similar problem, but for me it only happens rarely and
> I've never been able to duplicate it consistently. Does it always
> fail for you? If you have a test file shows the problem, would you
> mind forwarding it to me?
>
It doesn't need a file; here's a procedure that will recreate it:
- Open a new text file, set the mode to Python.
- Type "def foo(bar):", then newline, then "pass".
- Move the cursor back to just after the colon, press Enter. I get an
empty line with the cursor in the first column.

I can also make it happen by opening make-doc.py (in the peppy top
folder), going to the end of the "def findChangeLogVersion" line, and
hitting Enter.

Good news! I think I've found the cause of the traceback problem on
exit: after you do either of the above procedures, exit peppy by using
the close box on the window. It seems to be a problem in dealing with a
"dirty" buffer during shutdown.

Finally, here's another little glitch: after opening a new file and
typing into it, hit Ctrl-S -- peppy complains that saving to
"about:untitled" failed.

Rob McMullen

unread,
Nov 14, 2007, 6:13:46 PM11/14/07
to pyx...@googlegroups.com
On Nov 14, 2007 1:41 PM, Don Dwiggins <d...@dondwiggins.net> wrote:
> It doesn't need a file; here's a procedure that will recreate it:
> - Open a new text file, set the mode to Python.
> - Type "def foo(bar):", then newline, then "pass".
> - Move the cursor back to just after the colon, press Enter. I get an
> empty line with the cursor in the first column.

Aha! I see it, but strangely only on windows. GTK seems fine.
Thanks for showing me how to duplicate the problem.

> Good news! I think I've found the cause of the traceback problem on
> exit: after you do either of the above procedures, exit peppy by using
> the close box on the window. It seems to be a problem in dealing with a
> "dirty" buffer during shutdown.

Yep, I see that, too. Thanks.

> Finally, here's another little glitch: after opening a new file and
> typing into it, hit Ctrl-S -- peppy complains that saving to
> "about:untitled" failed.

That's a non-obvious artifact of the about: protocol. Because all my
file interaction is based on URLs, I've created this pseudo protocol
called 'about' that's analogous to the http protocol in that it's
read-only. So, loading from an about: url is fine, but you can't save
to it. The intent was that Save would be disabled, but Save As
wouldn't be, forcing you to choose a new filename.

Interestingly, that exposes a missing bit about my action handling:
Ctrl-S is disabled in the menubar and toolbar interface, but I don't
disable it when you try the keyboard shortcut. I'll have to disable
the keyboard shortcut if the menu item is unavailable.

Thanks,

Rob

Don Dwiggins

unread,
Nov 14, 2007, 7:43:05 PM11/14/07
to pyx...@googlegroups.com
Glad I could help on this.

> Interestingly, that exposes a missing bit about my action handling:
> Ctrl-S is disabled in the menubar and toolbar interface, but I don't
> disable it when you try the keyboard shortcut. I'll have to disable
> the keyboard shortcut if the menu item is unavailable.
>
I'd suggest for now not bothering with disabling menu and toolbar items
- just do it like Emacs, and map the relevant menu, toolbar, and
keystroke events to the "save file" function, and let it figure out what
do do (in this case, forward to "save file as").

Later, create an MVC-style model object that knows about the current
state of the buffer (and whatever else it needs to) and exposes Boolean
methods like "can save", "can delete selection", etc.; then treat the
menu/toolbar items as "views" on the object. They get notified of a
change of state, and use the methods to decide whether to enable
themselves. I've found that this kind of approach makes it much simpler
to ensure that all and only the right UI items are enabled at any time.

Rob McMullen

unread,
Nov 15, 2007, 12:13:10 AM11/15/07
to pyx...@googlegroups.com
On Nov 14, 2007 4:43 PM, Don Dwiggins <d...@dondwiggins.net> wrote:
> Glad I could help on this.

Turns out IDLE's PyParse is hardcoded to unix line endings! Before
investing a bunch of time converting PyParse to be line-ending
agnostic, I took the simple way out and just convert the temporary
text to unix line endings before passing it to the parser. Fixed in
svn and a new patchlevel release 0.7.1.1

> Later, create an MVC-style model object that knows about the current
> state of the buffer (and whatever else it needs to) and exposes Boolean
> methods like "can save", "can delete selection", etc.; then treat the
> menu/toolbar items as "views" on the object.

Essentially that's what I've already done. State is stored
extrinsically to the action; when each action's isEnabled method is
called to update the UI, the action goes to the stc buffer's CanSave,
CanEdit, etc. method to check for whatever conditions it needs to be
satisfied.

The same actions that populate the menubar/toolbar are also used for
keybinding processing; I just forgot to have the keyboard processor
check the enable state before firing off the action. :) That's also
now fixed in svn.

Rob

Reply all
Reply to author
Forward
0 new messages