Change color tags to '{! !}'

Add support for viewing config values
This commit is contained in:
Andrew Resch 2009-04-25 00:31:07 +00:00
parent 6d33ff9902
commit 753b93089f
11 changed files with 118 additions and 106 deletions

View File

@ -52,12 +52,12 @@ schemes = {
# Colors for various torrent states # Colors for various torrent states
state_color = { state_color = {
"Seeding": "{{blue,black,bold}}", "Seeding": "{!blue,black,bold!}",
"Downloading": "{{green,black,bold}}", "Downloading": "{!green,black,bold!}",
"Paused": "{{white,black}}", "Paused": "{!white,black!}",
"Checking": "{{green,black}}", "Checking": "{!green,black!}",
"Queued": "{{yellow,black}}", "Queued": "{!yellow,black!}",
"Error": "{{red,black,bold}}" "Error": "{!red,black,bold!}"
} }
def init_colors(): def init_colors():
@ -89,12 +89,12 @@ def get_line_length(line):
Returns the string length without the color formatting. Returns the string length without the color formatting.
""" """
if line.count("{{") != line.count ("}}"): if line.count("{!") != line.count("!}"):
raise BadColorString("Number of {{ does not equal number of }}") raise BadColorString("Number of {! is not equal to number of !}")
# Remove all the color tags # Remove all the color tags
while line.find("{{") != -1: while line.find("{!") != -1:
line = line[:line.find("{{")] + line[line.find("}}") + 2:] line = line[:line.find("{!")] + line[line.find("!}") + 2:]
# Replace tabs with the appropriate amount of spaces # Replace tabs with the appropriate amount of spaces
line = replace_tabs(line) line = replace_tabs(line)
@ -107,27 +107,26 @@ def parse_color_string(s):
:param s:, string to parse :param s:, string to parse
""" """
if s.count("{{") != s.count ("}}"): if s.count("{!") != s.count("!}"):
raise BadColorString("Number of {{ does not equal number of }}") raise BadColorString("Number of {! is not equal to number of !}")
ret = [] ret = []
# Keep track of where the strings # Keep track of where the strings
col_index = 0 col_index = 0
while s.find("{{") != -1: while s.find("{!") != -1:
begin = s.find("{{") begin = s.find("{!")
if begin > 0: if begin > 0:
ret.append((curses.color_pair(color_pairs[(schemes["input"][0], schemes["input"][1])]), s[:begin])) ret.append((curses.color_pair(color_pairs[(schemes["input"][0], schemes["input"][1])]), s[:begin]))
end = s.find("}}") end = s.find("!}")
if end == -1: if end == -1:
raise BadColorString("Missing closing '}}'") raise BadColorString("Missing closing '!}'")
# Get a list of attributes in the bracketed section # Get a list of attributes in the bracketed section
attrs = s[begin+2:end].split(",") attrs = s[begin+2:end].split(",")
if len(attrs) == 1 and not attrs: if len(attrs) == 1 and not attrs:
raise BadColorString("No description in {{ }}") raise BadColorString("No description in {! !}")
def apply_attrs(cp, a): def apply_attrs(cp, a):
# This function applies any additional attributes as necessary # This function applies any additional attributes as necessary
@ -151,13 +150,17 @@ def parse_color_string(s):
# Default to 'black' if no bg is chosen # Default to 'black' if no bg is chosen
bg = "black" bg = "black"
color_pair = curses.color_pair(color_pairs[(fg, bg)]) try:
color_pair = curses.color_pair(color_pairs[(fg, bg)])
except KeyError:
raise BadColorString("Bad color value in tag: %s,%s" % (fg, bg))
# Check for additional attributes and OR them to the color_pair # Check for additional attributes and OR them to the color_pair
color_pair = apply_attrs(color_pair, attrs) color_pair = apply_attrs(color_pair, attrs)
# We need to find the text now, so lets try to find another {{ and if # We need to find the text now, so lets try to find another {! and if
# there isn't one, then it's the rest of the string # there isn't one, then it's the rest of the string
next_begin = s.find("{{", end) next_begin = s.find("{!", end)
if next_begin == -1: if next_begin == -1:
ret.append((color_pair, replace_tabs(s[end+2:]))) ret.append((color_pair, replace_tabs(s[end+2:])))

View File

@ -48,13 +48,13 @@ class Command(BaseCommand):
t_options["download_location"] = options["path"] t_options["download_location"] = options["path"]
for arg in args: for arg in args:
self.console.write("{{info}}Attempting to add torrent: %s" % arg) self.console.write("{!info!}Attempting to add torrent: %s" % arg)
filename = os.path.split(arg)[-1] filename = os.path.split(arg)[-1]
filedump = base64.encodestring(open(arg).read()) filedump = base64.encodestring(open(arg).read())
def on_success(result): def on_success(result):
self.console.write("{{success}}Torrent added!") self.console.write("{!success!}Torrent added!")
def on_fail(result): def on_fail(result):
self.console.write("{{error}}Torrent was not added! %s" % result) self.console.write("{!error!}Torrent was not added! %s" % result)
client.core.add_torrent_file(filename, filedump, t_options).addCallback(on_success).addErrback(on_fail) client.core.add_torrent_file(filename, filedump, t_options).addCallback(on_success).addErrback(on_fail)

View File

@ -23,9 +23,12 @@
# Boston, MA 02110-1301, USA. # Boston, MA 02110-1301, USA.
# #
from deluge.ui.console.main import BaseCommand, match_torrents from deluge.ui.console.main import BaseCommand
import deluge.ui.console.colors as colors import deluge.ui.console.colors as colors
from deluge.ui.client import client from deluge.ui.client import client
import deluge.component as component
from deluge.log import LOG as log
from optparse import make_option from optparse import make_option
import re import re
@ -78,34 +81,46 @@ class Command(BaseCommand):
" config --set key value" " config --set key value"
def handle(self, *args, **options): def handle(self, *args, **options):
self.console = component.get("ConsoleUI")
if options['set']: if options['set']:
self._set_config(*args, **options) self._set_config(*args, **options)
else: else:
self._get_config(*args, **options) self._get_config(*args, **options)
def _get_config(self, *args, **options): def _get_config(self, *args, **options):
def _on_get_config(config): config = component.get("CoreConfig")
keys = config.keys()
keys.sort()
for key in keys:
if args and key not in args:
continue
color = 'white'
value = config[key]
if isinstance(value, bool):
color = 'yellow'
elif isinstance(value, int) or isinstance(value, float):
color = 'green'
elif isinstance(value, str):
color = 'cyan'
elif isinstance(value, list):
color = 'magenta'
print templates.config_display(key, style[color](str(value))) keys = config.keys()
client.get_config(_on_get_config) keys.sort()
s = ""
for key in keys:
if args and key not in args:
continue
color = 'white'
value = config[key]
if isinstance(value, bool):
color = 'yellow'
elif isinstance(value, int) or isinstance(value, float):
color = 'green'
elif isinstance(value, str):
color = 'cyan'
elif isinstance(value, list):
color = 'magenta'
elif isinstance(value, dict):
import pprint
value = pprint.pformat(value, 2, 80)
new_value = []
for line in value.splitlines():
new_value.append("{!%s,black,bold!}%s" % (color, line))
value = "\n".join(new_value)
s += " %s: {!%s,black,bold!}%s\n" % (key, color, value)
self.console.write(s)
def _set_config(self, *args, **options): def _set_config(self, *args, **options):
def _got_config_value(config_val): pass
""" def _got_config_value(config_val):
global c_val global c_val
c_val = config_val c_val = config_val
key = args[0] key = args[0]
@ -135,4 +150,4 @@ class Command(BaseCommand):
return [ k for k in keys if k.startswith(text) ] return [ k for k in keys if k.startswith(text) ]
def split(self, text): def split(self, text):
return str.split(text) return str.split(text)"""

View File

@ -34,10 +34,10 @@ class Command(BaseCommand):
port = int(port) port = int(port)
d = client.connect(host, port, username, password) d = client.connect(host, port, username, password)
def on_connect(result): def on_connect(result):
self.console.write("{{success}}Connected to %s:%s!" % (host, port)) self.console.write("{!success!}Connected to %s:%s!" % (host, port))
def on_connect_fail(result): def on_connect_fail(result):
self.console.write("{{error}}Failed to connect to %s:%s!" % (host, port)) self.console.write("{!error!}Failed to connect to %s:%s!" % (host, port))
d.addCallback(on_connect) d.addCallback(on_connect)
d.addErrback(on_connect_fail) d.addErrback(on_connect_fail)

View File

@ -33,9 +33,9 @@ class Command(BaseCommand):
self.console = component.get("ConsoleUI") self.console = component.get("ConsoleUI")
def on_shutdown(result): def on_shutdown(result):
self.write("{{success}}Daemon was shutdown") self.write("{!success!}Daemon was shutdown")
def on_shutdown_fail(reason): def on_shutdown_fail(reason):
self.write("{{error}}Unable to shutdown daemon: %s" % reason) self.write("{!error!}Unable to shutdown daemon: %s" % reason)
client.daemon.shutdown().addCallback(on_shutdown).addErrback(on_shutdown_fail) client.daemon.shutdown().addCallback(on_shutdown).addErrback(on_shutdown_fail)

View File

@ -41,7 +41,7 @@ class Command(BaseCommand):
try: try:
cmd = self._commands[args[0]] cmd = self._commands[args[0]]
except KeyError: except KeyError:
self.console.write("{{error}}Unknown command %r" % args[0]) self.console.write("{!error!}Unknown command %r" % args[0])
return return
try: try:
parser = cmd.create_parser() parser = cmd.create_parser()
@ -51,6 +51,6 @@ class Command(BaseCommand):
else: else:
max_length = max( len(k) for k in self._commands) max_length = max( len(k) for k in self._commands)
for cmd in sorted(self._commands): for cmd in sorted(self._commands):
self.console.write("{{info}}" + cmd + "{{input}} - " + self._commands[cmd].__doc__ or '') self.console.write("{!info!}" + cmd + "{!input!} - " + self._commands[cmd].__doc__ or '')
self.console.write(" ") self.console.write(" ")
self.console.write('For help on a specific command, use "<command> --help"') self.console.write('For help on a specific command, use "<command> --help"')

View File

@ -106,7 +106,7 @@ class Command(BaseCommand):
self.show_info(key, value, options["verbose"]) self.show_info(key, value, options["verbose"])
def on_torrents_status_fail(reason): def on_torrents_status_fail(reason):
self.console.write("{{error}}Error getting torrent info: %s" % reason) self.console.write("{!error!}Error getting torrent info: %s" % reason)
d = client.core.get_torrents_status({"id": torrent_ids}, status_keys) d = client.core.get_torrents_status({"id": torrent_ids}, status_keys)
d.addCallback(on_torrents_status) d.addCallback(on_torrents_status)
@ -123,61 +123,61 @@ class Command(BaseCommand):
the torrent the torrent
""" """
self.console.write(" ") self.console.write(" ")
self.console.write("{{info}}Name: {{input}}%s" % (status["name"])) self.console.write("{!info!}Name: {!input!}%s" % (status["name"]))
self.console.write("{{info}}ID: {{input}}%s" % (torrent_id)) self.console.write("{!info!}ID: {!input!}%s" % (torrent_id))
s = "{{info}}State: %s%s" % (colors.state_color[status["state"]], status["state"]) s = "{!info!}State: %s%s" % (colors.state_color[status["state"]], status["state"])
# Only show speed if active # Only show speed if active
if status["state"] in ("Seeding", "Downloading"): if status["state"] in ("Seeding", "Downloading"):
if status["state"] != "Seeding": if status["state"] != "Seeding":
s += " {{info}}Down Speed: {{input}}%s" % common.fspeed(status["download_payload_rate"]) s += " {!info!}Down Speed: {!input!}%s" % common.fspeed(status["download_payload_rate"])
s += " {{info}}Up Speed: {{input}}%s" % common.fspeed(status["upload_payload_rate"]) s += " {!info!}Up Speed: {!input!}%s" % common.fspeed(status["upload_payload_rate"])
if common.ftime(status["eta"]): if common.ftime(status["eta"]):
s += " {{info}}ETA: {{input}}%s" % common.ftime(status["eta"]) s += " {!info!}ETA: {!input!}%s" % common.ftime(status["eta"])
self.console.write(s) self.console.write(s)
if status["state"] in ("Seeding", "Downloading", "Queued"): if status["state"] in ("Seeding", "Downloading", "Queued"):
s = "{{info}}Seeds: {{input}}%s (%s)" % (status["num_seeds"], status["total_seeds"]) s = "{!info!}Seeds: {!input!}%s (%s)" % (status["num_seeds"], status["total_seeds"])
s += " {{info}}Peers: {{input}}%s (%s)" % (status["num_peers"], status["total_peers"]) s += " {!info!}Peers: {!input!}%s (%s)" % (status["num_peers"], status["total_peers"])
s += " {{info}}Availibility: {{input}}%.2f" % status["distributed_copies"] s += " {!info!}Availibility: {!input!}%.2f" % status["distributed_copies"]
self.console.write(s) self.console.write(s)
s = "{{info}}Size: {{input}}%s/%s" % (common.fsize(status["total_done"]), common.fsize(status["total_size"])) s = "{!info!}Size: {!input!}%s/%s" % (common.fsize(status["total_done"]), common.fsize(status["total_size"]))
s += " {{info}}Ratio: {{input}}%.3f" % status["ratio"] s += " {!info!}Ratio: {!input!}%.3f" % status["ratio"]
self.console.write(s) self.console.write(s)
if not status["is_finished"]: if not status["is_finished"]:
pbar = format_progressbar(status["progress"], self.console.screen.cols - (13 + len("%.2f%%" % status["progress"]))) pbar = format_progressbar(status["progress"], self.console.screen.cols - (13 + len("%.2f%%" % status["progress"])))
s = "{{info}}Progress: {{input}}%.2f%% %s" % (status["progress"], pbar) s = "{!info!}Progress: {!input!}%.2f%% %s" % (status["progress"], pbar)
self.console.write(s) self.console.write(s)
if verbose: if verbose:
self.console.write(" {{info}}::Files") self.console.write(" {!info!}::Files")
for i, f in enumerate(status["files"]): for i, f in enumerate(status["files"]):
s = " {{input}}%s (%s)" % (f["path"], common.fsize(f["size"])) s = " {!input!}%s (%s)" % (f["path"], common.fsize(f["size"]))
s += " {{info}}Progress: {{input}}%.2f%%" % (status["file_progress"][i] * 100) s += " {!info!}Progress: {!input!}%.2f%%" % (status["file_progress"][i] * 100)
s += " {{info}}Priority:" s += " {!info!}Priority:"
fp = common.FILE_PRIORITY[status["file_priorities"][i]].replace("Priority", "") fp = common.FILE_PRIORITY[status["file_priorities"][i]].replace("Priority", "")
if fp == "Do Not Download": if fp == "Do Not Download":
s += "{{error}}" s += "{!error!}"
else: else:
s += "{{success}}" s += "{!success!}"
s += " %s" % (fp) s += " %s" % (fp)
self.console.write(s) self.console.write(s)
self.console.write(" {{info}}::Peers") self.console.write(" {!info!}::Peers")
if len(status["peers"]) == 0: if len(status["peers"]) == 0:
self.console.write(" None") self.console.write(" None")
else: else:
s = "" s = ""
for peer in status["peers"]: for peer in status["peers"]:
if peer["seed"]: if peer["seed"]:
s += "%sSeed\t{{input}}" % colors.state_color["Seeding"] s += "%sSeed\t{!input!}" % colors.state_color["Seeding"]
else: else:
s += "%sPeer\t{{input}}" % colors.state_color["Downloading"] s += "%sPeer\t{!input!}" % colors.state_color["Downloading"]
s += peer["country"] + "\t" s += peer["country"] + "\t"
s += peer["ip"] s += peer["ip"]

View File

@ -49,11 +49,11 @@ class EventLog(component.Component):
def on_torrent_added_event(self, torrent_id): def on_torrent_added_event(self, torrent_id):
def on_torrent_status(status): def on_torrent_status(status):
self.console.write("{{event}}* TorrentAdded: {{info}}%s (%s)" % (status["name"], torrent_id)) self.console.write("{!event!}* TorrentAdded: {!info!}%s (%s)" % (status["name"], torrent_id))
client.core.get_torrent_status(torrent_id, ["name"]).addCallback(on_torrent_status) client.core.get_torrent_status(torrent_id, ["name"]).addCallback(on_torrent_status)
def on_torrent_removed_event(self, torrent_id): def on_torrent_removed_event(self, torrent_id):
self.console.write("{{event}}* TorrentRemovedEvent: {{info}}%s (%s)" % self.console.write("{!event!}* TorrentRemovedEvent: {!info!}%s (%s)" %
(self.console.get_torrent_name(torrent_id), torrent_id)) (self.console.get_torrent_name(torrent_id), torrent_id))
def on_torrent_state_changed_event(self, torrent_id, state): def on_torrent_state_changed_event(self, torrent_id, state):
@ -62,27 +62,27 @@ class EventLog(component.Component):
if state in colors.state_color: if state in colors.state_color:
state = colors.state_color[state] + state state = colors.state_color[state] + state
self.console.write("{{event}}* TorrentStateChanged: %s {{info}}%s (%s)" % self.console.write("{!event!}* TorrentStateChanged: %s {!info!}%s (%s)" %
(state, self.console.get_torrent_name(torrent_id), torrent_id)) (state, self.console.get_torrent_name(torrent_id), torrent_id))
def on_torrent_paused_event(self, torrent_id): def on_torrent_paused_event(self, torrent_id):
self.console.write("{{event}}* TorrentPaused: {{info}}%s (%s)" % self.console.write("{!event!}* TorrentPaused: {!info!}%s (%s)" %
(self.console.get_torrent_name(torrent_id), torrent_id)) (self.console.get_torrent_name(torrent_id), torrent_id))
def on_torrent_finished_event(self, torrent_id): def on_torrent_finished_event(self, torrent_id):
self.console.write("{{event}}* TorrentFinished: {{info}}%s (%s)" % self.console.write("{!event!}* TorrentFinished: {!info!}%s (%s)" %
(self.console.get_torrent_name(torrent_id), torrent_id)) (self.console.get_torrent_name(torrent_id), torrent_id))
def on_new_version_available_event(self, version): def on_new_version_available_event(self, version):
self.console.write("{{event}}* NewVersionAvailable: {{info}}%s" % self.console.write("{!event!}* NewVersionAvailable: {!info!}%s" %
(version)) (version))
def on_session_paused_event(self): def on_session_paused_event(self):
self.console.write("{{event}}* SessionPaused") self.console.write("{!event!}* SessionPaused")
def on_session_resumed_event(self): def on_session_resumed_event(self):
self.console.write("{{event}}* SessionResumed") self.console.write("{!event!}* SessionResumed")
def on_config_value_changed_event(self, key, value): def on_config_value_changed_event(self, key, value):
self.console.write("{{event}}* ConfigValueChanged: %s: %s" % self.console.write("{!event!}* ConfigValueChanged: %s: %s" %
(key, value)) (key, value))

View File

@ -40,10 +40,6 @@ import deluge.ui.console.screen as screen
import deluge.ui.console.colors as colors import deluge.ui.console.colors as colors
from deluge.log import LOG as log from deluge.log import LOG as log
# XXX: Remove when the commands are all fixed up
def match_torrents(a=[]):
pass
class OptionParser(optparse.OptionParser): class OptionParser(optparse.OptionParser):
"""subclass from optparse.OptionParser so exit() won't exit.""" """subclass from optparse.OptionParser so exit() won't exit."""
def exit(self, status=0, msg=None): def exit(self, status=0, msg=None):
@ -149,8 +145,8 @@ class ConsoleUI(component.Component):
self.statusbars = StatusBars() self.statusbars = StatusBars()
self.eventlog = EventLog() self.eventlog = EventLog()
self.screen.topbar = "{{status}}Deluge " + deluge.common.get_version() + " Console" self.screen.topbar = "{!status!}Deluge " + deluge.common.get_version() + " Console"
self.screen.bottombar = "{{status}}" self.screen.bottombar = "{!status!}"
self.screen.refresh() self.screen.refresh()
# The Screen object is designed to run as a twisted reader so that it # The Screen object is designed to run as a twisted reader so that it
@ -203,7 +199,7 @@ class ConsoleUI(component.Component):
try: try:
parser = self._commands[cmd].create_parser() parser = self._commands[cmd].create_parser()
except KeyError: except KeyError:
self.write("{{error}}Unknown command: %s" % cmd) self.write("{!error!}Unknown command: %s" % cmd)
return return
args = self._commands[cmd].split(line) args = self._commands[cmd].split(line)
@ -221,7 +217,7 @@ class ConsoleUI(component.Component):
try: try:
self._commands[cmd].handle(*args, **options.__dict__) self._commands[cmd].handle(*args, **options.__dict__)
except Exception, e: except Exception, e:
self.write("{{error}}" + str(e)) self.write("{!error!}" + str(e))
log.exception(e) log.exception(e)
import traceback import traceback
self.write("%s" % traceback.format_exc()) self.write("%s" % traceback.format_exc())

View File

@ -97,25 +97,23 @@ class Screen(CursesStdIO):
Add a line to the screen. This will be showed between the two bars. Add a line to the screen. This will be showed between the two bars.
The text can be formatted with color using the following format: The text can be formatted with color using the following format:
"{{fg, bg, attributes, ...}}" "{!fg, bg, attributes, ...!}"
See: http://docs.python.org/library/curses.html#constants for attributes. See: http://docs.python.org/library/curses.html#constants for attributes.
Alternatively, it can use some built-in scheme for coloring. Alternatively, it can use some built-in scheme for coloring.
See colors.py for built-in schemes. See colors.py for built-in schemes.
"{{scheme}}" "{!scheme!}"
Examples: Examples:
"{{blue, black, bold}}My Text is {{white, black}}cool" "{!blue, black, bold!}My Text is {!white, black!}cool"
"{{info}}I am some info text!" "{!info!}I am some info text!"
"{{error}}Uh oh!" "{!error!}Uh oh!"
:param text: str, the text to show :param text: str, the text to show
""" """
log.debug("adding line: %s", text)
def get_line_chunks(line): def get_line_chunks(line):
""" """
@ -123,11 +121,11 @@ class Screen(CursesStdIO):
""" """
chunks = [] chunks = []
num_chunks = line.count("{{") num_chunks = line.count("{!")
for i in range(num_chunks): for i in range(num_chunks):
# Find the beginning and end of the color tag # Find the beginning and end of the color tag
beg = line.find("{{") beg = line.find("{!")
end = line.find("}}") + 2 end = line.find("!}") + 2
color = line[beg:end] color = line[beg:end]
line = line[end:] line = line[end:]
@ -137,8 +135,8 @@ class Screen(CursesStdIO):
else: else:
# Not the last chunk so get the text up to the next tag # Not the last chunk so get the text up to the next tag
# and remove the text from line # and remove the text from line
text = line[:line.find("{{")] text = line[:line.find("{!")]
line = line[line.find("{{"):] line = line[line.find("{!"):]
chunks.append((color, text)) chunks.append((color, text))
@ -196,8 +194,8 @@ class Screen(CursesStdIO):
col = 0 col = 0
try: try:
parsed = colors.parse_color_string(string) parsed = colors.parse_color_string(string)
except colors.BadColorString: except colors.BadColorString, e:
log.error("Cannot add bad color string: %s", string) log.error("Cannot add bad color string %s: %s", string, e)
return return
for index, (color, s) in enumerate(parsed): for index, (color, s) in enumerate(parsed):

View File

@ -74,7 +74,7 @@ class StatusBars(component.Component):
def update_statusbars(self): def update_statusbars(self):
# Update the topbar string # Update the topbar string
self.screen.topbar = "{{status}}Deluge %s Console - " % deluge.common.get_version() self.screen.topbar = "{!status!}Deluge %s Console - " % deluge.common.get_version()
if client.connected(): if client.connected():
info = client.connection_info() info = client.connection_info()
self.screen.topbar += "%s@%s:%s" % (info[2], info[0], info[1]) self.screen.topbar += "%s@%s:%s" % (info[2], info[0], info[1])
@ -82,7 +82,7 @@ class StatusBars(component.Component):
self.screen.topbar += "Not Connected" self.screen.topbar += "Not Connected"
# Update the bottombar string # Update the bottombar string
self.screen.bottombar = "{{status}}C: %s" % self.connections self.screen.bottombar = "{!status!}C: %s" % self.connections
if self.config["max_connections_global"] > -1: if self.config["max_connections_global"] > -1:
self.screen.bottombar += " (%s)" % self.config["max_connections_global"] self.screen.bottombar += " (%s)" % self.config["max_connections_global"]