PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/old/txt2tags-1.0.py

http://txt2tags.googlecode.com/
Python | 1196 lines | 1191 code | 3 blank | 2 comment | 6 complexity | 43075a0c258c4af12096f3d18b07d8ff MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0, WTFPL
  1. #!/usr/bin/env python
  2. # txt2tags - generic text conversion tool - aurelio
  3. import re, string, os, sys, getopt, traceback
  4. from time import strftime,time,localtime
  5. my_url = 'http://txt2tags.sf.net'
  6. my_email = 'aurelio@verde666.org'
  7. my_version = '1.0'
  8. DEBUG = 0
  9. tags = ['txt', 'sgml', 'html', 'pm6', 'mgp', 'moin', 'man']
  10. FLAGS = {'noheaders':0,'enumtitle':0,'maskemail':0, 'stdout':0,
  11. 'toconly' :0,'toc' :0,'gui' :0 }
  12. T = CMDLINE = ''
  13. splitlevel = '' ; lang = 'english'
  14. doctype = outfile = ''
  15. pipefileid = '-'
  16. versionstr = "txt2tags version %s <%s>"%(my_version,my_url)
  17. usage = """
  18. %s
  19. usage: txt2tags -t <type> [OPTIONS] file.t2t
  20. txt2tags -t html -s <split level> -l <lang> file.t2t
  21. -t, --type target document type. actually supported:
  22. %s
  23. --stdout by default, the output is written to file.<type>
  24. with this option, STDOUT is used (no files written)
  25. --noheaders suppress header, title and footer information
  26. --enumtitle enumerate all title lines as 1, 1.1, 1.1.1, etc
  27. --maskemail hide email from spam robots. x@y.z turns to <x (a) y z>
  28. --toc add TOC (Table of Contents) to target document
  29. --toconly print document TOC and exit
  30. --gui invoke Graphical Tk Interface
  31. -h, --help print this help information and exit
  32. -V, --version print program version and exit
  33. extra options for HTML target (needs sgml-tools):
  34. --split split documents. values: 0, 1, 2 (default 0)
  35. --lang document language (default english)
  36. """%(versionstr, re.sub(r"[]'[]",'',repr(tags)))
  37. def Quit(msg, exitcode=0): print msg ; sys.exit(exitcode)
  38. def Error(msg): print "ERROR: %s"%msg ; sys.exit()
  39. def Debug(msg,i=0):
  40. if i > DEBUG: return
  41. print "(%d) %s"%(i,msg)
  42. def Readfile(file):
  43. if file == '-':
  44. try: data = sys.stdin.readlines()
  45. except: Error('You must feed me with data on STDIN!')
  46. else:
  47. try: f = open(file); data = f.readlines() ; f.close()
  48. except: Error("Cannot read file:\n %s"%file)
  49. return data
  50. def reset_flags():
  51. global FLAGS
  52. for flag in FLAGS.keys(): FLAGS[flag] = 0
  53. def set_outfile_name(infile, doctype):
  54. "dirname is the same for {in,out}file"
  55. if not infile: return
  56. if infile == pipefileid or FLAGS['toconly'] or FLAGS['stdout']:
  57. outfile = pipefileid
  58. else:
  59. outfile = "%s.%s"%(re.sub('\.(txt|t2t)$','',infile), doctype)
  60. Debug(" infile: '%s'"% infile, 1)
  61. Debug("outfile: '%s'"%outfile, 1)
  62. return outfile
  63. def finish_him(outlist, outfile):
  64. "writing output to screen or file"
  65. if outfile == pipefileid:
  66. for line in outlist: print line
  67. else:
  68. f = open(outfile, 'w'); f.writelines(addLineBreaks(outlist)); f.close()
  69. if not FLAGS['gui']: print 'wrote %s'%(outfile)
  70. if splitlevel:
  71. print "--- html..."
  72. os.system('sgml2html --language=%s --split=%s %s'%(
  73. lang,splitlevel,outfile))
  74. def ParseCmdline(cmdline=sys.argv):
  75. "return a dic with all options:value found"
  76. global CMDLINE ; CMDLINE = cmdline # save for dofooter()
  77. options = {'infile': ''}
  78. # get cmdline options
  79. longopt = ['help', 'version', 'type=', 'split=', 'lang=']+FLAGS.keys()
  80. try: (opt, args) = getopt.getopt(cmdline[1:], 'hVt:', longopt)
  81. except getopt.GetoptError:
  82. Error('bad option or missing argument (try --help)')
  83. # get infile, if any
  84. if args: options['infile'] = args[0]
  85. for name,val in opt:
  86. # parse information options
  87. if name in ['-h','--help' ]: Quit(usage)
  88. elif name in ['-V','--version']: Quit(versionstr)
  89. # parse short/long options
  90. elif name in ['-t','--type']: options['doctype'] = val ; continue
  91. # just long options
  92. options[name[2:]] = val # del --
  93. Debug("cmdline options: %s"%options, 1)
  94. return options
  95. def ParseCmdlineOptions(optdic):
  96. "set vars and flags according to options dic"
  97. global FLAGS, splitlevel, lang
  98. # store flags and vars
  99. myflags = [] # for debug msg
  100. for flag in FLAGS.keys():
  101. if optdic.has_key(flag): FLAGS[flag] = 1 ; myflags.append(flag)
  102. doctype = optdic.get('doctype')
  103. infile = optdic.get('infile')
  104. splitlevel = optdic.get('split')
  105. lang = optdic.get('lang')
  106. Debug("cmdline flags: %s"%string.join(myflags,', '), 1)
  107. if not doctype and FLAGS['toconly']: doctype = 'txt' # toconly default type
  108. if not infile or not doctype: Quit(usage, 1) # no filename/doctype
  109. # sanity check: validate target type
  110. if not tags.count(doctype):
  111. Error("invalid document type '%s' (try --help)"%(doctype))
  112. outfile = set_outfile_name(infile, doctype)
  113. # sanity check: validate split level
  114. if doctype != 'html': splitlevel = '' # only valid for HTML target
  115. if splitlevel:
  116. # checkings
  117. if outfile == pipefileid:
  118. Error('You need to provide a FILE (not STDIN) when using --split')
  119. if splitlevel[0] not in '012':
  120. Error('Option --split must be 0, 1 or 2')
  121. # check for sgml-tools
  122. #TODO how to test (in a clever way) if an executable is in path?
  123. #TODO os.system() return code? sgml2html without --help exit 0 also?
  124. # Error("Sorry, you must have 'sgml2html' program to use --split")
  125. # set things
  126. FLAGS['stdout'] = 0 # no --stdout
  127. doctype = 'sgml' # 1st do a sgml, then sgml2html
  128. outfile = set_outfile_name(infile, doctype)
  129. # sanity check: source loss!
  130. if infile != pipefileid and infile == outfile:
  131. Error("SUICIDE WARNING!!! (try --stdout)\n source"+\
  132. " and target files has the same name: %s"%outfile)
  133. ### yes, i've got my sample.t2t file deleted before add this test... :/
  134. return infile,outfile,doctype
  135. #TODO splitlevel, lang
  136. #---End of ParseCmdlineOptions
  137. def toc_master(doctype, header, doc, toc):
  138. "decide to include TOC or not on the outlist"
  139. # deal with the TOC options
  140. if FLAGS['toc'] or FLAGS['toconly']:
  141. # format TOC lines
  142. ### here we do toc as a valid t2t marked text (list type)
  143. FLAGS['noheaders'] = 1
  144. x,y,toc = doitall(['']+toc+['',''], doctype)
  145. # TOC between bars (not for --toconly)
  146. if FLAGS['toc']:
  147. para = TAGparagraph[T]
  148. tocbar = [para, re_x.sub('-'*72,TAGbar1[T]), para]
  149. toc = tocbar + toc + tocbar
  150. if FLAGS['toconly']: header = doc = []
  151. else:
  152. toc = []
  153. return header + toc + doc
  154. # check if we will enter on GUI mode
  155. if len(sys.argv) == 2 and sys.argv[1] == '--gui':
  156. FLAGS['gui'] = 1
  157. if len(sys.argv) == 1 and sys.platform[:3] in ['mac','cyg','win']:
  158. FLAGS['gui'] = 1
  159. # check for GUI mode ressorces
  160. if FLAGS['gui'] == 1:
  161. try:
  162. from tkFileDialog import askopenfilename
  163. from tkMessageBox import showinfo, showwarning, showerror
  164. import Tkinter
  165. except:
  166. # if GUI was forced, show the error message
  167. if len(sys.argv) > 1 and sys.argv[1] == '--gui':
  168. traceback.print_exc()
  169. sys.exit()
  170. # or just abandon GUI mode, and continue
  171. else:
  172. FLAGS['gui'] = 0
  173. # set the Line Break across platforms
  174. LB = '\n' # default
  175. if sys.platform[:3] == 'win': LB = '\r\n'
  176. #elif sys.platform[:3] == 'cyg': LB = '\r\n' # not sure if it's best :(
  177. elif sys.platform[:3] == 'mac': LB = '\r'
  178. ### all the registered tags
  179. TAGparagraph = ['', '<p>', '<P>', '<@Normal:>', '%font "normal", size 5\n', '', '.P']
  180. TAGtitle1 = [' \a' , '<sect>\a<p>' , '<H1>\a</H1>', '\n<@Title1:>\a', '%page\n\n\a', '= \a =', '.SH \a']
  181. TAGtitle2 = ['\t\a' , '<sect1>\a<p>', '<H2>\a</H2>', '\n<@Title2:>\a', '%page\n\n\a', '== \a ==', '.SS \a']
  182. TAGtitle3 = ['\t\t\a' , '<sect2>\a<p>', '<H3>\a</H3>', '\n<@Title3:>\a', '%page\n\n\a', '=== \a ===', '.SS \a']
  183. TAGtitle4 = ['\t\t\t\a' , '<sect3>\a<p>', '<H4>\a</H4>', '\n<@Title4:>\a', '%page\n\n\a', '==== \a ====', '.SS \a']
  184. TAGtitle5 = ['\t\t\t\t\a', '<sect4>\a<p>', '<H5>\a</H5>', '\n<@Title5:>\a', '%page\n\n\a', '===== \a =====', '.SS \a']
  185. TAGareaPreOpen = ['', '<tscreen><verb>', '<PRE>', '<@PreFormat:>', '\n%font "mono"', '{{{', '.nf']
  186. TAGareaPreClose = ['', '</verb></tscreen>', '</PRE>', '', '%font "normal"', '}}}', '.fi\n']
  187. TAGareaQuoteOpen = [' ', '<quote>', '<BLOCKQUOTE>', '<@Quote:>', '%prefix " "', ' ', '\n']
  188. TAGareaQuoteClose = ['', '</quote>', '</BLOCKQUOTE>', '', '%prefix " "', '', '\n']
  189. TAGfontMonoOpen = ['', '<tt>', '<CODE>', '<FONT "Lucida Console"><SIZE 9>', '\n%cont, font "mono"\n', '{{{', '']
  190. TAGfontMonoClose = ['', '</tt>', '</CODE>', '<SIZE$><FONT$>', '\n%cont, font "normal"\n', '}}}', '']
  191. TAGfontBoldOpen = ['', '<bf>', '<B>', '<B>', '\n%cont, font "normal-b"\n', "'''", r'\\fB']
  192. TAGfontBoldClose = ['', '</bf>', '</B>', '<P>', '\n%cont, font "normal"\n', "'''", r'\\fP']
  193. TAGfontItalicOpen = ['', '<em>', '<I>', '<I>', '\n%cont, font "normal-i"\n', "''", r'\\fI']
  194. TAGfontItalicClose = ['', '</em>', '</I>', '<P>', '\n%cont, font "normal"\n', "''", r'\\fP']
  195. TAGfontBoldItalicOpen = ['', '<bf><em>', '<B><I>', '<B><I>', '\n%cont, font "normal-bi"\n', "'''''", '\n.BI ']
  196. TAGfontBoldItalicClose = ['', '</em></bf>', '</I></B>', '<P>', '\n%cont, font "normal"\n', "'''''", '\n\\&']
  197. TAGfontUnderlineOpen = ['', TAGfontBoldItalicOpen[1], '<U>', '<U>', '\n%cont, fore "cyan"\n', TAGfontBoldItalicOpen[5], '']
  198. TAGfontUnderlineClose = ['', TAGfontBoldItalicClose[1], '</U>', '<P>', '\n%cont, fore "white"\n', TAGfontBoldItalicClose[5], '']
  199. TAGlistOpen = ['', '<itemize>', '<UL>', '<@Bullet:>', '', '', '\n'+TAGareaPreOpen[6]]
  200. TAGlistClose = ['', '</itemize>', '</UL>', '', '', '', TAGareaPreClose[6]]
  201. TAGlistItem = ['- ', '<item>', '<LI>', '\x95 ', '', '* ', '* '] # ~U
  202. TAGnumlistOpen = ['', '<enum>', '<OL>', '<@Bullet:>', '', '', '\n'+TAGareaPreOpen[6]]
  203. TAGnumlistClose = ['', '</enum>', '</OL>', '', '', '', TAGareaPreClose[6]]
  204. TAGnumlistItem = ['\a. ', '<item>', '<LI>', '~U ', '\a. ', '\a. ', '\a. ']
  205. TAGdeflistOpen = ['', '', '<DL>' , '', '', '', '']
  206. TAGdeflistItem1 = ['', '', '<DT>\a</DT>', '', '', '', '']
  207. TAGdeflistItem2 = ['', '', '<DD>' , '', '', '', ''] #TODO must close?
  208. TAGdeflistClose = ['', '', '</DL>' , '', '', '', '']
  209. TAGbar1 = ['\a', '<!-- \a -->', '<HR NOSHADE SIZE=1>', '\a', '%bar "white" 5', '----', '\n\n']
  210. TAGbar2 = ['\a', '<!-- \a -->', '<HR NOSHADE SIZE=5>', '\a', '%pause', '----', '\n\n']
  211. TAGurl = ['\a', '<htmlurl url="\a" name="\a">', '<A HREF="\a">\a</A>', TAGfontUnderlineOpen[3]+'\a'+TAGfontUnderlineClose[3], '\n%cont, fore "cyan"\n\a\n%cont, fore "white"\n', '[\a]', '\a']
  212. TAGurlMark = ['\a (\a)', TAGurl[1], TAGurl[2], '\a '+TAGurl[3], '\a '+TAGurl[4], '[\a \a]', '\a (\a)']
  213. TAGemail = ['\a', '<htmlurl url="mailto:\a" name="\a">', '<A HREF="mailto:\a">\a</A>', '\a', TAGurl[4], '[\a]', '\a']
  214. TAGemailMark = ['\a (\a)', TAGemail[1], TAGemail[2], '\a '+TAGemail[3], '\a '+TAGemail[4], '[\a \a]', '\a (\a)']
  215. TAGemail = ['\a', '<htmlurl url="mailto:\a" name="\a">', '<A HREF="mailto:\a">\a</A>', '\a', TAGurl[4], '[\a]', '\a']
  216. TAGimg = ['[\a]', '<figure><ph vspace=""><img src="\a"></figure>', '<IMG ALIGN="\a" SRC="\a">', '\a', '\n%center\n%newimage "\a", left\n', '[\a]', '\a']
  217. TAGtableOpen = [ '', '<table><tabular ca="c">', '<table align=center cellpadding=4 border=\a>', '', '', '', '']
  218. TAGtableLineOpen = [ '', '', '<tr>', '', '', '||', '']
  219. TAGtableLineClose = [ '', '<rowsep>', '</tr>', '', '', '', '']
  220. TAGtableCellOpen = [ '', '', '<td>', '', '', '', '']
  221. TAGtableCellClose = [ '', '<colsep>', '</td>', '', '', '||', '']
  222. TAGtableTitleCellOpen = [ '', '', '<th>', '', '', '', '']
  223. TAGtableTitleCellClose = [ '', '<colsep>', '</th>', '', '', '||', '']
  224. TAGtableClose = [ '', '</tabular></table>', '</table>', '', '', '', '']
  225. TAGanchor = ['', '', '<a name="\a">', '', '', '', '']
  226. TAGEOD = ['', '</article>', '</BODY></HTML>', '', '%%EOD', '', '']
  227. ### the cool regexes
  228. re_title = re.compile(r'^\s*(?P<tag>={1,5})(?P<txt>[^=].*[^=])\1(\[(?P<label>\w+)\])?$')
  229. re_areaPreOpen = re_areaPreClose = re.compile(r'^---$')
  230. re_quote = re.compile(r'^\t+')
  231. re_1linePreOld = re.compile(r'^ {4}([^\s-])')
  232. re_1linePre = re.compile(r'^--- ')
  233. re_mono = re.compile(r'`([^`]+)`')
  234. re_bold = re.compile(r'\*\*([^\s*].*?)\*\*')
  235. re_italic = re.compile(r'(^|[^:])//([^ /].*?)//')
  236. re_underline = re.compile(r'__([^_].*?)__') # underline lead/trailing blank
  237. re_bolditalic = re.compile(r'\*/([^/].*?)/\*')
  238. re_list = re.compile(r'^( *)([+-]) ([^ ])')
  239. re_deflist = re.compile(r'^( *)(=) ([^:]+):')
  240. re_bar =re.compile(r'^\s*([_=-]{20,})\s*$')
  241. re_table = re.compile(r'^ *\|\|?[<:>]*\s')
  242. # link things
  243. urlskel = {
  244. 'proto' : r'(https?|ftp|news|telnet|gopher|wais)://',
  245. 'guess' : r'(www[23]?|ftp)\.', # w/out proto, try to guess
  246. 'login' : r'A-Za-z0-9_.-', # for ftp://login@domain.com
  247. 'pass' : r'[^ @]*', # for ftp://login:password@domain.com
  248. 'chars' : r'A-Za-z0-9%._/~:,=-', # %20(space), :80(port)
  249. 'anchor': r'A-Za-z0-9%._-', # %nn(encoded)
  250. 'form' : r'A-Za-z0-9/%&=+.@*_-',# .@*_-(as is)
  251. 'punct' : r'.,;:!?'
  252. }
  253. patt_url_login = r'([%s]+(:%s)?@)?'%(urlskel['login'],urlskel['pass'])
  254. retxt_url = r'\b(%s%s|%s)[%s]+(#[%s]+|\?[%s]+)?(?=[%s]|[^%s]|$)\b'%(
  255. urlskel['proto'],patt_url_login, urlskel['guess'],
  256. urlskel['chars'],urlskel['anchor'],
  257. urlskel['form'] ,urlskel['punct'],urlskel['form'])
  258. retxt_url_local = r'[%s]+|[%s]*(#[%s]+)'%(
  259. urlskel['chars'],urlskel['chars'],urlskel['anchor'])
  260. retxt_email = r'\b[%s]+@([A-Za-z0-9_-]+\.)+[A-Za-z]{2,4}(\?[%s]+)?\b'%(
  261. urlskel['login'],urlskel['form'])
  262. re_link = re.compile(r'%s|%s'%(retxt_url,retxt_email), re.I)
  263. re_linkmark = re.compile(r'\[([^]]*) (%s|%s|%s)\]'%(
  264. retxt_url, retxt_email, retxt_url_local))
  265. re_x = re.compile('\a')
  266. re_blankline = re.compile(r'^\s*$')
  267. re_comment = re.compile(r'^//')
  268. re_date = re.compile(r'%%date\b(\((?P<fmt>.*?)\))?', re.I)
  269. re_img = re.compile(r'\[([\w_,.+%$#@!?+~/-][\w_,.+%$#@!?+~/ -]+\.(png|jpe?g|gif|eps|bmp))\]', re.L+re.I)
  270. def doHeader(doctype, title, author, date):
  271. ret = []
  272. title = string.strip(title)
  273. author = string.strip(author)
  274. date = string.strip(date)
  275. if doctype == 'txt':
  276. ret.append("%s\n%s\n%s"%(title,author,date))
  277. elif doctype == 'sgml':
  278. ret.append("<!doctype linuxdoc system>\n<article>")
  279. ret.append("<title>%s\n<author>%s\n<date>%s\n"%(title,author,date))
  280. elif doctype == 'html':
  281. ret.append('<HTML>\n<HEAD><TITLE>%s</TITLE></HEAD>'%title)
  282. ret.append('<BODY BGCOLOR="white" TEXT="black">')
  283. ret.append('<P ALIGN="center"><CENTER><H1>%s</H1>'%title)
  284. ret.append('<FONT SIZE=4><I>%s</I><BR>'%author)
  285. ret.append('%s</FONT></CENTER>\n'%date)
  286. elif doctype == 'man':
  287. # TODO man section 1 is hardcoded...
  288. ret.append('.TH "%s" 1 %s "%s"'%(title,date,author))
  289. elif doctype == 'pm6':
  290. # TODO style to <HR>
  291. ret.append("""\
  292. <PMTags1.0 win><C-COLORTABLE ("Preto" 1 0 0 0)
  293. ><@Normal=
  294. <FONT "Times New Roman"><CCOLOR "Preto"><SIZE 11>
  295. <HORIZONTAL 100><LETTERSPACE 0><CTRACK 127><CSSIZE 70><C+SIZE 58.3>
  296. <C-POSITION 33.3><C+POSITION 33.3><P><CBASELINE 0><CNOBREAK 0><CLEADING -0.05>
  297. <GGRID 0><GLEFT 7.2><GRIGHT 0><GFIRST 0><G+BEFORE 7.2><G+AFTER 0>
  298. <GALIGNMENT "justify"><GMETHOD "proportional"><G& "ENGLISH">
  299. <GPAIRS 12><G% 120><GKNEXT 0><GKWIDOW 0><GKORPHAN 0><GTABS $>
  300. <GHYPHENATION 2 34 0><GWORDSPACE 75 100 150><GSPACE -5 0 25>
  301. ><@Bullet=<@-PARENT "Normal"><FONT "Abadi MT Condensed Light">
  302. <GLEFT 14.4><G+BEFORE 2.15><G% 110><GTABS(25.2 l "")>
  303. ><@PreFormat=<@-PARENT "Normal"><FONT "Lucida Console"><SIZE 8><CTRACK 0>
  304. <GLEFT 0><G+BEFORE 0><GALIGNMENT "left"><GWORDSPACE 100 100 100><GSPACE 0 0 0>
  305. ><@Title1=<@-PARENT "Normal"><FONT "Arial"><SIZE 14><B>
  306. <GCONTENTS><GLEFT 0><G+BEFORE 0><GALIGNMENT "left">
  307. ><@Title2=<@-PARENT "Title1"><SIZE 12><G+BEFORE 3.6>
  308. ><@Title3=<@-PARENT "Title1"><SIZE 10><GLEFT 7.2><G+BEFORE 7.2>
  309. ><@Title4=<@-PARENT "Title3">
  310. ><@Title5=<@-PARENT "Title3">
  311. ><@Quote=<@-PARENT "Normal"><SIZE 10><I>>
  312. """)
  313. elif doctype == 'mgp':
  314. ret.append("""\
  315. #!/usr/X11R6/bin/mgp -t 90
  316. %deffont "normal" xfont "utopia-medium-r", charset "iso8859-1"
  317. %deffont "normal-i" xfont "utopia-medium-i", charset "iso8859-1"
  318. %deffont "normal-b" xfont "utopia-bold-r" , charset "iso8859-1"
  319. %deffont "normal-bi" xfont "utopia-bold-i" , charset "iso8859-1"
  320. %deffont "mono" xfont "courier-medium-r", charset "iso8859-1"
  321. %default 1 size 5
  322. %default 2 size 8, fore "yellow", font "normal-b", center
  323. %default 3 size 5, fore "white", font "normal", left, prefix " "
  324. %tab 1 size 4, vgap 30, prefix " ", icon arc "red" 40, leftfill
  325. %tab 2 prefix " ", icon arc "orange" 40, leftfill
  326. %tab 3 prefix " ", icon arc "brown" 40, leftfill
  327. %tab 4 prefix " ", icon arc "darkmagenta" 40, leftfill
  328. %tab 5 prefix " ", icon arc "magenta" 40, leftfill
  329. %%%%%%%%%%%%%%%%%%%%%%%%%% end of headers %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  330. %page
  331. """)
  332. # 1st title page
  333. ret.append('\n\n\n\n%%size 10, center, fore "yellow"\n%s'%title)
  334. ret.append('\n%%font "normal-i", size 6, fore "white", center')
  335. ret.append('%s\n\n%%font "mono", size 7, center\n%s'%(author,date))
  336. elif doctype == 'moin':
  337. pass #TODO
  338. else:
  339. Error("doheader: Unknow doctype '%s'"%doctype)
  340. return ret
  341. def doCommentLine(doctype,txt):
  342. if doctype == 'sgml' or doctype == 'html': ret = "<!-- %s -->"%txt
  343. elif doctype == 'mgp': ret = "%%%% %s"%txt
  344. elif doctype == 'man': ret = '.\\" %s'%txt
  345. else: ret = ''
  346. return ret
  347. def doFooter(doctype):
  348. ret = []
  349. ppgd = '%s code generated by txt2tags %s (%s)'%(doctype,my_version,my_url)
  350. cmdline = 'cmdline: txt2tags %s'%string.join(CMDLINE[1:], ' ')
  351. ret.append('\n'+doCommentLine(doctype,ppgd))
  352. ret.append(doCommentLine(doctype,cmdline))
  353. ret.append(TAGEOD[T])
  354. return ret
  355. def doEscape(doctype,txt):
  356. if doctype == 'html' or doctype == 'sgml':
  357. txt = re.sub('&','&amp;',txt)
  358. txt = re.sub('<','&lt;',txt)
  359. txt = re.sub('>','&gt;',txt)
  360. if doctype == 'sgml': txt = re.sub('\xff','&yuml;',txt) # "+y
  361. elif doctype == 'pm6' : txt = re.sub('<','<\#60>',txt)
  362. elif doctype == 'mgp' : txt = re.sub('^%([^%])','%prefix ""\n %\n%cont, prefix " "\n\\1',txt)
  363. elif doctype == 'man' : txt = re.sub('^\.', ' .',txt) # command ID
  364. return txt
  365. def doEscapeEscape(txt):
  366. while re.search(r'\\<', txt):
  367. txt = re.sub(r'\\<','<\#92><',txt)
  368. return txt
  369. def addLineBreaks(list):
  370. "use LB to respect sys.platform"
  371. ret = []
  372. for line in list:
  373. line = string.replace(line,'\n',LB) # embedded \n's
  374. ret.append(line+LB) # add final line break
  375. return ret
  376. ################################################################################
  377. ###MerryChristmas,IdontwanttofighttonightwithyouImissyourbodyandIneedyourlove###
  378. ################################################################################
  379. def doitall(inlines, doctype):
  380. global T
  381. # the defaults
  382. title = 'document title'
  383. author = 'author name'
  384. currdate = strftime('%Y%m%d',localtime(time())) # ISO current date
  385. date = currdate
  386. linkmask = '@@_@_@@'
  387. monomask = '@@_m_@@'
  388. T = tags.index(doctype)
  389. ret = []
  390. toclist = []
  391. header = []
  392. f_tt = 0
  393. listident = []
  394. listids = []
  395. listcount = []
  396. titlecount = ['',0,0,0,0,0]
  397. f_header = 0
  398. f_lastblank = 0
  399. holdspace = ''
  400. listholdspace = ''
  401. quotedepth = 0
  402. istable = 0
  403. tableborder = 0
  404. tablealign = []
  405. if outfile != pipefileid:
  406. if not FLAGS['gui']: print "--- %s..."%doctype
  407. # let's mark it up!
  408. linenr = 0
  409. for lineref in range(len(inlines)):
  410. skip_continue = 0
  411. urlbank = [] ; emailbank = []
  412. linkbank = []
  413. monobank = []
  414. linenr = lineref +1
  415. line = string.rstrip(inlines[lineref])
  416. # we need (not really) to mark each paragraph
  417. if doctype == 'pm6' and f_lastblank:
  418. if f_tt or f_header or listident: holdspace = ''
  419. else: holdspace = TAGparagraph[T]+'\n'
  420. # PRE-formatted area
  421. # we'll never support beautifiers inside pre-formatted
  422. if f_tt:
  423. f_lastblank = 0
  424. line = doEscape(doctype,line)
  425. # closing PRE
  426. if re_areaPreClose.search(line):
  427. if doctype != 'pm6': ret.append(TAGareaPreClose[T])
  428. f_tt = 0
  429. continue
  430. # normal PRE-inside line
  431. if doctype == 'pm6': line = doEscapeEscape(line)
  432. elif doctype in ('txt', 'man', 'html'): line = ' '+line # align
  433. ret.append(line)
  434. continue
  435. # detecting PRE
  436. if re_areaPreOpen.search(line):
  437. line = doEscape(doctype,line)
  438. if f_tt:
  439. warn = "WARNING:%d:opening PRE-formatted tag"%linenr
  440. Debug("%s without closing previous one"%warn, 1)
  441. ret.append(line)
  442. continue
  443. ret.append(TAGareaPreOpen[T])
  444. f_tt = 1
  445. continue
  446. # one line PRE-formatted text
  447. if re_1linePre.search(line):
  448. f_lastblank = 0
  449. line = doEscape(doctype,line)
  450. line = re_1linePre.sub('',line)
  451. if doctype == 'pm6': line = doEscapeEscape(line)
  452. if doctype in ('txt', 'man', 'html'): line = ' '+line # align
  453. ret.append('%s\n%s\n%s'%(TAGareaPreOpen[T],line,TAGareaPreClose[T]))
  454. continue
  455. # blank lines
  456. #TODO "holdspace" to save <p> to not show in closelist
  457. if re_blankline.search(line):
  458. if istable:
  459. if istableaware: ret.append(TAGtableClose[T])
  460. else: ret.append(TAGareaPreClose[T])
  461. istable = tableborder = 0
  462. continue
  463. #TODO generic class or function to close quotes/lists/tables
  464. # when entering pre,list,table,etc
  465. # closing quotes
  466. while quotedepth:
  467. quotedepth = quotedepth-1
  468. ret.append(TAGareaQuoteClose[T])
  469. if f_lastblank: # 2nd consecutive blank line
  470. if listident: # closes list (if any)
  471. while len(listident):
  472. if listids[-1] == '-': tag = TAGlistClose[T]
  473. elif listids[-1] == '+': tag = TAGnumlistClose[T]
  474. elif listids[-1] == '=': tag = TAGdeflistClose[T]
  475. if not tag: tag = TAGlistClose[T] # default
  476. if tag: # man tags just for mother-list and at ^
  477. if doctype == 'man':
  478. if len(listident) == 1: ret.append(tag)
  479. else: ret.append(listident[-1]+tag)
  480. del listident[-1]
  481. del listids[-1]
  482. # add visual separator line for the mother list
  483. if not listids and doctype == 'txt': ret.append('\n')
  484. holdspace = ''
  485. continue # consecutive blanks are trash
  486. if f_header or linenr == 1: # 1st blank after header (if any)
  487. # headers with less than 3 lines
  488. if linenr == 2: author = date = ''
  489. elif linenr == 3: date = ''
  490. if not FLAGS['noheaders']:
  491. header = doHeader(doctype,title,author,date)
  492. if doctype != 'pm6': ret.append(TAGparagraph[T])
  493. f_header = 0 # we're done with header
  494. continue
  495. # normal blank line
  496. if doctype != 'pm6':
  497. # paragraph (if any) is wanted inside lists also
  498. if listident:
  499. holdspace = holdspace+TAGparagraph[T]+'\n'
  500. elif doctype == 'html': ret.append(TAGparagraph[T])
  501. # sgml: the quote close tag must not be \n\n</quote>
  502. elif doctype == 'sgml' and quotedepth:
  503. skip_continue = 1
  504. # otherwise we just print a blank line
  505. else: ret.append('')
  506. f_lastblank = 1
  507. if not skip_continue: continue
  508. else:
  509. f_lastblank = 0 # reset blank status
  510. # first line with no header
  511. if FLAGS['noheaders'] and linenr == 1 and doctype != 'pm6':
  512. ret.append(TAGparagraph[T])
  513. # comments
  514. # just skip them
  515. if re_comment.search(line):
  516. f_lastblank = 1
  517. continue
  518. # protect pre-formatted font text from escaping and formatting
  519. if not f_tt:
  520. while re_mono.search(line):
  521. txt = re_mono.search(line).group(1)
  522. monobank.append(doEscape(doctype,txt))
  523. line = re_mono.sub(monomask,line,1)
  524. # protect URLs and emails from escaping and formatting
  525. # changing them by a mask
  526. if not f_tt:
  527. while re_linkmark.search(line): # search for named link
  528. m = re_linkmark.search(line)
  529. # remove quotes from old ["" link] tag
  530. label = re.sub('^"|"$','',m.group(1))
  531. link = m.group(2)
  532. linkbank.append([label, link])
  533. line = re_linkmark.sub(linkmask,line,1)
  534. while re_link.search(line): # simple url or email
  535. link = re_link.search(line).group()
  536. linkbank.append(['', link])
  537. line = re_link.sub(linkmask,line,1)
  538. # the target-specific special char escapes
  539. line = doEscape(doctype,line)
  540. # HR line
  541. if re_bar.search(line):
  542. txt = re_bar.search(line).group(1)
  543. if txt[0] == '=': bar = TAGbar2[T]
  544. else : bar = TAGbar1[T]
  545. line = re_bar.sub(bar,line)
  546. ret.append(re_x.sub(txt,line))
  547. continue
  548. # quote
  549. if re_quote.search(line):
  550. currquotedepth = len(re_quote.search(line).group(0)) # TABs number
  551. if doctype == 'sgml' and quotedepth and currquotedepth > quotedepth:
  552. currquotedepth = quotedepth
  553. if not TAGareaQuoteClose[T]:
  554. line = re_quote.sub(TAGareaQuoteOpen[T]*currquotedepth, line)
  555. else:
  556. # new (sub)quote
  557. if not quotedepth or currquotedepth > quotedepth:
  558. quotedepth = currquotedepth
  559. ret.append(TAGareaQuoteOpen[T])
  560. if doctype != 'html'and doctype != 'sgml':
  561. line = re_quote.sub('', line)
  562. # closing quotes
  563. while currquotedepth < quotedepth:
  564. quotedepth = quotedepth-1
  565. ret.append(TAGareaQuoteClose[T])
  566. else:
  567. # closing quotes
  568. while quotedepth:
  569. quotedepth = quotedepth-1
  570. ret.append(TAGareaQuoteClose[T])
  571. # title
  572. #TODO set next blank and set f_lastblank or f_lasttitle
  573. if re_title.search(line) and not listident:
  574. m = re_title.search(line)
  575. tag = m.group('tag')
  576. level = len(tag)
  577. tag = eval('TAGtitle%s[T]'%level)
  578. txt = string.strip(m.group('txt'))
  579. if doctype == 'sgml':
  580. txt = re.sub(r'\[', r'&lsqb;', txt)
  581. txt = re.sub(r'\\', r'&bsol;', txt)
  582. if FLAGS['enumtitle']: ### numbered title
  583. id = '' ; n = level #
  584. titlecount[n] = titlecount[n] +1 # add count
  585. if n < len(titlecount)-1: # reset sublevels count
  586. for i in range(n+1, len(titlecount)): titlecount[i] = 0
  587. for i in range(n): # compose id from hierarchy
  588. id = "%s%d."%(id,titlecount[i+1])
  589. txt = "%s %s"%(id, txt) # add id to title
  590. anchorid = 'toc%d'%(len(toclist)+1)
  591. if TAGanchor[T] and FLAGS['toc']:
  592. ret.append(re_x.sub(anchorid,TAGanchor[T]))
  593. line = re_title.sub(tag,line)
  594. ret.append(re_x.sub(txt,line))
  595. # let's do some TOC!
  596. if TAGanchor[T]:
  597. tocitemid = '#toc%d'%(len(toclist)+1)
  598. tocitem = '%s- [%s #%s]'%(' '*level,txt,anchorid)
  599. else:
  600. tocitem = '%s- %s'%(' '*level,txt)
  601. if doctype in ['txt', 'man']:
  602. tocitem = '%s%s' %(' '*level,txt)
  603. if level <= 3: toclist.append(tocitem) # max toc level: 3
  604. # add "underline" to text titles
  605. if doctype == 'txt': ret.append(re_x.sub('='*len(txt),tag))
  606. continue
  607. #TODO!
  608. # labeltxt = ''
  609. # label = m.group('label')
  610. # if label: labeltxt = '<label id="%s">' %label
  611. # list
  612. if re_list.search(line) or re_deflist.search(line):
  613. if re_list.search(line): rgx = re_list
  614. else : rgx = re_deflist
  615. m = rgx.search(line)
  616. listitemident = m.group(1)
  617. listtype = m.group(2)
  618. extra = m.group(3) # regex anchor char
  619. if listtype == '=':
  620. listdefterm = m.group(3)
  621. extra = ''
  622. # new sublist
  623. if not listident or len(listitemident) > len(listident[-1]):
  624. listident.append(listitemident)
  625. listids.append(listtype)
  626. if listids[-1] == '-': tag = TAGlistOpen[T]
  627. elif listids[-1] == '+': tag = TAGnumlistOpen[T]
  628. elif listids[-1] == '=': tag = TAGdeflistOpen[T]
  629. if not tag: tag = TAGlistOpen[T] # default
  630. # no need to reopen <pre> tag on man sublists
  631. if doctype == 'man' and len(listident) != 1: tag = ''
  632. openlist = listident[-1]+tag
  633. if doctype == 'pm6': listholdspace = openlist
  634. else:
  635. if string.strip(openlist): ret.append(openlist)
  636. # reset item manual count
  637. listcount.append(0)
  638. # closing sublists
  639. while len(listitemident) < len(listident[-1]):
  640. if listids[-1] == '-': tag = TAGlistClose[T]
  641. elif listids[-1] == '+': tag = TAGnumlistClose[T]
  642. elif listids[-1] == '=': tag = TAGdeflistClose[T]
  643. if not tag: tag = TAGlistClose[T] # default
  644. if tag: # man list is just a <pre> text, closed at mother-list
  645. if doctype != 'man': ret.append(listident[-1]+tag)
  646. del listident[-1]
  647. del listids[-1]
  648. if listcount: del listcount[-1]
  649. # normal item
  650. listid = listident[-1]
  651. if listids[-1] == '-':
  652. tag = TAGlistItem[T]
  653. elif listids[-1] == '+':
  654. tag = TAGnumlistItem[T]
  655. listcount[-1] = listcount[-1] +1
  656. if doctype in ['txt', 'man', 'moin', 'mgp']:
  657. tag = re_x.sub(str(listcount[-1]), tag)
  658. elif listids[-1] == '=':
  659. if not TAGdeflistItem1[T]:
  660. # emulate def list, with <li><b>def</b>:
  661. tag = TAGlistItem[T] +TAGfontBoldOpen[T] +listdefterm
  662. tag = tag +TAGfontBoldClose[T] +':'
  663. else:
  664. tag = re_x.sub(listdefterm, TAGdeflistItem1[T])
  665. tag = tag + TAGdeflistItem2[T] # open <DD>
  666. if doctype == 'mgp': listid = len(listident)*'\t'
  667. line = rgx.sub(listid+tag+extra,line)
  668. if listholdspace:
  669. line = listholdspace+line
  670. listholdspace = ''
  671. if doctype == 'sgml': line = re.sub(r'\[', r'&lsqb;', line)
  672. # table
  673. #TODO escape undesired format inside table
  674. #TODO not rstrip if table line (above)
  675. #TODO add man, pm6 targets
  676. if re_table.search(line): # only HTML for now
  677. closingbar = re.compile(r'\| *$')
  678. tableid = line[re_table.search(line).end()-1]
  679. if not istable: # table header
  680. if doctype in ['sgml', 'html', 'moin']:
  681. istableaware = 1
  682. if tableid == '\t': tableborder = 1
  683. if closingbar.search(line): tableborder = 1
  684. # add border=1
  685. ret.append(re_x.sub(`tableborder`, TAGtableOpen[T]))
  686. else:
  687. istableaware = 0 ; ret.append(TAGareaPreOpen[T])
  688. istable = 1
  689. if istableaware:
  690. line = re.sub(r'^ *' , '', line) # del leading spaces
  691. line = closingbar.sub('', line) # del last bar |
  692. tablefmt, tablecel = re.split(r'\s', line, 1)
  693. tablefmt = tablefmt[1:] # cut mark off
  694. tablecel = re.split(r'\t\|?| \|', tablecel)
  695. line = ''
  696. # setting cell and line tags
  697. tl1, tl2 = TAGtableLineOpen[T], TAGtableLineClose[T]
  698. tc1, tc2 = TAGtableCellOpen[T], TAGtableCellClose[T]
  699. #TODO if ' | ' table cell is center align
  700. if tablefmt and tablefmt[0] == '|': # title cell
  701. tc1,tc2 = TAGtableTitleCellOpen[T],TAGtableTitleCellClose[T]
  702. if doctype == 'html': tc2 = tc2+'\n' ; tl1 = tl1+'\n'
  703. if tablecel:
  704. while tablecel:
  705. cel = tablecel.pop(0)
  706. if not cel and doctype == 'html':
  707. cel = '&nbsp;'
  708. else:
  709. # user escaped (not delim!)
  710. cel = string.replace(cel,'\|', '|')
  711. if not tablecel and doctype == 'sgml':
  712. tc2 = '' # last cell
  713. line = '%s%s%s%s'%(line,tc1,string.strip(cel),tc2)
  714. line = '%s%s%s'%(tl1,line,tl2)
  715. ### BEGIN of at-any-part-of-the-line/various-per-line TAGs.
  716. # date
  717. while re_date.search(line):
  718. m = re_date.search(line)
  719. fmt = m.group('fmt') or ''
  720. dateme = currdate
  721. if fmt: dateme = strftime(fmt,localtime(time()))
  722. line = re_date.sub(dateme,line,1)
  723. # bold
  724. if re_bold.search(line):
  725. txt = r'%s\1%s'%(TAGfontBoldOpen[T],TAGfontBoldClose[T])
  726. line = re_bold.sub(txt,line)
  727. # italic
  728. if re_italic.search(line):
  729. txt = r'\1%s\2%s'%(TAGfontItalicOpen[T],TAGfontItalicClose[T])
  730. line = re_italic.sub(txt,line)
  731. # bolditalic
  732. if re_bolditalic.search(line):
  733. txt = r'%s\1%s'%(TAGfontBoldItalicOpen[T],TAGfontBoldItalicClose[T])
  734. line = re_bolditalic.sub(txt,line)
  735. # underline
  736. if re_underline.search(line):
  737. txt = r'%s\1%s'%(TAGfontUnderlineOpen[T],TAGfontUnderlineClose[T])
  738. line = re_underline.sub(txt,line)
  739. # image
  740. # first store blanks to detect image at ^
  741. try: leadingblanks = re.match(' +',line).end()
  742. except: leadingblanks = 0
  743. # moin and txt tags are the same as the mark
  744. while re_img.search(line) and doctype not in ['moin','txt']:
  745. m = re_img.search(line)
  746. txt = m.group(1)
  747. ini = m.start() ; head = leadingblanks
  748. end = m.end() ; tail = len(line)
  749. tag = TAGimg[T]
  750. if doctype == 'html': # do img align
  751. align = 'center' # default align # text + img + text
  752. if ini == head and end == tail:
  753. tag = '<P ALIGN="center">%s</P>'%tag # ^img$
  754. elif ini == head: align = 'left' # ^img + text$
  755. elif end == tail: align = 'right' # ^text + img$
  756. tag = re_x.sub(align, tag, 1) # add align on tag
  757. line = re_img.sub(tag,line,1)
  758. line = re_x.sub(txt,line,1)
  759. if doctype == 'sgml': line = re.sub(r'\[', r'&lsqb;', line)
  760. line = '%s%s'%(' '*leadingblanks,line) # put blanks back
  761. # font PRE
  762. for mono in monobank:
  763. line = string.replace(line, monomask, "%s%s%s"%(
  764. TAGfontMonoOpen[T],mono,TAGfontMonoClose[T]),1)
  765. # URL & email
  766. for link in linkbank:
  767. linktype = 'url'; label = link[0]; url = link[1]
  768. if re.match(retxt_email, url): linktype = 'email'
  769. guessurl = '' # adding protocol to guessed link
  770. if linktype == 'url' and re.match(urlskel['guess'], url):
  771. if url[0] == 'w': guessurl = 'http://' +url
  772. else: guessurl = 'ftp://' +url
  773. if not label and not guessurl: # simple link
  774. if FLAGS['maskemail'] and linktype == 'email':
  775. url = string.replace(url,'@',' (a) ')
  776. url = string.replace(url,'.',' ')
  777. url = doEscape(doctype,"<%s>"%url)
  778. line = string.replace(line, linkmask, url, 1)
  779. else:
  780. line = eval('string.replace(line,linkmask,TAG%s[T],1)'%linktype)
  781. line = re_x.sub(url,line)
  782. else: # named link!
  783. if not label: label = url
  784. if guessurl: url = guessurl
  785. # putting data on the right appearance order
  786. urlorder = [label, url] # label before link
  787. if doctype in ('html', 'sgml', 'moin'): # link before label
  788. urlorder = [url, label]
  789. # replace mask with tag
  790. line = eval('string.replace(line,linkmask,TAG%sMark[T],1)'%linktype)
  791. for data in urlorder: # fill \a from tag with data
  792. line = re_x.sub(data,line,1)
  793. # header
  794. # only not empty lines will reach here
  795. if not FLAGS['noheaders']:
  796. if linenr == 1:
  797. title = line
  798. f_header = 1
  799. continue
  800. if f_header:
  801. if linenr == 2: author = line ; continue
  802. elif linenr == 3: date = line ; continue
  803. else:
  804. header = doHeader(doctype,title,author,date)
  805. f_header = 0
  806. # FINAL scapes. TODO function for it
  807. # convert all \ before <...> to tag
  808. if doctype == 'pm6': line = doEscapeEscape(line)
  809. elif doctype == 'man' : line = re.sub('-',r'\-',line)
  810. ret.append(holdspace+line)
  811. holdspace = ''
  812. # EOF: close open lists/tables (TODO function for it)
  813. #TODO see same code in blanks-code and list-code
  814. if listident: # closes list (if any)
  815. while len(listident):
  816. if listids[-1] == '-': tag = TAGlistClose[T]
  817. elif listids[-1] == '+': tag = TAGnumlistClose[T]
  818. elif listids[-1] == '=': tag = TAGdeflistClose[T]
  819. if not tag: tag = TAGlistClose[T] # default
  820. if tag: # man tags just for mother-list and at ^
  821. if doctype == 'man':
  822. if len(listident) == 1: ret.append(tag)
  823. else: ret.append(listident[-1]+tag)
  824. del listident[-1]
  825. del listids[-1]
  826. # add visual separator line for the mother list
  827. if not listids and doctype == 'txt': ret.append('\n')
  828. if istable:
  829. if istableaware: ret.append(TAGtableClose[T])
  830. else: ret.append(TAGareaPreClose[T])
  831. if not FLAGS['noheaders']: ret.extend(doFooter(doctype))
  832. return header,toclist,ret
  833. #TODO
  834. #class Txt2tags:
  835. # def __init__(self, cmdline):
  836. # self.read_instructions(cmdline)
  837. # self.gui_detect()
  838. # self.do_your_job()
  839. # def read_instructions(self, cmdline):
  840. # pass
  841. # def gui_detect(self):
  842. # pass
  843. # def do_your_job(self):
  844. # pass
  845. # def finish_him(self):
  846. # pass
  847. #
  848. #class CmdlineMaster:
  849. # def __init__(self, cmdline):
  850. # self.cmdline
  851. # self.flags = {}
  852. # self.infile = ''
  853. # self.outfile = ''
  854. # self.target = ''
  855. #
  856. #class TagMakerMachine:
  857. # def __init_(self,flags,doctype,inlines):
  858. # self.flags = flags # dic
  859. # self.target = doctype
  860. # self.cmdline = []
  861. # self.HEAD = []
  862. # self.TOC = []
  863. # self.DOCUMENT = []
  864. # self.FOOT = []
  865. #
  866. # TODO each formatting function should set flags
  867. # like: readnetxline: 1 , continue: 1, etc.
  868. # for func in [do_bold, do_under, ...]:
  869. # func(); if readnextline: read(); etc
  870. ################################################################################
  871. ##################################### GUI ######################################
  872. ################################################################################
  873. # tk help: http://python.org/topics/tkinter/
  874. class Gui:
  875. "Graphical Tk Interface"
  876. def __init__(self):
  877. self.bg = 'orange'
  878. self.root = Tkinter.Tk()
  879. self.root.config(bd=15,bg=self.bg)
  880. self.root.title("txt2tags")
  881. self.frame1 = Tkinter.Frame(self.root,bg=self.bg)
  882. self.frame1.pack(fill='x')
  883. self.frame2 = Tkinter.Frame(self.root,bg=self.bg)
  884. self.frame2.pack()
  885. self.frame3 = Tkinter.Frame(self.root,bg=self.bg)
  886. self.frame3.pack(fill='x')
  887. self.frame = self.root
  888. self.infile = self.setvar('')
  889. #self.infile = self.setvar('C:/cygwin/home/Milene/abc.txt')
  890. #self.infile = self.setvar('C:/aurelio/a.txt')
  891. self.doctype = self.setvar('html')
  892. self.f_noheaders = self.setvar('')
  893. self.f_enumtitle = self.setvar('')
  894. self.f_toc = self.setvar('')
  895. self.f_toconly = self.setvar('')
  896. self.f_stdout = self.setvar('')
  897. ### config as dic for python 1.5 compat (**opts don't work :( )
  898. def entry(self, **opts): return Tkinter.Entry(self.frame, opts)
  899. def label(self, txt='', **opts):
  900. opts.update({'text':txt,'bg':self.bg})
  901. return Tkinter.Label(self.frame, opts)
  902. def button(self,name,cmd,**opts):
  903. opts.update({'text':name,'command':cmd})
  904. return Tkinter.Button(self.frame, opts)
  905. def check(self,name,val,**opts):
  906. opts.update( {'text':name, 'onvalue':val, 'offvalue':'',
  907. 'anchor':'w', 'bg':self.bg, 'activebackground':self.bg} )
  908. Tkinter.Checkbutton(self.frame, opts).pack(fill='x',padx=10)
  909. ### config as positional parameters for python 2.*
  910. # def entry(self, **opts): return Tkinter.Entry(self.frame, **opts)
  911. # def label(self, txt='', **opts):
  912. # return Tkinter.Label(self.frame, text=txt, bg=self.bg, **opts)
  913. # def button(self,name,cmd,**opts):
  914. # return Tkinter.Button(self.frame, text=name, command=cmd, **opts)
  915. # def check(self,name,val,**opts):
  916. # Tkinter.Checkbutton(self.frame,text=name, onvalue=val, offvalue='',
  917. # anchor='w', bg=self.bg, activebackground=self.bg, **opts).pack(
  918. # fill='x',padx=10)
  919. def exit(self): self.root.destroy(); sys.exit()
  920. def setvar(self, val): z = Tkinter.StringVar() ; z.set(val) ; return z
  921. def menu(self,sel,items):
  922. return apply(Tkinter.OptionMenu,(self.frame,sel)+tuple(items))
  923. def askfile(self):
  924. ftypes = [("txt2tags files",("*.t2t","*.txt")),("All files","*")]
  925. self.infile.set(askopenfilename(filetypes=ftypes))
  926. def scrollwindow(self,txt='no text!',title=''):
  927. win = Tkinter.Toplevel() ; win.title(title)
  928. scroll = Tkinter.Scrollbar(win)
  929. text = Tkinter.Text(win,yscrollcommand=scroll.set)
  930. scroll.config(command=text.yview)
  931. text.insert(Tkinter.END, string.join(txt,'\n'))
  932. text.pack(side='left',fill='both')
  933. scroll.pack(side='right',fill='y')
  934. def runprogram(self):
  935. # prepare
  936. infile, doctype = self.infile.get(), self.doctype.get()
  937. if not infile:
  938. showwarning('txt2tags',"You must provide the source file location!")
  939. return
  940. # compose cmdline
  941. reset_flags(); FLAGS['gui'] = 1
  942. myflags = []
  943. for flag in FLAGS.keys():
  944. if flag in ['maskemail','gui']: continue # not supported
  945. flag = getattr(self, 'f_%s'%flag)
  946. if flag.get(): myflags.append(flag.get())
  947. cmdline = ['txt2tags', '-t', doctype] +myflags +[infile]
  948. Debug('Gui/tk cmdline: %s'%cmdline,1)
  949. # run!
  950. try:
  951. infile,outfile,doctype = ParseCmdlineOptions(ParseCmdline(cmdline))
  952. header,toc,doc = doitall(Readfile(infile), doctype)
  953. outlist = toc_master(doctype,header,doc,toc)
  954. if outfile == pipefileid:
  955. title = 'txt2tags: %s converted to %s'%(
  956. os.path.basename(infile),string.upper(doctype))
  957. self.scrollwindow(outlist, title)
  958. else:
  959. finish_him(outlist,outfile)
  960. msg = "FROM:\n\t%s\nTO:\n\t%s"%(infile,outfile)
  961. showinfo('txt2tags', "Conversion done!\n\n%s"%msg)
  962. except ZeroDivisionError: # common error, not quit
  963. pass
  964. except: # fatal error
  965. traceback.print_exc()
  966. print '\nSorry! txt2tags-Tk Fatal Error.'
  967. errmsg = 'Unknown error occurred.\n\nPlease send the Error '+\
  968. 'Traceback dumped to the author:\n %s'%my_email
  969. showerror('txt2tags FATAL ERROR!',errmsg)
  970. self.exit()
  971. def mainwindow(self):
  972. action1 = " \nChoose the target document type:"
  973. action2 = "\n\nEnter the tagged source file location:"
  974. action3 = "\n\nSome options you may check:"
  975. nohead_txt = "Source file has no headers"
  976. enum_txt = "Number titles (1, 1.1, 1.1.1, etc)"
  977. toc_txt = "Do TOC also (Table of Contents)"
  978. toconly_txt= "Just do TOC, nothing more"
  979. stdout_txt = "Dump to screen (Don't save target file)"
  980. self.frame = self.frame1
  981. self.label("TXT2TAGS\n%s"%my_url).pack()
  982. self.label(action1, anchor='w').pack(fill='x')
  983. self.menu(self.doctype, tags).pack()
  984. self.label(action2, anchor='w').pack(fill='x')
  985. self.frame = self.frame2
  986. self.entry(textvariable=self.infile).pack(side='left',padx=10)
  987. self.button("Browse", self.askfile).pack(side='right')
  988. self.frame = self.frame3
  989. self.label(action3, anchor='w').pack(fill='x')
  990. self.check(nohead_txt ,'--noheaders',variable=self.f_noheaders)
  991. self.check(enum_txt ,'--enumtitle',variable=self.f_enumtitle)
  992. self.check(toc_txt ,'--toc' ,variable=self.f_toc)
  993. self.check(toconly_txt,'--toconly' ,variable=self.f_toconly)
  994. self.check(stdout_txt ,'--stdout' ,variable=self.f_stdout)
  995. self.label('\n').pack()
  996. self.button("Quit", self.exit).pack(side='left',padx=40)
  997. self.button("Convert!", self.runprogram).pack(side='right',padx=40)
  998. # as documentation told me
  999. if sys.platform[:3] == 'win':
  1000. self.root.iconify()
  1001. self.root.update()
  1002. self.root.deiconify()
  1003. self.root.mainloop()
  1004. ################################################################################
  1005. ################################################################################
  1006. Debug("system platform: %s"%sys.platform,1)
  1007. Debug("line break char: %s"%repr(LB),1)
  1008. if FLAGS['gui'] == 1:
  1009. # redefine Error function to raise exception instead sys.exit()
  1010. def Error(msg): showerror('txt2tags ERROR!', msg); raise ZeroDivisionError
  1011. Gui().mainwindow()
  1012. else:
  1013. # console mode rocks forever!
  1014. infile, outfile, doctype = ParseCmdlineOptions(ParseCmdline())
  1015. header,toc,doc = doitall(Readfile(infile), doctype)
  1016. outlist = toc_master(doctype, header, doc, toc) # TOC!
  1017. finish_him(outlist, outfile) # writing output to screen or file
  1018. sys.exit(0)
  1019. ### RESOURCES
  1020. # html: http://www.w3.org/TR/WD-html-lex
  1021. # man: man 7 man
  1022. # sgml: www.linuxdoc.org
  1023. # moin: http://twistedmatrix.com/users/jh.twistd/moin/moin.cgi/WikiSandBox
  1024. # moin: http://moin.sf.net
  1025. # pm6: <font$> turn all formatting to the style's default
  1026. # pm6: <#comments#> <font #comment# $>
  1027. # pagemaker table
  1028. # 1 = 0,55
  1029. # 2 = 1,10
  1030. # 3 = 1,65
  1031. # 4 = 2,20
  1032. #
  1033. # |__1_| | | | | |
  1034. # |_______2_| | | | |
  1035. # |____________3_| | | |