def setup(self): """Build up the UI by initializing widgets.""" # 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 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)
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)
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
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 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 def __init__(self, env=None, fm=None): self._draw_title = os.environ["TERM"] in TERMINALS_WITH_TITLE os.environ["ESCDELAY"] = "25" # don't know a cleaner way if env is not None: self.env = env if fm is not None: self.fm = fm 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.env.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.update_size() self.is_on = True 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""" self.suspend() DisplayableContainer.destroy(self) 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.env.keybuffer.clear() elif not DisplayableContainer.press(self, key): self.env.keymaps.use_keymap("browser") self.press(key) def press(self, key): keybuffer = self.env.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() 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.env.termsize = self.win.getmaxyx() y, x = self.env.termsize self.browser.resize(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(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.env.cwd.path if cwd.startswith(self.env.home_path): cwd = "~" + cwd[len(self.env.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: sys.stdout.write("\033]2;ranger:" + cwd + "\007") except UnicodeEncodeError: sys.stdout.write("\033]2;ranger:" + ascii_only(cwd) + "\007") 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): 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() return self.browser.pager def close_embedded_pager(self): self.browser.close_pager() def open_console(self, string="", prompt=None, position=None): if self.console.open(string, prompt=prompt, position=position): self.status.msg = None self.console.on_close = self.close_console self.console.visible = True self.status.visible = False def close_console(self): self.console.visible = False self.status.visible = True self.close_pager() def open_taskview(self): 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(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
class DefaultUI(UI): def setup(self): """Build up the UI by initializing widgets.""" # 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 update_size(self): """resize all widgets""" UI.update_size(self) y, x = self.env.termsize self.browser.resize(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(y - 1, 0, 1, x) self.console.resize(y - 1, 0, 1, x) def notify(self, *a, **k): return self.status.notify(*a, **k) 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): 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() return self.browser.pager def close_embedded_pager(self): self.browser.close_pager() def open_console(self, string='', prompt=None, position=None): if self.console.open(string, prompt=prompt, position=position): self.status.msg = None self.console.on_close = self.close_console self.console.visible = True self.status.visible = False def close_console(self): self.console.visible = False self.status.visible = True self.close_pager() def open_taskview(self): 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 scroll(self, relative): if self.browser and self.browser.main_column: self.browser.main_column.scroll(relative) 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 DefaultUI(UI): def setup(self): """Build up the UI by initializing widgets.""" # 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 update_size(self): """resize all widgets""" UI.update_size(self) y, x = self.env.termsize self.browser.resize(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(y - 1, 0, 1, x) self.console.resize(y - 1, 0, 1, x) def notify(self, *a, **k): return self.status.notify(*a, **k) 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): 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() return self.browser.pager def close_embedded_pager(self): self.browser.close_pager() def open_console(self, string='', prompt=None, position=None): if self.console.open(string, prompt=prompt, position=position): self.status.msg = None self.console.on_close = self.close_console self.console.visible = True self.status.visible = False def close_console(self): self.console.visible = False self.status.visible = True self.close_pager() def open_taskview(self): 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 self.fm.hint('*tasks:* *dd*:remove *J*:move_down *H*:move_up') 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 scroll(self, relative): if self.browser and self.browser.main_column: self.browser.main_column.scroll(relative) 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