bixbite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (194) hide show
  1. data/LICENSE +20 -0
  2. data/README.markdown +49 -0
  3. data/VERSION +1 -0
  4. data/bin/bixbite +73 -0
  5. data/lib/bixbite.rb +13 -0
  6. data/lib/bixbite/command.rb +14 -0
  7. data/lib/bixbite/create.rb +76 -0
  8. data/template/Rakefile +25 -0
  9. data/template/assets/bixbite/Rakefile.rb +297 -0
  10. data/template/assets/naturaldocs/NaturalDocs/Config/Languages.txt +286 -0
  11. data/template/assets/naturaldocs/NaturalDocs/Config/Topics.txt +382 -0
  12. data/template/assets/naturaldocs/NaturalDocs/Help/customizinglanguages.html +52 -0
  13. data/template/assets/naturaldocs/NaturalDocs/Help/customizingtopics.html +74 -0
  14. data/template/assets/naturaldocs/NaturalDocs/Help/documenting.html +58 -0
  15. data/template/assets/naturaldocs/NaturalDocs/Help/documenting/reference.html +146 -0
  16. data/template/assets/naturaldocs/NaturalDocs/Help/documenting/walkthrough.html +180 -0
  17. data/template/assets/naturaldocs/NaturalDocs/Help/example/Default.css +528 -0
  18. data/template/assets/naturaldocs/NaturalDocs/Help/example/NaturalDocs.js +204 -0
  19. data/template/assets/naturaldocs/NaturalDocs/Help/examples.css +90 -0
  20. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/background.png +0 -0
  21. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/leftside.png +0 -0
  22. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/logo.png +0 -0
  23. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overbody.png +0 -0
  24. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overbodybg.png +0 -0
  25. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overleftmargin.png +0 -0
  26. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overmenu.png +0 -0
  27. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/overmenubg.png +0 -0
  28. data/template/assets/naturaldocs/NaturalDocs/Help/images/header/rightside.png +0 -0
  29. data/template/assets/naturaldocs/NaturalDocs/Help/images/logo.gif +0 -0
  30. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/about.png +0 -0
  31. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/background.png +0 -0
  32. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/bottomleft.png +0 -0
  33. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/bottomright.png +0 -0
  34. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/community.png +0 -0
  35. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/customizing.png +0 -0
  36. data/template/assets/naturaldocs/NaturalDocs/Help/images/menu/using.png +0 -0
  37. data/template/assets/naturaldocs/NaturalDocs/Help/index.html +9 -0
  38. data/template/assets/naturaldocs/NaturalDocs/Help/javascript/BrowserStyles.js +77 -0
  39. data/template/assets/naturaldocs/NaturalDocs/Help/javascript/PNGHandling.js +72 -0
  40. data/template/assets/naturaldocs/NaturalDocs/Help/keywords.html +38 -0
  41. data/template/assets/naturaldocs/NaturalDocs/Help/languages.html +32 -0
  42. data/template/assets/naturaldocs/NaturalDocs/Help/menu.html +79 -0
  43. data/template/assets/naturaldocs/NaturalDocs/Help/output.html +84 -0
  44. data/template/assets/naturaldocs/NaturalDocs/Help/running.html +40 -0
  45. data/template/assets/naturaldocs/NaturalDocs/Help/styles.css +290 -0
  46. data/template/assets/naturaldocs/NaturalDocs/Help/styles.html +52 -0
  47. data/template/assets/naturaldocs/NaturalDocs/Help/troubleshooting.html +18 -0
  48. data/template/assets/naturaldocs/NaturalDocs/Info/CSSGuide.txt +947 -0
  49. data/template/assets/naturaldocs/NaturalDocs/Info/File Parsing.txt +83 -0
  50. data/template/assets/naturaldocs/NaturalDocs/Info/HTMLTestCases.pm +269 -0
  51. data/template/assets/naturaldocs/NaturalDocs/Info/Languages.txt +107 -0
  52. data/template/assets/naturaldocs/NaturalDocs/Info/NDMarkup.txt +91 -0
  53. data/template/assets/naturaldocs/NaturalDocs/Info/Symbol Management.txt +59 -0
  54. data/template/assets/naturaldocs/NaturalDocs/Info/images/Logo.png +0 -0
  55. data/template/assets/naturaldocs/NaturalDocs/JavaScript/NaturalDocs.js +836 -0
  56. data/template/assets/naturaldocs/NaturalDocs/License-GPL.txt +341 -0
  57. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/BinaryFile.pm +294 -0
  58. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder.pm +280 -0
  59. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/Base.pm +348 -0
  60. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/FramedHTML.pm +345 -0
  61. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/HTML.pm +398 -0
  62. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Builder/HTMLBase.pm +3693 -0
  63. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ClassHierarchy.pm +860 -0
  64. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ClassHierarchy/Class.pm +412 -0
  65. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ClassHierarchy/File.pm +157 -0
  66. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ConfigFile.pm +497 -0
  67. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Constants.pm +165 -0
  68. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/DefineMembers.pm +100 -0
  69. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Error.pm +305 -0
  70. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/File.pm +540 -0
  71. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ImageReferenceTable.pm +383 -0
  72. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ImageReferenceTable/Reference.pm +44 -0
  73. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ImageReferenceTable/String.pm +110 -0
  74. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages.pm +1475 -0
  75. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/ActionScript.pm +1473 -0
  76. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Ada.pm +38 -0
  77. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Advanced.pm +828 -0
  78. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Advanced/Scope.pm +95 -0
  79. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Advanced/ScopeChange.pm +70 -0
  80. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Base.pm +832 -0
  81. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/CSharp.pm +1484 -0
  82. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/PLSQL.pm +319 -0
  83. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Pascal.pm +143 -0
  84. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Perl.pm +1370 -0
  85. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Prototype.pm +92 -0
  86. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Prototype/Parameter.pm +87 -0
  87. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Simple.pm +503 -0
  88. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Languages/Tcl.pm +219 -0
  89. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Menu.pm +3406 -0
  90. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Menu/Entry.pm +201 -0
  91. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/NDMarkup.pm +76 -0
  92. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser.pm +1331 -0
  93. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser/JavaDoc.pm +464 -0
  94. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser/Native.pm +1060 -0
  95. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Parser/ParsedTopic.pm +253 -0
  96. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Project.pm +1402 -0
  97. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Project/ImageFile.pm +160 -0
  98. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Project/SourceFile.pm +113 -0
  99. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/ReferenceString.pm +334 -0
  100. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Settings.pm +1418 -0
  101. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Settings/BuildTarget.pm +66 -0
  102. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB.pm +678 -0
  103. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/Extension.pm +84 -0
  104. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/File.pm +129 -0
  105. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/Item.pm +201 -0
  106. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/ItemDefinition.pm +45 -0
  107. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SourceDB/WatchedFileDefinitions.pm +159 -0
  108. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/StatusMessage.pm +102 -0
  109. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolString.pm +212 -0
  110. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable.pm +1984 -0
  111. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/File.pm +186 -0
  112. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/IndexElement.pm +522 -0
  113. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/Reference.pm +273 -0
  114. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/ReferenceTarget.pm +97 -0
  115. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/Symbol.pm +428 -0
  116. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/SymbolTable/SymbolDefinition.pm +96 -0
  117. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Topics.pm +1319 -0
  118. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Topics/Type.pm +151 -0
  119. data/template/assets/naturaldocs/NaturalDocs/Modules/NaturalDocs/Version.pm +384 -0
  120. data/template/assets/naturaldocs/NaturalDocs/NaturalDocs +400 -0
  121. data/template/assets/naturaldocs/NaturalDocs/NaturalDocs.bat +17 -0
  122. data/template/assets/naturaldocs/NaturalDocs/Styles/Default.css +767 -0
  123. data/template/assets/naturaldocs/NaturalDocs/Styles/Roman.css +765 -0
  124. data/template/assets/naturaldocs/NaturalDocs/Styles/Small.css +763 -0
  125. data/template/assets/utilities/pngout +0 -0
  126. data/template/deploy/public_html/.htaccess +0 -0
  127. data/template/documentation/js/.htaccess +0 -0
  128. data/template/src/html/.htaccess +76 -0
  129. data/template/src/html/css/cmn/global.css +96 -0
  130. data/template/src/html/css/cmn/ie.css +15 -0
  131. data/template/src/html/css/cmn/ie6.css +15 -0
  132. data/template/src/html/images/cmn/.htaccess +0 -0
  133. data/template/src/html/images/tmp/.htaccess +0 -0
  134. data/template/src/html/includes/debug.inc +5 -0
  135. data/template/src/html/includes/footer.inc +52 -0
  136. data/template/src/html/includes/header.inc +61 -0
  137. data/template/src/html/includes/html.inc +3 -0
  138. data/template/src/html/includes/namespace.inc +19 -0
  139. data/template/src/html/includes/page.inc +151 -0
  140. data/template/src/html/index.html +35 -0
  141. data/template/src/html/js/cmn/bootstrap.js +74 -0
  142. data/template/src/html/js/cmn/global.js +142 -0
  143. data/template/src/html/js/cmn/lib/LAB.js +348 -0
  144. data/template/src/html/min/.htaccess +4 -0
  145. data/template/src/html/min/MinifyCLI.php +19 -0
  146. data/template/src/html/min/README.txt +132 -0
  147. data/template/src/html/min/builder/_index.js +242 -0
  148. data/template/src/html/min/builder/bm.js +36 -0
  149. data/template/src/html/min/builder/index.php +182 -0
  150. data/template/src/html/min/builder/ocCheck.php +36 -0
  151. data/template/src/html/min/builder/rewriteTest.js +1 -0
  152. data/template/src/html/min/config.php +187 -0
  153. data/template/src/html/min/groupsConfig.php +34 -0
  154. data/template/src/html/min/index.php +66 -0
  155. data/template/src/html/min/lib/FirePHP.php +1370 -0
  156. data/template/src/html/min/lib/HTTP/ConditionalGet.php +348 -0
  157. data/template/src/html/min/lib/HTTP/Encoder.php +326 -0
  158. data/template/src/html/min/lib/JSMin.php +314 -0
  159. data/template/src/html/min/lib/JSMinPlus.php +1872 -0
  160. data/template/src/html/min/lib/Minify.php +532 -0
  161. data/template/src/html/min/lib/Minify/Build.php +103 -0
  162. data/template/src/html/min/lib/Minify/CSS.php +83 -0
  163. data/template/src/html/min/lib/Minify/CSS/Compressor.php +250 -0
  164. data/template/src/html/min/lib/Minify/CSS/UriRewriter.php +270 -0
  165. data/template/src/html/min/lib/Minify/Cache/APC.php +130 -0
  166. data/template/src/html/min/lib/Minify/Cache/File.php +125 -0
  167. data/template/src/html/min/lib/Minify/Cache/Memcache.php +137 -0
  168. data/template/src/html/min/lib/Minify/ClosureCompiler.php +85 -0
  169. data/template/src/html/min/lib/Minify/CommentPreserver.php +90 -0
  170. data/template/src/html/min/lib/Minify/Controller/Base.php +202 -0
  171. data/template/src/html/min/lib/Minify/Controller/Files.php +78 -0
  172. data/template/src/html/min/lib/Minify/Controller/Groups.php +94 -0
  173. data/template/src/html/min/lib/Minify/Controller/MinApp.php +132 -0
  174. data/template/src/html/min/lib/Minify/Controller/Page.php +82 -0
  175. data/template/src/html/min/lib/Minify/Controller/Version1.php +118 -0
  176. data/template/src/html/min/lib/Minify/HTML.php +245 -0
  177. data/template/src/html/min/lib/Minify/ImportProcessor.php +157 -0
  178. data/template/src/html/min/lib/Minify/Lines.php +131 -0
  179. data/template/src/html/min/lib/Minify/Logger.php +45 -0
  180. data/template/src/html/min/lib/Minify/Packer.php +37 -0
  181. data/template/src/html/min/lib/Minify/Source.php +187 -0
  182. data/template/src/html/min/lib/Minify/YUICompressor.php +139 -0
  183. data/template/src/html/min/lib/Solar/Dir.php +199 -0
  184. data/template/src/html/min/lib/closure-compiler.jar +0 -0
  185. data/template/src/html/min/lib/yuicompressor-2.4.2.jar +0 -0
  186. data/template/src/html/min/utils.php +90 -0
  187. data/template/src/templates/css/template.css +7 -0
  188. data/template/src/templates/js/template.js +72 -0
  189. data/template/src/templates/template.html +18 -0
  190. data/template/src/yaml/config.yml +46 -0
  191. data/template/src/yaml/deploy.yml +35 -0
  192. data/test/bixbite_test.rb +7 -0
  193. data/test/test_helper.rb +10 -0
  194. metadata +278 -0
@@ -0,0 +1,201 @@
1
+ ###############################################################################
2
+ #
3
+ # Package: NaturalDocs::Menu::Entry
4
+ #
5
+ ###############################################################################
6
+ #
7
+ # A class representing an entry in the menu.
8
+ #
9
+ ###############################################################################
10
+
11
+ # This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure
12
+ # Natural Docs is licensed under the GPL
13
+
14
+ use strict;
15
+ use integer;
16
+
17
+ package NaturalDocs::Menu::Entry;
18
+
19
+
20
+ ###############################################################################
21
+ # Group: Implementation
22
+
23
+ #
24
+ # Constants: Members
25
+ #
26
+ # The object is implemented as a blessed arrayref with the indexes below.
27
+ #
28
+ # TYPE - The <MenuEntryType>
29
+ # TITLE - The title of the entry.
30
+ # TARGET - The target of the entry. If the type is <MENU_FILE>, it will be the source <FileName>. If the type is
31
+ # <MENU_LINK>, it will be the URL. If the type is <MENU_GROUP>, it will be an arrayref of
32
+ # <NaturalDocs::Menu::Entry> objects representing the group's content. If the type is <MENU_INDEX>, it will be
33
+ # a <TopicType>.
34
+ # FLAGS - Any <Menu Entry Flags> that apply.
35
+ #
36
+ use constant TYPE => 0;
37
+ use constant TITLE => 1;
38
+ use constant TARGET => 2;
39
+ use constant FLAGS => 3;
40
+ # DEPENDENCY: New() depends on the order of these constants.
41
+
42
+
43
+ ###############################################################################
44
+ # Group: Functions
45
+
46
+ #
47
+ # Function: New
48
+ #
49
+ # Creates and returns a new object.
50
+ #
51
+ # Parameters:
52
+ #
53
+ # type - The <MenuEntryType>.
54
+ # title - The title of the entry.
55
+ # target - The target of the entry, if applicable. If the type is <MENU_FILE>, use the source <FileName>. If the type is
56
+ # <MENU_LINK>, use the URL. If the type is <MENU_INDEX>, use the <TopicType>. Otherwise set it to undef.
57
+ # flags - Any <Menu Entry Flags> that apply.
58
+ #
59
+ sub New #(type, title, target, flags)
60
+ {
61
+ # DEPENDENCY: This gode depends on the order of the constants.
62
+
63
+ my $package = shift;
64
+
65
+ my $object = [ @_ ];
66
+ bless $object, $package;
67
+
68
+ if ($object->[TYPE] == ::MENU_GROUP())
69
+ { $object->[TARGET] = [ ]; };
70
+ if (!defined $object->[FLAGS])
71
+ { $object->[FLAGS] = 0; };
72
+
73
+ return $object;
74
+ };
75
+
76
+
77
+ # Function: Type
78
+ # Returns the <MenuEntryType>.
79
+ sub Type
80
+ { return $_[0]->[TYPE]; };
81
+
82
+ # Function: Title
83
+ # Returns the title of the entry.
84
+ sub Title
85
+ { return $_[0]->[TITLE]; };
86
+
87
+ # Function: SetTitle
88
+ # Replaces the entry's title.
89
+ sub SetTitle #(title)
90
+ { $_[0]->[TITLE] = $_[1]; };
91
+
92
+ #
93
+ # Function: Target
94
+ #
95
+ # Returns the target of the entry, if applicable. If the type is <MENU_FILE>, it returns the source <FileName>. If the type is
96
+ # <MENU_LINK>, it returns the URL. If the type is <MENU_INDEX>, it returns the <TopicType>. Otherwise it returns undef.
97
+ #
98
+ sub Target
99
+ {
100
+ my $self = shift;
101
+
102
+ # Group entries are the only time when target won't be undef when it should be.
103
+ if ($self->Type() == ::MENU_GROUP())
104
+ { return undef; }
105
+ else
106
+ { return $self->[TARGET]; };
107
+ };
108
+
109
+ # Function: SetTarget
110
+ # Replaces the entry's target.
111
+ sub SetTarget #(target)
112
+ { $_[0]->[TARGET] = $_[1]; };
113
+
114
+ # Function: Flags
115
+ # Returns the <Menu Entry Flags>.
116
+ sub Flags
117
+ { return $_[0]->[FLAGS]; };
118
+
119
+ # Function: SetFlags
120
+ # Replaces the <Menu Entry Flags>.
121
+ sub SetFlags #(flags)
122
+ { $_[0]->[FLAGS] = $_[1]; };
123
+
124
+
125
+
126
+ ###############################################################################
127
+ # Group: Group Functions
128
+ #
129
+ # All of these functions assume the type is <MENU_GROUP>. Do *not* call any of these without checking <Type()> first.
130
+
131
+
132
+ #
133
+ # Function: GroupContent
134
+ #
135
+ # Returns an arrayref of <NaturalDocs::Menu::Entry> objects representing the contents of the
136
+ # group, or undef otherwise. This arrayref will always exist for <MENU_GROUP>'s and can be changed.
137
+ #
138
+ sub GroupContent
139
+ {
140
+ return $_[0]->[TARGET];
141
+ };
142
+
143
+
144
+ #
145
+ # Function: GroupIsEmpty
146
+ #
147
+ # If the type is <MENU_GROUP>, returns whether the group is empty.
148
+ #
149
+ sub GroupIsEmpty
150
+ {
151
+ my $self = shift;
152
+ return (scalar @{$self->GroupContent()} > 0);
153
+ };
154
+
155
+
156
+ #
157
+ # Function: PushToGroup
158
+ #
159
+ # Pushes the entry to the end of the group content.
160
+ #
161
+ sub PushToGroup #(entry)
162
+ {
163
+ my ($self, $entry) = @_;
164
+ push @{$self->GroupContent()}, $entry;
165
+ };
166
+
167
+
168
+ #
169
+ # Function: DeleteFromGroup
170
+ #
171
+ # Deletes an entry from the group content by index.
172
+ #
173
+ sub DeleteFromGroup #(index)
174
+ {
175
+ my ($self, $index) = @_;
176
+
177
+ my $groupContent = $self->GroupContent();
178
+
179
+ splice( @$groupContent, $index, 1 );
180
+ };
181
+
182
+
183
+ #
184
+ # Function: MarkEndOfOriginal
185
+ #
186
+ # If the group doesn't already have one, adds a <MENU_ENDOFORIGINAL> entry to the end and sets the
187
+ # <MENU_GROUP_HASENDOFORIGINAL> flag.
188
+ #
189
+ sub MarkEndOfOriginal
190
+ {
191
+ my $self = shift;
192
+
193
+ if (($self->Flags() & ::MENU_GROUP_HASENDOFORIGINAL()) == 0)
194
+ {
195
+ $self->PushToGroup( NaturalDocs::Menu::Entry->New(::MENU_ENDOFORIGINAL(), undef, undef, undef) );
196
+ $self->SetFlags( $self->Flags() | ::MENU_GROUP_HASENDOFORIGINAL() );
197
+ };
198
+ };
199
+
200
+
201
+ 1;
@@ -0,0 +1,76 @@
1
+ ###############################################################################
2
+ #
3
+ # Package: NaturalDocs::NDMarkup
4
+ #
5
+ ###############################################################################
6
+ #
7
+ # A package of support functions for dealing with <NDMarkup>.
8
+ #
9
+ # Usage and Dependencies:
10
+ #
11
+ # The package doesn't depend on any Natural Docs packages and is ready to use right away.
12
+ #
13
+ ###############################################################################
14
+
15
+ # This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure
16
+ # Natural Docs is licensed under the GPL
17
+
18
+
19
+ use strict;
20
+ use integer;
21
+
22
+ package NaturalDocs::NDMarkup;
23
+
24
+ #
25
+ # Function: ConvertAmpChars
26
+ #
27
+ # Substitutes certain characters with their <NDMarkup> amp chars.
28
+ #
29
+ # Parameters:
30
+ #
31
+ # text - The block of text to convert.
32
+ #
33
+ # Returns:
34
+ #
35
+ # The converted text block.
36
+ #
37
+ sub ConvertAmpChars #(text)
38
+ {
39
+ my ($self, $text) = @_;
40
+
41
+ $text =~ s/&/&amp;/g;
42
+ $text =~ s/</&lt;/g;
43
+ $text =~ s/>/&gt;/g;
44
+ $text =~ s/\"/&quot;/g;
45
+
46
+ return $text;
47
+ };
48
+
49
+
50
+ #
51
+ # Function: RestoreAmpChars
52
+ #
53
+ # Replaces <NDMarkup> amp chars with their original symbols.
54
+ #
55
+ # Parameters:
56
+ #
57
+ # text - The text to restore.
58
+ #
59
+ # Returns:
60
+ #
61
+ # The restored text.
62
+ #
63
+ sub RestoreAmpChars #(text)
64
+ {
65
+ my ($self, $text) = @_;
66
+
67
+ $text =~ s/&quot;/\"/g;
68
+ $text =~ s/&gt;/>/g;
69
+ $text =~ s/&lt;/</g;
70
+ $text =~ s/&amp;/&/g;
71
+
72
+ return $text;
73
+ };
74
+
75
+
76
+ 1;
@@ -0,0 +1,1331 @@
1
+ ###############################################################################
2
+ #
3
+ # Package: NaturalDocs::Parser
4
+ #
5
+ ###############################################################################
6
+ #
7
+ # A package that coordinates source file parsing between the <NaturalDocs::Languages::Base>-derived objects and its own
8
+ # sub-packages such as <NaturalDocs::Parser::Native>. Also handles sending symbols to <NaturalDocs::SymbolTable> and
9
+ # other generic topic processing.
10
+ #
11
+ # Usage and Dependencies:
12
+ #
13
+ # - Prior to use, <NaturalDocs::Settings>, <NaturalDocs::Languages>, <NaturalDocs::Project>, <NaturalDocs::SymbolTable>,
14
+ # and <NaturalDocs::ClassHierarchy> must be initialized. <NaturalDocs::SymbolTable> and <NaturalDocs::ClassHierarchy>
15
+ # do not have to be fully resolved.
16
+ #
17
+ # - Aside from that, the package is ready to use right away. It does not have its own initialization function.
18
+ #
19
+ ###############################################################################
20
+
21
+ # This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure
22
+ # Natural Docs is licensed under the GPL
23
+
24
+ use NaturalDocs::Parser::ParsedTopic;
25
+ use NaturalDocs::Parser::Native;
26
+ use NaturalDocs::Parser::JavaDoc;
27
+
28
+ use strict;
29
+ use integer;
30
+
31
+ package NaturalDocs::Parser;
32
+
33
+
34
+
35
+ ###############################################################################
36
+ # Group: Variables
37
+
38
+
39
+ #
40
+ # var: sourceFile
41
+ #
42
+ # The source <FileName> currently being parsed.
43
+ #
44
+ my $sourceFile;
45
+
46
+ #
47
+ # var: language
48
+ #
49
+ # The language object for the file, derived from <NaturalDocs::Languages::Base>.
50
+ #
51
+ my $language;
52
+
53
+ #
54
+ # Array: parsedFile
55
+ #
56
+ # An array of <NaturalDocs::Parser::ParsedTopic> objects.
57
+ #
58
+ my @parsedFile;
59
+
60
+
61
+ #
62
+ # bool: parsingForInformation
63
+ # Whether <ParseForInformation()> was called. If false, then <ParseForBuild()> was called.
64
+ #
65
+ my $parsingForInformation;
66
+
67
+
68
+
69
+ ###############################################################################
70
+ # Group: Functions
71
+
72
+ #
73
+ # Function: ParseForInformation
74
+ #
75
+ # Parses the input file for information. Will update the information about the file in <NaturalDocs::SymbolTable> and
76
+ # <NaturalDocs::Project>.
77
+ #
78
+ # Parameters:
79
+ #
80
+ # file - The <FileName> to parse.
81
+ #
82
+ sub ParseForInformation #(file)
83
+ {
84
+ my ($self, $file) = @_;
85
+ $sourceFile = $file;
86
+
87
+ $parsingForInformation = 1;
88
+
89
+ # Watch this parse so we detect any changes.
90
+ NaturalDocs::SymbolTable->WatchFileForChanges($sourceFile);
91
+ NaturalDocs::ClassHierarchy->WatchFileForChanges($sourceFile);
92
+ NaturalDocs::SourceDB->WatchFileForChanges($sourceFile);
93
+
94
+ my $defaultMenuTitle = $self->Parse();
95
+
96
+ foreach my $topic (@parsedFile)
97
+ {
98
+ # Add a symbol for the topic.
99
+
100
+ my $type = $topic->Type();
101
+ if ($type eq ::TOPIC_ENUMERATION())
102
+ { $type = ::TOPIC_TYPE(); };
103
+
104
+ NaturalDocs::SymbolTable->AddSymbol($topic->Symbol(), $sourceFile, $type,
105
+ $topic->Prototype(), $topic->Summary());
106
+
107
+
108
+ # You can't put the function call directly in a while with a regex. It has to sit in a variable to work.
109
+ my $body = $topic->Body();
110
+
111
+
112
+ # If it's a list or enum topic, add a symbol for each description list entry.
113
+
114
+ if ($topic->IsList() || $topic->Type() eq ::TOPIC_ENUMERATION())
115
+ {
116
+ # We'll hijack the enum constants to apply to non-enum behavior too.
117
+ my $behavior;
118
+
119
+ if ($topic->Type() eq ::TOPIC_ENUMERATION())
120
+ {
121
+ $type = ::TOPIC_CONSTANT();
122
+ $behavior = $language->EnumValues();
123
+ }
124
+ elsif (NaturalDocs::Topics->TypeInfo($topic->Type())->Scope() == ::SCOPE_ALWAYS_GLOBAL())
125
+ {
126
+ $behavior = ::ENUM_GLOBAL();
127
+ }
128
+ else
129
+ {
130
+ $behavior = ::ENUM_UNDER_PARENT();
131
+ };
132
+
133
+ while ($body =~ /<ds>([^<]+)<\/ds><dd>(.*?)<\/dd>/g)
134
+ {
135
+ my ($listTextSymbol, $listSummary) = ($1, $2);
136
+
137
+ $listTextSymbol = NaturalDocs::NDMarkup->RestoreAmpChars($listTextSymbol);
138
+ my $listSymbol = NaturalDocs::SymbolString->FromText($listTextSymbol);
139
+
140
+ if ($behavior == ::ENUM_UNDER_PARENT())
141
+ { $listSymbol = NaturalDocs::SymbolString->Join($topic->Package(), $listSymbol); }
142
+ elsif ($behavior == ::ENUM_UNDER_TYPE())
143
+ { $listSymbol = NaturalDocs::SymbolString->Join($topic->Symbol(), $listSymbol); };
144
+
145
+ NaturalDocs::SymbolTable->AddSymbol($listSymbol, $sourceFile, $type, undef,
146
+ $self->GetSummaryFromDescriptionList($listSummary));
147
+ };
148
+ };
149
+
150
+
151
+ # Add references in the topic.
152
+
153
+ while ($body =~ /<link target=\"([^\"]*)\" name=\"[^\"]*\" original=\"[^\"]*\">/g)
154
+ {
155
+ my $linkText = NaturalDocs::NDMarkup->RestoreAmpChars($1);
156
+ my $linkSymbol = NaturalDocs::SymbolString->FromText($linkText);
157
+
158
+ NaturalDocs::SymbolTable->AddReference(::REFERENCE_TEXT(), $linkSymbol,
159
+ $topic->Package(), $topic->Using(), $sourceFile);
160
+ };
161
+
162
+
163
+ # Add images in the topic.
164
+
165
+ while ($body =~ /<img mode=\"[^\"]*\" target=\"([^\"]+)\" original=\"[^\"]*\">/g)
166
+ {
167
+ my $target = NaturalDocs::NDMarkup->RestoreAmpChars($1);
168
+ NaturalDocs::ImageReferenceTable->AddReference($sourceFile, $target);
169
+ };
170
+ };
171
+
172
+ # Handle any changes to the file.
173
+ NaturalDocs::ClassHierarchy->AnalyzeChanges();
174
+ NaturalDocs::SymbolTable->AnalyzeChanges();
175
+ NaturalDocs::SourceDB->AnalyzeWatchedFileChanges();
176
+
177
+ # Update project on the file's characteristics.
178
+ my $hasContent = (scalar @parsedFile > 0);
179
+
180
+ NaturalDocs::Project->SetHasContent($sourceFile, $hasContent);
181
+ if ($hasContent)
182
+ { NaturalDocs::Project->SetDefaultMenuTitle($sourceFile, $defaultMenuTitle); };
183
+
184
+ # We don't need to keep this around.
185
+ @parsedFile = ( );
186
+ };
187
+
188
+
189
+ #
190
+ # Function: ParseForBuild
191
+ #
192
+ # Parses the input file for building, returning it as a <NaturalDocs::Parser::ParsedTopic> arrayref.
193
+ #
194
+ # Note that all new and changed files should be parsed for symbols via <ParseForInformation()> before calling this function on
195
+ # *any* file. The reason is that <NaturalDocs::SymbolTable> needs to know about all the symbol definitions and references to
196
+ # resolve them properly.
197
+ #
198
+ # Parameters:
199
+ #
200
+ # file - The <FileName> to parse for building.
201
+ #
202
+ # Returns:
203
+ #
204
+ # An arrayref of the source file as <NaturalDocs::Parser::ParsedTopic> objects.
205
+ #
206
+ sub ParseForBuild #(file)
207
+ {
208
+ my ($self, $file) = @_;
209
+ $sourceFile = $file;
210
+
211
+ $parsingForInformation = undef;
212
+
213
+ $self->Parse();
214
+
215
+ return \@parsedFile;
216
+ };
217
+
218
+
219
+
220
+
221
+ ###############################################################################
222
+ # Group: Interface Functions
223
+
224
+
225
+ #
226
+ # Function: OnComment
227
+ #
228
+ # The function called by <NaturalDocs::Languages::Base>-derived objects when their parsers encounter a comment
229
+ # suitable for documentation.
230
+ #
231
+ # Parameters:
232
+ #
233
+ # commentLines - An arrayref of the comment's lines. The language's comment symbols should be converted to spaces,
234
+ # and there should be no line break characters at the end of each line. *The original memory will be
235
+ # changed.*
236
+ # lineNumber - The line number of the first of the comment lines.
237
+ # isJavaDoc - Whether the comment is in JavaDoc format.
238
+ #
239
+ # Returns:
240
+ #
241
+ # The number of topics created by this comment, or zero if none.
242
+ #
243
+ sub OnComment #(string[] commentLines, int lineNumber, bool isJavaDoc)
244
+ {
245
+ my ($self, $commentLines, $lineNumber, $isJavaDoc) = @_;
246
+
247
+ $self->CleanComment($commentLines);
248
+
249
+ # We check if it's definitely Natural Docs content first. This overrides all else, since it's possible that a comment could start
250
+ # with a topic line yet have something that looks like a JavaDoc tag. Natural Docs wins in this case.
251
+ if (NaturalDocs::Parser::Native->IsMine($commentLines, $isJavaDoc))
252
+ { return NaturalDocs::Parser::Native->ParseComment($commentLines, $isJavaDoc, $lineNumber, \@parsedFile); }
253
+
254
+ elsif (NaturalDocs::Parser::JavaDoc->IsMine($commentLines, $isJavaDoc))
255
+ { return NaturalDocs::Parser::JavaDoc->ParseComment($commentLines, $isJavaDoc, $lineNumber, \@parsedFile); }
256
+
257
+ # If the content is ambiguous and it's a JavaDoc-styled comment, treat it as Natural Docs content.
258
+ elsif ($isJavaDoc)
259
+ { return NaturalDocs::Parser::Native->ParseComment($commentLines, $isJavaDoc, $lineNumber, \@parsedFile); }
260
+ };
261
+
262
+
263
+ #
264
+ # Function: OnClass
265
+ #
266
+ # A function called by <NaturalDocs::Languages::Base>-derived objects when their parsers encounter a class declaration.
267
+ #
268
+ # Parameters:
269
+ #
270
+ # class - The <SymbolString> of the class encountered.
271
+ #
272
+ sub OnClass #(class)
273
+ {
274
+ my ($self, $class) = @_;
275
+
276
+ if ($parsingForInformation)
277
+ { NaturalDocs::ClassHierarchy->AddClass($sourceFile, $class); };
278
+ };
279
+
280
+
281
+ #
282
+ # Function: OnClassParent
283
+ #
284
+ # A function called by <NaturalDocs::Languages::Base>-derived objects when their parsers encounter a declaration of
285
+ # inheritance.
286
+ #
287
+ # Parameters:
288
+ #
289
+ # class - The <SymbolString> of the class we're in.
290
+ # parent - The <SymbolString> of the class it inherits.
291
+ # scope - The package <SymbolString> that the reference appeared in.
292
+ # using - An arrayref of package <SymbolStrings> that the reference has access to via "using" statements.
293
+ # resolvingFlags - Any <Resolving Flags> to be used when resolving the reference. <RESOLVE_NOPLURAL> is added
294
+ # automatically since that would never apply to source code.
295
+ #
296
+ sub OnClassParent #(class, parent, scope, using, resolvingFlags)
297
+ {
298
+ my ($self, $class, $parent, $scope, $using, $resolvingFlags) = @_;
299
+
300
+ if ($parsingForInformation)
301
+ {
302
+ NaturalDocs::ClassHierarchy->AddParentReference($sourceFile, $class, $parent, $scope, $using,
303
+ $resolvingFlags | ::RESOLVE_NOPLURAL());
304
+ };
305
+ };
306
+
307
+
308
+
309
+ ###############################################################################
310
+ # Group: Support Functions
311
+
312
+
313
+ # Function: Parse
314
+ #
315
+ # Opens the source file and parses process. Most of the actual parsing is done in <NaturalDocs::Languages::Base->ParseFile()>
316
+ # and <OnComment()>, though.
317
+ #
318
+ # *Do not call externally.* Rather, call <ParseForInformation()> or <ParseForBuild()>.
319
+ #
320
+ # Returns:
321
+ #
322
+ # The default menu title of the file. Will be the <FileName> if nothing better is found.
323
+ #
324
+ sub Parse
325
+ {
326
+ my ($self) = @_;
327
+
328
+ NaturalDocs::Error->OnStartParsing($sourceFile);
329
+
330
+ $language = NaturalDocs::Languages->LanguageOf($sourceFile);
331
+ NaturalDocs::Parser::Native->Start();
332
+ @parsedFile = ( );
333
+
334
+ my ($autoTopics, $scopeRecord) = $language->ParseFile($sourceFile, \@parsedFile);
335
+
336
+
337
+ $self->AddToClassHierarchy();
338
+
339
+ $self->BreakLists();
340
+
341
+ if (defined $autoTopics)
342
+ {
343
+ if (defined $scopeRecord)
344
+ { $self->RepairPackages($autoTopics, $scopeRecord); };
345
+
346
+ $self->MergeAutoTopics($language, $autoTopics);
347
+ };
348
+
349
+ $self->RemoveRemainingHeaderlessTopics();
350
+
351
+
352
+ # We don't need to do this if there aren't any auto-topics because the only package changes would be implied by the comments.
353
+ if (defined $autoTopics)
354
+ { $self->AddPackageDelineators(); };
355
+
356
+ if (!NaturalDocs::Settings->NoAutoGroup())
357
+ { $self->MakeAutoGroups($autoTopics); };
358
+
359
+
360
+ # Set the menu title.
361
+
362
+ my $defaultMenuTitle = $sourceFile;
363
+
364
+ if (scalar @parsedFile)
365
+ {
366
+ my $addFileTitle;
367
+
368
+ if (NaturalDocs::Settings->OnlyFileTitles())
369
+ {
370
+ # We still want to use the title from the topics if the first one is a file.
371
+ if ($parsedFile[0]->Type() eq ::TOPIC_FILE())
372
+ { $addFileTitle = 0; }
373
+ else
374
+ { $addFileTitle = 1; };
375
+ }
376
+ elsif (scalar @parsedFile == 1 || NaturalDocs::Topics->TypeInfo( $parsedFile[0]->Type() )->PageTitleIfFirst())
377
+ { $addFileTitle = 0; }
378
+ else
379
+ { $addFileTitle = 1; };
380
+
381
+ if (!$addFileTitle)
382
+ {
383
+ $defaultMenuTitle = $parsedFile[0]->Title();
384
+ }
385
+ else
386
+ {
387
+ # If the title ended up being the file name, add a leading section for it.
388
+
389
+ unshift @parsedFile,
390
+ NaturalDocs::Parser::ParsedTopic->New(::TOPIC_FILE(), (NaturalDocs::File->SplitPath($sourceFile))[2],
391
+ undef, undef, undef, undef, undef, 1, undef);
392
+ };
393
+ };
394
+
395
+ NaturalDocs::Error->OnEndParsing($sourceFile);
396
+
397
+ return $defaultMenuTitle;
398
+ };
399
+
400
+
401
+ #
402
+ # Function: CleanComment
403
+ #
404
+ # Removes any extraneous formatting and whitespace from the comment. Eliminates comment boxes, horizontal lines, trailing
405
+ # whitespace from lines, and expands all tab characters. It keeps leading whitespace, though, since it may be needed for
406
+ # example code, and blank lines, since the original line numbers are needed.
407
+ #
408
+ # Parameters:
409
+ #
410
+ # commentLines - An arrayref of the comment lines to clean. *The original memory will be changed.* Lines should have the
411
+ # language's comment symbols replaced by spaces and not have a trailing line break.
412
+ #
413
+ sub CleanComment #(commentLines)
414
+ {
415
+ my ($self, $commentLines) = @_;
416
+
417
+ use constant DONT_KNOW => 0;
418
+ use constant IS_UNIFORM => 1;
419
+ use constant IS_UNIFORM_IF_AT_END => 2;
420
+ use constant IS_NOT_UNIFORM => 3;
421
+
422
+ my $leftSide = DONT_KNOW;
423
+ my $rightSide = DONT_KNOW;
424
+ my $leftSideChar;
425
+ my $rightSideChar;
426
+
427
+ my $index = 0;
428
+ my $tabLength = NaturalDocs::Settings->TabLength();
429
+
430
+ while ($index < scalar @$commentLines)
431
+ {
432
+ # Strip trailing whitespace from the original.
433
+
434
+ $commentLines->[$index] =~ s/[ \t]+$//;
435
+
436
+
437
+ # Expand tabs in the original. This method is almost six times faster than Text::Tabs' method.
438
+
439
+ my $tabIndex = index($commentLines->[$index], "\t");
440
+
441
+ while ($tabIndex != -1)
442
+ {
443
+ substr( $commentLines->[$index], $tabIndex, 1, ' ' x ($tabLength - ($tabIndex % $tabLength)) );
444
+ $tabIndex = index($commentLines->[$index], "\t", $tabIndex);
445
+ };
446
+
447
+
448
+ # Make a working copy and strip leading whitespace as well. This has to be done after tabs are expanded because
449
+ # stripping indentation could change how far tabs are expanded.
450
+
451
+ my $line = $commentLines->[$index];
452
+ $line =~ s/^ +//;
453
+
454
+ # If the line is blank...
455
+ if (!length $line)
456
+ {
457
+ # If we have a potential vertical line, this only acceptable if it's at the end of the comment.
458
+ if ($leftSide == IS_UNIFORM)
459
+ { $leftSide = IS_UNIFORM_IF_AT_END; };
460
+ if ($rightSide == IS_UNIFORM)
461
+ { $rightSide = IS_UNIFORM_IF_AT_END; };
462
+ }
463
+
464
+ # If there's at least four symbols in a row, it's a horizontal line. The second regex supports differing edge characters. It
465
+ # doesn't matter if any of this matches the left and right side symbols. The length < 256 is a sanity check, because that
466
+ # regexp has caused the perl regexp engine to choke on an insane line someone sent me from an automatically generated
467
+ # file. It had over 10k characters on the first line, and most of them were 0x00.
468
+ elsif ($line =~ /^([^a-zA-Z0-9 ])\1{3,}$/ ||
469
+ (length $line < 256 && $line =~ /^([^a-zA-Z0-9 ])\1*([^a-zA-Z0-9 ])\2{3,}([^a-zA-Z0-9 ])\3*$/) )
470
+ {
471
+ # Ignore it. This has no effect on the vertical line detection. We want to keep it in the output though in case it was
472
+ # in a code section.
473
+ }
474
+
475
+ # If the line is not blank or a horizontal line...
476
+ else
477
+ {
478
+ # More content means any previous blank lines are no longer tolerated in vertical line detection. They are only
479
+ # acceptable at the end of the comment.
480
+
481
+ if ($leftSide == IS_UNIFORM_IF_AT_END)
482
+ { $leftSide = IS_NOT_UNIFORM; };
483
+ if ($rightSide == IS_UNIFORM_IF_AT_END)
484
+ { $rightSide = IS_NOT_UNIFORM; };
485
+
486
+
487
+ # Detect vertical lines. Lines are only lines if they are followed by whitespace or a connected horizontal line.
488
+ # Otherwise we may accidentally detect lines from short comments that just happen to have every first or last
489
+ # character the same.
490
+
491
+ if ($leftSide != IS_NOT_UNIFORM)
492
+ {
493
+ if ($line =~ /^([^a-zA-Z0-9])\1*(?: |$)/)
494
+ {
495
+ if ($leftSide == DONT_KNOW)
496
+ {
497
+ $leftSide = IS_UNIFORM;
498
+ $leftSideChar = $1;
499
+ }
500
+ else # ($leftSide == IS_UNIFORM) Other choices already ruled out.
501
+ {
502
+ if ($leftSideChar ne $1)
503
+ { $leftSide = IS_NOT_UNIFORM; };
504
+ };
505
+ }
506
+ # We'll tolerate the lack of symbols on the left on the first line, because it may be a
507
+ # /* Function: Whatever
508
+ # * Description.
509
+ # */
510
+ # comment which would have the leading /* blanked out.
511
+ elsif ($index != 0)
512
+ {
513
+ $leftSide = IS_NOT_UNIFORM;
514
+ };
515
+ };
516
+
517
+ if ($rightSide != IS_NOT_UNIFORM)
518
+ {
519
+ if ($line =~ / ([^a-zA-Z0-9])\1*$/)
520
+ {
521
+ if ($rightSide == DONT_KNOW)
522
+ {
523
+ $rightSide = IS_UNIFORM;
524
+ $rightSideChar = $1;
525
+ }
526
+ else # ($rightSide == IS_UNIFORM) Other choices already ruled out.
527
+ {
528
+ if ($rightSideChar ne $1)
529
+ { $rightSide = IS_NOT_UNIFORM; };
530
+ };
531
+ }
532
+ else
533
+ {
534
+ $rightSide = IS_NOT_UNIFORM;
535
+ };
536
+ };
537
+
538
+ # We'll remove vertical lines later if they're uniform throughout the entire comment.
539
+ };
540
+
541
+ $index++;
542
+ };
543
+
544
+
545
+ if ($leftSide == IS_UNIFORM_IF_AT_END)
546
+ { $leftSide = IS_UNIFORM; };
547
+ if ($rightSide == IS_UNIFORM_IF_AT_END)
548
+ { $rightSide = IS_UNIFORM; };
549
+
550
+
551
+ $index = 0;
552
+ my $inCodeSection = 0;
553
+
554
+ while ($index < scalar @$commentLines)
555
+ {
556
+ # Clear horizontal lines only if we're not in a code section.
557
+ if ($commentLines->[$index] =~ /^ *([^a-zA-Z0-9 ])\1{3,}$/ ||
558
+ ( length $commentLines->[$index] < 256 &&
559
+ $commentLines->[$index] =~ /^ *([^a-zA-Z0-9 ])\1*([^a-zA-Z0-9 ])\2{3,}([^a-zA-Z0-9 ])\3*$/ ) )
560
+ {
561
+ if (!$inCodeSection)
562
+ { $commentLines->[$index] = ''; }
563
+ }
564
+
565
+ else
566
+ {
567
+ # Clear vertical lines.
568
+
569
+ if ($leftSide == IS_UNIFORM)
570
+ {
571
+ # This works because every line should either start this way, be blank, or be the first line that doesn't start with a
572
+ # symbol.
573
+ $commentLines->[$index] =~ s/^ *([^a-zA-Z0-9 ])\1*//;
574
+ };
575
+
576
+ if ($rightSide == IS_UNIFORM)
577
+ {
578
+ $commentLines->[$index] =~ s/ *([^a-zA-Z0-9 ])\1*$//;
579
+ };
580
+
581
+
582
+ # Clear horizontal lines again if there were vertical lines. This catches lines that were separated from the verticals by
583
+ # whitespace.
584
+
585
+ if (($leftSide == IS_UNIFORM || $rightSide == IS_UNIFORM) && !$inCodeSection)
586
+ {
587
+ $commentLines->[$index] =~ s/^ *([^a-zA-Z0-9 ])\1{3,}$//;
588
+ $commentLines->[$index] =~ s/^ *([^a-zA-Z0-9 ])\1*([^a-zA-Z0-9 ])\2{3,}([^a-zA-Z0-9 ])\3*$//;
589
+ };
590
+
591
+
592
+ # Check for the start and end of code sections. Note that this doesn't affect vertical line removal.
593
+
594
+ if (!$inCodeSection &&
595
+ $commentLines->[$index] =~ /^ *\( *(?:(?:start|begin)? +)?(?:table|code|example|diagram) *\)$/i )
596
+ {
597
+ $inCodeSection = 1;
598
+ }
599
+ elsif ($inCodeSection &&
600
+ $commentLines->[$index] =~ /^ *\( *(?:end|finish|done)(?: +(?:table|code|example|diagram))? *\)$/i)
601
+ {
602
+ $inCodeSection = 0;
603
+ }
604
+ }
605
+
606
+
607
+ $index++;
608
+ };
609
+
610
+ };
611
+
612
+
613
+
614
+ ###############################################################################
615
+ # Group: Processing Functions
616
+
617
+
618
+ #
619
+ # Function: RepairPackages
620
+ #
621
+ # Recalculates the packages for all comment topics using the auto-topics and the scope record. Call this *before* calling
622
+ # <MergeAutoTopics()>.
623
+ #
624
+ # Parameters:
625
+ #
626
+ # autoTopics - A reference to the list of automatically generated <NaturalDocs::Parser::ParsedTopics>.
627
+ # scopeRecord - A reference to an array of <NaturalDocs::Languages::Advanced::ScopeChanges>.
628
+ #
629
+ sub RepairPackages #(autoTopics, scopeRecord)
630
+ {
631
+ my ($self, $autoTopics, $scopeRecord) = @_;
632
+
633
+ my $topicIndex = 0;
634
+ my $autoTopicIndex = 0;
635
+ my $scopeIndex = 0;
636
+
637
+ my $topic = $parsedFile[0];
638
+ my $autoTopic = $autoTopics->[0];
639
+ my $scopeChange = $scopeRecord->[0];
640
+
641
+ my $currentPackage;
642
+ my $inFakePackage;
643
+
644
+ while (defined $topic)
645
+ {
646
+ # First update the scope via the record if its defined and has the lowest line number.
647
+ if (defined $scopeChange &&
648
+ $scopeChange->LineNumber() <= $topic->LineNumber() &&
649
+ (!defined $autoTopic || $scopeChange->LineNumber() <= $autoTopic->LineNumber()) )
650
+ {
651
+ $currentPackage = $scopeChange->Scope();
652
+ $scopeIndex++;
653
+ $scopeChange = $scopeRecord->[$scopeIndex]; # Will be undef when past end.
654
+ $inFakePackage = undef;
655
+ }
656
+
657
+ # Next try to end a fake scope with an auto topic if its defined and has the lowest line number.
658
+ elsif (defined $autoTopic &&
659
+ $autoTopic->LineNumber() <= $topic->LineNumber())
660
+ {
661
+ if ($inFakePackage)
662
+ {
663
+ $currentPackage = $autoTopic->Package();
664
+ $inFakePackage = undef;
665
+ };
666
+
667
+ $autoTopicIndex++;
668
+ $autoTopic = $autoTopics->[$autoTopicIndex]; # Will be undef when past end.
669
+ }
670
+
671
+
672
+ # Finally try to handle the topic, since it has the lowest line number. Check for Type() because headerless topics won't have
673
+ # one.
674
+ else
675
+ {
676
+ my $scope;
677
+ if ($topic->Type())
678
+ { $scope = NaturalDocs::Topics->TypeInfo($topic->Type())->Scope(); }
679
+ else
680
+ { $scope = ::SCOPE_NORMAL(); };
681
+
682
+ if ($scope == ::SCOPE_START() || $scope == ::SCOPE_END())
683
+ {
684
+ # They should already have the correct class and scope.
685
+ $currentPackage = $topic->Package();
686
+ $inFakePackage = 1;
687
+ }
688
+ else
689
+ {
690
+ # Fix the package of everything else.
691
+
692
+ # Note that the first function or variable topic to appear in a fake package will assume that package even if it turns out
693
+ # to be incorrect in the actual code, since the topic will come before the auto-topic. This will be corrected in
694
+ # MergeAutoTopics().
695
+
696
+ $topic->SetPackage($currentPackage);
697
+ };
698
+
699
+ $topicIndex++;
700
+ $topic = $parsedFile[$topicIndex]; # Will be undef when past end.
701
+ };
702
+ };
703
+
704
+ };
705
+
706
+
707
+ #
708
+ # Function: MergeAutoTopics
709
+ #
710
+ # Merges the automatically generated topics into the file. If an auto-topic matches an existing topic, it will have it's prototype
711
+ # and package transferred. If it doesn't, the auto-topic will be inserted into the list unless
712
+ # <NaturalDocs::Settings->DocumentedOnly()> is set. If an existing topic doesn't have a title, it's assumed to be a headerless
713
+ # comment and will be merged with the next auto-topic or discarded.
714
+ #
715
+ # Parameters:
716
+ #
717
+ # language - The <NaturalDocs::Languages::Base>-derived class for the file.
718
+ # autoTopics - A reference to the list of automatically generated topics.
719
+ #
720
+ sub MergeAutoTopics #(language, autoTopics)
721
+ {
722
+ my ($self, $language, $autoTopics) = @_;
723
+
724
+ my $topicIndex = 0;
725
+ my $autoTopicIndex = 0;
726
+
727
+ # Keys are topic types, values are existence hashrefs of titles.
728
+ my %topicsInLists;
729
+
730
+ while ($topicIndex < scalar @parsedFile && $autoTopicIndex < scalar @$autoTopics)
731
+ {
732
+ my $topic = $parsedFile[$topicIndex];
733
+ my $autoTopic = $autoTopics->[$autoTopicIndex];
734
+
735
+ my $cleanTitle = $topic->Title();
736
+ $cleanTitle =~ s/[\t ]*\([^\(]*$//;
737
+
738
+ # Add the auto-topic if it's higher in the file than the current topic.
739
+ if ($autoTopic->LineNumber() < $topic->LineNumber())
740
+ {
741
+ if (exists $topicsInLists{$autoTopic->Type()} &&
742
+ exists $topicsInLists{$autoTopic->Type()}->{$autoTopic->Title()})
743
+ {
744
+ # Remove it from the list so a second one with the same name will be added.
745
+ delete $topicsInLists{$autoTopic->Type()}->{$autoTopic->Title()};
746
+ }
747
+ elsif (!NaturalDocs::Settings->DocumentedOnly())
748
+ {
749
+ splice(@parsedFile, $topicIndex, 0, $autoTopic);
750
+ $topicIndex++;
751
+ };
752
+
753
+ $autoTopicIndex++;
754
+ }
755
+
756
+ # Remove a headerless topic if there's another topic between it and the next auto-topic.
757
+ elsif (!$topic->Title() && $topicIndex + 1 < scalar @parsedFile &&
758
+ $parsedFile[$topicIndex+1]->LineNumber() < $autoTopic->LineNumber())
759
+ {
760
+ splice(@parsedFile, $topicIndex, 1);
761
+ }
762
+
763
+ # Transfer information if we have a match or a headerless topic.
764
+ elsif ( !$topic->Title() || ($topic->Type() == $autoTopic->Type() && index($autoTopic->Title(), $cleanTitle) != -1) )
765
+ {
766
+ $topic->SetType($autoTopic->Type());
767
+ $topic->SetPrototype($autoTopic->Prototype());
768
+ $topic->SetUsing($autoTopic->Using());
769
+
770
+ if (!$topic->Title())
771
+ { $topic->SetTitle($autoTopic->Title()); };
772
+
773
+ if (NaturalDocs::Topics->TypeInfo($topic->Type())->Scope() != ::SCOPE_START())
774
+ { $topic->SetPackage($autoTopic->Package()); }
775
+ elsif ($autoTopic->Package() ne $topic->Package())
776
+ {
777
+ my @autoPackageIdentifiers = NaturalDocs::SymbolString->IdentifiersOf($autoTopic->Package());
778
+ my @packageIdentifiers = NaturalDocs::SymbolString->IdentifiersOf($topic->Package());
779
+
780
+ while (scalar @autoPackageIdentifiers && $autoPackageIdentifiers[-1] eq $packageIdentifiers[-1])
781
+ {
782
+ pop @autoPackageIdentifiers;
783
+ pop @packageIdentifiers;
784
+ };
785
+
786
+ if (scalar @autoPackageIdentifiers)
787
+ { $topic->SetPackage( NaturalDocs::SymbolString->Join(@autoPackageIdentifiers) ); };
788
+ };
789
+
790
+ $topicIndex++;
791
+ $autoTopicIndex++;
792
+ }
793
+
794
+ # Extract topics in lists.
795
+ elsif ($topic->IsList())
796
+ {
797
+ if (!exists $topicsInLists{$topic->Type()})
798
+ { $topicsInLists{$topic->Type()} = { }; };
799
+
800
+ my $body = $topic->Body();
801
+
802
+ while ($body =~ /<ds>([^<]+)<\/ds>/g)
803
+ { $topicsInLists{$topic->Type()}->{NaturalDocs::NDMarkup->RestoreAmpChars($1)} = 1; };
804
+
805
+ $topicIndex++;
806
+ }
807
+
808
+ # Otherwise there's no match. Skip the topic. The auto-topic will be added later.
809
+ else
810
+ {
811
+ $topicIndex++;
812
+ }
813
+ };
814
+
815
+ # Add any auto-topics remaining.
816
+ if (!NaturalDocs::Settings->DocumentedOnly())
817
+ {
818
+ while ($autoTopicIndex < scalar @$autoTopics)
819
+ {
820
+ my $autoTopic = $autoTopics->[$autoTopicIndex];
821
+
822
+ if (exists $topicsInLists{$autoTopic->Type()} &&
823
+ exists $topicsInLists{$autoTopic->Type()}->{$autoTopic->Title()})
824
+ {
825
+ # Remove it from the list so a second one with the same name will be added.
826
+ delete $topicsInLists{$autoTopic->Type()}->{$autoTopic->Title()};
827
+ }
828
+ else
829
+ {
830
+ push(@parsedFile, $autoTopic);
831
+ };
832
+
833
+ $autoTopicIndex++;
834
+ };
835
+ };
836
+ };
837
+
838
+
839
+ #
840
+ # Function: RemoveRemainingHeaderlessTopics
841
+ #
842
+ # After <MergeAutoTopics()> is done, this function removes any remaining headerless topics from the file. If they don't merge
843
+ # into anything, they're not valid topics.
844
+ #
845
+ sub RemoveRemainingHeaderlessTopics
846
+ {
847
+ my ($self) = @_;
848
+
849
+ my $index = 0;
850
+ while ($index < scalar @parsedFile)
851
+ {
852
+ if ($parsedFile[$index]->Title())
853
+ { $index++; }
854
+ else
855
+ { splice(@parsedFile, $index, 1); };
856
+ };
857
+ };
858
+
859
+
860
+ #
861
+ # Function: MakeAutoGroups
862
+ #
863
+ # Creates group topics for files that do not have them.
864
+ #
865
+ sub MakeAutoGroups
866
+ {
867
+ my ($self) = @_;
868
+
869
+ # No groups only one topic.
870
+ if (scalar @parsedFile < 2)
871
+ { return; };
872
+
873
+ my $index = 0;
874
+ my $startStretch = 0;
875
+
876
+ # Skip the first entry if its the page title.
877
+ if (NaturalDocs::Topics->TypeInfo( $parsedFile[0]->Type() )->PageTitleIfFirst())
878
+ {
879
+ $index = 1;
880
+ $startStretch = 1;
881
+ };
882
+
883
+ # Make auto-groups for each stretch between scope-altering topics.
884
+ while ($index < scalar @parsedFile)
885
+ {
886
+ my $scope = NaturalDocs::Topics->TypeInfo($parsedFile[$index]->Type())->Scope();
887
+
888
+ if ($scope == ::SCOPE_START() || $scope == ::SCOPE_END())
889
+ {
890
+ if ($index > $startStretch)
891
+ { $index += $self->MakeAutoGroupsFor($startStretch, $index); };
892
+
893
+ $startStretch = $index + 1;
894
+ };
895
+
896
+ $index++;
897
+ };
898
+
899
+ if ($index > $startStretch)
900
+ { $self->MakeAutoGroupsFor($startStretch, $index); };
901
+ };
902
+
903
+
904
+ #
905
+ # Function: MakeAutoGroupsFor
906
+ #
907
+ # Creates group topics for sections of files that do not have them. A support function for <MakeAutoGroups()>.
908
+ #
909
+ # Parameters:
910
+ #
911
+ # startIndex - The index to start at.
912
+ # endIndex - The index to end at. Not inclusive.
913
+ #
914
+ # Returns:
915
+ #
916
+ # The number of group topics added.
917
+ #
918
+ sub MakeAutoGroupsFor #(startIndex, endIndex)
919
+ {
920
+ my ($self, $startIndex, $endIndex) = @_;
921
+
922
+ # No groups if any are defined already.
923
+ for (my $i = $startIndex; $i < $endIndex; $i++)
924
+ {
925
+ if ($parsedFile[$i]->Type() eq ::TOPIC_GROUP())
926
+ { return 0; };
927
+ };
928
+
929
+
930
+ use constant COUNT => 0;
931
+ use constant TYPE => 1;
932
+ use constant SECOND_TYPE => 2;
933
+ use constant SIZE => 3;
934
+
935
+ # This is an array of ( count, type, secondType ) triples. Count and Type will always be filled in; count is the number of
936
+ # consecutive topics of type. On the second pass, if small groups are combined secondType will be filled in. There will not be
937
+ # more than two types per group.
938
+ my @groups;
939
+ my $groupIndex = 0;
940
+
941
+
942
+ # First pass: Determine all the groups.
943
+
944
+ my $i = $startIndex;
945
+ my $currentType;
946
+
947
+ while ($i < $endIndex)
948
+ {
949
+ if (!defined $currentType || ($parsedFile[$i]->Type() ne $currentType && $parsedFile[$i]->Type() ne ::TOPIC_GENERIC()) )
950
+ {
951
+ if (defined $currentType)
952
+ { $groupIndex += SIZE; };
953
+
954
+ $currentType = $parsedFile[$i]->Type();
955
+
956
+ $groups[$groupIndex + COUNT] = 1;
957
+ $groups[$groupIndex + TYPE] = $currentType;
958
+ }
959
+ else
960
+ { $groups[$groupIndex + COUNT]++; };
961
+
962
+ $i++;
963
+ };
964
+
965
+
966
+ # Second pass: Combine groups based on "noise". Noise means types go from A to B to A at least once, and there are at least
967
+ # two groups in a row with three or less, and at least one of those groups is two or less. So 3, 3, 3 doesn't count as noise, but
968
+ # 3, 2, 3 does.
969
+
970
+ $groupIndex = 0;
971
+
972
+ # While there are at least three groups left...
973
+ while ($groupIndex < scalar @groups - (2 * SIZE))
974
+ {
975
+ # If the group two places in front of this one has the same type...
976
+ if ($groups[$groupIndex + (2 * SIZE) + TYPE] eq $groups[$groupIndex + TYPE])
977
+ {
978
+ # It means we went from A to B to A, which partially qualifies as noise.
979
+
980
+ my $firstType = $groups[$groupIndex + TYPE];
981
+ my $secondType = $groups[$groupIndex + SIZE + TYPE];
982
+
983
+ if (NaturalDocs::Topics->TypeInfo($firstType)->CanGroupWith($secondType) ||
984
+ NaturalDocs::Topics->TypeInfo($secondType)->CanGroupWith($firstType))
985
+ {
986
+ my $hasNoise;
987
+
988
+ my $hasThrees;
989
+ my $hasTwosOrOnes;
990
+
991
+ my $endIndex = $groupIndex;
992
+
993
+ while ($endIndex < scalar @groups &&
994
+ ($groups[$endIndex + TYPE] eq $firstType || $groups[$endIndex + TYPE] eq $secondType))
995
+ {
996
+ if ($groups[$endIndex + COUNT] > 3)
997
+ {
998
+ # They must be consecutive to count.
999
+ $hasThrees = 0;
1000
+ $hasTwosOrOnes = 0;
1001
+ }
1002
+ elsif ($groups[$endIndex + COUNT] == 3)
1003
+ {
1004
+ $hasThrees = 1;
1005
+
1006
+ if ($hasTwosOrOnes)
1007
+ { $hasNoise = 1; };
1008
+ }
1009
+ else # < 3
1010
+ {
1011
+ if ($hasThrees || $hasTwosOrOnes)
1012
+ { $hasNoise = 1; };
1013
+
1014
+ $hasTwosOrOnes = 1;
1015
+ };
1016
+
1017
+ $endIndex += SIZE;
1018
+ };
1019
+
1020
+ if (!$hasNoise)
1021
+ {
1022
+ $groupIndex = $endIndex - SIZE;
1023
+ }
1024
+ else # hasNoise
1025
+ {
1026
+ $groups[$groupIndex + SECOND_TYPE] = $secondType;
1027
+
1028
+ for (my $noiseIndex = $groupIndex + SIZE; $noiseIndex < $endIndex; $noiseIndex += SIZE)
1029
+ {
1030
+ $groups[$groupIndex + COUNT] += $groups[$noiseIndex + COUNT];
1031
+ };
1032
+
1033
+ splice(@groups, $groupIndex + SIZE, $endIndex - $groupIndex - SIZE);
1034
+
1035
+ $groupIndex += SIZE;
1036
+ };
1037
+ }
1038
+
1039
+ else # They can't group together
1040
+ {
1041
+ $groupIndex += SIZE;
1042
+ };
1043
+ }
1044
+
1045
+ else
1046
+ { $groupIndex += SIZE; };
1047
+ };
1048
+
1049
+
1050
+ # Finally, create group topics for the parsed file.
1051
+
1052
+ $groupIndex = 0;
1053
+ $i = $startIndex;
1054
+
1055
+ while ($groupIndex < scalar @groups)
1056
+ {
1057
+ if ($groups[$groupIndex + TYPE] ne ::TOPIC_GENERIC())
1058
+ {
1059
+ my $topic = $parsedFile[$i];
1060
+ my $title = NaturalDocs::Topics->NameOfType($groups[$groupIndex + TYPE], 1);
1061
+
1062
+ if (defined $groups[$groupIndex + SECOND_TYPE])
1063
+ { $title .= ' and ' . NaturalDocs::Topics->NameOfType($groups[$groupIndex + SECOND_TYPE], 1); };
1064
+
1065
+ splice(@parsedFile, $i, 0, NaturalDocs::Parser::ParsedTopic->New(::TOPIC_GROUP(),
1066
+ $title,
1067
+ $topic->Package(), $topic->Using(),
1068
+ undef, undef, undef,
1069
+ $topic->LineNumber()) );
1070
+ $i++;
1071
+ };
1072
+
1073
+ $i += $groups[$groupIndex + COUNT];
1074
+ $groupIndex += SIZE;
1075
+ };
1076
+
1077
+ return (scalar @groups / SIZE);
1078
+ };
1079
+
1080
+
1081
+ #
1082
+ # Function: AddToClassHierarchy
1083
+ #
1084
+ # Adds any class topics to the class hierarchy, since they may not have been called with <OnClass()> if they didn't match up to
1085
+ # an auto-topic.
1086
+ #
1087
+ sub AddToClassHierarchy
1088
+ {
1089
+ my ($self) = @_;
1090
+
1091
+ foreach my $topic (@parsedFile)
1092
+ {
1093
+ if ($topic->Type() && NaturalDocs::Topics->TypeInfo( $topic->Type() )->ClassHierarchy())
1094
+ {
1095
+ if ($topic->IsList())
1096
+ {
1097
+ my $body = $topic->Body();
1098
+
1099
+ while ($body =~ /<ds>([^<]+)<\/ds>/g)
1100
+ {
1101
+ $self->OnClass( NaturalDocs::SymbolString->FromText( NaturalDocs::NDMarkup->RestoreAmpChars($1) ) );
1102
+ };
1103
+ }
1104
+ else
1105
+ {
1106
+ $self->OnClass($topic->Package());
1107
+ };
1108
+ };
1109
+ };
1110
+ };
1111
+
1112
+
1113
+ #
1114
+ # Function: AddPackageDelineators
1115
+ #
1116
+ # Adds section and class topics to make sure the package is correctly represented in the documentation. Should be called last in
1117
+ # this process.
1118
+ #
1119
+ sub AddPackageDelineators
1120
+ {
1121
+ my ($self) = @_;
1122
+
1123
+ my $index = 0;
1124
+ my $currentPackage;
1125
+
1126
+ # Values are the arrayref [ title, type ];
1127
+ my %usedPackages;
1128
+
1129
+ while ($index < scalar @parsedFile)
1130
+ {
1131
+ my $topic = $parsedFile[$index];
1132
+
1133
+ if ($topic->Package() ne $currentPackage)
1134
+ {
1135
+ $currentPackage = $topic->Package();
1136
+ my $scopeType = NaturalDocs::Topics->TypeInfo($topic->Type())->Scope();
1137
+
1138
+ if ($scopeType == ::SCOPE_START())
1139
+ {
1140
+ $usedPackages{$currentPackage} = [ $topic->Title(), $topic->Type() ];
1141
+ }
1142
+ elsif ($scopeType == ::SCOPE_END())
1143
+ {
1144
+ my $newTopic;
1145
+
1146
+ if (!defined $currentPackage)
1147
+ {
1148
+ $newTopic = NaturalDocs::Parser::ParsedTopic->New(::TOPIC_SECTION(), 'Global',
1149
+ undef, undef,
1150
+ undef, undef, undef,
1151
+ $topic->LineNumber(), undef);
1152
+ }
1153
+ else
1154
+ {
1155
+ my ($title, $body, $summary, $type);
1156
+ my @packageIdentifiers = NaturalDocs::SymbolString->IdentifiersOf($currentPackage);
1157
+
1158
+ if (exists $usedPackages{$currentPackage})
1159
+ {
1160
+ $title = $usedPackages{$currentPackage}->[0];
1161
+ $type = $usedPackages{$currentPackage}->[1];
1162
+ $body = '<p>(continued)</p>';
1163
+ $summary = '(continued)';
1164
+ }
1165
+ else
1166
+ {
1167
+ $title = join($language->PackageSeparator(), @packageIdentifiers);
1168
+ $type = ::TOPIC_CLASS();
1169
+
1170
+ # Body and summary stay undef.
1171
+
1172
+ $usedPackages{$currentPackage} = $title;
1173
+ };
1174
+
1175
+ my @titleIdentifiers = NaturalDocs::SymbolString->IdentifiersOf( NaturalDocs::SymbolString->FromText($title) );
1176
+ for (my $i = 0; $i < scalar @titleIdentifiers; $i++)
1177
+ { pop @packageIdentifiers; };
1178
+
1179
+ $newTopic = NaturalDocs::Parser::ParsedTopic->New($type, $title,
1180
+ NaturalDocs::SymbolString->Join(@packageIdentifiers), undef,
1181
+ undef, $summary, $body,
1182
+ $topic->LineNumber(), undef);
1183
+ }
1184
+
1185
+ splice(@parsedFile, $index, 0, $newTopic);
1186
+ $index++;
1187
+ }
1188
+ };
1189
+
1190
+ $index++;
1191
+ };
1192
+ };
1193
+
1194
+
1195
+ #
1196
+ # Function: BreakLists
1197
+ #
1198
+ # Breaks list topics into individual topics.
1199
+ #
1200
+ sub BreakLists
1201
+ {
1202
+ my $self = shift;
1203
+
1204
+ my $index = 0;
1205
+
1206
+ while ($index < scalar @parsedFile)
1207
+ {
1208
+ my $topic = $parsedFile[$index];
1209
+
1210
+ if ($topic->IsList() && NaturalDocs::Topics->TypeInfo( $topic->Type() )->BreakLists())
1211
+ {
1212
+ my $body = $topic->Body();
1213
+
1214
+ my @newTopics;
1215
+ my $newBody;
1216
+
1217
+ my $bodyIndex = 0;
1218
+
1219
+ for (;;)
1220
+ {
1221
+ my $startList = index($body, '<dl>', $bodyIndex);
1222
+
1223
+ if ($startList == -1)
1224
+ { last; };
1225
+
1226
+ $newBody .= substr($body, $bodyIndex, $startList - $bodyIndex);
1227
+
1228
+ my $endList = index($body, '</dl>', $startList);
1229
+ my $listBody = substr($body, $startList, $endList - $startList);
1230
+
1231
+ while ($listBody =~ /<ds>([^<]+)<\/ds><dd>(.*?)<\/dd>/g)
1232
+ {
1233
+ my ($symbol, $description) = ($1, $2);
1234
+
1235
+ push @newTopics, NaturalDocs::Parser::ParsedTopic->New( $topic->Type(), $symbol, $topic->Package(),
1236
+ $topic->Using(), undef,
1237
+ $self->GetSummaryFromDescriptionList($description),
1238
+ '<p>' . $description . '</p>', $topic->LineNumber(),
1239
+ undef );
1240
+ };
1241
+
1242
+ $bodyIndex = $endList + 5;
1243
+ };
1244
+
1245
+ $newBody .= substr($body, $bodyIndex);
1246
+
1247
+ # Remove trailing headings.
1248
+ $newBody =~ s/(?:<h>[^<]+<\/h>)+$//;
1249
+
1250
+ # Remove empty headings.
1251
+ $newBody =~ s/(?:<h>[^<]+<\/h>)+(<h>[^<]+<\/h>)/$1/g;
1252
+
1253
+ if ($newBody)
1254
+ {
1255
+ unshift @newTopics, NaturalDocs::Parser::ParsedTopic->New( ::TOPIC_GROUP(), $topic->Title(), $topic->Package(),
1256
+ $topic->Using(), undef,
1257
+ $self->GetSummaryFromBody($newBody), $newBody,
1258
+ $topic->LineNumber(), undef );
1259
+ };
1260
+
1261
+ splice(@parsedFile, $index, 1, @newTopics);
1262
+
1263
+ $index += scalar @newTopics;
1264
+ }
1265
+
1266
+ else # not a list
1267
+ { $index++; };
1268
+ };
1269
+ };
1270
+
1271
+
1272
+ #
1273
+ # Function: GetSummaryFromBody
1274
+ #
1275
+ # Returns the summary text from the topic body.
1276
+ #
1277
+ # Parameters:
1278
+ #
1279
+ # body - The complete topic body, in <NDMarkup>.
1280
+ #
1281
+ # Returns:
1282
+ #
1283
+ # The topic summary, or undef if none.
1284
+ #
1285
+ sub GetSummaryFromBody #(body)
1286
+ {
1287
+ my ($self, $body) = @_;
1288
+
1289
+ my $summary;
1290
+
1291
+ # Extract the first sentence from the leading paragraph, if any. We'll tolerate a single header beforehand, but nothing else.
1292
+
1293
+ if ($body =~ /^(?:<h>[^<]*<\/h>)?<p>(.*?)(<\/p>|[\.\!\?](?:[\)\}\'\ ]|&quot;|&gt;))/x)
1294
+ {
1295
+ $summary = $1;
1296
+
1297
+ if ($2 ne '</p>')
1298
+ { $summary .= $2; };
1299
+ };
1300
+
1301
+ return $summary;
1302
+ };
1303
+
1304
+
1305
+ #
1306
+ # Function: GetSummaryFromDescriptionList
1307
+ #
1308
+ # Returns the summary text from a description list entry.
1309
+ #
1310
+ # Parameters:
1311
+ #
1312
+ # description - The description in <NDMarkup>. Should be the content between the <dd></dd> tags only.
1313
+ #
1314
+ # Returns:
1315
+ #
1316
+ # The description summary, or undef if none.
1317
+ #
1318
+ sub GetSummaryFromDescriptionList #(description)
1319
+ {
1320
+ my ($self, $description) = @_;
1321
+
1322
+ my $summary;
1323
+
1324
+ if ($description =~ /^(.*?)($|[\.\!\?](?:[\)\}\'\ ]|&quot;|&gt;))/)
1325
+ { $summary = $1 . $2; };
1326
+
1327
+ return $summary;
1328
+ };
1329
+
1330
+
1331
+ 1;