3 """elisp2rst [<options>] <file.el>
5 Emacs-LISP to reStructuredText converter.
13 hierarchy
= ('=', '-', '~', '+', '^')
15 def underline(title
, char
, outfile
):
17 Outputs 'title' with underline character 'char' to file 'outfile'
19 print >> outfile
, title
20 print >> outfile
, char
* len(title
)
22 def printpar(paragraph
, outfile
, indent
=None):
24 Output a paragraph's lines to 'outfile'.
28 for line
in map(str.rstrip
, paragraph
):
35 class ElispFormatError(Exception):
37 Error raised during the parsing of Emacs-LISP code.
41 def elisp2rst(infile
, outfile
):
43 Reads Emacs-LISP text and converts it in to reStructuredText. 'infile' and
44 'outfile' are expected to be open file objects for input and output.
46 This code does the following transformations:
49 - create a title and subtitle
50 - converts the RFC822 headers into bibliographic fields
51 - converts the copyright line at the top into a biblio field
52 - places the copyright notice in a bibliographic field
53 - converts the ;;; section titles to include underlines
54 - adds an extra colon at the end of appropriate lines for creating literal
58 hidx
= 0 # index in the hierarchy
60 # Get the title and subtitle lines.
61 titleline
= infile
.next()
62 mo
= re
.match('^;;; (.*) --- (.*)$', titleline
)
64 title
, subtitle
= mo
.group(1, 2)
66 title
, subtitle
= titleline
[4:], None
68 underline(title
, hierarchy
[hidx
], outfile
)
71 underline(subtitle
, hierarchy
[hidx
], outfile
)
74 # Process the rest of the lines until we hit a ';;; Code:' section.
75 precommentary
, done_pre
= [], False
76 "List of paragraphs that appear before the commentary."
78 copyright_years
, fields
= None, None
79 "Copyright years and RFC822 field list, if present in the pre-commentary."
85 mo
= re
.match(';;; (.*)', line
)
88 # If we reached the code marker, stop processing.
89 if title
.startswith('Code:'):
92 if title
.startswith('Commentary:'):
95 # Output the pre-commentary stuff.
98 if line
.startswith(' ') or line
.startswith('\t'):
99 print >> outfile
, ' %s' % line
101 print >> outfile
, ':%s' % line
102 outfile
.write(os
.linesep
)
106 prepars
.append(copyright_years
)
107 prepars
.extend(precommentary
)
109 print >> outfile
, '.. note::'
112 printpar(par
, outfile
, indent
=' ')
115 if title
.endswith(':'):
119 underline(title
, hierarchy
[hidx
], outfile
)
122 # Detect LISP code and exit if we find some.
123 if re
.match('\([a-zA-Z-]+( |$)', line
):
126 # Normal text contents.
127 mo
= re
.match(';;? ?(.*)$', line
)
129 line_contents
= mo
.group(1)
130 line_contents
= re
.sub("`(.*?)'", "``\\1``", line_contents
)
131 paragraph
.append(line_contents
)
133 if not re
.match('^[ \t\f]*$', line
):
134 raise ElispFormatError("Unknown line format")
137 if parnum
== 0 and paragraph
[0].startswith('Copyright'):
138 copyright_years
= paragraph
139 elif parnum
== 1 and re
.match('[A-Za-z]+: ', paragraph
[0]):
142 precommentary
.append(paragraph
)
144 printpar(paragraph
, outfile
)
151 printpar(paragraph
, outfile
)
163 parser
= optparse
.OptionParser(__doc__
.strip())
164 opts
, args
= parser
.parse_args()
167 parser
.error("You must specify a single Emacs-LISP file as input.")
170 elispf
= open(elispfn
, 'r')
172 elisp2rst(elispf
, sys
.stdout
)
179 if __name__
== '__main__':