Beispiel #1
0
def complete_line(line, possible_matches):
    "Find the common prefix of possible matches, proritizing matching-case elements"

    if not possible_matches: return line

    line = line.replace(r"\ ", " ")

    matches1 = []
    matches2 = []

    for match in possible_matches:
        match = format_utils.remove_formatting(match)
        match = match.replace(r"\ ", " ")
        m1, m2 = "", ""
        for i, c in enumerate(line):
            if m1 and m2: break
            if not m1 and c != line[i]:
                m1 = line[:i]
            if not m2 and c.lower() != line[i].lower():
                m2 = line[:i]
        if   not m1: matches1.append(match)
        elif not m2: matches2.append(match)

    possible_matches = matches1 + matches2

    maxlen = 9001

    for match in possible_matches[1:]:
        for i, c in enumerate(match):
            try:
                if c.lower() != possible_matches[0][i].lower():
                    maxlen = min(maxlen, i)
                    break
            except IndexError:
                maxlen = min(maxlen, i)
                break

    return possible_matches[0][:maxlen].replace(" ", r"\ ")
Beispiel #2
0
def complete_line(line, possible_matches):
    "Find the common prefix of possible matches, proritizing matching-case elements"

    if not possible_matches: return line

    line = line.replace(r"\ ", " ")

    matches1 = []
    matches2 = []

    for match in possible_matches:
        match = format_utils.remove_formatting(match)
        match = match.replace(r"\ ", " ")
        m1, m2 = "", ""
        for i, c in enumerate(line):
            if m1 and m2: break
            if not m1 and c != line[i]:
                m1 = line[:i]
            if not m2 and c.lower() != line[i].lower():
                m2 = line[:i]
        if not m1: matches1.append(match)
        elif not m2: matches2.append(match)

    possible_matches = matches1 + matches2

    maxlen = 9001

    for match in possible_matches[1:]:
        for i, c in enumerate(match):
            try:
                if c.lower() != possible_matches[0][i].lower():
                    maxlen = min(maxlen, i)
                    break
            except IndexError:
                maxlen = min(maxlen, i)
                break

    return possible_matches[0][:maxlen].replace(" ", r"\ ")
Beispiel #3
0
    def tab_completer(self, line, cursor, hits):
        """
        Called when the user hits 'tab' and will autocomplete or show options.
        If a command is already supplied in the line, this function will call the
        complete method of the command.

        :param line: str, the current input string
        :param cursor: int, the cursor position in the line
        :param second_hit: bool, if this is the second time in a row the tab key
            has been pressed

        :returns: 2-tuple (string, cursor position)

        """
        # First check to see if there is no space, this will mean that it's a
        # command that needs to be completed.

        #We don't want to split by escaped spaces
        def split(string):
            return re.split(r"(?<!\\) ", string)

        if " " not in line:
            possible_matches = []
            # Iterate through the commands looking for ones that startwith the
            # line.
            for cmd in self.console._commands:
                if cmd.startswith(line):
                    possible_matches.append(cmd)

            line_prefix = ""
        else:
            cmd = split(line)[0]
            if cmd in self.console._commands:
                # Call the command's complete method to get 'er done
                possible_matches = self.console._commands[cmd].complete(split(line)[-1])
                line_prefix = " ".join(split(line)[:-1]) + " "
            else:
                # This is a bogus command
                return (line, cursor)

        # No matches, so just return what we got passed
        if len(possible_matches) == 0:
            return (line, cursor)
        # If we only have 1 possible match, then just modify the line and
        # return it, else we need to print out the matches without modifying
        # the line.
        elif len(possible_matches) == 1:
            #Do not append space after directory names
            new_line = line_prefix + possible_matches[0]
            if not new_line.endswith("/") and not new_line.endswith(r"\\"):
                new_line += " "
            #We only want to print eventual colors or other control characters, not return them
            new_line = format_utils.remove_formatting(new_line)
            return (new_line, len(new_line))
        else:
            if   hits == 1:
                p = " ".join(split(line)[:-1])

                try:
                    l_arg = split(line)[-1]
                except IndexError:
                    l_arg = ""

                new_line = " ".join( [p, complete_line(l_arg, possible_matches)] ).lstrip()

                if len(format_utils.remove_formatting(new_line)) > len(line):
                    line = new_line
                    cursor = len(line)
            elif hits >= 2:
                max_list = self.console_config["torrents_per_tab_press"]
                match_count = len(possible_matches)
                listed = (hits-2) * max_list
                pages = (match_count-1) // max_list + 1
                left = match_count - listed
                if hits == 2:
                    self.write(" ")

                    if match_count >= 4:
                        self.write("{!green!}Autocompletion matches:")
                #Only list some of the matching torrents as there can be hundreds of them
                if self.console_config["third_tab_lists_all"]:
                    if hits == 2 and left > max_list:
                        for i in range(listed, listed + max_list):
                            match = possible_matches[i]
                            self.write(match.replace(r"\ ", " "))
                        self.write("{!error!}And %i more. Press <tab> to list them" % (left - max_list) )
                    else:
                        self.tab_count = 0
                        for match in possible_matches[listed:]:
                            self.write(match.replace(r"\ ", " "))
                else:
                    if left > max_list:
                        for i in range(listed, listed + max_list):
                            match = possible_matches[i]
                            self.write(match.replace(r"\ ", " "))
                        self.write("{!error!}And %i more (%i/%i). Press <tab> to view more" % (left - max_list, hits-1, pages) )
                    else:
                        self.tab_count = 0
                        for match in possible_matches[listed:]:
                            self.write(match.replace(r"\ ", " "))
                        if hits > 2:
                            self.write("{!green!}Finished listing %i torrents (%i/%i)" % (match_count, hits-1, pages) )

            #We only want to print eventual colors or other control characters, not return them
            line = format_utils.remove_formatting(line)
            cursor = len(line)
            return (line, cursor)
Beispiel #4
0
    def __init__(self, stdscr, encoding=None):

        component.Component.__init__(self, "LegacyUI", 1, depend=["SessionProxy"])

        self.batch_write = False

        # A list of strings to be displayed based on the offset (scroll)
        self.lines = []
        # The offset to display lines
        self.display_lines_offset = 0

        # Holds the user input and is cleared on 'enter'
        self.input = ""
        self.input_incomplete = ""
        self._old_char = 0
        self._last_char = 0
        self._last_del_char = ''

        # Keep track of where the cursor is
        self.input_cursor = 0
        # Keep a history of inputs
        self.input_history = []
        self.input_history_index = 0

        # Keep track of double- and multi-tabs
        self.tab_count = 0

        # Get a handle to the main console
        self.console = component.get("ConsoleUI")

        self.console_config = component.get("AllTorrents").config

        #To avoid having to truncate the file every time we're writing
        # or doing it on exit(and therefore relying on an error-less
        # or in other words clean exit, we're going to have two files
        # that we swap around based on length
        config_dir = deluge.configmanager.get_config_dir()
        self.history_file = [
            os.path.join(config_dir, "legacy.hist1"),
            os.path.join(config_dir, "legacy.hist2")
        ]
        self._hf_lines = [0, 0]

        if self.console_config["save_legacy_history"]:
            try:
                lines1 = open(self.history_file[0], 'r').read().splitlines()
                self._hf_lines[0] = len(lines1)
            except:
                lines1 = []
                self._hf_lines[0] = 0

            try:
                lines2 = open(self.history_file[1], 'r').read().splitlines()
                self._hf_lines[1] = len(lines2)
            except:
                lines2 = []
                self._hf_lines[1] = 0

            #The non-full file is the active one
            if self._hf_lines[0] > self._hf_lines[1]:
                self.lines = lines1 + lines2
            else:
                self.lines = lines2 + lines1

            if len(self.lines) > MAX_HISTFILE_SIZE:
                self.lines = self.lines[-MAX_HISTFILE_SIZE:]

            #Instead of having additional input history file, we can
            # simply scan for lines beginning with ">>> "
            for i, line in enumerate(self.lines):
                #if not isinstance(line, unicode):
                    #line = line.encode(self.encoding)
                    #self.lines[i] = line
                line = format_utils.remove_formatting(line)
                if line.startswith(">>> "):
                    input = line[4:]
                    if self.console_config["ignore_duplicate_lines"]:
                        if len(self.input_history) > 0:
                            if self.input_history[-1] != input:
                                self.input_history.append(input)
                        else:
                            self.input_history.append(input)

            self.input_history_index = len(self.input_history)

            component.start("LegacyUI")


        # show the cursor
        curses.curs_set(2)

        BaseMode.__init__(self, stdscr, encoding)

        # This gets fired once we have received the torrents list from the core
        self.started_deferred = defer.Deferred()

        # Maintain a list of (torrent_id, name) for use in tab completion
        self.torrents = []
        def on_session_state(result):
            def on_torrents_status(torrents):
                for torrent_id, status in torrents.items():
                    self.torrents.append((torrent_id, status["name"]))
                self.started_deferred.callback(True)

            client.core.get_torrents_status({"id": result}, ["name"]).addCallback(on_torrents_status)
        client.core.get_session_state().addCallback(on_session_state)

        # Register some event handlers to keep the torrent list up-to-date
        client.register_event_handler("TorrentAddedEvent", self.on_torrent_added_event)
        client.register_event_handler("TorrentRemovedEvent", self.on_torrent_removed_event)
Beispiel #5
0
    def tab_completer(self, line, cursor, hits):
        """
        Called when the user hits 'tab' and will autocomplete or show options.
        If a command is already supplied in the line, this function will call the
        complete method of the command.

        :param line: str, the current input string
        :param cursor: int, the cursor position in the line
        :param second_hit: bool, if this is the second time in a row the tab key
            has been pressed

        :returns: 2-tuple (string, cursor position)

        """

        # First check to see if there is no space, this will mean that it's a
        # command that needs to be completed.

        #We don't want to split by escaped spaces
        def split(string):
            return re.split(r"(?<!\\) ", string)

        if " " not in line:
            possible_matches = []
            # Iterate through the commands looking for ones that startwith the
            # line.
            for cmd in self.console._commands:
                if cmd.startswith(line):
                    possible_matches.append(cmd)

            line_prefix = ""
        else:
            cmd = split(line)[0]
            if cmd in self.console._commands:
                # Call the command's complete method to get 'er done
                possible_matches = self.console._commands[cmd].complete(
                    split(line)[-1])
                line_prefix = " ".join(split(line)[:-1]) + " "
            else:
                # This is a bogus command
                return (line, cursor)

        # No matches, so just return what we got passed
        if len(possible_matches) == 0:
            return (line, cursor)
        # If we only have 1 possible match, then just modify the line and
        # return it, else we need to print out the matches without modifying
        # the line.
        elif len(possible_matches) == 1:
            #Do not append space after directory names
            new_line = line_prefix + possible_matches[0]
            if not new_line.endswith("/") and not new_line.endswith(r"\\"):
                new_line += " "
            #We only want to print eventual colors or other control characters, not return them
            new_line = format_utils.remove_formatting(new_line)
            return (new_line, len(new_line))
        else:
            if hits == 1:
                p = " ".join(split(line)[:-1])

                try:
                    l_arg = split(line)[-1]
                except IndexError:
                    l_arg = ""

                new_line = " ".join(
                    [p, complete_line(l_arg, possible_matches)]).lstrip()

                if len(format_utils.remove_formatting(new_line)) > len(line):
                    line = new_line
                    cursor = len(line)
            elif hits >= 2:
                max_list = self.console_config["torrents_per_tab_press"]
                match_count = len(possible_matches)
                listed = (hits - 2) * max_list
                pages = (match_count - 1) // max_list + 1
                left = match_count - listed
                if hits == 2:
                    self.write(" ")

                    if match_count >= 4:
                        self.write("{!green!}Autocompletion matches:")
                #Only list some of the matching torrents as there can be hundreds of them
                if self.console_config["third_tab_lists_all"]:
                    if hits == 2 and left > max_list:
                        for i in range(listed, listed + max_list):
                            match = possible_matches[i]
                            self.write(match.replace(r"\ ", " "))
                        self.write(
                            "{!error!}And %i more. Press <tab> to list them" %
                            (left - max_list))
                    else:
                        self.tab_count = 0
                        for match in possible_matches[listed:]:
                            self.write(match.replace(r"\ ", " "))
                else:
                    if left > max_list:
                        for i in range(listed, listed + max_list):
                            match = possible_matches[i]
                            self.write(match.replace(r"\ ", " "))
                        self.write(
                            "{!error!}And %i more (%i/%i). Press <tab> to view more"
                            % (left - max_list, hits - 1, pages))
                    else:
                        self.tab_count = 0
                        for match in possible_matches[listed:]:
                            self.write(match.replace(r"\ ", " "))
                        if hits > 2:
                            self.write(
                                "{!green!}Finished listing %i torrents (%i/%i)"
                                % (match_count, hits - 1, pages))

            #We only want to print eventual colors or other control characters, not return them
            line = format_utils.remove_formatting(line)
            cursor = len(line)
            return (line, cursor)
Beispiel #6
0
    def __init__(self, stdscr, encoding=None):

        component.Component.__init__(self,
                                     "LegacyUI",
                                     1,
                                     depend=["SessionProxy"])

        self.batch_write = False

        # A list of strings to be displayed based on the offset (scroll)
        self.lines = []
        # The offset to display lines
        self.display_lines_offset = 0

        # Holds the user input and is cleared on 'enter'
        self.input = ""
        self.input_incomplete = ""
        self._old_char = 0
        self._last_char = 0
        self._last_del_char = ''

        # Keep track of where the cursor is
        self.input_cursor = 0
        # Keep a history of inputs
        self.input_history = []
        self.input_history_index = 0

        # Keep track of double- and multi-tabs
        self.tab_count = 0

        # Get a handle to the main console
        self.console = component.get("ConsoleUI")

        self.console_config = component.get("AllTorrents").config

        #To avoid having to truncate the file every time we're writing
        # or doing it on exit(and therefore relying on an error-less
        # or in other words clean exit, we're going to have two files
        # that we swap around based on length
        config_dir = deluge.configmanager.get_config_dir()
        self.history_file = [
            os.path.join(config_dir, "legacy.hist1"),
            os.path.join(config_dir, "legacy.hist2")
        ]
        self._hf_lines = [0, 0]

        if self.console_config["save_legacy_history"]:
            try:
                lines1 = open(self.history_file[0], 'r').read().splitlines()
                self._hf_lines[0] = len(lines1)
            except:
                lines1 = []
                self._hf_lines[0] = 0

            try:
                lines2 = open(self.history_file[1], 'r').read().splitlines()
                self._hf_lines[1] = len(lines2)
            except:
                lines2 = []
                self._hf_lines[1] = 0

            #The non-full file is the active one
            if self._hf_lines[0] > self._hf_lines[1]:
                self.lines = lines1 + lines2
            else:
                self.lines = lines2 + lines1

            if len(self.lines) > MAX_HISTFILE_SIZE:
                self.lines = self.lines[-MAX_HISTFILE_SIZE:]

            #Instead of having additional input history file, we can
            # simply scan for lines beginning with ">>> "
            for i, line in enumerate(self.lines):
                #if not isinstance(line, unicode):
                #line = line.encode(self.encoding)
                #self.lines[i] = line
                line = format_utils.remove_formatting(line)
                if line.startswith(">>> "):
                    input = line[4:]
                    if self.console_config["ignore_duplicate_lines"]:
                        if len(self.input_history) > 0:
                            if self.input_history[-1] != input:
                                self.input_history.append(input)
                        else:
                            self.input_history.append(input)

            self.input_history_index = len(self.input_history)

            component.start("LegacyUI")

        # show the cursor
        curses.curs_set(2)

        BaseMode.__init__(self, stdscr, encoding)

        # This gets fired once we have received the torrents list from the core
        self.started_deferred = defer.Deferred()

        # Maintain a list of (torrent_id, name) for use in tab completion
        self.torrents = []

        def on_session_state(result):
            def on_torrents_status(torrents):
                for torrent_id, status in torrents.items():
                    self.torrents.append((torrent_id, status["name"]))
                self.started_deferred.callback(True)

            client.core.get_torrents_status({
                "id": result
            }, ["name"]).addCallback(on_torrents_status)

        client.core.get_session_state().addCallback(on_session_state)

        # Register some event handlers to keep the torrent list up-to-date
        client.register_event_handler("TorrentAddedEvent",
                                      self.on_torrent_added_event)
        client.register_event_handler("TorrentRemovedEvent",
                                      self.on_torrent_removed_event)