FooBarWidget-mizuho 0.9.3 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. data/asciidoc/BUGS +3 -3
  2. data/asciidoc/CHANGELOG +112 -63
  3. data/asciidoc/CHANGELOG.txt +50 -0
  4. data/asciidoc/INSTALL +6 -6
  5. data/asciidoc/Makefile.in +21 -5
  6. data/asciidoc/README +3 -3
  7. data/asciidoc/asciidoc.conf +9 -12
  8. data/asciidoc/asciidoc.py +204 -151
  9. data/asciidoc/common.aap +2 -2
  10. data/asciidoc/doc/a2x.1 +4 -3
  11. data/asciidoc/doc/a2x.1.txt +1 -1
  12. data/asciidoc/doc/article.css-embedded.html +13 -12
  13. data/asciidoc/doc/article.html +46 -644
  14. data/asciidoc/doc/article.pdf +0 -0
  15. data/asciidoc/doc/asciidoc.1 +2 -2
  16. data/asciidoc/doc/asciidoc.1.css-embedded.html +14 -13
  17. data/asciidoc/doc/asciidoc.1.css.html +3 -3
  18. data/asciidoc/doc/asciidoc.1.html +3 -3
  19. data/asciidoc/doc/asciidoc.css-embedded.html +238 -225
  20. data/asciidoc/doc/asciidoc.css.html +227 -215
  21. data/asciidoc/doc/asciidoc.dict +10 -1
  22. data/asciidoc/doc/asciidoc.html +181 -164
  23. data/asciidoc/doc/asciidoc.txt +167 -148
  24. data/asciidoc/doc/asciimathml.txt +5 -4
  25. data/asciidoc/doc/book.css-embedded.html +13 -12
  26. data/asciidoc/doc/faq.txt +60 -3
  27. data/asciidoc/doc/music-filter.html +94 -41
  28. data/asciidoc/doc/music-filter.pdf +0 -0
  29. data/asciidoc/doc/source-highlight-filter.html +125 -465
  30. data/asciidoc/doc/source-highlight-filter.pdf +0 -0
  31. data/asciidoc/docbook.conf +8 -2
  32. data/asciidoc/examples/website/CHANGELOG.html +129 -4
  33. data/asciidoc/examples/website/INSTALL.html +6 -6
  34. data/asciidoc/examples/website/README-website.html +3 -3
  35. data/asciidoc/examples/website/README.html +3 -3
  36. data/asciidoc/examples/website/a2x.1.html +4 -4
  37. data/asciidoc/examples/website/asciidoc-docbook-xsl.html +3 -3
  38. data/asciidoc/examples/website/asciidoc-graphviz-sample.txt +1 -0
  39. data/asciidoc/examples/website/downloads.html +7 -7
  40. data/asciidoc/examples/website/faq.html +95 -40
  41. data/asciidoc/examples/website/index.html +34 -13
  42. data/asciidoc/examples/website/index.txt +25 -9
  43. data/asciidoc/examples/website/latex-backend.html +4 -4
  44. data/asciidoc/examples/website/manpage.html +3 -3
  45. data/asciidoc/examples/website/music-filter.html +3 -3
  46. data/asciidoc/examples/website/sample1.png +0 -0
  47. data/asciidoc/examples/website/sample3.png +0 -0
  48. data/asciidoc/examples/website/sample4.png +0 -0
  49. data/asciidoc/examples/website/source-highlight-filter.html +5 -5
  50. data/asciidoc/examples/website/support.html +3 -3
  51. data/asciidoc/examples/website/userguide.html +227 -215
  52. data/asciidoc/examples/website/version9.html +3 -3
  53. data/asciidoc/filters/{code-filter-readme.txt → code/code-filter-readme.txt} +0 -0
  54. data/asciidoc/filters/{code-filter-test.txt → code/code-filter-test.txt} +0 -0
  55. data/asciidoc/filters/{code-filter.conf → code/code-filter.conf} +1 -1
  56. data/asciidoc/filters/{code-filter.py → code/code-filter.py} +0 -0
  57. data/asciidoc/filters/graphviz/asciidoc-graphviz-sample.txt +130 -0
  58. data/asciidoc/filters/graphviz/graphviz-filter.conf +39 -0
  59. data/asciidoc/filters/graphviz/graphviz2png.py +154 -0
  60. data/asciidoc/filters/{music-filter-test.txt → music/music-filter-test.txt} +0 -0
  61. data/asciidoc/filters/{music-filter.conf → music/music-filter.conf} +0 -0
  62. data/asciidoc/filters/{music2png.py → music/music2png.py} +0 -0
  63. data/asciidoc/filters/{source-highlight-filter-test.txt → source/source-highlight-filter-test.txt} +0 -0
  64. data/asciidoc/filters/{source-highlight-filter.conf → source/source-highlight-filter.conf} +2 -1
  65. data/asciidoc/html4.conf +5 -2
  66. data/asciidoc/stylesheets/xhtml11-quirks.css +0 -8
  67. data/asciidoc/stylesheets/xhtml11.css +11 -2
  68. data/asciidoc/vim/syntax/asciidoc.vim +1 -1
  69. data/asciidoc/xhtml11.conf +5 -2
  70. data/lib/mizuho/parser.rb +5 -1
  71. data/mizuho.gemspec +5 -16
  72. data/test/parser_spec.rb +49 -0
  73. metadata +22 -10
@@ -3,6 +3,56 @@ AsciiDoc ChangeLog
3
3
 
4
4
  :replacements.\bweb:: http://www.methods.co.nz/asciidoc/
5
5
 
6
+ Version 8.3.3 (2009-01-02)
7
+ --------------------------
8
+ This release supercedes 8.3.2.
9
+
10
+ .Bug fixes
11
+ - The broken and confusing numeration and numeration2 numbered list
12
+ attributes have been dropped, use the style attribute instead.
13
+
14
+
15
+ Version 8.3.2 (2009-01-01)
16
+ --------------------------
17
+ .Additions and changes
18
+ - Added Gouichi Iisaka's Graphviz filter to distribution.
19
+ - The 'SidebarBlock' element can now be rendered with an 'abstract'
20
+ style.
21
+ - Reorganized filters into a separate subdirectory for each filter.
22
+ - Updated `Makefile.in` and `MANIFEST` files to reflect new filters
23
+ organization.
24
+ - Added 'listing' style to 'LiteralBlock' element so listings with
25
+ nested listing blocks can be rendered as a listing block.
26
+ - Changed example 'code' filter to use preferred 'ListingBlock' syntax
27
+ (the old `~` delimited filter syntax is no longer used).
28
+ - Implemented 'enumeration' and 'enumeration2' numbered list
29
+ attributes for specifying the list numbering style ('arabic',
30
+ 'loweralpha', 'upperalpha', 'lowerroman' and 'upperroman').
31
+ - AsciiDoc now recognizes 'upperalpha', 'lowerroman' and 'upperroman'
32
+ numbers in `listdef-numbered2` numbered lists and sets the number
33
+ style based on the style of the first numbered list item
34
+ (alternative to setting 'enumeration2' attribute).
35
+ - Updated `formatlistpat` definition in `.vimrc` example in User
36
+ Guide.
37
+ - You can now backslash escape system block macros.
38
+ - Added 'Pychart' FAQ.
39
+ - Drop paragraph 'text' and list 'text', 'index' and 'label' match
40
+ groups from attributes -- they are included in the element's text
41
+ and we don't want them processed a second time as attributes.
42
+ - Changed comment line block macro to a passthrough block macro to
43
+ ensure no substitutions.
44
+ - A 'subslist' no longer has to be appended to a 'PassthroughBlock'
45
+ macro definition, if omitted no substitutions are performed.
46
+ - Code tidy up: replaced deprecated `<>` operator with `!=`.
47
+ - Removed unused linuxdoc code.
48
+ - Code tidy ups: dropped old types module reference; replaced
49
+ `has_key()` with preferred `in` operator.
50
+
51
+ .Bug fixes
52
+ - Old syntax source highlight filter regression: special characters
53
+ where not escaped in DocBook outputs.
54
+
55
+
6
56
  Version 8.3.1 (2008-12-14)
7
57
  --------------------------
8
58
  .Additions and changes
data/asciidoc/INSTALL CHANGED
@@ -1,6 +1,6 @@
1
1
  AsciiDoc Installation
2
2
 
3
- version 8.3.1, 14 December 2008
3
+ version 8.3.3, 2 January 2009
4
4
 
5
5
  Note: The current version of AsciiDoc requires Python 2.4 or newer to
6
6
  run. If you don't already have an up-to-date version of Python
@@ -27,8 +27,8 @@
27
27
 
28
28
  The autoconf(1) generated configure script creates a make file that is
29
29
  tailored for your system. To install:
30
- $ tar -xzf asciidoc-8.3.1.tar.gz
31
- $ cd asciidoc-8.3.1
30
+ $ tar -xzf asciidoc-8.3.3.tar.gz
31
+ $ cd asciidoc-8.3.3
32
32
  $ ./configure
33
33
  $ make
34
34
  $ sudo make install
@@ -51,7 +51,7 @@
51
51
  new folder:
52
52
  $ mkdir asciidoc
53
53
  $ cd asciidoc
54
- $ unzip ../asciidoc-8.3.1.zip
54
+ $ unzip ../asciidoc-8.3.3.zip
55
55
  __________________________________________________________________
56
56
 
57
57
  4. Testing your installation
@@ -65,8 +65,8 @@
65
65
  directly or create a suitable asciidoc.bat file.
66
66
  __________________________________________________________________
67
67
 
68
- Version 8.3.1
69
- Last updated 2008-12-13 10:52:07 NZDT
68
+ Version 8.3.3
69
+ Last updated 2009-01-02 12:45:19 NZDT
70
70
 
71
71
  References
72
72
 
data/asciidoc/Makefile.in CHANGED
@@ -2,6 +2,8 @@
2
2
  # Make file to install/uninstall AsciiDoc
3
3
  #
4
4
 
5
+ .NOTPARALLEL:
6
+
5
7
  INSTALL = @INSTALL@
6
8
  INSTALL_PROG = @INSTALL_PROGRAM@
7
9
  INSTALL_DATA = @INSTALL_DATA@
@@ -32,11 +34,25 @@ manpdir = $(mandir)/man1
32
34
  conf = $(wildcard *.conf)
33
35
  confdir = $(ASCIIDOCCONF)
34
36
 
35
- filters = $(wildcard filters/*.py)
36
37
  filtersdir = $(ASCIIDOCCONF)/filters
37
38
 
38
- filterconfs = $(wildcard filters/*.conf)
39
- filterconfsdir = $(ASCIIDOCCONF)/filters
39
+ codefilter = filters/code/code-filter.py
40
+ codefilterdir = $(filtersdir)/code
41
+ codefilterconf = filters/code/code-filter.conf
42
+ codefilterconfdir = $(filtersdir)/code
43
+
44
+ graphvizfilter = filters/graphviz/graphviz2png.py
45
+ graphvizfilterdir = $(filtersdir)/graphviz
46
+ graphvizfilterconf = filters/graphviz/graphviz-filter.conf
47
+ graphvizfilterconfdir = $(filtersdir)/graphviz
48
+
49
+ musicfilter = filters/music/music2png.py
50
+ musicfilterdir = $(filtersdir)/music
51
+ musicfilterconf = filters/music/music-filter.conf
52
+ musicfilterconfdir = $(filtersdir)/music
53
+
54
+ sourcefilterconf = filters/source/source-highlight-filter.conf
55
+ sourcefilterconfdir = $(filtersdir)/source
40
56
 
41
57
  docbook = $(wildcard docbook-xsl/*.xsl)
42
58
  docbookdir = $(ASCIIDOCCONF)/docbook-xsl
@@ -59,8 +75,8 @@ iconsdir = $(ASCIIDOCCONF)/images/icons
59
75
  doc = $(wildcard README*) $(wildcard BUGS*) $(wildcard INSTALL*) $(wildcard CHANGELOG*)
60
76
  docdir = $(datadir)/doc/asciidoc
61
77
 
62
- DATATARGETS = manp conf filterconfs docbook dblatex css js callouts icons
63
- PROGTARGETS = prog filters
78
+ DATATARGETS = manp conf docbook dblatex css js callouts icons codefilterconf musicfilterconf sourcefilterconf graphvizfilterconf
79
+ PROGTARGETS = prog codefilter musicfilter graphvizfilter
64
80
  TARGETS = $(DATATARGETS) $(PROGTARGETS) doc
65
81
 
66
82
  INSTDIRS = $(TARGETS:%=%dir)
data/asciidoc/README CHANGED
@@ -1,6 +1,6 @@
1
1
  AsciiDoc README File
2
2
 
3
- version 8.3.1, 14 December 2008
3
+ version 8.3.3, 2 January 2009
4
4
  __________________________________________________________________
5
5
 
6
6
  1. Prerequisites
@@ -36,8 +36,8 @@
36
36
  granted under the terms of the GNU General Public License (GPL).
37
37
  __________________________________________________________________
38
38
 
39
- Version 8.3.1
40
- Last updated 2008-12-13 09:58:33 NZDT
39
+ Version 8.3.3
40
+ Last updated 2009-01-02 12:45:18 NZDT
41
41
 
42
42
  References
43
43
 
@@ -231,20 +231,11 @@ endif::asciidoc7compatible[]
231
231
  (?u)^(?P<name>image)::(?P<target>\S*?)(\[(?P<attrlist>.*?)\])$=#
232
232
 
233
233
  # Passthrough macros.
234
- (?u)^(?P<name>pass)::(?P<subslist>\S*?)(\[(?P<passtext>.*?)\])$=#[]
234
+ (?u)^(?P<name>pass)::(?P<subslist>\S*?)(\[(?P<passtext>.*?)\])$=#
235
235
 
236
236
  ^'{3,}$=#ruler
237
237
  ^<{3,}$=#pagebreak
238
- ^//([^/].*|)$=#comment
239
-
240
- # Default block macro (listed last as a catchall)).
241
- #(?u)^(?P<name>\w(\w|-)*?)::(?P<target>\S*?)(\[(?P<attrlist>.*?)\])$=#
242
-
243
- #--------------
244
- # System macros
245
- #--------------
246
- # This default system macro is hardwired into asciidoc.
247
- #(?u)^(?P<name>\w(\w|-)*?)::(?P<target>\S*?)(\[(?P<attrlist>.*?)\])$=+
238
+ ^//(?P<passtext>[^/].*|)$=#comment
248
239
 
249
240
  #-----------------
250
241
  # Delimited blocks
@@ -260,6 +251,8 @@ options=skip
260
251
  delimiter=^\*{4,}$
261
252
  template=sidebarblock
262
253
  options=sectionbody
254
+ posattrs=style
255
+ abstract-style=template="abstractblock"
263
256
 
264
257
  [blockdef-list]
265
258
  delimiter=^--$
@@ -288,6 +281,7 @@ delimiter=^\.{4,}$
288
281
  template=literalblock
289
282
  subs=verbatim
290
283
  posattrs=style
284
+ listing-style=template="listingblock"
291
285
  # DEPRECATED: Use verse style on quote blocks instead.
292
286
  verse-style=template="verseblock",subs="normal"
293
287
 
@@ -311,6 +305,7 @@ WARNING-style=template="admonitionblock",name="warning",caption="{warning_captio
311
305
  CAUTION-style=template="admonitionblock",name="caution",caption="{caution_caption}"
312
306
 
313
307
  # For use by custom filters.
308
+ # NOTE: No longer used, a styled listing block (blockdef-listing) is preferable.
314
309
  [blockdef-filter]
315
310
  delimiter=^~{4,}$
316
311
  template=listingblock
@@ -341,12 +336,14 @@ delimiter=^\s*(?P<index>\d*)\. +(?P<text>.+)$
341
336
  posattrs=style
342
337
  type=numbered
343
338
  tags=numbered
339
+ style=arabic
344
340
 
345
341
  [listdef-numbered2]
346
- delimiter=^\s*(?P<index>[.a-z])\. +(?P<text>.+)$
342
+ delimiter=^\s*(?P<index>[.a-zA-Z]|[ivxIVX]+)\. +(?P<text>.+)$
347
343
  posattrs=style
348
344
  type=numbered
349
345
  tags=numbered2
346
+ style=loweralpha
350
347
 
351
348
  [listdef-labeled]
352
349
  delimiter=^\s*(?P<label>.*\S)::(\s+(?P<text>.+))?$
data/asciidoc/asciidoc.py CHANGED
@@ -7,9 +7,8 @@ under the terms of the GNU General Public License (GPL).
7
7
  """
8
8
 
9
9
  import sys, os, re, time, traceback, tempfile, subprocess, codecs, locale
10
- from types import *
11
10
 
12
- VERSION = '8.3.1' # See CHANGLOG file for version history.
11
+ VERSION = '8.3.3' # See CHANGLOG file for version history.
13
12
 
14
13
  #---------------------------------------------------------------------------
15
14
  # Program onstants.
@@ -110,22 +109,19 @@ def verbose(msg,linenos=True):
110
109
  if config.verbose:
111
110
  console(msg,linenos=linenos)
112
111
 
113
- def warning(msg,linenos=True):
114
- console(msg,'WARNING: ',linenos)
112
+ def warning(msg,linenos=True,offset=0):
113
+ console(msg,'WARNING: ',linenos,offset=offset)
115
114
  document.has_warnings = True
116
115
 
117
116
  def deprecated(msg, linenos=True):
118
117
  console(msg, 'DEPRECATED: ', linenos)
119
118
 
120
- def message(msg, prefix='', linenos=True, cursor=None):
121
- """
122
- Return formatted message string. 'offset' is added to reported line number
123
- for warnings emitted when reading ahead.
124
- """
119
+ def message(msg, prefix='', linenos=True, cursor=None, offset=0):
120
+ """Return formatted message string."""
125
121
  if linenos and reader.cursor:
126
122
  if not cursor:
127
123
  cursor = reader.cursor
128
- prefix += '%s: line %d: ' % (os.path.basename(cursor[0]),cursor[1])
124
+ prefix += '%s: line %d: ' % (os.path.basename(cursor[0]),cursor[1]+offset)
129
125
  return prefix + msg
130
126
 
131
127
  def error(msg, cursor=None, halt=False):
@@ -141,8 +137,8 @@ def error(msg, cursor=None, halt=False):
141
137
  console(msg,'ERROR: ',cursor=cursor)
142
138
  document.has_errors = True
143
139
 
144
- def console(msg, prefix='', linenos=True, cursor=None):
145
- print_stderr(message(msg,prefix,linenos,cursor))
140
+ def console(msg, prefix='', linenos=True, cursor=None, offset=0):
141
+ print_stderr(message(msg,prefix,linenos,cursor,offset))
146
142
 
147
143
  def file_in(fname, directory):
148
144
  """Return True if file fname resides inside directory."""
@@ -308,7 +304,7 @@ def parse_attributes(attrs,dict):
308
304
  def f(*args,**keywords):
309
305
  # Name and add aguments '1','2'... to keywords.
310
306
  for i in range(len(args)):
311
- if not keywords.has_key(str(i+1)):
307
+ if not str(i+1) in keywords:
312
308
  keywords[str(i+1)] = args[i]
313
309
  return keywords
314
310
 
@@ -560,16 +556,28 @@ def update_attrs(attrs,dict):
560
556
  raise EAsciiDoc,'illegal attribute name: %s' % k
561
557
  attrs[k] = v
562
558
 
563
- def filter_lines(filter_cmd, lines, dict={}):
559
+ def filter_lines(filter_cmd, lines, attrs={}):
564
560
  """
565
561
  Run 'lines' through the 'filter_cmd' shell command and return the result.
566
- The 'dict' dictionary contains additional filter attributes.
562
+ The 'attrs' dictionary contains additional filter attributes.
567
563
  """
564
+ def findfilter(name,dir,filter):
565
+ """Find filter file 'fname' with style name 'name' in directory
566
+ 'dir'. Return found file path or None if not found."""
567
+ if name:
568
+ result = os.path.join(dir,'filters',name,filter)
569
+ if os.path.isfile(result):
570
+ return result
571
+ result = os.path.join(dir,'filters',filter)
572
+ if os.path.isfile(result):
573
+ return result
574
+ return None
575
+
568
576
  # Return input lines if there's not filter.
569
577
  if not filter_cmd or not filter_cmd.strip():
570
578
  return lines
571
579
  # Perform attributes substitution on the filter command.
572
- s = subs_attrs(filter_cmd, dict)
580
+ s = subs_attrs(filter_cmd, attrs)
573
581
  if not s:
574
582
  raise EAsciiDoc,'undefined filter attribute in command: %s' % filter_cmd
575
583
  filter_cmd = s.strip()
@@ -583,33 +591,23 @@ def filter_lines(filter_cmd, lines, dict={}):
583
591
  # Unquoted catch all.
584
592
  mo = re.match(r'^(?P<cmd>\S+)(?P<tail>.*)$', filter_cmd)
585
593
  cmd = mo.group('cmd').strip()
586
- # Search for the filter command in both user and application 'filters'
587
- # sub-directories.
588
- found = False
594
+ found = None
589
595
  if not os.path.dirname(cmd):
590
- # Check in asciidoc user and application directories for unqualified
591
- # file name.
596
+ # Filter command has no directory path so search filter directories.
597
+ filtername = attrs.get('style')
592
598
  if USER_DIR:
593
- cmd2 = os.path.join(USER_DIR,'filters',cmd)
594
- if os.path.isfile(cmd2):
595
- found = True
599
+ found = findfilter(filtername, USER_DIR, cmd)
596
600
  if not found:
597
- cmd2 = os.path.join(CONF_DIR,'filters',cmd)
598
- if os.path.isfile(cmd2):
599
- found = True
601
+ found = findfilter(filtername, CONF_DIR, cmd)
600
602
  if not found:
601
- cmd2 = os.path.join(APP_DIR,'filters',cmd)
602
- if os.path.isfile(cmd2):
603
- found = True
604
- if found:
605
- cmd = cmd2
603
+ found = findfilter(filtername, APP_DIR, cmd)
606
604
  else:
607
605
  if os.path.isfile(cmd):
608
- found = True
606
+ found = cmd
609
607
  else:
610
608
  warning('filter not found: %s' % cmd)
611
609
  if found:
612
- filter_cmd = '"' + cmd + '"' + mo.group('tail')
610
+ filter_cmd = '"' + found + '"' + mo.group('tail')
613
611
  if sys.platform == 'win32':
614
612
  # Windows doesn't like running scripts directly so explicitly
615
613
  # specify interpreter.
@@ -743,7 +741,7 @@ def subs_attrs(lines, dictionary=None):
743
741
  if n == 0: break
744
742
  return result
745
743
 
746
- if isinstance(lines,StringType):
744
+ if type(lines) == str:
747
745
  string_result = True
748
746
  lines = [lines]
749
747
  else:
@@ -929,6 +927,7 @@ class Lex:
929
927
  prev_cursor = None
930
928
  def __init__(self):
931
929
  raise AssertionError,'no class instances allowed'
930
+ @staticmethod
932
931
  def next():
933
932
  """Returns class of next element on the input (None if EOF). The
934
933
  reader is assumed to be at the first line following a previous element,
@@ -981,8 +980,8 @@ class Lex:
981
980
  Lex.prev_cursor = reader.cursor
982
981
  Lex.prev_element = result
983
982
  return result
984
- next = staticmethod(next)
985
983
 
984
+ @staticmethod
986
985
  def subs_1(s,options):
987
986
  """Perform substitution specified in 'options' (in 'options' order) on
988
987
  Does not process 'attributes' substitutions."""
@@ -1011,8 +1010,8 @@ class Lex:
1011
1010
  if not result:
1012
1011
  break
1013
1012
  return result
1014
- subs_1 = staticmethod(subs_1)
1015
1013
 
1014
+ @staticmethod
1016
1015
  def subs(lines,options):
1017
1016
  """Perform inline processing specified by 'options' (in 'options'
1018
1017
  order) on sequence of 'lines'."""
@@ -1040,8 +1039,8 @@ class Lex:
1040
1039
  if 'macros' in options:
1041
1040
  para = macros.restore_passthroughs(para)
1042
1041
  return para.splitlines()
1043
- subs = staticmethod(subs)
1044
1042
 
1043
+ @staticmethod
1045
1044
  def set_margin(lines, margin=0):
1046
1045
  """Utility routine that sets the left margin to 'margin' space in a
1047
1046
  block of non-blank lines."""
@@ -1055,7 +1054,6 @@ class Lex:
1055
1054
  for i in range(len(lines)):
1056
1055
  lines[i] = ' '*margin + lines[i][width:]
1057
1056
  return lines
1058
- set_margin = staticmethod(set_margin)
1059
1057
 
1060
1058
  #---------------------------------------------------------------------------
1061
1059
  # Document element classes parse AsciiDoc reader input and write DocBook writer
@@ -1167,7 +1165,7 @@ class Document:
1167
1165
  error('SYNOPSIS section expected')
1168
1166
  else:
1169
1167
  Title.translate()
1170
- if Title.attributes['title'].upper() <> 'SYNOPSIS':
1168
+ if Title.attributes['title'].upper() != 'SYNOPSIS':
1171
1169
  error('second section must be named SYNOPSIS')
1172
1170
  if Title.level != 1:
1173
1171
  error('SYNOPSIS section title must be at level 1')
@@ -1272,6 +1270,7 @@ class Header:
1272
1270
  """Static methods and attributes only."""
1273
1271
  def __init__(self):
1274
1272
  raise AssertionError,'no class instances allowed'
1273
+ @staticmethod
1275
1274
  def translate():
1276
1275
  assert Lex.next() is Title and Title.level == 0
1277
1276
  Title.translate()
@@ -1324,7 +1323,7 @@ class Header:
1324
1323
  error('NAME section expected')
1325
1324
  else:
1326
1325
  Title.translate()
1327
- if Title.attributes['title'].upper() <> 'NAME':
1326
+ if Title.attributes['title'].upper() != 'NAME':
1328
1327
  error('first section must be named NAME')
1329
1328
  if Title.level != 1:
1330
1329
  error('NAME section title must be at level 1')
@@ -1338,9 +1337,6 @@ class Header:
1338
1337
  attrs['manname'] = mo.group('manname').strip()
1339
1338
  attrs['manpurpose'] = mo.group('manpurpose').strip()
1340
1339
  document.process_author_names()
1341
- if document.backend == 'linuxdoc' and not attrs.has_key('author'):
1342
- warning('linuxdoc requires author name')
1343
- translate = staticmethod(translate)
1344
1340
 
1345
1341
  class AttributeEntry:
1346
1342
  """Static methods and attributes only."""
@@ -1351,6 +1347,7 @@ class AttributeEntry:
1351
1347
  value = None
1352
1348
  def __init__(self):
1353
1349
  raise AssertionError,'no class instances allowed'
1350
+ @staticmethod
1354
1351
  def isnext():
1355
1352
  result = False # Assume not next.
1356
1353
  if not AttributeEntry.pattern:
@@ -1377,7 +1374,7 @@ class AttributeEntry:
1377
1374
  AttributeEntry.value = AttributeEntry.value.strip()
1378
1375
  result = True
1379
1376
  return result
1380
- isnext = staticmethod(isnext)
1377
+ @staticmethod
1381
1378
  def translate():
1382
1379
  assert Lex.next() is AttributeEntry
1383
1380
  attr = AttributeEntry # Alias for brevity.
@@ -1411,12 +1408,11 @@ class AttributeEntry:
1411
1408
  document.attributes[attr.name] = attr.value
1412
1409
  elif attr.name in document.attributes:
1413
1410
  del document.attributes[attr.name]
1414
- translate = staticmethod(translate)
1411
+ @staticmethod
1415
1412
  def translate_all():
1416
1413
  """ Process all contiguous attribute lines on reader."""
1417
1414
  while AttributeEntry.isnext():
1418
1415
  AttributeEntry.translate()
1419
- translate_all = staticmethod(translate_all)
1420
1416
 
1421
1417
  class AttributeList:
1422
1418
  """Static methods and attributes only."""
@@ -1425,10 +1421,11 @@ class AttributeList:
1425
1421
  attrs = {}
1426
1422
  def __init__(self):
1427
1423
  raise AssertionError,'no class instances allowed'
1424
+ @staticmethod
1428
1425
  def isnext():
1429
1426
  result = False # Assume not next.
1430
1427
  if not AttributeList.pattern:
1431
- if not document.attributes.has_key('attributelist-pattern'):
1428
+ if not 'attributelist-pattern' in document.attributes:
1432
1429
  error("[attributes] missing 'attributelist-pattern' entry")
1433
1430
  AttributeList.pattern = document.attributes['attributelist-pattern']
1434
1431
  line = reader.read_next()
@@ -1438,7 +1435,7 @@ class AttributeList:
1438
1435
  AttributeList.match = mo
1439
1436
  result = True
1440
1437
  return result
1441
- isnext = staticmethod(isnext)
1438
+ @staticmethod
1442
1439
  def translate():
1443
1440
  assert Lex.next() is AttributeList
1444
1441
  reader.read() # Discard attribute list from reader.
@@ -1451,7 +1448,7 @@ class AttributeList:
1451
1448
  parse_attributes(v, AttributeList.attrs)
1452
1449
  else:
1453
1450
  AttributeList.attrs[k] = v
1454
- translate = staticmethod(translate)
1451
+ @staticmethod
1455
1452
  def consume(d):
1456
1453
  """Add attribute list to the dictionary 'd' and reset the
1457
1454
  list."""
@@ -1463,7 +1460,6 @@ class AttributeList:
1463
1460
  options = parse_options(d['options'], (), 'illegal option name')
1464
1461
  for option in options:
1465
1462
  d[option+'-option'] = ''
1466
- consume = staticmethod(consume)
1467
1463
 
1468
1464
  class BlockTitle:
1469
1465
  """Static methods and attributes only."""
@@ -1471,6 +1467,7 @@ class BlockTitle:
1471
1467
  pattern = None
1472
1468
  def __init__(self):
1473
1469
  raise AssertionError,'no class instances allowed'
1470
+ @staticmethod
1474
1471
  def isnext():
1475
1472
  result = False # Assume not next.
1476
1473
  line = reader.read_next()
@@ -1480,7 +1477,7 @@ class BlockTitle:
1480
1477
  BlockTitle.title = mo.group('title')
1481
1478
  result = True
1482
1479
  return result
1483
- isnext = staticmethod(isnext)
1480
+ @staticmethod
1484
1481
  def translate():
1485
1482
  assert Lex.next() is BlockTitle
1486
1483
  reader.read() # Discard title from reader.
@@ -1492,13 +1489,12 @@ class BlockTitle:
1492
1489
  if not s:
1493
1490
  warning('blank block title')
1494
1491
  BlockTitle.title = s
1495
- translate = staticmethod(translate)
1492
+ @staticmethod
1496
1493
  def consume(d):
1497
1494
  """If there is a title add it to dictionary 'd' then reset title."""
1498
1495
  if BlockTitle.title:
1499
1496
  d['title'] = BlockTitle.title
1500
1497
  BlockTitle.title = None
1501
- consume = staticmethod(consume)
1502
1498
 
1503
1499
  class Title:
1504
1500
  """Processes Header and Section titles. Static methods and attributes
@@ -1515,6 +1511,7 @@ class Title:
1515
1511
  linecount = None # Number of lines in title (1 or 2).
1516
1512
  def __init__(self):
1517
1513
  raise AssertionError,'no class instances allowed'
1514
+ @staticmethod
1518
1515
  def translate():
1519
1516
  """Parse the Title.attributes and Title.level from the reader. The
1520
1517
  real work has already been done by parse()."""
@@ -1531,11 +1528,11 @@ class Title:
1531
1528
  if not s:
1532
1529
  warning('blank section title')
1533
1530
  Title.attributes['title'] = s
1534
- translate = staticmethod(translate)
1531
+ @staticmethod
1535
1532
  def isnext():
1536
1533
  lines = reader.read_ahead(2)
1537
1534
  return Title.parse(lines)
1538
- isnext = staticmethod(isnext)
1535
+ @staticmethod
1539
1536
  def parse(lines):
1540
1537
  """Parse title at start of lines tuple."""
1541
1538
  if len(lines) == 0: return False
@@ -1544,7 +1541,7 @@ class Title:
1544
1541
  result = False
1545
1542
  for level in range(len(Title.underlines)):
1546
1543
  k = 'sect%s' % level
1547
- if Title.dump_dict.has_key(k):
1544
+ if k in Title.dump_dict:
1548
1545
  mo = re.match(Title.dump_dict[k], lines[0])
1549
1546
  if mo:
1550
1547
  Title.attributes = mo.groupdict()
@@ -1578,16 +1575,16 @@ class Title:
1578
1575
  result = True
1579
1576
  # Check for expected pattern match groups.
1580
1577
  if result:
1581
- if not Title.attributes.has_key('title'):
1578
+ if not 'title' in Title.attributes:
1582
1579
  warning('[titles] entry has no <title> group')
1583
1580
  Title.attributes['title'] = lines[0]
1584
1581
  for k,v in Title.attributes.items():
1585
1582
  if v is None: del Title.attributes[k]
1586
1583
  return result
1587
- parse = staticmethod(parse)
1584
+ @staticmethod
1588
1585
  def load(entries):
1589
1586
  """Load and validate [titles] section entries dictionary."""
1590
- if entries.has_key('underlines'):
1587
+ if 'underlines' in entries:
1591
1588
  errmsg = 'malformed [titles] underlines entry'
1592
1589
  try:
1593
1590
  underlines = parse_list(entries['underlines'])
@@ -1600,17 +1597,17 @@ class Title:
1600
1597
  raise EAsciiDoc,errmsg
1601
1598
  Title.underlines = tuple(underlines)
1602
1599
  Title.dump_dict['underlines'] = entries['underlines']
1603
- if entries.has_key('subs'):
1600
+ if 'subs' in entries:
1604
1601
  Title.subs = parse_options(entries['subs'], SUBS_OPTIONS,
1605
1602
  'illegal [titles] subs entry')
1606
1603
  Title.dump_dict['subs'] = entries['subs']
1607
- if entries.has_key('sectiontitle'):
1604
+ if 'sectiontitle' in entries:
1608
1605
  pat = entries['sectiontitle']
1609
1606
  if not pat or not is_regexp(pat):
1610
1607
  raise EAsciiDoc,'malformed [titles] sectiontitle entry'
1611
1608
  Title.pattern = pat
1612
1609
  Title.dump_dict['sectiontitle'] = pat
1613
- if entries.has_key('blocktitle'):
1610
+ if 'blocktitle' in entries:
1614
1611
  pat = entries['blocktitle']
1615
1612
  if not pat or not is_regexp(pat):
1616
1613
  raise EAsciiDoc,'malformed [titles] blocktitle entry'
@@ -1618,7 +1615,7 @@ class Title:
1618
1615
  Title.dump_dict['blocktitle'] = pat
1619
1616
  # Load single-line title patterns.
1620
1617
  for k in ('sect0','sect1','sect2','sect3','sect4'):
1621
- if entries.has_key(k):
1618
+ if k in entries:
1622
1619
  pat = entries[k]
1623
1620
  if not pat or not is_regexp(pat):
1624
1621
  raise EAsciiDoc,'malformed [titles] %s entry' % k
@@ -1626,10 +1623,10 @@ class Title:
1626
1623
  # TODO: Check we have either a Title.pattern or at least one
1627
1624
  # single-line title pattern -- can this be done here or do we need
1628
1625
  # check routine like the other block checkers?
1629
- load = staticmethod(load)
1626
+ @staticmethod
1630
1627
  def dump():
1631
1628
  dump_section('titles',Title.dump_dict)
1632
- dump = staticmethod(dump)
1629
+ @staticmethod
1633
1630
  def setsectname():
1634
1631
  """Set Title section name. First search for section title in
1635
1632
  [specialsections], if not found use default 'sect<level>' name."""
@@ -1645,7 +1642,7 @@ class Title:
1645
1642
  break
1646
1643
  else:
1647
1644
  Title.sectname = 'sect%d' % Title.level
1648
- setsectname = staticmethod(setsectname)
1645
+ @staticmethod
1649
1646
  def getnumber(level):
1650
1647
  """Return next section number at section 'level' formatted like
1651
1648
  1.2.3.4."""
@@ -1663,7 +1660,6 @@ class Title:
1663
1660
  # Reset unprocessed section levels.
1664
1661
  Title.section_numbers[l] = 0
1665
1662
  return number
1666
- getnumber = staticmethod(getnumber)
1667
1663
 
1668
1664
 
1669
1665
  class Section:
@@ -1672,16 +1668,17 @@ class Section:
1672
1668
  ids = [] # List of already used ids.
1673
1669
  def __init__(self):
1674
1670
  raise AssertionError,'no class instances allowed'
1671
+ @staticmethod
1675
1672
  def savetag(level,etag):
1676
1673
  """Save section end."""
1677
1674
  Section.endtags.append((level,etag))
1678
- savetag = staticmethod(savetag)
1675
+ @staticmethod
1679
1676
  def setlevel(level):
1680
1677
  """Set document level and write open section close tags up to level."""
1681
1678
  while Section.endtags and Section.endtags[-1][0] >= level:
1682
1679
  writer.write(Section.endtags.pop()[1])
1683
1680
  document.level = level
1684
- setlevel = staticmethod(setlevel)
1681
+ @staticmethod
1685
1682
  def gen_id(title):
1686
1683
  """
1687
1684
  The normalized value of the id attribute is an NCName according to
@@ -1708,7 +1705,7 @@ class Section:
1708
1705
  else:
1709
1706
  ident = base_ident
1710
1707
  i += 1
1711
- gen_id = staticmethod(gen_id)
1708
+ @staticmethod
1712
1709
  def translate():
1713
1710
  assert Lex.next() is Title
1714
1711
  prev_sectname = Title.sectname
@@ -1743,17 +1740,13 @@ class Section:
1743
1740
  Section.savetag(Title.level,etag)
1744
1741
  writer.write(stag)
1745
1742
  Section.translate_body()
1746
- translate = staticmethod(translate)
1743
+ @staticmethod
1747
1744
  def translate_body(terminator=Title):
1748
1745
  isempty = True
1749
1746
  next = Lex.next()
1750
1747
  while next and next is not terminator:
1751
1748
  if next is Title and isinstance(terminator,DelimitedBlock):
1752
1749
  error('title not permitted in sidebar body')
1753
- if document.backend == 'linuxdoc' \
1754
- and document.level == 0 \
1755
- and not isinstance(next,Paragraph):
1756
- warning('only paragraphs are permitted in linuxdoc synopsis')
1757
1750
  next.translate()
1758
1751
  next = Lex.next()
1759
1752
  isempty = False
@@ -1764,7 +1757,6 @@ class Section:
1764
1757
  if isempty:
1765
1758
  if document.backend == 'docbook' and Title.sectname != 'sect-index':
1766
1759
  error('empty section is not valid')
1767
- translate_body = staticmethod(translate_body)
1768
1760
 
1769
1761
  class AbstractBlock:
1770
1762
  def __init__(self):
@@ -1930,7 +1922,7 @@ class AbstractBlock:
1930
1922
  if self.style:
1931
1923
  if not is_name(self.style):
1932
1924
  raise EAsciiDoc, 'illegal style name: %s' % self.style
1933
- if not self.styles.has_key(self.style):
1925
+ if not self.style in self.styles:
1934
1926
  if not isinstance(self,List): # Lists don't have templates.
1935
1927
  warning('[%s] \'%s\' style not in %s' % (
1936
1928
  self.name,self.style,self.styles.keys()))
@@ -1938,7 +1930,7 @@ class AbstractBlock:
1938
1930
  all_styles_have_template = True
1939
1931
  for k,v in self.styles.items():
1940
1932
  t = v.get('template')
1941
- if t and not config.sections.has_key(t):
1933
+ if t and not t in config.sections:
1942
1934
  warning('[%s] missing template section' % t)
1943
1935
  if not t:
1944
1936
  all_styles_have_template = False
@@ -1946,7 +1938,7 @@ class AbstractBlock:
1946
1938
  # styles have templates.
1947
1939
  if self.is_conf_entry('template') and not 'skip' in self.options:
1948
1940
  if self.template:
1949
- if not config.sections.has_key(self.template):
1941
+ if not self.template in config.sections:
1950
1942
  warning('[%s] missing template section' % self.template)
1951
1943
  elif not all_styles_have_template:
1952
1944
  if not isinstance(self,List): # Lists don't have templates.
@@ -2003,6 +1995,9 @@ class AbstractBlock:
2003
1995
 
2004
1996
  params = list(self.PARAM_NAMES) + params
2005
1997
  self.attributes = {}
1998
+ if self.style:
1999
+ # If a default style is defined make it available in the template.
2000
+ self.attributes['style'] = self.style
2006
2001
  self.attributes.update(attrs)
2007
2002
  # Calculate dynamic block parameters.
2008
2003
  # Start with configuration file defaults.
@@ -2020,19 +2015,19 @@ class AbstractBlock:
2020
2015
  if style:
2021
2016
  if not is_name(style):
2022
2017
  raise EAsciiDoc, 'illegal style name: %s' % style
2023
- if self.styles.has_key(style):
2018
+ if style in self.styles:
2024
2019
  self.attributes['style'] = style
2025
2020
  for k,v in self.styles[style].items():
2026
2021
  if k == 'posattrs':
2027
2022
  posattrs = v
2028
2023
  elif k in params:
2029
2024
  self.parameters[k] = v
2030
- elif not self.attributes.has_key(k):
2025
+ elif not k in self.attributes:
2031
2026
  # Style attributes don't take precedence over explicit.
2032
2027
  self.attributes[k] = v
2033
2028
  # Set named positional attributes.
2034
2029
  for i,v in enumerate(posattrs):
2035
- if self.attributes.has_key(str(i+1)):
2030
+ if str(i+1) in self.attributes:
2036
2031
  self.attributes[v] = self.attributes[str(i+1)]
2037
2032
  # Override config and style attributes with attribute list attributes.
2038
2033
  self.update_parameters(attrs)
@@ -2102,8 +2097,8 @@ class Paragraph(AbstractBlock):
2102
2097
  return result
2103
2098
  def translate(self):
2104
2099
  AbstractBlock.translate(self)
2105
- attrs = {}
2106
- attrs.update(self.mo.groupdict())
2100
+ attrs = self.mo.groupdict().copy()
2101
+ if 'text' in attrs: del attrs['text']
2107
2102
  BlockTitle.consume(attrs)
2108
2103
  AttributeList.consume(attrs)
2109
2104
  self.merge_attributes(attrs)
@@ -2153,14 +2148,15 @@ class List(AbstractBlock):
2153
2148
  self.PARAM_NAMES += ('tags',)
2154
2149
  # tabledef conf file parameters.
2155
2150
  self.type=None
2156
- self.tags=None # Name of listtags-<tags> conf section.
2151
+ self.tags=None # Name of listtags-<tags> conf section.
2157
2152
  # Calculated parameters.
2158
2153
  self.tag=None # Current tags AttrDict.
2159
2154
  self.label=None # List item label (labeled lists).
2160
2155
  self.text=None # Text in first line of list item.
2161
2156
  self.index=None # Matched delimiter 'index' group (numbered lists).
2162
- self.type=None # List type.
2157
+ self.type=None # List type ('numbered','bulleted','labeled').
2163
2158
  self.listindex=None # Current list index (1..)
2159
+ self.number_style=None # Numbered list number style ('arabic'..)
2164
2160
  def load(self,name,entries):
2165
2161
  AbstractBlock.load(self,name,entries)
2166
2162
  def dump(self):
@@ -2202,9 +2198,6 @@ class List(AbstractBlock):
2202
2198
  def iscontinued(self):
2203
2199
  if reader.read_next() == '+':
2204
2200
  reader.read() # Discard.
2205
- # Allow attribute list to precede continued list item element.
2206
- while Lex.next() is AttributeList:
2207
- Lex.next().translate()
2208
2201
  return True
2209
2202
  else:
2210
2203
  return False
@@ -2233,6 +2226,7 @@ class List(AbstractBlock):
2233
2226
  lists.delimiter + r'|^\+$|^$|' + blocks.delimiter
2234
2227
  + r'|' + tables.delimiter
2235
2228
  + r'|' + tables_OLD.delimiter
2229
+ + r'|' + AttributeList.pattern
2236
2230
  )
2237
2231
  if self.text is not None:
2238
2232
  text = [self.text] + list(text)
@@ -2240,6 +2234,9 @@ class List(AbstractBlock):
2240
2234
  writer.write_tag(self.tag.text, text, self.presubs, self.attributes)
2241
2235
  continued = self.iscontinued()
2242
2236
  while True:
2237
+ # Allow attribute list to precede continued list item element.
2238
+ while Lex.next() is AttributeList:
2239
+ Lex.next().translate()
2243
2240
  next = Lex.next()
2244
2241
  if next in lists.open:
2245
2242
  break
@@ -2267,11 +2264,16 @@ class List(AbstractBlock):
2267
2264
  lists.delimiter + r'|^$|' + blocks.delimiter
2268
2265
  + r'|' + tables.delimiter
2269
2266
  + r'|' + tables_OLD.delimiter
2267
+ + r'|' + AttributeList.pattern
2270
2268
  )
2271
2269
  if self.text is not None:
2272
2270
  text = [self.text] + list(text)
2273
- writer.write_tag(self.tag.text, text, self.presubs, self.attributes)
2271
+ if text:
2272
+ writer.write_tag(self.tag.text, text, self.presubs, self.attributes)
2274
2273
  while True:
2274
+ # Allow attribute list to precede continued list item element.
2275
+ while Lex.next() is AttributeList:
2276
+ Lex.next().translate()
2275
2277
  next = Lex.next()
2276
2278
  if next in lists.open:
2277
2279
  break
@@ -2288,21 +2290,63 @@ class List(AbstractBlock):
2288
2290
  else:
2289
2291
  break
2290
2292
  writer.write(itemtag[1])
2293
+
2294
+ @staticmethod
2295
+ def parse_index(index):
2296
+ """Parse the numbered list item index and return a (style,ordinal)
2297
+ tuple. style in ('arabic'...); ordinal in (1...).
2298
+ NOTE: 'i' and 'I' return (1,'lowerroman') and (1,'upperroman')."""
2299
+ def roman_to_int(roman):
2300
+ roman = roman.lower()
2301
+ digits = {'i':1,'v':5,'x':10}
2302
+ result = 0
2303
+ for i in range(len(roman)):
2304
+ digit = digits[roman[i]]
2305
+ # If next digit is larger this digit is negative.
2306
+ if i+1 < len(roman) and digits[roman[i+1]] > digit:
2307
+ result -= digit
2308
+ else:
2309
+ result += digit
2310
+ return result
2311
+ if re.match(r'^\d+$', index):
2312
+ style = 'arabic'
2313
+ ordinal = int(index)
2314
+ elif re.match(r'^[ivx]+$', index):
2315
+ style = 'lowerroman'
2316
+ ordinal = roman_to_int(index)
2317
+ elif re.match(r'^[IVX]+$', index):
2318
+ style = 'upperroman'
2319
+ ordinal = roman_to_int(index)
2320
+ elif re.match(r'^[a-z]$', index):
2321
+ style = 'loweralpha'
2322
+ ordinal = ord(index) - ord('a') + 1
2323
+ elif re.match(r'^[A-Z]$', index):
2324
+ style = 'upperalpha'
2325
+ ordinal = ord(index) - ord('A') + 1
2326
+ else:
2327
+ style = None
2328
+ ordinal = None
2329
+ return (style,ordinal)
2330
+
2291
2331
  def check_index(self):
2292
- """ Check calculated listindex (1,2,...) against the item index in the
2293
- document (self.index)."""
2332
+ """ Check calculated listindex (1,2,...) against the item number in the
2333
+ document (self.index) and check the number style is the same as
2334
+ the first item (self.number_style)."""
2294
2335
  assert self.type in ('numbered','callout')
2295
2336
  if self.index:
2296
- matched = False
2297
- if re.match(r'\d+', self.index):
2298
- i = int(self.index)
2299
- matched = True
2300
- elif re.match(r'[a-z]', self.index):
2301
- i = ord(self.index) - ord('a') + 1
2302
- matched = True
2303
- if matched and i != self.listindex:
2304
- print 'type: ',self.type,': expected ',self.listindex,' got ',i
2305
- warning('list item %s out of sequence' % self.index)
2337
+ style,ordinal = self.parse_index(self.index)
2338
+ if style and self.number_style:
2339
+ if (self.index in 'ivx' and self.number_style == 'loweralpha' or
2340
+ self.index in 'IVX' and self.number_style == 'upperalpha'):
2341
+ # Sidestep possible i,v,x,I,V,X ambiguity.
2342
+ return
2343
+ if style != self.number_style:
2344
+ warning('list item style: expected %s got %s' %
2345
+ (self.number_style,style), offset=1)
2346
+ if ordinal != self.listindex:
2347
+ warning('list item index: expected %s got %s' %
2348
+ (self.listindex,ordinal), offset=1)
2349
+
2306
2350
  def check_tags(self):
2307
2351
  """ Check that all necessary tags are present. """
2308
2352
  tags = set(Lists.TAGS)
@@ -2316,10 +2360,17 @@ class List(AbstractBlock):
2316
2360
  if self.short_name() in ('bibliography','glossary','qanda'):
2317
2361
  deprecated('old %s list syntax' % self.short_name())
2318
2362
  lists.open.append(self)
2319
- attrs = {}
2320
- attrs.update(self.mo.groupdict())
2363
+ attrs = self.mo.groupdict().copy()
2364
+ for k in ('label','text','index'):
2365
+ if k in attrs: del attrs[k]
2366
+ if self.index:
2367
+ # Set the numbering style from first list item.
2368
+ style = self.parse_index(self.index)[0]
2369
+ if style:
2370
+ attrs['style'] = style
2321
2371
  BlockTitle.consume(attrs)
2322
2372
  AttributeList.consume(attrs)
2373
+ self.number_style = attrs.get('style')
2323
2374
  self.merge_attributes(attrs,['tags'])
2324
2375
  self.tag = lists.tags[self.parameters.tags]
2325
2376
  self.check_tags()
@@ -2380,7 +2431,7 @@ class Lists(AbstractBlocks):
2380
2431
  mo = re.match(r'^listtags-(?P<name>\w+)$',section)
2381
2432
  if mo:
2382
2433
  name = mo.group('name')
2383
- if self.tags.has_key(name):
2434
+ if name in self.tags:
2384
2435
  d = self.tags[name]
2385
2436
  else:
2386
2437
  d = AttrDict()
@@ -2904,7 +2955,7 @@ class Tables(AbstractBlocks):
2904
2955
  mo = re.match(r'^tabletags-(?P<name>\w+)$',section)
2905
2956
  if mo:
2906
2957
  name = mo.group('name')
2907
- if self.tags.has_key(name):
2958
+ if name in self.tags:
2908
2959
  d = self.tags[name]
2909
2960
  else:
2910
2961
  d = AttrDict()
@@ -2961,15 +3012,15 @@ class Tables(AbstractBlocks):
2961
3012
 
2962
3013
  class Macros:
2963
3014
  # Default system macro syntax.
2964
- SYS_DEFAULT = r'(?u)^(?P<name>\w(\w|-)*?)::(?P<target>\S*?)' + \
2965
- r'(\[(?P<attrlist>.*?)\])$'
3015
+ SYS_RE = r'(?u)^(?P<name>[\\]?\w(\w|-)*?)::(?P<target>\S*?)' + \
3016
+ r'(\[(?P<attrlist>.*?)\])$'
2966
3017
  def __init__(self):
2967
3018
  self.macros = [] # List of Macros.
2968
3019
  self.current = None # The last matched block macro.
2969
3020
  self.passthroughs = []
2970
3021
  # Initialize default system macro.
2971
3022
  m = Macro()
2972
- m.pattern = self.SYS_DEFAULT
3023
+ m.pattern = self.SYS_RE
2973
3024
  m.prefix = '+'
2974
3025
  m.reo = re.compile(m.pattern)
2975
3026
  self.macros.append(m)
@@ -3060,7 +3111,7 @@ class Macro:
3060
3111
  self.name = '' # Conf file macro name (None if implicit).
3061
3112
  self.prefix = '' # '' if inline, '+' if system, '#' if block.
3062
3113
  self.reo = None # Compiled pattern re object.
3063
- self.subslist = None # Default subs for macros passtext group.
3114
+ self.subslist = [] # Default subs for macros passtext group.
3064
3115
  def has_passthrough(self):
3065
3116
  return self.pattern.find(r'(?P<passtext>') >= 0
3066
3117
  def section_name(self,name=None):
@@ -3074,7 +3125,7 @@ class Macro:
3074
3125
  suffix = '-blockmacro'
3075
3126
  else:
3076
3127
  suffix = '-inlinemacro'
3077
- if config.sections.has_key(name+suffix):
3128
+ if name+suffix in config.sections:
3078
3129
  return name+suffix
3079
3130
  else:
3080
3131
  warning('missing macro section: [%s]' % (name+suffix))
@@ -3112,7 +3163,7 @@ class Macro:
3112
3163
  self.reo = re.compile(pattern)
3113
3164
  self.prefix = prefix
3114
3165
  self.name = name
3115
- self.subslist = subslist
3166
+ self.subslist = subslist or []
3116
3167
 
3117
3168
  def subs(self,text):
3118
3169
  def subs_func(mo):
@@ -3129,7 +3180,7 @@ class Macro:
3129
3180
  if self.name:
3130
3181
  name = self.name
3131
3182
  else:
3132
- if not d.has_key('name'):
3183
+ if not 'name' in d:
3133
3184
  warning('missing macro name group: %s' % mo.re.pattern)
3134
3185
  return ''
3135
3186
  name = d['name']
@@ -3142,7 +3193,7 @@ class Macro:
3142
3193
  AttributeList.consume(d)
3143
3194
  BlockTitle.consume(d)
3144
3195
  # Parse macro attributes.
3145
- if d.has_key('attrlist'):
3196
+ if 'attrlist' in d:
3146
3197
  if d['attrlist'] in (None,''):
3147
3198
  del d['attrlist']
3148
3199
  else:
@@ -3160,8 +3211,8 @@ class Macro:
3160
3211
  listindex =int(d['index'])
3161
3212
  d['coid'] = calloutmap.add(listindex)
3162
3213
  # Unescape special characters in LaTeX target file names.
3163
- if document.backend == 'latex' and d.has_key('target') and d['target']:
3164
- if not d.has_key('0'):
3214
+ if document.backend == 'latex' and 'target' in d and d['target']:
3215
+ if not '0' in d:
3165
3216
  d['0'] = d['target']
3166
3217
  d['target']= config.subs_specialchars_reverse(d['target'])
3167
3218
  # BUG: We've already done attribute substitution on the macro which
@@ -3217,7 +3268,7 @@ class Macro:
3217
3268
  if mo.group()[0] == '\\':
3218
3269
  return mo.group()
3219
3270
  d = mo.groupdict()
3220
- if not d.has_key('passtext'):
3271
+ if not 'passtext' in d:
3221
3272
  warning('passthrough macro %s: missing passtext group' %
3222
3273
  d.get('name',''))
3223
3274
  return mo.group()
@@ -3261,17 +3312,17 @@ class CalloutMap:
3261
3312
  # Add next callout index to listindex map entry. Return the callout id.
3262
3313
  self.calloutindex += 1
3263
3314
  # Append the coindex to a list in the comap dictionary.
3264
- if not self.comap.has_key(listindex):
3315
+ if not listindex in self.comap:
3265
3316
  self.comap[listindex] = [self.calloutindex]
3266
3317
  else:
3267
3318
  self.comap[listindex].append(self.calloutindex)
3268
3319
  return self.calloutid(self.listnumber, self.calloutindex)
3320
+ @staticmethod
3269
3321
  def calloutid(listnumber,calloutindex):
3270
3322
  return 'CO%d-%d' % (listnumber,calloutindex)
3271
- calloutid = staticmethod(calloutid)
3272
3323
  def calloutids(self,listindex):
3273
3324
  # Retieve list of callout indexes that refer to listindex.
3274
- if self.comap.has_key(listindex):
3325
+ if listindex in self.comap:
3275
3326
  result = ''
3276
3327
  for coindex in self.comap[listindex]:
3277
3328
  result += ' ' + self.calloutid(self.listnumber,coindex)
@@ -3385,13 +3436,13 @@ class Reader1:
3385
3436
  assign(parent,self)
3386
3437
  self.parent = parent
3387
3438
  # Set attributes in child.
3388
- if attrs.has_key('tabsize'):
3439
+ if 'tabsize' in attrs:
3389
3440
  self.tabsize = int(validate(attrs['tabsize'],
3390
3441
  'int($)>=0',
3391
3442
  'illegal include macro tabsize argument'))
3392
3443
  else:
3393
3444
  self.tabsize = config.tabsize
3394
- if attrs.has_key('depth'):
3445
+ if 'depth' in attrs:
3395
3446
  attrs['depth'] = int(validate(attrs['depth'],
3396
3447
  'int($)>=1',
3397
3448
  'illegal include macro depth argument'))
@@ -3498,6 +3549,10 @@ class Reader(Reader1):
3498
3549
  if s is not None:
3499
3550
  self.cursor[2] = s # So we don't re-evaluate.
3500
3551
  result = s
3552
+ if result:
3553
+ # Unescape escaped system macros.
3554
+ if macros.match('+',r'\\eval|\\sys|\\sys2|\\ifdef|\\ifndef|\\endif|\\include|\\include1',result):
3555
+ result = result[1:]
3501
3556
  return result
3502
3557
  def eof(self):
3503
3558
  return self.read_next() is None
@@ -3649,7 +3704,7 @@ def _subs_specialwords(mo):
3649
3704
  Config.subs_specialwords()."""
3650
3705
  word = mo.re.pattern # The special word.
3651
3706
  template = config.specialwords[word] # The corresponding markup template.
3652
- if not config.sections.has_key(template):
3707
+ if not template in config.sections:
3653
3708
  raise EAsciiDoc,'missing special word template [%s]' % template
3654
3709
  if mo.group()[0] == '\\':
3655
3710
  return mo.group()[1:] # Return escaped word.
@@ -3737,7 +3792,7 @@ class Config:
3737
3792
  found = reo.findall(s)
3738
3793
  if found:
3739
3794
  if section: # Store previous section.
3740
- if sections.has_key(section) \
3795
+ if section in sections \
3741
3796
  and self.entries_section(section):
3742
3797
  if ''.join(contents):
3743
3798
  # Merge entries.
@@ -3751,7 +3806,7 @@ class Config:
3751
3806
  else:
3752
3807
  contents.append(s)
3753
3808
  if section and contents: # Store last section.
3754
- if sections.has_key(section) \
3809
+ if section in sections \
3755
3810
  and self.entries_section(section):
3756
3811
  if ''.join(contents):
3757
3812
  # Merge entries.
@@ -3816,17 +3871,17 @@ class Config:
3816
3871
  if lang:
3817
3872
  conf = 'lang-' + lang + '.conf'
3818
3873
  self.load_file(conf,dir)
3819
- # Load ./filters/*.conf files if they exist.
3820
- filters = os.path.join(dir,'filters')
3821
- if os.path.isdir(filters):
3822
- for f in os.listdir(filters):
3874
+ # Load filter .conf files.
3875
+ filtersdir = os.path.join(dir,'filters')
3876
+ for dirpath,dirnames,filenames in os.walk(filtersdir):
3877
+ for f in filenames:
3823
3878
  if re.match(r'^.+\.conf$',f):
3824
- self.load_file(f,filters)
3879
+ self.load_file(f,dirpath)
3825
3880
 
3826
3881
  def load_miscellaneous(self,d):
3827
3882
  """Set miscellaneous configuration entries from dictionary 'd'."""
3828
3883
  def set_misc(name,rule='True',intval=False):
3829
- if d.has_key(name):
3884
+ if name in d:
3830
3885
  errmsg = 'illegal [miscellaneous] %s entry' % name
3831
3886
  if intval:
3832
3887
  setattr(self, name, int(validate(d[name],rule,errmsg)))
@@ -3837,14 +3892,14 @@ class Config:
3837
3892
  set_misc('pagewidth','int($)>0',intval=True)
3838
3893
  set_misc('pageunits')
3839
3894
  set_misc('outfilesuffix')
3840
- if d.has_key('newline'):
3895
+ if 'newline' in d:
3841
3896
  # Convert escape sequences to their character values.
3842
3897
  self.newline = eval('"'+d['newline']+'"')
3843
- if d.has_key('subsnormal'):
3898
+ if 'subsnormal' in d:
3844
3899
  self.subsnormal = parse_options(d['subsnormal'],SUBS_OPTIONS,
3845
3900
  'illegal [%s] %s: %s' %
3846
3901
  ('miscellaneous','subsnormal',d['subsnormal']))
3847
- if d.has_key('subsverbatim'):
3902
+ if 'subsverbatim' in d:
3848
3903
  self.subsverbatim = parse_options(d['subsverbatim'],SUBS_OPTIONS,
3849
3904
  'illegal [%s] %s: %s' %
3850
3905
  ('miscellaneous','subsverbatim',d['subsverbatim']))
@@ -3864,7 +3919,7 @@ class Config:
3864
3919
  for macro in self.specialwords.values():
3865
3920
  if not is_name(macro):
3866
3921
  raise EAsciiDoc,'illegal special word name: %s' % macro
3867
- if not self.sections.has_key(macro):
3922
+ if not macro in self.sections:
3868
3923
  warning('missing special word macro: [%s]' % macro)
3869
3924
  # Check all text quotes have a corresponding tag.
3870
3925
  for q in self.quotes.keys():
@@ -3874,11 +3929,11 @@ class Config:
3874
3929
  else:
3875
3930
  if tag[0] == '#':
3876
3931
  tag = tag[1:]
3877
- if not self.tags.has_key(tag):
3932
+ if not tag in self.tags:
3878
3933
  warning('[quotes] %s missing tag definition: %s' % (q,tag))
3879
3934
  # Check all specialsections section names exist.
3880
3935
  for k,v in self.specialsections.items():
3881
- if not self.sections.has_key(v):
3936
+ if not v in self.sections:
3882
3937
  warning('[%s] missing specialsections section' % v)
3883
3938
  paragraphs.validate()
3884
3939
  lists.validate()
@@ -3920,7 +3975,7 @@ class Config:
3920
3975
  dump_section('specialcharacters',self.specialchars)
3921
3976
  d = {}
3922
3977
  for k,v in self.specialwords.items():
3923
- if d.has_key(v):
3978
+ if v in d:
3924
3979
  d[v] = '%s "%s"' % (d[v],k) # Append word list.
3925
3980
  else:
3926
3981
  d[v] = '"%s"' % k
@@ -3950,7 +4005,7 @@ class Config:
3950
4005
  """Section attribute substitution using attributes from
3951
4006
  document.attributes and 'd'. Lines containing undefinded
3952
4007
  attributes are deleted."""
3953
- if self.sections.has_key(section):
4008
+ if section in self.sections:
3954
4009
  return subs_attrs(self.sections[section],d)
3955
4010
  else:
3956
4011
  warning('missing [%s] section' % section)
@@ -3962,7 +4017,7 @@ class Config:
3962
4017
  parse_entries(self.sections.get('tags',()),d)
3963
4018
  for k,v in d.items():
3964
4019
  if v is None:
3965
- if self.tags.has_key(k):
4020
+ if k in self.tags:
3966
4021
  del self.tags[k]
3967
4022
  elif v == '':
3968
4023
  self.tags[k] = (None,None)
@@ -3986,7 +4041,7 @@ class Config:
3986
4041
  # split_tag() and would call subs_tag(). self.tags dictionary values
3987
4042
  # would be strings not tuples.
3988
4043
 
3989
- if not self.tags.has_key(name):
4044
+ if not name in self.tags:
3990
4045
  raise EAsciiDoc, 'missing tag: %s' % name
3991
4046
  stag,etag = self.tags[name]
3992
4047
  if d is not None:
@@ -4011,7 +4066,7 @@ class Config:
4011
4066
  raise EAsciiDoc,'[specialsections] entry ' \
4012
4067
  'is not a valid regular expression: %s' % pat
4013
4068
  if sectname is None:
4014
- if self.specialsections.has_key(pat):
4069
+ if pat in self.specialsections:
4015
4070
  del self.specialsections[pat]
4016
4071
  else:
4017
4072
  self.specialsections[pat] = sectname
@@ -4025,18 +4080,18 @@ class Config:
4025
4080
  raise EAsciiDoc,'[%s] entry in %s is not a valid' \
4026
4081
  ' regular expression: %s' % (sect,self.fname,pat)
4027
4082
 
4083
+ @staticmethod
4028
4084
  def set_replacement(pat, rep, replacements):
4029
4085
  """Add pattern and replacement to replacements dictionary."""
4030
4086
  pat = strip_quotes(pat)
4031
4087
  if not is_regexp(pat):
4032
4088
  return False
4033
4089
  if rep is None:
4034
- if replacements.has_key(pat):
4090
+ if pat in replacements:
4035
4091
  del replacements[pat]
4036
4092
  else:
4037
4093
  replacements[pat] = strip_quotes(rep)
4038
4094
  return True
4039
- set_replacement = staticmethod(set_replacement)
4040
4095
 
4041
4096
  def subs_replacements(self,s,sect='replacements'):
4042
4097
  """Substitute patterns from self.replacements in 's'."""
@@ -4104,7 +4159,7 @@ class Config:
4104
4159
  mo = macros.match('+',r'template',line)
4105
4160
  if mo:
4106
4161
  s = mo.group('attrlist')
4107
- if self.sections.has_key(s):
4162
+ if s in self.sections:
4108
4163
  result += self.sections[s]
4109
4164
  else:
4110
4165
  warning('missing [%s] section' % s)
@@ -4121,7 +4176,7 @@ class Config:
4121
4176
  attributes plus 'd' attributes. Return tuple (stag,etag) containing
4122
4177
  pre and post | placeholder tags."""
4123
4178
  assert section is not None
4124
- if self.sections.has_key(section):
4179
+ if section in self.sections:
4125
4180
  body = self.sections[section]
4126
4181
  else:
4127
4182
  warning('missing [%s] section' % section)
@@ -4689,9 +4744,6 @@ def asciidoc(backend, doctype, confiles, infile, outfile, options):
4689
4744
  try:
4690
4745
  if doctype not in ('article','manpage','book'):
4691
4746
  raise EAsciiDoc,'illegal document type'
4692
- if backend == 'linuxdoc' and doctype != 'article':
4693
- raise EAsciiDoc,'%s %s documents are not supported' \
4694
- % (backend,doctype)
4695
4747
  document.backend = backend
4696
4748
  if not os.path.exists(os.path.join(APP_DIR, backend+'.conf')) and not \
4697
4749
  os.path.exists(os.path.join(CONF_DIR, backend+'.conf')):
@@ -4820,9 +4872,10 @@ def main():
4820
4872
  print_stderr('FAILED: Python 2.3 or better required.')
4821
4873
  sys.exit(1)
4822
4874
  # Locate the executable and configuration files directory.
4823
- global APP_FILE,APP_DIR,USER_DIR
4875
+ global APP_FILE,APP_DIR,CONF_DIR,USER_DIR
4824
4876
  APP_FILE = os.path.realpath(sys.argv[0])
4825
4877
  APP_DIR = os.path.dirname(APP_FILE)
4878
+ CONF_DIR = APP_DIR
4826
4879
  USER_DIR = os.environ.get('HOME')
4827
4880
  if USER_DIR is not None:
4828
4881
  USER_DIR = os.path.join(USER_DIR,'.asciidoc')