diff options
| -rwxr-xr-x | py3status/__init__.py | 122 |
1 files changed, 92 insertions, 30 deletions
diff --git a/py3status/__init__.py b/py3status/__init__.py index 226448b..2027882 100755 --- a/py3status/__init__.py +++ b/py3status/__init__.py @@ -1,4 +1,7 @@ +from __future__ import print_function + import argparse +import ast import imp import locale import os @@ -40,6 +43,12 @@ def print_line(line): sys.__stdout__.flush() +def print_stderr(line): + """Print line to stderr + """ + print(line, file=sys.stderr) + + class IOPoller: """ This class implements a predictive and timing-out I/O reader @@ -1120,6 +1129,27 @@ class Py3statusWrapper(): version = 'unknown' config['version'] = version + # i3status config file default detection + # respect i3status' file detection order wrt issue #43 + i3status_config_file_candidates = [ + '{}/.i3status.conf'.format(home_path), + '{}/.config/i3status/config'.format( + os.environ.get('XDG_CONFIG_HOME', home_path) + ), + '/etc/i3status.conf', + '{}/i3status/config'.format( + os.environ.get('XDG_CONFIG_DIRS', '/etc/xdg') + ) + ] + for fn in i3status_config_file_candidates: + if os.path.isfile(fn): + i3status_config_file_default = fn + break + else: + # if none of the default files exists, we will default + # to ~/.i3/i3status.conf + i3status_config_file_default = '{}/.i3/i3status.conf'.format(home_path) + # command line options parser = argparse.ArgumentParser( description='The agile, python-powered, i3status wrapper') @@ -1127,6 +1157,7 @@ class Py3statusWrapper(): parser.add_argument('-c', '--config', action="store", dest="i3status_conf", type=str, + default=i3status_config_file_default, help="path to i3status config file") parser.add_argument('-d', '--debug', action="store_true", help="be verbose in syslog") @@ -1149,8 +1180,19 @@ class Py3statusWrapper(): (default 60 sec)""") parser.add_argument('-v', '--version', action="store_true", help="""show py3status version and exit""") + + parser.add_argument('cli_command', nargs='?', + choices=[ + 'list-modules', + ]) + parser.add_argument('cli_command_arg', nargs='?', help=argparse.SUPPRESS) + options = parser.parse_args() + if options.cli_command: + config['cli_command'] = options.cli_command + config['cli_command_arg'] = options.cli_command_arg + # only asked for version if options.version: from platform import python_version @@ -1169,36 +1211,7 @@ class Py3statusWrapper(): config['include_paths'] = options.include_paths config['interval'] = int(options.interval) config['standalone'] = options.standalone - - # i3status config file path setup or default detection - if options.i3status_conf: - config['i3status_config_path'] = options.i3status_conf - else: - # find i3status default config file - # respect i3status' file detection order wrt issue #43 - i3status_config_files = [ - '{}/.i3status.conf'.format(home_path), - '{}/.config/i3status/config'.format( - os.environ.get('XDG_CONFIG_HOME', home_path) - ), - '/etc/i3status.conf', - '{}/i3status/config'.format( - os.environ.get('XDG_CONFIG_DIRS', '/etc/xdg') - ) - ] - i3status_config_files = list( - filter( - os.path.isfile, - i3status_config_files - ) - ) - - # if none of the default files exists, we will default - # to ~/.i3/i3status.conf - config['i3status_config_path'] = ( - i3status_config_files[0] if i3status_config_files - else '{}/.i3/i3status.conf'.format(home_path) - ) + config['i3status_config_path'] = options.i3status_conf # all done return config @@ -1283,6 +1296,14 @@ class Py3statusWrapper(): # setup configuration self.config = self.get_config() + + if 'cli_command' in self.config: + self.handle_cli_command( + self.config['cli_command'], + self.config['cli_command_arg'] + ) + sys.exit() + if self.config['debug']: syslog( LOG_INFO, @@ -1578,6 +1599,47 @@ class Py3statusWrapper(): delta += 0.1 sleep(0.1) + @staticmethod + def print_module_description(mod_name, mod_path): + """Print module description extracted from its docstring. + """ + if mod_name == '__init__': + return + + path = os.path.join(*mod_path) + try: + with open(path) as f: + module = ast.parse(f.read()) + + items = [i for i in module.body if isinstance(i, ast.Expr)] + if items: + ds = items[0].value.s + ds = ds.lstrip() + ds = ds.split('\n\n',1)[0] # Filter only up to an empty line. + ds = ds.split('.', 1)[0] # And the first dot + ds = ds.replace('\n', ' ') + print_stderr(" %-22s %s." % (mod_name, ds)) + + else: + print_stderr(" %-22s No docstring in %s" % (mod_name, path)) + + except Exception as e: + print_stderr(" %-22s Unable to parse %s" % (mod_name, path)) + + def handle_cli_command(self, cmd, cmd_arg): + """Handle a command from the CLI. + """ + if cmd == 'list-modules': + user_modules = self.get_user_modules() + print_stderr("Available modules:") + for mod_name, mod_path in sorted(user_modules.items()): + self.print_module_description(mod_name, mod_path) + + sys.exit() + + print_stderr("Error: unknown command") + sys.exit(1) + def main(): try: |
