Skip to content

Virtual File

import type { CodeMapping, Mapping, VirtualCode } from '@volar/language-core';
import type ts from 'typescript';
import { getChunkInfoDict } from './parsers.ts.md';
export class TsMdVirtualFile implements VirtualCode {
id!: string;
languageId = 'markdown';
mappings: CodeMapping[] = [];
embeddedCodes: VirtualCode[] = [];
linkedCodeMappings: Mapping[] = [];
constructor(
public snapshot: ts.IScriptSnapshot,
public uri: string,
private dict: Record<string, string>,
) {
this.id = uri;
this.refreshEmbedded();
}
/** Markdown が更新された時に呼ぶ */
update(snapshot: ts.IScriptSnapshot, dict: Record<string, string>) {
this.snapshot = snapshot;
this.dict = dict;
this.refreshEmbedded();
}
private refreshEmbedded() {
const infoDict = getChunkInfoDict(this.snapshot, this.uri);
this.embeddedCodes = [];
this.linkedCodeMappings = [];
this.dict = {};
this.mappings = [
{
sourceOffsets: [0],
generatedOffsets: [0],
lengths: [this.snapshot.getLength()],
data: {
completion: true,
format: true,
navigation: true,
semantic: true,
structure: true,
verification: true,
},
},
];
for (const [name, info] of Object.entries(infoDict)) {
const { code, start } = info;
this.dict[name] = code;
this.embeddedCodes.push({
id: `${this.uri}__${name}.ts`,
languageId: 'ts',
mappings: [],
linkedCodeMappings: [
{
sourceOffsets: [0],
generatedOffsets: [start],
lengths: [code.length],
generatedLengths: [code.length],
data: {},
},
],
snapshot: {
getText: (s, e) => code.slice(s, e),
getLength: () => code.length,
getChangeRange: () => undefined,
},
});
this.linkedCodeMappings.push({
sourceOffsets: [start],
generatedOffsets: [0],
lengths: [code.length],
generatedLengths: [code.length],
data: {},
});
}
}
}