mirror of
https://github.com/Microsoft/vscode
synced 2024-10-12 06:17:18 +00:00
Fix references to header to return just the span of the header itself and not its body
This commit is contained in:
parent
464e50f207
commit
e32a13be77
|
@ -58,7 +58,7 @@ export class MdDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
|
|||
this.getSymbolName(entry),
|
||||
vscode.SymbolKind.String,
|
||||
'',
|
||||
entry.location);
|
||||
entry.sectionLocation);
|
||||
}
|
||||
|
||||
private toDocumentSymbol(entry: TocEntry) {
|
||||
|
@ -66,8 +66,8 @@ export class MdDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
|
|||
this.getSymbolName(entry),
|
||||
'',
|
||||
vscode.SymbolKind.String,
|
||||
entry.location.range,
|
||||
entry.location.range);
|
||||
entry.sectionLocation.range,
|
||||
entry.sectionLocation.range);
|
||||
}
|
||||
|
||||
private getSymbolName(entry: TocEntry): string {
|
||||
|
|
|
@ -57,7 +57,7 @@ export class MdFoldingProvider implements vscode.FoldingRangeProvider {
|
|||
private async getHeaderFoldingRanges(document: SkinnyTextDocument) {
|
||||
const toc = await TableOfContents.create(this.engine, document);
|
||||
return toc.entries.map(entry => {
|
||||
let endLine = entry.location.range.end.line;
|
||||
let endLine = entry.sectionLocation.range.end.line;
|
||||
if (document.lineAt(endLine).isEmptyOrWhitespace && endLine >= entry.line + 1) {
|
||||
endLine = endLine - 1;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ function isLinkToHeader(target: LinkTarget, header: TocEntry, headerDocument: vs
|
|||
|
||||
|
||||
export interface MdReference {
|
||||
readonly isTriggerLocation: boolean;
|
||||
readonly isDefinition: boolean;
|
||||
readonly location: vscode.Location;
|
||||
}
|
||||
|
@ -41,25 +42,27 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
}
|
||||
|
||||
async provideReferences(document: SkinnyTextDocument, position: vscode.Position, context: vscode.ReferenceContext, token: vscode.CancellationToken): Promise<vscode.Location[] | undefined> {
|
||||
const toc = await TableOfContents.create(this.engine, document);
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const header = toc.entries.find(entry => entry.line === position.line);
|
||||
|
||||
let allRefs: MdReference[];
|
||||
if (header) {
|
||||
allRefs = await this.getReferencesToHeader(document, header);
|
||||
} else {
|
||||
allRefs = await this.getReferencesToLinkAtPosition(document, position);
|
||||
}
|
||||
const allRefs = await this.getAllReferences(document, position, token);
|
||||
|
||||
return allRefs
|
||||
.filter(ref => context.includeDeclaration || !ref.isDefinition)
|
||||
.map(ref => ref.location);
|
||||
}
|
||||
|
||||
public async getAllReferences(document: SkinnyTextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<MdReference[]> {
|
||||
const toc = await TableOfContents.create(this.engine, document);
|
||||
if (token.isCancellationRequested) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const header = toc.entries.find(entry => entry.line === position.line);
|
||||
if (header) {
|
||||
return this.getReferencesToHeader(document, header);
|
||||
} else {
|
||||
return this.getReferencesToLinkAtPosition(document, position);
|
||||
}
|
||||
}
|
||||
|
||||
private async getReferencesToHeader(document: SkinnyTextDocument, header: TocEntry): Promise<MdReference[]> {
|
||||
const links = (await this._linkCache.getAll()).flat();
|
||||
|
||||
|
@ -67,6 +70,7 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
|
||||
const line = document.lineAt(header.line);
|
||||
references.push({
|
||||
isTriggerLocation: true,
|
||||
isDefinition: true,
|
||||
location: new vscode.Location(document.uri, new vscode.Range(header.line, 0, header.line, line.text.length)),
|
||||
});
|
||||
|
@ -74,11 +78,13 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
for (const link of links) {
|
||||
if (isLinkToHeader(link.target, header, document.uri, this.slugifier)) {
|
||||
references.push({
|
||||
isTriggerLocation: false,
|
||||
isDefinition: false,
|
||||
location: new vscode.Location(link.sourceResource, link.sourceRange)
|
||||
});
|
||||
} else if (link.target.kind === 'definition' && isLinkToHeader(link.target.target, header, document.uri, this.slugifier)) {
|
||||
references.push({
|
||||
isTriggerLocation: false,
|
||||
isDefinition: false,
|
||||
location: new vscode.Location(link.sourceResource, link.sourceRange)
|
||||
});
|
||||
|
@ -124,7 +130,11 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
const toc = await TableOfContents.create(this.engine, targetDoc);
|
||||
const entry = toc.lookup(sourceLink.target.fragment);
|
||||
if (entry) {
|
||||
references.push({ isDefinition: true, location: entry.location });
|
||||
references.push({
|
||||
isTriggerLocation: false,
|
||||
isDefinition: true,
|
||||
location: entry.headerLocation,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,15 +150,25 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
continue;
|
||||
}
|
||||
|
||||
const isTriggerLocation = sourceLink.sourceResource.fsPath === link.sourceResource.fsPath && sourceLink.sourceRange.isEqual(link.sourceRange);
|
||||
|
||||
if (sourceLink.target.fragment) {
|
||||
if (this.slugifier.fromHeading(link.target.fragment).equals(this.slugifier.fromHeading(sourceLink.target.fragment))) {
|
||||
references.push({ isDefinition: false, location: new vscode.Location(link.sourceResource, link.sourceRange) });
|
||||
references.push({
|
||||
isTriggerLocation,
|
||||
isDefinition: false,
|
||||
location: new vscode.Location(link.sourceResource, link.sourceRange),
|
||||
});
|
||||
}
|
||||
} else { // Triggered on a link without a fragment so we only require matching the file and ignore fragments
|
||||
|
||||
// But exclude cases where the file is referencing itself
|
||||
if (link.sourceResource.fsPath !== targetDoc.uri.fsPath) {
|
||||
references.push({ isDefinition: false, location: new vscode.Location(link.sourceResource, link.sourceRange) });
|
||||
references.push({
|
||||
isTriggerLocation,
|
||||
isDefinition: false,
|
||||
location: new vscode.Location(link.sourceResource, link.sourceRange),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -156,14 +176,17 @@ export class MdReferencesProvider extends Disposable implements vscode.Reference
|
|||
return references;
|
||||
}
|
||||
|
||||
private *getReferencesToReferenceLink(allLinks: Iterable<LinkData>, sourceLink: LinkData): Iterable<MdReference> {
|
||||
private * getReferencesToReferenceLink(allLinks: Iterable<LinkData>, sourceLink: LinkData): Iterable<MdReference> {
|
||||
if (sourceLink.target.kind !== 'reference') {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const link of allLinks) {
|
||||
if (link.target.kind === 'reference' || link.target.kind === 'definition') {
|
||||
if (link.target.ref === sourceLink.target.ref && link.sourceResource.fsPath === sourceLink.sourceResource.fsPath) {
|
||||
const isTriggerLocation = sourceLink.sourceResource.fsPath === link.sourceResource.fsPath && sourceLink.sourceRange.isEqual(link.sourceRange);
|
||||
yield {
|
||||
isTriggerLocation,
|
||||
isDefinition: false,
|
||||
location: new vscode.Location(sourceLink.sourceResource, link.sourceRange)
|
||||
};
|
||||
|
|
|
@ -70,7 +70,7 @@ export class MdSmartSelect implements vscode.SelectionRangeProvider {
|
|||
}
|
||||
|
||||
function getHeadersForPosition(toc: readonly TocEntry[], position: vscode.Position): { headers: TocEntry[]; headerOnThisLine: boolean } {
|
||||
const enclosingHeaders = toc.filter(header => header.location.range.start.line <= position.line && header.location.range.end.line >= position.line);
|
||||
const enclosingHeaders = toc.filter(header => header.sectionLocation.range.start.line <= position.line && header.sectionLocation.range.end.line >= position.line);
|
||||
const sortedHeaders = enclosingHeaders.sort((header1, header2) => (header1.line - position.line) - (header2.line - position.line));
|
||||
const onThisLine = toc.find(header => header.line === position.line) !== undefined;
|
||||
return {
|
||||
|
@ -80,7 +80,7 @@ function getHeadersForPosition(toc: readonly TocEntry[], position: vscode.Positi
|
|||
}
|
||||
|
||||
function createHeaderRange(header: TocEntry, isClosestHeaderToPosition: boolean, onHeaderLine: boolean, parent?: vscode.SelectionRange, startOfChildRange?: vscode.Position): vscode.SelectionRange | undefined {
|
||||
const range = header.location.range;
|
||||
const range = header.sectionLocation.range;
|
||||
const contentRange = new vscode.Range(range.start.translate(1), range.end);
|
||||
if (onHeaderLine && isClosestHeaderToPosition && startOfChildRange) {
|
||||
// selection was made on this header line, so select header and its content until the start of its first child
|
||||
|
@ -240,9 +240,9 @@ function isBlockElement(token: Token): boolean {
|
|||
function getFirstChildHeader(document: SkinnyTextDocument, header?: TocEntry, toc?: readonly TocEntry[]): vscode.Position | undefined {
|
||||
let childRange: vscode.Position | undefined;
|
||||
if (header && toc) {
|
||||
let children = toc.filter(t => header.location.range.contains(t.location.range) && t.location.range.start.line > header.location.range.start.line).sort((t1, t2) => t1.line - t2.line);
|
||||
let children = toc.filter(t => header.sectionLocation.range.contains(t.sectionLocation.range) && t.sectionLocation.range.start.line > header.sectionLocation.range.start.line).sort((t1, t2) => t1.line - t2.line);
|
||||
if (children.length > 0) {
|
||||
childRange = children[0].location.range.start;
|
||||
childRange = children[0].sectionLocation.range.start;
|
||||
const lineText = document.lineAt(childRange.line - 1).text;
|
||||
return childRange ? childRange.translate(-1, lineText.length) : undefined;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,16 @@ export interface TocEntry {
|
|||
readonly text: string;
|
||||
readonly level: number;
|
||||
readonly line: number;
|
||||
readonly location: vscode.Location;
|
||||
|
||||
/**
|
||||
* The entire range of the header section
|
||||
*/
|
||||
readonly sectionLocation: vscode.Location;
|
||||
|
||||
/**
|
||||
* The range of the header itself
|
||||
*/
|
||||
readonly headerLocation: vscode.Location;
|
||||
}
|
||||
|
||||
export class TableOfContents {
|
||||
|
@ -68,13 +77,16 @@ export class TableOfContents {
|
|||
existingSlugEntries.set(slug.value, { count: 0 });
|
||||
}
|
||||
|
||||
const headerLocation = new vscode.Location(document.uri,
|
||||
new vscode.Range(lineNumber, 0, lineNumber, line.text.length));
|
||||
|
||||
toc.push({
|
||||
slug,
|
||||
text: TableOfContents.getHeaderText(line.text),
|
||||
level: TableOfContents.getHeaderLevel(heading.markup),
|
||||
line: lineNumber,
|
||||
location: new vscode.Location(document.uri,
|
||||
new vscode.Range(lineNumber, 0, lineNumber, line.text.length))
|
||||
sectionLocation: headerLocation, // Populated in next steps
|
||||
headerLocation,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -90,9 +102,9 @@ export class TableOfContents {
|
|||
const endLine = end ?? document.lineCount - 1;
|
||||
return {
|
||||
...entry,
|
||||
location: new vscode.Location(document.uri,
|
||||
sectionLocation: new vscode.Location(document.uri,
|
||||
new vscode.Range(
|
||||
entry.location.range.start,
|
||||
entry.sectionLocation.range.start,
|
||||
new vscode.Position(endLine, document.lineAt(endLine).text.length)))
|
||||
};
|
||||
});
|
||||
|
|
|
@ -30,7 +30,8 @@ function assertReferencesEqual(actualRefs: readonly vscode.Location[], ...expect
|
|||
const actual = actualRefs[i];
|
||||
const expected = expectedRefs[i];
|
||||
assert.strictEqual(actual.uri.toString(), expected.uri.toString(), `Ref '${i}' has expected document`);
|
||||
assert.strictEqual(actual.range.start.line, expected.line, `Ref '${i}' has expected line`);
|
||||
assert.strictEqual(actual.range.start.line, expected.line, `Ref '${i}' has expected start line`);
|
||||
assert.strictEqual(actual.range.end.line, expected.line, `Ref '${i}' has expected end line`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue