Bug 770: Move codw->cmdw transform to outer layer
[elinks/elinks-j605.git] / contrib / python / elinks_maint.py
blobb66897799f7f8280844e1cd59451854de1fa6167
1 """Additional Python code for ELinks maintainers.
3 This module is intended for ELinks maintainers. If you modify or add to
4 the Python APIs in src/scripting/python/*.c and/or contrib/python/hooks.py,
5 you should update the accompanying docstrings to reflect your changes and
6 then generate a new version of the file doc/python.txt (which serves as a
7 reference manual for the browser's Python APIs). The embedded interpreter
8 can use introspection to regenerate the python.txt document for you; just
9 copy this file into your ~/.elinks directory and add something like the
10 following to ~/.elinks/hooks.py:
12 import elinks_maint
13 elinks.bind_key('F2', elinks_maint.generate_python_txt)
15 """
17 import inspect
18 import tempfile
19 import types
21 preface = """\
22 Python programmers can customize the behavior of ELinks by creating a Python
23 hooks module. The embedded Python interpreter provides an internal module
24 called elinks that can be used by the hooks module to create keystroke
25 bindings for Python code, obtain information about the document being
26 viewed, display simple dialog boxes and menus, load documents into the
27 ELinks cache, or display documents to the user. These two modules are
28 described below.
30 """
32 module_template = """
33 MODULE
34 %s - %s
36 DESCRIPTION
39 FUNCTIONS
41 """
43 separator = '-' * 78 + '\n'
45 def document_modules(*modules):
46 """Format the internal documentation found in one or more Python modules."""
47 output = []
48 for module in modules:
49 name, doc, namespace = module.__name__, module.__doc__, module.__dict__
50 if not name or not namespace:
51 continue
52 try:
53 summary, junk, description = doc.rstrip().split('\n', 2)
54 except:
55 summary, description = '?', '(no description available)'
56 functions = document_functions(namespace)
57 output.append(module_template % (name, summary, indent(description),
58 indent(functions)))
59 return separator.join(output)
61 def document_functions(namespace):
62 """Format the internal documentation for all functions in a namespace."""
63 objects = namespace.items()
64 objects.sort()
65 output = []
66 for name, object in objects:
67 if name.startswith('_'):
68 continue
69 species = type(object)
70 if species == types.BuiltinFunctionType:
71 args = '(...)'
72 elif species == types.FunctionType:
73 args = inspect.formatargspec(*inspect.getargspec(object))
74 else:
75 continue
76 description = inspect.getdoc(object)
77 output.append('%s%s\n%s\n' % (name, args, indent(description)))
78 return '\n'.join(output)
80 def generate_python_txt():
81 """Generate documentation for the hooks and elinks modules."""
82 import elinks
83 import hooks
85 # Remove anything that doesn't belong in the API documentation.
87 hooks_api_functions = (
88 'follow_url_hook',
89 'goto_url_hook',
90 'pre_format_html_hook',
91 'proxy_for_hook',
92 'quit_hook',
94 for key in hooks.__dict__.keys():
95 if key not in hooks_api_functions and not key.startswith('_'):
96 del hooks.__dict__[key]
97 hooks.__doc__ = hooks.__doc__.replace('Example Python', 'Python')
99 # Generate the documentation.
101 try:
102 output = separator.join((preface, document_modules(hooks, elinks)))
103 finally:
104 # Restore the hooks module to a sane state.
105 reload(hooks)
107 # View the documentation.
109 path = write_tempfile(output)
110 elinks.open(path)
112 def indent(text):
113 """Return indented text."""
114 indent = ' ' * 4
115 return '\n'.join([indent + line for line in text.split('\n')])
117 def write_tempfile(text):
118 """Write a string to a temporary file and return the file's name."""
119 output = tempfile.NamedTemporaryFile(prefix='elinks_maint', suffix='.txt')
120 output.write(text)
121 output.flush()
122 _tempfiles[text] = output
123 return output.name
125 # Temp files are stashed in this dictionary to prevent them from being closed
126 # before ELinks has a chance to read them; they will be automatically deleted
127 # when the dictionary is garbage-collected at exit time.
129 _tempfiles = {}