IDLE 3000 (suggested improvements)

r rt8396 at gmail.com
Tue Jan 27 18:19:36 CET 2009


Proposal:
OK, so the python language has officially moved into the next level. I
look at IDLE and think, hmm great IDE but it could really use a spit
shining. So here is a very simple script showing my ideas to improve
IDLE.

Reason for change:
The text widget and the prompt(>>>) should be separated. Trying to
write a conditional in the interactive IDLE is a real pain. Not to
mention that when you copy code from Interactive  IDLE to the IDLE
editor window the indention is eight spaces instead four and you've
got that prompt(>>>) stuck in there. I have a solution for the problem
though.

I hope you are using fixed-width font

Lst|<----- Text Widget ---->|
   |                        |
>>>|if this:                |
...|    if that:            |
...|        ...             |
...|    elif that:          |
...|        ...             |
...|    else:               |
...|        ...             |
>>>|                        |
>>>|x = 10                  |
>>>|                        |


Basically you have a Listbox on the left for the prompt and a Text on
the right. Disable the Listbox highlight and key press events and now
we have a very friendly interactive IDLE! No more prompt hijacking
your snippets, and no more eigtht space indention! Hip-Hip-Hooray!


#-- Start Script --#

from Tkinter import *
import tkMessageBox as MB

class CMD(Toplevel):
    def __init__(self, master):
        Toplevel.__init__(self, master)
        self.master = master
        self.startidx = '1.0'
        self.backidx = '1.0'
        self.title('IDLE 3000')

        self.listbox = Listbox(self, width=3, relief=FLAT, font=
('Courier New',12), takefocus=0)
        self.listbox.pack(fill=Y, side=LEFT)
        self.listbox.insert(0, '>>>')

        self.text = Text(self, relief=FLAT, spacing3=1, wrap=NONE,
font=('Courier New',12))
        self.text.pack(fill=BOTH, side=LEFT, expand=1)
        self.text.config(width=50, height=20)
        self.text.focus_set()

        self.listbox.bind("<KeyPress>"          , lambda e: "break")
        self.listbox.bind("<Button-1>"          , lambda e: "break")
        self.listbox.bind("<B1-Motion>"         , lambda e: "break")
        self.listbox.bind("<ButtonRelease-1>"   , lambda e: "break")
        self.listbox.bind("<B2-Motion>"         , lambda e: "break")
        self.listbox.bind("<MouseWheel>"        , lambda e: "break")

        self.text.bind('<Next>'         , lambda e: "break")#pageup
        self.text.bind('<Prior>'        , lambda e: "break")#pagedown
        self.text.bind('<Delete>'       , lambda e: "break")
        self.text.bind('<Control-Home>' , lambda e: "break")
        self.text.bind('<Control-End>'  , lambda e: "break")
        self.text.bind("<B2-Motion>"    , lambda e: "break")
        self.text.bind('<Button-2>'     , lambda e: "break")
        self.text.bind("<MouseWheel>"   , lambda e: "break")

        self.text.bind("<Up>"       , self.onUp)
        self.text.bind("<Down>"     , self.onDown)
        self.text.bind("<Tab>"      , self.onTab)
        self.text.bind("<Return>"   , self.onReturn)
        self.text.bind("<BackSpace>", self.onBackSpace)

        self.protocol("WM_DELETE_WINDOW", self.onQuit)
        self.lift(master)
        self.master.withdraw()

    def fix_index(self, chars):
        self.backidx = '%d.0' %(int(self.backidx.split('.')[0])+1)
        self.text.insert(END, '\n')
        self.text.mark_set(INSERT, END)
        self.text.see(INSERT)
        self.listbox.insert(END, chars)
        self.listbox.see(self.listbox.size())

    def onQuit(self):
        self.grab_release()
        self.master.destroy()

    def onTab(self, event=None):
        curline, cursor = self.text.index(INSERT).split('.')[0]+'.0',
self.text.index(INSERT)
        self.text.insert(INSERT, '    ')
        return "break"

    def onDown(self, event):
        i = self.text.index(INSERT+'+1l') #;print 'New index: ', i
        self.text.mark_set(INSERT, i)
        self.text.see(i)
        self.listbox.see(int(i.split('.')[0])-1)
        return "break"

    def onUp(self, event=None):
        i = self.text.index(INSERT+'-1l') #;print 'New index: ', i
        self.text.mark_set(INSERT, i)
        self.text.see(i)
        self.listbox.see(int(i.split('.')[0])-1)
        return "break"

    def onBackSpace(self, event=None):
        if self.text.compare(self.text.index(INSERT), '!=',
self.backidx):
            self.text.delete(self.text.index(INSERT+'-1c'))
        return "break"

    def onReturn(self, event=None):
        curline, cursor = self.text.index(INSERT).split('.')[0]+'.0',
self.text.index(INSERT)
        text = self.text.get(self.startidx, END).strip()
        if self.text.compare(curline, '<', self.startidx):#'Out Of
Zone'
            self.text.mark_set(INSERT, END+'-1c')
            self.text.see(INSERT)
            self.listbox.see(END)
        elif '.0' in cursor: #nothing typed on this line, try to exec
command
            cmd = text.rstrip('\n')
            try:
                exec(cmd)
            except:
                self.master.bell()
                print '%s\n%s\n%s' %(sys.exc_traceback, sys.exc_type,
sys.exc_value)
            finally:
                self.fix_index('>>>')
                self.startidx = self.text.index(INSERT)
        elif text != '':#something typed
            self.fix_index('...')
        else: #insert newline
            self.fix_index('>>>')
        return "break"


if __name__ == '__main__':
    print 'main'
    root = Tk()

    MB.showinfo('IDLE 3000 Introduction','''
This Demo shows how i think the standard IDLE should behave.
You will notice the prompt is outside of the text widget. This
keeps the prompt from hijacking your code snippits when you
copy-paste to the main editor window. This also keeps all indention
at the Python recommended four spaces.

Please note this demo is to only show the layout, it does not include
syntax highlight, auto-tab, auto-dedent, or any other feature. This is
not even the correct way to write a good editor. My only intention is
to
show a more user friendly layout

have fun :)
''')
    cmd = CMD(root)
    root.mainloop()


#-- End Script --#

Issue #2:
When you press MMB and there is a highlighted selection in the text it
gets pasted over and over again @ the insertion cursor. This can be
aggravating, and turn a clean script into a bowl of "Cheerios"
breakfast cereal in no time.



More information about the Python-list mailing list