carve-hexapdf 0.1.3 → 0.1.5
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 +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +3 -0
- data/lib/carve/hexapdf/renderer.rb +41 -7
- data/lib/carve/hexapdf/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 52d77d202d7f1390346e49475aa665563e045e3bcf0c411bfb10a0d99c800070
|
|
4
|
+
data.tar.gz: 74687ef32c19f1969dff555ace0311b406c65aecb2b7ea0fa6c5eeced9977b3c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 718e37565452624372860471353c73c80b26566e603d62b60912d2dba8ec5b99555c2671c7663ddc42dac18b88c620b091490908eb756f2c1277bf1a7f0ea731
|
|
7
|
+
data.tar.gz: 11b5129dd95d3f1ffd4260a136f6c842a381d4286fcaedac400ff53ca25b49b084e3d6f58c725b8a56d74dc29343149307c42ae586308b91701b546250302ef0
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.5] - 2026-10-24
|
|
11
|
+
|
|
12
|
+
Ruby interchange text now appears in rendered PDFs, and tables with span markers render without a PDF layout error.
|
|
13
|
+
|
|
14
|
+
### Fixes
|
|
15
|
+
|
|
16
|
+
- Ruby base text and annotations render together instead of losing the annotation (#58).
|
|
17
|
+
- Tables with ownerless span markers or a header rowspan crossing into body rows render without a PDF layout error (#60).
|
|
18
|
+
|
|
19
|
+
**Full Changelog**: https://github.com/markup-carve/carve-hexapdf/compare/v0.1.4...v0.1.5
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## [0.1.4] - 2026-10-23
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- A table continuation row (`+ x |`) joins its cell with one space, as the spec
|
|
27
|
+
renders it; the two halves used to run together (`1x`) (#54).
|
|
28
|
+
- A CriticMarkup substitution reaches the page on carve-lang 0.1.3 and older,
|
|
29
|
+
which publish its halves as `oldText`/`newText` strings; both halves used to
|
|
30
|
+
be dropped (#55).
|
|
31
|
+
|
|
10
32
|
## [0.1.3] - 2026-10-08
|
|
11
33
|
|
|
12
34
|
### Fixed
|
data/README.md
CHANGED
|
@@ -54,6 +54,9 @@ ast = Carve.parse("# From AST")
|
|
|
54
54
|
pdf_bytes = Carve::Hexapdf.render_ast(ast)
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
For interchange `ruby` nodes, PDF text shows each pair as
|
|
58
|
+
`base(annotation)`, including `()` when the annotation is empty.
|
|
59
|
+
|
|
57
60
|
### Includes
|
|
58
61
|
|
|
59
62
|
A Carve document can pull another file in with `{{ path }}`. A String has no
|
|
@@ -429,7 +429,9 @@ module Carve
|
|
|
429
429
|
resolved = resolve_spans(Array(node[:rows]))
|
|
430
430
|
return if resolved.empty?
|
|
431
431
|
|
|
432
|
-
|
|
432
|
+
# HexaPDF cannot repeat a header whose cell spans into the body.
|
|
433
|
+
header_count = resolved.first.any? { |o| o[:header] } &&
|
|
434
|
+
resolved.first.none? { |o| o[:row_span] > 1 } ? 1 : 0
|
|
433
435
|
table_style = style_for("table")
|
|
434
436
|
header_style = style_for("table.header")
|
|
435
437
|
|
|
@@ -478,8 +480,17 @@ module Carve
|
|
|
478
480
|
case cell[:span]
|
|
479
481
|
when "colspan"
|
|
480
482
|
owner = last || col_owner[col - 1]
|
|
481
|
-
|
|
482
|
-
|
|
483
|
+
if owner
|
|
484
|
+
owner[:col_span] += 1
|
|
485
|
+
col_owner[col] = owner
|
|
486
|
+
else
|
|
487
|
+
# A leading marker has no cell to extend. Keep its grid slot
|
|
488
|
+
# so the table has a drawable cell in this row.
|
|
489
|
+
o = { cell: cell, header: cell[:header], col_span: 1, row_span: 1 }
|
|
490
|
+
emitted << o
|
|
491
|
+
last = o
|
|
492
|
+
col_owner[col] = o
|
|
493
|
+
end
|
|
483
494
|
when "rowspan"
|
|
484
495
|
owner = col_owner[col]
|
|
485
496
|
# A multi-column cell has one `^` per covered column on the next
|
|
@@ -488,8 +499,12 @@ module Carve
|
|
|
488
499
|
owner[:row_span] += 1
|
|
489
500
|
bumped[owner.object_id] = true
|
|
490
501
|
end
|
|
491
|
-
|
|
492
|
-
|
|
502
|
+
if owner.nil?
|
|
503
|
+
o = { cell: cell, header: cell[:header], col_span: 1, row_span: 1 }
|
|
504
|
+
emitted << o
|
|
505
|
+
col_owner[col] = o
|
|
506
|
+
end
|
|
507
|
+
# A valid owner's slot remains available for further `^` rows.
|
|
493
508
|
else
|
|
494
509
|
o = { cell: cell, header: cell[:header], col_span: 1, row_span: 1 }
|
|
495
510
|
emitted << o
|
|
@@ -514,6 +529,8 @@ module Carve
|
|
|
514
529
|
case node[:type]
|
|
515
530
|
when "text" then out << run(node[:value].to_s, ctx)
|
|
516
531
|
when "soft_break" then out << run(" ", ctx)
|
|
532
|
+
# A `+` continuation row join; the spec renders it as one space.
|
|
533
|
+
when "cell_wrap" then out << run(" ", ctx)
|
|
517
534
|
when "hard_break" then out << { text: "\n" }
|
|
518
535
|
# Each emphasis sort is its OWN node type. They used to be one
|
|
519
536
|
# `emphasis` node carrying a `kind`, so a profile could not deny bold
|
|
@@ -587,9 +604,18 @@ module Carve
|
|
|
587
604
|
# Both halves are inline arrays, and both reach the page: struck for the
|
|
588
605
|
# replaced run, underlined for the replacement, which is what the
|
|
589
606
|
# reference ANSI and HTML renderers show.
|
|
607
|
+
# carve-lang 0.1.3 and older publish the halves as `oldText`/`newText`
|
|
608
|
+
# strings; the gemspec floor still admits those engines.
|
|
590
609
|
when "substitution"
|
|
591
|
-
|
|
592
|
-
|
|
610
|
+
emit_half(node[:old], node[:oldText], ctx.merge(strike: true), out)
|
|
611
|
+
emit_half(node[:new], node[:newText], ctx.merge(underline: true), out)
|
|
612
|
+
when "ruby"
|
|
613
|
+
Array(node[:pairs]).each do |pair|
|
|
614
|
+
Array(pair[:base]).each { |part| emit_inline(part, ctx, out) }
|
|
615
|
+
out << run("(", ctx)
|
|
616
|
+
Array(pair[:annotation]).each { |part| emit_inline(part, ctx, out) }
|
|
617
|
+
out << run(")", ctx)
|
|
618
|
+
end
|
|
593
619
|
when "smart_punctuation" then out << run(smart_punctuation_text(node), ctx)
|
|
594
620
|
# A character the author escaped. The backslash is authoring syntax, so
|
|
595
621
|
# the page shows the character - but the node has no children, so
|
|
@@ -646,6 +672,14 @@ module Carve
|
|
|
646
672
|
Array(node[:children]).each { |c| emit_inline(c, ctx, out) }
|
|
647
673
|
end
|
|
648
674
|
|
|
675
|
+
def emit_half(inlines, text, ctx, out)
|
|
676
|
+
if inlines.nil? && text
|
|
677
|
+
out << run(text.to_s, ctx)
|
|
678
|
+
else
|
|
679
|
+
emit_children({ children: inlines }, ctx, out)
|
|
680
|
+
end
|
|
681
|
+
end
|
|
682
|
+
|
|
649
683
|
# Styling for one emphasis node.
|
|
650
684
|
#
|
|
651
685
|
# `/*both*/` is a single `strong` node carrying `boldItalic`, not a
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: carve-hexapdf
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- markup-carve
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: carve-lang
|