| // 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; |
| } |
| } |