From e6e0eefaa42cca595f3d15a8cfe46ad725894b53 Mon Sep 17 00:00:00 2001 From: Asmageddon Date: Sat, 26 May 2012 13:24:38 +0200 Subject: [PATCH] Added (quite elaborate) inexact-case torrent name completion --- deluge/ui/console/main.py | 13 +++--- deluge/ui/console/modes/legacy.py | 71 +++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 10 deletions(-) diff --git a/deluge/ui/console/main.py b/deluge/ui/console/main.py index 9ec0279a4..01db19213 100644 --- a/deluge/ui/console/main.py +++ b/deluge/ui/console/main.py @@ -230,7 +230,7 @@ class ConsoleUI(component.Component): cmdr.exec_args(args,*daemon) else: cmdr.exec_args(args,None,None,None,None) - + self.coreconfig = CoreConfig() if self.interactive and not deluge.common.windows_check(): @@ -292,7 +292,7 @@ Please use commands from the command line, eg:\n client.core.get_torrents_status({"id": result}, ["name"]).addCallback(on_torrents_status) client.core.get_session_state().addCallback(on_session_state) - + def match_torrent(self, string): """ Returns a list of torrent_id matches for the string. It will search both @@ -306,13 +306,14 @@ Please use commands from the command line, eg:\n """ if self.interactive and isinstance(self.screen,deluge.ui.console.modes.legacy.Legacy): return self.screen.match_torrent(string) - ret = [] + matches = [] + string = string.decode(self.encoding) for tid, name in self.torrents: if tid.startswith(string) or name.startswith(string): - ret.append(tid) + matches.append(tid) - return ret + return matches def get_torrent_name(self, torrent_id): @@ -322,7 +323,7 @@ Please use commands from the command line, eg:\n for tid, name in self.torrents: if torrent_id == tid: return name - + return None diff --git a/deluge/ui/console/modes/legacy.py b/deluge/ui/console/modes/legacy.py index 6235a6fe9..4a6532904 100644 --- a/deluge/ui/console/modes/legacy.py +++ b/deluge/ui/console/modes/legacy.py @@ -52,11 +52,58 @@ strwidth = format_utils.strwidth import logging,os log = logging.getLogger(__name__) +import shlex import re LINES_BUFFER_SIZE = 5000 INPUT_HISTORY_SIZE = 500 +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): + if c.lower() != possible_matches[0][i].lower(): + maxlen = min(maxlen, i) + break + + return possible_matches[0][:maxlen].replace(" ", r"\ ") + +def commonprefix(m): + "Given a list of pathnames, returns the longest common leading component" + if not m: return '' + s1 = min(m) + s2 = max(m) + for i, c in enumerate(s1): + if c != s2[i]: + return s1[:i] + return s + + class Legacy(BaseMode): def __init__(self, stdscr, console_config, encoding=None): @@ -549,8 +596,11 @@ class Legacy(BaseMode): else: if hits == 1: p = " ".join(split(line)[:-1]) - new_line = " ".join([p, os.path.commonprefix(possible_matches)]).lstrip() - if len(new_line) > len(line): + + l_arg = shlex.split(line)[-1] + 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: @@ -617,13 +667,18 @@ class Legacy(BaseMode): line = line.replace("\\ ", " ") possible_matches = [] + possible_matches2 = [] - match_count = 0 + match_count = 0 + match_count2 = 0 for torrent_id, torrent_name in self.torrents: if torrent_id.startswith(line): match_count += 1 if torrent_name.startswith(line): match_count += 1 + elif torrent_name.lower().startswith(line.lower()): + match_count2 += 1 + # Find all possible matches for torrent_id, torrent_name in self.torrents: #Escape spaces to avoid, for example, expanding "Doc" into "Doctor Who" and removing everything containing one of these words @@ -636,6 +691,10 @@ class Legacy(BaseMode): if torrent_name.startswith(line): possible_matches.append(escaped_name) break + elif match_count == 0 and match_count2 == 1: + if torrent_name.lower().startswith(line.lower()): + possible_matches.append(escaped_name) + break else: l = len(raw_line) @@ -647,7 +706,11 @@ class Legacy(BaseMode): if torrent_name.startswith(line): text = "{!info!}%s{!input!}%s ({!cyan!}%s{!input!})" % (escaped_name[:l], escaped_name[l:], torrent_id) possible_matches.append(text) - return possible_matches + elif torrent_name.lower().startswith(line.lower()): + text = "{!info!}%s{!input!}%s ({!cyan!}%s{!input!})" % (escaped_name[:l], escaped_name[l:], torrent_id) + possible_matches2.append(text) + + return possible_matches + possible_matches2 def get_torrent_name(self, torrent_id): """