diff --git a/bazel-jdt-bridge/vscode-extension/package-lock.json b/bazel-jdt-bridge/vscode-extension/package-lock.json index 0bf39d2..278477b 100644 --- a/bazel-jdt-bridge/vscode-extension/package-lock.json +++ b/bazel-jdt-bridge/vscode-extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "bazel-jdt-bridge", - "version": "0.1.0-pre.4", + "version": "0.1.0-pre.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "bazel-jdt-bridge", - "version": "0.1.0-pre.4", + "version": "0.1.0-pre.5", "devDependencies": { "@types/mocha": "^10.0.9", "@types/node": "^18.19.130", diff --git a/bazel-jdt-bridge/vscode-extension/package.json b/bazel-jdt-bridge/vscode-extension/package.json index 24d9476..cd70250 100644 --- a/bazel-jdt-bridge/vscode-extension/package.json +++ b/bazel-jdt-bridge/vscode-extension/package.json @@ -34,8 +34,21 @@ { "command": "bazel-jdt.createProjectForPackage", "title": "Bazel: Create Project for Package" + }, + { + "command": "bazel-jdt.addDirectoryToProject", + "title": "Bazel: Add to Project" } ], + "menus": { + "explorer/context": [ + { + "command": "bazel-jdt.addDirectoryToProject", + "when": "explorerResourceIsFolder", + "group": "bazel-jdt@1" + } + ] + }, "configuration": { "title": "Bazel JDT Bridge", "properties": { diff --git a/bazel-jdt-bridge/vscode-extension/src/bazelproject.ts b/bazel-jdt-bridge/vscode-extension/src/bazelproject.ts index 2c00163..3058bd5 100644 --- a/bazel-jdt-bridge/vscode-extension/src/bazelproject.ts +++ b/bazel-jdt-bridge/vscode-extension/src/bazelproject.ts @@ -116,6 +116,56 @@ export function parseBazelprojectContent(content: string): BazelProjectViewConfi return config; } +export function addDirectoryToBazelproject( + bazelprojectPath: string, + relativeDir: string +): 'added' | 'already-exists' | 'created' { + if (fs.existsSync(bazelprojectPath)) { + const content = fs.readFileSync(bazelprojectPath, 'utf-8'); + const config = parseBazelprojectContent(content); + if (config.directories.includes(relativeDir)) { + return 'already-exists'; + } + fs.writeFileSync(bazelprojectPath, insertDirectoryIntoContent(content, relativeDir), 'utf-8'); + return 'added'; + } else { + fs.writeFileSync( + bazelprojectPath, + `directories:\n ${relativeDir}\n\nderive_targets_from_directories: True\n`, + 'utf-8' + ); + return 'created'; + } +} + +function insertDirectoryIntoContent(content: string, dir: string): string { + const lines = content.split('\n'); + let inDirectories = false; + let lastDirLineIdx = -1; + + for (let i = 0; i < lines.length; i++) { + const trimmed = lines[i].trim(); + if (trimmed === 'directories:') { + inDirectories = true; + lastDirLineIdx = i; + continue; + } + if (inDirectories) { + if (trimmed.length === 0 || trimmed.startsWith('#') || /^[a-z_]+:/i.test(trimmed)) { + break; + } + lastDirLineIdx = i; + } + } + + if (lastDirLineIdx >= 0) { + lines.splice(lastDirLineIdx + 1, 0, ` ${dir}`); + } else { + lines.unshift('directories:', ` ${dir}`, ''); + } + return lines.join('\n'); +} + export function resolveScopePatterns(config: BazelProjectViewConfig): string[] { const patterns: string[] = []; diff --git a/bazel-jdt-bridge/vscode-extension/src/commands.ts b/bazel-jdt-bridge/vscode-extension/src/commands.ts index fd3b1f5..91f4ead 100644 --- a/bazel-jdt-bridge/vscode-extension/src/commands.ts +++ b/bazel-jdt-bridge/vscode-extension/src/commands.ts @@ -1,7 +1,9 @@ import * as vscode from 'vscode'; +import * as path from 'path'; +import * as fs from 'fs'; import { getConfig } from './config'; import { runImportWizard } from './importWizard'; -import { parseBazelprojectFile } from './bazelproject'; +import { parseBazelprojectFile, addDirectoryToBazelproject } from './bazelproject'; export function registerImportCommand(context: vscode.ExtensionContext) { const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || ''; @@ -44,6 +46,34 @@ export function registerImportCommand(context: vscode.ExtensionContext) { ); } +export function registerAddDirectoryCommand(context: vscode.ExtensionContext, workspaceRoot: string) { + context.subscriptions.push( + vscode.commands.registerCommand('bazel-jdt.addDirectoryToProject', async (uri: vscode.Uri) => { + if (!uri) return; + + const dirPath = uri.fsPath; + const hasBuild = fs.existsSync(path.join(dirPath, 'BUILD')) || + fs.existsSync(path.join(dirPath, 'BUILD.bazel')); + if (!hasBuild) { + vscode.window.showWarningMessage('No BUILD file found in selected directory.'); + return; + } + + const relativeDir = path.relative(workspaceRoot, dirPath); + const bazelprojectPath = path.join(workspaceRoot, '.bazelproject'); + const result = addDirectoryToBazelproject(bazelprojectPath, relativeDir); + + if (result === 'already-exists') { + vscode.window.showInformationMessage(`'${relativeDir}' is already in the Bazel project scope.`); + } else if (result === 'added') { + vscode.window.showInformationMessage(`Added '${relativeDir}' to Bazel project scope.`); + } else { + vscode.window.showInformationMessage(`Created .bazelproject with '${relativeDir}'.`); + } + }) + ); +} + export function registerRuntimeCommands(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand('bazel-jdt.syncProject', async () => { diff --git a/bazel-jdt-bridge/vscode-extension/src/extension.ts b/bazel-jdt-bridge/vscode-extension/src/extension.ts index 7fd87c3..78d7775 100644 --- a/bazel-jdt-bridge/vscode-extension/src/extension.ts +++ b/bazel-jdt-bridge/vscode-extension/src/extension.ts @@ -1,7 +1,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import * as fs from 'fs'; -import { registerImportCommand, registerRuntimeCommands } from './commands'; +import { registerImportCommand, registerRuntimeCommands, registerAddDirectoryCommand } from './commands'; import { BazelDebugConfigurationProvider } from './debugAdapter'; import { createStatusBar } from './statusBar'; import { getConfig } from './config'; @@ -26,6 +26,7 @@ export async function activate(context: vscode.ExtensionContext) { activateFull(context, workspaceRoot); } else { registerImportCommand(context); + registerAddDirectoryCommand(context, workspaceRoot); setupCreationOnlyWatcher(context, workspaceRoot); } } @@ -34,6 +35,7 @@ function activateFull(context: vscode.ExtensionContext, workspaceRoot: string) { const statusBarItem = createStatusBar(context); registerImportCommand(context); registerRuntimeCommands(context); + registerAddDirectoryCommand(context, workspaceRoot); context.subscriptions.push( vscode.debug.registerDebugConfigurationProvider( 'java', new BazelDebugConfigurationProvider()