From 9dc70419971f23ea6d9de373bab8489447c3d9d4 Mon Sep 17 00:00:00 2001 From: enkore Date: Sat, 23 Feb 2013 18:41:33 +0100 Subject: [PATCH] First draft of a doc generator for this (Already supports multiple Modules per python module) --- i3pystatus/mkdocs.py | 167 +++++++++++++++++++++++++++++++++++++++++++ mkdocs.sh | 4 ++ template.md | 51 +++++++++++++ 3 files changed, 222 insertions(+) create mode 100755 i3pystatus/mkdocs.py create mode 100644 mkdocs.sh create mode 100644 template.md diff --git a/i3pystatus/mkdocs.py b/i3pystatus/mkdocs.py new file mode 100755 index 0000000..f5c4844 --- /dev/null +++ b/i3pystatus/mkdocs.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python + +import sys +import io +import pkgutil +from collections import namedtuple + +import i3pystatus + +IGNORE = ("__main__", "mkdocs") + +class Module: + name = "" + doc = "" + settings = [] + +class Setting: + name = "" + doc = "" + required = False + default = None + +#finder = ClassFinder(baseclass=Module, exclude=[Module, IntervalModule, AsyncModule]) +finder = i3pystatus.ModuleFinder() + +def trim(docstring): + if not docstring: + return '' + # Convert tabs to spaces (following the normal Python rules) + # and split into a list of lines: + lines = docstring.expandtabs().splitlines() + # Determine minimum indentation (first line doesn't count): + indent = sys.maxsize + for line in lines[1:]: + stripped = line.lstrip() + if stripped: + indent = min(indent, len(line) - len(stripped)) + # Remove indentation (first line is special): + trimmed = [lines[0].strip()] + if indent < sys.maxsize: + for line in lines[1:]: + trimmed.append(line[indent:].rstrip()) + # Strip off trailing and leading blank lines: + while trimmed and not trimmed[-1]: + trimmed.pop() + while trimmed and not trimmed[0]: + trimmed.pop(0) + # Return a single string: + return '\n'.join(trimmed) + +def get_modules(): + modules = [] + for finder, modname, ispkg in pkgutil.iter_modules(i3pystatus.get_path()): + if modname not in IGNORE: + modules.append(get_module(finder, modname)) + + return modules + +def get_module(finder, modname): + fullname = "i3pystatus.{modname}".format(modname=modname) + return (modname, finder.find_loader(fullname)[0].load_module(fullname)) + +def get_settings(cls): + settings = [] + + for setting in cls.settings: + s = Setting() + if isinstance(setting, tuple): + s.name = setting[0] + s.doc = setting[1] + else: + s.name = setting + + if setting in cls.required: + s.required = True + elif hasattr(cls, s.name): + s.default = getattr(cls, s.name) + + settings.append(s) + + return settings + +def get_all(): + mods = [] + + for name, module in get_modules(): + classes = finder.search_module(module) + + for cls in classes: + m = Module() + + if len(classes) == 1: + m.name = name + else: + m.name = "{module}.{cls}".format(module=name, cls=cls.__name__) + + if hasattr(cls, "__doc__"): + m.doc = cls.__doc__ + elif hasattr(module, "__doc__"): + m.doc = module.__doc__ + + m.settings = get_settings(cls) + + mods.append(m) + + return mods + +def format_settings(settings): + return "\n".join((format_setting(setting) for setting in settings)) + +def format_setting(setting): + attrs = [] + if setting.required: + attrs.append("required") + if setting.default: + attrs.append("default: {default}".format(default=setting.default)) + + formatted = "* {name} ".format(name=setting.name) + if setting.doc or attrs: + formatted += "— " + if setting.doc: + formatted += setting.doc + if attrs: + formatted += " ({attrs})".format(attrs=", ".join(attrs)) + + return formatted + +def write_mods(f, mods): + for mod in mods: + f.write(""" +### {name} + +{doc} + +{settings}\n""".format( + name=mod.name, + doc=trim(mod.doc), + settings=format_settings(mod.settings) + )) + +# io.StringIO + +write_mods(sys.stdout, get_all()) + +with open("template.md", "r") as template: + tpl = template.read() + + f = io.StringIO() + write_mods(f, get_all()) + + print(tpl.replace("!!module_doc!!", f.getvalue())) + + +# return [finder.search_module] +# mods = [] +# + # for modname, module in modules: + # classes = finder.search_module(module) +# +# +# + # mods.append(get_mod(modname)) + # mods.append(mod( + # name=modname, + # docstring=module.__doc__ if hasattr(module, "__doc__") else "", + # settings=get_settings(module) + # )) \ No newline at end of file diff --git a/mkdocs.sh b/mkdocs.sh new file mode 100644 index 0000000..a6ce5f1 --- /dev/null +++ b/mkdocs.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +python -m i3pystatus.mkdocs > README.md + diff --git a/template.md b/template.md new file mode 100644 index 0000000..d1c7327 --- /dev/null +++ b/template.md @@ -0,0 +1,51 @@ +# i3pystatus + +i3pystatus is a (hopefully growing) collection of python scripts for +status output compatible to i3status / i3bar of the i3 window manager. + +## Installation + +To install it, follow these steps: + + cd ~/.config/i3status/ + git clone git@github.com:janoliver/i3pystatus contrib + cd contrib/i3pystatus + cp __main__.py.dist __main__.py + +Add the following to `~/.config/i3status/config`: + + general { + output_format = "i3bar" + colors = true + interval = 5 + } + +Change your i3wm config to the following: + + # i3bar + bar { + status_command cd ~/.config/i3status/contrib ; i3status | python -m i3pystatus + position top + workspace_buttons yes + } + +And finally adjust the settings in `~/.config/i3status/contrib/i3pystatus/__main__.py` +as you like. + +## Modules + +!!module_doc!! + +## Contribute + +To contribute a module, make sure it uses one of the Module classes. Most modules +use IntervalModule, which just calls a function repeatedly in a specified interval. + +The output attribute should be set to a dictionary which represents your modules output, +the protocol is documented [here](http://i3wm.org/docs/i3bar-protocol.html). + +Please add an example for how to configure it to `__main__.py.dist`. It should be +a python class that can be registered with the `I3statusHandler` class. Also don't +forget to add yourself to the LICENSE file. + +**Patches and pull requests are very welcome :-)**