Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 1 | import string |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 2 | from Tkinter import TclError |
| 3 | |
| 4 | ###$ event <<newline-and-indent>> |
| 5 | ###$ win <Key-Return> |
| 6 | ###$ win <KP_Enter> |
| 7 | ###$ unix <Key-Return> |
| 8 | ###$ unix <KP_Enter> |
| 9 | |
| 10 | ###$ event <<indent-region>> |
| 11 | ###$ win <Control-bracketright> |
| 12 | ###$ unix <Alt-bracketright> |
| 13 | ###$ unix <Control-bracketright> |
| 14 | |
| 15 | ###$ event <<dedent-region>> |
| 16 | ###$ win <Control-bracketleft> |
| 17 | ###$ unix <Alt-bracketleft> |
| 18 | ###$ unix <Control-bracketleft> |
| 19 | |
| 20 | ###$ event <<comment-region>> |
| 21 | ###$ win <Alt-Key-3> |
| 22 | ###$ unix <Alt-Key-3> |
| 23 | |
| 24 | ###$ event <<uncomment-region>> |
| 25 | ###$ win <Alt-Key-4> |
| 26 | ###$ unix <Alt-Key-4> |
| 27 | |
| 28 | ###$ event <<tabify-region>> |
| 29 | ###$ win <Alt-Key-5> |
| 30 | ###$ unix <Alt-Key-5> |
| 31 | |
| 32 | ###$ event <<untabify-region>> |
| 33 | ###$ win <Alt-Key-6> |
| 34 | ###$ unix <Alt-Key-6> |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 35 | |
| 36 | class AutoIndent: |
| 37 | |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 38 | menudefs = [ |
| 39 | ('edit', [ |
| 40 | None, |
| 41 | ('_Indent region', '<<indent-region>>'), |
| 42 | ('_Dedent region', '<<dedent-region>>'), |
| 43 | ('Comment _out region', '<<comment-region>>'), |
| 44 | ('U_ncomment region', '<<uncomment-region>>'), |
| 45 | ('Tabify region', '<<tabify-region>>'), |
| 46 | ('Untabify region', '<<untabify-region>>'), |
| 47 | ]), |
| 48 | ] |
| 49 | |
Guido van Rossum | 33f2b7b | 1999-01-03 00:47:35 +0000 | [diff] [blame^] | 50 | keydefs = { |
| 51 | '<<smart-backspace>>': ['<Key-BackSpace>'], |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 52 | '<<newline-and-indent>>': ['<Key-Return>', '<KP_Enter>'], |
Guido van Rossum | 33f2b7b | 1999-01-03 00:47:35 +0000 | [diff] [blame^] | 53 | } |
| 54 | |
| 55 | windows_keydefs = { |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 56 | '<<indent-region>>': ['<Control-bracketright>'], |
| 57 | '<<dedent-region>>': ['<Control-bracketleft>'], |
| 58 | '<<comment-region>>': ['<Alt-Key-3>'], |
| 59 | '<<uncomment-region>>': ['<Alt-Key-4>'], |
| 60 | '<<tabify-region>>': ['<Alt-Key-5>'], |
| 61 | '<<untabify-region>>': ['<Alt-Key-6>'], |
| 62 | } |
| 63 | |
| 64 | unix_keydefs = { |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 65 | '<<indent-region>>': ['<Alt-bracketright>', |
| 66 | '<Meta-bracketright>', |
| 67 | '<Control-bracketright>'], |
| 68 | '<<dedent-region>>': ['<Alt-bracketleft>', |
| 69 | '<Meta-bracketleft>', |
| 70 | '<Control-bracketleft>'], |
| 71 | '<<comment-region>>': ['<Alt-Key-3>', '<Meta-Key-3>'], |
| 72 | '<<uncomment-region>>': ['<Alt-Key-4>', '<Meta-Key-4>'], |
| 73 | '<<tabify-region>>': ['<Alt-Key-5>', '<Meta-Key-5>'], |
| 74 | '<<untabify-region>>': ['<Alt-Key-6>', '<Meta-Key-6>'], |
| 75 | } |
| 76 | |
| 77 | prefertabs = 0 |
| 78 | spaceindent = 4*" " |
| 79 | |
| 80 | def __init__(self, editwin): |
| 81 | self.text = editwin.text |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 82 | |
| 83 | def config(self, **options): |
| 84 | for key, value in options.items(): |
| 85 | if key == 'prefertabs': |
| 86 | self.prefertabs = value |
| 87 | elif key == 'spaceindent': |
| 88 | self.spaceindent = value |
| 89 | else: |
| 90 | raise KeyError, "bad option name: %s" % `key` |
| 91 | |
Guido van Rossum | 33f2b7b | 1999-01-03 00:47:35 +0000 | [diff] [blame^] | 92 | def smart_backspace_event(self, event): |
| 93 | text = self.text |
| 94 | try: |
| 95 | first = text.index("sel.first") |
| 96 | last = text.index("sel.last") |
| 97 | except TclError: |
| 98 | first = last = None |
| 99 | if first and last: |
| 100 | text.delete(first, last) |
| 101 | text.mark_set("insert", first) |
| 102 | return "break" |
| 103 | # After Tim Peters |
| 104 | ndelete = 1 |
| 105 | chars = text.get("insert linestart", "insert") |
| 106 | i = 0 |
| 107 | n = len(chars) |
| 108 | while i < n and chars[i] in " \t": |
| 109 | i = i+1 |
| 110 | if i == n and chars[-4:] == " ": |
| 111 | ndelete = 4 |
| 112 | text.delete("insert - %d chars" % ndelete, "insert") |
| 113 | return "break" |
| 114 | |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 115 | def newline_and_indent_event(self, event): |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 116 | text = self.text |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 117 | try: |
| 118 | first = text.index("sel.first") |
| 119 | last = text.index("sel.last") |
| 120 | except TclError: |
| 121 | first = last = None |
| 122 | if first and last: |
| 123 | text.delete(first, last) |
| 124 | text.mark_set("insert", first) |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 125 | line = text.get("insert linestart", "insert") |
| 126 | i, n = 0, len(line) |
| 127 | while i < n and line[i] in " \t": |
| 128 | i = i+1 |
| 129 | indent = line[:i] |
| 130 | lastchar = text.get("insert -1c") |
| 131 | if lastchar == ":": |
| 132 | if not indent: |
| 133 | if self.prefertabs: |
| 134 | indent = "\t" |
| 135 | else: |
| 136 | indent = self.spaceindent |
| 137 | elif indent[-1] == "\t": |
| 138 | indent = indent + "\t" |
| 139 | else: |
| 140 | indent = indent + self.spaceindent |
| 141 | text.insert("insert", "\n" + indent) |
| 142 | text.see("insert") |
| 143 | return "break" |
| 144 | |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 145 | auto_indent = newline_and_indent_event |
| 146 | |
| 147 | def indent_region_event(self, event): |
| 148 | head, tail, chars, lines = self.get_region() |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 149 | for pos in range(len(lines)): |
| 150 | line = lines[pos] |
| 151 | if line: |
| 152 | i, n = 0, len(line) |
| 153 | while i < n and line[i] in " \t": |
| 154 | i = i+1 |
| 155 | line = line[:i] + " " + line[i:] |
| 156 | lines[pos] = line |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 157 | self.set_region(head, tail, chars, lines) |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 158 | return "break" |
| 159 | |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 160 | def dedent_region_event(self, event): |
| 161 | head, tail, chars, lines = self.get_region() |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 162 | for pos in range(len(lines)): |
| 163 | line = lines[pos] |
| 164 | if line: |
| 165 | i, n = 0, len(line) |
| 166 | while i < n and line[i] in " \t": |
| 167 | i = i+1 |
| 168 | indent, line = line[:i], line[i:] |
| 169 | if indent: |
| 170 | if indent == "\t" or indent[-2:] == "\t\t": |
| 171 | indent = indent[:-1] + " " |
| 172 | elif indent[-4:] == " ": |
| 173 | indent = indent[:-4] |
| 174 | else: |
| 175 | indent = string.expandtabs(indent, 8) |
| 176 | indent = indent[:-4] |
| 177 | line = indent + line |
| 178 | lines[pos] = line |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 179 | self.set_region(head, tail, chars, lines) |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 180 | return "break" |
| 181 | |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 182 | def comment_region_event(self, event): |
| 183 | head, tail, chars, lines = self.get_region() |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 184 | for pos in range(len(lines)): |
| 185 | line = lines[pos] |
| 186 | if not line: |
| 187 | continue |
| 188 | lines[pos] = '##' + line |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 189 | self.set_region(head, tail, chars, lines) |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 190 | |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 191 | def uncomment_region_event(self, event): |
| 192 | head, tail, chars, lines = self.get_region() |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 193 | for pos in range(len(lines)): |
| 194 | line = lines[pos] |
| 195 | if not line: |
| 196 | continue |
| 197 | if line[:2] == '##': |
| 198 | line = line[2:] |
| 199 | elif line[:1] == '#': |
| 200 | line = line[1:] |
| 201 | lines[pos] = line |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 202 | self.set_region(head, tail, chars, lines) |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 203 | |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 204 | def tabify_region_event(self, event): |
| 205 | head, tail, chars, lines = self.get_region() |
| 206 | lines = map(tabify, lines) |
| 207 | self.set_region(head, tail, chars, lines) |
| 208 | |
| 209 | def untabify_region_event(self, event): |
| 210 | head, tail, chars, lines = self.get_region() |
| 211 | lines = map(string.expandtabs, lines) |
| 212 | self.set_region(head, tail, chars, lines) |
| 213 | |
| 214 | def get_region(self): |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 215 | text = self.text |
| 216 | head = text.index("sel.first linestart") |
| 217 | tail = text.index("sel.last -1c lineend +1c") |
| 218 | if not (head and tail): |
| 219 | head = text.index("insert linestart") |
| 220 | tail = text.index("insert lineend +1c") |
| 221 | chars = text.get(head, tail) |
| 222 | lines = string.split(chars, "\n") |
| 223 | return head, tail, chars, lines |
| 224 | |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 225 | def set_region(self, head, tail, chars, lines): |
Guido van Rossum | 3b4ca0d | 1998-10-10 18:48:31 +0000 | [diff] [blame] | 226 | text = self.text |
| 227 | newchars = string.join(lines, "\n") |
| 228 | if newchars == chars: |
| 229 | text.bell() |
| 230 | return |
| 231 | text.tag_remove("sel", "1.0", "end") |
| 232 | text.mark_set("insert", head) |
| 233 | text.delete(head, tail) |
| 234 | text.insert(head, newchars) |
| 235 | text.tag_add("sel", head, "insert") |
Guido van Rossum | 504b0bf | 1999-01-02 21:28:54 +0000 | [diff] [blame] | 236 | |
| 237 | def tabify(line, tabsize=8): |
| 238 | spaces = tabsize * ' ' |
| 239 | for i in range(0, len(line), tabsize): |
| 240 | if line[i:i+tabsize] != spaces: |
| 241 | break |
| 242 | else: |
| 243 | i = len(line) |
| 244 | return '\t' * (i/tabsize) + line[i:] |