przn 0.6.0 → 0.6.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: 56ed8d9e234041229585322f1f9aaf797365bbfe9bb929a07f99773c31cd3196
4
- data.tar.gz: 33e859f3378fe0283408c7868807948336b819a13856bb20ca7440da07a3c121
3
+ metadata.gz: bf3f41f00dfc08adebe854f3f009edd1b8e2e1fcdd904ec73cce7a5e2e59fbbe
4
+ data.tar.gz: 310bf650d376be4f1b9b7b5528519d70781cd2809de7de213c79f1618e2007a4
5
5
  SHA512:
6
- metadata.gz: d2ef79cbd2d70f062934e38ced0187edcd6d8fd9076361b2ec29ccbd057ca6c4cbc049a171adf94ca4a0fdee447e9f5df0f2a9cc7dd30343138b92672f7cb37b
7
- data.tar.gz: 38ad30e07a8e78f2e1b7898e0d07b4eddbf219ad723ac64246be0bdfe9a9d3cf59158230e1d199e745db03971a15e1bedb10847c06e2bae0f67e0e3958045d23
6
+ metadata.gz: cc467c11b19484f3bf4fdb66539f2877d7141658461051c0b87c0a845623c8677851817230caf4a87f990c4e42ae360ac1e8bc29f317a4e132e7f6e0472e24dc
7
+ data.tar.gz: deb83b4dac905ffed4dd37c0c6ac6991498952bec9e0f4d34cc0395db0c1a048a24e1d95baf1c56b9c7b40388ffc85a22e383e67b81cbedcc8f2f2f1f2d5b04b
data/README.md CHANGED
@@ -336,7 +336,7 @@ Rabbit-compatible kramdown form is also accepted: `{::at x="10" y="20"}content{:
336
336
  - **`Nc`** — same as plain integer; the `c` is explicit cells, useful when sitting next to an `<img>` that defaults the other way.
337
337
  - **`Npx`** — pixels. Converted to the cell containing that pixel (text can only land on cell boundaries, so a px value is rounded to its enclosing cell).
338
338
  - **`N%`** — percent of the terminal's current width / height. Auto-adjusts when the pane is resized.
339
- - **Alignment keywords** — `x="left"` / `"center"` / `"right"`, `y="top"` / `"center"` / `"bottom"` (`middle` is accepted as a synonym of `center` on both axes). The position resolves against the content's own rendered footprint — `x="center"` measures the widest `<br>`-split line at its actual rendered cell width and centres the whole block; `y="bottom"` sums each line's height (respecting inline `<size>` / `<font size>`) and pins the last line to the bottom edge. Mix and match: `<at x="center" y="bottom">caption</at>` drops the caption centered on the bottom row.
339
+ - **Alignment keywords** — `x="left"` / `"center"` / `"right"`, `y="top"` / `"center"` / `"bottom"` (`middle` is accepted as a synonym of `center` on both axes). The position resolves against the content's own rendered footprint — `x="center"` measures the widest `<br>`-split line at its actual rendered cell width and centres the whole block; in Echoes, a line that is a single run in a proportional face (the theme / slot `family`, or a `<font face>`) is instead centred by Echoes' pixel-precise halign, the same shortcut centred headings and paragraphs use, so Helvetica and friends land at the true centre rather than the cell-grid estimate; `y="bottom"` sums each line's height (respecting inline `<size>` / `<font size>`) and pins the last line to the bottom edge. Mix and match: `<at x="center" y="bottom">caption</at>` drops the caption centered on the bottom row.
340
340
  - Content is parsed inline, so all the usual styling works inside an `<at>` — `<size>`, `<color>`, `<font>`, `**bold**`, `*italic*`, etc.
341
341
  - The block doesn't take up vertical space in the slide's layout — paragraphs around it render in their normal positions and the absolute placement layers on top. Useful for overlaying labels on a `<bg .../>` gradient or pinning annotations to specific cells.
342
342
  - Out-of-range coordinates clamp into the visible area; missing / unparseable coordinates skip silently.
@@ -745,7 +745,7 @@ Notes:
745
745
  - **`font.size`** — OSC 66 scale; controls the visual size of body text (numeric `1`–`7` or named `xx-small` … `xxxx-large`). Default `2` (small). Inline `<size=...>` runs override it per-segment.
746
746
  - **`font.color`** — deck-wide default text color. Inline `<color=...>` / `<font color="...">` runs still win per-segment.
747
747
  - **`bullet`** — `bullet.text` is the character; `bullet.size` is the OSC 66 scale used to render it. When `bullet.size` is smaller than the body text scale, the bullet is rendered with fractional scaling and vertical centering so it still aligns with the body line. `bullet.color` sets a dedicated foreground color for the marker (named ANSI or 6-digit hex); when unset, the bullet inherits the body text color.
748
- - **`title`** — h1 typography. Same three knobs as `font` (`family`, `size`, `color`) but each is independent: `title.family` _(Echoes only)_ does **not** inherit `font.family`, `title.color` does **not** inherit `font.color`. `title.size` defaults to x-large (OSC 66 `s=4`). When `title.family` is set, h1 lines emit as one slot-spanning multicell with halign=2 so Echoes' proportional-font measurement centers the text pixel-precisely instead of using the cell-grid estimate. h2–h6 stay body text.
748
+ - **`title`** — h1 typography. Same three knobs as `font` (`family`, `size`, `color`) but each is independent: `title.family` _(Echoes only)_ does **not** inherit `font.family`, `title.color` does **not** inherit `font.color`. `title.size` defaults to x-large (OSC 66 `s=4`). When `title.family` is set and the h1 is centred (slot `x: center`), each line emits as one slot-spanning multicell with halign=2 so Echoes' proportional-font measurement centers the text pixel-precisely instead of using the cell-grid estimate; at a numeric slot `x:` the title is left-aligned at that column like any other block. h2–h6 stay body text.
749
749
  - **`code`** — fenced code block (and inline `<code>`) typography. `code.family` _(Echoes only)_ sets the OSC 66 `f=` face for code (falls back to `font.family` when unset, so a single body-font override usually styles code too); `code.size` is the OSC 66 scale (default = `font.size`); `code.color` is the foreground colour for **all** code text — fenced blocks and inline `<code>` alike — falling back to the body fg when unset; `code.bg` is the **fenced-block** background — accepts the same forms as `font.color` (CSS / ANSI named or 6-digit hex; default is dim gray, ANSI 256-color 236). Inline `<code>` segments in the **terminal** keep the historical gray-background styling for the bg; only fenced blocks read `code.bg`. `code.highlight` picks the syntax-highlight colour scheme: any Rouge theme name works — common picks are `monokai`, `gruvbox`, `github.dark`, `base16.solarized.dark`, `tulip`. Unset (the default) uses przn's built-in ANSI palette, which maps tokens to ANSI colour names and so picks up the user's terminal palette (handy on light terminals where absolute monokai-style hex would clash). Unknown / mistyped theme names silently fall through to the ANSI palette.
750
750
  - **`background`** _(Echoes only)_ — the deck-wide default background. A per-slide `<bg .../>` directive overrides it for that slide. The Prawn fallback paints the PDF page in `background.color` when set; otherwise it leaves the page Prawn's default (white).
751
751
  - **`counter`** — bottom-of-screen slide counter (hide it on a single slide with `# Title {counter=hide}`). Without `counter.duration`, przn shows a plain `N / M` counter at the bottom-right. Set `counter.duration` to opt into the Rabbit-style runner bar: current slide # at the very left, total at the very right, 🐇 running between them tracking slide progress and 🐢 tracking elapsed time against the goal. Drag the 🐇 with the mouse to jump to another slide. `counter.color` (named ANSI or 6-digit hex) styles both the plain counter and the runner-bar anchor numbers; default is dim ANSI. `counter.rabbit` and `counter.turtle` are the **raw escape sequences** the renderer writes at the two runner positions — the default theme ships an Echoes-private OSC 7772 `;multicell` with `flip=h` so the emojis face rightward (towards the right anchor); terminals that don't speak OSC 7772 silently drop the sequence and no runner glyph appears. To stay portable, override these with a plain glyph or a standard OSC 66 multicell — at the cost of the flip on Echoes.
data/lib/przn/renderer.rb CHANGED
@@ -1127,13 +1127,46 @@ module Przn
1127
1127
  # next line starts. Falls back to body_scale when a line
1128
1128
  # carries no explicit size, matching the pre-fix behavior.
1129
1129
  y_cursor = y
1130
+ centered = %w[center middle].include?(alignment_keyword(attrs[:x], :x))
1130
1131
  lines.zip(line_heights).each do |line_segs, line_h|
1131
- @terminal.move_to(y_cursor, x)
1132
- @terminal.write render_segments_scaled(line_segs, body_scale, line_height: line_h)
1132
+ if centered && (line = at_server_centered_line(line_segs))
1133
+ # Same shortcut as centered headings / paragraphs: a
1134
+ # proportional face makes the cell-grid `x` above land the
1135
+ # line well left of center (Helvetica digits are far narrower
1136
+ # than their cells), so hand the centering to Echoes' halign
1137
+ # inside a pane-spanning block instead.
1138
+ text, scale, face, color = line
1139
+ col, body = server_centered_emit(text, scale, face, @terminal.width)
1140
+ body = "#{color_code(color)}#{body}#{ANSI[:reset]}" if color && !color.to_s.empty?
1141
+ @terminal.move_to(y_cursor, col)
1142
+ @terminal.write body
1143
+ else
1144
+ @terminal.move_to(y_cursor, x)
1145
+ @terminal.write render_segments_scaled(line_segs, body_scale, line_height: line_h)
1146
+ end
1133
1147
  y_cursor += line_h
1134
1148
  end
1135
1149
  end
1136
1150
 
1151
+ # The `<at x="center">` lines Echoes should center itself (see
1152
+ # `server_centered_eligible?` for the reasoning): a bare text run in
1153
+ # a proportional theme / slot font, or a single `<font>` run that
1154
+ # carries or inherits a face. Returns `[text, scale, face, color]`,
1155
+ # or nil to keep the cell-grid path.
1156
+ def at_server_centered_line(line_segs)
1157
+ return nil unless KittyText.echoes? && line_segs.size == 1
1158
+ type, content, attrs = line_segs.first
1159
+ attrs ||= {}
1160
+ return nil unless type == :text || type == :font
1161
+
1162
+ face = (type == :font && attrs[:face]) || slot_family || @theme.font[:family]
1163
+ return nil if face.nil? || face.to_s.empty?
1164
+ scale = (type == :font && attrs[:size] && Parser::SIZE_SCALES[attrs[:size]]) || body_scale
1165
+ return nil unless scale > 0 && (@terminal.width.to_f / scale).floor >= 1
1166
+ color = (type == :font && attrs[:color]) || slot_color || @theme.font[:color]
1167
+ [content, scale, face, color]
1168
+ end
1169
+
1137
1170
  # `<at x|y="…">` extension over `resolve_at_coord` that adds the
1138
1171
  # keyword forms `left|center|right` (x-axis) and `top|center|bottom`
1139
1172
  # (y-axis). `middle` is accepted as a synonym of `center` for
@@ -1918,7 +1951,7 @@ module Przn
1918
1951
  vis = segments_visible_cells(line_segs, scale)
1919
1952
  pad = compute_pad(width, vis, align)
1920
1953
  term_move(row, pad + 1)
1921
- @terminal.write "#{ANSI[:bold]}#{render_segments_scaled(line_segs, scale, default_face: face, default_h: 2, default_color: color)}#{ANSI[:reset]}"
1954
+ @terminal.write "#{ANSI[:bold]}#{render_segments_scaled(line_segs, scale, default_face: face, default_h: heading_halign(align), default_color: color)}#{ANSI[:reset]}"
1922
1955
  end
1923
1956
  row += scale
1924
1957
  end
@@ -1949,6 +1982,19 @@ module Przn
1949
1982
  end
1950
1983
  end
1951
1984
 
1985
+ # OSC 66 `h=` for an h1 line drawn by the cell-grid path, so the
1986
+ # glyphs of a proportional `title.family` sit inside their reserved
1987
+ # cell block the way the line itself is aligned (Echoes: 1 = right,
1988
+ # 2 = center). A left / unaligned title gets no `h=` — the default
1989
+ # left placement is the right one, and h=2 would quietly center the
1990
+ # text inside a block that nearly spans the slot.
1991
+ def heading_halign(align)
1992
+ case align
1993
+ when :center then 2
1994
+ when :right then 1
1995
+ end
1996
+ end
1997
+
1952
1998
  def render_paragraph(block, width, row, align: nil)
1953
1999
  text = block[:content]
1954
2000
  # Two scales, not one:
@@ -2722,10 +2768,10 @@ module Przn
2722
2768
  # `<color=...>` runs still win for their own segments.
2723
2769
  #
2724
2770
  # `default_h:` threads an OSC 66 `h=` (horizontal alignment) into every
2725
- # emit on the line. h1 uses h=2 so a proportional `title.family` is
2726
- # centered within the reserved cell block — without it the glyphs left-
2727
- # align inside the block and the visible text drifts left of the center
2728
- # column we computed.
2771
+ # emit on the line. A centered h1 uses h=2 so a proportional
2772
+ # `title.family` is centered within the reserved cell block — without
2773
+ # it the glyphs left-align inside the block and the visible text drifts
2774
+ # left of the center column we computed.
2729
2775
  def render_segments_scaled(segments, para_scale, line_height: nil, default_face: :body, default_h: nil, default_color: :body)
2730
2776
  f = default_face == :body ? (slot_family || @theme.font[:family]) : default_face
2731
2777
  h = default_h
data/lib/przn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Przn
4
- VERSION = '0.6.0'
4
+ VERSION = '0.6.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: przn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Akira Matsuda