asciidoctor-lists-extended 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 763b4829cf12a23c7ae9c993f9f10fc394919af9adb8c4e5eaf34f82a017ce76
4
- data.tar.gz: 1a22a3265585f57715f25d0f14f8d3c44889eb9efd9976698dd7aa42b760dc46
3
+ metadata.gz: c1f0396e93370444193a1258530dd32f81db35dddaedc4c911a31655d94d5e2c
4
+ data.tar.gz: bbd4f0412e6b11fcfc1bb39b38a2cd9932c8738a740d8c6b693f4185c03c0566
5
5
  SHA512:
6
- metadata.gz: 3260b2cbe8a43684258c6a2a9e33f0e236b01453e99dc4cec4dcf967f15011c1f8f96daf833160d7e24d18593838d6752271050b22fc53a6f8edfcd58ccc77bd
7
- data.tar.gz: f42056096abc9bd690b97abbffcc40ee61ad3dc8f64b4f041eec42ec5fbdf87de9c61e5605cdf608eb4e73b5e0105ec0ce04c74ff79e99e70ffe290035f4c3cf
6
+ metadata.gz: 9970ef9f04375ee8e446abb219171880806ac09bdc09f1909f0830eda569e37191188cd195813185339e56b31ccaaf6446f835415f77d5adaf912b6bf032aee3
7
+ data.tar.gz: fe43e888bba80b85b9212f24df7bed543224e510f22e4b40aefd754eeacf27b0e5e22220d2bc9a3d70e684dacab1e00d49ab120547b74382b6ad9bdc86bda824
data/README.adoc CHANGED
@@ -1,13 +1,30 @@
1
1
  = asciidoctor-lists-extended
2
2
  :toc: left
3
3
  :toclevels: 2
4
- :source-highlighter: rouge
4
+ :source-highlighter: highlight.js
5
5
 
6
6
  A converter-aware asciidoctor extension that generates a *List of Figures*, *List of Tables*, *List of Listings*, and *List of Examples* — or any custom captioned block type.
7
7
 
8
8
  Replaces and supersedes `asciidoctor-pdf-lofte`.
9
9
  Compatible with the `asciidoctor-lists` macro syntax.
10
10
 
11
+ == Preview
12
+
13
+ .Table of Contents with List of Figures, List of Tables, and List of Examples entries
14
+ image::test/images/toc.png[PDF Table of Contents showing list entries,pdfwidth=100%]
15
+
16
+ .List of Figures — dot-leader style matching the ToC
17
+ image::test/images/lof.png[List of Figures rendered in PDF front matter,pdfwidth=100%]
18
+
19
+ .List of Listings
20
+ image::test/images/lol.png[List of Listings rendered in PDF front matter,pdfwidth=100%]
21
+
22
+ .List of Examples
23
+ image::test/images/loe.png[List of Examples rendered in PDF front matter,pdfwidth=100%]
24
+
25
+ .PDF bookmark outline showing list entries
26
+ image::test/images/pdf-outline.png[PDF bookmark outline panel,pdfwidth=100%]
27
+
11
28
  == Features
12
29
 
13
30
  * Works with *HTML5* (xref links) and *asciidoctor-pdf* (dot-leader style matching the ToC)
@@ -47,13 +64,13 @@ asciidoctor -r /path/to/lib/asciidoctor-lists-extended.rb document.adoc
47
64
  :toc:
48
65
  :doctype: book
49
66
 
50
- \== List of Figures <1>
67
+ == List of Figures <1>
51
68
  list-of::image[] <2>
52
69
 
53
- \== List of Tables
70
+ == List of Tables
54
71
  list-of::table[]
55
72
 
56
- \== Chapter 1
73
+ == Chapter 1
57
74
 
58
75
  .My Architecture Diagram <3>
59
76
  image::arch.png[]
@@ -165,7 +182,7 @@ In PDF mode the extension hooks into `asciidoctor-pdf`'s ToC allocation/renderin
165
182
  All lists are placed in the *front matter* (directly after the ToC) regardless of where the `list-of::` macros appear in the source.
166
183
  The macro order in the source determines the order of the lists in the front matter.
167
184
 
168
- You can place additional `list-of::` macros inside chapter subsections to generate *chapter-scoped* lists.
185
+ You can place `list-of::` macros inside any subsection to generate *section-scoped* lists.
169
186
  The scope is determined automatically from where the macro appears in the document hierarchy:
170
187
 
171
188
  [cols="1,2"]
@@ -176,30 +193,41 @@ The scope is determined automatically from where the macro appears in the docume
176
193
  e.g. a front-matter `== List of Figures`
177
194
  |*Document-wide* — collects all matching elements in the entire document.
178
195
 
179
- |Inside a subsection (`=== …`) nested within a chapter +
196
+ |Inside a subsection (`=== …`) +
180
197
  e.g. `=== Chapter 1 Figures` inside `== Chapter 1`
181
- |*Chapter-scoped* — collects only elements from that chapter and its child sections.
198
+ |*Section-scoped* — collects only elements placed inside that same subsection.
182
199
  |===
183
200
 
184
- .Example: global list plus a per-chapter list
201
+ [IMPORTANT]
202
+ ====
203
+ For section-scoped lists, place the captioned content *before* the `list-of::` macros
204
+ within the subsection.
205
+ This ensures all entries have already been rendered when the list runs, so page numbers
206
+ show correctly (no `?`).
207
+ ====
208
+
209
+ .Example: global list plus a per-section list
185
210
  [source,asciidoc]
186
211
  ----
187
- \== List of Figures <1>
212
+ == List of Figures <1>
188
213
  list-of::image[]
189
214
 
190
- \== Chapter 1
215
+ == Chapter 1
191
216
 
192
- .Overview Diagram
193
- image::arch.png[]
217
+ === Chapter 1 Figures <2>
194
218
 
195
- \=== Chapter 1 Figures <2>
196
- list-of::image[]
219
+ .Overview Diagram <3>
220
+ image::arch.png[]
197
221
 
198
222
  .Detailed Flow
199
223
  image::flow.png[]
224
+
225
+ list-of::image[] <4>
200
226
  ----
201
- <1> Document-wide: collects all images.
202
- <2> Chapter-scoped: collects only Chapter 1's images.
227
+ <1> Document-wide: collects all images across the entire document.
228
+ <2> Subsection that owns both the content and the scoped list.
229
+ <3> Captioned images placed *before* the macro so page numbers are resolved.
230
+ <4> Section-scoped: collects only images placed inside `=== Chapter 1 Figures`.
203
231
 
204
232
  === Styling
205
233
 
@@ -250,19 +278,19 @@ The containing section and heading are rendered normally.
250
278
  :table-caption: Table
251
279
  :listing-caption: Listing
252
280
 
253
- \== List of Figures
281
+ == List of Figures
254
282
  list-of::image[] <1>
255
283
 
256
- \== List of Tables
284
+ == List of Tables
257
285
  list-of::table[hide_empty_section] <2>
258
286
 
259
- \== List of Code Examples
287
+ == List of Code Examples
260
288
  list-of::listing[title="Code Examples"] <3>
261
289
 
262
- \== List of Appendix Examples
290
+ == List of Appendix Examples
263
291
  list-of::example[exclude_from_outline] <4>
264
292
 
265
- \== Chapter 1: Architecture
293
+ == Chapter 1: Architecture
266
294
 
267
295
  .System Overview
268
296
  image::arch.png[]
@@ -332,10 +360,10 @@ The `list-of::` macros render as `<ul>` lists with `<a href="#…">` links.
332
360
 
333
361
  |`:lof-title: List of Figures` +
334
362
  `:lot-title: List of Tables`
335
- |`\== List of Figures` +
363
+ |`== List of Figures` +
336
364
  `list-of::image[]` +
337
365
  +
338
- `\== List of Tables` +
366
+ `== List of Tables` +
339
367
  `list-of::table[]`
340
368
 
341
369
  |`:include-lists-in-toc:`
@@ -64,13 +64,7 @@ module Asciidoctor
64
64
  def scope_node_for(block, document)
65
65
  node = block.parent
66
66
  return document unless node.respond_to?(:context) && node.context == :section
67
- node.parent.context == :document ? document : chapter_ancestor(node)
68
- end
69
-
70
- def chapter_ancestor(section)
71
- node = section
72
- node = node.parent while node.parent&.context == :section
73
- node
67
+ node.parent.context == :document ? document : node
74
68
  end
75
69
 
76
70
  # Parse AsciiDoc source lines in the context of +parent+, returning the
@@ -29,7 +29,8 @@ module Asciidoctor
29
29
  super
30
30
  @list_extents = {} # UUID → Extent (front-matter lists only)
31
31
  @list_configs_ordered = [] # front-matter list configs in document order
32
- @inline_list_configs = {} # UUID → config for chapter-scoped inline lists
32
+ @inline_list_configs = {} # UUID → config for section-scoped inline lists
33
+ @inline_render_positions = {} # UUID → deferred render position (page + cursor)
33
34
  @inline_num_front_matter_pages = 0 # saved from ink_toc for inline page-number math
34
35
  @rendering_list = false
35
36
  @list_toc_insert_idx = 0
@@ -89,7 +90,29 @@ module Asciidoctor
89
90
  @list_toc_insert_idx += 1
90
91
  end
91
92
 
92
- super
93
+ result = super
94
+
95
+ # Phase 2: render deferred inline section-scoped lists.
96
+ # traverse doc has completed before ink_toc is called, so all
97
+ # pdf-page-start attributes are now set and page numbers are real.
98
+ unless @inline_render_positions.empty?
99
+ @inline_render_positions.each_value do |pos|
100
+ go_to_page pos[:page]
101
+ move_cursor_to pos[:cursor]
102
+ entries = get_list_entries(pos[:config][:scope_node], pos[:config][:element])
103
+ next if entries.empty?
104
+ entries.each { |e| e.level = 2 if e.title }
105
+ begin
106
+ @rendering_list = true
107
+ ink_toc_level entries, pos[:num_levels], pos[:dot_leader], num_front_matter_pages
108
+ ensure
109
+ @rendering_list = false
110
+ end
111
+ end
112
+ go_to_page page_count
113
+ end
114
+
115
+ result
93
116
  end
94
117
 
95
118
  # -----------------------------------------------------------------------
@@ -122,19 +145,69 @@ module Asciidoctor
122
145
  # cursor position without a heading (the enclosing === section provides
123
146
  # the heading) and without any page break before or after.
124
147
  # All other paragraphs delegate to super unchanged.
148
+ # -----------------------------------------------------------------------
149
+ # convert_paragraph override
150
+ # -----------------------------------------------------------------------
151
+ # Intercepts UUID placeholder paragraphs for section-scoped inline lists.
152
+ #
153
+ # Rendering strategy (two-phase):
154
+ # Phase 1 — body rendering (here, scratch? may be true or false):
155
+ # • When scratch? is true: call ink_toc_level in scratch mode so Prawn
156
+ # measures the correct space for page-break decisions.
157
+ # • When scratch? is false: dry-run the list to measure its height,
158
+ # reserve that space in the document by advancing the cursor, and
159
+ # record the page + cursor position in @inline_render_positions.
160
+ # No visible content is written yet.
161
+ #
162
+ # Phase 2 — ink_toc (called by asciidoctor-pdf AFTER traverse doc):
163
+ # By the time ink_toc runs all pdf-page-start attributes have been set.
164
+ # For each saved position, navigate there and render with real dot leaders
165
+ # and page numbers. See ink_toc below.
125
166
  def convert_paragraph(node)
126
167
  if node.content_model == :simple && node.lines.size == 1 &&
127
168
  (config = @inline_list_configs[node.lines[0]])
169
+ uuid = node.lines[0]
128
170
  entries = get_list_entries(config[:scope_node], config[:element])
171
+
129
172
  unless entries.empty?
130
173
  entries.each { |e| e.level = 2 if e.title }
131
- num_levels = (node.document.attr 'toclevels', 2).to_i
174
+ num_levels = @theme.toc_levels || 2
132
175
  dot_leader = build_dot_leader_config(num_levels)
133
- begin
134
- @rendering_list = true
135
- ink_toc_level entries, num_levels, dot_leader, @inline_num_front_matter_pages
136
- ensure
137
- @rendering_list = false
176
+
177
+ if scratch?
178
+ # Scratch pass (e.g. heading orphan detection): measure space only.
179
+ begin
180
+ @rendering_list = true
181
+ ink_toc_level entries, num_levels, dot_leader, 0
182
+ ensure
183
+ @rendering_list = false
184
+ end
185
+ else
186
+ # Real pass: measure via dry_run, reserve blank space, save position.
187
+ extent = dry_run(onto: self) do
188
+ begin
189
+ @rendering_list = true
190
+ ink_toc_level entries, num_levels, dot_leader, 0
191
+ ensure
192
+ @rendering_list = false
193
+ end
194
+ end
195
+
196
+ save_page = extent.from.page
197
+ save_cursor = extent.from.cursor
198
+
199
+ # Reserve the space without rendering any content.
200
+ extent.each_page { |first_page| start_new_page unless first_page }
201
+ move_cursor_to extent.to.cursor
202
+
203
+ @inline_render_positions[uuid] = {
204
+ config: config,
205
+ entries: entries,
206
+ num_levels: num_levels,
207
+ dot_leader: dot_leader,
208
+ page: save_page,
209
+ cursor: save_cursor,
210
+ }
138
211
  end
139
212
  end
140
213
  return
@@ -134,24 +134,16 @@ module Asciidoctor
134
134
  # Determine the collection scope for a list-of:: UUID placeholder block.
135
135
  #
136
136
  # Rule: if the macro's parent section is a top-level section (its parent is
137
- # the Document), scope is the whole document. If the macro is nested inside
138
- # a chapter (grandparent is another section), scope is the chapter ancestor —
139
- # the first ancestor section whose parent is the Document.
137
+ # the Document), scope is the whole document. Otherwise, scope is the direct
138
+ # parent section the macro collects only elements within that subsection.
140
139
  #
141
140
  # This means front-matter lists (== List of Figures) collect everything, while
142
- # per-chapter lists (=== Chapter Figures inside == Chapter 1) collect only
143
- # their chapter's content automatically.
141
+ # per-section lists (=== Chapter Figures inside == Chapter 1) collect only
142
+ # elements placed inside that same subsection.
144
143
  def scope_node_for(block)
145
144
  node = block.parent
146
145
  return block.document unless node.respond_to?(:context) && node.context == :section
147
- node.parent.context == :document ? block.document : chapter_ancestor(node)
148
- end
149
-
150
- # Walk up the parent chain to find the first section whose parent is the Document.
151
- def chapter_ancestor(section)
152
- node = section
153
- node = node.parent while node.parent&.context == :section
154
- node
146
+ node.parent.context == :document ? block.document : node
155
147
  end
156
148
 
157
149
  # Safe accessor: use the asciidoctor-pdf constant if available, else fall back.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-lists-extended
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - 白一百 baiyibai