Skip to content

Commit

Permalink
fix: document source map cannot reactive original document update
Browse files Browse the repository at this point in the history
close #1814
  • Loading branch information
johnsoncodehk committed Sep 4, 2022
1 parent f87049a commit 2758510
Show file tree
Hide file tree
Showing 10 changed files with 40 additions and 45 deletions.
11 changes: 5 additions & 6 deletions packages/pug-language-service/src/pugDocument.ts
@@ -1,4 +1,4 @@
import { SourceMapBase, Mapping } from '@volar/source-map';
import { SourceMapBase } from '@volar/source-map';
import { TextDocument } from 'vscode-languageserver-textdocument';
import type * as html from 'vscode-html-languageservice';
import { baseParse } from './baseParse';
Expand All @@ -15,7 +15,7 @@ export function register(htmlLs: html.LanguageService) {
const sourceMap = new SourceMap(
parsed.pugTextDocument,
htmlTextDocument,
parsed.sourceMap.mappings,
parsed.sourceMap,
);
const htmlDocument = htmlLs.parseHTMLDocument(htmlTextDocument);

Expand All @@ -31,14 +31,13 @@ export function register(htmlLs: html.LanguageService) {
}

// TODO: reuse from vueDocuments.ts
export class SourceMap<Data = undefined> extends SourceMapBase<Data> {
export class SourceMap<Data = undefined> {

constructor(
public sourceDocument: TextDocument,
public mappedDocument: TextDocument,
public _mappings?: Mapping<Data>[],
public base: SourceMapBase<Data> = new SourceMapBase(),
) {
super(_mappings);
}

public getSourceRange<T extends number | vscode.Position>(start: T, end?: T, filter?: (data: Data) => boolean) {
Expand Down Expand Up @@ -68,7 +67,7 @@ export class SourceMap<Data = undefined> extends SourceMapBase<Data> {
const startOffset = startIsNumber ? start : fromDoc.offsetAt(start);
const endOffset = endIsNumber ? end : fromDoc.offsetAt(end);

for (const mapped of super.getRanges(startOffset, endOffset, sourceToTarget, filter)) {
for (const mapped of this.base.getRanges(startOffset, endOffset, sourceToTarget, filter)) {
yield getMapped(mapped);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/source-map/src/index.ts
Expand Up @@ -165,7 +165,7 @@ export class SourceMapBase<Data = undefined> {
return this.getRanges(start, end ?? start, true, filter);
}

protected * getRanges(startOffset: number, endOffset: number, sourceToTarget: boolean, filter?: (data: Data) => boolean) {
public * getRanges(startOffset: number, endOffset: number, sourceToTarget: boolean, filter?: (data: Data) => boolean) {

const memo = this.__memo.value;
const _memo = sourceToTarget ? memo.source : memo.mapped;
Expand Down
6 changes: 3 additions & 3 deletions packages/vue-language-service/src/documentFeatures/format.ts
Expand Up @@ -79,14 +79,14 @@ export function register(context: DocumentServiceRuntimeContext) {
let end = sourceMap.getMappedRange(range.end)?.[0].end;

if (!start) {
const minSourceStart = Math.min(...sourceMap.mappings.map(m => m.sourceRange.start));
const minSourceStart = Math.min(...sourceMap.base.mappings.map(m => m.sourceRange.start));
if (document.offsetAt(range.start) <= minSourceStart) {
start = range.start;
}
}

if (!end) {
const maxSourceEnd = Math.max(...sourceMap.mappings.map(m => m.sourceRange.end));
const maxSourceEnd = Math.max(...sourceMap.base.mappings.map(m => m.sourceRange.end));
if (document.offsetAt(range.end) >= maxSourceEnd) {
end = range.end;
}
Expand Down Expand Up @@ -252,7 +252,7 @@ function patchInterpolationIndent(vueDocument: VueDocument, sourceMap: EmbeddedD
const indentTextEdits: vscode.TextEdit[] = [];
const document = vueDocument.getDocument();

for (const mapped of sourceMap.mappings) {
for (const mapped of sourceMap.base.mappings) {

const textRange = {
start: document.positionAt(mapped.sourceRange.start),
Expand Down
Expand Up @@ -49,7 +49,7 @@ export function register(context: LanguageServiceRuntimeContext) {
let minStart: number | undefined;
let maxEnd: number | undefined;

for (const mapping of sourceMap.mappings) {
for (const mapping of sourceMap.base.mappings) {
const overlapRange = shared.getOverlapRange2(offsetRange, mapping.sourceRange);
if (overlapRange) {
const embeddedRange = sourceMap.getMappedRange(overlapRange.start, overlapRange.end)?.[0];
Expand Down
Expand Up @@ -44,7 +44,7 @@ export function register(context: LanguageServiceRuntimeContext) {

for (const sourceMap of vueDocument.getSourceMaps()) {

for (const mapped of sourceMap.mappings) {
for (const mapped of sourceMap.base.mappings) {

if (!mapped.data.capabilities.displayWithLink)
continue;
Expand Down
Expand Up @@ -35,7 +35,7 @@ export function register(context: LanguageServiceRuntimeContext) {
end: number,
} | undefined;

for (const mapping of sourceMap.mappings) {
for (const mapping of sourceMap.base.mappings) {

if (cancleToken?.isCancellationRequested)
return;
Expand Down
Expand Up @@ -34,7 +34,7 @@ export function register(context: LanguageServiceRuntimeContext) {
let minStart: number | undefined;
let maxEnd: number | undefined;

for (const mapping of sourceMap.mappings) {
for (const mapping of sourceMap.base.mappings) {
const overlapRange = shared.getOverlapRange2(offsetRange, mapping.sourceRange);
if (overlapRange) {
const embeddedRange = sourceMap.getMappedRange(overlapRange.start, overlapRange.end)?.[0];
Expand Down
8 changes: 1 addition & 7 deletions packages/vue-language-service/src/languageService.ts
Expand Up @@ -197,15 +197,9 @@ export function createLanguageService(
const scriptTsPlugin = useTsPlugins(
tsLs,
false,
uri => (uri.indexOf('.__VLS_template') === -1 ? {
uri => ({
// includeCompletionsForModuleExports: true, // set in server/src/tsConfigs.ts
includeCompletionsWithInsertText: true, // if missing, { 'aaa-bbb': any, ccc: any } type only has result ['ccc']
} : {
// includeCompletionsForModuleExports: true, // set in server/src/tsConfigs.ts
includeCompletionsWithInsertText: true, // if missing, { 'aaa-bbb': any, ccc: any } type only has result ['ccc']
quotePreference: 'single',
includeCompletionsForModuleExports: false,
includeCompletionsForImportStatements: false,
}),
);
const autoDotValuePlugin = useAutoDotValuePlugin({
Expand Down
Expand Up @@ -34,7 +34,7 @@ export default function (options: {
const result: vscode.CodeLens[] = [];

for (const sourceMap of vueDocument.getSourceMaps()) {
for (const mapping of sourceMap.mappings) {
for (const mapping of sourceMap.base.mappings) {

if (!mapping.data.capabilities.referencesCodeLens)
continue;
Expand Down
48 changes: 25 additions & 23 deletions packages/vue-language-service/src/vueDocuments.ts
@@ -1,7 +1,7 @@
import * as vue from '@volar/vue-language-core';
import * as shared from '@volar/shared';
import { computed } from '@vue/reactivity';
import { SourceMapBase, Mapping } from '@volar/source-map';
import { computed, ComputedRef } from '@vue/reactivity';
import { SourceMapBase } from '@volar/source-map';
import { TextDocument } from 'vscode-languageserver-textdocument';
import { EmbeddedFileMappingData, TeleportMappingData, TeleportSideData } from '@volar/vue-language-core';
import { walkElementNodes } from '@volar/vue-language-core';
Expand All @@ -20,14 +20,13 @@ export interface ITemplateScriptData {
componentItems: vscode.CompletionItem[];
}

export class SourceMap<Data = undefined> extends SourceMapBase<Data> {
export class SourceMap<Data = undefined> {

constructor(
public sourceDocument: TextDocument,
public mappedDocument: TextDocument,
public _mappings?: Mapping<Data>[],
public base: SourceMapBase<Data> = new SourceMapBase(),
) {
super(_mappings);
}

public getSourceRange<T extends number | vscode.Position>(start: T, end?: T, filter?: (data: Data) => boolean) {
Expand Down Expand Up @@ -57,7 +56,7 @@ export class SourceMap<Data = undefined> extends SourceMapBase<Data> {
const startOffset = startIsNumber ? start : fromDoc.offsetAt(start);
const endOffset = endIsNumber ? end : fromDoc.offsetAt(end);

for (const mapped of super.getRanges(startOffset, endOffset, sourceToTarget, filter)) {
for (const mapped of this.base.getRanges(startOffset, endOffset, sourceToTarget, filter)) {
yield getMapped(mapped);
}

Expand All @@ -81,7 +80,7 @@ export class EmbeddedDocumentSourceMap extends SourceMap<EmbeddedFileMappingData
public mappedDocument: TextDocument,
_sourceMap: vue.EmbeddedFileSourceMap,
) {
super(sourceDocument, mappedDocument, _sourceMap.mappings);
super(sourceDocument, mappedDocument, _sourceMap);
}
}

Expand All @@ -91,7 +90,7 @@ export class TeleportSourceMap extends SourceMap<TeleportMappingData> {
public document: TextDocument,
teleport: vue.Teleport,
) {
super(document, document, teleport.mappings);
super(document, document, teleport);
}
*findTeleports(start: vscode.Position, end?: vscode.Position, filter?: (data: TeleportSideData) => boolean) {
for (const [teleRange, data] of this.getMappedRanges(start, end, filter ? data => filter(data.toTarget) : undefined)) {
Expand Down Expand Up @@ -181,7 +180,7 @@ export function parseVueDocuments(

if (sourceMap) {

if (sourceMapFilter && !sourceMapFilter(sourceMap))
if (sourceMapFilter && !sourceMapFilter(sourceMap.base))
return;

for (const vueRange of sourceMap.getSourceRanges(start, end, filter)) {
Expand Down Expand Up @@ -216,9 +215,14 @@ export function parseVueDocument(
tsLs: ts2.LanguageService | undefined,
) {

// cache map
let documentVersion = 0;
let templateScriptData: ITemplateScriptData = {
components: [],
componentItems: [],
};
const embeddedDocumentVersions = new Map<string, number>();

// cache map
const embeddedDocumentsMap = useCacheMap<vue.EmbeddedFile, TextDocument>(embeddedFile => {

const uri = shared.getUriByPath(rootUri, embeddedFile.fileName);
Expand All @@ -241,20 +245,21 @@ export function parseVueDocument(
embedded.sourceMap,
);
});
let templateScriptData: ITemplateScriptData = {
components: [],
componentItems: [],
};

// reactivity
// computed
const document = computed(() => TextDocument.create(
shared.getUriByPath(rootUri, vueFile.fileName),
vueFile.fileName.endsWith('.md') ? 'markdown' : 'vue',
documentVersion++,
vueFile.text,
));
const sourceMaps = computed(() => {
return vueFile.allEmbeddeds.map(embedded => sourceMapsMap.get(embedded));
return vueFile.allEmbeddeds.map(embedded => new EmbeddedDocumentSourceMap(
embedded.file,
document.value,
embeddedDocumentsMap.get(embedded.file),
embedded.sourceMap,
));
});
const teleports = computed(() => {
return vueFile.teleports.map(teleportAndFile => {
Expand Down Expand Up @@ -319,7 +324,6 @@ export function parseVueDocument(
getTemplateTagsAndAttrs: () => templateTagsAndAttrs.value,
};


async function getTemplateData() {

const options: ts.GetCompletionsAtPositionOptions = {
Expand Down Expand Up @@ -355,11 +359,9 @@ export function parseVueDocument(
}
}

export function useCacheMap<T extends object, K>(
parse: (t: T) => K,
) {
export function useCacheMap<T extends object, K>(parse: (t: T) => K) {

const cache = new WeakMap<T, K>();
const cache = new WeakMap<T, ComputedRef<K>>();

return {
get,
Expand All @@ -371,10 +373,10 @@ export function useCacheMap<T extends object, K>(

if (!result) {

result = parse(source);
result = computed(() => parse(source));
cache.set(source, result);
}

return result;
return result.value;
}
}

0 comments on commit 2758510

Please sign in to comment.