blob: a4cce6bc2b0895ccb3431cd37db602281ee041a6 [file] [log] [blame] [edit]
// Copyright 2025 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as vscode from 'vscode';
import * as path from 'path';
// Capture Groups | 0:Match | 1: Filepath | 2: Line | 3: Column
// CPP and Rust format of ../../[path]/[file].[extension]:[line]:[column]
const CPP_RUST_MATCHER = /\.\.\/\.\.(\/.*):(\d+):(\d+)/g;
// GN format of //[path].[extension]:[line]:[column]
const GN_MATCHER = /(\/\/.*):(\d+):(\d+)/g;
// Python format of [path].[extension]:[line]
const PY_MATCHER = /(.*.py):(\d+)/g;
/**
* Provide DocumentLinks for Fuchsia output syntax errors in Fuchsia builds.
*/
export class FuchsiaDocumentLinkProvider implements vscode.DocumentLinkProvider {
provideDocumentLinks(
document: vscode.TextDocument,
token: vscode.CancellationToken
): vscode.ProviderResult<vscode.DocumentLink[]> {
const links: vscode.DocumentLink[] = [];
const workspaceFolder = vscode.workspace.workspaceFolders;
if (!workspaceFolder || workspaceFolder[0].name !== 'fuchsia') {
return [];
}
const workspacePath = workspaceFolder[0].uri.fsPath;
const text = document.getText();
const matcher = new RegExp(
`${CPP_RUST_MATCHER.source}|${GN_MATCHER.source}|${PY_MATCHER.source}`,
'g');
let matches = text.matchAll(matcher);
for (const fileMatch of matches) {
// Remove null items in matcher groups
const match = fileMatch.filter((item) => !!item);
const linkText = match[0];
const filePath = match[1];
const line = parseInt(match[2]);
const column = parseInt(match[3]);
const fullPath = path.join(workspacePath, filePath);
const fileUri = vscode.Uri.file(fullPath);
// The range in the document to underline link
const start = document.positionAt(fileMatch.index!);
const end = document.positionAt(fileMatch.index! + linkText.length);
const linkRange = new vscode.Range(start, end);
// Link format is file:///path/to/file.ts#Lline,column
const link = new vscode.DocumentLink(
linkRange,
fileUri.with({ fragment: `L${line},${column}` })
);
link.tooltip =
`Go to line ${line}${isNaN(column) ? '' : `:${column}`} in ${path.basename(filePath)}`;
links.push(link);
}
return links;
}
}