[Python-checkins] r65052 - in sandbox/trunk/ttk-gsoc/src/idlelib: EditorWindow.py HyperParser.py editorpage.py tabbedpages_new.py tabbedpages_old.py
guilherme.polo
python-checkins at python.org
Thu Jul 17 03:27:36 CEST 2008
Author: guilherme.polo
Date: Thu Jul 17 03:27:35 2008
New Revision: 65052
Log:
Moved a lot of stuff from EditorWindow to a new module: editorpage. tabs are not working at all yet, this is a first step towards tabs support
Added:
sandbox/trunk/ttk-gsoc/src/idlelib/editorpage.py
Modified:
sandbox/trunk/ttk-gsoc/src/idlelib/EditorWindow.py
sandbox/trunk/ttk-gsoc/src/idlelib/HyperParser.py
sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_new.py
sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_old.py
Modified: sandbox/trunk/ttk-gsoc/src/idlelib/EditorWindow.py
==============================================================================
--- sandbox/trunk/ttk-gsoc/src/idlelib/EditorWindow.py (original)
+++ sandbox/trunk/ttk-gsoc/src/idlelib/EditorWindow.py Thu Jul 17 03:27:35 2008
@@ -6,25 +6,17 @@
import webbrowser
import tkMessageBox
import tkSimpleDialog
-from Tkinter import Frame, Text, Menu, Scrollbar, TclError, BooleanVar
-from Tkconstants import INSERT, END, RIGHT, BOTTOM, TOP, X, Y, BOTH, LEFT
+from Tkinter import Menu, Scrollbar, TclError, BooleanVar
+from Tkconstants import INSERT, END, RIGHT, BOTTOM, TOP, X, Y, BOTH
-import idlever
-import textView
-import aboutDialog
-import configDialog
import macosxSupport
-import PyParse
import Bindings
-import GrepDialog
import WindowList
import PathBrowser
import ClassBrowser
-import SearchDialog
-import ReplaceDialog
+from editorpage import EditorPage, classifyws
from tabbedpages import get_tabbedpage
from configHandler import idleConf
-from MultiCall import MultiCallCreator
from IOBinding import IOBinding, filesystemencoding, encoding
from Percolator import Percolator
from UndoDelegator import UndoDelegator
@@ -32,8 +24,9 @@
TabbedPageSet = get_tabbedpage()
-if idleConf.GetOption('main', 'General', 'use-ttk', type='int'):
- from ttk import Frame, Scrollbar
+TTK = idleConf.GetOption('main', 'General', 'use-ttk', type='int')
+if TTK:
+ from ttk import Scrollbar
# The default tab setting for a Text widget, in average-width characters.
TK_TABWIDTH_DEFAULT = 8
@@ -58,6 +51,24 @@
class EditorWindow(object):
from ColorDelegator import ColorDelegator
help_url = None
+ rmenu = None
+ rmenu_specs = [
+ # ("Label", "<<virtual-event>>"), ...
+ ("Close", "<<close-window>>"), # Example
+ ]
+ menu_specs = [
+ ("file", "_File"),
+ ("edit", "_Edit"),
+ ("format", "F_ormat"),
+ ("run", "_Run"),
+ ("options", "_Options"),
+ ("windows", "_Windows"),
+ ("help", "_Help"),
+ ]
+
+ if macosxSupport.runningAsOSXApp():
+ del menu_specs[-3]
+ menu_specs[-2] = ("windows", "_Window")
def __init__(self, flist=None, filename=None, key=None, root=None):
if EditorWindow.help_url is None:
@@ -114,63 +125,18 @@
# create a Notebook where the text pages for this EditorWindow will
# reside
- first_page_title = "#1"
- self.text_notebook = TabbedPageSet(top, page_names=[first_page_title])
+ self.text_notebook = TabbedPageSet(top)
+ self.text = text = self.new_tab()
+ self.top.focused_widget = self.text
+ self.text_notebook.pack(fill=BOTH, expand=True)
- page_frame = self.text_notebook.pages[first_page_title].frame
- vbar = Scrollbar(page_frame, name='vbar')
# The following "width" attribute is used by PyShell, so keep it here
- self.width = idleConf.GetOption('main', 'EditorWindow', 'width')
- self.text = text = MultiCallCreator(Text)(
- page_frame, name='text', padx=5, wrap='none', width=self.width,
- height=idleConf.GetOption('main', 'EditorWindow', 'height'))
- self.top.focused_widget = self.text
+ self.width = idleConf.GetOption('main', 'EditorPage', 'width')
self.createmenubar()
- self.apply_bindings()
self.top.protocol("WM_DELETE_WINDOW", self.close)
self.top.bind("<<close-window>>", self.close_event)
- if macosxSupport.runningAsOSXApp():
- # Command-W on editorwindows doesn't work without this.
- text.bind('<<close-window>>', self.close_event)
- text.bind("<<close-tab>>", self.close_tab)
- text.bind("<<open-new-tab>>", self.new_editor_page)
- text.bind("<<cut>>", self.cut)
- text.bind("<<copy>>", self.copy)
- text.bind("<<paste>>", self.paste)
- text.bind("<<center-insert>>", self.center_insert_event)
- text.bind("<<help>>", self.help_dialog)
- text.bind("<<python-docs>>", self.python_docs)
- text.bind("<<about-idle>>", self.about_dialog)
- text.bind("<<open-config-dialog>>", self.config_dialog)
- text.bind("<<open-module>>", self.open_module)
- text.bind("<<do-nothing>>", lambda event: "break")
- text.bind("<<select-all>>", self.select_all)
- text.bind("<<remove-selection>>", self.remove_selection)
- text.bind("<<find>>", self.find_event)
- text.bind("<<find-again>>", self.find_again_event)
- text.bind("<<find-in-files>>", self.find_in_files_event)
- text.bind("<<find-selection>>", self.find_selection_event)
- text.bind("<<replace>>", self.replace_event)
- text.bind("<<goto-line>>", self.goto_line_event)
- text.bind("<3>", self.right_menu_event)
- text.bind("<<smart-backspace>>",self.smart_backspace_event)
- text.bind("<<newline-and-indent>>",self.newline_and_indent_event)
- text.bind("<<smart-indent>>",self.smart_indent_event)
- text.bind("<<indent-region>>",self.indent_region_event)
- text.bind("<<dedent-region>>",self.dedent_region_event)
- text.bind("<<comment-region>>",self.comment_region_event)
- text.bind("<<uncomment-region>>",self.uncomment_region_event)
- text.bind("<<tabify-region>>",self.tabify_region_event)
- text.bind("<<untabify-region>>",self.untabify_region_event)
- text.bind("<<toggle-tabs>>",self.toggle_tabs_event)
- text.bind("<<change-indentwidth>>",self.change_indentwidth_event)
- text.bind("<Left>", self.move_at_edge_if_selection(0))
- text.bind("<Right>", self.move_at_edge_if_selection(1))
- text.bind("<<del-word-left>>", self.del_word_left)
- text.bind("<<del-word-right>>", self.del_word_right)
- text.bind("<<beginning-of-line>>", self.home_callback)
if flist:
flist.inversedict[self] = key
@@ -182,18 +148,6 @@
text.bind("<<open-path-browser>>", self.open_path_browser)
self.set_status_bar()
- vbar['command'] = text.yview
- vbar.pack(side=RIGHT, fill=Y)
- text['yscrollcommand'] = vbar.set
- fontWeight = 'normal'
- if idleConf.GetOption('main', 'EditorWindow', 'font-bold', type='bool'):
- fontWeight='bold'
- text.config(font=(idleConf.GetOption('main', 'EditorWindow', 'font'),
- idleConf.GetOption('main', 'EditorWindow', 'font-size'),
- fontWeight))
- text.pack(side=TOP, fill=BOTH, expand=1)
- text.focus_set()
- self.text_notebook.pack(fill=BOTH, expand=True)
# usetabs true -> literal tab characters are used by indent and
# dedent cmds, possibly mixed with spaces if
@@ -300,54 +254,36 @@
self.flist.new(dirname)
return "break"
- def new_editor_page(self, event):
+ def new_tab(self, event=None):
"""Create a new EditorPage and insert it into the notebook."""
- print "Not yet"
- return "break"
-
- def home_callback(self, event):
- if (event.state & 12) != 0 and event.keysym == "Home":
- # state&1==shift, state&4==control, state&8==alt
- return # <Modifier-Home>; fall back to class binding
-
- if self.text.index("iomark") and \
- self.text.compare("iomark", "<=", "insert lineend") and \
- self.text.compare("insert linestart", "<=", "iomark"):
- insertpt = int(self.text.index("iomark").split(".")[1])
- else:
- line = self.text.get("insert linestart", "insert lineend")
- for insertpt in xrange(len(line)):
- if line[insertpt] not in (' ','\t'):
- break
- else:
- insertpt=len(line)
-
- lineat = int(self.text.index("insert").split('.')[1])
+ page_title = "#%d" % (len(self.text_notebook.pages) + 1)
+ page = self.text_notebook.add_page(page_title)
- if insertpt == lineat:
- insertpt = 0
-
- dest = "insert linestart+"+str(insertpt)+"c"
-
- if (event.state&1) == 0:
- # shift not pressed
- self.text.tag_remove("sel", "1.0", "end")
+ if TTK:
+ parent = page.frame
else:
- if not self.text.index("sel.first"):
- self.text.mark_set("anchor","insert")
+ parent = page.frame
- first = self.text.index(dest)
- last = self.text.index("anchor")
+ vbar = Scrollbar(parent, name='vbar')
+ page.editpage = EditorPage(parent, self, name='text', padx=5,
+ wrap='none')
+ text = page.editpage.text
- if self.text.compare(first,">",last):
- first,last = last,first
+ vbar['command'] = text.yview
+ vbar.pack(side=RIGHT, fill=Y)
+ text['yscrollcommand'] = vbar.set
+ fontWeight = 'normal'
+ if idleConf.GetOption('main', 'EditorPage', 'font-bold', type='bool'):
+ fontWeight = 'bold'
+ text.config(font=(idleConf.GetOption('main', 'EditorPage', 'font'),
+ idleConf.GetOption('main', 'EditorPage', 'font-size'),
+ fontWeight))
+ text.pack(side=TOP, fill=BOTH, expand=1)
+ text.focus_set()
- self.text.tag_remove("sel", "1.0", "end")
- self.text.tag_add("sel", first, last)
+ self.apply_bindings()
- self.text.mark_set("insert", dest)
- self.text.see("insert")
- return "break"
+ return text
def set_status_bar(self):
self.status_bar = MultiStatusBar(self.top)
@@ -368,21 +304,6 @@
self.status_bar.set_label('column', 'Col: %s' % column)
self.status_bar.set_label('line', 'Ln: %s' % line)
- menu_specs = [
- ("file", "_File"),
- ("edit", "_Edit"),
- ("format", "F_ormat"),
- ("run", "_Run"),
- ("options", "_Options"),
- ("windows", "_Windows"),
- ("help", "_Help"),
- ]
-
- if macosxSupport.runningAsOSXApp():
- del menu_specs[-3]
- menu_specs[-2] = ("windows", "_Window")
-
-
def createmenubar(self):
mbar = self.menubar
self.menudict = menudict = {}
@@ -410,138 +331,6 @@
menu.delete(self.wmenu_end+1, end)
WindowList.add_windows_to_menu(menu)
- rmenu = None
-
- def right_menu_event(self, event):
- self.text.tag_remove("sel", "1.0", "end")
- self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
- if not self.rmenu:
- self.make_rmenu()
- rmenu = self.rmenu
- self.event = event
- iswin = sys.platform[:3] == 'win'
- if iswin:
- self.text.config(cursor="arrow")
- rmenu.tk_popup(event.x_root, event.y_root)
- if iswin:
- self.text.config(cursor="ibeam")
-
- rmenu_specs = [
- # ("Label", "<<virtual-event>>"), ...
- ("Close", "<<close-window>>"), # Example
- ]
-
- def make_rmenu(self):
- rmenu = Menu(self.text, tearoff=0)
- for label, eventname in self.rmenu_specs:
- def command(text=self.text, eventname=eventname):
- text.event_generate(eventname)
- rmenu.add_command(label=label, command=command)
- self.rmenu = rmenu
-
- def about_dialog(self, event=None):
- aboutDialog.AboutDialog(self.top,'About IDLE')
-
- def config_dialog(self, event=None):
- configDialog.ConfigDialog(self.top,'Settings')
-
- def help_dialog(self, event=None):
- fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'help.txt')
- textView.view_file(self.top,'Help',fn)
-
- def python_docs(self, event=None):
- if sys.platform[:3] == 'win':
- os.startfile(self.help_url)
- else:
- webbrowser.open(self.help_url)
- return "break"
-
- def cut(self,event):
- self.text.event_generate("<<Cut>>")
- return "break"
-
- def copy(self,event):
- if not self.text.tag_ranges("sel"):
- # There is no selection, so do nothing and maybe interrupt.
- return
- self.text.event_generate("<<Copy>>")
- return "break"
-
- def paste(self,event):
- self.text.event_generate("<<Paste>>")
- self.text.see("insert")
- return "break"
-
- def select_all(self, event=None):
- self.text.tag_add("sel", "1.0", "end-1c")
- self.text.mark_set("insert", "1.0")
- self.text.see("insert")
- return "break"
-
- def remove_selection(self, event=None):
- self.text.tag_remove("sel", "1.0", "end")
- self.text.see("insert")
-
- def move_at_edge_if_selection(self, edge_index):
- """Cursor move begins at start or end of selection
-
- When a left/right cursor key is pressed create and return to Tkinter a
- function which causes a cursor move from the associated edge of the
- selection.
-
- """
- self_text_index = self.text.index
- self_text_mark_set = self.text.mark_set
- edges_table = ("sel.first+1c", "sel.last-1c")
- def move_at_edge(event):
- if (event.state & 5) == 0: # no shift(==1) or control(==4) pressed
- try:
- self_text_index("sel.first")
- self_text_mark_set("insert", edges_table[edge_index])
- except TclError:
- pass
- return move_at_edge
-
- def del_word_left(self, event):
- self.text.event_generate('<Meta-Delete>')
- return "break"
-
- def del_word_right(self, event):
- self.text.event_generate('<Meta-d>')
- return "break"
-
- def find_event(self, event):
- SearchDialog.find(self.text)
- return "break"
-
- def find_again_event(self, event):
- SearchDialog.find_again(self.text)
- return "break"
-
- def find_selection_event(self, event):
- SearchDialog.find_selection(self.text)
- return "break"
-
- def find_in_files_event(self, event):
- GrepDialog.grep(self.text, self.io, self.flist)
- return "break"
-
- def replace_event(self, event):
- ReplaceDialog.replace(self.text)
- return "break"
-
- def goto_line_event(self, event):
- text = self.text
- lineno = tkSimpleDialog.askinteger("Goto",
- "Go to line number:",parent=text)
- if lineno is None:
- return "break"
- if lineno <= 0:
- text.bell()
- return "break"
- text.mark_set("insert", "%d.0" % lineno)
- text.see("insert")
-
def open_module(self, event=None):
# XXX Shouldn't this be in IOBinding or in FileList?
try:
@@ -591,12 +380,37 @@
def open_path_browser(self, event=None):
PathBrowser.PathBrowser(self.flist)
+ def current_page(self):
+ """Return the active EditorPage in EditorWindow."""
+ curr_tab = self.text_notebook.select()
+ if TTK:
+ page = self.text_notebook.pages[self.text_notebook.tab(
+ curr_tab)['text']].editpage
+ else:
+ page = self.text_notebook.pages[curr_tab].editpage
+ return page
+
+ def newline_and_indent_event(self, event):
+ """Call newline_and_indent_event on current EditorPage."""
+ self.current_page().newline_and_indent_event(event)
+
+ def get_selection_indices(self):
+ """Call get_selection_indices on current EditorPage."""
+ return self.current_page().get_selection_indices()
+
+ def build_char_in_string_func(self, startindex):
+ """Call build_char_in_string_func on current EditorPage."""
+ return self.current_page().build_char_in_string_func(startindex)
+
def gotoline(self, lineno):
+ page = self.current_page()
+ text = page.text
+
if lineno is not None and lineno > 0:
- self.text.mark_set("insert", "%d.0" % lineno)
- self.text.tag_remove("sel", "1.0", "end")
- self.text.tag_add("sel", "insert", "insert +1l")
- self.center()
+ text.mark_set("insert", "%d.0" % lineno)
+ text.tag_remove("sel", "1.0", "end")
+ text.tag_add("sel", "insert", "insert +1l")
+ page.center()
def ispythonsource(self, filename):
if not filename or os.path.isdir(filename):
@@ -665,11 +479,11 @@
def ResetFont(self):
"Update the text widgets' font if it is changed"
# Called from configDialog.py
- fontWeight='normal'
- if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'):
- fontWeight='bold'
- self.text.config(font=(idleConf.GetOption('main','EditorWindow','font'),
- idleConf.GetOption('main','EditorWindow','font-size'),
+ fontWeight = 'normal'
+ if idleConf.GetOption('main', 'EditorPage', 'font-bold', type='bool'):
+ fontWeight = 'bold'
+ self.text.config(font=(idleConf.GetOption('main', 'EditorPage', 'font'),
+ idleConf.GetOption('main', 'EditorPage', 'font-size'),
fontWeight))
def RemoveKeybindings(self):
@@ -834,31 +648,6 @@
# return unicode string to display non-ASCII chars correctly
return self._filename_to_unicode(self.io.filename or "")
- def center_insert_event(self, event):
- self.center()
-
- def center(self, mark="insert"):
- text = self.text
- top, bot = self.getwindowlines()
- lineno = self.getlineno(mark)
- height = bot - top
- newtop = max(1, lineno - height//2)
- text.yview(float(newtop))
-
- def getwindowlines(self):
- text = self.text
- top = self.getlineno("@0,0")
- bot = self.getlineno("@0,65535")
- if top == bot and text.winfo_height() == 1:
- # Geometry manager hasn't run yet
- height = int(text['height'])
- bot = top + height - 1
- return top, bot
-
- def getlineno(self, mark="insert"):
- text = self.text
- return int(float(text.index(mark)))
-
def get_geometry(self):
"Return (width, height, x, y)"
geom = self.top.wm_geometry()
@@ -869,10 +658,6 @@
def close_event(self, event):
self.close()
- def close_tab(self, event):
- """Close current tab, if no more tabs present, close the window."""
- print "I do nothing right now"
-
def maybesave(self):
if self.io:
if not self.get_saved():
@@ -956,11 +741,13 @@
def apply_bindings(self, keydefs=None):
if keydefs is None:
keydefs = Bindings.default_keydefs
- text = self.text
- text.keydefs = keydefs
- for event, keylist in keydefs.items():
- if keylist:
- text.event_add(event, *keylist)
+
+ for page in self.text_notebook.pages.itervalues():
+ text = page.editpage.text
+ text.keydefs = keydefs
+ for event, keylist in keydefs.items():
+ if keylist:
+ text.event_add(event, *keylist)
def fill_menus(self, menudefs=None, keydefs=None):
"""Add appropriate entries to the menus and submenus
@@ -1025,40 +812,13 @@
# reusing IDLE's support code needs to define these for its GUI's
# flavor of widget.
- # Is character at text_index in a Python string? Return 0 for
- # "guaranteed no", true for anything else. This info is expensive
- # to compute ab initio, but is probably already known by the
- # platform's colorizer.
-
- def is_char_in_string(self, text_index):
- if self.color:
- # Return true iff colorizer hasn't (re)gotten this far
- # yet, or the character is tagged as being in a string
- return self.text.tag_prevrange("TODO", text_index) or \
- "STRING" in self.text.tag_names(text_index)
- else:
- # The colorizer is missing: assume the worst
- return 1
-
- # If a selection is defined in the text widget, return (start,
- # end) as Tkinter text indices, otherwise return (None, None)
- def get_selection_indices(self):
- try:
- first = self.text.index("sel.first")
- last = self.text.index("sel.last")
- return first, last
- except TclError:
- return None, None
-
# Return the text widget's current view of what a tab stop means
# (equivalent width in spaces).
-
def get_tabwidth(self):
current = self.text['tabs'] or TK_TABWIDTH_DEFAULT
return int(current)
# Set the text widget's current view of what a tab stop means.
-
def set_tabwidth(self, newtabwidth):
text = self.text
if self.get_tabwidth() != newtabwidth:
@@ -1072,7 +832,6 @@
# indentwidth != tabwidth set usetabs false.
# In any case, adjust the Text widget's view of what a tab
# character means.
-
def set_indentation_params(self, ispythonsource, guess=True):
if guess and ispythonsource:
i = self.guess_indent()
@@ -1082,355 +841,10 @@
self.usetabs = False
self.set_tabwidth(self.tabwidth)
- def smart_backspace_event(self, event):
- text = self.text
- first, last = self.get_selection_indices()
- if first and last:
- text.delete(first, last)
- text.mark_set("insert", first)
- return "break"
- # Delete whitespace left, until hitting a real char or closest
- # preceding virtual tab stop.
- chars = text.get("insert linestart", "insert")
- if chars == '':
- if text.compare("insert", ">", "1.0"):
- # easy: delete preceding newline
- text.delete("insert-1c")
- else:
- text.bell() # at start of buffer
- return "break"
- if chars[-1] not in " \t":
- # easy: delete preceding real char
- text.delete("insert-1c")
- return "break"
- # Ick. It may require *inserting* spaces if we back up over a
- # tab character! This is written to be clear, not fast.
- tabwidth = self.tabwidth
- have = len(chars.expandtabs(tabwidth))
- assert have > 0
- want = ((have - 1) // self.indentwidth) * self.indentwidth
- # Debug prompt is multilined....
- last_line_of_prompt = sys.ps1.split('\n')[-1]
- ncharsdeleted = 0
- while 1:
- if chars == last_line_of_prompt:
- break
- chars = chars[:-1]
- ncharsdeleted = ncharsdeleted + 1
- have = len(chars.expandtabs(tabwidth))
- if have <= want or chars[-1] not in " \t":
- break
- text.undo_block_start()
- text.delete("insert-%dc" % ncharsdeleted, "insert")
- if have < want:
- text.insert("insert", ' ' * (want - have))
- text.undo_block_stop()
- return "break"
-
- def smart_indent_event(self, event):
- # if intraline selection:
- # delete it
- # elif multiline selection:
- # do indent-region
- # else:
- # indent one level
- text = self.text
- first, last = self.get_selection_indices()
- text.undo_block_start()
- try:
- if first and last:
- if index2line(first) != index2line(last):
- return self.indent_region_event(event)
- text.delete(first, last)
- text.mark_set("insert", first)
- prefix = text.get("insert linestart", "insert")
- raw, effective = classifyws(prefix, self.tabwidth)
- if raw == len(prefix):
- # only whitespace to the left
- self.reindent_to(effective + self.indentwidth)
- else:
- # tab to the next 'stop' within or to right of line's text:
- if self.usetabs:
- pad = '\t'
- else:
- effective = len(prefix.expandtabs(self.tabwidth))
- n = self.indentwidth
- pad = ' ' * (n - effective % n)
- text.insert("insert", pad)
- text.see("insert")
- return "break"
- finally:
- text.undo_block_stop()
-
- def newline_and_indent_event(self, event):
- text = self.text
- first, last = self.get_selection_indices()
- text.undo_block_start()
- try:
- if first and last:
- text.delete(first, last)
- text.mark_set("insert", first)
- line = text.get("insert linestart", "insert")
- i, n = 0, len(line)
- while i < n and line[i] in " \t":
- i = i+1
- if i == n:
- # the cursor is in or at leading indentation in a continuation
- # line; just inject an empty line at the start
- text.insert("insert linestart", '\n')
- return "break"
- indent = line[:i]
- # strip whitespace before insert point unless it's in the prompt
- i = 0
- last_line_of_prompt = sys.ps1.split('\n')[-1]
- while line and line[-1] in " \t" and line != last_line_of_prompt:
- line = line[:-1]
- i = i+1
- if i:
- text.delete("insert - %d chars" % i, "insert")
- # strip whitespace after insert point
- while text.get("insert") in " \t":
- text.delete("insert")
- # start new line
- text.insert("insert", '\n')
-
- # adjust indentation for continuations and block
- # open/close first need to find the last stmt
- lno = index2line(text.index('insert'))
- y = PyParse.Parser(self.indentwidth, self.tabwidth)
- if not self.context_use_ps1:
- for context in self.num_context_lines:
- startat = max(lno - context, 1)
- startatindex = `startat` + ".0"
- rawtext = text.get(startatindex, "insert")
- y.set_str(rawtext)
- bod = y.find_good_parse_start(
- self.context_use_ps1,
- self._build_char_in_string_func(startatindex))
- if bod is not None or startat == 1:
- break
- y.set_lo(bod or 0)
- else:
- r = text.tag_prevrange("console", "insert")
- if r:
- startatindex = r[1]
- else:
- startatindex = "1.0"
- rawtext = text.get(startatindex, "insert")
- y.set_str(rawtext)
- y.set_lo(0)
-
- c = y.get_continuation_type()
- if c != PyParse.C_NONE:
- # The current stmt hasn't ended yet.
- if c == PyParse.C_STRING_FIRST_LINE:
- # after the first line of a string; do not indent at all
- pass
- elif c == PyParse.C_STRING_NEXT_LINES:
- # inside a string which started before this line;
- # just mimic the current indent
- text.insert("insert", indent)
- elif c == PyParse.C_BRACKET:
- # line up with the first (if any) element of the
- # last open bracket structure; else indent one
- # level beyond the indent of the line with the
- # last open bracket
- self.reindent_to(y.compute_bracket_indent())
- elif c == PyParse.C_BACKSLASH:
- # if more than one line in this stmt already, just
- # mimic the current indent; else if initial line
- # has a start on an assignment stmt, indent to
- # beyond leftmost =; else to beyond first chunk of
- # non-whitespace on initial line
- if y.get_num_lines_in_stmt() > 1:
- text.insert("insert", indent)
- else:
- self.reindent_to(y.compute_backslash_indent())
- else:
- assert 0, "bogus continuation type %r" % (c,)
- return "break"
-
- # This line starts a brand new stmt; indent relative to
- # indentation of initial line of closest preceding
- # interesting stmt.
- indent = y.get_base_indent_string()
- text.insert("insert", indent)
- if y.is_block_opener():
- self.smart_indent_event(event)
- elif indent and y.is_block_closer():
- self.smart_backspace_event(event)
- return "break"
- finally:
- text.see("insert")
- text.undo_block_stop()
-
- # Our editwin provides a is_char_in_string function that works
- # with a Tk text index, but PyParse only knows about offsets into
- # a string. This builds a function for PyParse that accepts an
- # offset.
-
- def _build_char_in_string_func(self, startindex):
- def inner(offset, _startindex=startindex,
- _icis=self.is_char_in_string):
- return _icis(_startindex + "+%dc" % offset)
- return inner
-
- def indent_region_event(self, event):
- head, tail, chars, lines = self.get_region()
- for pos in range(len(lines)):
- line = lines[pos]
- if line:
- raw, effective = classifyws(line, self.tabwidth)
- effective = effective + self.indentwidth
- lines[pos] = self._make_blanks(effective) + line[raw:]
- self.set_region(head, tail, chars, lines)
- return "break"
-
- def dedent_region_event(self, event):
- head, tail, chars, lines = self.get_region()
- for pos in range(len(lines)):
- line = lines[pos]
- if line:
- raw, effective = classifyws(line, self.tabwidth)
- effective = max(effective - self.indentwidth, 0)
- lines[pos] = self._make_blanks(effective) + line[raw:]
- self.set_region(head, tail, chars, lines)
- return "break"
-
- def comment_region_event(self, event):
- head, tail, chars, lines = self.get_region()
- for pos in range(len(lines) - 1):
- line = lines[pos]
- lines[pos] = '##' + line
- self.set_region(head, tail, chars, lines)
-
- def uncomment_region_event(self, event):
- head, tail, chars, lines = self.get_region()
- for pos in range(len(lines)):
- line = lines[pos]
- if not line:
- continue
- if line[:2] == '##':
- line = line[2:]
- elif line[:1] == '#':
- line = line[1:]
- lines[pos] = line
- self.set_region(head, tail, chars, lines)
-
- def tabify_region_event(self, event):
- head, tail, chars, lines = self.get_region()
- tabwidth = self._asktabwidth()
- for pos in range(len(lines)):
- line = lines[pos]
- if line:
- raw, effective = classifyws(line, tabwidth)
- ntabs, nspaces = divmod(effective, tabwidth)
- lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:]
- self.set_region(head, tail, chars, lines)
-
- def untabify_region_event(self, event):
- head, tail, chars, lines = self.get_region()
- tabwidth = self._asktabwidth()
- for pos in range(len(lines)):
- lines[pos] = lines[pos].expandtabs(tabwidth)
- self.set_region(head, tail, chars, lines)
-
- def toggle_tabs_event(self, event):
- if self.askyesno(
- "Toggle tabs",
- "Turn tabs " + ("on", "off")[self.usetabs] +
- "?\nIndent width " +
- ("will be", "remains at")[self.usetabs] + " 8." +
- "\n Note: a tab is always 8 columns",
- parent=self.text):
- self.usetabs = not self.usetabs
- # Try to prevent inconsistent indentation.
- # User must change indent width manually after using tabs.
- self.indentwidth = 8
- return "break"
-
- # XXX this isn't bound to anything -- see tabwidth comments
-## def change_tabwidth_event(self, event):
-## new = self._asktabwidth()
-## if new != self.tabwidth:
-## self.tabwidth = new
-## self.set_indentation_params(0, guess=0)
-## return "break"
-
- def change_indentwidth_event(self, event):
- new = self.askinteger(
- "Indent width",
- "New indent width (2-16)\n(Always use 8 when using tabs)",
- parent=self.text,
- initialvalue=self.indentwidth,
- minvalue=2,
- maxvalue=16)
- if new and new != self.indentwidth and not self.usetabs:
- self.indentwidth = new
- return "break"
-
- def get_region(self):
- text = self.text
- first, last = self.get_selection_indices()
- if first and last:
- head = text.index(first + " linestart")
- tail = text.index(last + "-1c lineend +1c")
- else:
- head = text.index("insert linestart")
- tail = text.index("insert lineend +1c")
- chars = text.get(head, tail)
- lines = chars.split("\n")
- return head, tail, chars, lines
-
- def set_region(self, head, tail, chars, lines):
- text = self.text
- newchars = "\n".join(lines)
- if newchars == chars:
- text.bell()
- return
- text.tag_remove("sel", "1.0", "end")
- text.mark_set("insert", head)
- text.undo_block_start()
- text.delete(head, tail)
- text.insert(head, newchars)
- text.undo_block_stop()
- text.tag_add("sel", head, "insert")
-
- # Make string that displays as n leading blanks.
-
- def _make_blanks(self, n):
- if self.usetabs:
- ntabs, nspaces = divmod(n, self.tabwidth)
- return '\t' * ntabs + ' ' * nspaces
- else:
- return ' ' * n
-
- # Delete from beginning of line to insert point, then reinsert
- # column logical (meaning use tabs if appropriate) spaces.
-
- def reindent_to(self, column):
- text = self.text
- text.undo_block_start()
- if text.compare("insert linestart", "!=", "insert"):
- text.delete("insert linestart", "insert")
- if column:
- text.insert("insert", self._make_blanks(column))
- text.undo_block_stop()
-
- def _asktabwidth(self):
- return self.askinteger(
- "Tab width",
- "Columns per tab? (2-16)",
- parent=self.text,
- initialvalue=self.indentwidth,
- minvalue=2,
- maxvalue=16) or self.tabwidth
-
# Guess indentwidth from text content.
# Return guessed indentwidth. This should not be believed unless
# it's in a reasonable range (e.g., it will be 0 if no indented
# blocks are found).
-
def guess_indent(self):
opener, indented = IndentSearcher(self.text, self.tabwidth).run()
if opener and indented:
@@ -1440,28 +854,11 @@
indentsmall = indentlarge = 0
return indentlarge - indentsmall
-# "line.col" -> line, as an int
-def index2line(index):
- return int(float(index))
-
# Look at the leading whitespace in s.
# Return pair (# of leading ws characters,
# effective # of leading blanks after expanding
# tabs to width tabwidth)
-def classifyws(s, tabwidth):
- raw = effective = 0
- for ch in s:
- if ch == ' ':
- raw = raw + 1
- effective = effective + 1
- elif ch == '\t':
- raw = raw + 1
- effective = (effective // tabwidth + 1) * tabwidth
- else:
- break
- return raw, effective
-
import tokenize
_tokenize = tokenize
del tokenize
@@ -1558,6 +955,7 @@
def test():
+ from Tkinter import Tk
root = Tk()
fixwordbreaks(root)
root.withdraw()
Modified: sandbox/trunk/ttk-gsoc/src/idlelib/HyperParser.py
==============================================================================
--- sandbox/trunk/ttk-gsoc/src/idlelib/HyperParser.py (original)
+++ sandbox/trunk/ttk-gsoc/src/idlelib/HyperParser.py Thu Jul 17 03:27:35 2008
@@ -10,7 +10,9 @@
import string
import keyword
+
import PyParse
+from editorpage import index2line
class HyperParser:
@@ -24,8 +26,6 @@
parser = PyParse.Parser(editwin.indentwidth, editwin.tabwidth)
- def index2line(index):
- return int(float(index))
lno = index2line(text.index(index))
if not editwin.context_use_ps1:
@@ -38,7 +38,7 @@
# its status will be the same as the char before it, if should.
parser.set_str(text.get(startatindex, stopatindex)+' \n')
bod = parser.find_good_parse_start(
- editwin._build_char_in_string_func(startatindex))
+ editwin.build_char_in_string_func(startatindex))
if bod is not None or startat == 1:
break
parser.set_lo(bod or 0)
Added: sandbox/trunk/ttk-gsoc/src/idlelib/editorpage.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/ttk-gsoc/src/idlelib/editorpage.py Thu Jul 17 03:27:35 2008
@@ -0,0 +1,675 @@
+import os
+import sys
+import webbrowser
+import tkSimpleDialog
+from Tkinter import Text, Menu, TclError
+
+import textView
+import aboutDialog
+import configDialog
+import macosxSupport
+import PyParse
+import GrepDialog
+import SearchDialog
+import ReplaceDialog
+from configHandler import idleConf
+from MultiCall import MultiCallCreator
+
+#def callback(method, widget=None):
+# def func(*args):
+# if widget:
+# return method(widget=widget, *args)
+# else:
+# return method(*args)
+
+# return func
+
+def classifyws(s, tabwidth):
+ raw = effective = 0
+ for ch in s:
+ if ch == ' ':
+ raw = raw + 1
+ effective = effective + 1
+ elif ch == '\t':
+ raw = raw + 1
+ effective = (effective // tabwidth + 1) * tabwidth
+ else:
+ break
+ return raw, effective
+
+# "line.col" -> line, as an int
+def index2line(index):
+ return int(float(index))
+
+class EditorPage:
+ def __init__(self, parent, editwin, **kwargs):
+ self.editwin = editwin
+ kwargs.setdefault('width', idleConf.GetOption('main', 'EditorPage',
+ 'width'))
+ kwargs.setdefault('height', idleConf.GetOption('main', 'EditorPage',
+ 'height'))
+
+ self.text = MultiCallCreator(Text)(parent, **kwargs)
+ self._setup_bindings()
+
+ def center(self, mark="insert"):
+ # Used by EditorWindow.gotoline
+ text = self.text
+ top, bot = self._getwindowlines()
+ lineno = self._getlineno(mark)
+ height = bot - top
+ newtop = max(1, lineno - height//2)
+ text.yview(float(newtop))
+
+ def newline_and_indent_event(self, event):
+ # Used by EditorWindow.newline_and_indent_event which is used by PyShell
+ text = self.text
+ first, last = self.get_selection_indices()
+ text.undo_block_start()
+ try:
+ if first and last:
+ text.delete(first, last)
+ text.mark_set("insert", first)
+ line = text.get("insert linestart", "insert")
+ i, n = 0, len(line)
+ while i < n and line[i] in " \t":
+ i = i+1
+ if i == n:
+ # the cursor is in or at leading indentation in a continuation
+ # line; just inject an empty line at the start
+ text.insert("insert linestart", '\n')
+ return "break"
+ indent = line[:i]
+ # strip whitespace before insert point unless it's in the prompt
+ i = 0
+ last_line_of_prompt = sys.ps1.split('\n')[-1]
+ while line and line[-1] in " \t" and line != last_line_of_prompt:
+ line = line[:-1]
+ i = i+1
+ if i:
+ text.delete("insert - %d chars" % i, "insert")
+ # strip whitespace after insert point
+ while text.get("insert") in " \t":
+ text.delete("insert")
+ # start new line
+ text.insert("insert", '\n')
+
+ # adjust indentation for continuations and block
+ # open/close first need to find the last stmt
+ lno = index2line(text.index('insert'))
+ y = PyParse.Parser(self.editwin.indentwidth, self.editwin.tabwidth)
+ if not self.editwin.context_use_ps1:
+ for context in self.editwin.num_context_lines:
+ startat = max(lno - context, 1)
+ startatindex = `startat` + ".0"
+ rawtext = text.get(startatindex, "insert")
+ y.set_str(rawtext)
+ bod = y.find_good_parse_start(
+ self.editwin.context_use_ps1,
+ self.build_char_in_string_func(startatindex))
+ if bod is not None or startat == 1:
+ break
+ y.set_lo(bod or 0)
+ else:
+ r = text.tag_prevrange("console", "insert")
+ if r:
+ startatindex = r[1]
+ else:
+ startatindex = "1.0"
+ rawtext = text.get(startatindex, "insert")
+ y.set_str(rawtext)
+ y.set_lo(0)
+
+ c = y.get_continuation_type()
+ if c != PyParse.C_NONE:
+ # The current stmt hasn't ended yet.
+ if c == PyParse.C_STRING_FIRST_LINE:
+ # after the first line of a string; do not indent at all
+ pass
+ elif c == PyParse.C_STRING_NEXT_LINES:
+ # inside a string which started before this line;
+ # just mimic the current indent
+ text.insert("insert", indent)
+ elif c == PyParse.C_BRACKET:
+ # line up with the first (if any) element of the
+ # last open bracket structure; else indent one
+ # level beyond the indent of the line with the
+ # last open bracket
+ self.__reindent_to(y.compute_bracket_indent())
+ elif c == PyParse.C_BACKSLASH:
+ # if more than one line in this stmt already, just
+ # mimic the current indent; else if initial line
+ # has a start on an assignment stmt, indent to
+ # beyond leftmost =; else to beyond first chunk of
+ # non-whitespace on initial line
+ if y.get_num_lines_in_stmt() > 1:
+ text.insert("insert", indent)
+ else:
+ self.__reindent_to(y.compute_backslash_indent())
+ else:
+ assert 0, "bogus continuation type %r" % (c,)
+ return "break"
+
+ # This line starts a brand new stmt; indent relative to
+ # indentation of initial line of closest preceding
+ # interesting stmt.
+ indent = y.get_base_indent_string()
+ text.insert("insert", indent)
+ if y.is_block_opener():
+ self._smart_indent_event(event)
+ elif indent and y.is_block_closer():
+ self._smart_backspace_event(event)
+ return "break"
+ finally:
+ text.see("insert")
+ text.undo_block_stop()
+
+ # If a selection is defined in the text widget, return (start,
+ # end) as Tkinter text indices, otherwise return (None, None)
+ def get_selection_indices(self):
+ # Used by EditorWindow.get_selection_indices which is used by
+ # FormatParagraph
+ try:
+ first = self.text.index("sel.first")
+ last = self.text.index("sel.last")
+ return first, last
+ except TclError:
+ return None, None
+
+ # Our editpage provides a __is_char_in_string function that works
+ # with a Tk text index, but PyParse only knows about offsets into
+ # a string. This builds a function for PyParse that accepts an
+ # offset.
+ def build_char_in_string_func(self, startindex):
+ # Used by EditorWindow.build_char_in_string_func which is used by
+ # HyperParser
+ def inner(offset, _startindex=startindex,
+ _icis=self.__is_char_in_string):
+ return _icis(_startindex + "+%dc" % offset)
+ return inner
+
+ def _setup_bindings(self):
+ text = self.text
+ actions = ('<<close-tab>>', '<<help>>', '<<python-docs>>',
+ '<<about-idle>>', '<<open-config-dialog>>',
+ '<<cut>>', '<<copy>>', '<<paste>>', '<<select-all>>',
+ '<<remove-selection>>', '<<del-word-left>>', '<<del-word-right>>',
+ '<<beginning-of-line>>')
+
+ for action in actions:
+ prefix_size = action.count('<')
+ method_name = action[prefix_size:-prefix_size].replace('-', '_')
+ text.bind(action, getattr(self, "_%s" % method_name.lower()))
+
+ events = ('<<find>>', '<<center-insert>>', '<<find-again>>',
+ '<<find-in-files>>', '<<find-selection>>', '<<replace>>',
+ '<<goto-line>>', '<<smart-backspace>>', '<<smart-indent>>',
+ '<<indent-region>>', '<<dedent-region>>', '<<comment-region>>',
+ '<<tabify-region>>', '<<untabify-region>>', '<<toggle-tabs>>',
+ '<<change-indentwidth>>')
+
+ for event in events:
+ prefix_size = event.count('<')
+ method_name = event[prefix_size:-prefix_size].replace('-', '_')
+ text.bind(event, getattr(self, "_%s_event" % method_name.lower()))
+
+ parent_actions = ('<<new-tab>>', '<<open-module>>')
+
+ for action in parent_actions:
+ prefix_size = action.count('<')
+ method_name = action[prefix_size:-prefix_size].replace('-', '_')
+ text.bind(action, getattr(self.editwin, method_name))
+
+ text.bind('<<newline-and-indent>>', self.newline_and_indent_event)
+ text.bind("<<do-nothing>>", lambda event: "break")
+ text.bind("<Left>", self._move_at_edge_if_selection(0))
+ text.bind("<Right>", self._move_at_edge_if_selection(1))
+ text.bind("<3>", self._right_menu)
+
+ if macosxSupport.runningAsOSXApp():
+ # Command-W on editorwindows doesn't work without this.
+ text.bind('<<close-window>>', self.editwin.close_event)
+
+ def _close_tab(self, event):
+ """Close current tab, if no more tabs present, close the window."""
+ print "I do nothing right now"
+
+ def _help(self, event=None):
+ fn = os.path.join(os.path.abspath(os.path.dirname(__file__)),
+ 'help.txt')
+ textView.view_file(self.text, 'Help', fn)
+
+ def _python_docs(self, event=None):
+ if sys.platform[:3] == 'win':
+ os.startfile(self.editwin.help_url)
+ else:
+ webbrowser.open(self.editwin.help_url)
+ return "break"
+
+ def _about_idle(self, event=None):
+ aboutDialog.AboutDialog(self.text, 'About IDLE')
+
+ def _open_config_dialog(self, event=None):
+ # When changing colors and saving it, it requires the attribute
+ # instance_dict making necessary to pass self.editwin.top as the
+ # parent
+ configDialog.ConfigDialog(self.editwin.top, 'Settings')
+
+ def _find_event(self, event):
+ SearchDialog.find(self.text)
+ return "break"
+
+ def _find_again_event(self, event):
+ SearchDialog.find_again(self.text)
+ return "break"
+
+ def _find_selection_event(self, event):
+ SearchDialog.find_selection(self.text)
+ return "break"
+
+ def _find_in_files_event(self, event):
+ # XXX not expected to work correctly for now
+ GrepDialog.grep(self.text, self.editwin.io, self.editwin.flist)
+ return "break"
+
+ def _replace_event(self, event):
+ ReplaceDialog.replace(self.text)
+ return "break"
+
+ def _center_insert_event(self, event):
+ self.center()
+
+ def _getwindowlines(self):
+ text = self.text
+ top = self._getlineno("@0,0")
+ bot = self._getlineno("@0,65535")
+ if top == bot and text.winfo_height() == 1:
+ # Geometry manager hasn't run yet
+ height = int(text['height'])
+ bot = top + height - 1
+ return top, bot
+
+ def _getlineno(self, mark="insert"):
+ return int(float(self.text.index(mark)))
+
+ def _goto_line_event(self, event):
+ text = self.text
+ lineno = tkSimpleDialog.askinteger("Goto", "Go to line number:",
+ parent=text)
+
+ if lineno is None:
+ return "break"
+
+ if lineno <= 0:
+ text.bell()
+ return "break"
+
+ text.mark_set("insert", "%d.0" % lineno)
+ text.see("insert")
+
+ def _cut(self, event):
+ self.text.event_generate("<<Cut>>")
+ return "break"
+
+ def _copy(self, event):
+ if not self.text.tag_ranges("sel"):
+ # There is no selection, so do nothing and maybe interrupt.
+ return
+
+ self.text.event_generate("<<Copy>>")
+ return "break"
+
+ def _paste(self, event):
+ self.text.event_generate("<<Paste>>")
+ self.text.see("insert")
+ return "break"
+
+ def _select_all(self, event=None):
+ self.text.tag_add("sel", "1.0", "end-1c")
+ self.text.mark_set("insert", "1.0")
+ self.text.see("insert")
+ return "break"
+
+ def _remove_selection(self, event=None):
+ self.text.tag_remove("sel", "1.0", "end")
+ self.text.see("insert")
+
+ def _del_word_left(self, event):
+ self.text.event_generate('<Meta-Delete>')
+ return "break"
+
+ def _del_word_right(self, event):
+ self.text.event_generate('<Meta-d>')
+ return "break"
+
+ def _move_at_edge_if_selection(self, edge_index):
+ """Cursor move begins at start or end of selection
+ When a left/right cursor key is pressed create and return to Tkinter a
+ function which causes a cursor move from the associated edge of the
+ selection.
+ """
+ text_index = self.text.index
+ text_mark_set = self.text.mark_set
+ edges_table = ("sel.first+1c", "sel.last-1c")
+
+ def move_at_edge(event):
+ if (event.state & 5) == 0: # no shift(==1) or control(==4) pressed
+ try:
+ text_index("sel.first")
+ text_mark_set("insert", edges_table[edge_index])
+ except TclError:
+ pass
+
+ return move_at_edge
+
+ def _beginning_of_line(self, event):
+ if (event.state & 12) != 0 and event.keysym == "Home":
+ # state&1==shift, state&4==control, state&8==alt
+ return # <Modifier-Home>; fall back to class binding
+
+ text = self.text
+
+ if text.index("iomark") and \
+ text.compare("iomark", "<=", "insert lineend") and \
+ text.compare("insert linestart", "<=", "iomark"):
+ insertpt = int(text.index("iomark").split(".")[1])
+ else:
+ line = text.get("insert linestart", "insert lineend")
+ for insertpt in xrange(len(line)):
+ if line[insertpt] not in (' ','\t'):
+ break
+ else:
+ insertpt=len(line)
+
+ lineat = int(text.index("insert").split('.')[1])
+
+ if insertpt == lineat:
+ insertpt = 0
+
+ dest = "insert linestart+%sc" % str(insertpt)
+
+ if (event.state & 1) == 0:
+ # shift not pressed
+ text.tag_remove("sel", "1.0", "end")
+ else:
+ if not text.index("sel.first"):
+ text.mark_set("anchor", "insert")
+
+ first = text.index(dest)
+ last = text.index("anchor")
+
+ if text.compare(first, ">", last):
+ first, last = last, first
+
+ text.tag_remove("sel", "1.0", "end")
+ text.tag_add("sel", first, last)
+
+ text.mark_set("insert", dest)
+ text.see("insert")
+ return "break"
+
+ def _smart_backspace_event(self, event):
+ text = self.text
+ first, last = self.get_selection_indices()
+ if first and last:
+ text.delete(first, last)
+ text.mark_set("insert", first)
+ return "break"
+ # Delete whitespace left, until hitting a real char or closest
+ # preceding virtual tab stop.
+ chars = text.get("insert linestart", "insert")
+ if chars == '':
+ if text.compare("insert", ">", "1.0"):
+ # easy: delete preceding newline
+ text.delete("insert-1c")
+ else:
+ text.bell() # at start of buffer
+ return "break"
+ if chars[-1] not in " \t":
+ # easy: delete preceding real char
+ text.delete("insert-1c")
+ return "break"
+ # Ick. It may require *inserting* spaces if we back up over a
+ # tab character! This is written to be clear, not fast.
+ tabwidth = self.editwin.tabwidth
+ have = len(chars.expandtabs(tabwidth))
+ assert have > 0
+ want = ((have - 1) //
+ self.editwin.indentwidth) * self.editwin.indentwidth
+ # Debug prompt is multilined....
+ last_line_of_prompt = sys.ps1.split('\n')[-1]
+ ncharsdeleted = 0
+ while 1:
+ if chars == last_line_of_prompt:
+ break
+ chars = chars[:-1]
+ ncharsdeleted = ncharsdeleted + 1
+ have = len(chars.expandtabs(tabwidth))
+ if have <= want or chars[-1] not in " \t":
+ break
+ text.undo_block_start()
+ text.delete("insert-%dc" % ncharsdeleted, "insert")
+ if have < want:
+ text.insert("insert", ' ' * (want - have))
+ text.undo_block_stop()
+ return "break"
+
+ def _smart_indent_event(self, event):
+ # if intraline selection:
+ # delete it
+ # elif multiline selection:
+ # do indent-region
+ # else:
+ # indent one level
+ text = self.text
+ first, last = self.get_selection_indices()
+ text.undo_block_start()
+ try:
+ if first and last:
+ if index2line(first) != index2line(last):
+ return self._indent_region_event(event)
+ text.delete(first, last)
+ text.mark_set("insert", first)
+ prefix = text.get("insert linestart", "insert")
+ raw, effective = classifyws(prefix, self.editwin.tabwidth)
+ if raw == len(prefix):
+ # only whitespace to the left
+ self.__reindent_to(effective + self.editwin.indentwidth)
+ else:
+ # tab to the next 'stop' within or to right of line's text:
+ if self.editwin.usetabs:
+ pad = '\t'
+ else:
+ effective = len(prefix.expandtabs(self.editwin.tabwidth))
+ n = self.editwin.indentwidth
+ pad = ' ' * (n - effective % n)
+ text.insert("insert", pad)
+ text.see("insert")
+ return "break"
+ finally:
+ text.undo_block_stop()
+
+ def _indent_region_event(self, event):
+ head, tail, chars, lines = self.__get_region()
+ for pos in range(len(lines)):
+ line = lines[pos]
+ if line:
+ raw, effective = classifyws(line, self.editwin.tabwidth)
+ effective = effective + self.editwin.indentwidth
+ lines[pos] = self.__make_blanks(effective) + line[raw:]
+ self.__set_region(head, tail, chars, lines)
+ return "break"
+
+ def _dedent_region_event(self, event):
+ head, tail, chars, lines = self.__get_region()
+ for pos in range(len(lines)):
+ line = lines[pos]
+ if line:
+ raw, effective = classifyws(line, self.editwin.tabwidth)
+ effective = max(effective - self.editwin.indentwidth, 0)
+ lines[pos] = self.__make_blanks(effective) + line[raw:]
+ self.__set_region(head, tail, chars, lines)
+ return "break"
+
+ def _comment_region_event(self, event):
+ head, tail, chars, lines = self.__get_region()
+ for pos in range(len(lines) - 1):
+ line = lines[pos]
+ lines[pos] = '##' + line
+ self.__set_region(head, tail, chars, lines)
+
+ def _uncomment_region_event(self, event):
+ head, tail, chars, lines = self.__get_region()
+ for pos in range(len(lines)):
+ line = lines[pos]
+ if not line:
+ continue
+ if line[:2] == '##':
+ line = line[2:]
+ elif line[:1] == '#':
+ line = line[1:]
+ lines[pos] = line
+ self.__set_region(head, tail, chars, lines)
+
+ def _tabify_region_event(self, event):
+ head, tail, chars, lines = self.__get_region()
+ tabwidth = self.__asktabwidth()
+ for pos in range(len(lines)):
+ line = lines[pos]
+ if line:
+ raw, effective = classifyws(line, tabwidth)
+ ntabs, nspaces = divmod(effective, tabwidth)
+ lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:]
+ self.__set_region(head, tail, chars, lines)
+
+ def _untabify_region_event(self, event):
+ head, tail, chars, lines = self.__get_region()
+ tabwidth = self.__asktabwidth()
+ for pos in range(len(lines)):
+ lines[pos] = lines[pos].expandtabs(tabwidth)
+ self.__set_region(head, tail, chars, lines)
+
+ def _toggle_tabs_event(self, event):
+ if self.editwin.askyesno(
+ "Toggle tabs",
+ "Turn tabs " + ("on", "off")[self.editwin.usetabs] +
+ "?\nIndent width " +
+ ("will be", "remains at")[self.editwin.usetabs] + " 8." +
+ "\n Note: a tab is always 8 columns",
+ parent=self.text):
+ self.editwin.usetabs = not self.editwin.usetabs
+ # Try to prevent inconsistent indentation.
+ # User must change indent width manually after using tabs.
+ self.editwin.indentwidth = 8
+ return "break"
+
+ def _change_indentwidth_event(self, event):
+ new = self.editwin.askinteger(
+ "Indent width",
+ "New indent width (2-16)\n(Always use 8 when using tabs)",
+ parent=self.text,
+ initialvalue=self.editwin.indentwidth,
+ minvalue=2,
+ maxvalue=16)
+ if new and new != self.editwin.indentwidth and not self.editwin.usetabs:
+ self.editwin.indentwidth = new
+ return "break"
+
+ def _right_menu(self, event):
+ self.text.tag_remove("sel", "1.0", "end")
+ self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
+
+ if not self.editwin.rmenu:
+ self.__make_rmenu()
+
+ rmenu = self.editwin.rmenu
+ self.event = event
+ iswin = sys.platform[:3] == 'win'
+ if iswin:
+ self.text.config(cursor="arrow")
+ rmenu.tk_popup(event.x_root, event.y_root)
+ if iswin:
+ self.text.config(cursor="ibeam")
+
+ def __make_rmenu(self):
+ rmenu = Menu(self.text, tearoff=False)
+
+ for label, eventname in self.editwin.rmenu_specs:
+ def command(text=self.text, eventname=eventname):
+ text.event_generate(eventname)
+ rmenu.add_command(label=label, command=command)
+
+ self.editwin.rmenu = rmenu
+
+ def __asktabwidth(self):
+ return self.editwin.askinteger(
+ "Tab width",
+ "Columns per tab? (2-16)",
+ parent=self.text,
+ initialvalue=self.editwin.indentwidth,
+ minvalue=2,
+ maxvalue=16) or self.editwin.tabwidth
+
+ # Make string that displays as n leading blanks.
+ def __make_blanks(self, n):
+ if self.editwin.usetabs:
+ ntabs, nspaces = divmod(n, self.editwin.tabwidth)
+ return '\t' * ntabs + ' ' * nspaces
+ else:
+ return ' ' * n
+
+ def __get_region(self):
+ text = self.text
+ first, last = self.get_selection_indices()
+ if first and last:
+ head = text.index(first + " linestart")
+ tail = text.index(last + "-1c lineend +1c")
+ else:
+ head = text.index("insert linestart")
+ tail = text.index("insert lineend +1c")
+ chars = text.get(head, tail)
+ lines = chars.split("\n")
+ return head, tail, chars, lines
+
+ def __set_region(self, head, tail, chars, lines):
+ text = self.text
+ newchars = "\n".join(lines)
+ if newchars == chars:
+ text.bell()
+ return
+ text.tag_remove("sel", "1.0", "end")
+ text.mark_set("insert", head)
+ text.undo_block_start()
+ text.delete(head, tail)
+ text.insert(head, newchars)
+ text.undo_block_stop()
+ text.tag_add("sel", head, "insert")
+
+ # Delete from beginning of line to insert point, then reinsert
+ # column logical (meaning use tabs if appropriate) spaces.
+ def __reindent_to(self, column):
+ text = self.text
+ text.undo_block_start()
+ if text.compare("insert linestart", "!=", "insert"):
+ text.delete("insert linestart", "insert")
+ if column:
+ text.insert("insert", self.__make_blanks(column))
+ text.undo_block_stop()
+
+ # Tk implementations of "virtual text methods" -- each platform
+ # reusing IDLE's support code needs to define these for its GUI's
+ # flavor of widget.
+
+ # Is character at text_index in a Python string? Return 0 for
+ # "guaranteed no", true for anything else. This info is expensive
+ # to compute ab initio, but is probably already known by the
+ # platform's colorizer.
+ def __is_char_in_string(self, text_index):
+ if self.editwin.color: # XXX should this attribute be set per page ?
+ # Return true iff colorizer hasn't (re)gotten this far
+ # yet, or the character is tagged as being in a string
+ return self.text.tag_prevrange("TODO", text_index) or \
+ "STRING" in self.text.tag_names(text_index)
+ else:
+ # The colorizer is missing: assume the worst
+ return 1
Modified: sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_new.py
==============================================================================
--- sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_new.py (original)
+++ sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_new.py Thu Jul 17 03:27:35 2008
@@ -51,6 +51,8 @@
# workaround for bug #1878298 at tktoolkit sf bug tracker
self.event_generate('<Expose>')
+ return fpage
+
def remove_page(self, page_name):
if not page_name in self.pages:
raise KeyError("No such TabPage: '%s" % page_name)
Modified: sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_old.py
==============================================================================
--- sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_old.py (original)
+++ sandbox/trunk/ttk-gsoc/src/idlelib/tabbedpages_old.py Thu Jul 17 03:27:35 2008
@@ -428,6 +428,8 @@
self._default_page = page_name
self.change_page(page_name)
+ return self.pages[page_name]
+
def remove_page(self, page_name):
"""Destroy the page whose name is given in page_name."""
if not page_name in self.pages:
@@ -467,6 +469,10 @@
self._tab_set.set_selected_tab(page_name)
+ def select(self):
+ """Return the name of the currently selected page."""
+ return self._current_page
+
if __name__ == '__main__':
from Tkinter import Tk, Label, Entry, Button
# test dialog
More information about the Python-checkins
mailing list