import { affineTextStyles } from '@blocksuite/affine-shared/styles'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import { ShadowlessElement } from '@blocksuite/std'; import { ZERO_WIDTH_SPACE } from '@blocksuite/std/inline'; import type { DeltaInsert } from '@blocksuite/store'; import { html } from 'lit'; import { property } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; import type { ThemedToken } from 'shiki'; export class AffineCodeUnit extends ShadowlessElement { get codeBlock() { return this.closest('affine-code'); } get vElement() { return this.closest('v-element'); } override render() { if (this.delta.attributes?.link && this.codeBlock) { return html``; } let style = this.delta.attributes ? affineTextStyles(this.delta.attributes) : {}; if (this.delta.attributes?.code) { style = { ...style, 'font-size': 'calc(var(--affine-font-base) - 3px)', padding: '0px 4px 2px', }; } const plainContent = html``; const codeBlock = this.codeBlock; const vElement = this.vElement; if (!codeBlock || !vElement) return plainContent; const tokens = codeBlock.highlightTokens$.value; if (tokens.length === 0) return plainContent; // copy the tokens to avoid modifying the original tokens const lineTokens = structuredClone(tokens[vElement.lineIndex]); if (lineTokens.length === 0) return plainContent; const startOffset = vElement.startOffset; const endOffset = vElement.endOffset; const includedTokens: ThemedToken[] = []; lineTokens.forEach(token => { if ( (token.offset <= startOffset && token.offset + token.content.length >= startOffset) || (token.offset >= startOffset && token.offset + token.content.length <= endOffset) || (token.offset <= endOffset && token.offset + token.content.length >= endOffset) ) { includedTokens.push(token); } }); if (includedTokens.length === 0) return plainContent; if (includedTokens.length === 1) { const token = includedTokens[0]; const content = token.content.slice( startOffset - token.offset, endOffset - token.offset ); return html``; } else { const firstToken = includedTokens[0]; const lastToken = includedTokens[includedTokens.length - 1]; const firstContent = firstToken.content.slice( startOffset - firstToken.offset, firstToken.content.length ); const lastContent = lastToken.content.slice( 0, endOffset - lastToken.offset ); firstToken.content = firstContent; lastToken.content = lastContent; const vTexts = includedTokens.map(token => { return html``; }); return html`${vTexts}`; } } @property({ type: Object }) accessor delta: DeltaInsert = { insert: ZERO_WIDTH_SPACE, }; } declare global { interface HTMLElementTagNameMap { 'affine-code-unit': AffineCodeUnit; } }