Add namespaced commands

master
Lars Vierbergen 8 years ago
parent 6b483981d9
commit 652d1a5e03
  1. 7
      modules/application.py
  2. 69
      modules/core.py
  3. 8
      modules/toggle.py

@ -121,11 +121,11 @@ class Application(GroupedControl):
super().cleanup()
def respond_to(self, command):
def respond_to_ex(self, command):
if command == '':
return False
logger.info('Received command %s', command)
return super().respond_to(command)
return super().respond_to_ex(command)
def handle_signal(self, signal, tb):
raise Exception("Received signal %s"%signal)
@ -134,6 +134,7 @@ class Application(GroupedControl):
def run(self):
parser = argparse.ArgumentParser(description='Action manager for xmobar')
self.set_name_ex('')
self.configure(parser)
self.bind_arguments(parser.parse_args())
@ -143,7 +144,7 @@ class Application(GroupedControl):
try:
self.args.output_pipe.writelines(str(self)+"\n")
while True:
if self.respond_to(str.rstrip(self.args.command_pipe.readline())) or self.periodic():
if self.respond_to_ex(str.rstrip(self.args.command_pipe.readline())) or self.periodic():
self.args.output_pipe.writelines(str(self) + "\n")
else:
time.sleep(1)

@ -19,6 +19,7 @@ class AbstractControl(metaclass=abc.ABCMeta):
Creates a new control
"""
self.args = None
self.__name = None
@property
def visible(self):
@ -94,6 +95,31 @@ class AbstractControl(metaclass=abc.ABCMeta):
"""
return False
def respond_to_ex(self, command: str):
"""
Responds to a non-cleaned user command
Namespaced commands still contain the namespace of this class, which has to be
removed from the command before it is passed on to respond_to()
:param command: The uncleaned command from the user
:return: bool Whether the displayed information is changed by the executed operations.
"""
logger.debug('%s.respond_to_ex: %s', self.__class__.__name__, command)
if command[0] == ':':
split_command = command.split(':', 2)
if len(split_command) == 3:
if split_command[1] != self.get_namespace():
logger.error('%s.respond_to_ex: Unsollicited command (mismatch %s <-> %s)', self.__class__.__name__, split_command[1], self.get_namespace())
return False
command = ':' + split_command[2]
logger.debug('%s.respond_to: %s', self.__class__.__name__, command)
return self.respond_to(command)
logger.warning('%s.respond_to_ex: Could not split into full command.', self.__class__.__name__)
else:
logger.debug('%s.respond_to: %s', self.__class__.__name__, command)
return self.respond_to(command)
def __str__(self):
"""
Creates the string representation of the module to show on the action bar
@ -153,6 +179,32 @@ class AbstractControl(metaclass=abc.ABCMeta):
"""
return {self.__class__.__name__: self.dump_state()}
def get_namespace(self):
"""
:return: The class-specific part of the namespace to use for namespaced commands. It cannot contain colons
"""
return self.__class__.__name__
def set_name(self, name: str):
"""
Sets the namespace to use for namespaced commands
This method may be overridden to customize the namespace used for the class
It must call parent().set_name() with the desired name
:param name: The namespace to use for namespaced commands
"""
self.__name = name
logger.debug('%s.set_name: Set name to %s', self.__class__.__name__, name)
def set_name_ex(self, name: str):
"""
Sets the namespace to use for namespaced commands
This method must not be overridden
:param name: Namespace used by the object one up the hierarchy
"""
self.set_name('%s:%s' % (name, self.get_namespace()))
def create_pipe_command(self, command: str):
"""
Creates a shell command that will pass :command to the daemon through the controlpipe
@ -160,6 +212,8 @@ class AbstractControl(metaclass=abc.ABCMeta):
:param command: The command to pass
:return: str Shell command that will pass the given command through the controlpipe
"""
if command[0] == ':':
command = self.__name + command
return '{}/command.sh {} {}'.format(os.path.abspath(sys.path[0]), command,
os.path.abspath(self.args.command_pipe.name))
@ -202,7 +256,12 @@ class GroupedControl(AbstractControl):
[m.cleanup() for m in self.__modules if m.enabled]
def respond_to(self, command):
if command[0] != ':':
return any([m.respond_to(command) for m in self.__modules if m.enabled])
split_command = command.split(':', maxsplit=2)
if len(split_command) == 3:
index = int(split_command[1])
return self.__modules[index].respond_to_ex(':' + split_command[2])
def periodic(self):
return any([m.periodic() for m in self.__modules if m.enabled])
@ -214,6 +273,10 @@ class GroupedControl(AbstractControl):
data.update(m.dump_state_ex())
return data
def set_name(self, name: str):
super().set_name(name)
[m.set_name_ex('%s:%d' % (name, i)) for i, m in enumerate(self.__modules)]
def __passthrough_log(self, fn, s):
logger.debug('%s.%s(): %s', self.__class__.__name__, fn, s)
return s
@ -262,7 +325,7 @@ class WrappingControl(AbstractControl):
self.child.load_state(state)
def respond_to(self, command):
return self.child.respond_to(command)
return self.child.respond_to_ex(command)
@property
def enabled(self):
@ -288,6 +351,10 @@ class WrappingControl(AbstractControl):
def load_state_ex(self, state):
self.child.load_state_ex(state)
def set_name(self, name: str):
super().set_name(name)
self.child.set_name_ex(name)
def __str__(self):
return self.child.__str__()

@ -1,6 +1,5 @@
from .core import AbstractControl, WrappingControl, action
import abc
import functools
class ToggleAction(AbstractControl, metaclass=abc.ABCMeta):
@ -46,16 +45,13 @@ class ToggleControl(WrappingControl):
super().__init__(toggle_action)
self.__letter = letter
def __get_control_command(self):
return '%s:%s:%s' % (self.__class__.__name__, self.__letter, self.child.__class__.__name__)
def respond_to(self, command):
if command == self.__get_control_command():
if command == ':toggle':
self.child.toggle()
return True
def __str__(self):
return action(
self.create_pipe_command(self.__get_control_command()),
self.create_pipe_command(':toggle'),
self.__letter.upper() if self.child.state else self.__letter.lower()
)

Loading…
Cancel
Save