1#!/usr/bin/env python
2
3# Convert Tim-style text to html or qml
4#
5# The Rules:
6# - Lines with all upper case words to h2 or h3 capwords depending on next line underlining (first to h1/title though)
7#   (must be 3 chars or more)
8#   (todo: relax to not all upper case... no need to capwords if not)
9# - Other text to p, blank lines break a p
10# - Lines beginning with "- " (NB space) to ul/li (bulleted)
11# - Lines beginning with "-?" (no space) to ul/li (?) with <br> at end of first line
12# - Words delim <xxx> to <i>xxx</i>
13# "$ " at start of line indicates one line of code (add <br> too)
14
15import sys
16import string
17import re
18
19def line_of_dashes(n):
20    r=""
21    for i in xrange(n):
22        r+="-"
23    return r
24
25def line_of_equals(n):
26    r=""
27    for i in xrange(n):
28        r+="="
29    return r
30
31class TextToMarkup:
32
33    def __init__(self,m,s):
34        self.startup=1       # True
35        self.scope_p=0       # False
36        self.scope_ul=0      # False
37        self.scope_li=0      # False
38        self.done_title=0    # False
39        self.skipnextline=0  # False
40        self.mode=m
41        self.stringify=s
42
43    def dispose(self,l):
44        if self.stringify:
45            self.output.write("\"")       # Actually, they should all have been &quot;-ed anyway
46            for c in l:
47                if c=="\"":
48                    self.output.write("\\\"")
49                else:
50                    self.output.write(c)
51            self.output.write("\\n\"\n")
52        else:
53            self.output.write(l+"\n")
54
55    def process_word(self,w):
56        r=""
57        if len(w)<3:                      # Special case allows "<" or "<>" without turning italic
58            for i in xrange(len(w)):
59                if w[i]=="<":
60                    r+="&lt;"
61                elif w[i]==">":
62                    r+="&gt;"
63                else:
64                    r+=w[i]
65        else:
66            for i in xrange(len(w)):
67                if w[i]=="<":
68                    r+="<i>"
69                elif w[i]==">":
70                    r+="</i>"
71                elif w[i]=='"':
72                    r+="&quot;"
73                elif w[i]=="&":
74                    r+="&amp;"
75                else:
76                    r+=w[i]
77        return r
78
79    def process_paragraph_text(self,txt):
80
81        is_code=0 # False
82        specialbreak=0 # False
83        r="  "
84
85        if txt[0]=="-":
86            if txt[1]==" ":
87                txt=txt[2:]
88            else:
89                specialbreak=1 # True
90            if self.scope_ul and self.scope_li:
91                r+="</li>"
92                self.scope_li=0 # False
93            if not self.scope_ul:
94                r+="<ul>"
95                self.scope_ul=1 # True
96            if not self.scope_li:
97                r+="<li>"
98                self.scope_li=1 # True
99
100        elif txt[0]=="$":
101            is_code=1           # True
102            r+="<code>"
103            txt=txt[2:]
104
105        for w in txt.split():
106            r+=self.process_word(w)
107            r+=" "
108        if is_code:
109            r+="</code>"
110        if specialbreak:
111            r+="<br>"
112        return r
113
114    def process(self,in_stream,out_stream):
115        self.output=out_stream
116        self.input=in_stream
117
118        if self.mode=="html":
119            self.dispose("<html>")
120
121        while 1:    # True
122
123            if self.startup:
124                self.currline_raw=in_stream.readline()
125                self.nextline_raw=in_stream.readline()
126                self.startup=0   # False
127            else:
128                self.currline_raw=self.nextline_raw
129                self.nextline_raw=in_stream.readline()
130
131            if not self.currline_raw:
132                break
133
134            if self.skipnextline:
135                self.skipnextline=0 # False
136                continue
137
138            # Should track last line too
139            self.currline=self.currline_raw.strip()
140            self.nextline=self.nextline_raw.strip()
141
142            if len(self.currline)>2 and self.nextline==line_of_equals(len(self.currline)):
143                if self.done_title:
144                    self.dispose("<h2>"+string.capwords(self.currline)+"</h2>")
145                    self.skipnextline=1 # True
146                    continue
147                else:
148                    if (self.mode=="html"):
149                        self.dispose("<head>")
150                        self.dispose("<!--- AUTOMATICALLY GENERATED FILE : DO NOT EDIT --->")
151                        self.dispose("<title>"+string.capwords(self.currline)+"</title>")
152                        self.dispose("</head>")
153                        self.dispose("<body>")
154                    elif (self.mode=="qml"):
155                        self.dispose("<qt title='"+string.capwords(self.currline)+"'>")
156                    self.dispose("<h1>"+string.capwords(self.currline)+"</h1>")
157                    self.done_title=1 # True
158                    self.skipnextline=1 # True
159                    continue
160            elif len(self.currline)>2 and self.nextline==line_of_dashes(len(self.currline)):
161                self.dispose("<h3>"+string.capwords(self.currline)+"</h3>")
162                self.skipnextline=1 # True
163                continue
164            elif self.scope_p:
165                if (len(self.currline)):
166                    self.dispose(self.process_paragraph_text(self.currline))
167                else:
168                    if self.scope_li:
169                        self.dispose("</li>")
170                        self.scope_li=0 # False
171                    if self.scope_ul:
172                        self.dispose("</ul>")
173                        self.scope_ul=0 # False
174                    self.dispose("</p>")
175                    self.scope_p=0 # False
176            elif len(self.currline):
177                self.dispose("<p>")
178                self.dispose(self.process_paragraph_text(self.currline))
179                self.scope_p=1 # True
180            else:
181                self.dispose("")
182
183        if self.mode=="html":
184            self.dispose("</body>")
185            self.dispose("</html>")
186
187#########################################
188
189if __name__=='__main__':
190
191    mode=None
192    stringify=0 # False
193    for i in xrange(1,len(sys.argv)):
194        if sys.argv[i]=="-qml":
195            mode="qml"
196        if sys.argv[i]=="-html":
197            mode="html"
198        elif sys.argv[i]=="-s":
199            stringify=1 # True
200
201    t2m=TextToMarkup(mode,stringify)    # "html" and "qml" are alternatives.  Should be stringify option.
202    t2m.process(sys.stdin,sys.stdout)
203
204