refactors

--HG--
branch : pmacs2
This commit is contained in:
moculus 2008-11-08 15:30:04 +00:00
parent 4b36c23942
commit ad71553553
27 changed files with 197 additions and 192 deletions

View File

@ -8,37 +8,11 @@ import bufferlist, color, completer, keyinput, method, minibuffer, mode
import util, window import util, window
from point import Point from point import Point
def run(buffers, jump_to_line=None, init_mode=None):
# save terminal state so we can restore it when the program exits
attr = termios.tcgetattr(sys.stdin)
keyinput.disable_control_chars()
retval = 1
try:
retval = curses.wrapper(run_app, buffers, jump_to_line, init_mode)
except:
traceback.print_exc()
# restore terminal state
termios.tcsetattr(sys.stdin, termios.TCSANOW, attr)
return retval
def run_app(stdscr, buffers, jump_to_line=None, init_mode=None):
curses.def_shell_mode()
a = Application(stdscr, buffers, jump_to_line, init_mode)
a.run()
MAX_ERROR_DISPLAY = 128
KILL_RING_LIMIT = 128
WORD_LETTERS = list(string.letters + string.digits)
ERROR_TIMEOUT = -1
#ERROR_TIMEOUT = 2
class Application(object): class Application(object):
def __init__(self, stdscr, buffers=[], jump_to_line=None, init_mode=None): def __init__(self, stdscr, buffers=[], jump_to_line=None, init_mode=None):
# initalize curses primitives # initalize curses primitives
self.stdscr = stdscr self.stdscr = stdscr
(self.y, self.x) = self.stdscr.getmaxyx() self.y, self.x = self.stdscr.getmaxyx()
# initialize some basic stuff # initialize some basic stuff
# a highlighted_range contains three things: (window, start_p, end_p) # a highlighted_range contains three things: (window, start_p, end_p)
@ -51,7 +25,15 @@ class Application(object):
self.mini_prompt = "" self.mini_prompt = ""
self.error_string = "" self.error_string = ""
self.error_timestamp = None self.error_timestamp = None
self.need_draw = True
self.input = keyinput.Handler() self.input = keyinput.Handler()
# some constants
self.error_timeout = -1
self.max_error_len = 192
self.max_num_kills = 64
self.def_word_letters = string.letters + string.digits
# let's prepopulate some default token colors # let's prepopulate some default token colors
self.token_colors = { self.token_colors = {
'comment': ('red', 'default', 'bold'), 'comment': ('red', 'default', 'bold'),
@ -544,7 +526,8 @@ class Application(object):
self.kill_ring[-1] = self.kill_ring[-1] + s self.kill_ring[-1] = self.kill_ring[-1] + s
else: else:
self.kill_ring.append(s) self.kill_ring.append(s)
if KILL_RING_LIMIT and len(self.kill_ring) > KILL_RING_LIMIT: #if KILL_RING_LIMIT and len(self.kill_ring) > KILL_RING_LIMIT:
if self.max_num_kills and len(self.kill_ring) > self.max_num_kills:
self.kill_ring.pop(0) self.kill_ring.pop(0)
def pop_kill(self): def pop_kill(self):
return self.kill_ring.pop(-1) return self.kill_ring.pop(-1)
@ -605,16 +588,22 @@ class Application(object):
while i == curses.KEY_RESIZE: while i == curses.KEY_RESIZE:
i = self.win.getch() i = self.win.getch()
self.resize_event() self.resize_event()
self.need_draw = True
err = '' err = ''
try: try:
self.input.parse(i) self.input.parse(i)
except Exception, e: except Exception, e:
err = str(e) err = str(e)
while len(self.input.tokens):
if self.input.tokens:
self.need_draw = True
while self.input.tokens:
t = self.input.tokens.pop(0) t = self.input.tokens.pop(0)
self.active_window().mode.handle_token(t) self.active_window().mode.handle_token(t)
self.draw(err) if self.need_draw:
self.draw(err)
self.need_draw = False
# clear the error line; it might look confusing to the user # clear the error line; it might look confusing to the user
try: try:
@ -667,8 +656,8 @@ class Application(object):
self.resize_event() self.resize_event()
if err: if err:
self.set_error(err) self.set_error(err)
if self.error_timestamp is not None and ERROR_TIMEOUT > 0 and \ if self.error_timestamp is not None and self.error_timeout > 0 and \
time.time() - self.error_timestamp > ERROR_TIMEOUT: time.time() - self.error_timestamp > self.error_timeout:
self.clear_error() self.clear_error()
(y, x) = self.stdscr.getmaxyx() (y, x) = self.stdscr.getmaxyx()
if y != self.y or x != self.x: if y != self.y or x != self.x:
@ -861,10 +850,10 @@ class Application(object):
def get_minibuffer_lines(self): def get_minibuffer_lines(self):
lines, lines2 = [], [] lines, lines2 = [], []
if self.error_string: if self.error_string:
if len(self.error_string) < MAX_ERROR_DISPLAY: if len(self.error_string) < self.max_error_len:
s = self.error_string s = self.error_string
else: else:
s = self.error_string[:MAX_ERROR_DISPLAY] + '...' s = self.error_string[:self.max_error_len] + '...'
elif self.mini_buffer_is_open(): elif self.mini_buffer_is_open():
s = self.mini_prompt + self.mini_buffer.lines[0] s = self.mini_prompt + self.mini_buffer.lines[0]
lines2 = self.mini_buffer.lines[1:] lines2 = self.mini_buffer.lines[1:]
@ -895,6 +884,11 @@ def open_plain_file(path, name=None, binary=False):
else: else:
raise Exception, "can't open %r; unsupported file type" % path raise Exception, "can't open %r; unsupported file type" % path
def run_app(stdscr, buffers, jump_to_line=None, init_mode=None):
curses.def_shell_mode()
a = Application(stdscr, buffers, jump_to_line, init_mode)
a.run()
if __name__ == "__main__": if __name__ == "__main__":
ciphers = { ciphers = {
'none': open_plain_file, 'none': open_plain_file,
@ -986,5 +980,17 @@ if __name__ == "__main__":
paths.add(path) paths.add(path)
names.add(name) names.add(name)
# save terminal state so we can restore it when the program exits
attr = termios.tcgetattr(sys.stdin)
keyinput.disable_control_chars()
# ok, now run our app # ok, now run our app
run(buffers, opts.goto, opts.mode) retval = 1
try:
retval = curses.wrapper(run_app, buffers, opts.goto, opts.mode)
except:
traceback.print_exc()
# restore terminal state
termios.tcsetattr(sys.stdin, termios.TCSANOW, attr)
sys.exit(retval)

View File

@ -1,4 +1,4 @@
import codecs, datetime, grp, md5, os, pwd, re, sets, shutil, stat, string import codecs, datetime, grp, md5, os, pwd, re, shutil, stat, string
import fcntl, select, pty, threading import fcntl, select, pty, threading
import aes, dirutil, regex, highlight, lex, term import aes, dirutil, regex, highlight, lex, term
from point import Point from point import Point

View File

@ -10,9 +10,10 @@ class XTermBuffer(Buffer, XTerm):
modename = 'pipe' modename = 'pipe'
termtype = 'xterm' termtype = 'xterm'
#termtype = 'vt100' #termtype = 'vt100'
def __init__(self, cmd, args, name=None): def __init__(self, app, cmd, args, name=None):
XTerm.__init__(self) XTerm.__init__(self)
Buffer.__init__(self) Buffer.__init__(self)
self.application = app
self._name = name or '*XTerm*' self._name = name or '*XTerm*'
self._pid, self._pty = pty.fork() self._pid, self._pty = pty.fork()
if self._pid == 0: if self._pid == 0:
@ -102,6 +103,7 @@ class XTermBuffer(Buffer, XTerm):
if ifd: if ifd:
data = os.read(ifd[0], 1024) data = os.read(ifd[0], 1024)
self.term_receive(data) self.term_receive(data)
self.application.need_draw = True
if ofd: if ofd:
self._lock.acquire() self._lock.acquire()
n = os.write(ofd[0], self._towrite) n = os.write(ofd[0], self._towrite)

View File

@ -1,4 +1,4 @@
import glob, os, pwd, sets import glob, os, pwd
import method, util import method, util
def find_common_string(candidates): def find_common_string(candidates):
@ -78,7 +78,7 @@ class CommandCompleter(Completer):
def get_candidates(self, s, w=None): def get_candidates(self, s, w=None):
path = os.getenv('PATH') path = os.getenv('PATH')
path_dirs = path.split(':') path_dirs = path.split(':')
candidates = sets.Set() candidates = set()
for d in path_dirs: for d in path_dirs:
if (not os.path.isdir(d) or not os.access(d, os.R_OK)): if (not os.path.isdir(d) or not os.access(d, os.R_OK)):
continue continue

View File

@ -1,4 +1,4 @@
import os, commands, re, sets, tempfile import os, commands, re, tempfile
from subprocess import Popen, PIPE, STDOUT from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, regex, util, window import buffer, default, dirutil, regex, util, window
@ -216,7 +216,9 @@ class KillRegion(Method):
class Copy(Method): class Copy(Method):
'''Copy the contents of the current line''' '''Copy the contents of the current line'''
def _execute(self, w, **vargs): def _execute(self, w, **vargs):
w.copy_line() result = w.copy_line()
if result is None:
w.set_error("Empty kill region")
class CopyRegion(Method): class CopyRegion(Method):
'''Copy the region between the mark and the cursor''' '''Copy the region between the mark and the cursor'''
def _execute(self, w, **vargs): def _execute(self, w, **vargs):
@ -1017,23 +1019,3 @@ class SetModeTabWidth(Method):
return return
app.modes[mode].tabwidth = vargs['width'] app.modes[mode].tabwidth = vargs['width']
w.set_error('Default tab width set to %d' % app.modes[mode].tabwidth) w.set_error('Default tab width set to %d' % app.modes[mode].tabwidth)
#class HideRange(Method):
# def _execute(self, w, **vargs):
# cursor = w.logical_cursor()
# if cursor.y < w.mark.y:
# y1, y2 = cursor.y, w.mark.y
# elif w.mark.y < cursor.y:
# y1, y2 = w.mark.y, cursor.y
# else:
# w.set_error("No line range selected")
# w.hide(y1, y2)
# w.set_error("Lines %d through %d hidden" % (y1, y2))
#class UnhideLine(Method):
# def _execute(self, w, **vargs):
# cursor = w.logical_cursor()
# if w.ishidden(cursor.y):
# w.unhide(cursor.y)
# w.set_error("Line %d is no longer hidden" % cursor.y)
# else:
# w.set_error("Line %d is not hidden" % cursor.y)

View File

@ -1,4 +1,4 @@
import os, commands, re, sets, tempfile import os, commands, re, tempfile
from subprocess import Popen, PIPE, STDOUT from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, regex, util, window import buffer, default, dirutil, regex, util, window

View File

@ -1,4 +1,4 @@
import os, commands, re, sets, tempfile import os, commands, re, tempfile
from subprocess import Popen, PIPE, STDOUT from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, lex, regex, util, window import buffer, default, dirutil, lex, regex, util, window

View File

@ -1,4 +1,4 @@
import os, commands, re, sets, tempfile import os, commands, re, tempfile
from subprocess import Popen, PIPE, STDOUT from subprocess import Popen, PIPE, STDOUT
import buffer, buffer.about import buffer, buffer.about

View File

@ -1,4 +1,4 @@
import os, commands, re, sets, tempfile import os, commands, re, tempfile
from subprocess import Popen, PIPE, STDOUT from subprocess import Popen, PIPE, STDOUT
import buffer, buffer.console import buffer, buffer.console

View File

@ -1,4 +1,4 @@
import os, commands, re, sets, tempfile import os, commands, re, tempfile
from subprocess import Popen, PIPE, STDOUT from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, regex, util, window import buffer, default, dirutil, regex, util, window

View File

@ -1,4 +1,4 @@
import os, commands, re, sets, tempfile import os, commands, re, tempfile
from subprocess import Popen, PIPE, STDOUT from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, regex, util, window import buffer, default, dirutil, regex, util, window

View File

@ -1,4 +1,4 @@
import os, commands, re, sets, tempfile import os, commands, re, tempfile
from subprocess import Popen, PIPE, STDOUT from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, regex, term, util, window import buffer, default, dirutil, regex, term, util, window

View File

@ -1,4 +1,4 @@
import os, commands, re, sets, tempfile import os, commands, re, tempfile
from subprocess import Popen, PIPE, STDOUT from subprocess import Popen, PIPE, STDOUT
import buffer, default, dirutil, lex, regex, util, window import buffer, default, dirutil, lex, regex, util, window

View File

@ -1,4 +1,4 @@
import math, os, sets, string import math, os, string
import color, method import color, method
from lex import Lexer from lex import Lexer
from point import Point from point import Point
@ -75,19 +75,20 @@ class Handler(object):
class Fundamental(Handler): class Fundamental(Handler):
'''This is the default mode''' '''This is the default mode'''
modename = "Fundamental" modename = "Fundamental"
paths = [] paths = []
basenames = [] basenames = []
extensions = [] extensions = []
detection = [] detection = []
savetabs = False savetabs = False
tabwidth = 4 tabwidth = 4
tabbercls = None tabbercls = None
grammar = None grammar = None
lexer = None lexer = None
tabber = None tabber = None
context = None context = None
colors = {} colors = {}
word_letters = None
# config settings installed/modified by the mode # config settings installed/modified by the mode
config = {} config = {}
@ -124,7 +125,7 @@ class Fundamental(Handler):
for val2 in val: for val2 in val:
app.config[key].append(val2) app.config[key].append(val2)
for (key, val) in cls.sconfig.iteritems(): for (key, val) in cls.sconfig.iteritems():
app.config.setdefault(key, sets.Set()) app.config.setdefault(key, set())
app.config[key].add(val) app.config[key].add(val)
for (key, d) in cls.dconfig.iteritems(): for (key, d) in cls.dconfig.iteritems():
app.config.setdefault(key, {}) app.config.setdefault(key, {})
@ -231,6 +232,10 @@ class Fundamental(Handler):
self.add_bindings('insert-text2', ('C-c M-i',)) self.add_bindings('insert-text2', ('C-c M-i',))
self.add_bindings('insert-multiline-text', ('C-c m',)) self.add_bindings('insert-multiline-text', ('C-c m',))
# used for all word operations
if not self.word_letters:
self.word_letters = w.application.def_word_letters
# create all the insert actions for the basic text input # create all the insert actions for the basic text input
for c in string.letters + string.digits + string.punctuation: for c in string.letters + string.digits + string.punctuation:
self.add_binding('insert-string-%s' % c, c) self.add_binding('insert-string-%s' % c, c)
@ -259,8 +264,6 @@ class Fundamental(Handler):
c, fg, bg = " ", "red", "default" c, fg, bg = " ", "red", "default"
if cont: if cont:
c = "\\" c = "\\"
if w.hiddenindicator(y):
bg = "green"
return [RenderString(s=c, attrs=color.build(fg, bg))] return [RenderString(s=c, attrs=color.build(fg, bg))]
def get_lmargin(self, w, y, x, ended=False, cont=False): def get_lmargin(self, w, y, x, ended=False, cont=False):
lm = self.lmargin lm = self.lmargin
@ -342,10 +345,10 @@ class Fundamental(Handler):
self.window.application.last_action = act.name self.window.application.last_action = act.name
except ActionError, e: except ActionError, e:
#XYZ: HACK--should fix #XYZ: HACK--should fix
if t not in ('C-]', 'C-g'): if t in ('C-]', 'C-g'):
self.window.set_error(str(e))
else:
self.window.set_error('Cancelled') self.window.set_error('Cancelled')
else:
self.window.set_error(str(e))
except Exception, e: except Exception, e:
if DEBUG: if DEBUG:
raise raise

View File

@ -1,4 +1,4 @@
import re, sets, string import re, string
import color, method, minibuffer, mode, searchutil import color, method, minibuffer, mode, searchutil
from point import Point from point import Point

View File

@ -1,4 +1,4 @@
import commands, os.path, sets, string, sys, traceback import commands, os.path, string, sys, traceback
import color, completer, default, mode, method, regex, tab import color, completer, default, mode, method, regex, tab
from point import Point from point import Point
from lex import Grammar, PatternRule, RegionRule, OverridePatternRule from lex import Grammar, PatternRule, RegionRule, OverridePatternRule

View File

@ -1,4 +1,4 @@
import commands, os.path, sets, string, sys, traceback import commands, os.path, string, sys, traceback
import color, completer, default, mode, method, regex, tab import color, completer, default, mode, method, regex, tab
from point import Point from point import Point
from lex import Grammar, PatternRule, RegionRule, OverridePatternRule, NocasePatternRule from lex import Grammar, PatternRule, RegionRule, OverridePatternRule, NocasePatternRule

View File

@ -1,4 +1,4 @@
import commands, os.path, sets, string, sys, traceback import commands, os.path, string, sys, traceback
import color, completer, default, mode, method, regex, tab import color, completer, default, mode, method, regex, tab
from point import Point from point import Point
from lex import Grammar, PatternRule, RegionRule, OverridePatternRule, NocasePatternRule from lex import Grammar, PatternRule, RegionRule, OverridePatternRule, NocasePatternRule

View File

@ -1,4 +1,4 @@
import commands, os.path, sets, string, sys, traceback import commands, os.path, string, sys, traceback
import color, completer, default, mode, method, regex, tab import color, completer, default, mode, method, regex, tab
from point import Point from point import Point
from lex import Grammar, PatternRule, RegionRule, OverridePatternRule from lex import Grammar, PatternRule, RegionRule, OverridePatternRule

View File

@ -1,4 +1,4 @@
import commands, os.path, sets, string, sys, traceback import commands, os.path, string, sys, traceback
import color, completer, default, mode, method, regex, tab import color, completer, default, mode, method, regex, tab
from point import Point from point import Point
from lex import Grammar, PatternRule, RegionRule, NocasePatternRule from lex import Grammar, PatternRule, RegionRule, NocasePatternRule

View File

@ -1,4 +1,4 @@
import os, re, sets, string, sys import os, re, string, sys
import buffer, color, commands, completer, context, default, method, mode, regex, tab import buffer, color, commands, completer, context, default, method, mode, regex, tab
from point import Point from point import Point
from lex import Grammar, PatternRule, ContextPatternRule, RegionRule, \ from lex import Grammar, PatternRule, ContextPatternRule, RegionRule, \

View File

@ -1,4 +1,4 @@
import commands, os.path, sets, string, sys, traceback import commands, os.path, string, sys, traceback
import color, completer, context, default, mode, method, regex, tab, method.introspect import color, completer, context, default, mode, method, regex, tab, method.introspect
from point import Point from point import Point
from lex import Grammar, PatternRule, RegionRule, OverridePatternRule from lex import Grammar, PatternRule, RegionRule, OverridePatternRule

View File

@ -1,4 +1,4 @@
import re, sets, string import re, string
import color, method, minibuffer, mode, searchutil import color, method, minibuffer, mode, searchutil
from point import Point from point import Point

View File

@ -1,4 +1,4 @@
import commands, os.path, sets, string, sys, traceback import commands, os.path, string, sys, traceback
import color, completer, default, mode, method, regex, tab import color, completer, default, mode, method, regex, tab
from point import Point from point import Point
from lex import Grammar, PatternRule, RegionRule, OverridePatternRule from lex import Grammar, PatternRule, RegionRule, OverridePatternRule

View File

@ -1,4 +1,4 @@
import re, sets, string import re, string
import color, method, minibuffer, mode, searchutil import color, method, minibuffer, mode, searchutil
from point import Point from point import Point

View File

@ -123,7 +123,7 @@ class OpenShell(Method):
a = w.application a = w.application
if not a.has_buffer_name('*Shell*'): if not a.has_buffer_name('*Shell*'):
#b = buffer.pipe.PipeBuffer('/bin/bash', [], name="*Shell*", term='xterm') #b = buffer.pipe.PipeBuffer('/bin/bash', [], name="*Shell*", term='xterm')
b = buffer.emul.XTermBuffer('/bin/bash', [], name="*Shell*") b = buffer.emul.XTermBuffer(a, '/bin/bash', [], name="*Shell*")
a.add_buffer(b) a.add_buffer(b)
window.Window(b, a) window.Window(b, a)
b = a.bufferlist.get_buffer_by_name('*Shell*') b = a.bufferlist.get_buffer_by_name('*Shell*')

194
window.py
View File

@ -3,8 +3,6 @@ import color, highlight, regex
from point import Point from point import Point
from render import RenderString from render import RenderString
WORD_LETTERS = list(string.letters + string.digits)
# note about the cursor: the cursor position will insert in front of the # note about the cursor: the cursor position will insert in front of the
# character it highlights. to this end, it needs to be able to highlight behind # character it highlights. to this end, it needs to be able to highlight behind
# the last character on a line. thus, the x coordinate of the (logical) cursor # the last character on a line. thus, the x coordinate of the (logical) cursor
@ -22,19 +20,16 @@ class Window(object):
margins = ((80, 'blue'),) margins = ((80, 'blue'),)
margins_visible = False margins_visible = False
def __init__(self, b, a, height=24, width=80, mode_name=None): def __init__(self, b, a, height=24, width=80, mode_name=None):
self.buffer = b self.buffer = b
self.application = a self.application = a
self.height = height self.height = height
self.width = width self.width = width
self.first = Point(0, 0)
self.first = Point(0, 0) self.last = None
self.last = None self.cursor = Point(0, 0)
self.cursor = Point(0, 0) self.mark = None
self.mark = None self.active_point = None
self.active_point = None self.input_line = ""
self.input_line = ""
self.hidden_ranges = {}
self.hidden_lines = {}
if mode_name is not None: if mode_name is not None:
pass pass
@ -311,14 +306,14 @@ class Window(object):
x = len(self.buffer.lines[y]) x = len(self.buffer.lines[y])
else: else:
x -= 1 x -= 1
while (y, x) >= start and self.xy_char(x, y) not in WORD_LETTERS: while (y, x) >= start and self.xy_char(x, y) not in self.mode.word_letters:
if x == 0: if x == 0:
y -= 1 y -= 1
x = len(self.buffer.lines[y]) x = len(self.buffer.lines[y])
else: else:
x -= 1 x -= 1
found_word = False found_word = False
while (y, x) >= start and self.xy_char(x, y) in WORD_LETTERS: while (y, x) >= start and self.xy_char(x, y) in self.mode.word_letters:
found_word = True found_word = True
if x == 0: if x == 0:
y -= 1 y -= 1
@ -339,13 +334,13 @@ class Window(object):
else: else:
(x, y) = p.xy() (x, y) = p.xy()
end = self.buffer.get_buffer_end() end = self.buffer.get_buffer_end()
while (y, x) < end and self.xy_char(x, y) not in WORD_LETTERS: while (y, x) < end and self.xy_char(x, y) not in self.mode.word_letters:
if x == len(self.buffer.lines[y]): if x == len(self.buffer.lines[y]):
x = 0 x = 0
y += 1 y += 1
else: else:
x += 1 x += 1
while (y, x) < end and self.xy_char(x, y) in WORD_LETTERS: while (y, x) < end and self.xy_char(x, y) in self.mode.word_letters:
if x == len(self.buffer.lines[y]): if x == len(self.buffer.lines[y]):
x = 0 x = 0
y += 1 y += 1
@ -360,27 +355,27 @@ class Window(object):
p = self.find_right_word() p = self.find_right_word()
if p is not None: if p is not None:
self.goto(p) self.goto(p)
def get_word_bounds_at_point(self, p, wl=WORD_LETTERS): def get_word_bounds_at_point(self, p):
if len(self.buffer.lines[p.y]) == 0: if len(self.buffer.lines[p.y]) == 0:
return None return None
elif self.cursor_char() not in wl: elif self.cursor_char() not in wl:
return None return None
x1 = x2 = p.x x1 = x2 = p.x
while x1 > 0 and self.xy_char(x1 - 1, p.y) in wl: while x1 > 0 and self.xy_char(x1 - 1, p.y) in self.mode.word_letters:
x1 -= 1 x1 -= 1
while x2 < len(self.buffer.lines[p.y]) and self.xy_char(x2, p.y) in wl: while x2 < len(self.buffer.lines[p.y]) and self.xy_char(x2, p.y) in wl:
x2 += 1 x2 += 1
return (Point(x1, p.y), Point(x2, p.y)) return (Point(x1, p.y), Point(x2, p.y))
def get_word_at_point(self, p, wl=WORD_LETTERS): def get_word_at_point(self, p):
bounds = self.get_word_bounds_at_point(p, wl) bounds = self.get_word_bounds_at_point(p)
if bounds is None: if bounds is None:
return None return None
else: else:
return self.buffer.get_substring(bounds[0], bounds[1]) return self.buffer.get_substring(bounds[0], bounds[1])
def get_word_bounds(self, wl=WORD_LETTERS): def get_word_bounds(self):
return self.get_word_bounds_at_point(self.logical_cursor(), wl) return self.get_word_bounds_at_point(self.logical_cursor())
def get_word(self, wl=WORD_LETTERS): def get_word(self):
return self.get_word_at_point(self.logical_cursor(), wl) return self.get_word_at_point(self.logical_cursor())
# page up/down # page up/down
def _pshift_up(self, p, num): def _pshift_up(self, p, num):
@ -496,69 +491,111 @@ class Window(object):
self.set_mark_point(self.logical_cursor()) self.set_mark_point(self.logical_cursor())
self.goto(p) self.goto(p)
# deletion # finding (used by deletion, killing, and copying)
def left_delete(self): def get_line(self):
self.buffer.left_delete(self.logical_cursor()) (x, y) = self.logical_cursor().xy()
def right_delete(self): lines = self.buffer.lines
self.buffer.right_delete(self.logical_cursor()) if y < len(lines) - 1:
def delete(self, p1, p2): return (Point(0, y), Point(0, y + 1))
self.buffer.delete(p1, p2) elif y > 0:
return (Point(len(lines[y - 1]), y - 1), Point(len(lines[y]), y))
# killing else:
def kill_line(self): return (None, None)
return self.copy_line(kill=True) def get_line_left(self):
def kill_region(self): cursor = self.logical_cursor()
return self.copy_region(kill=True) (x, y) = cursor.xy()
def kill_left_word(self): lines = self.buffer.lines
p1 = self.find_left_word() if (x > 0) and not regex.whitespace.match(lines[y][:x]):
p2 = self.logical_cursor() return (Point(0, y), cursor)
if p1 == p2: elif y > 0:
return return (Point(len(lines[y - 1]), y - 1), cursor)
return self.kill(p1, p2) else:
def kill_right_word(self): return (None, None)
p1 = self.logical_cursor() def get_line_right(self):
p2 = self.find_right_word()
if p1 == p2:
return
return self.kill(p1, p2)
def copy_line(self, kill=False):
cursor = self.logical_cursor() cursor = self.logical_cursor()
(x, y) = cursor.xy() (x, y) = cursor.xy()
lines = self.buffer.lines lines = self.buffer.lines
if (x < len(lines[y]) and not regex.whitespace.match(lines[y][x:])): if (x < len(lines[y]) and not regex.whitespace.match(lines[y][x:])):
limit = Point(len(lines[y]), y) return (cursor, Point(len(lines[y]), y))
elif y < len(lines) - 1: elif y < len(lines) - 1:
limit = Point(0, y + 1) return (cursor, Point(0, y + 1))
else: else:
return return (None, None)
if kill: def get_region(self):
return self.kill(cursor, limit)
else:
return self.copy(cursor, limit)
def copy_region(self, kill=False):
cursor = self.logical_cursor() cursor = self.logical_cursor()
p1, p2 = None, None
if cursor < self.mark: if cursor < self.mark:
p1 = cursor p1 = cursor
p2 = self.mark p2 = self.mark
elif self.mark < cursor: elif self.mark < cursor:
p1 = self.mark p1 = self.mark
p2 = cursor p2 = cursor
return (p1, p2)
def get_left_word(self):
p1 = self.find_left_word()
p2 = self.logical_cursor()
if p1 == p2:
return (None, None)
else: else:
self.input_line = "Empty kill region" return (p1, p2)
return def get_right_word(self):
if kill: p1 = self.logical_cursor()
return self.kill(p1, p2) p2 = self.find_right_word()
if p1 == p2:
return (None, None)
else: else:
return self.copy(p1, p2) return (p1, p2)
# deletion
def delete(self, p1, p2):
self.buffer.delete(p1, p2)
def delete_line(self):
(p1, p2) = self.get_line_right()
if p1 is not None: self.delete(p1, p2)
def delete_region(self):
(p1, p2) = self.get_region()
if p1 is not None: self.delete(p1, p2)
def delete_left_word(self):
(p1, p2) = self.get_left_word()
if p1 is not None: self.delete(p1, p2)
def delete_right_word(self):
(p1, p2) = self.get_right_word()
if p1 is not None: self.delete(p1, p2)
def left_delete(self):
self.buffer.left_delete(self.logical_cursor())
def right_delete(self):
self.buffer.right_delete(self.logical_cursor())
# killing
def kill(self, p1, p2): def kill(self, p1, p2):
killed = self.buffer.get_substring(p1, p2) killed = self.buffer.get_substring(p1, p2)
self.buffer.delete(p1, p2) self.buffer.delete(p1, p2)
self.application.push_kill(killed) self.application.push_kill(killed)
return killed return killed
def kill_line(self):
(p1, p2) = self.get_line_right()
if p1 is not None: self.kill(p1, p2)
def kill_region(self):
(p1, p2) = self.get_region()
if p1 is not None: self.kill(p1, p2)
def kill_left_word(self):
(p1, p2) = self.get_left_word()
if p1 is not None: self.kill(p1, p2)
def kill_right_word(self):
(p1, p2) = self.get_right_word()
if p1 is not None: self.kill(p1, p2)
# copying
def copy(self, p1, p2): def copy(self, p1, p2):
copied = self.buffer.get_substring(p1, p2) copied = self.buffer.get_substring(p1, p2)
self.application.push_kill(copied) self.application.push_kill(copied)
return copied return copied
def copy_line(self):
(p1, p2) = self.get_line_right()
if p1 is not None: return self.copy(p1, p2)
def copy_region(self, kill=False):
(p1, p2) = self.get_region()
if p1 is not None: return self.copy(p1, p2)
# overwriting # overwriting
def overwrite_char_at_cursor(self, c): def overwrite_char_at_cursor(self, c):
@ -610,31 +647,6 @@ class Window(object):
else: else:
return self.buffer.lines[y][x] return self.buffer.lines[y][x]
# hiding stuff
def hide(self, y1, y2):
if y2 == 0:
return
for (py1, py2) in self.hidden_ranges.itervalues():
if ((y1 >= py1 and y1 < py2) or
(y2 >= py1 and y2 < py2) or
(y1 <= py1 and y2 >= py2)):
return
for i in range(y1, y2):
self.hidden_lines[i] = y2
self.hidden_ranges[y2] = (y1, y2)
def ishidden(self, y):
return self.hidden_lines.setdefault(y, False)
def hiddenindicator(self, y):
return y in self.hidden_ranges
def unhide(self, y):
py2 = self.ishidden(y)
if not py2:
return
py1 = self.hidden_ranges[py2][0]
del self.hidden_ranges[py2]
for i in range(py1, py2):
self.hidden_lines[i] = False
# undo/redo # undo/redo
def undo(self): def undo(self):
p = self.buffer.undo() p = self.buffer.undo()