From 84578a5dd9e17f63217827027aedf0845c85cdb8 Mon Sep 17 00:00:00 2001 From: hazre Date: Thu, 5 Feb 2026 22:49:51 +0100 Subject: [PATCH] fix: respect fractional line height in previews --- src/editor/preview-style.ts | 36 ++++++++++++++++++ src/editor/syntax-highlight-renderer.ts | 49 ++++++++++++++++--------- 2 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 src/editor/preview-style.ts diff --git a/src/editor/preview-style.ts b/src/editor/preview-style.ts new file mode 100644 index 0000000..6737d49 --- /dev/null +++ b/src/editor/preview-style.ts @@ -0,0 +1,36 @@ +export interface PreviewBoxStyleInput { + lineCount: number; + maxLineLength: number; + fontSize: number; + lineHeight: number; + marginLeftPx?: number; +} + +export function resolveLineHeight( + fontSize: number, + lineHeightSetting: number, +): number { + if (lineHeightSetting > 0) { + if (lineHeightSetting < fontSize) { + return Math.ceil(fontSize * lineHeightSetting); + } + return Math.ceil(lineHeightSetting); + } + return Math.ceil(fontSize * 1.35); +} + +export function computePreviewBoxStyle({ + lineCount, + maxLineLength, + fontSize, + lineHeight, + marginLeftPx = 12, +}: PreviewBoxStyleInput): string { + const safeLines = Math.max(1, lineCount); + const safeLineHeight = Math.max(1, lineHeight); + const charWidth = fontSize * 0.6; + const width = Math.max(1, Math.ceil(maxLineLength * charWidth)); + const height = safeLines * safeLineHeight; + + return `none; display: inline-block; vertical-align: top; height: ${height}px; width: ${width}px; margin-left: ${marginLeftPx}px`; +} diff --git a/src/editor/syntax-highlight-renderer.ts b/src/editor/syntax-highlight-renderer.ts index 6f76a07..996562e 100644 --- a/src/editor/syntax-highlight-renderer.ts +++ b/src/editor/syntax-highlight-renderer.ts @@ -32,6 +32,10 @@ import type { ThemeRegistrationAny } from "@shikijs/types"; import type { IRawThemeSetting } from "@shikijs/vscode-textmate"; import * as vscode from "vscode"; import { z } from "zod"; +import { + computePreviewBoxStyle, + resolveLineHeight, +} from "~/editor/preview-style.ts"; const ALL_LANGS = [ ...langBash, @@ -572,10 +576,10 @@ function renderSyntaxHighlightedSvgFromLines( cachePrefix: string, ): vscode.Uri { const settings = getEditorFontSettings(); - const lineHeight = - settings.lineHeight > 0 - ? settings.lineHeight - : Math.ceil(settings.fontSize * 1.35); + const lineHeight = resolveLineHeight( + settings.fontSize, + settings.lineHeight, + ); const fontSize = settings.fontSize; const textY = Math.ceil(lineHeight - settings.fontSize * 0.25); const charWidth = settings.fontSize * 0.6; @@ -672,7 +676,6 @@ function renderSyntaxHighlightedSvgFromLines( .slice(0, 16); const svgPath = path.join(getSvgCacheDir(), `${cachePrefix}-${hash}.svg`); fs.writeFileSync(svgPath, svg, "utf8"); - return vscode.Uri.file(svgPath); } @@ -737,13 +740,23 @@ export function createHighlightedBoxDecoration( dark, highlightRanges, ); - + const settings = getEditorFontSettings(); + const lineHeight = resolveLineHeight( + settings.fontSize, + settings.lineHeight, + ); + const boxStyle = computePreviewBoxStyle({ + lineCount: 1, + maxLineLength: text.length, + fontSize: settings.fontSize, + lineHeight, + }); return { range, renderOptions: { after: { contentIconPath: svgUri, - textDecoration: buildBoxTextDecoration("-40%"), + textDecoration: boxStyle, }, }, }; @@ -763,22 +776,24 @@ export function createHighlightedBoxDecorationMultiline( highlightRangesByLine, ); const settings = getEditorFontSettings(); - const lineHeight = - settings.lineHeight > 0 - ? settings.lineHeight - : Math.ceil(settings.fontSize * 1.35); - + const lineHeight = resolveLineHeight( + settings.fontSize, + settings.lineHeight, + ); + const maxLineLength = Math.max(1, ...lines.map((line) => line.length)); + const boxStyle = computePreviewBoxStyle({ + lineCount: Math.max(1, lines.length), + maxLineLength, + fontSize: settings.fontSize, + lineHeight, + }); return { range, renderOptions: { after: { contentIconPath: svgUri, - textDecoration: buildBoxTextDecoration(`-${lineHeight / 2}px`), + textDecoration: boxStyle, }, }, }; } - -function buildBoxTextDecoration(translateY: string): string { - return `none; position: absolute; top: 50%; transform: translateY(${translateY}); margin-left: 12px`; -}