def __init__(self, env=None, fm=None): self.keybuffer = KeyBuffer() self.keymaps = KeyMaps(self.keybuffer) self.redrawlock = threading.Event() self.redrawlock.set() if fm is not None: self.fm = fm
def __init__(self, env=None, fm=None): # pylint: disable=super-init-not-called self.keybuffer = KeyBuffer() self.keymaps = KeyMaps(self.keybuffer) self.redrawlock = threading.Event() self.redrawlock.set() self.titlebar = None self._viewmode = None self.taskview = None self.status = None self.console = None self.pager = None self._draw_title = None self._tmux_automatic_rename = None self.browser = None if fm is not None: self.fm = fm
def __init__(self, path): SignalDispatcher.__init__(self) self.path = abspath(expanduser(path)) self._cf = None self.pathway = () self.directories = {} self.keybuffer = KeyBuffer() self.keymaps = KeyMaps(self.keybuffer) self.copy = set() self.history = History(self.settings.max_history_size, unique=False) try: self.username = pwd.getpwuid(os.geteuid()).pw_name except: self.username = "******" + str(os.geteuid()) self.hostname = socket.gethostname() self.home_path = os.path.expanduser("~") self.signal_bind("move", self._set_cf_from_signal, priority=0.1, weak=True)
class UI(DisplayableContainer): ALLOWED_VIEWMODES = 'miller', 'multipane' is_set_up = False load_mode = False is_on = False termsize = None def __init__(self, env=None, fm=None): self.keybuffer = KeyBuffer() self.keymaps = KeyMaps(self.keybuffer) self.redrawlock = threading.Event() self.redrawlock.set() if fm is not None: self.fm = fm def setup_curses(self): os.environ['ESCDELAY'] = '25' # don't know a cleaner way try: self.win = curses.initscr() except _curses.error as e: if e.args[0] == "setupterm: could not find terminal": os.environ['TERM'] = 'linux' self.win = curses.initscr() self.keymaps.use_keymap('browser') DisplayableContainer.__init__(self, None) def initialize(self): """initialize curses, then call setup (at the first time) and resize.""" self.win.leaveok(0) self.win.keypad(1) self.load_mode = False curses.cbreak() curses.noecho() curses.halfdelay(20) try: curses.curs_set(int(bool(self.settings.show_cursor))) except: pass curses.start_color() try: curses.use_default_colors() except: pass self.settings.signal_bind('setopt.mouse_enabled', _setup_mouse) _setup_mouse(dict(value=self.settings.mouse_enabled)) if not self.is_set_up: self.is_set_up = True self.setup() self.win.addstr("loading...") self.win.refresh() self._draw_title = curses.tigetflag('hs') # has_status_line self.update_size() self.is_on = True if self.settings.update_tmux_title: sys.stdout.write("\033kranger\033\\") sys.stdout.flush() if 'vcsthread' in self.__dict__: self.vcsthread.unpause() def suspend(self): """Turn off curses""" if 'vcsthread' in self.__dict__: self.vcsthread.pause() self.vcsthread.paused.wait() self.win.keypad(0) curses.nocbreak() curses.echo() try: curses.curs_set(1) except: pass if self.settings.mouse_enabled: _setup_mouse(dict(value=False)) curses.endwin() self.is_on = False def set_load_mode(self, boolean): boolean = bool(boolean) if boolean != self.load_mode: self.load_mode = boolean if boolean: # don't wait for key presses in the load mode curses.cbreak() self.win.nodelay(1) else: self.win.nodelay(0) # Sanitize halfdelay setting halfdelay = min(255, max(1, self.settings.idle_delay // 100)) curses.halfdelay(halfdelay) def destroy(self): """Destroy all widgets and turn off curses""" DisplayableContainer.destroy(self) self.suspend() def handle_mouse(self): """Handles mouse input""" try: event = MouseEvent(curses.getmouse()) except _curses.error: return if not self.console.visible: DisplayableContainer.click(self, event) def handle_key(self, key): """Handles key input""" if hasattr(self, 'hint'): self.hint() if key < 0: self.keybuffer.clear() elif not DisplayableContainer.press(self, key): self.keymaps.use_keymap('browser') self.press(key) def press(self, key): keybuffer = self.keybuffer self.status.clear_message() keybuffer.add(key) self.fm.hide_bookmarks() self.browser.draw_hints = not keybuffer.finished_parsing \ and keybuffer.finished_parsing_quantifier if keybuffer.result is not None: try: self.fm.execute_console(keybuffer.result, wildcards=keybuffer.wildcards, quantifier=keybuffer.quantifier) finally: if keybuffer.finished_parsing: keybuffer.clear() elif keybuffer.finished_parsing: keybuffer.clear() return False return True def handle_keys(self, *keys): for key in keys: self.handle_key(key) def handle_input(self): key = self.win.getch() if key is 27 or key >= 128 and key < 256: # Handle special keys like ALT+X or unicode here: keys = [key] previous_load_mode = self.load_mode self.set_load_mode(True) for n in range(4): getkey = self.win.getch() if getkey is not -1: keys.append(getkey) if len(keys) == 1: keys.append(-1) elif keys[0] == 27: keys[0] = ALT_KEY if self.settings.xterm_alt_key: if len(keys) == 2 and keys[1] in range(127, 256): if keys[0] == 195: keys = [ALT_KEY, keys[1] - 64] elif keys[0] == 194: keys = [ALT_KEY, keys[1] - 128] self.handle_keys(*keys) self.set_load_mode(previous_load_mode) if self.settings.flushinput and not self.console.visible: curses.flushinp() else: # Handle simple key presses, CTRL+X, etc here: if key >= 0: if self.settings.flushinput and not self.console.visible: curses.flushinp() if key == curses.KEY_MOUSE: self.handle_mouse() elif key == curses.KEY_RESIZE: self.update_size() else: if not self.fm.input_is_blocked(): self.handle_key(key) def setup(self): """Build up the UI by initializing widgets.""" from ranger.gui.widgets.view_miller import ViewMiller from ranger.gui.widgets.titlebar import TitleBar from ranger.gui.widgets.console import Console from ranger.gui.widgets.statusbar import StatusBar from ranger.gui.widgets.taskview import TaskView from ranger.gui.widgets.pager import Pager # Create a title bar self.titlebar = TitleBar(self.win) self.add_child(self.titlebar) # Create the browser view self.settings.signal_bind('setopt.viewmode', self._set_viewmode) self._viewmode = None # The following line sets self.browser implicitly through the signal self.viewmode = self.settings.viewmode self.add_child(self.browser) # Create the process manager self.taskview = TaskView(self.win) self.taskview.visible = False self.add_child(self.taskview) # Create the status bar self.status = StatusBar(self.win, self.browser.main_column) self.add_child(self.status) # Create the console self.console = Console(self.win) self.add_child(self.console) self.console.visible = False # Create the pager self.pager = Pager(self.win) self.pager.visible = False self.add_child(self.pager) @lazy_property def vcsthread(self): """VCS thread""" from ranger.ext.vcs import VcsThread thread = VcsThread(self) thread.start() return thread def redraw(self): """Redraw all widgets""" self.redrawlock.wait() self.redrawlock.clear() self.poke() # determine which widgets are shown if self.console.wait_for_command_input or self.console.question_queue: self.console.focused = True self.console.visible = True self.status.visible = False else: self.console.focused = False self.console.visible = False self.status.visible = True self.draw() self.finalize() self.redrawlock.set() def redraw_window(self): """Redraw the window. This only calls self.win.redrawwin().""" self.win.erase() self.win.redrawwin() self.win.refresh() self.win.redrawwin() self.need_redraw = True def update_size(self): """resize all widgets""" self.termsize = self.win.getmaxyx() y, x = self.termsize self.browser.resize(self.settings.status_bar_on_top and 2 or 1, 0, y - 2, x) self.taskview.resize(1, 0, y - 2, x) self.pager.resize(1, 0, y - 2, x) self.titlebar.resize(0, 0, 1, x) self.status.resize(self.settings.status_bar_on_top and 1 or y - 1, 0, 1, x) self.console.resize(y - 1, 0, 1, x) def draw(self): """Draw all objects in the container""" self.win.touchwin() DisplayableContainer.draw(self) if self._draw_title and self.settings.update_title: cwd = self.fm.thisdir.path if cwd.startswith(self.fm.home_path): cwd = '~' + cwd[len(self.fm.home_path):] if self.settings.shorten_title: split = cwd.rsplit(os.sep, self.settings.shorten_title) if os.sep in split[0]: cwd = os.sep.join(split[1:]) try: fixed_cwd = cwd.encode('utf-8', 'surrogateescape'). \ decode('utf-8', 'replace') sys.stdout.write( "%sranger:%s%s" % (curses.tigetstr('tsl').decode('latin-1'), fixed_cwd, curses.tigetstr('fsl').decode('latin-1'))) sys.stdout.flush() except: pass self.win.refresh() def finalize(self): """Finalize every object in container and refresh the window""" DisplayableContainer.finalize(self) self.win.refresh() def draw_images(self): if self.pager.visible: self.pager.draw_image() elif hasattr(self.browser, 'pager'): if self.browser.pager.visible: self.browser.pager.draw_image() else: self.browser.columns[-1].draw_image() def close_pager(self): if self.console.visible: self.console.focused = True self.pager.close() self.pager.visible = False self.pager.focused = False self.browser.visible = True def open_pager(self): self.browser.columns[-1].clear_image(force=True) if self.console.focused: self.console.focused = False self.pager.open() self.pager.visible = True self.pager.focused = True self.browser.visible = False return self.pager def open_embedded_pager(self): self.browser.open_pager() for column in self.browser.columns: if column == self.browser.main_column: break column.level_shift(amount=1) return self.browser.pager def close_embedded_pager(self): self.browser.close_pager() for column in self.browser.columns: column.level_restore() def open_console(self, string='', prompt=None, position=None): if self.console.open(string, prompt=prompt, position=position): self.status.msg = None def close_console(self): self.console.close() self.close_pager() def open_taskview(self): self.browser.columns[-1].clear_image(force=True) self.pager.close() self.pager.visible = False self.pager.focused = False self.console.visible = False self.browser.visible = False self.taskview.visible = True self.taskview.focused = True def redraw_main_column(self): self.browser.main_column.need_redraw = True def close_taskview(self): self.taskview.visible = False self.browser.visible = True self.taskview.focused = False def throbber(self, string='.', remove=False): if remove: self.titlebar.throbber = type(self.titlebar).throbber else: self.titlebar.throbber = string def hint(self, text=None): self.status.hint = text def get_pager(self): if hasattr(self.browser, 'pager') and self.browser.pager.visible: return self.browser.pager else: return self.pager def _get_viewmode(self): return self._viewmode def _set_viewmode(self, value): if isinstance(value, Signal): value = value.value if value == '': value = self.ALLOWED_VIEWMODES[0] if value in self.ALLOWED_VIEWMODES: if self._viewmode != value: self._viewmode = value resize = False if hasattr(self, 'browser'): old_size = self.browser.y, self.browser.x, self.browser.hei, self.browser.wid self.remove_child(self.browser) self.browser.destroy() resize = True self.browser = self._viewmode_to_class(value)(self.win) self.add_child(self.browser) if resize: self.browser.resize(*old_size) else: raise ValueError("Attempting to set invalid viewmode `%s`, should " "be one of `%s`." % (value, "`, `".join(self.ALLOWED_VIEWMODES))) viewmode = property(_get_viewmode, _set_viewmode) def _viewmode_to_class(self, viewmode): if viewmode == 'miller': from ranger.gui.widgets.view_miller import ViewMiller return ViewMiller if viewmode == 'multipane': from ranger.gui.widgets.view_multipane import ViewMultipane return ViewMultipane
def __init__(self, env=None, fm=None): self.keybuffer = KeyBuffer() self.keymaps = KeyMaps(self.keybuffer) if fm is not None: self.fm = fm
class UI(DisplayableContainer): is_set_up = False load_mode = False is_on = False termsize = None def __init__(self, env=None, fm=None): self.keybuffer = KeyBuffer() self.keymaps = KeyMaps(self.keybuffer) if fm is not None: self.fm = fm def setup_curses(self): os.environ['ESCDELAY'] = '25' # don't know a cleaner way try: self.win = curses.initscr() except _curses.error as e: if e.args[0] == "setupterm: could not find terminal": os.environ['TERM'] = 'linux' self.win = curses.initscr() self.keymaps.use_keymap('browser') DisplayableContainer.__init__(self, None) def initialize(self): """initialize curses, then call setup (at the first time) and resize.""" self.win.leaveok(0) self.win.keypad(1) self.load_mode = False curses.cbreak() curses.noecho() curses.halfdelay(20) try: curses.curs_set(int(bool(self.settings.show_cursor))) except: pass curses.start_color() curses.use_default_colors() self.settings.signal_bind('setopt.mouse_enabled', _setup_mouse) _setup_mouse(dict(value=self.settings.mouse_enabled)) if not self.is_set_up: self.is_set_up = True self.setup() self.win.addstr("loading...") self.win.refresh() self._draw_title = curses.tigetflag('hs') # has_status_line self.update_size() self.is_on = True if self.settings.update_tmux_title: sys.stdout.write("\033kranger\033\\") sys.stdout.flush() def suspend(self): """Turn off curses""" self.win.keypad(0) curses.nocbreak() curses.echo() try: curses.curs_set(1) except: pass if self.settings.mouse_enabled: _setup_mouse(dict(value=False)) curses.endwin() self.is_on = False def set_load_mode(self, boolean): boolean = bool(boolean) if boolean != self.load_mode: self.load_mode = boolean if boolean: # don't wait for key presses in the load mode curses.cbreak() self.win.nodelay(1) else: self.win.nodelay(0) curses.halfdelay(20) def destroy(self): """Destroy all widgets and turn off curses""" DisplayableContainer.destroy(self) self.suspend() def handle_mouse(self): """Handles mouse input""" try: event = MouseEvent(curses.getmouse()) except _curses.error: return if not self.console.visible: DisplayableContainer.click(self, event) def handle_key(self, key): """Handles key input""" if hasattr(self, 'hint'): self.hint() if key < 0: self.keybuffer.clear() elif not DisplayableContainer.press(self, key): self.keymaps.use_keymap('browser') self.press(key) def press(self, key): keybuffer = self.keybuffer self.status.clear_message() keybuffer.add(key) self.fm.hide_bookmarks() self.browser.draw_hints = not keybuffer.finished_parsing \ and keybuffer.finished_parsing_quantifier if keybuffer.result is not None: try: self.fm.execute_console(keybuffer.result, wildcards=keybuffer.wildcards, quantifier=keybuffer.quantifier) finally: if keybuffer.finished_parsing: keybuffer.clear() elif keybuffer.finished_parsing: keybuffer.clear() return False return True def handle_keys(self, *keys): for key in keys: self.handle_key(key) def handle_input(self): key = self.win.getch() if key is 27 or key >= 128 and key < 256: # Handle special keys like ALT+X or unicode here: keys = [key] previous_load_mode = self.load_mode self.set_load_mode(True) for n in range(4): getkey = self.win.getch() if getkey is not -1: keys.append(getkey) if len(keys) == 1: keys.append(-1) elif keys[0] == 27: keys[0] = ALT_KEY if self.settings.xterm_alt_key: if len(keys) == 2 and keys[1] in range(127, 256): if keys[0] == 195: keys = [ALT_KEY, keys[1] - 64] elif keys[0] == 194: keys = [ALT_KEY, keys[1] - 128] self.handle_keys(*keys) self.set_load_mode(previous_load_mode) if self.settings.flushinput and not self.console.visible: curses.flushinp() else: # Handle simple key presses, CTRL+X, etc here: if key > 0: if self.settings.flushinput and not self.console.visible: curses.flushinp() if key == curses.KEY_MOUSE: self.handle_mouse() elif key == curses.KEY_RESIZE: self.update_size() else: if not self.fm.input_is_blocked(): self.handle_key(key) def setup(self): """Build up the UI by initializing widgets.""" from ranger.gui.widgets.browserview import BrowserView from ranger.gui.widgets.titlebar import TitleBar from ranger.gui.widgets.console import Console from ranger.gui.widgets.statusbar import StatusBar from ranger.gui.widgets.taskview import TaskView from ranger.gui.widgets.pager import Pager # Create a title bar self.titlebar = TitleBar(self.win) self.add_child(self.titlebar) # Create the browser view self.browser = BrowserView(self.win, self.settings.column_ratios) self.settings.signal_bind('setopt.column_ratios', self.browser.change_ratios) self.add_child(self.browser) # Create the process manager self.taskview = TaskView(self.win) self.taskview.visible = False self.add_child(self.taskview) # Create the status bar self.status = StatusBar(self.win, self.browser.main_column) self.add_child(self.status) # Create the console self.console = Console(self.win) self.add_child(self.console) self.console.visible = False # Create the pager self.pager = Pager(self.win) self.pager.visible = False self.add_child(self.pager) def redraw(self): """Redraw all widgets""" self.poke() # determine which widgets are shown if self.console.wait_for_command_input or self.console.question_queue: self.console.focused = True self.console.visible = True self.status.visible = False else: self.console.focused = False self.console.visible = False self.status.visible = True self.draw() self.finalize() def redraw_window(self): """Redraw the window. This only calls self.win.redrawwin().""" self.win.erase() self.win.redrawwin() self.win.refresh() self.win.redrawwin() self.need_redraw = True def update_size(self): """resize all widgets""" self.termsize = self.win.getmaxyx() y, x = self.termsize self.browser.resize(self.settings.status_bar_on_top and 2 or 1, 0, y - 2, x) self.taskview.resize(1, 0, y - 2, x) self.pager.resize(1, 0, y - 2, x) self.titlebar.resize(0, 0, 1, x) self.status.resize(self.settings.status_bar_on_top and 1 or y-1, 0, 1, x) self.console.resize(y - 1, 0, 1, x) def draw(self): """Draw all objects in the container""" self.win.touchwin() DisplayableContainer.draw(self) if self._draw_title and self.settings.update_title: cwd = self.fm.thisdir.path if cwd.startswith(self.fm.home_path): cwd = '~' + cwd[len(self.fm.home_path):] if self.settings.shorten_title: split = cwd.rsplit(os.sep, self.settings.shorten_title) if os.sep in split[0]: cwd = os.sep.join(split[1:]) try: fixed_cwd = cwd.encode('utf-8', 'surrogateescape'). \ decode('utf-8', 'replace') sys.stdout.write("%sranger:%s%s" % (curses.tigetstr('tsl').decode('latin-1'), fixed_cwd, curses.tigetstr('fsl').decode('latin-1'))) sys.stdout.flush() except: pass self.win.refresh() def finalize(self): """Finalize every object in container and refresh the window""" DisplayableContainer.finalize(self) self.win.refresh() def close_pager(self): if self.console.visible: self.console.focused = True self.pager.close() self.pager.visible = False self.pager.focused = False self.browser.visible = True def open_pager(self): self.browser.columns[-1].clear_image(force=True) if self.console.focused: self.console.focused = False self.pager.open() self.pager.visible = True self.pager.focused = True self.browser.visible = False return self.pager def open_embedded_pager(self): self.browser.open_pager() for column in self.browser.columns: if column == self.browser.main_column: break column.level_shift(amount=1) return self.browser.pager def close_embedded_pager(self): self.browser.close_pager() for column in self.browser.columns: column.level_restore() def open_console(self, string='', prompt=None, position=None): if self.console.open(string, prompt=prompt, position=position): self.status.msg = None def close_console(self): self.console.close() self.close_pager() def open_taskview(self): self.browser.columns[-1].clear_image(force=True) self.pager.close() self.pager.visible = False self.pager.focused = False self.console.visible = False self.browser.visible = False self.taskview.visible = True self.taskview.focused = True def redraw_main_column(self): self.browser.main_column.need_redraw = True def close_taskview(self): self.taskview.visible = False self.browser.visible = True self.taskview.focused = False def throbber(self, string='.', remove=False): if remove: self.titlebar.throbber = type(self.titlebar).throbber else: self.titlebar.throbber = string def hint(self, text=None): self.status.hint = text
class UI( # pylint: disable=too-many-instance-attributes,too-many-public-methods DisplayableContainer): ALLOWED_VIEWMODES = 'miller', 'multipane' is_set_up = False load_mode = False is_on = False termsize = None def __init__(self, env=None, fm=None): # pylint: disable=super-init-not-called self.keybuffer = KeyBuffer() self.keymaps = KeyMaps(self.keybuffer) self.redrawlock = threading.Event() self.redrawlock.set() self.titlebar = None self._viewmode = None self.taskview = None self.status = None self.console = None self.pager = None self.multiplexer = None self._draw_title = None self._tmux_automatic_rename = None self._multiplexer_title = None self.browser = None if fm is not None: self.fm = fm def setup_curses(self): os.environ['ESCDELAY'] = '25' # don't know a cleaner way try: self.win = curses.initscr() except curses.error as ex: if ex.args[0] == "setupterm: could not find terminal": os.environ['TERM'] = 'linux' self.win = curses.initscr() self.keymaps.use_keymap('browser') DisplayableContainer.__init__(self, None) def initialize(self): """initialize curses, then call setup (at the first time) and resize.""" self.win.leaveok(0) self.win.keypad(1) self.load_mode = False curses.cbreak() curses.noecho() curses.halfdelay(20) try: curses.curs_set(int(bool(self.settings.show_cursor))) except curses.error: pass curses.start_color() try: curses.use_default_colors() except curses.error: pass self.settings.signal_bind('setopt.mouse_enabled', _setup_mouse) self.settings.signal_bind('setopt.freeze_files', self.redraw_statusbar) _setup_mouse(dict(value=self.settings.mouse_enabled)) if not self.is_set_up: self.is_set_up = True self.setup() self.win.addstr("loading...") self.win.refresh() self._draw_title = curses.tigetflag('hs') # has_status_line self.update_size() self.is_on = True self.handle_multiplexer() if 'vcsthread' in self.__dict__: self.vcsthread.unpause() def suspend(self): """Turn off curses""" if 'vcsthread' in self.__dict__: self.vcsthread.pause() self.vcsthread.paused.wait() if self.fm.image_displayer: self.fm.image_displayer.quit() self.win.keypad(0) curses.nocbreak() curses.echo() try: curses.curs_set(1) except curses.error: pass if self.settings.mouse_enabled: _setup_mouse(dict(value=False)) curses.endwin() self.is_on = False def set_load_mode(self, boolean): boolean = bool(boolean) if boolean != self.load_mode: self.load_mode = boolean if boolean: # don't wait for key presses in the load mode curses.cbreak() self.win.nodelay(1) else: self.win.nodelay(0) # Sanitize halfdelay setting halfdelay = min(255, max(1, self.settings.idle_delay // 100)) curses.halfdelay(halfdelay) def destroy(self): """Destroy all widgets and turn off curses""" if 'vcsthread' in self.__dict__: if not self.vcsthread.stop(): self.fm.notify('Failed to stop `UI.vcsthread`', bad=True) del self.__dict__['vcsthread'] DisplayableContainer.destroy(self) self.restore_multiplexer_name() self.suspend() def handle_mouse(self): """Handles mouse input""" try: event = MouseEvent(curses.getmouse()) except curses.error: return if not self.console.visible: DisplayableContainer.click(self, event) def handle_key(self, key): """Handles key input""" self.hint() if key < 0: self.keybuffer.clear() elif not DisplayableContainer.press(self, key): self.keymaps.use_keymap('browser') self.press(key) def press(self, key): keybuffer = self.keybuffer self.status.clear_message() keybuffer.add(key) self.fm.hide_bookmarks() self.browser.draw_hints = not keybuffer.finished_parsing \ and keybuffer.finished_parsing_quantifier if keybuffer.result is not None: try: self.fm.execute_console( keybuffer.result, wildcards=keybuffer.wildcards, quantifier=keybuffer.quantifier, ) finally: if keybuffer.finished_parsing: keybuffer.clear() elif keybuffer.finished_parsing: keybuffer.clear() return False return True def handle_keys(self, *keys): for key in keys: self.handle_key(key) def handle_input(self): # pylint: disable=too-many-branches key = self.win.getch() if key == curses.KEY_ENTER: key = ord('\n') if key == 27 or (128 <= key < 256): # Handle special keys like ALT+X or unicode here: keys = [key] previous_load_mode = self.load_mode self.set_load_mode(True) for _ in range(4): getkey = self.win.getch() if getkey != -1: keys.append(getkey) if len(keys) == 1: keys.append(-1) elif keys[0] == 27: keys[0] = ALT_KEY if self.settings.xterm_alt_key: if len(keys) == 2 and keys[1] in range(127, 256): if keys[0] == 195: keys = [ALT_KEY, keys[1] - 64] elif keys[0] == 194: keys = [ALT_KEY, keys[1] - 128] self.handle_keys(*keys) self.set_load_mode(previous_load_mode) if self.settings.flushinput and not self.console.visible: curses.flushinp() else: # Handle simple key presses, CTRL+X, etc here: if key >= 0: if self.settings.flushinput and not self.console.visible: curses.flushinp() if key == curses.KEY_MOUSE: self.handle_mouse() elif key == curses.KEY_RESIZE: self.update_size() else: if not self.fm.input_is_blocked(): self.handle_key(key) elif key == -1 and not os.isatty(sys.stdin.fileno()): # STDIN has been closed self.fm.exit() def setup(self): """Build up the UI by initializing widgets.""" from ranger.gui.widgets.titlebar import TitleBar from ranger.gui.widgets.console import Console from ranger.gui.widgets.statusbar import StatusBar from ranger.gui.widgets.taskview import TaskView from ranger.gui.widgets.pager import Pager # Create a titlebar self.titlebar = TitleBar(self.win) self.add_child(self.titlebar) # Create the browser view self.settings.signal_bind('setopt.viewmode', self._set_viewmode) self._viewmode = None # The following line sets self.browser implicitly through the signal self.viewmode = self.settings.viewmode self.add_child(self.browser) # Create the process manager self.taskview = TaskView(self.win) self.taskview.visible = False self.add_child(self.taskview) # Create the status bar self.status = StatusBar(self.win, self.browser.main_column) self.add_child(self.status) # Create the console self.console = Console(self.win) self.add_child(self.console) self.console.visible = False # Create the pager self.pager = Pager(self.win) self.pager.visible = False self.add_child(self.pager) @lazy_property def vcsthread(self): """VCS thread""" from ranger.ext.vcs import VcsThread thread = VcsThread(self) thread.start() return thread def redraw(self): """Redraw all widgets""" self.redrawlock.wait() self.redrawlock.clear() self.poke() # determine which widgets are shown if self.console.wait_for_command_input or self.console.question_queue: self.console.focused = True self.console.visible = True self.status.visible = False else: self.console.focused = False self.console.visible = False self.status.visible = True self.draw() self.finalize() self.redrawlock.set() def redraw_window(self): """Redraw the window. This only calls self.win.redrawwin().""" self.win.erase() self.win.redrawwin() self.win.refresh() self.win.redrawwin() self.need_redraw = True def update_size(self): """resize all widgets""" self.termsize = self.win.getmaxyx() y, x = self.termsize self.browser.resize(self.settings.status_bar_on_top and 2 or 1, 0, y - 2, x) self.taskview.resize(1, 0, y - 2, x) self.pager.resize(1, 0, y - 2, x) self.titlebar.resize(0, 0, 1, x) self.status.resize(self.settings.status_bar_on_top and 1 or y - 1, 0, 1, x) self.console.resize(y - 1, 0, 1, x) def draw(self): """Draw all objects in the container""" self.win.touchwin() DisplayableContainer.draw(self) if self._draw_title and self.settings.update_title: cwd = self.fm.thisdir.path if self.settings.tilde_in_titlebar \ and (cwd == self.fm.home_path or cwd.startswith(self.fm.home_path + "/")): cwd = '~' + cwd[len(self.fm.home_path):] if self.settings.shorten_title: split = cwd.rsplit(os.sep, self.settings.shorten_title) if os.sep in split[0]: cwd = os.sep.join(split[1:]) try: fixed_cwd = cwd.encode('utf-8', 'surrogateescape'). \ decode('utf-8', 'replace') escapes = [ curses.tigetstr('tsl').decode('latin-1'), ESCAPE_ICON_TITLE ] bel = curses.tigetstr('fsl').decode('latin-1') fmt_tups = [(e, fixed_cwd, bel) for e in escapes] except UnicodeError: pass else: for fmt_tup in fmt_tups: sys.stdout.write("%sranger:%s%s" % fmt_tup) sys.stdout.flush() self.win.refresh() def finalize(self): """Finalize every object in container and refresh the window""" DisplayableContainer.finalize(self) self.win.refresh() def draw_images(self): if self.pager.visible: self.pager.draw_image() elif self.browser.pager: if self.browser.pager.visible: self.browser.pager.draw_image() else: self.browser.columns[-1].draw_image() def close_pager(self): if self.console.visible: self.console.focused = True self.pager.close() self.pager.visible = False self.pager.focused = False self.browser.visible = True def open_pager(self): self.browser.columns[-1].clear_image(force=True) if self.console.focused: self.console.focused = False self.pager.open() self.pager.visible = True self.pager.focused = True self.browser.visible = False return self.pager def open_embedded_pager(self): self.browser.open_pager() for column in self.browser.columns: if column == self.browser.main_column: break column.level_shift(amount=1) return self.browser.pager def close_embedded_pager(self): self.browser.close_pager() for column in self.browser.columns: column.level_restore() def open_console(self, string='', prompt=None, position=None): if self.console.open(string, prompt=prompt, position=position): self.status.msg = None def close_console(self): self.console.close() self.close_pager() def open_taskview(self): self.browser.columns[-1].clear_image(force=True) self.pager.close() self.pager.visible = False self.pager.focused = False self.console.visible = False self.browser.visible = False self.taskview.visible = True self.taskview.focused = True def redraw_main_column(self): self.browser.main_column.need_redraw = True def redraw_statusbar(self): self.status.need_redraw = True def close_taskview(self): self.taskview.visible = False self.browser.visible = True self.taskview.focused = False def throbber(self, string='.', remove=False): if remove: self.titlebar.throbber = type(self.titlebar).throbber else: self.titlebar.throbber = string # Handles window renaming behaviour of the terminal multiplexers # GNU Screen and Tmux def handle_multiplexer(self): if (self.settings.update_tmux_title and not self._multiplexer_title): try: if _in_tmux(): # Stores the automatic-rename setting # prints out a warning if allow-rename isn't set in tmux try: tmux_allow_rename = check_output( ['tmux', 'show-window-options', '-v', 'allow-rename']).strip() except CalledProcessError: tmux_allow_rename = 'off' if tmux_allow_rename == 'off': self.fm.notify('Warning: allow-rename not set in Tmux!', bad=True) else: self._multiplexer_title = check_output( ['tmux', 'display-message', '-p', '#W']).strip() self._tmux_automatic_rename = check_output( ['tmux', 'show-window-options', '-v', 'automatic-rename']).strip() if self._tmux_automatic_rename == 'on': check_output(['tmux', 'set-window-option', 'automatic-rename', 'off']) elif _in_screen(): # Stores the screen window name before renaming it # gives out a warning if $TERM is not "screen" self._multiplexer_title = check_output( ['screen', '-Q', 'title']).strip() except CalledProcessError: self.fm.notify("Couldn't access previous multiplexer window" " name, won't be able to restore.", bad=False) if not self._multiplexer_title: self._multiplexer_title = os.path.basename( os.environ.get("SHELL", "shell")) sys.stdout.write("\033kranger\033\\") sys.stdout.flush() # Restore window name def restore_multiplexer_name(self): if self._multiplexer_title: try: if _in_tmux(): if self._tmux_automatic_rename: check_output(['tmux', 'set-window-option', 'automatic-rename', self._tmux_automatic_rename]) else: check_output(['tmux', 'set-window-option', '-u', 'automatic-rename']) except CalledProcessError: self.fm.notify("Could not restore multiplexer window name!", bad=True) sys.stdout.write("\033k{0}\033\\".format(self._multiplexer_title)) sys.stdout.flush() def hint(self, text=None): self.status.hint = text def get_pager(self): if self.browser.pager and self.browser.pager.visible: return self.browser.pager return self.pager def _get_viewmode(self): return self._viewmode def _set_viewmode(self, value): if isinstance(value, Signal): value = value.value if value == '': value = self.ALLOWED_VIEWMODES[0] if value in self.ALLOWED_VIEWMODES: if self._viewmode != value: self._viewmode = value new_browser = self._viewmode_to_class(value)(self.win) if self.browser is None: self.add_child(new_browser) else: old_size = self.browser.y, self.browser.x, self.browser.hei, self.browser.wid self.replace_child(self.browser, new_browser) self.browser.destroy() new_browser.resize(*old_size) self.browser = new_browser self.redraw_window() else: raise ValueError("Attempting to set invalid viewmode `%s`, should " "be one of `%s`." % (value, "`, `".join(self.ALLOWED_VIEWMODES))) viewmode = property(_get_viewmode, _set_viewmode) @staticmethod def _viewmode_to_class(viewmode): if viewmode == 'miller': from ranger.gui.widgets.view_miller import ViewMiller return ViewMiller elif viewmode == 'multipane': from ranger.gui.widgets.view_multipane import ViewMultipane return ViewMultipane return None
class Environment(SettingsAware, SignalDispatcher): """ A collection of data which is relevant for more than one class. """ cwd = None # current directory copy = None cmd = None cut = None termsize = None history = None directories = None last_search = None pathway = None path = None def __init__(self, path): SignalDispatcher.__init__(self) self.path = abspath(expanduser(path)) self._cf = None self.pathway = () self.directories = {} self.keybuffer = KeyBuffer() self.keymaps = KeyMaps(self.keybuffer) self.copy = set() self.history = History(self.settings.max_history_size, unique=False) try: self.username = pwd.getpwuid(os.geteuid()).pw_name except: self.username = '******' + str(os.geteuid()) self.hostname = socket.gethostname() self.home_path = os.path.expanduser('~') self.signal_bind('move', self._set_cf_from_signal, priority=0.1, weak=True) def _set_cf_from_signal(self, signal): self._cf = signal.new def _set_cf(self, value): if value is not self._cf: previous = self._cf self.signal_emit('move', previous=previous, new=value) def _get_cf(self): return self._cf cf = property(_get_cf, _set_cf) def key_append(self, key): """Append a key to the keybuffer""" # special keys: if key == curses.KEY_RESIZE: self.keybuffer.clear() self.keybuffer.add(key) def key_clear(self): """Clear the keybuffer""" self.keybuffer.clear() def at_level(self, level): """ Returns the FileSystemObject at the given level. level >0 => previews level 0 => current file/directory level <0 => parent directories """ if level <= 0: try: return self.pathway[level - 1] except IndexError: return None else: directory = self.cf for i in range(level - 1): if directory is None: return None if directory.is_directory: directory = directory.pointed_obj else: return None try: return self.directories[directory.path] except AttributeError: return None except KeyError: return directory def garbage_collect(self, age, tabs): """Delete unused directory objects""" for key in tuple(self.directories): value = self.directories[key] if age != -1: if not value.is_older_than(age) or value in self.pathway: continue if value in tabs.values(): continue del self.directories[key] if value.is_directory: value.files = None self.settings.signal_garbage_collect() self.signal_garbage_collect() def get_selection(self): if self.cwd: return self.cwd.get_selection() return set() def get_directory(self, path): """Get the directory object at the given path""" path = abspath(path) try: return self.directories[path] except KeyError: obj = Directory(path) self.directories[path] = obj return obj def get_free_space(self, path): stat = os.statvfs(path) return stat.f_bavail * stat.f_bsize def assign_cursor_positions_for_subdirs(self): """Assign correct cursor positions for subdirectories""" last_path = None for path in reversed(self.pathway): if last_path is None: last_path = path continue path.move_to_obj(last_path) last_path = path def ensure_correct_pointer(self): if self.cwd: self.cwd.correct_pointer() def history_go(self, relative): """Move relative in history""" if self.history: self.history.move(relative).go(history=False) def enter_dir(self, path, history = True): """Enter given path""" if path is None: return path = str(path) previous = self.cwd # get the absolute path path = normpath(join(self.path, expanduser(path))) if not isdir(path): return False new_cwd = self.get_directory(path) try: os.chdir(path) except: return True self.path = path self.cwd = new_cwd self.cwd.load_content_if_outdated() # build the pathway, a tuple of directory objects which lie # on the path to the current directory. if path == '/': self.pathway = (self.get_directory('/'), ) else: pathway = [] currentpath = '/' for dir in path.split('/'): currentpath = join(currentpath, dir) pathway.append(self.get_directory(currentpath)) self.pathway = tuple(pathway) self.assign_cursor_positions_for_subdirs() # set the current file. self.cwd.sort_directories_first = self.settings.sort_directories_first self.cwd.sort_reverse = self.settings.sort_reverse self.cwd.sort_if_outdated() self.cf = self.cwd.pointed_obj if history: self.history.add(new_cwd) self.signal_emit('cd', previous=previous, new=self.cwd) return True
class UI( # pylint: disable=too-many-instance-attributes,too-many-public-methods DisplayableContainer): ALLOWED_VIEWMODES = 'miller', 'multipane' is_set_up = False load_mode = False is_on = False termsize = None def __init__(self, env=None, fm=None): # pylint: disable=super-init-not-called self.keybuffer = KeyBuffer() self.keymaps = KeyMaps(self.keybuffer) self.redrawlock = threading.Event() self.redrawlock.set() self.titlebar = None self._viewmode = None self.taskview = None self.status = None self.console = None self.pager = None self._draw_title = None self._tmux_automatic_rename = None self.browser = None if fm is not None: self.fm = fm def setup_curses(self): os.environ['ESCDELAY'] = '25' # don't know a cleaner way try: self.win = curses.initscr() except curses.error as ex: if ex.args[0] == "setupterm: could not find terminal": os.environ['TERM'] = 'linux' self.win = curses.initscr() self.keymaps.use_keymap('browser') DisplayableContainer.__init__(self, None) def initialize(self): """initialize curses, then call setup (at the first time) and resize.""" self.win.leaveok(0) self.win.keypad(1) self.load_mode = False curses.cbreak() curses.noecho() curses.halfdelay(20) try: curses.curs_set(int(bool(self.settings.show_cursor))) except curses.error: pass curses.start_color() try: curses.use_default_colors() except curses.error: pass self.settings.signal_bind('setopt.mouse_enabled', _setup_mouse) self.settings.signal_bind('setopt.freeze_files', self.redraw_statusbar) _setup_mouse(dict(value=self.settings.mouse_enabled)) if not self.is_set_up: self.is_set_up = True self.setup() self.win.addstr("loading...") self.win.refresh() self._draw_title = curses.tigetflag('hs') # has_status_line # Save tmux setting `automatic-rename` if self.settings.update_tmux_title and 'TMUX' in os.environ: try: self._tmux_automatic_rename = check_output( ['tmux', 'show-window-options', '-v', 'automatic-rename']).strip() except CalledProcessError: self._tmux_automatic_rename = None self.update_size() self.is_on = True if self.settings.update_tmux_title and 'TMUX' in os.environ: sys.stdout.write("\033kranger\033\\") sys.stdout.flush() if 'vcsthread' in self.__dict__: self.vcsthread.unpause() def suspend(self): """Turn off curses""" if 'vcsthread' in self.__dict__: self.vcsthread.pause() self.vcsthread.paused.wait() self.win.keypad(0) curses.nocbreak() curses.echo() try: curses.curs_set(1) except curses.error: pass if self.settings.mouse_enabled: _setup_mouse(dict(value=False)) curses.endwin() self.is_on = False def set_load_mode(self, boolean): boolean = bool(boolean) if boolean != self.load_mode: self.load_mode = boolean if boolean: # don't wait for key presses in the load mode curses.cbreak() self.win.nodelay(1) else: self.win.nodelay(0) # Sanitize halfdelay setting halfdelay = min(255, max(1, self.settings.idle_delay // 100)) curses.halfdelay(halfdelay) def destroy(self): """Destroy all widgets and turn off curses""" if 'vcsthread' in self.__dict__: if not self.vcsthread.stop(): self.fm.notify('Failed to stop `UI.vcsthread`', bad=True) del self.__dict__['vcsthread'] DisplayableContainer.destroy(self) # Restore tmux setting `automatic-rename` if self.settings.update_tmux_title and 'TMUX' in os.environ: if self._tmux_automatic_rename: try: check_output(['tmux', 'set-window-option', 'automatic-rename', self._tmux_automatic_rename]) except CalledProcessError: pass else: try: check_output(['tmux', 'set-window-option', '-u', 'automatic-rename']) except CalledProcessError: pass self.suspend() def handle_mouse(self): """Handles mouse input""" try: event = MouseEvent(curses.getmouse()) except curses.error: return if not self.console.visible: DisplayableContainer.click(self, event) def handle_key(self, key): """Handles key input""" self.hint() if key < 0: self.keybuffer.clear() elif not DisplayableContainer.press(self, key): self.keymaps.use_keymap('browser') self.press(key) def press(self, key): keybuffer = self.keybuffer self.status.clear_message() keybuffer.add(key) self.fm.hide_bookmarks() self.browser.draw_hints = not keybuffer.finished_parsing \ and keybuffer.finished_parsing_quantifier if keybuffer.result is not None: try: self.fm.execute_console( keybuffer.result, wildcards=keybuffer.wildcards, quantifier=keybuffer.quantifier, ) finally: if keybuffer.finished_parsing: keybuffer.clear() elif keybuffer.finished_parsing: keybuffer.clear() return False return True def handle_keys(self, *keys): for key in keys: self.handle_key(key) def handle_input(self): key = self.win.getch() if key == 27 or (key >= 128 and key < 256): # Handle special keys like ALT+X or unicode here: keys = [key] previous_load_mode = self.load_mode self.set_load_mode(True) for _ in range(4): getkey = self.win.getch() if getkey != -1: keys.append(getkey) if len(keys) == 1: keys.append(-1) elif keys[0] == 27: keys[0] = ALT_KEY if self.settings.xterm_alt_key: if len(keys) == 2 and keys[1] in range(127, 256): if keys[0] == 195: keys = [ALT_KEY, keys[1] - 64] elif keys[0] == 194: keys = [ALT_KEY, keys[1] - 128] self.handle_keys(*keys) self.set_load_mode(previous_load_mode) if self.settings.flushinput and not self.console.visible: curses.flushinp() else: # Handle simple key presses, CTRL+X, etc here: if key >= 0: if self.settings.flushinput and not self.console.visible: curses.flushinp() if key == curses.KEY_MOUSE: self.handle_mouse() elif key == curses.KEY_RESIZE: self.update_size() else: if not self.fm.input_is_blocked(): self.handle_key(key) def setup(self): """Build up the UI by initializing widgets.""" from ranger.gui.widgets.titlebar import TitleBar from ranger.gui.widgets.console import Console from ranger.gui.widgets.statusbar import StatusBar from ranger.gui.widgets.taskview import TaskView from ranger.gui.widgets.pager import Pager # Create a titlebar self.titlebar = TitleBar(self.win) self.add_child(self.titlebar) # Create the browser view self.settings.signal_bind('setopt.viewmode', self._set_viewmode) self._viewmode = None # The following line sets self.browser implicitly through the signal self.viewmode = self.settings.viewmode self.add_child(self.browser) # Create the process manager self.taskview = TaskView(self.win) self.taskview.visible = False self.add_child(self.taskview) # Create the status bar self.status = StatusBar(self.win, self.browser.main_column) self.add_child(self.status) # Create the console self.console = Console(self.win) self.add_child(self.console) self.console.visible = False # Create the pager self.pager = Pager(self.win) self.pager.visible = False self.add_child(self.pager) @lazy_property def vcsthread(self): """VCS thread""" from ranger.ext.vcs import VcsThread thread = VcsThread(self) thread.start() return thread def redraw(self): """Redraw all widgets""" self.redrawlock.wait() self.redrawlock.clear() self.poke() # determine which widgets are shown if self.console.wait_for_command_input or self.console.question_queue: self.console.focused = True self.console.visible = True self.status.visible = False else: self.console.focused = False self.console.visible = False self.status.visible = True self.draw() self.finalize() self.redrawlock.set() def redraw_window(self): """Redraw the window. This only calls self.win.redrawwin().""" self.win.erase() self.win.redrawwin() self.win.refresh() self.win.redrawwin() self.need_redraw = True def update_size(self): """resize all widgets""" self.termsize = self.win.getmaxyx() y, x = self.termsize self.browser.resize(self.settings.status_bar_on_top and 2 or 1, 0, y - 2, x) self.taskview.resize(1, 0, y - 2, x) self.pager.resize(1, 0, y - 2, x) self.titlebar.resize(0, 0, 1, x) self.status.resize(self.settings.status_bar_on_top and 1 or y - 1, 0, 1, x) self.console.resize(y - 1, 0, 1, x) def draw(self): """Draw all objects in the container""" self.win.touchwin() DisplayableContainer.draw(self) if self._draw_title and self.settings.update_title: cwd = self.fm.thisdir.path if cwd.startswith(self.fm.home_path): cwd = '~' + cwd[len(self.fm.home_path):] if self.settings.shorten_title: split = cwd.rsplit(os.sep, self.settings.shorten_title) if os.sep in split[0]: cwd = os.sep.join(split[1:]) try: fixed_cwd = cwd.encode('utf-8', 'surrogateescape'). \ decode('utf-8', 'replace') fmt_tup = ( curses.tigetstr('tsl').decode('latin-1'), fixed_cwd, curses.tigetstr('fsl').decode('latin-1'), ) except UnicodeError: pass else: sys.stdout.write("%sranger:%s%s" % fmt_tup) sys.stdout.flush() self.win.refresh() def finalize(self): """Finalize every object in container and refresh the window""" DisplayableContainer.finalize(self) self.win.refresh() def draw_images(self): if self.pager.visible: self.pager.draw_image() elif self.browser.pager: if self.browser.pager.visible: self.browser.pager.draw_image() else: self.browser.columns[-1].draw_image() def close_pager(self): if self.console.visible: self.console.focused = True self.pager.close() self.pager.visible = False self.pager.focused = False self.browser.visible = True def open_pager(self): self.browser.columns[-1].clear_image(force=True) if self.console.focused: self.console.focused = False self.pager.open() self.pager.visible = True self.pager.focused = True self.browser.visible = False return self.pager def open_embedded_pager(self): self.browser.open_pager() for column in self.browser.columns: if column == self.browser.main_column: break column.level_shift(amount=1) return self.browser.pager def close_embedded_pager(self): self.browser.close_pager() for column in self.browser.columns: column.level_restore() def open_console(self, string='', prompt=None, position=None): if self.console.open(string, prompt=prompt, position=position): self.status.msg = None def close_console(self): self.console.close() self.close_pager() def open_taskview(self): self.browser.columns[-1].clear_image(force=True) self.pager.close() self.pager.visible = False self.pager.focused = False self.console.visible = False self.browser.visible = False self.taskview.visible = True self.taskview.focused = True def redraw_main_column(self): self.browser.main_column.need_redraw = True def redraw_statusbar(self): self.status.need_redraw = True def close_taskview(self): self.taskview.visible = False self.browser.visible = True self.taskview.focused = False def throbber(self, string='.', remove=False): if remove: self.titlebar.throbber = type(self.titlebar).throbber else: self.titlebar.throbber = string def hint(self, text=None): self.status.hint = text def get_pager(self): if self.browser.pager and self.browser.pager.visible: return self.browser.pager return self.pager def _get_viewmode(self): return self._viewmode def _set_viewmode(self, value): if isinstance(value, Signal): value = value.value if value == '': value = self.ALLOWED_VIEWMODES[0] if value in self.ALLOWED_VIEWMODES: if self._viewmode != value: self._viewmode = value new_browser = self._viewmode_to_class(value)(self.win) if self.browser is None: self.add_child(new_browser) else: old_size = self.browser.y, self.browser.x, self.browser.hei, self.browser.wid self.replace_child(self.browser, new_browser) self.browser.destroy() new_browser.resize(*old_size) self.browser = new_browser self.redraw_window() else: raise ValueError("Attempting to set invalid viewmode `%s`, should " "be one of `%s`." % (value, "`, `".join(self.ALLOWED_VIEWMODES))) viewmode = property(_get_viewmode, _set_viewmode) @staticmethod def _viewmode_to_class(viewmode): if viewmode == 'miller': from ranger.gui.widgets.view_miller import ViewMiller return ViewMiller elif viewmode == 'multipane': from ranger.gui.widgets.view_multipane import ViewMultipane return ViewMultipane return None
class UI(DisplayableContainer): is_set_up = False load_mode = False is_on = False termsize = None is_collapsed = False def __init__(self, env=None, fm=None): self.keybuffer = KeyBuffer() self.keymaps = KeyMaps(self.keybuffer) if fm is not None: self.fm = fm def setup_curses(self): os.environ['ESCDELAY'] = '25' # don't know a cleaner way try: self.win = curses.initscr() except _curses.error as e: if e.args[0] == "setupterm: could not find terminal": os.environ['TERM'] = 'linux' self.win = curses.initscr() self.keymaps.use_keymap('browser') DisplayableContainer.__init__(self, None) def initialize(self): """initialize curses, then call setup (at the first time) and resize.""" self.win.leaveok(0) self.win.keypad(1) self.load_mode = False curses.cbreak() curses.noecho() curses.halfdelay(20) try: curses.curs_set(int(bool(self.settings.show_cursor))) except: pass curses.start_color() try: curses.use_default_colors() except: pass self.settings.signal_bind('setopt.mouse_enabled', _setup_mouse) _setup_mouse(dict(value=self.settings.mouse_enabled)) if not self.is_set_up: self.is_set_up = True self.setup() self.win.addstr("loading...") self.win.refresh() self._draw_title = True self.update_size() self.is_on = True if self.settings.update_tmux_title: sys.stdout.write("\033kranger\033\\") sys.stdout.flush() def suspend(self): """Turn off curses""" self.win.keypad(0) curses.nocbreak() curses.echo() try: curses.curs_set(1) except: pass if self.settings.mouse_enabled: _setup_mouse(dict(value=False)) curses.endwin() self.is_on = False def set_load_mode(self, boolean): boolean = bool(boolean) if boolean != self.load_mode: self.load_mode = boolean if boolean: # don't wait for key presses in the load mode curses.cbreak() self.win.nodelay(1) else: self.win.nodelay(0) curses.halfdelay(20) def destroy(self): """Destroy all widgets and turn off curses""" DisplayableContainer.destroy(self) self.suspend() def handle_mouse(self): """Handles mouse input""" try: event = MouseEvent(curses.getmouse()) except _curses.error: return if not self.console.visible: DisplayableContainer.click(self, event) def handle_key(self, key): """Handles key input""" if hasattr(self, 'hint'): self.hint() if key < 0: self.keybuffer.clear() elif not DisplayableContainer.press(self, key): self.keymaps.use_keymap('browser') self.press(key) def press(self, key): keybuffer = self.keybuffer self.status.clear_message() keybuffer.add(key) self.fm.hide_bookmarks() self.browser.draw_hints = not keybuffer.finished_parsing \ and keybuffer.finished_parsing_quantifier if keybuffer.result is not None: try: self.fm.execute_console(keybuffer.result, wildcards=keybuffer.wildcards, quantifier=keybuffer.quantifier) finally: if keybuffer.finished_parsing: keybuffer.clear() elif keybuffer.finished_parsing: keybuffer.clear() return False return True def handle_keys(self, *keys): for key in keys: self.handle_key(key) def handle_input(self): key = self.win.getch() if key < 0: return False elif key is 27 or key >= 128 and key < 256: # Handle special keys like ALT+X or unicode here: keys = [key] previous_load_mode = self.load_mode self.set_load_mode(True) for n in range(4): getkey = self.win.getch() if getkey is not -1: keys.append(getkey) if len(keys) == 1: keys.append(-1) elif keys[0] == 27: keys[0] = ALT_KEY if self.settings.xterm_alt_key: if len(keys) == 2 and keys[1] in range(127, 256): if keys[0] == 195: keys = [ALT_KEY, keys[1] - 64] elif keys[0] == 194: keys = [ALT_KEY, keys[1] - 128] self.handle_keys(*keys) self.set_load_mode(previous_load_mode) if self.settings.flushinput and not self.console.visible: curses.flushinp() else: # Handle simple key presses, CTRL+X, etc here: if self.settings.flushinput and not self.console.visible: curses.flushinp() if key == curses.KEY_MOUSE: self.handle_mouse() elif key == curses.KEY_RESIZE: self.update_size() else: if not self.fm.input_is_blocked(): self.handle_key(key) return True def setup(self): """Build up the UI by initializing widgets.""" from ranger.gui.widgets.browserview import BrowserView from ranger.gui.widgets.titlebar import TitleBar from ranger.gui.widgets.console import Console from ranger.gui.widgets.statusbar import StatusBar from ranger.gui.widgets.taskview import TaskView from ranger.gui.widgets.pager import Pager # Create a title bar self.titlebar = TitleBar(self.win) self.add_child(self.titlebar) # Create the browser view self.browser = BrowserView(self.win, self.settings.column_ratios) self.settings.signal_bind('setopt.column_ratios', self.browser.change_ratios) self.add_child(self.browser) # Create the process manager self.taskview = TaskView(self.win) self.taskview.visible = False self.add_child(self.taskview) # Create the status bar self.status = StatusBar(self.win, self.browser.main_column) self.add_child(self.status) # Create the console self.console = Console(self.win) self.add_child(self.console) self.console.visible = False # Create the pager self.pager = Pager(self.win) self.pager.visible = False self.add_child(self.pager) def redraw(self): """Redraw all widgets""" self.poke() # determine which widgets are shown if self.console.wait_for_command_input or self.console.question_queue: self.console.focused = True self.console.visible = True self.status.visible = False else: self.console.focused = False self.console.visible = False self.status.visible = True self.draw() self.finalize() def redraw_window(self): """Redraw the window. This only calls self.win.redrawwin().""" self.win.erase() self.win.redrawwin() self.win.refresh() self.win.redrawwin() self.need_redraw = True def update_size(self): """resize all widgets""" self.termsize = self.win.getmaxyx() y, x = self.termsize # macranger responsive columns if x < 60: self.browser.preview = False self.browser.change_ratios([1]) self.browser.need_clear = True self.is_collapsed = True elif self.is_collapsed: self.browser.preview = True self.browser.change_ratios(self.settings.column_ratios) self.is_collapsed = False self.browser.resize(self.settings.status_bar_on_top and 2 or 1, 0, y - 2, x) self.taskview.resize(1, 0, y - 2, x) self.pager.resize(1, 0, y - 2, x) self.titlebar.resize(0, 0, 1, x) self.status.resize(self.settings.status_bar_on_top and 1 or y-1, 0, 1, x) self.console.resize(y - 1, 0, 1, x) def draw(self): """Draw all objects in the container""" self.win.touchwin() DisplayableContainer.draw(self) if self._draw_title and self.settings.update_title: cwd = self.fm.thisdir.path extra = "" if self.settings.using_macranger_app: extra = "^^" + cwd if cwd.startswith(self.fm.home_path): cwd = '~' + cwd[len(self.fm.home_path):] if self.settings.shorten_title: split = cwd.rsplit(os.sep, self.settings.shorten_title) if os.sep in split[0]: cwd = os.sep.join(split[1:]) fixed_cwd = cwd.encode('utf-8', 'surrogateescape'). \ decode('utf-8', 'replace') sys.stdout.write("\033]2;%s%s\007" % (fixed_cwd,extra)) sys.stdout.write("\033]1;%s\007" % (fixed_cwd)) sys.stdout.flush() self.win.refresh() def finalize(self): """Finalize every object in container and refresh the window""" DisplayableContainer.finalize(self) self.win.refresh() def draw_images(self): if self.pager.visible: self.pager.draw_image() elif self.browser.pager.visible: self.browser.pager.draw_image() else: self.browser.columns[-1].draw_image() def close_pager(self): if self.console.visible: self.console.focused = True self.pager.close() self.pager.visible = False self.pager.focused = False self.browser.visible = True def open_pager(self): self.browser.columns[-1].clear_image(force=True) if self.console.focused: self.console.focused = False self.pager.open() self.pager.visible = True self.pager.focused = True self.browser.visible = False return self.pager def open_embedded_pager(self): self.browser.open_pager() for column in self.browser.columns: if column == self.browser.main_column: break column.level_shift(amount=1) return self.browser.pager def close_embedded_pager(self): self.browser.close_pager() for column in self.browser.columns: column.level_restore() def open_console(self, string='', prompt=None, position=None): if self.console.open(string, prompt=prompt, position=position): self.status.msg = None def close_console(self): self.console.close() self.close_pager() def open_taskview(self): self.browser.columns[-1].clear_image(force=True) self.pager.close() self.pager.visible = False self.pager.focused = False self.console.visible = False self.browser.visible = False self.taskview.visible = True self.taskview.focused = True def redraw_main_column(self): self.browser.main_column.need_redraw = True def close_taskview(self): self.taskview.visible = False self.browser.visible = True self.taskview.focused = False def throbber(self, string='.', remove=False): if remove: self.titlebar.throbber = type(self.titlebar).throbber else: self.titlebar.throbber = string def hint(self, text=None): self.status.hint = text def get_pager(self): if self.browser.pager.visible: return self.browser.pager else: return self.pager