Commit e1e6bc22 authored by Guido van Rossum's avatar Guido van Rossum

Tim Peters smart.patch:

EditorWindow.py:

+ Added get_tabwidth & set_tabwidth "virtual text" methods, that get/set the
widget's view of what a tab means.

+ Moved TK_TABWIDTH_DEFAULT here from AutoIndent.

+ Renamed Mark's get_selection_index to get_selection_indices (sorry, Mark,
but the name was plain wrong <wink>).

FormatParagraph.py:  renamed use of get_selection_index.

AutoIndent.py:

+ Moved TK_TABWIDTH_DEFAULT to EditorWindow.

+ Rewrote set_indentation_params to use new VTW get/set_tabwidth methods.

+ Changed smart_backspace_event to delete whitespace back to closest
preceding virtual tab stop or real character (note that this may require
inserting characters if backspacing over a tab!).

+ Nuked almost references to the selection tag, in favor of using
get_selection_indices.  The sole exception is in set_region, for which no
"set_selection" abstraction has yet been agreed upon.

+ Had too much fun using the spiffy new features of the format-paragraph
cmd.
parent 3fea3ac0
...@@ -3,9 +3,6 @@ import string ...@@ -3,9 +3,6 @@ import string
#import tkMessageBox #import tkMessageBox
#import tkSimpleDialog #import tkSimpleDialog
# The default tab setting for a Text widget, in average-width characters.
TK_TABWIDTH_DEFAULT = 8
###$ event <<newline-and-indent>> ###$ event <<newline-and-indent>>
###$ win <Key-Return> ###$ win <Key-Return>
###$ win <KP_Enter> ###$ win <KP_Enter>
...@@ -101,7 +98,7 @@ class AutoIndent: ...@@ -101,7 +98,7 @@ class AutoIndent:
# Nobody expects this, so for now tabwidth should never be changed. # Nobody expects this, so for now tabwidth should never be changed.
usetabs = 1 usetabs = 1
indentwidth = 4 indentwidth = 4
tabwidth = TK_TABWIDTH_DEFAULT tabwidth = 8 # for IDLE use, must remain 8 until Tk is fixed
# If context_use_ps1 is true, parsing searches back for a ps1 line; # If context_use_ps1 is true, parsing searches back for a ps1 line;
# else searches for a popular (if, def, ...) Python stmt. # else searches for a popular (if, def, ...) Python stmt.
...@@ -139,8 +136,6 @@ class AutoIndent: ...@@ -139,8 +136,6 @@ class AutoIndent:
# character means. # character means.
def set_indentation_params(self, ispythonsource, guess=1): def set_indentation_params(self, ispythonsource, guess=1):
text = self.text
if guess and ispythonsource: if guess and ispythonsource:
i = self.guess_indent() i = self.guess_indent()
if 2 <= i <= 8: if 2 <= i <= 8:
...@@ -148,40 +143,48 @@ class AutoIndent: ...@@ -148,40 +143,48 @@ class AutoIndent:
if self.indentwidth != self.tabwidth: if self.indentwidth != self.tabwidth:
self.usetabs = 0 self.usetabs = 0
current_tabs = text['tabs'] self.editwin.set_tabwidth(self.tabwidth)
if current_tabs == "" and self.tabwidth == TK_TABWIDTH_DEFAULT:
pass
else:
# Reconfigure the Text widget by measuring the width
# of a tabwidth-length string in pixels, forcing the
# widget's tab stops to that.
need_tabs = text.tk.call("font", "measure", text['font'],
"-displayof", text.master,
"n" * self.tabwidth)
if current_tabs != need_tabs:
text.configure(tabs=need_tabs)
def smart_backspace_event(self, event): def smart_backspace_event(self, event):
text = self.text text = self.text
try: first, last = self.editwin.get_selection_indices()
first = text.index("sel.first")
last = text.index("sel.last")
except: # Was catching TclError, but this doesnt work for
first = last = None
if first and last: if first and last:
text.delete(first, last) text.delete(first, last)
text.mark_set("insert", first) text.mark_set("insert", first)
return "break" return "break"
# If we're at the end of leading whitespace, nuke one indent # Delete whitespace left, until hitting a real char or closest
# level, else one character. # preceding virtual tab stop.
chars = text.get("insert linestart", "insert") chars = text.get("insert linestart", "insert")
raw, effective = classifyws(chars, self.tabwidth) if chars == '':
if 0 < raw == len(chars): if text.compare("insert", ">", "1.0"):
if effective >= self.indentwidth: # easy: delete preceding newline
self.reindent_to(effective - self.indentwidth) text.delete("insert-1c")
else:
text.bell() # at start of buffer
return "break" return "break"
if chars[-1] not in " \t":
# easy: delete preceding real char
text.delete("insert-1c") text.delete("insert-1c")
return "break" return "break"
# Ick. It may require *inserting* spaces if we back up over a
# tab character! This is written to be clear, not fast.
expand, tabwidth = string.expandtabs, self.tabwidth
have = len(expand(chars, tabwidth))
assert have > 0
want = int((have - 1) / self.indentwidth) * self.indentwidth
ncharsdeleted = 0
while 1:
chars = chars[:-1]
ncharsdeleted = ncharsdeleted + 1
have = len(expand(chars, 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): def smart_indent_event(self, event):
# if intraline selection: # if intraline selection:
...@@ -190,11 +193,7 @@ class AutoIndent: ...@@ -190,11 +193,7 @@ class AutoIndent:
# do indent-region & return # do indent-region & return
# indent one level # indent one level
text = self.text text = self.text
try: first, last = self.editwin.get_selection_indices()
first = text.index("sel.first")
last = text.index("sel.last")
except: # Was catching TclError, but this doesnt work for
first = last = None
text.undo_block_start() text.undo_block_start()
try: try:
if first and last: if first and last:
...@@ -223,11 +222,7 @@ class AutoIndent: ...@@ -223,11 +222,7 @@ class AutoIndent:
def newline_and_indent_event(self, event): def newline_and_indent_event(self, event):
text = self.text text = self.text
try: first, last = self.editwin.get_selection_indices()
first = text.index("sel.first")
last = text.index("sel.last")
except: # Was catching TclError, but this doesnt work for
first = last = None
text.undo_block_start() text.undo_block_start()
try: try:
if first and last: if first and last:
...@@ -256,8 +251,8 @@ class AutoIndent: ...@@ -256,8 +251,8 @@ class AutoIndent:
# start new line # start new line
text.insert("insert", '\n') text.insert("insert", '\n')
# adjust indentation for continuations and block open/close # adjust indentation for continuations and block
# first need to find the last stmt # open/close first need to find the last stmt
lno = index2line(text.index('insert')) lno = index2line(text.index('insert'))
y = PyParse.Parser(self.indentwidth, self.tabwidth) y = PyParse.Parser(self.indentwidth, self.tabwidth)
for context in self.num_context_lines: for context in self.num_context_lines:
...@@ -280,15 +275,15 @@ class AutoIndent: ...@@ -280,15 +275,15 @@ class AutoIndent:
elif c == PyParse.C_BRACKET: elif c == PyParse.C_BRACKET:
# line up with the first (if any) element of the # line up with the first (if any) element of the
# last open bracket structure; else indent one # last open bracket structure; else indent one
# level beyond the indent of the line with the last # level beyond the indent of the line with the
# open bracket # last open bracket
self.reindent_to(y.compute_bracket_indent()) self.reindent_to(y.compute_bracket_indent())
elif c == PyParse.C_BACKSLASH: elif c == PyParse.C_BACKSLASH:
# if more than one line in this stmt already, just # if more than one line in this stmt already, just
# mimic the current indent; else if initial line has # mimic the current indent; else if initial line
# a start on an assignment stmt, indent to beyond # has a start on an assignment stmt, indent to
# leftmost =; else to beyond first chunk of non- # beyond leftmost =; else to beyond first chunk of
# whitespace on initial line # non-whitespace on initial line
if y.get_num_lines_in_stmt() > 1: if y.get_num_lines_in_stmt() > 1:
text.insert("insert", indent) text.insert("insert", indent)
else: else:
...@@ -298,8 +293,8 @@ class AutoIndent: ...@@ -298,8 +293,8 @@ class AutoIndent:
return "break" return "break"
# This line starts a brand new stmt; indent relative to # This line starts a brand new stmt; indent relative to
# indentation of initial line of closest preceding interesting # indentation of initial line of closest preceding
# stmt. # interesting stmt.
indent = y.get_base_indent_string() indent = y.get_base_indent_string()
text.insert("insert", indent) text.insert("insert", indent)
if y.is_block_opener(): if y.is_block_opener():
...@@ -313,9 +308,10 @@ class AutoIndent: ...@@ -313,9 +308,10 @@ class AutoIndent:
auto_indent = newline_and_indent_event auto_indent = newline_and_indent_event
# Our editwin provides a is_char_in_string function that works with # Our editwin provides a is_char_in_string function that works
# a Tk text index, but PyParse only knows about offsets into a string. # with a Tk text index, but PyParse only knows about offsets into
# This builds a function for PyParse that accepts an offset. # a string. This builds a function for PyParse that accepts an
# offset.
def _build_char_in_string_func(self, startindex): def _build_char_in_string_func(self, startindex):
def inner(offset, _startindex=startindex, def inner(offset, _startindex=startindex,
...@@ -413,9 +409,11 @@ class AutoIndent: ...@@ -413,9 +409,11 @@ class AutoIndent:
def get_region(self): def get_region(self):
text = self.text text = self.text
head = text.index("sel.first linestart") first, last = self.editwin.get_selection_indices()
tail = text.index("sel.last -1c lineend +1c") if first and last:
if not (head and tail): head = text.index(first + " linestart")
tail = text.index(last + "-1c lineend +1c")
else:
head = text.index("insert linestart") head = text.index("insert linestart")
tail = text.index("insert lineend +1c") tail = text.index("insert lineend +1c")
chars = text.get(head, tail) chars = text.get(head, tail)
......
...@@ -9,6 +9,9 @@ import tkMessageBox ...@@ -9,6 +9,9 @@ import tkMessageBox
import idlever import idlever
import WindowList import WindowList
# The default tab setting for a Text widget, in average-width characters.
TK_TABWIDTH_DEFAULT = 8
# File menu # File menu
#$ event <<open-module>> #$ event <<open-module>>
...@@ -599,7 +602,7 @@ class EditorWindow: ...@@ -599,7 +602,7 @@ class EditorWindow:
# If a selection is defined in the text widget, return (start, # If a selection is defined in the text widget, return (start,
# end) as Tkinter text indices, otherwise return (None, None) # end) as Tkinter text indices, otherwise return (None, None)
def get_selection_index(self): def get_selection_indices(self):
try: try:
first = self.text.index("sel.first") first = self.text.index("sel.first")
last = self.text.index("sel.last") last = self.text.index("sel.last")
...@@ -607,6 +610,23 @@ class EditorWindow: ...@@ -607,6 +610,23 @@ class EditorWindow:
except TclError: except TclError:
return None, None 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:
pixels = text.tk.call("font", "measure", text["font"],
"-displayof", text.master,
"n" * newtabwith)
text.configure(tabs=pixels)
def prepstr(s): def prepstr(s):
# Helper to extract the underscore from a string, e.g. # Helper to extract the underscore from a string, e.g.
# prepstr("Co_py") returns (2, "Copy"). # prepstr("Co_py") returns (2, "Copy").
......
...@@ -38,7 +38,7 @@ class FormatParagraph: ...@@ -38,7 +38,7 @@ class FormatParagraph:
def format_paragraph_event(self, event): def format_paragraph_event(self, event):
text = self.editwin.text text = self.editwin.text
first, last = self.editwin.get_selection_index() first, last = self.editwin.get_selection_indices()
if first and last: if first and last:
data = text.get(first, last) data = text.get(first, last)
comment_header = '' comment_header = ''
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment