FooBarWidget-mizuho 0.9.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
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')