From e6dfc442a984bc50a70be5017f4ab9a0e6efadef Mon Sep 17 00:00:00 2001 From: hut Date: Wed, 2 Dec 2009 14:29:10 +0100 Subject: implemented a console (without commands) --- ranger/command.py | 6 +-- ranger/conf/keys.py | 75 +++++++++++++++++++++++++--------- ranger/conf/options.py | 12 +++--- ranger/fm.py | 22 +++++++--- ranger/gui/defaultui.py | 28 +++++++++---- ranger/gui/ui.py | 55 +++++++++++++------------ ranger/gui/wconsole.py | 105 ++++++++++++++++++++++++++++++++++++++++++++++++ ranger/gui/widget.py | 10 ++++- 8 files changed, 246 insertions(+), 67 deletions(-) create mode 100644 ranger/gui/wconsole.py diff --git a/ranger/command.py b/ranger/command.py index 203a0329..389f0df5 100644 --- a/ranger/command.py +++ b/ranger/command.py @@ -72,10 +72,10 @@ class CommandList(): class Command(): def __init__(self, fnc, keys): - self.fnc = fnc + self.execute = fnc self.keys = keys self.commandlist = None - def execute(self, fm): - self.fnc(fm) +# def execute(self, fm): +# self.fnc(fm) diff --git a/ranger/conf/keys.py b/ranger/conf/keys.py index f1349717..fef36b6e 100644 --- a/ranger/conf/keys.py +++ b/ranger/conf/keys.py @@ -10,39 +10,39 @@ def initialize_commands(cl): # * an integer which represents an ascii code # * a tuple of integers + def curry(fnc, *args, **keywords): + return lambda fm: fnc(fm, *args, **keywords) + def move(**keywords): return lambda fm: fm.move_pointer(**keywords) def move_pages(n): return lambda fm: fm.move_pointer_by_pages(n) + cl.bind(FM.move_left, 'h', curses.KEY_BACKSPACE, 127) + cl.bind(FM.move_right, 'l', curses.KEY_ENTER, ctrl('j')) + cl.bind(curry(FM.history_go, -1), 'H') + cl.bind(curry(FM.history_go, 1), 'L') + cl.bind(move( relative = 1 ), 'j') + cl.bind(move_pages( 0.5 ), 'J') + cl.bind(move( relative = -1 ), 'k') + cl.bind(move_pages( -0.5 ), 'K') + cl.bind(move( absolute = 0 ), 'gg') + cl.bind(move( absolute = -1 ), 'G') + cl.bind(FM.edit_file, 'E') + + # toggle options def toggle_option(string): return lambda fm: fm.toggle_boolean_option(string) - def cd(path): - return lambda fm: fm.enter_dir(path) - - def history(n): - return lambda fm: fm.history_go(n) - - cl.bind(FM.move_left, 'h', curses.KEY_BACKSPACE, 127) - cl.bind(FM.move_right, 'l', curses.KEY_ENTER, ctrl('j')) - cl.bind(history(-1), 'H') - cl.bind(history(1), 'L') - cl.bind(move( relative = 1 ), 'j') - cl.bind(move_pages( 0.5 ), 'J') - cl.bind(move( relative = -1 ), 'k') - cl.bind(move_pages( -0.5 ), 'K') - cl.bind(move( absolute = 0 ), 'gg') - cl.bind(move( absolute = -1 ), 'G') - cl.bind(FM.edit_file, 'E') - - # toggle options cl.bind(toggle_option('show_hidden'), 'th') cl.bind(toggle_option('preview_files'), 'tp') cl.bind(toggle_option('directories_first'), 'td') # key combinations which change the current directory + def cd(path): + return lambda fm: fm.enter_dir(path) + cl.bind(cd("~"), 'gh') cl.bind(cd("/etc"), 'ge') cl.bind(cd("/usr"), 'gu') @@ -56,8 +56,45 @@ def initialize_commands(cl): cl.bind(FM.exit, ctrl('D'), 'q', 'ZZ') cl.bind(FM.reset, ctrl('R')) cl.bind(FM.redraw, ctrl('L')) + cl.bind(FM.interrupt, ctrl('C')) cl.bind(FM.resize, curses.KEY_RESIZE) cl.bind(FM.handle_mouse, curses.KEY_MOUSE) + cl.bind(curry(FM.open_console, ':'), ':') cl.rebuild_paths() + +def initialize_console_commands(cl): + from ranger.fm import FM + from ranger.gui.wconsole import WConsole + from curses.ascii import ctrl, ESC + import curses + + def type_key(key): + return lambda con, fm: con.type_key(key) + + def curry(fnc, *args, **keywords): + return lambda con, fm: fnc(con, *args, **keywords) + + def curry_fm(fnc, *args, **keywords): + return lambda con, fm: fnc(fm, *args, **keywords) + + # movement + cl.bind(curry(WConsole.move, relative = -1), curses.KEY_LEFT, ctrl('b')) + cl.bind(curry(WConsole.move, relative = 1), curses.KEY_RIGHT, ctrl('f')) + cl.bind(curry(WConsole.move, absolute = 0), curses.KEY_HOME, ctrl('a')) + cl.bind(curry(WConsole.move, absolute = -1), curses.KEY_END, ctrl('e')) + cl.bind(curry(WConsole.delete, 0), curses.KEY_DC, ctrl('d')) + cl.bind(curry(WConsole.delete, -1), curses.KEY_BACKSPACE, 127, ctrl('h')) + cl.bind(curry(WConsole.delete_rest, -1), ctrl('U')) + cl.bind(curry(WConsole.delete_rest, 1), ctrl('K')) + + # system functions + cl.bind(curry(WConsole.close), ESC, ctrl('C')) + cl.bind(curry(WConsole.execute), curses.KEY_ENTER, ctrl('j')) + cl.bind(curry_fm(FM.redraw), ctrl('L')) + cl.bind(curry_fm(FM.resize), curses.KEY_RESIZE) + + for i in range(ord(' '), ord('~')): + cl.bind(type_key(i), i) + diff --git a/ranger/conf/options.py b/ranger/conf/options.py index e8baa60d..00d2f9f3 100644 --- a/ranger/conf/options.py +++ b/ranger/conf/options.py @@ -5,9 +5,9 @@ def get(): def dummy(): """ provide a way of getting options until get() is implemented """ return { - 'show_hidden': False, - 'scroll_offset': 2, - 'directories_first': True, - 'preview_files' : False, - 'max_history_size': 20 - } + 'show_hidden': False, + 'scroll_offset': 2, + 'directories_first': True, + 'preview_files' : False, + 'max_history_size': 20 + } diff --git a/ranger/fm.py b/ranger/fm.py index d314fea4..05c1e262 100644 --- a/ranger/fm.py +++ b/ranger/fm.py @@ -7,8 +7,6 @@ class FM(): self.ui = ui def run(self): - import time - self.env.enter_dir(self.env.path) while 1: @@ -17,10 +15,17 @@ class FM(): key = self.ui.get_next_key() self.ui.press(key, self) except KeyboardInterrupt: - self.env.key_clear() - time.sleep(0.2) + self.ui.press(3, self) except: raise + + def interrupt(self): + import time + self.env.key_clear() + try: + time.sleep(0.2) + except KeyboardInterrupt: + raise SystemExit() def resize(self): self.ui.resize() @@ -64,6 +69,10 @@ class FM(): self.ui.initialize() + def open_console(self, mode = ':'): + if self.ui.can('open_console'): + self.ui.open_console(mode) + def move_pointer(self, relative = 0, absolute = None): self.env.cf = self.env.pwd.move_pointer(relative, absolute) @@ -72,8 +81,9 @@ class FM(): relative = int(relative * self.env.termsize[0])) def scroll(self, relative): - self.ui.scroll(relative) - self.env.cf = self.env.pwd.pointed_file + if self.ui.can('scroll'): + self.ui.scroll(relative) + self.env.cf = self.env.pwd.pointed_file def redraw(self): self.ui.redraw() diff --git a/ranger/gui/defaultui.py b/ranger/gui/defaultui.py index d4d89047..547f20ff 100644 --- a/ranger/gui/defaultui.py +++ b/ranger/gui/defaultui.py @@ -1,11 +1,12 @@ -from ranger.gui.ui import UI as SuperClass -from ranger.gui.wdisplay import WDisplay -from ranger.gui.wtitlebar import WTitleBar RATIO = ( 0.15, 0.15, 0.4, 0.3 ) +from ranger.gui.ui import UI as SuperClass class DefaultUI(SuperClass): def setup(self): + from ranger.gui.wdisplay import WDisplay + from ranger.gui.wtitlebar import WTitleBar + from ranger.gui.wconsole import WConsole self.titlebar = WTitleBar(self.win, self.colorscheme) self.add_widget(self.titlebar) @@ -19,9 +20,9 @@ class DefaultUI(SuperClass): self.displays[2].main_display = True for disp in self.displays: self.add_widget(disp) - - def scroll(self, relative): - self.main_display.scroll(relative) + + self.console = WConsole(self.win, self.colorscheme) + self.add_widget(self.console) def resize(self): SuperClass.resize(self) @@ -33,11 +34,24 @@ class DefaultUI(SuperClass): for ratio in RATIO: wid = int(ratio * x) try: - self.displays[i].setdim(1, leftborder, y-1, wid - 1) + self.displays[i].setdim(1, leftborder, y-2, wid - 1) except KeyError: pass leftborder += wid i += 1 self.titlebar.setdim(0, 0, 1, x) + self.console.setdim(y-1, 0, 1, x) + + # ---specials--- + def open_console(self, mode): + if self.console.open(mode): + self.console.on_close = self.close_console + self.console.visible = True + + def close_console(self): + self.console.visible = False + + def scroll(self, relative): + self.main_display.scroll(relative) diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py index a04455ab..79077cbc 100644 --- a/ranger/gui/ui.py +++ b/ranger/gui/ui.py @@ -1,5 +1,22 @@ import curses +class MouseEvent(): + import curses + PRESSED = [ 0, + curses.BUTTON1_PRESSED, + curses.BUTTON2_PRESSED, + curses.BUTTON3_PRESSED, + curses.BUTTON4_PRESSED ] + + def __init__(self, getmouse): + _, self.x, self.y, _, self.bstate = getmouse + + def pressed(self, n): + try: + return (self.bstate & MouseEvent.PRESSED[n]) != 0 + except: + return False + class UI(): def __init__(self, env, commandlist, colorscheme): self.env = env @@ -15,7 +32,7 @@ class UI(): os.environ['ESCDELAY'] = '25' self.win = curses.initscr() - self.win.leaveok(1) + self.win.leaveok(0) self.win.keypad(1) curses.noecho() @@ -51,10 +68,10 @@ class UI(): else: fm.scroll(relative = 3) - def setup(self): - pass + def can(self, attr): + return hasattr(self, attr) - def scroll(self, relative): + def setup(self): pass def resize(self): @@ -74,8 +91,10 @@ class UI(): def press(self, key, fm): self.env.key_append(key) -# from ranger.helper import log -# log(self.env.keybuffer) + for widg in self.widgets: + if widg.focused: + widg.press(key, fm, self.env) + return try: cmd = self.commandlist.paths[self.env.keybuffer] @@ -98,28 +117,14 @@ class UI(): self.win.erase() for widg in self.widgets: widg.feed_env(self.env) - widg.draw() + if widg.visible: + widg.draw() + for widg in self.widgets: + if widg.visible: + widg.finalize() self.win.refresh() def get_next_key(self): key = self.win.getch() curses.flushinp() return key - - -class MouseEvent(): - import curses - PRESSED = [ 0, - curses.BUTTON1_PRESSED, - curses.BUTTON2_PRESSED, - curses.BUTTON3_PRESSED, - curses.BUTTON4_PRESSED ] - - def __init__(self, getmouse): - _, self.x, self.y, _, self.bstate = getmouse - - def pressed(self, n): - try: - return (self.bstate & MouseEvent.PRESSED[n]) != 0 - except: - return False diff --git a/ranger/gui/wconsole.py b/ranger/gui/wconsole.py new file mode 100644 index 00000000..4411e83b --- /dev/null +++ b/ranger/gui/wconsole.py @@ -0,0 +1,105 @@ +from ranger.gui.widget import Widget as SuperClass +import curses + +CONSOLE_MODES = tuple(':/?>!') + +class WConsole(SuperClass): + def __init__(self, win, colorscheme): + from ranger.command import CommandList + from ranger.conf.keys import initialize_console_commands + SuperClass.__init__(self, win, colorscheme) + self.mode = None + self.visible = False + self.commandlist = CommandList() + initialize_console_commands(self.commandlist) + self.last_cursor_mode = 1 + self.clear() + + def draw(self): + if self.mode is None: + return + + self.win.addstr(self.y, self.x, ":" + self.line) + + def finalize(self): + try: + self.win.move(self.y, self.x + self.pos + 1) + except: + pass + + def open(self, mode): + if mode not in CONSOLE_MODES: + return False + + self.last_cursor_mode = curses.curs_set(1) + self.mode = mode + self.focused = True + self.visible = True + return True + + def close(self): + curses.curs_set(self.last_cursor_mode) + self.focused = False + self.visible = False + if hasattr(self, 'on_close'): + self.on_close() + + def clear(self): + self.pos = 0 + self.line = '' + + def press(self, key, fm, env): + from curses.ascii import ctrl, ESC + from ranger.helper import log + log(key) + + try: + cmd = self.commandlist.paths[env.keybuffer] + except KeyError: + env.key_clear() + return + + if cmd == self.commandlist.dummy_object: + return + + cmd.execute(self, fm) + env.key_clear() + + def type_key(self, key): + if isinstance(key, int): + key = chr(key) + + if self.pos == len(self.line): + self.line += key + else: + self.line = self.line[:self.pos] + key + self.line[self.pos:] + + self.pos += len(key) + + def move(self, relative = 0, absolute = None): + if absolute is not None: + if absolute < 0: + self.pos = len(self.line) + 1 + absolute + else: + self.pos = absolute + + self.pos = min(max(0, self.pos + relative), len(self.line)) + + def delete_rest(self, direction): + if direction > 0: + self.line = self.line[:self.pos] + else: + self.line = self.line[self.pos:] + self.pos = 0 + + def delete(self, mod): + pos = self.pos + mod + + self.line = self.line[0:pos] + self.line[pos+1:] + self.move(relative = mod) + + def execute(self): + self.line = '' + self.pos = 0 + self.close() + diff --git a/ranger/gui/widget.py b/ranger/gui/widget.py index f9a0651f..fa1ca585 100644 --- a/ranger/gui/widget.py +++ b/ranger/gui/widget.py @@ -11,7 +11,9 @@ def combine(keylist, keys): class Widget(): def __init__(self, win, colorscheme): self.win = win + self.focused = False self.colorscheme = colorscheme + self.visible = True self.setdim(0, 0, 0, 0) def color(self, keylist = None, *keys): @@ -49,7 +51,7 @@ class Widget(): return (x >= self.x and x < self.x + self.wid) and \ (y >= self.y and y < self.y + self.hei) - def feed_env(self): + def feed_env(self, env): pass def feed(self): @@ -57,9 +59,15 @@ class Widget(): def click(self, event, fm): pass + + def press(self, key, fm): + pass def draw(self): pass + def finalize(self): + pass + def destroy(self): pass -- cgit 1.4.1-2-gfad0