示例#1
0
文件: console.py 项目: tonttu/ranger
 def __init__(self, win):
     Widget.__init__(self, win)
     self.clear()
     self.history = History(self.settings.max_console_history_size)
     # load history from files
     if not ranger.arg.clean:
         self.historypath = self.fm.confpath('history')
         try:
             f = open(self.historypath, 'r')
         except:
             pass
         else:
             for line in f:
                 self.history.add(line[:-1])
             f.close()
示例#2
0
    def __init__(self, path):
        SignalDispatcher.__init__(self)
        self.path = abspath(expanduser(path))
        self._cf = None
        self.pathway = ()
        self.directories = {}
        self.keybuffer = KeyBuffer(None, None)
        self.keymanager = KeyManager(self.keybuffer, ALLOWED_CONTEXTS)
        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)
示例#3
0
文件: console.py 项目: ornicar/ranger
 def __init__(self, win):
     Widget.__init__(self, win)
     self.clear()
     self.history = History(self.settings.max_console_history_size)
     # load history from files
     if not ranger.arg.clean:
         self.historypath = self.fm.confpath("history")
         try:
             f = open(self.historypath, "r")
         except:
             pass
         else:
             for line in f:
                 self.history.add(line[:-1])
             f.close()
示例#4
0
    def __init__(self, path):
        SignalDispatcher.__init__(self)
        self.path = abspath(expanduser(path))
        self._cf = None
        self.pathway = ()
        self.directories = {}
        self.keybuffer = KeyBuffer(None, None)
        self.keymanager = KeyManager(self.keybuffer, ALLOWED_CONTEXTS)
        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)
示例#5
0
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
    keybuffer = None
    keymanager = None

    def __init__(self, path):
        SignalDispatcher.__init__(self)
        self.path = abspath(expanduser(path))
        self._cf = None
        self.pathway = ()
        self.directories = {}
        self.keybuffer = KeyBuffer(None, None)
        self.keymanager = KeyManager(self.keybuffer, ALLOWED_CONTEXTS)
        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):
        """Delete unused directory objects"""
        for key in tuple(self.directories):
            value = self.directories[key]
            if value.is_older_than(age) and not value in self.pathway:
                del self.directories[key]
                if value.is_directory:
                    value.files = None

    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
示例#6
0
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
    keybuffer = None
    keymanager = None

    def __init__(self, path):
        SignalDispatcher.__init__(self)
        self.path = abspath(expanduser(path))
        self._cf = None
        self.pathway = ()
        self.directories = {}
        self.keybuffer = KeyBuffer(None, None)
        self.keymanager = KeyManager(self.keybuffer, ALLOWED_CONTEXTS)
        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):
        """Delete unused directory objects"""
        for key in tuple(self.directories):
            value = self.directories[key]
            if age == -1 or \
              (value.is_older_than(age) and not value in self.pathway):
                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
示例#7
0
文件: console.py 项目: tonttu/ranger
class Console(Widget):
    visible = False
    last_cursor_mode = None
    history_search_pattern = None
    prompt = ':'
    copy = ''
    tab_deque = None
    original_line = None
    history = None
    override = None
    allow_close = False
    historypath = None

    def __init__(self, win):
        Widget.__init__(self, win)
        self.clear()
        self.history = History(self.settings.max_console_history_size)
        # load history from files
        if not ranger.arg.clean:
            self.historypath = self.fm.confpath('history')
            try:
                f = open(self.historypath, 'r')
            except:
                pass
            else:
                for line in f:
                    self.history.add(line[:-1])
                f.close()

    def destroy(self):
        # save history to files
        if ranger.arg.clean or not self.settings.save_console_history:
            return
        if self.historypath:
            try:
                f = open(self.historypath, 'w')
            except:
                pass
            else:
                for entry in self.history:
                    f.write(entry + '\n')
                f.close()

    def draw(self):
        self.win.erase()
        self.addstr(0, 0, self.prompt)
        if self.fm.py3:
            overflow = -self.wid + len(self.prompt) + len(self.line) + 1
        else:
            overflow = -self.wid + len(self.prompt) + uwid(self.line) + 1
        if overflow > 0:
            #XXX: cut uft-char-wise, consider width
            self.addstr(self.line[overflow:])
        else:
            self.addstr(self.line)

    def finalize(self):
        try:
            if self.fm.py3:
                xpos = sum(utf_char_width_(ord(c)) for c in self.line[0:self.pos]) \
                 + len(self.prompt)
            else:
                xpos = uwid(self.line[0:self.pos]) + len(self.prompt)
            self.fm.ui.win.move(self.y, self.x + min(self.wid - 1, xpos))
        except:
            pass

    def open(self, string='', prompt=None, position=None):
        if prompt is not None:
            assert isinstance(prompt, str)
            self.prompt = prompt
        elif 'prompt' in self.__dict__:
            del self.prompt

        if self.last_cursor_mode is None:
            try:
                self.last_cursor_mode = curses.curs_set(1)
            except:
                pass
        self.allow_close = False
        self.tab_deque = None
        self.focused = True
        self.visible = True
        self.unicode_buffer = ""
        self.line = string
        self.history_search_pattern = self.line
        self.pos = len(string)
        if position is not None:
            self.pos = min(self.pos, position)
        self.history.fast_forward()
        self.history.add('')
        return True

    def close(self):
        if self.last_cursor_mode is not None:
            try:
                curses.curs_set(self.last_cursor_mode)
            except:
                pass
            self.last_cursor_mode = None
        self.add_to_history()
        self.tab_deque = None
        self.clear()
        self.__class__ = Console
        self.focused = False
        self.visible = False
        if hasattr(self, 'on_close'):
            self.on_close()

    def clear(self):
        self.pos = 0
        self.line = ''

    def press(self, key):
        self.env.keymanager.use_context('console')
        self.env.key_append(key)
        kbuf = self.env.keybuffer
        cmd = kbuf.command

        if kbuf.failure:
            kbuf.clear()
            return
        elif not cmd:
            return

        self.env.cmd = cmd

        if cmd.function:
            try:
                cmd.function(CommandArgs.from_widget(self))
            except Exception as error:
                self.fm.notify(error)
            if kbuf.done:
                kbuf.clear()
        else:
            kbuf.clear()

    def type_key(self, key):
        self.tab_deque = None

        if isinstance(key, int):
            try:
                key = chr(key)
            except ValueError:
                return

        if self.fm.py3:
            self.unicode_buffer += key
            try:
                decoded = self.unicode_buffer.encode("latin-1").decode("utf-8")
            except UnicodeDecodeError:
                pass
            else:
                self.unicode_buffer = ""
                if self.pos == len(self.line):
                    self.line += decoded
                else:
                    pos = self.pos
                    self.line = self.line[:pos] + decoded + self.line[pos:]
                self.pos += len(decoded)
        else:
            if self.pos == len(self.line):
                self.line += key
            else:
                self.line = self.line[:self.pos] + key + self.line[self.pos:]
            self.pos += len(key)

        self.on_line_change()

    def history_move(self, n):
        try:
            current = self.history.current()
        except HistoryEmptyException:
            pass
        else:
            if self.line != current and self.line != self.history.top():
                self.history.modify(self.line)
            if self.history_search_pattern:
                self.history.search(self.history_search_pattern, n)
            else:
                self.history.move(n)
            current = self.history.current()
            if self.line != current:
                self.line = self.history.current()
                self.pos = len(self.line)

    def add_to_history(self):
        self.history.fast_forward()
        self.history.modify(self.line, unique=True)

    def move(self, **keywords):
        direction = Direction(keywords)
        if direction.horizontal():
            # Ensure that the pointer is moved utf-char-wise
            if self.fm.py3:
                self.pos = direction.move(direction=direction.right(),
                                          minimum=0,
                                          maximum=len(self.line) + 1,
                                          current=self.pos)
            else:
                uc = uchars(self.line)
                upos = len(uchars(self.line[:self.pos]))
                newupos = direction.move(direction=direction.right(),
                                         minimum=0,
                                         maximum=len(uc) + 1,
                                         current=upos)
                self.pos = len(''.join(uc[:newupos]))

    def delete_rest(self, direction):
        self.tab_deque = None
        if direction > 0:
            self.copy = self.line[self.pos:]
            self.line = self.line[:self.pos]
        else:
            self.copy = self.line[:self.pos]
            self.line = self.line[self.pos:]
            self.pos = 0
        self.on_line_change()

    def paste(self):
        if self.pos == len(self.line):
            self.line += self.copy
        else:
            self.line = self.line[:self.pos] + self.copy + self.line[self.pos:]
        self.pos += len(self.copy)
        self.on_line_change()

    def delete_word(self, backward=True):
        if self.line:
            self.tab_deque = None
            if backward:
                right_part = self.line[self.pos:]
                i = self.pos - 2
                while i >= 0 and re.match(r'[\w\d]', self.line[i], re.U):
                    i -= 1
                self.copy = self.line[i + 1:self.pos]
                self.line = self.line[:i + 1] + right_part
                self.pos = i + 1
            else:
                left_part = self.line[:self.pos]
                i = self.pos + 1
                while i < len(self.line) and re.match(r'[\w\d]', self.line[i],
                                                      re.U):
                    i += 1
                self.copy = self.line[self.pos:i]
                if i >= len(self.line):
                    self.line = left_part
                    self.pos = len(self.line)
                else:
                    self.line = left_part + self.line[i:]
                    self.pos = len(left_part)
            self.on_line_change()

    def delete(self, mod):
        self.tab_deque = None
        if mod == -1 and self.pos == 0:
            if not self.line:
                self.close()
            return
        # Delete utf-char-wise
        if self.fm.py3:
            left_part = self.line[:self.pos + mod]
            self.pos = len(left_part)
            self.line = left_part + self.line[self.pos + 1:]
        else:
            uc = uchars(self.line)
            upos = len(uchars(self.line[:self.pos])) + mod
            left_part = ''.join(uc[:upos])
            self.pos = len(left_part)
            self.line = left_part + ''.join(uc[upos + 1:])
        self.on_line_change()

    def execute(self, cmd=None):
        self.allow_close = True
        if cmd is None:
            cmd = self._get_cmd()

        if cmd:
            try:
                cmd.execute()
            except Exception as error:
                self.fm.notify(error)

        if self.allow_close:
            self.close()

    def _get_cmd(self):
        try:
            command_class = self._get_cmd_class()
        except KeyError:
            self.fm.notify("Invalid command! Press ? for help.", bad=True)
        except:
            return None
        else:
            return command_class(self.line)

    def _get_cmd_class(self):
        return self.fm.commands.get_command(self.line.split()[0])

    def _get_tab(self):
        if ' ' in self.line:
            cmd = self._get_cmd()
            if cmd:
                return cmd.tab()
            else:
                return None

        return self.fm.commands.command_generator(self.line)

    def tab(self, n=1):
        if self.tab_deque is None:
            tab_result = self._get_tab()

            if isinstance(tab_result, str):
                self.line = tab_result
                self.pos = len(tab_result)
                self.on_line_change()

            elif tab_result == None:
                pass

            elif hasattr(tab_result, '__iter__'):
                self.tab_deque = deque(tab_result)
                self.tab_deque.appendleft(self.line)

        if self.tab_deque is not None:
            self.tab_deque.rotate(-n)
            self.line = self.tab_deque[0]
            self.pos = len(self.line)
            self.on_line_change()

    def on_line_change(self):
        self.history_search_pattern = self.line
        try:
            cls = self._get_cmd_class()
        except (KeyError, ValueError, IndexError):
            pass
        else:
            cmd = cls(self.line)
            if cmd and cmd.quick():
                self.execute(cmd)
示例#8
0
    def test_history(self):
        hist = History(3)
        for i in range(6):
            hist.add(i)
        self.assertEqual([3, 4, 5], list(hist))

        hist.back()

        self.assertEqual(4, hist.current())
        self.assertEqual([3, 4], list(hist._left()))

        self.assertEqual(5, hist.top())

        hist.back()
        self.assertEqual(3, hist.current())
        self.assertEqual([3], list(hist._left()))

        # no change if current == bottom
        self.assertEqual(hist.current(), hist.bottom())
        last = hist.current()
        hist.back()
        self.assertEqual(hist.current(), last)

        self.assertEqual(5, hist.top())

        hist.forward()
        hist.forward()
        self.assertEqual(5, hist.current())
        self.assertEqual([3, 4, 5], list(hist._left()))

        self.assertEqual(3, hist.bottom())
        hist.add(6)
        self.assertEqual(4, hist.bottom())
        self.assertEqual([4, 5, 6], list(hist._left()))

        hist.back()
        hist.fast_forward()
        self.assertEqual([4, 5, 6], list(hist._left()))
        hist.back()
        hist.back()
        hist.fast_forward()
        self.assertEqual([4, 5, 6], list(hist._left()))
        hist.back()
        hist.back()
        hist.back()
        hist.fast_forward()
        self.assertEqual([4, 5, 6], list(hist._left()))
        hist.back()
        hist.back()
        hist.back()
        hist.back()
        hist.fast_forward()
        self.assertEqual([4, 5, 6], list(hist._left()))
示例#9
0
文件: console.py 项目: ornicar/ranger
class Console(Widget):
    visible = False
    last_cursor_mode = None
    history_search_pattern = None
    prompt = ":"
    copy = ""
    tab_deque = None
    original_line = None
    history = None
    override = None
    allow_close = False
    historypath = None

    def __init__(self, win):
        Widget.__init__(self, win)
        self.clear()
        self.history = History(self.settings.max_console_history_size)
        # load history from files
        if not ranger.arg.clean:
            self.historypath = self.fm.confpath("history")
            try:
                f = open(self.historypath, "r")
            except:
                pass
            else:
                for line in f:
                    self.history.add(line[:-1])
                f.close()

    def destroy(self):
        # save history to files
        if ranger.arg.clean or not self.settings.save_console_history:
            return
        if self.historypath:
            try:
                f = open(self.historypath, "w")
            except:
                pass
            else:
                for entry in self.history:
                    f.write(entry + "\n")
                f.close()

    def draw(self):
        self.win.erase()
        self.addstr(0, 0, self.prompt)
        if self.fm.py3:
            overflow = -self.wid + len(self.prompt) + len(self.line) + 1
        else:
            overflow = -self.wid + len(self.prompt) + uwid(self.line) + 1
        if overflow > 0:
            # XXX: cut uft-char-wise, consider width
            self.addstr(self.line[overflow:])
        else:
            self.addstr(self.line)

    def finalize(self):
        try:
            if self.fm.py3:
                xpos = sum(utf_char_width_(ord(c)) for c in self.line[0 : self.pos]) + len(self.prompt)
            else:
                xpos = uwid(self.line[0 : self.pos]) + len(self.prompt)
            self.fm.ui.win.move(self.y, self.x + min(self.wid - 1, xpos))
        except:
            pass

    def open(self, string="", prompt=None, position=None):
        if prompt is not None:
            assert isinstance(prompt, str)
            self.prompt = prompt
        elif "prompt" in self.__dict__:
            del self.prompt

        if self.last_cursor_mode is None:
            try:
                self.last_cursor_mode = curses.curs_set(1)
            except:
                pass
        self.allow_close = False
        self.tab_deque = None
        self.focused = True
        self.visible = True
        self.unicode_buffer = ""
        self.line = string
        self.history_search_pattern = self.line
        self.pos = len(string)
        if position is not None:
            self.pos = min(self.pos, position)
        self.history.fast_forward()
        self.history.add("")
        return True

    def close(self):
        if self.last_cursor_mode is not None:
            try:
                curses.curs_set(self.last_cursor_mode)
            except:
                pass
            self.last_cursor_mode = None
        self.add_to_history()
        self.tab_deque = None
        self.clear()
        self.__class__ = Console
        self.focused = False
        self.visible = False
        if hasattr(self, "on_close"):
            self.on_close()

    def clear(self):
        self.pos = 0
        self.line = ""

    def press(self, key):
        self.env.keymanager.use_context("console")
        self.env.key_append(key)
        kbuf = self.env.keybuffer
        cmd = kbuf.command

        if kbuf.failure:
            kbuf.clear()
            return
        elif not cmd:
            return

        self.env.cmd = cmd

        if cmd.function:
            try:
                cmd.function(CommandArgs.from_widget(self))
            except Exception as error:
                self.fm.notify(error)
            if kbuf.done:
                kbuf.clear()
        else:
            kbuf.clear()

    def type_key(self, key):
        self.tab_deque = None

        if isinstance(key, int):
            try:
                key = chr(key)
            except ValueError:
                return

        if self.fm.py3:
            self.unicode_buffer += key
            try:
                decoded = self.unicode_buffer.encode("latin-1").decode("utf-8")
            except UnicodeDecodeError:
                pass
            else:
                self.unicode_buffer = ""
                if self.pos == len(self.line):
                    self.line += decoded
                else:
                    pos = self.pos
                    self.line = self.line[:pos] + decoded + self.line[pos:]
                self.pos += len(decoded)
        else:
            if self.pos == len(self.line):
                self.line += key
            else:
                self.line = self.line[: self.pos] + key + self.line[self.pos :]
            self.pos += len(key)

        self.on_line_change()

    def history_move(self, n):
        try:
            current = self.history.current()
        except HistoryEmptyException:
            pass
        else:
            if self.line != current and self.line != self.history.top():
                self.history.modify(self.line)
            if self.history_search_pattern:
                self.history.search(self.history_search_pattern, n)
            else:
                self.history.move(n)
            current = self.history.current()
            if self.line != current:
                self.line = self.history.current()
                self.pos = len(self.line)

    def add_to_history(self):
        self.history.fast_forward()
        self.history.modify(self.line, unique=True)

    def move(self, **keywords):
        direction = Direction(keywords)
        if direction.horizontal():
            # Ensure that the pointer is moved utf-char-wise
            if self.fm.py3:
                self.pos = direction.move(
                    direction=direction.right(), minimum=0, maximum=len(self.line) + 1, current=self.pos
                )
            else:
                uc = uchars(self.line)
                upos = len(uchars(self.line[: self.pos]))
                newupos = direction.move(direction=direction.right(), minimum=0, maximum=len(uc) + 1, current=upos)
                self.pos = len("".join(uc[:newupos]))

    def delete_rest(self, direction):
        self.tab_deque = None
        if direction > 0:
            self.copy = self.line[self.pos :]
            self.line = self.line[: self.pos]
        else:
            self.copy = self.line[: self.pos]
            self.line = self.line[self.pos :]
            self.pos = 0
        self.on_line_change()

    def paste(self):
        if self.pos == len(self.line):
            self.line += self.copy
        else:
            self.line = self.line[: self.pos] + self.copy + self.line[self.pos :]
        self.pos += len(self.copy)
        self.on_line_change()

    def delete_word(self):
        if self.line:
            self.tab_deque = None
            i = len(self.line) - 2
            while i >= 0 and re.match(r"[\w\d]", self.line[i], re.U):
                i -= 1
            self.copy = self.line[i + 1 :]
            self.line = self.line[: i + 1]
            self.pos = len(self.line)
            self.on_line_change()

    def delete(self, mod):
        self.tab_deque = None
        if mod == -1 and self.pos == 0:
            if not self.line:
                self.close()
            return
            # Delete utf-char-wise
        if self.fm.py3:
            left_part = self.line[: self.pos + mod]
            self.pos = len(left_part)
            self.line = left_part + self.line[self.pos + 1 :]
        else:
            uc = uchars(self.line)
            upos = len(uchars(self.line[: self.pos])) + mod
            left_part = "".join(uc[:upos])
            self.pos = len(left_part)
            self.line = left_part + "".join(uc[upos + 1 :])
        self.on_line_change()

    def execute(self, cmd=None):
        self.allow_close = True
        if cmd is None:
            cmd = self._get_cmd()

        if cmd:
            try:
                cmd.execute()
            except Exception as error:
                self.fm.notify(error)

        if self.allow_close:
            self.close()

    def _get_cmd(self):
        try:
            command_class = self._get_cmd_class()
        except KeyError:
            self.fm.notify("Invalid command! Press ? for help.", bad=True)
        except:
            return None
        else:
            return command_class(self.line)

    def _get_cmd_class(self):
        return self.fm.commands.get_command(self.line.split()[0])

    def _get_tab(self):
        if " " in self.line:
            cmd = self._get_cmd()
            if cmd:
                return cmd.tab()
            else:
                return None

        return self.fm.commands.command_generator(self.line)

    def tab(self, n=1):
        if self.tab_deque is None:
            tab_result = self._get_tab()

            if isinstance(tab_result, str):
                self.line = tab_result
                self.pos = len(tab_result)
                self.on_line_change()

            elif tab_result == None:
                pass

            elif hasattr(tab_result, "__iter__"):
                self.tab_deque = deque(tab_result)
                self.tab_deque.appendleft(self.line)

        if self.tab_deque is not None:
            self.tab_deque.rotate(-n)
            self.line = self.tab_deque[0]
            self.pos = len(self.line)
            self.on_line_change()

    def on_line_change(self):
        self.history_search_pattern = self.line
        try:
            cls = self._get_cmd_class()
        except (KeyError, ValueError, IndexError):
            pass
        else:
            cmd = cls(self.line)
            if cmd and cmd.quick():
                self.execute(cmd)
示例#10
0
	def test_history(self):
		hist = History(3)
		for i in range(6):
			hist.add(i)
		self.assertEqual([3,4,5], list(hist))

		hist.back()

		self.assertEqual(4, hist.current())
		self.assertEqual([3,4], list(hist._left()))

		self.assertEqual(5, hist.top())

		hist.back()
		self.assertEqual(3, hist.current())
		self.assertEqual([3], list(hist._left()))

		# no change if current == bottom
		self.assertEqual(hist.current(), hist.bottom())
		last = hist.current()
		hist.back()
		self.assertEqual(hist.current(), last)

		self.assertEqual(5, hist.top())

		hist.forward()
		hist.forward()
		self.assertEqual(5, hist.current())
		self.assertEqual([3,4,5], list(hist._left()))


		self.assertEqual(3, hist.bottom())
		hist.add(6)
		self.assertEqual(4, hist.bottom())
		self.assertEqual([4,5,6], list(hist._left()))

		hist.back()
		hist.fast_forward()
		self.assertEqual([4,5,6], list(hist._left()))
		hist.back()
		hist.back()
		hist.fast_forward()
		self.assertEqual([4,5,6], list(hist._left()))
		hist.back()
		hist.back()
		hist.back()
		hist.fast_forward()
		self.assertEqual([4,5,6], list(hist._left()))
		hist.back()
		hist.back()
		hist.back()
		hist.back()
		hist.fast_forward()
		self.assertEqual([4,5,6], list(hist._left()))