Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,21 @@ This extension provides intelligent formatting for Device Tree Source (DTS) file

*Example of Device Tree file before and after formatting*

### Include File Navigation

This extension provides intelligent navigation for `#include` directives with support for:

- **Go to definition**: Ctrl+Click on include paths to jump to the file
- **Smart file resolution**: Automatically searches multiple locations:
- Relative to current file
- Workspace root
- `arch/*/boot/dts/` directories (Linux kernel structure)
- `arch/*/dts/` directories (U-Boot structure)
- Configurable custom search paths
- **Visual feedback**: Include paths are underlined when the file is found
- **Diagnostic warnings**: Missing include files are highlighted with warnings
- **Configurable search paths**: Add custom directories via `devicetree.includeSearchPaths` setting

### Supported File Extensions

- `.dts` - Device Tree Source files
Expand Down
6 changes: 6 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,10 @@ export default [{
"max-lines-per-function": ["warn", { max: 100, skipBlankLines: true, skipComments: true }],
complexity: ["warn", 15],
},
}, {
// Test files are allowed to have long functions (test suites are naturally large)
files: ["**/*.test.ts"],
rules: {
"max-lines-per-function": "off",
},
}];
23 changes: 17 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"scripts": {
"compile": "webpack",
"compile-tests": "tsc -p . --outDir out",
"lint": "eslint src",
"lint": "eslint src --max-warnings 0",
"package": "webpack --mode production --devtool hidden-source-map",
"pretest": "npm run compile-tests && npm run compile && npm run lint",
"test": "vscode-test",
Expand All @@ -61,11 +61,6 @@
{
"title": "DeviceTree Language",
"properties": {
"devicetree.maxLineLength": {
"type": "number",
"default": 80,
"description": "Maximum line length for DeviceTree files. Lines longer than this will be wrapped."
},
"devicetree.diagnostics.enableWarnings": {
"type": "boolean",
"default": true,
Expand All @@ -75,6 +70,22 @@
"type": "boolean",
"default": true,
"markdownDescription": "Include comments when calculating line length for warnings."
},
"devicetree.includeSearchPaths": {
"type": "array",
"default": [
"include",
"include/dt-bindings"
],
"description": "Additional directories to search for included files (relative to workspace root).",
"items": {
"type": "string"
}
},
"devicetree.maxLineLength": {
"type": "number",
"default": 80,
"description": "Maximum line length for DeviceTree files. Lines longer than this will be wrapped."
}
}
}
Expand Down
57 changes: 53 additions & 4 deletions src/diagnostics.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as vscode from 'vscode';
import * as path from 'path';
import { DtsDocumentLinkProvider, parseIncludes } from './links';

/**
* Provider for DeviceTree diagnostic warnings
Expand All @@ -7,13 +9,15 @@ import * as vscode from 'vscode';
export class DtsDiagnosticsProvider {
private diagnosticCollection: vscode.DiagnosticCollection;
private maxLineLength: number;
private includeComments: boolean;
private tabSize: number;
private includeComments: boolean;
private linkProvider: DtsDocumentLinkProvider;

constructor(maxLineLength: number, includeComments: boolean) {
constructor(maxLineLength: number, includeComments: boolean, linkProvider: DtsDocumentLinkProvider) {
this.diagnosticCollection = vscode.languages.createDiagnosticCollection('devicetree');
this.maxLineLength = maxLineLength + 1;
this.includeComments = includeComments;
this.linkProvider = linkProvider;

// Read tabSize from editor configuration
const editorConfig = vscode.workspace.getConfiguration('editor');
Expand Down Expand Up @@ -125,11 +129,51 @@ export class DtsDiagnosticsProvider {
return diagnostics;
}

/**
* Check for missing include files
* @param document The document to check
* @returns Array of diagnostics for missing include files
*/
private async checkIncludeFiles(
document: vscode.TextDocument,
): Promise<vscode.Diagnostic[]> {
const diagnostics: vscode.Diagnostic[] = [];
const includes = parseIncludes(document);
const currentFileDir = path.dirname(document.uri.fsPath);

for (const include of includes) {
// Check if file exists
const targetUri = await this.linkProvider.findIncludedFile(
include.path,
currentFileDir
);

if (!targetUri) {
const range = new vscode.Range(
new vscode.Position(include.line, include.startChar),
new vscode.Position(include.line, include.endChar)
);
const diagnostic = new vscode.Diagnostic(
range,
`Include file "${include.path}" was not found.\n` +
`Update the 'includeSearchPaths' settings for new location to search.`,
vscode.DiagnosticSeverity.Warning
);
diagnostic.source = 'DeviceTree';
diagnostics.push(diagnostic);
}
}

return diagnostics;
}

/**
* Analyze a document and update diagnostics
* @param document The document to analyze
*/
public analyzeDocument(document: vscode.TextDocument): void {
public async analyzeDocument(
document: vscode.TextDocument
): Promise<void> {
if (document.languageId !== 'dts') {
return;
}
Expand All @@ -143,11 +187,16 @@ export class DtsDiagnosticsProvider {
this.tabSize = editor.options.tabSize as number;
}

// Run all diagnostic checks
const diagnostics: vscode.Diagnostic[] = [];

// Run all diagnostic checks, currently only line length
// Check line length
diagnostics.push(...this.checkLineLength(document));

// Check include files
const includeDiagnostics = await this.checkIncludeFiles(document);
diagnostics.push(...includeDiagnostics);

this.diagnosticCollection.set(document.uri, diagnostics);
}

Expand Down
21 changes: 19 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
// Import the formatter and diagnostics providers
import { DtsFormatterProvider } from './formatter';
import { DtsDocumentLinkProvider } from './links';
import { DtsDiagnosticsProvider } from './diagnostics';
import { DtsFormatterProvider } from './formatter';

// Global provider instances
let linkProvider: DtsDocumentLinkProvider | undefined;
let diagnosticsProvider: DtsDiagnosticsProvider | undefined;
let formatterProvider: DtsFormatterProvider | undefined;

Expand All @@ -23,11 +25,17 @@ export function activate(context: vscode.ExtensionContext) {
const maxLineLength = config.get<number>('maxLineLength', 80);
const enableWarnings = config.get<boolean>('diagnostics.enableWarnings', true);
const includeComments = config.get<boolean>('diagnostics.lineLengthIncludeComments', true);
const includeSearchPaths = config.get<string[]>('includeSearchPaths', ['include', 'include/dt-bindings']);

// Create providers
diagnosticsProvider = new DtsDiagnosticsProvider(maxLineLength, includeComments);
linkProvider = new DtsDocumentLinkProvider(includeSearchPaths);
diagnosticsProvider = new DtsDiagnosticsProvider(maxLineLength, includeComments, linkProvider);
formatterProvider = new DtsFormatterProvider(maxLineLength);

context.subscriptions.push(
vscode.languages.registerDocumentLinkProvider('dts', linkProvider)
);

context.subscriptions.push(
vscode.languages.registerDocumentFormattingEditProvider('dts', formatterProvider)
);
Expand Down Expand Up @@ -78,12 +86,18 @@ export function activate(context: vscode.ExtensionContext) {
const config = vscode.workspace.getConfiguration('devicetree');
const maxLineLength = config.get<number>('maxLineLength', 80);
const includeComments = config.get<boolean>('diagnostics.lineLengthIncludeComments', true);
const includeSearchPaths = config.get<string[]>('includeSearchPaths', ['include', 'include/dt-bindings']);

// Update formatter settings
if (formatterProvider) {
formatterProvider.updateSettings(maxLineLength);
}

// Update link provider search paths
if (linkProvider) {
linkProvider.updateSearchPaths(includeSearchPaths);
}

// Update diagnostics settings
if (diagnosticsProvider) {
diagnosticsProvider.updateSettings(maxLineLength, includeComments);
Expand Down Expand Up @@ -114,4 +128,7 @@ export function deactivate() {
diagnosticsProvider.dispose();
diagnosticsProvider = undefined;
}
if (linkProvider) {
linkProvider = undefined;
}
}
Loading
Loading