can't appear inside
- try:
- if len(lines) == 1 and \
- TARGET in ('html', 'xhtml') and \
- re.match('^\s*
.*\s*$', lines[0]):
- result = [lines[0]]
- except: pass
-
- return result
-
- def verb(self):
- "Verbatim lines are not masked, so there's no need to unmask"
- result = []
- open_ = TAGS['blockVerbOpen']
- close = TAGS['blockVerbClose']
-
- # Blank line before?
- if self._should_add_blank_line('before', 'verb'): result.append('')
-
- # Open tag
- if open_: result.append(open_)
-
- # Get contents
- for line in self.hold():
- if self.prop('mapped') == 'table':
- line = MacroMaster().expand(line)
- if not rules['verbblocknotescaped']:
- line = doEscape(TARGET,line)
- if rules['indentverbblock']:
- line = ' '+line
- if rules['verbblockfinalescape']:
- line = doFinalEscape(TARGET, line)
- result.append(line)
-
- # Close tag
- if close: result.append(close)
-
- # Blank line after?
- if self._should_add_blank_line('after', 'verb'): result.append('')
-
- return result
-
- def numtitle(self): return self.title('numtitle')
- def title(self, name='title'):
- result = []
-
- # Blank line before?
- if self._should_add_blank_line('before', name): result.append('')
-
- # Get contents
- result.extend(TITLE.get())
-
- # Blank line after?
- if self._should_add_blank_line('after', name): result.append('')
-
- return result
-
- def table(self):
- result = []
-
- # Blank line before?
- if self._should_add_blank_line('before', 'table'): result.append('')
-
- # Rewrite all table cells by the unmasked and escaped data
- lines = self._get_escaped_hold()
- for i in range(len(lines)):
- cells = lines[i].split(SEPARATOR)
- self.tableparser.rows[i]['cells'] = cells
- result.extend(self.tableparser.dump())
-
- # Blank line after?
- if self._should_add_blank_line('after', 'table'): result.append('')
-
- return result
-
- def quote(self):
- result = []
- open_ = TAGS['blockQuoteOpen'] # block based
- close = TAGS['blockQuoteClose']
- qline = TAGS['blockQuoteLine'] # line based
- indent = tagindent = '\t'*self.depth
-
- # Apply rules
- if rules['tagnotindentable']: tagindent = ''
- if not rules['keepquoteindent']: indent = ''
-
- # Blank line before?
- if self._should_add_blank_line('before', 'quote'): result.append('')
-
- # Open tag
- if open_: result.append(tagindent+open_)
-
- # Get contents
- for item in self.hold():
- if type(item) == type([]):
- result.extend(item) # subquotes
- else:
- item = regex['quote'].sub('', item) # del TABs
- item = self._last_escapes(item)
- item = qline*self.depth + item
- result.append(indent+item) # quote line
-
- # Close tag
- if close: result.append(tagindent+close)
-
- # Blank line after?
- if self._should_add_blank_line('after', 'quote'): result.append('')
-
- return result
-
- def bar(self):
- result = []
- bar_tag = ''
-
- # Blank line before?
- if self._should_add_blank_line('before', 'bar'): result.append('')
-
- # Get the original bar chars
- bar_chars = self.hold()[0].strip()
-
- # Set bar type
- if bar_chars.startswith('='): bar_tag = TAGS['bar2']
- else : bar_tag = TAGS['bar1']
-
- # To avoid comment tag confusion like (sgml)
- if TAGS['comment'].count('--'):
- bar_chars = bar_chars.replace('--', '__')
-
- # Get the bar tag (may contain \a)
- result.append(regex['x'].sub(bar_chars, bar_tag))
-
- # Blank line after?
- if self._should_add_blank_line('after', 'bar'): result.append('')
-
- return result
-
- def deflist(self): return self.list('deflist')
- def numlist(self): return self.list('numlist')
- def list(self, name='list'):
- result = []
- items = self.hold()
- indent = self.prop('indent')
- tagindent = indent
- listline = TAGS.get(name+'ItemLine')
- itemcount = 0
-
- if name == 'deflist':
- itemopen = TAGS[name+'Item1Open']
- itemclose = TAGS[name+'Item2Close']
- itemsep = TAGS[name+'Item1Close']+\
- TAGS[name+'Item2Open']
- else:
- itemopen = TAGS[name+'ItemOpen']
- itemclose = TAGS[name+'ItemClose']
- itemsep = ''
-
- # Apply rules
- if rules['tagnotindentable']: tagindent = ''
- if not rules['keeplistindent']: indent = tagindent = ''
-
- # ItemLine: number of leading chars identifies list depth
- if listline:
- itemopen = listline*self.depth + itemopen
-
- # Adds trailing space on opening tags
- if (name == 'list' and rules['spacedlistitemopen']) or \
- (name == 'numlist' and rules['spacednumlistitemopen']):
- itemopen = itemopen + ' '
-
- # Remove two-blanks from list ending mark, to avoid
- items[-1] = self._remove_twoblanks(items[-1])
-
- # Blank line before?
- if self._should_add_blank_line('before', name): result.append('')
-
- # Tag each list item (multiline items), store in listbody
- itemopenorig = itemopen
- listbody = []
- widelist = 0
- for item in items:
-
- # Add "manual" item count for noautonum targets
- itemcount += 1
- if name == 'numlist' and not rules['autonumberlist']:
- n = str(itemcount)
- itemopen = regex['x'].sub(n, itemopenorig)
- del n
-
- # Tag it
- item[0] = self._last_escapes(item[0])
- if name == 'deflist':
- z,term,rest = item[0].split(SEPARATOR, 2)
- item[0] = rest
- if not item[0]: del item[0] # to avoid
- listbody.append(tagindent+itemopen+term+itemsep)
- else:
- fullitem = tagindent+itemopen
- listbody.append(item[0].replace(SEPARATOR, fullitem))
- del item[0]
-
- # Process next lines for this item (if any)
- for line in item:
- if type(line) == type([]): # sublist inside
- listbody.extend(line)
- else:
- line = self._last_escapes(line)
-
- # Blank lines turns to
- if not line and rules['parainsidelist']:
- line = indent + TAGS['paragraphOpen'] + TAGS['paragraphClose']
- line = line.rstrip()
- widelist = 1
-
- # Some targets don't like identation here (wiki)
- if not rules['keeplistindent'] or (name == 'deflist' and rules['deflisttextstrip']):
- line = line.lstrip()
-
- # Maybe we have a line prefix to add? (wiki)
- if name == 'deflist' and TAGS['deflistItem2LinePrefix']:
- line = TAGS['deflistItem2LinePrefix'] + line
-
- listbody.append(line)
-
- # Close item (if needed)
- if itemclose: listbody.append(tagindent+itemclose)
-
- if not widelist and rules['compactlist']:
- listopen = TAGS.get(name+'OpenCompact')
- listclose = TAGS.get(name+'CloseCompact')
- else:
- listopen = TAGS.get(name+'Open')
- listclose = TAGS.get(name+'Close')
-
- # Open list (not nestable lists are only opened at mother)
- if listopen and not \
- (rules['listnotnested'] and BLOCK.depth != 1):
- result.append(tagindent+listopen)
-
- result.extend(listbody)
-
- # Close list (not nestable lists are only closed at mother)
- if listclose and not \
- (rules['listnotnested'] and self.depth != 1):
- result.append(tagindent+listclose)
-
- # Blank line after?
- if self._should_add_blank_line('after', name): result.append('')
-
- return result
-
-
-##############################################################################
-
-
-class MacroMaster:
- def __init__(self, config={}):
- self.name = ''
- self.config = config or CONF
- self.infile = self.config['sourcefile']
- self.outfile = self.config['outfile']
- self.currdate = time.localtime(time.time())
- self.rgx = regex.get('macros') or getRegexes()['macros']
- self.fileinfo = { 'infile': None, 'outfile': None }
- self.dft_fmt = MACROS
-
- def walk_file_format(self, fmt):
- "Walks the %%{in/out}file format string, expanding the % flags"
- i = 0; ret = '' # counter/hold
- while i < len(fmt): # char by char
- c = fmt[i]; i += 1
- if c == '%': # hot char!
- if i == len(fmt): # % at the end
- ret = ret + c
- break
- c = fmt[i]; i += 1 # read next
- ret = ret + self.expand_file_flag(c)
- else:
- ret = ret +c # common char
- return ret
-
- def expand_file_flag(self, flag):
- "%f: filename %F: filename (w/o extension)"
- "%d: dirname %D: dirname (only parent dir)"
- "%p: file path %e: extension"
- info = self.fileinfo[self.name] # get dict
- if flag == '%': x = '%' # %% -> %
- elif flag == 'f': x = info['name']
- elif flag == 'F': x = re.sub('\.[^.]*$','',info['name'])
- elif flag == 'd': x = info['dir']
- elif flag == 'D': x = os.path.split(info['dir'])[-1]
- elif flag == 'p': x = info['path']
- elif flag == 'e': x = re.search('.(\.([^.]+))?$', info['name']).group(2) or ''
- #TODO simpler way for %e ?
- else : x = '%'+flag # false alarm
- return x
-
- def set_file_info(self, macroname):
- if self.fileinfo.get(macroname): return # already done
- file_ = getattr(self, self.name) # self.infile
- if file_ == STDOUT or file_ == MODULEOUT:
- dir_ = ''
- path = name = file_
- else:
- path = os.path.abspath(file_)
- dir_ = os.path.dirname(path)
- name = os.path.basename(path)
- self.fileinfo[macroname] = {'path':path,'dir':dir_,'name':name}
-
- def expand(self, line=''):
- "Expand all macros found on the line"
- while self.rgx.search(line):
- m = self.rgx.search(line)
- name = self.name = m.group('name').lower()
- fmt = m.group('fmt') or self.dft_fmt.get(name)
- if name == 'date':
- txt = time.strftime(fmt,self.currdate)
- elif name == 'mtime':
- if self.infile in (STDIN, MODULEIN):
- fdate = self.currdate
- else:
- mtime = os.path.getmtime(self.infile)
- fdate = time.localtime(mtime)
- txt = time.strftime(fmt,fdate)
- elif name == 'infile' or name == 'outfile':
- self.set_file_info(name)
- txt = self.walk_file_format(fmt)
- else:
- Error("Unknown macro name '%s'"%name)
- line = self.rgx.sub(txt,line,1)
- return line
-
-
-##############################################################################
-
-
-def listTargets():
- """list all available targets"""
- targets = TARGETS
- targets.sort()
- for target in targets:
- print("%s\t%s" % (target, TARGET_NAMES.get(target)))
-
-def dumpConfig(source_raw, parsed_config):
- onoff = {1:_('ON'), 0:_('OFF')}
- data = [
- (_('RC file') , RC_RAW ),
- (_('source document'), source_raw ),
- (_('command line') , CMDLINE_RAW)
- ]
- # First show all RAW data found
- for label, cfg in data:
- print(_('RAW config for %s')%label)
- for target,key,val in cfg:
- target = '(%s)'%target
- key = dotted_spaces("%-14s"%key)
- val = val or _('ON')
- print(' %-8s %s: %s'%(target,key,val))
- print()
- # Then the parsed results of all of them
- print(_('Full PARSED config'))
- keys = list(parsed_config.keys()) ; keys.sort() # sorted
- for key in keys:
- val = parsed_config[key]
- # Filters are the last
- if key == 'preproc' or key == 'postproc':
- continue
- # Flag beautifier
- if key in list(FLAGS.keys()) or key in list(ACTIONS.keys()):
- val = onoff.get(val) or val
- # List beautifier
- if type(val) == type([]):
- if key == 'options': sep = ' '
- else : sep = ', '
- val = sep.join(val)
- print("%25s: %s"%(dotted_spaces("%-14s"%key),val))
- print()
- print(_('Active filters'))
- for filter_ in ['preproc', 'postproc']:
- for rule in parsed_config.get(filter_) or []:
- print("%25s: %s -> %s" % (
- dotted_spaces("%-14s"%filter_), rule[0], rule[1]))
-
-
-def get_file_body(file_):
- "Returns all the document BODY lines"
- return process_source_file(file_, noconf=1)[1][2]
-
-
-def finish_him(outlist, config):
- "Writing output to screen or file"
- outfile = config['outfile']
- outlist = unmaskEscapeChar(outlist)
- outlist = expandLineBreaks(outlist)
-
- # Apply PostProc filters
- if config['postproc']:
- filters = compile_filters(config['postproc'],
- _('Invalid PostProc filter regex'))
- postoutlist = []
- errmsg = _('Invalid PostProc filter replacement')
- for line in outlist:
- for rgx,repl in filters:
- try: line = rgx.sub(repl, line)
- except: Error("%s: '%s'"%(errmsg, repl))
- postoutlist.append(line)
- outlist = postoutlist[:]
-
- if outfile == MODULEOUT:
- return outlist
- elif outfile == STDOUT:
- if GUI:
- return outlist, config
- else:
- for line in outlist: print(line)
- else:
- Savefile(outfile, addLineBreaks(outlist))
- if not GUI and not QUIET:
- print(_('%s wrote %s')%(my_name,outfile))
-
- if config['split']:
- if not QUIET: print("--- html...")
- sgml2html = 'sgml2html -s %s -l %s %s' % (
- config['split'], config['lang'] or lang, outfile)
- if not QUIET: print("Running system command:", sgml2html)
- os.system(sgml2html)
-
-
-def toc_inside_body(body, toc, config):
- ret = []
- if AUTOTOC: return body # nothing to expand
- toc_mark = MaskMaster().tocmask
- # Expand toc mark with TOC contents
- for line in body:
- if line.count(toc_mark): # toc mark found
- if config['toc']:
- ret.extend(toc) # include if --toc
- else:
- pass # or remove %%toc line
- else:
- ret.append(line) # common line
- return ret
-
-def toc_tagger(toc, config):
- "Returns the tagged TOC, as a single tag or a tagged list"
- ret = []
- # Convert the TOC list (t2t-marked) to the target's list format
- if config['toc-only'] or (config['toc'] and not TAGS['TOC']):
- fakeconf = config.copy()
- fakeconf['headers'] = 0
- fakeconf['toc-only'] = 0
- fakeconf['mask-email'] = 0
- fakeconf['preproc'] = []
- fakeconf['postproc'] = []
- fakeconf['css-sugar'] = 0
- fakeconf['art-no-title'] = 1 # needed for --toc and --slides together, avoids slide title before TOC
- ret,foo = convert(toc, fakeconf)
- set_global_config(config) # restore config
- # Our TOC list is not needed, the target already knows how to do a TOC
- elif config['toc'] and TAGS['TOC']:
- ret = [TAGS['TOC']]
- return ret
-
-def toc_formatter(toc, config):
- "Formats TOC for automatic placement between headers and body"
-
- if config['toc-only']: return toc # no formatting needed
- if not config['toc'] : return [] # TOC disabled
- ret = toc
-
- # Art: An automatic "Table of Contents" header is added to the TOC slide
- if config['target'] == 'art' and config['slides']:
- n = (config['height'] - 1) - (len(toc) + 6) % (config['height'] - 1)
- toc = aa_slide(_("Table of Contents"), config['width']) + toc + ([''] * n)
- toc.append(aa_line(AA['bar2'], config['width']))
- return toc
-
- # TOC open/close tags (if any)
- if TAGS['tocOpen' ]: ret.insert(0, TAGS['tocOpen'])
- if TAGS['tocClose']: ret.append(TAGS['tocClose'])
-
- # Autotoc specific formatting
- if AUTOTOC:
- if rules['autotocwithbars']: # TOC between bars
- para = TAGS['paragraphOpen']+TAGS['paragraphClose']
- bar = regex['x'].sub('-' * DFT_TEXT_WIDTH, TAGS['bar1'])
- tocbar = [para, bar, para]
- if config['target'] == 'art' and config['headers']:
- # exception: header already printed a bar
- ret = [para] + ret + tocbar
- else:
- ret = tocbar + ret + tocbar
- if rules['blankendautotoc']: # blank line after TOC
- ret.append('')
- if rules['autotocnewpagebefore']: # page break before TOC
- ret.insert(0,TAGS['pageBreak'])
- if rules['autotocnewpageafter']: # page break after TOC
- ret.append(TAGS['pageBreak'])
- return ret
-
-
-def doHeader(headers, config):
- if not config['headers']: return []
- if not headers: headers = ['','','']
- target = config['target']
- if target not in HEADER_TEMPLATE:
- Error("doHeader: Unknown target '%s'"%target)
-
- if target in ('html','xhtml') and config.get('css-sugar'):
- template = HEADER_TEMPLATE[target+'css'].split('\n')
- else:
- template = HEADER_TEMPLATE[target].split('\n')
-
- head_data = {'STYLE':[], 'ENCODING':''}
- for key in head_data.keys():
- val = config.get(key.lower())
- # Remove .sty extension from each style filename (freaking tex)
- # XXX Can't handle --style foo.sty,bar.sty
- if target == 'tex' and key == 'STYLE':
- val = [re.sub('(?i)\.sty$','',x) for x in val]
- if key == 'ENCODING':
- val = get_encoding_string(val, target)
- head_data[key] = val
- # Parse header contents
- for i in 0,1,2:
- # Expand macros
- contents = MacroMaster(config=config).expand(headers[i])
- # Escapes - on tex, just do it if any \tag{} present
- if target != 'tex' or \
- (target == 'tex' and re.search(r'\\\w+{', contents)):
- contents = doEscape(target, contents)
- if target == 'lout':
- contents = doFinalEscape(target, contents)
-
- head_data['HEADER%d'%(i+1)] = contents
-
- # css-inside removes STYLE line
- #XXX In tex, this also removes the modules call (%!style:amsfonts)
- if target in ('html','xhtml') and config.get('css-inside') and \
- config.get('style'):
- head_data['STYLE'] = []
-
- Debug("Header Data: %s"%head_data, 1)
-
- # ASCII Art does not use a header template, aa_header() formats the header
- if target == 'art':
- n_h = len([v for v in head_data if v.startswith("HEADER") and head_data[v]])
- if not n_h :
- return []
- if config['slides']:
- x = config['height'] - 3 - (n_h * 3)
- n = x / (n_h + 1)
- end = x % (n_h + 1)
- template = aa_header(head_data, config['width'], n, end)
- else:
- template = [''] + aa_header(head_data, config['width'], 2, 0)
- # Header done, let's get out
- return template
-
- # Scan for empty dictionary keys
- # If found, scan template lines for that key reference
- # If found, remove the reference
- # If there isn't any other key reference on the same line, remove it
- #TODO loop by template line > key
- for key in head_data.keys():
- if head_data.get(key): continue
- for line in template:
- if line.count('%%(%s)s'%key):
- sline = line.replace('%%(%s)s'%key, '')
- if not re.search(r'%\([A-Z0-9]+\)s', sline):
- template.remove(line)
- # Style is a multiple tag.
- # - If none or just one, use default template
- # - If two or more, insert extra lines in a loop (and remove original)
- styles = head_data['STYLE']
- if len(styles) == 1:
- head_data['STYLE'] = styles[0]
- elif len(styles) > 1:
- style_mark = '%(STYLE)s'
- for i in range(len(template)):
- if template[i].count(style_mark):
- while styles:
- template.insert(i+1, template[i].replace(style_mark, styles.pop()))
- del template[i]
- break
- # Populate template with data (dict expansion)
- template = '\n'.join(template) % head_data
-
- # Adding CSS contents into template (for --css-inside)
- # This code sux. Dirty++
- if target in ('html','xhtml') and config.get('css-inside') and \
- config.get('style'):
- set_global_config(config) # usually on convert(), needed here
- for i in range(len(config['style'])):
- cssfile = config['style'][i]
- if not os.path.isabs(cssfile):
- infile = config.get('sourcefile')
- cssfile = os.path.join(
- os.path.dirname(infile), cssfile)
- try:
- contents = Readfile(cssfile, 1)
- css = "\n%s\n%s\n%s\n%s\n" % (
- doCommentLine("Included %s" % cssfile),
- TAGS['cssOpen'],
- '\n'.join(contents),
- TAGS['cssClose'])
- # Style now is content, needs escaping (tex)
- #css = maskEscapeChar(css)
- except:
- errmsg = "CSS include failed for %s" % cssfile
- css = "\n%s\n" % (doCommentLine(errmsg))
- # Insert this CSS file contents on the template
- template = re.sub('(?i)()', css+r'\1', template)
- # template = re.sub(r'(?i)(\\begin{document})',
- # css+'\n'+r'\1', template) # tex
-
- # The last blank line to keep everything separated
- template = re.sub('(?i)()', '\n'+r'\1', template)
-
- return template.split('\n')
-
-def doCommentLine(txt):
- # The -- string ends a (h|sg|xht)ml comment :(
- txt = maskEscapeChar(txt)
- if TAGS['comment'].count('--') and txt.count('--'):
- txt = re.sub('-(?=-)', r'-\\', txt)
-
- if TAGS['comment']:
- return regex['x'].sub(txt, TAGS['comment'])
- return ''
-
-def doFooter(config):
- ret = []
-
- # No footer. The --no-headers option hides header AND footer
- if not config['headers']:
- return []
-
- # Only add blank line before footer if last block doesn't added by itself
- if not rules.get('blanksaround'+BLOCK.last):
- ret.append('')
-
- # Add txt2tags info at footer, if target supports comments
- if TAGS['comment']:
-
- # Not using TARGET_NAMES because it's i18n'ed.
- # It's best to always present this info in english.
- target = config['target']
- if config['target'] == 'tex':
- target = 'LaTeX2e'
-
- t2t_version = '%s code generated by %s %s (%s)' % (target, my_name, my_version, my_url)
- cmdline = 'cmdline: %s %s' % (my_name, ' '.join(config['realcmdline']))
-
- ret.append(doCommentLine(t2t_version))
- ret.append(doCommentLine(cmdline))
-
- # Maybe we have a specific tag to close the document?
- if TAGS['EOD']:
- ret.append(TAGS['EOD'])
-
- return ret
-
-def doEscape(target,txt):
- "Target-specific special escapes. Apply *before* insert any tag."
- tmpmask = 'vvvvThisEscapingSuxvvvv'
- if target in ('html','sgml','xhtml','dbk'):
- txt = re.sub('&','&',txt)
- txt = re.sub('<','<',txt)
- txt = re.sub('>','>',txt)
- if target == 'sgml':
- txt = re.sub('\xff','ÿ',txt) # "+y
- elif target == 'pm6':
- txt = re.sub('<','<\#60>',txt)
- elif target == 'mgp':
- txt = re.sub('^%',' %',txt) # add leading blank to avoid parse
- elif target == 'man':
- txt = re.sub("^([.'])", '\\&\\1',txt) # command ID
- txt = txt.replace(ESCCHAR, ESCCHAR+'e') # \e
- elif target == 'lout':
- # TIP: / moved to FinalEscape to avoid //italic//
- # TIP: these are also converted by lout: ... --- --
- txt = txt.replace(ESCCHAR, tmpmask) # \
- txt = txt.replace('"', '"%s""'%ESCCHAR) # "\""
- txt = re.sub('([|&{}@#^~])', '"\\1"', txt) # "@"
- txt = txt.replace(tmpmask, '"%s"'%(ESCCHAR*2)) # "\\"
- elif target == 'tex':
- # Mark literal \ to be changed to $\backslash$ later
- txt = txt.replace(ESCCHAR, tmpmask)
- txt = re.sub('([#$&%{}])', ESCCHAR+r'\1' , txt) # \%
- txt = re.sub('([~^])' , ESCCHAR+r'\1{}', txt) # \~{}
- txt = re.sub('([<|>])' , r'$\1$', txt) # $>$
- txt = txt.replace(tmpmask, maskEscapeChar(r'$\backslash$'))
- # TIP the _ is escaped at the end
- return txt
-
-# TODO man: where - really needs to be escaped?
-def doFinalEscape(target, txt):
- "Last escapes of each line"
- if target == 'pm6' : txt = txt.replace(ESCCHAR+'<', r'<\#92><')
- elif target == 'man' : txt = txt.replace('-', r'\-')
- elif target == 'sgml': txt = txt.replace('[', '[')
- elif target == 'lout': txt = txt.replace('/', '"/"')
- elif target == 'tex' :
- txt = txt.replace('_', r'\_')
- txt = txt.replace('vvvvTexUndervvvv', '_') # shame!
- ## JS
- txt = txt.replace('vvvUnderscoreInRawTextvvv', '_')
- txt = txt.replace('vvvUnderscoreInTaggedTextvvv', '_')
- return txt
-
-def EscapeCharHandler(action, data):
- "Mask/Unmask the Escape Char on the given string"
- if not data.strip(): return data
- if action not in ('mask','unmask'):
- Error("EscapeCharHandler: Invalid action '%s'"%action)
- if action == 'mask': return data.replace('\\', ESCCHAR)
- else: return data.replace(ESCCHAR, '\\')
-
-def maskEscapeChar(data):
- "Replace any Escape Char \ with a text mask (Input: str or list)"
- if type(data) == type([]):
- return [EscapeCharHandler('mask', x) for x in data]
- return EscapeCharHandler('mask',data)
-
-def unmaskEscapeChar(data):
- "Undo the Escape char \ masking (Input: str or list)"
- if type(data) == type([]):
- return [EscapeCharHandler('unmask', x) for x in data]
- return EscapeCharHandler('unmask',data)
-
-def addLineBreaks(mylist):
- "use LB to respect sys.platform"
- ret = []
- for line in mylist:
- line = line.replace('\n', LB) # embedded \n's
- ret.append(line+LB) # add final line break
- return ret
-
-# Convert ['foo\nbar'] to ['foo', 'bar']
-def expandLineBreaks(mylist):
- ret = []
- for line in mylist:
- ret.extend(line.split('\n'))
- return ret
-
-def compile_filters(filters, errmsg='Filter'):
- if filters:
- for i in range(len(filters)):
- patt,repl = filters[i]
- try: rgx = re.compile(patt)
- except: Error("%s: '%s'"%(errmsg, patt))
- filters[i] = (rgx,repl)
- return filters
-
-def enclose_me(tagname, txt):
- return TAGS.get(tagname+'Open') + txt + TAGS.get(tagname+'Close')
-
-def beautify_me(name, font, line):
- "where name is: bold, italic, underline or strike"
-
- # Exception: Doesn't parse an horizontal bar as strike
- if name == 'strike' and regex['bar'].search(line): return line
-
- open_ = TAGS['%sOpen' % font]
- close = TAGS['%sClose' % font]
- txt = r'%s\1%s'%(open_, close)
- line = regex[font].sub(txt, line)
- return line
-
-def get_tagged_link(label, url):
- ret = ''
- target = CONF['target']
- image_re = regex['img']
-
- # Set link type
- if regex['email'].match(url):
- linktype = 'email'
- else:
- linktype = 'url';
-
- # Escape specials from TEXT parts
- label = doEscape(target,label)
-
- # Escape specials from link URL
- if not rules['linkable'] or rules['escapeurl']:
- url = doEscape(target, url)
-
- # Adding protocol to guessed link
- guessurl = ''
- if linktype == 'url' and \
- re.match('(?i)'+regex['_urlskel']['guess'], url):
- if url[0] in 'Ww': guessurl = 'http://' +url
- else : guessurl = 'ftp://' +url
-
- # Not link aware targets -> protocol is useless
- if not rules['linkable']: guessurl = ''
-
- # Simple link (not guessed)
- if not label and not guessurl:
- if CONF['mask-email'] and linktype == 'email':
- # Do the email mask feature (no TAGs, just text)
- url = url.replace('@', ' (a) ')
- url = url.replace('.', ' ')
- url = "<%s>" % url
- if rules['linkable']: url = doEscape(target, url)
- ret = url
- else:
- # Just add link data to tag
- tag = TAGS[linktype]
- ret = regex['x'].sub(url,tag)
-
- # Named link or guessed simple link
- else:
- # Adjusts for guessed link
- if not label: label = url # no protocol
- if guessurl : url = guessurl # with protocol
-
- # Image inside link!
- if image_re.match(label):
- if rules['imglinkable']: # get image tag
- label = parse_images(label)
- else: # img@link !supported
- label = "(%s)"%image_re.match(label).group(1)
-
- # Putting data on the right appearance order
- if rules['labelbeforelink'] or not rules['linkable']:
- urlorder = [label, url] # label before link
- else:
- urlorder = [url, label] # link before label
-
- # Add link data to tag (replace \a's)
- ret = TAGS["%sMark"%linktype]
- for data in urlorder:
- ret = regex['x'].sub(data,ret,1)
-
- return ret
-
-
-def parse_deflist_term(line):
- "Extract and parse definition list term contents"
- img_re = regex['img']
- term = regex['deflist'].search(line).group(3)
-
- # Mask image inside term as (image.jpg), where not supported
- if not rules['imgasdefterm'] and img_re.search(term):
- while img_re.search(term):
- imgfile = img_re.search(term).group(1)
- term = img_re.sub('(%s)'%imgfile, term, 1)
-
- #TODO tex: escape ] on term. \], \rbrack{} and \verb!]! don't work :(
- return term
-
-
-def get_image_align(line):
- "Return the image (first found) align for the given line"
-
- # First clear marks that can mess align detection
- line = re.sub(SEPARATOR+'$', '', line) # remove deflist sep
- line = re.sub('^'+SEPARATOR, '', line) # remove list sep
- line = re.sub('^[\t]+' , '', line) # remove quote mark
-
- # Get image position on the line
- m = regex['img'].search(line)
- ini = m.start() ; head = 0
- end = m.end() ; tail = len(line)
-
- # The align detection algorithm
- if ini == head and end != tail: align = 'left' # ^img + text$
- elif ini != head and end == tail: align = 'right' # ^text + img$
- else : align = 'center' # default align
-
- # Some special cases
- if BLOCK.isblock('table'): align = 'center' # ignore when table
-# if TARGET == 'mgp' and align == 'center': align = 'center'
-
- return align
-
-
-# Reference: http://www.iana.org/assignments/character-sets
-# http://www.drclue.net/F1.cgi/HTML/META/META.html
-def get_encoding_string(enc, target):
- if not enc: return ''
- # Target specific translation table
- translate = {
- 'tex': {
- # missing: ansinew , applemac , cp437 , cp437de , cp865
- 'utf-8' : 'utf8',
- 'us-ascii' : 'ascii',
- 'windows-1250': 'cp1250',
- 'windows-1252': 'cp1252',
- 'ibm850' : 'cp850',
- 'ibm852' : 'cp852',
- 'iso-8859-1' : 'latin1',
- 'iso-8859-2' : 'latin2',
- 'iso-8859-3' : 'latin3',
- 'iso-8859-4' : 'latin4',
- 'iso-8859-5' : 'latin5',
- 'iso-8859-9' : 'latin9',
- 'koi8-r' : 'koi8-r'
- }
- }
- # Normalization
- enc = re.sub('(?i)(us[-_]?)?ascii|us|ibm367','us-ascii' , enc)
- enc = re.sub('(?i)(ibm|cp)?85([02])' ,'ibm85\\2' , enc)
- enc = re.sub('(?i)(iso[_-]?)?8859[_-]?' ,'iso-8859-' , enc)
- enc = re.sub('iso-8859-($|[^1-9]).*' ,'iso-8859-1', enc)
- # Apply translation table
- try: enc = translate[target][enc.lower()]
- except: pass
- return enc
-
-
-##############################################################################
-##MerryChristmas,IdontwanttofighttonightwithyouImissyourbodyandIneedyourlove##
-##############################################################################
-
-
-def process_source_file(file_='', noconf=0, contents=[]):
- """
- Find and Join all the configuration available for a source file.
- No sanity checking is done on this step.
- It also extracts the source document parts into separate holders.
-
- The config scan order is:
- 1. The user configuration file (i.e. $HOME/.txt2tagsrc)
- 2. The source document's CONF area
- 3. The command line options
-
- The return data is a tuple of two items:
- 1. The parsed config dictionary
- 2. The document's parts, as a (head, conf, body) tuple
-
- All the conversion process will be based on the data and
- configuration returned by this function.
- The source files is read on this step only.
- """
- if contents:
- source = SourceDocument(contents=contents)
- else:
- source = SourceDocument(file_)
- head, conf, body = source.split()
- Message(_("Source document contents stored"),2)
- if not noconf:
- # Read document config
- source_raw = source.get_raw_config()
- # Join all the config directives found, then parse it
- full_raw = RC_RAW + source_raw + CMDLINE_RAW
- Message(_("Parsing and saving all config found (%03d items)") % (len(full_raw)), 1)
- full_parsed = ConfigMaster(full_raw).parse()
- # Add manually the filename to the conf dic
- if contents:
- full_parsed['sourcefile'] = MODULEIN
- full_parsed['infile'] = MODULEIN
- full_parsed['outfile'] = MODULEOUT
- else:
- full_parsed['sourcefile'] = file_
- # Maybe should we dump the config found?
- if full_parsed.get('dump-config'):
- dumpConfig(source_raw, full_parsed)
- Quit()
- # The user just want to know a single config value (hidden feature)
- #TODO pick a better name than --show-config-value
- elif full_parsed.get('show-config-value'):
- config_value = full_parsed.get(full_parsed['show-config-value'])
- if config_value:
- if type(config_value) == type([]):
- print('\n'.join(config_value))
- else:
- print(config_value)
- Quit()
- # Okay, all done
- Debug("FULL config for this file: %s"%full_parsed, 1)
- else:
- full_parsed = {}
- return full_parsed, (head,conf,body)
-
-def get_infiles_config(infiles):
- """
- Find and Join into a single list, all configuration available
- for each input file. This function is supposed to be the very
- first one to be called, before any processing.
- """
- return list(map(process_source_file, infiles))
-
-def convert_this_files(configs):
- global CONF
- for myconf,doc in configs: # multifile support
- target_head = []
- target_toc = []
- target_body = []
- target_foot = []
- source_head, source_conf, source_body = doc
- myconf = ConfigMaster().sanity(myconf)
- # Compose the target file Headers
- #TODO escape line before?
- #TODO see exceptions by tex and mgp
- Message(_("Composing target Headers"),1)
- target_head = doHeader(source_head, myconf)
- # Parse the full marked body into tagged target
- first_body_line = (len(source_head) or 1)+ len(source_conf) + 1
- Message(_("Composing target Body"),1)
- target_body, marked_toc = convert(source_body, myconf, firstlinenr=first_body_line)
- # If dump-source, we're done
- if myconf['dump-source']:
- for line in source_head+source_conf+target_body:
- print(line)
- return
-
- # Close the last slide
- if myconf['slides'] and not myconf['toc-only'] and myconf['target'] == 'art':
- n = (myconf['height'] - 1) - (AA_COUNT % (myconf['height'] - 1) + 1)
- target_body = target_body + ([''] * n) + [aa_line(AA['bar2'], myconf['width'])]
-
- # Compose the target file Footer
- Message(_("Composing target Footer"),1)
- target_foot = doFooter(myconf)
-
- # Make TOC (if needed)
- Message(_("Composing target TOC"),1)
- tagged_toc = toc_tagger(marked_toc, myconf)
- target_toc = toc_formatter(tagged_toc, myconf)
- target_body = toc_inside_body(target_body, target_toc, myconf)
- if not AUTOTOC and not myconf['toc-only']: target_toc = []
- # Finally, we have our document
- outlist = target_head + target_toc + target_body + target_foot
- # If on GUI, abort before finish_him
- # If module, return finish_him as list
- # Else, write results to file or STDOUT
- if GUI:
- return outlist, myconf
- elif myconf.get('outfile') == MODULEOUT:
- return finish_him(outlist, myconf), myconf
- else:
- Message(_("Saving results to the output file"),1)
- finish_him(outlist, myconf)
-
-
-def parse_images(line):
- "Tag all images found"
- while regex['img'].search(line) and TAGS['img'] != '[\a]':
- txt = regex['img'].search(line).group(1)
- tag = TAGS['img']
-
- # If target supports image alignment, here we go
- if rules['imgalignable']:
-
- align = get_image_align(line) # right
- align_name = align.capitalize() # Right
-
- # The align is a full tag, or part of the image tag (~A~)
- if TAGS['imgAlign'+align_name]:
- tag = TAGS['imgAlign'+align_name]
- else:
- align_tag = TAGS['_imgAlign'+align_name]
- tag = regex['_imgAlign'].sub(align_tag, tag, 1)
-
- # Dirty fix to allow centered solo images
- if align == 'center' and TARGET in ('html','xhtml'):
- rest = regex['img'].sub('',line,1)
- if re.match('^\s+$', rest):
- tag = "
%s" %tag
-
- if TARGET == 'tex':
- tag = re.sub(r'\\b',r'\\\\b',tag)
- txt = txt.replace('_', 'vvvvTexUndervvvv')
-
- # Ugly hack to avoid infinite loop when target's image tag contains []
- tag = tag.replace('[', 'vvvvEscapeSquareBracketvvvv')
-
- line = regex['img'].sub(tag,line,1)
- line = regex['x'].sub(txt,line,1)
- return line.replace('vvvvEscapeSquareBracketvvvv','[')
-
-
-def add_inline_tags(line):
- # Beautifiers
- for beauti, font in [
- ('bold', 'fontBold'), ('italic', 'fontItalic'),
- ('underline', 'fontUnderline'), ('strike', 'fontStrike')]:
- if regex[font].search(line):
- line = beautify_me(beauti, font, line)
-
- line = parse_images(line)
- return line
-
-
-def get_include_contents(file_, path=''):
- "Parses %!include: value and extract file contents"
- ids = {'`':'verb', '"':'raw', "'":'tagged' }
- id_ = 't2t'
- # Set include type and remove identifier marks
- mark = file_[0]
- if mark in ids.keys():
- if file_[:2] == file_[-2:] == mark*2:
- id_ = ids[mark] # set type
- file_ = file_[2:-2] # remove marks
- # Handle remote dir execution
- filepath = os.path.join(path, file_)
- # Read included file contents
- lines = Readfile(filepath, remove_linebreaks=1)
- # Default txt2tags marked text, just BODY matters
- if id_ == 't2t':
- lines = get_file_body(filepath)
- #TODO fix images relative path if file has a path, ie.: chapter1/index.t2t (wait until tree parsing)
- #TODO for the images path fix, also respect outfile path, if different from infile (wait until tree parsing)
- lines.insert(0, '%%INCLUDED(%s) starts here: %s'%(id_,file_))
- # This appears when included hit EOF with verbatim area open
- #lines.append('%%INCLUDED(%s) ends here: %s'%(id_,file_))
- return id_, lines
-
-
-def set_global_config(config):
- global CONF, TAGS, regex, rules, TARGET
- CONF = config
- rules = getRules(CONF)
- TAGS = getTags(CONF)
- regex = getRegexes()
- TARGET = config['target'] # save for buggy functions that need global
-
-
-def convert(bodylines, config, firstlinenr=1):
- global BLOCK, TITLE
-
- set_global_config(config)
-
- target = config['target']
- BLOCK = BlockMaster()
- MASK = MaskMaster()
- TITLE = TitleMaster()
-
- ret = []
- dump_source = []
- f_lastwasblank = 0
-
- # Compiling all PreProc regexes
- pre_filter = compile_filters(
- CONF['preproc'], _('Invalid PreProc filter regex'))
-
- # Let's mark it up!
- linenr = firstlinenr-1
- lineref = 0
- while lineref < len(bodylines):
- # Defaults
- MASK.reset()
- results_box = ''
-
- untouchedline = bodylines[lineref]
- dump_source.append(untouchedline)
-
- line = re.sub('[\n\r]+$','',untouchedline) # del line break
-
- # Apply PreProc filters
- if pre_filter:
- errmsg = _('Invalid PreProc filter replacement')
- for rgx,repl in pre_filter:
- try: line = rgx.sub(repl, line)
- except: Error("%s: '%s'"%(errmsg, repl))
-
- line = maskEscapeChar(line) # protect \ char
- linenr += 1
- lineref += 1
-
- Debug(repr(line), 2, linenr) # heavy debug: show each line
-
- #------------------[ Comment Block ]------------------------
-
- # We're already on a comment block
- if BLOCK.block() == 'comment':
-
- # Closing comment
- if regex['blockCommentClose'].search(line):
- ret.extend(BLOCK.blockout() or [])
- continue
-
- # Normal comment-inside line. Ignore it.
- continue
-
- # Detecting comment block init
- if regex['blockCommentOpen'].search(line) \
- and BLOCK.block() not in BLOCK.exclusive:
- ret.extend(BLOCK.blockin('comment'))
- continue
-
- #-------------------------[ Tagged Text ]----------------------
-
- # We're already on a tagged block
- if BLOCK.block() == 'tagged':
-
- # Closing tagged
- if regex['blockTaggedClose'].search(line):
- ret.extend(BLOCK.blockout())
- continue
-
- # Normal tagged-inside line
- BLOCK.holdadd(line)
- continue
-
- # Detecting tagged block init
- if regex['blockTaggedOpen'].search(line) \
- and BLOCK.block() not in BLOCK.exclusive:
- ret.extend(BLOCK.blockin('tagged'))
- continue
-
- # One line tagged text
- if regex['1lineTagged'].search(line) \
- and BLOCK.block() not in BLOCK.exclusive:
- ret.extend(BLOCK.blockin('tagged'))
- line = regex['1lineTagged'].sub('',line)
- BLOCK.holdadd(line)
- ret.extend(BLOCK.blockout())
- continue
-
- #-------------------------[ Raw Text ]----------------------
-
- # We're already on a raw block
- if BLOCK.block() == 'raw':
-
- # Closing raw
- if regex['blockRawClose'].search(line):
- ret.extend(BLOCK.blockout())
- continue
-
- # Normal raw-inside line
- BLOCK.holdadd(line)
- continue
-
- # Detecting raw block init
- if regex['blockRawOpen'].search(line) \
- and BLOCK.block() not in BLOCK.exclusive:
- ret.extend(BLOCK.blockin('raw'))
- continue
-
- # One line raw text
- if regex['1lineRaw'].search(line) \
- and BLOCK.block() not in BLOCK.exclusive:
- ret.extend(BLOCK.blockin('raw'))
- line = regex['1lineRaw'].sub('',line)
- BLOCK.holdadd(line)
- ret.extend(BLOCK.blockout())
- continue
-
- #------------------------[ Verbatim ]----------------------
-
- #TIP We'll never support beautifiers inside verbatim
-
- # Closing table mapped to verb
- if BLOCK.block() == 'verb' \
- and BLOCK.prop('mapped') == 'table' \
- and not regex['table'].search(line):
- ret.extend(BLOCK.blockout())
-
- # We're already on a verb block
- if BLOCK.block() == 'verb':
-
- # Closing verb
- if regex['blockVerbClose'].search(line):
- ret.extend(BLOCK.blockout())
- continue
-
- # Normal verb-inside line
- BLOCK.holdadd(line)
- continue
-
- # Detecting verb block init
- if regex['blockVerbOpen'].search(line) \
- and BLOCK.block() not in BLOCK.exclusive:
- ret.extend(BLOCK.blockin('verb'))
- f_lastwasblank = 0
- continue
-
- # One line verb-formatted text
- if regex['1lineVerb'].search(line) \
- and BLOCK.block() not in BLOCK.exclusive:
- ret.extend(BLOCK.blockin('verb'))
- line = regex['1lineVerb'].sub('',line)
- BLOCK.holdadd(line)
- ret.extend(BLOCK.blockout())
- f_lastwasblank = 0
- continue
-
- # Tables are mapped to verb when target is not table-aware
- if not rules['tableable'] and regex['table'].search(line):
- if not BLOCK.isblock('verb'):
- ret.extend(BLOCK.blockin('verb'))
- BLOCK.propset('mapped', 'table')
- BLOCK.holdadd(line)
- continue
-
- #---------------------[ blank lines ]-----------------------
-
- if regex['blankline'].search(line):
-
- # Close open paragraph
- if BLOCK.isblock('para'):
- ret.extend(BLOCK.blockout())
- f_lastwasblank = 1
- continue
-
- # Close all open tables
- if BLOCK.isblock('table'):
- ret.extend(BLOCK.blockout())
- f_lastwasblank = 1
- continue
-
- # Close all open quotes
- while BLOCK.isblock('quote'):
- ret.extend(BLOCK.blockout())
-
- # Closing all open lists
- if f_lastwasblank: # 2nd consecutive blank
- if BLOCK.block().endswith('list'):
- BLOCK.holdaddsub('') # helps parser
- while BLOCK.depth: # closes list (if any)
- ret.extend(BLOCK.blockout())
- continue # ignore consecutive blanks
-
- # Paragraph (if any) is wanted inside lists also
- if BLOCK.block().endswith('list'):
- BLOCK.holdaddsub('')
-
- f_lastwasblank = 1
- continue
-
-
- #---------------------[ special ]---------------------------
-
- if regex['special'].search(line):
-
- targ, key, val = ConfigLines().parse_line(line, None, target)
-
- if key:
- Debug("Found config '%s', value '%s'" % (key, val), 1, linenr)
- else:
- Debug('Bogus Special Line', 1, linenr)
-
- # %!include command
- if key == 'include':
-
- incpath = os.path.dirname(CONF['sourcefile'])
- incfile = val
- err = _('A file cannot include itself (loop!)')
- if CONF['sourcefile'] == incfile:
- Error("%s: %s"%(err,incfile))
- inctype, inclines = get_include_contents(incfile, incpath)
-
- # Verb, raw and tagged are easy
- if inctype != 't2t':
- ret.extend(BLOCK.blockin(inctype))
- BLOCK.holdextend(inclines)
- ret.extend(BLOCK.blockout())
- else:
- # Insert include lines into body
- #TODO include maxdepth limit
- bodylines = bodylines[:lineref] + inclines + bodylines[lineref:]
- #TODO fix path if include@include
- # Remove %!include call
- if CONF['dump-source']:
- dump_source.pop()
-
- # This line is done, go to next
- continue
-
- # %!csv command
- elif key == 'csv':
-
- if not csv:
- Error("Python module 'csv' not found, but needed for %!csv")
-
- table = []
- filename = val
- reader = csv.reader(Readfile(filename))
-
- # Convert each CSV line to a txt2tags' table line
- # foo,bar,baz -> | foo | bar | baz |
- try:
- for row in reader:
- table.append('| %s |' % ' | '.join(row))
- except csv.Error as e:
- Error('CSV: file %s: %s' % (filename, e))
-
- # Parse and convert the new table
- # Note: cell contents is raw, no t2t marks are parsed
- if rules['tableable']:
- ret.extend(BLOCK.blockin('table'))
- if table:
- BLOCK.tableparser.__init__(table[0])
- for row in table:
- tablerow = TableMaster().parse_row(row)
- BLOCK.tableparser.add_row(tablerow)
-
- # Very ugly, but necessary for escapes
- line = SEPARATOR.join(tablerow['cells'])
- BLOCK.holdadd(doEscape(target, line))
- ret.extend(BLOCK.blockout())
-
- # Tables are mapped to verb when target is not table-aware
- else:
- if target == 'art' and table:
- table = aa_table(table)
- ret.extend(BLOCK.blockin('verb'))
- BLOCK.propset('mapped', 'table')
- for row in table:
- BLOCK.holdadd(row)
- ret.extend(BLOCK.blockout())
-
- # This line is done, go to next
- continue
-
- #---------------------[ dump-source ]-----------------------
-
- # We don't need to go any further
- if CONF['dump-source']:
- continue
-
- #---------------------[ Comments ]--------------------------
-
- # Just skip them (if not macro)
- if regex['comment'].search(line) and not \
- regex['macros'].match(line) and not \
- regex['toc'].match(line):
- continue
-
- #---------------------[ Triggers ]--------------------------
-
- # Valid line, reset blank status
- f_lastwasblank = 0
-
- # Any NOT quote line closes all open quotes
- if BLOCK.isblock('quote') and not regex['quote'].search(line):
- while BLOCK.isblock('quote'):
- ret.extend(BLOCK.blockout())
-
- # Any NOT table line closes an open table
- if BLOCK.isblock('table') and not regex['table'].search(line):
- ret.extend(BLOCK.blockout())
-
-
- #---------------------[ Horizontal Bar ]--------------------
-
- if regex['bar'].search(line):
-
- # Bars inside quotes are handled on the Quote processing
- # Otherwise we parse the bars right here
- #
- if not (BLOCK.isblock('quote') or regex['quote'].search(line)) \
- or (BLOCK.isblock('quote') and not rules['barinsidequote']):
-
- # Close all the opened blocks
- ret.extend(BLOCK.blockin('bar'))
-
- # Extract the bar chars (- or =)
- m = regex['bar'].search(line)
- bar_chars = m.group(2)
-
- # Process and dump the tagged bar
- BLOCK.holdadd(bar_chars)
- ret.extend(BLOCK.blockout())
- Debug("BAR: %s"%line, 6)
-
- # We're done, nothing more to process
- continue
-
-
- #---------------------[ Title ]-----------------------------
-
- if (regex['title'].search(line) or regex['numtitle'].search(line)) \
- and not BLOCK.block().endswith('list'):
-
- if regex['title'].search(line):
- name = 'title'
- else:
- name = 'numtitle'
-
- # Close all the opened blocks
- ret.extend(BLOCK.blockin(name))
-
- # Process title
- TITLE.add(line)
- ret.extend(BLOCK.blockout())
-
- # We're done, nothing more to process
- continue
-
- #---------------------[ %%toc ]-----------------------
-
- # %%toc line closes paragraph
- if BLOCK.block() == 'para' and regex['toc'].search(line):
- ret.extend(BLOCK.blockout())
-
- #---------------------[ apply masks ]-----------------------
-
- line = MASK.mask(line)
-
- #XXX from here, only block-inside lines will pass
-
- #---------------------[ Quote ]-----------------------------
-
- if regex['quote'].search(line):
-
- # Store number of leading TABS
- quotedepth = len(regex['quote'].search(line).group(0))
-
- # SGML doesn't support nested quotes
- if rules['quotenotnested']: quotedepth = 1
-
- # Don't cross depth limit
- maxdepth = rules['quotemaxdepth']
- if maxdepth and quotedepth > maxdepth:
- quotedepth = maxdepth
-
- # New quote
- if not BLOCK.isblock('quote'):
- ret.extend(BLOCK.blockin('quote'))
-
- # New subquotes
- while BLOCK.depth < quotedepth:
- BLOCK.blockin('quote')
-
- # Closing quotes
- while quotedepth < BLOCK.depth:
- ret.extend(BLOCK.blockout())
-
- # Bar inside quote
- if regex['bar'].search(line) and rules['barinsidequote']:
- tempBlock = BlockMaster()
- tagged_bar = []
- tagged_bar.extend(tempBlock.blockin('bar'))
- tempBlock.holdadd(line)
- tagged_bar.extend(tempBlock.blockout())
- BLOCK.holdextend(tagged_bar)
- continue
-
- #---------------------[ Lists ]-----------------------------
-
- # An empty item also closes the current list
- if BLOCK.block().endswith('list'):
- m = regex['listclose'].match(line)
- if m:
- listindent = m.group(1)
- listtype = m.group(2)
- currlisttype = BLOCK.prop('type')
- currlistindent = BLOCK.prop('indent')
- if listindent == currlistindent and \
- listtype == currlisttype:
- ret.extend(BLOCK.blockout())
- continue
-
- if regex['list'].search(line) or \
- regex['numlist'].search(line) or \
- regex['deflist'].search(line):
-
- listindent = BLOCK.prop('indent')
- listids = ''.join(LISTNAMES.keys())
- m = re.match('^( *)([%s]) ' % re.escape(listids), line)
- listitemindent = m.group(1)
- listtype = m.group(2)
- listname = LISTNAMES[listtype]
- results_box = BLOCK.holdadd
-
- # Del list ID (and separate term from definition)
- if listname == 'deflist':
- term = parse_deflist_term(line)
- line = regex['deflist'].sub(
- SEPARATOR+term+SEPARATOR,line)
- else:
- line = regex[listname].sub(SEPARATOR,line)
-
- # Don't cross depth limit
- maxdepth = rules['listmaxdepth']
- if maxdepth and BLOCK.depth == maxdepth:
- if len(listitemindent) > len(listindent):
- listitemindent = listindent
-
- # List bumping (same indent, diff mark)
- # Close the currently open list to clear the mess
- if BLOCK.block().endswith('list') \
- and listname != BLOCK.block() \
- and len(listitemindent) == len(listindent):
- ret.extend(BLOCK.blockout())
- listindent = BLOCK.prop('indent')
-
- # Open mother list or sublist
- if not BLOCK.block().endswith('list') or \
- len(listitemindent) > len(listindent):
- ret.extend(BLOCK.blockin(listname))
- BLOCK.propset('indent',listitemindent)
- BLOCK.propset('type',listtype)
-
- # Closing sublists
- while len(listitemindent) < len(BLOCK.prop('indent')):
- ret.extend(BLOCK.blockout())
-
- # O-oh, sublist before list ("\n\n - foo\n- foo")
- # Fix: close sublist (as mother), open another list
- if not BLOCK.block().endswith('list'):
- ret.extend(BLOCK.blockin(listname))
- BLOCK.propset('indent',listitemindent)
- BLOCK.propset('type',listtype)
-
- #---------------------[ Table ]-----------------------------
-
- #TODO escape undesired format inside table
- #TODO add pm6 target
- if regex['table'].search(line):
-
- if not BLOCK.isblock('table'): # first table line!
- ret.extend(BLOCK.blockin('table'))
- BLOCK.tableparser.__init__(line)
-
- tablerow = TableMaster().parse_row(line)
- BLOCK.tableparser.add_row(tablerow) # save config
-
- # Maintain line to unmask and inlines
- # XXX Bug: | **bo | ld** | turns **bo\x01ld** and gets converted :(
- # TODO isolate unmask+inlines parsing to use here
- line = SEPARATOR.join(tablerow['cells'])
-
- #---------------------[ Paragraph ]-------------------------
-
- if not BLOCK.block() and \
- not line.count(MASK.tocmask): # new para!
- ret.extend(BLOCK.blockin('para'))
-
-
- ############################################################
- ############################################################
- ############################################################
-
-
- #---------------------[ Final Parses ]----------------------
-
- # The target-specific special char escapes for body lines
- line = doEscape(target,line)
-
- line = add_inline_tags(line)
- line = MASK.undo(line)
-
-
- #---------------------[ Hold or Return? ]-------------------
-
- ### Now we must choose where to put the parsed line
- #
- if not results_box:
- # List item extra lines
- if BLOCK.block().endswith('list'):
- results_box = BLOCK.holdaddsub
- # Other blocks
- elif BLOCK.block():
- results_box = BLOCK.holdadd
- # No blocks
- else:
- line = doFinalEscape(target, line)
- results_box = ret.append
-
- results_box(line)
-
- # EOF: close any open para/verb/lists/table/quotes
- Debug('EOF',7)
- while BLOCK.block():
- ret.extend(BLOCK.blockout())
-
- # Maybe close some opened title area?
- if rules['titleblocks']:
- ret.extend(TITLE.close_all())
-
- # Maybe a major tag to enclose body? (like DIV for CSS)
- if TAGS['bodyOpen' ]: ret.insert(0, TAGS['bodyOpen'])
- if TAGS['bodyClose']: ret.append(TAGS['bodyClose'])
-
- if CONF['toc-only']: ret = []
- marked_toc = TITLE.dump_marked_toc(CONF['toc-level'])
-
- # If dump-source, all parsing is ignored
- if CONF['dump-source']: ret = dump_source[:]
-
- return ret, marked_toc
-
-
-
-##############################################################################
-################################### GUI ######################################
-##############################################################################
-#
-# Tk help: http://python.org/topics/tkinter/
-# Tuto: http://ibiblio.org/obp/py4fun/gui/tkPhone.html
-# /usr/lib/python*/lib-tk/Tkinter.py
-#
-# grid table : row=0, column=0, columnspan=2, rowspan=2
-# grid align : sticky='n,s,e,w' (North, South, East, West)
-# pack place : side='top,bottom,right,left'
-# pack fill : fill='x,y,both,none', expand=1
-# pack align : anchor='n,s,e,w' (North, South, East, West)
-# padding : padx=10, pady=10, ipadx=10, ipady=10 (internal)
-# checkbox : offvalue is return if the _user_ deselected the box
-# label align: justify=left,right,center
-
-def load_GUI_resources():
- "Load all extra modules and methods used by GUI"
- global askopenfilename, showinfo, showwarning, showerror, Tkinter
- from tkinter.filedialog import askopenfilename
- from tkinter.messagebox import showinfo,showwarning,showerror
- import tkinter
-
-class Gui:
- "Graphical Tk Interface"
- def __init__(self, conf={}):
- self.root = tkinter.Tk() # mother window, come to butthead
- self.root.title(my_name) # window title bar text
- self.window = self.root # variable "focus" for inclusion
- self.row = 0 # row count for grid()
-
- self.action_length = 150 # left column length (pixel)
- self.frame_margin = 10 # frame margin size (pixel)
- self.frame_border = 6 # frame border size (pixel)
-
- # The default Gui colors, can be changed by %!guicolors
- self.dft_gui_colors = ['#6c6','white','#cf9','#030']
- self.gui_colors = []
- self.bg1 = self.fg1 = self.bg2 = self.fg2 = ''
-
- # On Tk, vars need to be set/get using setvar()/get()
- self.infile = self.setvar('')
- self.target = self.setvar('')
- self.target_name = self.setvar('')
-
- # The checks appearance order
- self.checks = [
- 'headers', 'enum-title', 'toc', 'mask-email', 'toc-only', 'stdout'
- ]
-
- # Creating variables for all checks
- for check in self.checks:
- setattr(self, 'f_'+check, self.setvar(''))
-
- # Load RC config
- self.conf = {}
- if conf: self.load_config(conf)
-
- def load_config(self, conf):
- self.conf = conf
- self.gui_colors = conf.get('guicolors') or self.dft_gui_colors
- self.bg1, self.fg1, self.bg2, self.fg2 = self.gui_colors
- self.root.config(bd=15,bg=self.bg1)
-
- ### Config as dic for python 1.5 compat (**opts don't work :( )
- def entry(self, **opts): return tkinter.Entry(self.window, opts)
- def label(self, txt='', bg=None, **opts):
- opts.update({'text':txt,'bg':bg or self.bg1})
- return tkinter.Label(self.window, opts)
- def button(self,name,cmd,**opts):
- opts.update({'text':name,'command':cmd})
- return tkinter.Button(self.window, opts)
- def check(self,name,checked=0,**opts):
- bg, fg = self.bg2, self.fg2
- opts.update({
- 'text':name,
- 'onvalue':1,
- 'offvalue':0,
- 'activeforeground':fg,
- 'activebackground':bg,
- 'highlightbackground':bg,
- 'fg':fg,
- 'bg':bg,
- 'anchor':'w'
- })
- chk = tkinter.Checkbutton(self.window, opts)
- if checked: chk.select()
- chk.grid(columnspan=2, sticky='w', padx=0)
- def menu(self,sel,items):
- return tkinter.OptionMenu(*(self.window,sel)+tuple(items))
-
- # Handy auxiliary functions
- def action(self, txt):
- self.label(
- txt,
- fg=self.fg1,
- bg=self.bg1,
- wraplength=self.action_length).grid(column=0,row=self.row)
- def frame_open(self):
- self.window = tkinter.Frame(
- self.root,
- bg=self.bg2,
- borderwidth=self.frame_border)
- def frame_close(self):
- self.window.grid(
- column=1,
- row=self.row,
- sticky='w',
- padx=self.frame_margin)
- self.window = self.root
- self.label('').grid()
- self.row += 2 # update row count
- def target_name2key(self):
- name = self.target_name.get()
- target = [x for x in TARGETS if TARGET_NAMES[x] == name]
- try : key = target[0]
- except: key = ''
- self.target = self.setvar(key)
- def target_key2name(self):
- key = self.target.get()
- name = TARGET_NAMES.get(key) or key
- self.target_name = self.setvar(name)
-
- def exit(self): self.root.destroy()
- def setvar(self, val): z = tkinter.StringVar() ; z.set(val) ; return z
-
- def askfile(self):
- ftypes= [(_('txt2tags files'), ('*.t2t','*.txt')), (_('All files'),'*')]
- newfile = askopenfilename(filetypes=ftypes)
- if newfile:
- self.infile.set(newfile)
- newconf = process_source_file(newfile)[0]
- newconf = ConfigMaster().sanity(newconf, gui=1)
- # Restate all checkboxes after file selection
- #TODO how to make a refresh without killing it?
- self.root.destroy()
- self.__init__(newconf)
- self.mainwindow()
-
- def scrollwindow(self, txt='no text!', title=''):
- # Create components
- win = tkinter.Toplevel() ; win.title(title)
- frame = tkinter.Frame(win)
- scroll = tkinter.Scrollbar(frame)
- text = tkinter.Text(frame,yscrollcommand=scroll.set)
- button = tkinter.Button(win)
- # Config
- text.insert(tkinter.END, '\n'.join(txt))
- scroll.config(command=text.yview)
- button.config(text=_('Close'), command=win.destroy)
- button.focus_set()
- # Packing
- text.pack(side='left', fill='both', expand=1)
- scroll.pack(side='right', fill='y')
- frame.pack(fill='both', expand=1)
- button.pack(ipadx=30)
-
- def runprogram(self):
- global CMDLINE_RAW
- # Prepare
- self.target_name2key()
- infile, target = self.infile.get(), self.target.get()
- # Sanity
- if not target:
- showwarning(my_name,_("You must select a target type!"))
- return
- if not infile:
- showwarning(my_name,_("You must provide the source file location!"))
- return
- # Compose cmdline
- guiflags = []
- real_cmdline_conf = ConfigMaster(CMDLINE_RAW).parse()
- if 'infile' in real_cmdline_conf:
- del real_cmdline_conf['infile']
- if 'target' in real_cmdline_conf:
- del real_cmdline_conf['target']
- real_cmdline = CommandLine().compose_cmdline(real_cmdline_conf)
- default_outfile = ConfigMaster().get_outfile_name(
- {'sourcefile':infile, 'outfile':'', 'target':target})
- for opt in self.checks:
- val = int(getattr(self, 'f_%s'%opt).get() or "0")
- if opt == 'stdout': opt = 'outfile'
- on_config = self.conf.get(opt) or 0
- on_cmdline = real_cmdline_conf.get(opt) or 0
- if opt == 'outfile':
- if on_config == STDOUT: on_config = 1
- else: on_config = 0
- if on_cmdline == STDOUT: on_cmdline = 1
- else: on_cmdline = 0
- if val != on_config or (
- val == on_config == on_cmdline and
- opt in real_cmdline_conf):
- if val:
- # Was not set, but user selected on GUI
- Debug("user turned ON: %s"%opt)
- if opt == 'outfile': opt = '-o-'
- else: opt = '--%s'%opt
- else:
- # Was set, but user deselected on GUI
- Debug("user turned OFF: %s"%opt)
- if opt == 'outfile':
- opt = "-o%s"%default_outfile
- else: opt = '--no-%s'%opt
- guiflags.append(opt)
- cmdline = [my_name, '-t', target] + real_cmdline + guiflags + [infile]
- Debug('Gui/Tk cmdline: %s' % cmdline, 5)
- # Run!
- cmdline_raw_orig = CMDLINE_RAW
- try:
- # Fake the GUI cmdline as the real one, and parse file
- CMDLINE_RAW = CommandLine().get_raw_config(cmdline[1:])
- data = process_source_file(infile)
- # On GUI, convert_* returns the data, not finish_him()
- outlist, config = convert_this_files([data])
- # On GUI and STDOUT, finish_him() returns the data
- result = finish_him(outlist, config)
- # Show outlist in s a nice new window
- if result:
- outlist, config = result
- title = _('%s: %s converted to %s') % (
- my_name,
- os.path.basename(infile),
- config['target'].upper())
- self.scrollwindow(outlist, title)
- # Show the "file saved" message
- else:
- msg = "%s\n\n %s\n%s\n\n %s\n%s"%(
- _('Conversion done!'),
- _('FROM:'), infile,
- _('TO:'), config['outfile'])
- showinfo(my_name, msg)
- except error: # common error (windowed), not quit
- pass
- except: # fatal error (windowed and printed)
- errormsg = getUnknownErrorMessage()
- print(errormsg)
- showerror(_('%s FATAL ERROR!')%my_name,errormsg)
- self.exit()
- CMDLINE_RAW = cmdline_raw_orig
-
- def mainwindow(self):
- self.infile.set(self.conf.get('sourcefile') or '')
- self.target.set(self.conf.get('target') or _('-- select one --'))
- outfile = self.conf.get('outfile')
- if outfile == STDOUT: # map -o-
- self.conf['stdout'] = 1
- if self.conf.get('headers') == None:
- self.conf['headers'] = 1 # map default
-
- action1 = _("Enter the source file location:")
- action2 = _("Choose the target document type:")
- action3 = _("Some options you may check:")
- action4 = _("Some extra options:")
- checks_txt = {
- 'headers' : _("Include headers on output"),
- 'enum-title': _("Number titles (1, 1.1, 1.1.1, etc)"),
- 'toc' : _("Do TOC also (Table of Contents)"),
- 'mask-email': _("Hide e-mails from SPAM robots"),
-
- 'toc-only' : _("Just do TOC, nothing more"),
- 'stdout' : _("Dump to screen (Don't save target file)")
- }
- targets_menu = [TARGET_NAMES[x] for x in TARGETS]
-
- # Header
- self.label("%s %s"%(my_name.upper(), my_version),
- bg=self.bg2, fg=self.fg2).grid(columnspan=2, ipadx=10)
- self.label(_("ONE source, MULTI targets")+'\n%s\n'%my_url,
- bg=self.bg1, fg=self.fg1).grid(columnspan=2)
- self.row = 2
- # Choose input file
- self.action(action1) ; self.frame_open()
- e_infile = self.entry(textvariable=self.infile,width=25)
- e_infile.grid(row=self.row, column=0, sticky='e')
- if not self.infile.get(): e_infile.focus_set()
- self.button(_("Browse"), self.askfile).grid(
- row=self.row, column=1, sticky='w', padx=10)
- # Show outfile name, style and encoding (if any)
- txt = ''
- if outfile:
- txt = outfile
- if outfile == STDOUT: txt = _('')
- l_output = self.label(_('Output: ')+txt, fg=self.fg2, bg=self.bg2)
- l_output.grid(columnspan=2, sticky='w')
- for setting in ['style','encoding']:
- if self.conf.get(setting):
- name = setting.capitalize()
- val = self.conf[setting]
- self.label('%s: %s'%(name, val),
- fg=self.fg2, bg=self.bg2).grid(
- columnspan=2, sticky='w')
- # Choose target
- self.frame_close() ; self.action(action2)
- self.frame_open()
- self.target_key2name()
- self.menu(self.target_name, targets_menu).grid(
- columnspan=2, sticky='w')
- # Options checkboxes label
- self.frame_close() ; self.action(action3)
- self.frame_open()
- # Compose options check boxes, example:
- # self.check(checks_txt['toc'],1,variable=self.f_toc)
- for check in self.checks:
- # Extra options label
- if check == 'toc-only':
- self.frame_close() ; self.action(action4)
- self.frame_open()
- txt = checks_txt[check]
- var = getattr(self, 'f_'+check)
- checked = self.conf.get(check)
- self.check(txt,checked,variable=var)
- self.frame_close()
- # Spacer and buttons
- self.label('').grid() ; self.row += 1
- b_quit = self.button(_("Quit"), self.exit)
- b_quit.grid(row=self.row, column=0, sticky='w', padx=30)
- b_conv = self.button(_("Convert!"), self.runprogram)
- b_conv.grid(row=self.row, column=1, sticky='e', padx=30)
- if self.target.get() and self.infile.get():
- b_conv.focus_set()
-
- # As documentation told me
- if sys.platform.startswith('win'):
- self.root.iconify()
- self.root.update()
- self.root.deiconify()
-
- self.root.mainloop()
-
-
-##############################################################################
-##############################################################################
-
-def exec_command_line(user_cmdline=[]):
- global CMDLINE_RAW, RC_RAW, DEBUG, VERBOSE, QUIET, GUI, Error
-
- # Extract command line data
- cmdline_data = user_cmdline or sys.argv[1:]
- CMDLINE_RAW = CommandLine().get_raw_config(cmdline_data, relative=1)
- cmdline_parsed = ConfigMaster(CMDLINE_RAW).parse()
- DEBUG = cmdline_parsed.get('debug' ) or 0
- VERBOSE = cmdline_parsed.get('verbose') or 0
- QUIET = cmdline_parsed.get('quiet' ) or 0
- GUI = cmdline_parsed.get('gui' ) or 0
- infiles = cmdline_parsed.get('infile' ) or []
-
- Message(_("Txt2tags %s processing begins")%my_version,1)
-
- # The easy ones
- if cmdline_parsed.get('help' ): Quit(USAGE)
- if cmdline_parsed.get('version'): Quit(VERSIONSTR)
- if cmdline_parsed.get('targets'):
- listTargets()
- Quit()
-
- # Multifile haters
- if len(infiles) > 1:
- errmsg=_("Option --%s can't be used with multiple input files")
- for option in NO_MULTI_INPUT:
- if cmdline_parsed.get(option):
- Error(errmsg%option)
-
- Debug("system platform: %s"%sys.platform)
- Debug("python version: %s"%(sys.version.split('(')[0]))
- Debug("line break char: %s"%repr(LB))
- Debug("command line: %s"%sys.argv)
- Debug("command line raw config: %s"%CMDLINE_RAW,1)
-
- # Extract RC file config
- if cmdline_parsed.get('rc') == 0:
- Message(_("Ignoring user configuration file"),1)
- else:
- rc_file = get_rc_path()
- if os.path.isfile(rc_file):
- Message(_("Loading user configuration file"),1)
- RC_RAW = ConfigLines(file_=rc_file).get_raw_config()
-
- Debug("rc file: %s"%rc_file)
- Debug("rc file raw config: %s"%RC_RAW,1)
-
- # Get all infiles config (if any)
- infiles_config = get_infiles_config(infiles)
-
- # Is GUI available?
- # Try to load and start GUI interface for --gui
- if GUI:
- try:
- load_GUI_resources()
- Debug("GUI resources OK (Tk module is installed)")
- winbox = Gui()
- Debug("GUI display OK")
- GUI = 1
- except:
- Debug("GUI Error: no Tk module or no DISPLAY")
- GUI = 0
-
- # User forced --gui, but it's not available
- if cmdline_parsed.get('gui') and not GUI:
- print(getTraceback()); print()
- Error(
- "Sorry, I can't run my Graphical Interface - GUI\n"
- "- Check if Python Tcl/Tk module is installed (Tkinter)\n"
- "- Make sure you are in a graphical environment (like X)")
-
- # Okay, we will use GUI
- if GUI:
- Message(_("We are on GUI interface"),1)
-
- # Redefine Error function to raise exception instead sys.exit()
- def Error(msg):
- showerror(_('txt2tags ERROR!'), msg)
- raise error
-
- # If no input file, get RC+cmdline config, else full config
- if not infiles:
- gui_conf = ConfigMaster(RC_RAW+CMDLINE_RAW).parse()
- else:
- try : gui_conf = infiles_config[0][0]
- except: gui_conf = {}
-
- # Sanity is needed to set outfile and other things
- gui_conf = ConfigMaster().sanity(gui_conf, gui=1)
- Debug("GUI config: %s"%gui_conf,5)
-
- # Insert config and populate the nice window!
- winbox.load_config(gui_conf)
- winbox.mainwindow()
-
- # Console mode rocks forever!
- else:
- Message(_("We are on Command Line interface"),1)
-
- # Called with no arguments, show error
- # TODO#1: this checking should be only in ConfigMaster.sanity()
- if not infiles:
- Error(_('Missing input file (try --help)') + '\n\n' +
- _('Please inform an input file (.t2t) at the end of the command.') + '\n' +
- _('Example:') + ' %s -t html %s' % (my_name, _('file.t2t')))
-
- convert_this_files(infiles_config)
-
- Message(_("Txt2tags finished successfully"),1)
-
-if __name__ == '__main__':
- try:
- exec_command_line()
- except error as msg:
- sys.stderr.write("%s\n"%msg)
- sys.stderr.flush()
- sys.exit(1)
- except SystemExit:
- pass
- except:
- sys.stderr.write(getUnknownErrorMessage())
- sys.stderr.flush()
- sys.exit(1)
- Quit()
-
-# The End.
diff --git a/misc/autodoc/markup.py b/misc/autodoc/markup.py
index 3adbf822a..43ba1d0c4 100644
--- a/misc/autodoc/markup.py
+++ b/misc/autodoc/markup.py
@@ -3,7 +3,7 @@
try:
import txt2tags
except ImportError:
- from external import txt2tags
+ raise SystemExit("txt2tags is not installed. Please install it with 'pip install -r requirements.txt', preferably in a virtual environment.")
def _get_config(target):
diff --git a/misc/tox.ini b/misc/tox.ini
index afbc7e11c..0aa77b564 100644
--- a/misc/tox.ini
+++ b/misc/tox.ini
@@ -1,10 +1,8 @@
-# Note that we can't run fast-downward.py from within the misc/
-# directory because the driver confuses the misc/release with the
-# builds/release directory.
-# All tests (except for 'build' and 'autocdoc') assume that Fast
-# Downward is already built. For the translator tests it is sufficient
-# to build the 'translate' configuration.
-
+# Note that we can't run fast-downward.py from within the misc/ directory
+# because the driver confuses the misc/release with the builds/release
+# directory.
+# All tests (except for 'build') assume that Fast Downward is already built. For
+# the translator tests it is sufficient to build the 'translate' configuration.
[tox]
envlist = build, driver, translator, search, style, autodoc, clang-tidy
@@ -13,9 +11,10 @@ skip_missing_interpreters = true
skipsdist = true
[testenv:autodoc]
-changedir = {toxinidir}/../
+deps = -r autodoc/requirements.txt
+changedir = {toxinidir}/autodoc/
commands =
- bash -c "python3 misc/autodoc/autodoc.py --dry-run > /dev/null"
+ bash -c "python3 autodoc.py --dry-run > /dev/null"
allowlist_externals =
bash
diff --git a/src/search/utils/markup.cc b/src/search/utils/markup.cc
index 867ffd11d..e8ccec3c0 100644
--- a/src/search/utils/markup.cc
+++ b/src/search/utils/markup.cc
@@ -32,9 +32,9 @@ string format_conference_reference(
const string &year) {
ostringstream ss;
ss << "\n\n"
- << format_authors(authors) << ".<
>\n"
- << "[" << t2t_escape(title) << " " << url << "].<
>\n"
- << "In //" << t2t_escape(conference) << "//";
+ << "- " << format_authors(authors) << ".<
>\n"
+ << " [" << t2t_escape(title) << " " << url << "].<
>\n"
+ << " In //" << t2t_escape(conference) << "//";
if (!pages.empty())
ss << ", pp. " << t2t_escape(pages);
ss << ". ";
@@ -50,9 +50,9 @@ string format_journal_reference(
const string &year) {
ostringstream ss;
ss << "\n\n"
- << format_authors(authors) << ".<
>\n"
- << "[" << t2t_escape(title) << " " << url << "].<
>\n"
- << "//" << t2t_escape(journal) << "// "
+ << "- " << format_authors(authors) << ".<
>\n"
+ << " [" << t2t_escape(title) << " " << url << "].<
>\n"
+ << " //" << t2t_escape(journal) << "// "
<< t2t_escape(volume) << ":" << t2t_escape(pages) << ". "
<< t2t_escape(year) << ".\n\n\n";
return ss.str();