66 lines
2.7 KiB
TypeScript
66 lines
2.7 KiB
TypeScript
import type { SqlTextRange } from "@/lib/sql/sqlStatementRanges";
|
|
import { trailingStatementDelimiterPosition, type StatementDelimiterDocument } from "@/lib/sql/statementDelimiter";
|
|
|
|
export function currentStatementFrameRangeTo(doc: StatementDelimiterDocument, range: SqlTextRange): number {
|
|
const delimiterPos = trailingStatementDelimiterPosition(doc, range.to);
|
|
return delimiterPos === null ? range.to : delimiterPos + 1;
|
|
}
|
|
|
|
export function shouldRebuildCurrentStatementFrame(update: { docChanged: boolean; selectionSet: boolean; configurationChanged: boolean }): boolean {
|
|
return update.docChanged || update.selectionSet || update.configurationChanged;
|
|
}
|
|
|
|
export function visualSqlColumns(text: string): number {
|
|
let columns = 0;
|
|
for (const ch of text) {
|
|
if (ch === "\t") {
|
|
columns += 4;
|
|
} else if (isWideSqlChar(ch)) {
|
|
columns += 2;
|
|
} else {
|
|
columns += 1;
|
|
}
|
|
}
|
|
return columns;
|
|
}
|
|
|
|
export function isWideSqlChar(ch: string): boolean {
|
|
return /[\u1100-\u115f\u2329\u232a\u2e80-\u303e\u3040-\ua4cf\uac00-\ud7a3\uf900-\ufaff\ufe10-\ufe19\ufe30-\ufe6f\uff00-\uff60\uffe0-\uffe6]/u.test(ch);
|
|
}
|
|
|
|
/** Approximate visual columns for a `.cm-insert-value-hint` widget (0.85em text + padding/margin). */
|
|
export function estimateInlineHintVisualColumns(label: string): number {
|
|
// Slightly generous vs CSS (0.85em font + 0.3em*2 padding + 0.35em margin) so the
|
|
// statement frame does not clip past inlay hints.
|
|
return Math.max(2, Math.ceil(label.length * 0.9 + 2.2));
|
|
}
|
|
|
|
export interface InlineHintForFrameWidth {
|
|
from: number;
|
|
column: string;
|
|
}
|
|
|
|
/** Document text columns plus inline widget hints that sit on `[lineFrom, lineTo)`. */
|
|
export function visualSqlColumnsWithInlineHints(text: string, lineFrom: number, lineTo: number, hints: readonly InlineHintForFrameWidth[] = []): number {
|
|
let columns = visualSqlColumns(text);
|
|
const seen = new Set<number>();
|
|
for (const hint of hints) {
|
|
if (hint.from < lineFrom || hint.from >= lineTo) continue;
|
|
if (seen.has(hint.from)) continue;
|
|
seen.add(hint.from);
|
|
columns += estimateInlineHintVisualColumns(hint.column);
|
|
}
|
|
return columns;
|
|
}
|
|
|
|
/** Measure rendered line width in CSS pixels, including inline widgets already in the DOM. */
|
|
export function measureSqlLineWidthPx(view: { coordsAtPos: (pos: number, side?: -1 | 1) => { left: number; right: number; top: number; bottom: number } | null }, from: number, to: number): number | null {
|
|
if (to < from) return null;
|
|
const start = view.coordsAtPos(from, 1);
|
|
const end = view.coordsAtPos(to, -1);
|
|
if (!start || !end) return null;
|
|
// Ignore cross-line measurements (wrapping / mismatched sides).
|
|
if (Math.abs(start.top - end.top) > 2) return null;
|
|
return Math.max(0, end.right - start.left);
|
|
}
|