asciidoctor-dot-leader 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d9a25c3ac68e342ade564fce5f6ae421fb3ba5da8ebec4584682cf6b5c2f0202
4
+ data.tar.gz: 3883b7986da82e541f1a7dcdf029dc077489906a3ad303e33140ca2f98696d1a
5
+ SHA512:
6
+ metadata.gz: 671510acec6229d3d54dfb4b9255c307a9141e70d307e3db369ca40773ac4d1f5bc880def7f0d3bc506251a42886956660e5a7535b0743e7e42d98adffaf0e96
7
+ data.tar.gz: 4a21802b05620af76b340504cd1d9951430a0502c4e1f77769c04a76cafc7ee86b26b1163e91fc4525082e2cc74e9223dd0f8bb30780a74a41d2084c16d4772b
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ MIT License
2
+
3
+
4
+ This project includes code from Asciidoctor PDF by OpenDevise Inc. and the Asciidoctor Project,
5
+ licensed under the MIT License:
6
+
7
+ Copyright (c) 2025 白一百 baiyibai
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
data/README.adoc ADDED
@@ -0,0 +1,98 @@
1
+ = AsciiDoctor Dot Leader Inline Macro
2
+
3
+ This project provides an inline macro which `pass:[dot:leader["left", "right"]]` which inserts leaders between the values.
4
+
5
+ Dot . . . . . . . . . . . . . . . . . . . . . . . . Leaders
6
+
7
+ It currently supports three backends:
8
+
9
+ * AsciiDoctor (Ruby) - `backend-html5`
10
+ * AsciiDoctor-PDF (Ruby) - `backend-pdf`
11
+ * AsciiDoctor.js - `backend-webview-html5` - See <<asciidoctor-js-dot-leader>>
12
+
13
+ .PDF
14
+ image:resources/images/example-pdf-adoc-formatted.png[]
15
+
16
+ .HTML5
17
+ image:resources/images/example-html5-roles.png[]
18
+
19
+ .AsciiDoctor.js
20
+ image:resources/images/example-webview-html5-inline-passthroughs.png[]
21
+
22
+ == Markup And Usage _Manual_
23
+
24
+ Markup examples, rendered output examples, and extensive compatibility information is provided _for multiple output_ formats *in multiple formats*:
25
+
26
+ * link:dot_leader_example.pdf[]
27
+ * link:dot_leader_example.html[]
28
+ * Or clone the project and open the link:dot_leader_example.adoc[] file with Visual Studio Code's Asciidoc's preview window.
29
+
30
+ == Todo
31
+
32
+ There are a few items which need fixing:
33
+
34
+ * PDF
35
+ ** [ ] Upload gem to rubygems.org
36
+ * HTML5
37
+ ** [ ] Include .css automatically?
38
+ * webview-html5 (Asciidoctor.js) for Microsoft Visual Studio Code and possibly others
39
+ ** [ ] Release on npm
40
+
41
+ == Ruby GEM Build Instructions (for 白一百 baiyibai)
42
+
43
+ ```
44
+ gem build asciidoctor-dot-leader.gemspec
45
+ gem install ./asciidoctor-dot-leader-1.0.0.gem
46
+ ```
47
+
48
+ [#asciidoctor-js-dot-leader]
49
+ == AsciiDoctor.js Dot Leader Inline Macro
50
+
51
+ This project provides an inline macro, `pass:[dot:leader["left", "right"]]`, which inserts dot leaders between the provided values.
52
+
53
+ === Target Application
54
+
55
+ This has only been tested with the Microsoft Visual Studio Code's AsciiDoc extension's _Preview_ function which uses the `backen-webview-html5`.
56
+
57
+ === Usage
58
+
59
+ Complete these steps to enable the pass:[dot:leader[]] macro:
60
+
61
+ . Install the library.
62
+ . Create an `.asciidoctor/lib/` folder in the root of the asciidoctor project.
63
+ . Set up the target project directory to use the extension by using either of these methods:
64
+ .. Copy the `.dot_leader.js` file to the `.asciidoctor/lib/` folder.
65
+ .. Create a `.dot_leader_linker.js` file in the `.asciidoctor/lib/` folder and copy and modify this content to it:
66
+ +
67
+ [source,javascript]
68
+ ----
69
+ module.exports = require('../../asciidoctorjs-extension/dot_leader.js')
70
+
71
+ // TODO: Install locally and test if it works
72
+ // module.exports = require('asciidoctor-dot-leader')
73
+ ----
74
+ +
75
+ . Enable the AsciiDoc Extension's ability to use extensions in the _Preview_ function using either of these methods:
76
+ .. Set this configuration flag:
77
+ +
78
+ [source,javascript]
79
+ ----
80
+ "asciidoc.extensions.registerWorkspaceExtensions": true
81
+ ----
82
+ +
83
+ .. Enable the Asciidoc > Extensions: *Register Workspace Extensions* option.
84
+ . Open a document containing `pass:[dot:leader[]]` inline macros, and press the _Preview_ button.
85
+
86
+
87
+ == Copyright
88
+
89
+ Copyright (C) 2025-present 白一百 baiyibai
90
+ Free use of this software is granted under the terms of the MIT License.
91
+
92
+ * The image _The «Public Domain Mark» icon from Creative Commons with transparent background._ is in the public domain and taken from: +
93
+ https://commons.wikimedia.org/wiki/File:Cc-public_domain_mark.svg[^]
94
+
95
+ * The CSS taken from https://www.w3.org/Style/Examples/007/leaders.en.html[^].
96
+
97
+
98
+ For the full text of the license, see the link:LICENSE[] file.
@@ -0,0 +1,11 @@
1
+ # dot_leader_html.rb 2025-07-20 白一百 baiyibai
2
+ # https://gitlab.com/baiyibai/asciidoctor-pdf-dot-leader
3
+ require 'asciidoctor/converter/html5'
4
+
5
+ Asciidoctor::Converter::Html5Converter.class_eval do
6
+ def convert_inline_dot_leader(node)
7
+ l_text = node.attr('l_text')
8
+ r_text = node.attr('r_text')
9
+ %(<ul class="leaders"><li><span>#{l_text}</span><span>#{r_text}</span></li></ul>)
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ # dot_leader_inline_macro.rb 2025-07-20 白一百 baiyibai
2
+ # https://gitlab.com/baiyibai/asciidoctor-pdf-dot-leader
3
+ # This extension provides the 'dot:leader["left","right"]' extension.
4
+ Asciidoctor::Extensions.register do
5
+ inline_macro do
6
+ named :dot
7
+ process do |parent, target, attrs|
8
+ l_text = attrs[1] || ''
9
+ r_text = attrs[2] || ''
10
+
11
+ # Perform attribute substitution (must be done twice because attributes are placed inside of attributes)
12
+ l_text = parent.apply_subs l_text, [:attributes]
13
+ r_text = parent.apply_subs r_text, [:attributes]
14
+
15
+ # Handles both pass:[]#text# and [.role]#text#, and attributes again
16
+ # Do not use :specialcharacters
17
+ l_fragments = parent.apply_subs l_text, [:quotes, :macros, :attributes, :replacements, :post_replacements]
18
+ r_fragments = parent.apply_subs r_text, [:quotes, :macros, :attributes, :replacements, :post_replacements]
19
+
20
+
21
+ # warn "DEBUG dot: target='#{target}', l_text='#{l_fragments}', r_text='#{r_fragments}'"
22
+
23
+ create_inline parent, :dot_leader, target,
24
+ type: :dot,
25
+ attributes: {
26
+ 'l_text' => l_fragments,
27
+ 'r_text' => r_fragments,
28
+ }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,190 @@
1
+ # dot_leader_pdf.rb 2025-07-20 白一百 baiyibai
2
+ # https://gitlab.com/baiyibai/asciidoctor-pdf-dot-leader
3
+ # This inline macro uses AsciiDoctor-PDF's ToC generation code as a jumping off point, but departs from it.
4
+ # Use '':dot-leader-scale: 0.6' to set the document-wide factor
5
+ require 'asciidoctor-pdf' unless defined? ::Asciidoctor::Converter::PdfConverter
6
+ class DotLeader < (Asciidoctor::Converter.for 'pdf')
7
+ register_for 'pdf'
8
+
9
+ def rendered_width_of_fragments(fragments, scale, roles = [])
10
+ fragments.sum do |fragment|
11
+ styles = fragment[:styles] || Set.new
12
+ size = font_size
13
+ size *= scale if styles.include?(:subscript) || styles.include?(:superscript)
14
+ font_style = if styles.include?(:bold) && styles.include?(:italic)
15
+ :bold_italic
16
+ elsif styles.include?(:bold)
17
+ :bold
18
+ elsif styles.include?(:italic)
19
+ :italic
20
+ else
21
+ :normal
22
+ end
23
+
24
+ font_name = fragment[:font] || font_family
25
+
26
+ width = nil
27
+ # Handle inline image width
28
+ if fragment[:image_format]
29
+ # Use numeric value if it's a string
30
+ image_width = fragment[:image_width]
31
+ return image_width.to_f if image_width
32
+ end
33
+ font font_name, style: font_style, size: size do
34
+ width = rendered_width_of_string(fragment[:text])
35
+ end
36
+ width
37
+ end
38
+ end
39
+
40
+ def convert_inline_dot_leader(node)
41
+ # warn "Node attributes: #{node.attributes.inspect}"
42
+ return nil unless node.type == :dot
43
+
44
+ left_side = node.attr('l_text') || ''
45
+ right_side = node.attr('r_text') || ''
46
+ if left_side.empty? # Allow items only on the right
47
+ left_side = ' '
48
+ end
49
+ doc = node.document
50
+ if doc.attr 'dot-leader-scale'
51
+ scale = doc.attr 'dot-leader-scale'
52
+ scale = scale.to_f
53
+ else
54
+ scale = 0.6
55
+ end
56
+
57
+ # 2025-07-17 BYB: Create the dot_leader array; copied from ink_toc
58
+ dot_leader = theme_font :toc do
59
+ # TODO: we could simplify by using nested theme_font :toc_dot_leader #BYB: Original note from ink_toc
60
+ if (dot_leader_font_style = @theme.toc_dot_leader_font_style&.to_sym || :normal) != font_style
61
+ font_style dot_leader_font_style
62
+ end
63
+ font_size @theme.toc_dot_leader_font_size
64
+ {
65
+ font_color: @theme.toc_dot_leader_font_color || @font_color,
66
+ font_style: dot_leader_font_style,
67
+ font_size: font_size,
68
+ levels: ((dot_leader_l = @theme.toc_dot_leader_levels) == 'none' ? ::Set.new :
69
+ (dot_leader_l && dot_leader_l != 'all' ? dot_leader_l.to_s.split.map(&:to_i).to_set : nil)),
70
+ text: (dot_leader_text = @theme.toc_dot_leader_content || DotLeaderTextDefault),
71
+ width: dot_leader_text.empty? ? 0 : (rendered_width_of_string dot_leader_text),
72
+ # TODO: spacer gives a little bit of room between dots and page number #BYB: Original note from ink_toc
73
+ spacer: { text: NoBreakSpace, size: (spacer_font_size = @font_size * 0.25) },
74
+ spacer_width: (rendered_width_of_char NoBreakSpace, size: spacer_font_size),
75
+ }
76
+ end
77
+
78
+ # 2025-07-17 BYB: Set toc_font_info
79
+ toc_font_info = theme_font :toc do
80
+ { font: font, size: @font_size }
81
+ end
82
+
83
+ # 2025-07-17 BYB: Set a dummy entry_level and entry_anchor
84
+ entry_level = 2
85
+ entry_anchor = nil
86
+
87
+ # 2025-07-17 BYB: Store the cursor position
88
+ start_cursor = cursor
89
+ start_dots = nil
90
+
91
+ # 2025-07-17 BYB: left_side original
92
+ left_side_inherited = (apply_text_decoration ::Set.new, :toc, entry_level).merge anchor: entry_anchor, color: @font_color
93
+ # NOTE: use text formatter to add anchor overlay to avoid using inline format with synthetic anchor tag
94
+ left_side_fragments = text_formatter.format left_side, inherited: left_side_inherited
95
+ # warn "left_side_fragments: #{left_side_fragments.inspect}"
96
+
97
+ # 2025-07-17 BYB: Try doing the same for the right side
98
+ right_side_inherited = (apply_text_decoration ::Set.new, :toc, entry_level).merge anchor: entry_anchor, color: @font_color
99
+ # NOTE: use text formatter to add anchor overlay to avoid using inline format with synthetic anchor tag
100
+ right_side_fragments = text_formatter.format right_side, inherited: right_side_inherited
101
+
102
+ line_metrics = calc_line_metrics @base_line_height
103
+
104
+ # 2025-07-17 BYB: This needs to be modified
105
+ right_side_placeholder_width = rendered_width_of_string right_side * @toc_max_pagenum_digits
106
+ # puts right_side_placeholder_width.inspect # Various widths
107
+ right_side_placeholder_width = 0 # BYB: Not a problem for now
108
+
109
+ right_side_placeholder_width = rendered_width_of_fragments right_side_fragments, scale, node.roles.to_a
110
+
111
+ left_side_test_width = rendered_width_of_fragments left_side_fragments, scale, node.roles.to_a
112
+
113
+ # 2025-07-17 Set hanging_indent to toc; potentially this could be styled
114
+ hanging_indent = @theme.toc_hanging_indent
115
+ start_page_number = page_number
116
+
117
+ indent 0, right_side_placeholder_width do
118
+ fragment_positions = []
119
+ left_side_fragments.each do |fragment|
120
+ fragment_positions << (fragment_position = ::Asciidoctor::PDF::FormattedText::FragmentPositionRenderer.new)
121
+ (fragment[:callback] ||= []) << fragment_position
122
+ end
123
+
124
+ if right_side_placeholder_width > bounds.width
125
+ warn "WARN: dot-leader: The right side too wide to fit on a line; skipping: #{left_side} #{right_side}"
126
+ return nil
127
+ end
128
+
129
+ typeset_formatted_text left_side_fragments, line_metrics, hanging_indent: hanging_indent, normalize_line_height: true
130
+
131
+ break unless (last_fragment_position = fragment_positions.select(&:page_number)[-1])
132
+ start_dots = last_fragment_position.right + hanging_indent
133
+ last_fragment_cursor = last_fragment_position.top + line_metrics.padding_top
134
+ start_cursor = last_fragment_cursor if last_fragment_position.page_number > start_page_number || (start_cursor - last_fragment_cursor) > line_metrics.height
135
+ end
136
+
137
+ # 2025-07-17 No loop
138
+ # NOTE: this will leave behind a gap where this entry would have been
139
+ # break unless start_dots
140
+
141
+ end_cursor = cursor
142
+ move_cursor_to start_cursor
143
+ # NOTE: we're guaranteed to be on the same page as the final line of the entry
144
+
145
+ if dot_leader[:width] > 0 && (dot_leader[:levels] ? (dot_leader[:levels].include? entry_level.pred) : true)
146
+ # 2025-07-17 BYB: Needed to calculate the right side width
147
+ # right_side_width = rendered_width_of_string right_side
148
+ right_side_width = right_side_placeholder_width
149
+
150
+ right_side_font_settings = { color: @font_color, font: font_family, size: @font_size, styles: font_styles }
151
+ save_font do
152
+ # NOTE: the same font is used for dot leaders throughout toc
153
+ set_font toc_font_info[:font], dot_leader[:font_size]
154
+ font_style dot_leader[:font_style]
155
+ # 2025-07-17 BYB: Add support for Multiple Columns https://asciidoctor.zulipchat.com/#narrow/channel/288690-users.2Fasciidoctor-pdf/topic/Implicit.20page.20break.20after.20column_box
156
+ if node.parent.parent.attributes['columns']
157
+ start_dots = start_dots - bounds.left
158
+ end
159
+ num_dots = [((bounds.width - start_dots - dot_leader[:spacer_width] - right_side_width) / dot_leader[:width]).floor, 0].max
160
+ # FIXME: dots don't line up in columns if width of page numbers differ # BYB: Original
161
+ fragment_positions = []
162
+ right_side_fragments.each do |fragment|
163
+ fragment_positions << (fragment_position = ::Asciidoctor::PDF::FormattedText::FragmentPositionRenderer.new)
164
+ (fragment[:callback] ||= []) << fragment_position
165
+ end
166
+ typeset_formatted_text [
167
+ { text: dot_leader[:text] * num_dots, color: dot_leader[:font_color] },
168
+ dot_leader[:spacer],
169
+ *right_side_fragments.map { |fragment|
170
+ fragment.dup.tap do |f|
171
+ f[:styles] = Array(f[:styles])
172
+ f[:styles] |= Array(right_side_font_settings[:styles]) if right_side_font_settings[:styles]
173
+ f[:font] ||= right_side_font_settings[:font] if right_side_font_settings[:font]
174
+ f[:size] ||= right_side_font_settings[:size] if right_side_font_settings[:size]
175
+ f[:color] ||= right_side_font_settings[:color] if right_side_font_settings[:color]
176
+ f[:anchor] = entry_anchor if entry_anchor
177
+ end
178
+ }
179
+ ], line_metrics, align: :right
180
+ end
181
+ else
182
+ typeset_formatted_text [{ text: right_side, color: @font_color, anchor: entry_anchor }], line_metrics, align: :right
183
+ end
184
+ move_cursor_to end_cursor
185
+
186
+ # Return nil to avoid numbers being printed out
187
+ nil
188
+
189
+ end
190
+ end
@@ -0,0 +1,19 @@
1
+ # dot_leader.rb 2025-07-20 白一百 baiyibai
2
+ # https://gitlab.com/baiyibai/asciidoctor-pdf-dot-leader
3
+ # This gem is structured so that asciidoctor-pdf is not required for html5 output
4
+ require_relative 'dot_leader/dot_leader_inline_macro'
5
+
6
+ # Try to load the PDF converter support if available
7
+ begin
8
+ require 'asciidoctor-pdf'
9
+ require_relative 'dot_leader/dot_leader_pdf'
10
+ rescue LoadError
11
+ # PDF not available, do nothing
12
+ end
13
+
14
+ # Try to load the HTML backend support if Asciidoctor is available
15
+ begin
16
+ require_relative 'dot_leader/dot_leader_html'
17
+ rescue LoadError
18
+ # HTML-specific code couldn't be loaded — possibly not needed
19
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'asciidoctor/dot_leader'
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: asciidoctor-dot-leader
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - 白一百 baiyibai
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: asciidoctor
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ description: Extension for asciidoctor (pdf and html) for creating dot leaders using
27
+ the dot.leader["left","right"] syntax.
28
+ email: rubygems@baiyibai.cyou
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - LICENSE
34
+ - README.adoc
35
+ - lib/asciidoctor-dot-leader.rb
36
+ - lib/asciidoctor/dot_leader.rb
37
+ - lib/asciidoctor/dot_leader/dot_leader_html.rb
38
+ - lib/asciidoctor/dot_leader/dot_leader_inline_macro.rb
39
+ - lib/asciidoctor/dot_leader/dot_leader_pdf.rb
40
+ homepage: https://gitlab.com/baiyibai/asciidoctor-dot-leader
41
+ licenses:
42
+ - MIT
43
+ metadata:
44
+ source_code_uri: https://gitlab.com/baiyibai/asciidoctor-dot-leader.git
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 3.0.0
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.6.7
60
+ specification_version: 4
61
+ summary: Extension for asciidoctor (pdf and html) for creating dot leaders
62
+ test_files: []