Skip to content

Commit cdbb008

Browse files
committed
Add Filesystem API to jars
1 parent 2a241a8 commit cdbb008

File tree

5 files changed

+325
-91
lines changed

5 files changed

+325
-91
lines changed

package.json

+29-19
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@
7171
{
7272
"id": "java",
7373
"extensions": [
74-
".cfr"
74+
".cfr",
75+
".class"
7576
]
7677
},
7778
{
@@ -407,6 +408,11 @@
407408
"category": "Metals",
408409
"title": "Run doctor"
409410
},
411+
{
412+
"command": "metals.show-libraries-folder",
413+
"category": "Metals",
414+
"title": "Show libraries folder in file explorer"
415+
},
410416
{
411417
"command": "metals.show-tasty",
412418
"category": "Metals",
@@ -561,33 +567,37 @@
561567
}
562568
],
563569
"commandPalette": [
570+
{
571+
"command": "metals.show-libraries-folder",
572+
"when": "metals:enabled"
573+
},
564574
{
565575
"command": "metals.show-tasty",
566-
"when": "metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.tasty || metals:enabled && resourceExtname==.tasty-decoded"
576+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceExtname==.tasty-decoded"
567577
},
568578
{
569579
"command": "metals.show-cfr",
570-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.class || metals:enabled && resourceExtname==.cfr"
580+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.java || metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceExtname==.cfr"
571581
},
572582
{
573583
"command": "metals.show-javap",
574-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.class || metals:enabled && resourceExtname==.javap"
584+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.java || metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resourceExtname==.javap"
575585
},
576586
{
577587
"command": "metals.show-javap-verbose",
578-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.class || metals:enabled && resourceExtname==.javap-verbose"
588+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.java || metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resourceExtname==.javap-verbose"
579589
},
580590
{
581591
"command": "metals.show-semanticdb-compact",
582-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.semanticdb || metals:enabled && resourceExtname==.semanticdb-compact"
592+
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resourceExtname==.semanticdb-compact"
583593
},
584594
{
585595
"command": "metals.show-semanticdb-detailed",
586-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.semanticdb || metals:enabled && resourceExtname==.semanticdb-detailed"
596+
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resourceExtname==.semanticdb-detailed"
587597
},
588598
{
589599
"command": "metals.show-semanticdb-proto",
590-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.semanticdb || metals:enabled && resourceExtname==.semanticdb-proto"
600+
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resourceExtname==.semanticdb-proto"
591601
},
592602
{
593603
"command": "metals.reveal-active-file",
@@ -647,11 +657,11 @@
647657
},
648658
{
649659
"command": "metals.new-scala-file",
650-
"when": "metals:enabled"
660+
"when": "metals:enabled && resourceScheme != metalsfs"
651661
},
652662
{
653663
"command": "metals.new-java-file",
654-
"when": "metals:enabled"
664+
"when": "metals:enabled && resourceScheme != metalsfs"
655665
},
656666
{
657667
"command": "metals.new-scala-project",
@@ -685,12 +695,12 @@
685695
"explorer/context": [
686696
{
687697
"command": "metals.new-scala-file",
688-
"when": "metals:enabled",
698+
"when": "metals:enabled && resourceScheme != metalsfs",
689699
"group": "navigation@1"
690700
},
691701
{
692702
"command": "metals.new-java-file",
693-
"when": "metals:enabled",
703+
"when": "metals:enabled && resourceScheme != metalsfs",
694704
"group": "navigation@2"
695705
},
696706
{
@@ -702,37 +712,37 @@
702712
"metals.analyze": [
703713
{
704714
"command": "metals.show-tasty",
705-
"when": "metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.tasty || metals:enabled && resourceExtname==.tasty-decoded",
715+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceExtname==.tasty || metals:enabled && resourceExtname==.tasty-decoded",
706716
"group": "metals-1@1"
707717
},
708718
{
709719
"command": "metals.show-cfr",
710-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.class",
720+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.java || metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceScheme != metalsfs && resourceExtname==.class",
711721
"group": "metals-2@1"
712722
},
713723
{
714724
"command": "metals.show-javap",
715-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.class",
725+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.java || metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceExtname==.class",
716726
"group": "metals-3@1"
717727
},
718728
{
719729
"command": "metals.show-javap-verbose",
720-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.class",
730+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.java || metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceExtname==.class",
721731
"group": "metals-3@2"
722732
},
723733
{
724734
"command": "metals.show-semanticdb-compact",
725-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.semanticdb",
735+
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resource ~= ///.metals//readonly/// && resourceExtname==.class || metals:enabled && resourceExtname==.semanticdb",
726736
"group": "metals-4@1"
727737
},
728738
{
729739
"command": "metals.show-semanticdb-detailed",
730-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.semanticdb",
740+
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resource ~= ///.metals//readonly/// && resourceExtname==.class || metals:enabled && resourceExtname==.semanticdb",
731741
"group": "metals-4@2"
732742
},
733743
{
734744
"command": "metals.show-semanticdb-proto",
735-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.semanticdb",
745+
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resource ~= ///.metals//readonly/// && resourceExtname==.class || metals:enabled && resourceExtname==.semanticdb",
736746
"group": "metals-4@3"
737747
}
738748
],

src/extension.ts

+102-58
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
ProviderResult,
2929
Hover,
3030
TextDocument,
31+
FileSystemProvider,
3132
} from "vscode";
3233
import {
3334
LanguageClient,
@@ -78,7 +79,11 @@ import {
7879
startFindInFilesProvider,
7980
} from "./findInFiles";
8081
import * as ext from "./hoverExtension";
81-
import { decodeAndShowFile, MetalsFileProvider } from "./metalsContentProvider";
82+
import {
83+
decodeAndShowFile,
84+
DecodeExtension,
85+
MetalsFileProvider,
86+
} from "./metalsContentProvider";
8287
import {
8388
getJavaHomeFromConfig,
8489
getTextDocumentPositionParams,
@@ -90,6 +95,7 @@ import * as workbenchCommands from "./workbenchCommands";
9095
import { getServerVersion } from "./getServerVersion";
9196
import { getCoursierMirrorPath } from "./mirrors";
9297
import { DoctorProvider } from "./doctor";
98+
import MetalsFileSystemProvider from "./metalsFileSystemProvider";
9399

94100
const outputChannel = window.createOutputChannel("Metals");
95101
const openSettingsAction = "Open settings";
@@ -98,6 +104,8 @@ const downloadJava = "Download Java";
98104
const installJava11Action = "Install Java (JDK 11)";
99105
const installJava17Action = "Install Java (JDK 17)";
100106

107+
const librariesURI = Uri.parse("metalsfs:/metalsLibraries");
108+
101109
let treeViews: MetalsTreeViews | undefined;
102110
let currentClient: LanguageClient | undefined;
103111

@@ -364,8 +372,8 @@ function launchMetals(
364372
documentSelector: [
365373
{ scheme: "file", language: "scala" },
366374
{ scheme: "file", language: "java" },
367-
{ scheme: "jar", language: "scala" },
368-
{ scheme: "jar", language: "java" },
375+
{ scheme: "metalsfs", language: "scala" },
376+
{ scheme: "metalsfs", language: "java" },
369377
],
370378
synchronize: {
371379
configurationSection: "metals",
@@ -440,6 +448,18 @@ function launchMetals(
440448
);
441449
}
442450

451+
function registerFileSystemProvider(
452+
scheme: string,
453+
provider: FileSystemProvider
454+
) {
455+
context.subscriptions.push(
456+
workspace.registerFileSystemProvider(scheme, provider, {
457+
isCaseSensitive: true,
458+
isReadonly: true,
459+
})
460+
);
461+
}
462+
443463
function registerTextDocumentContentProvider(
444464
scheme: string,
445465
provider: TextDocumentContentProvider
@@ -450,52 +470,26 @@ function launchMetals(
450470
}
451471

452472
const metalsFileProvider = new MetalsFileProvider(client);
453-
454473
registerTextDocumentContentProvider("metalsDecode", metalsFileProvider);
455-
registerTextDocumentContentProvider("jar", metalsFileProvider);
456-
457-
registerCommand("metals.show-cfr", async (uri: Uri) => {
458-
await decodeAndShowFile(client, metalsFileProvider, uri, "cfr");
459-
});
460-
461-
registerCommand("metals.show-javap-verbose", async (uri: Uri) => {
462-
await decodeAndShowFile(client, metalsFileProvider, uri, "javap-verbose");
463-
});
464-
465-
registerCommand("metals.show-javap", async (uri: Uri) => {
466-
await decodeAndShowFile(client, metalsFileProvider, uri, "javap");
467-
});
468-
469-
registerCommand("metals.show-semanticdb-compact", async (uri: Uri) => {
470-
await decodeAndShowFile(
471-
client,
472-
metalsFileProvider,
473-
uri,
474-
"semanticdb-compact"
475-
);
476-
});
477-
478-
registerCommand("metals.show-semanticdb-detailed", async (uri: Uri) => {
479-
await decodeAndShowFile(
480-
client,
481-
metalsFileProvider,
482-
uri,
483-
"semanticdb-detailed"
484-
);
485-
});
486474

487-
registerCommand("metals.show-semanticdb-proto", async (uri: Uri) => {
488-
await decodeAndShowFile(
489-
client,
490-
metalsFileProvider,
491-
uri,
492-
"semanticdb-proto"
493-
);
494-
});
475+
registerCommand("metals.show-libraries-folder", async () =>
476+
addLibrariesFolder()
477+
);
495478

496-
registerCommand("metals.show-tasty", async (uri: Uri) => {
497-
await decodeAndShowFile(client, metalsFileProvider, uri, "tasty-decoded");
498-
});
479+
const decodeCommands: [string, DecodeExtension][] = [
480+
["cfr", "cfr"],
481+
["javap-verbose", "javap-verbose"],
482+
["javap", "javap"],
483+
["semanticdb-compact", "semanticdb-compact"],
484+
["semanticdb-detailed", "semanticdb-detailed"],
485+
["semanticdb-proto", "semanticdb-proto"],
486+
["tasty", "tasty-decoded"],
487+
];
488+
decodeCommands.forEach((command) =>
489+
registerCommand(`metals.show-${command[0]}`, async (uri: Uri) => {
490+
await decodeAndShowFile(client, metalsFileProvider, uri, command[1]);
491+
})
492+
);
499493

500494
registerCommand(
501495
"metals.restartServer",
@@ -636,7 +630,7 @@ function launchMetals(
636630
codeLensRefresher
637631
);
638632
languages.registerCodeLensProvider(
639-
{ scheme: "jar", language: "scala" },
633+
{ scheme: "metalsfs", language: "scala" },
640634
codeLensRefresher
641635
);
642636

@@ -703,6 +697,19 @@ function launchMetals(
703697
case ClientCommands.ReloadDoctor:
704698
doctorProvider.reloadOrRefreshDoctor(params);
705699
break;
700+
case "metals-library-filesystem-ready": {
701+
const metalsFileSystemProvider = new MetalsFileSystemProvider(
702+
client,
703+
librariesURI
704+
);
705+
registerFileSystemProvider(
706+
librariesURI.scheme,
707+
metalsFileSystemProvider
708+
);
709+
710+
metalsFileSystemProvider.reinitialiseURI(librariesURI);
711+
break;
712+
}
706713
case ClientCommands.FocusDiagnostics:
707714
commands.executeCommand(ClientCommands.FocusDiagnostics);
708715
break;
@@ -862,7 +869,7 @@ function launchMetals(
862869
registerCommand("metals.reveal-active-file", () => {
863870
if (treeViews) {
864871
const editor = window.visibleTextEditors.find((e) =>
865-
isSupportedLanguage(e.document.languageId)
872+
isSupportedDocument(e.document)
866873
);
867874
if (editor) {
868875
const params = getTextDocumentPositionParams(editor);
@@ -939,7 +946,6 @@ function launchMetals(
939946
client,
940947
findInFilesProvider,
941948
findInFilesView,
942-
metalsFileProvider,
943949
outputChannel
944950
)
945951
);
@@ -985,7 +991,7 @@ function launchMetals(
985991
);
986992

987993
window.onDidChangeActiveTextEditor((editor) => {
988-
if (editor && isSupportedLanguage(editor.document.languageId)) {
994+
if (editor && isSupportedDocument(editor.document)) {
989995
client.sendNotification(
990996
MetalsDidFocus.type,
991997
editor.document.uri.toString()
@@ -1241,14 +1247,52 @@ function detectLaunchConfigurationChanges() {
12411247
);
12421248
}
12431249

1244-
function isSupportedLanguage(languageId: TextDocument["languageId"]): boolean {
1245-
switch (languageId) {
1246-
case "scala":
1247-
case "sc":
1248-
case "java":
1249-
return true;
1250-
default:
1251-
return false;
1250+
function isSupportedDocument(textDocument: TextDocument): boolean {
1251+
return (
1252+
["metalsfs", "file"].includes(textDocument.uri.scheme) &&
1253+
["scala", "sc", "java"].includes(textDocument.languageId)
1254+
);
1255+
}
1256+
1257+
function addLibrariesFolder() {
1258+
const libraryFolderName = "Metals - Libraries";
1259+
1260+
// filesystem can be persistent across VSCode sessions so may already exist
1261+
const newLibraryFolder = {
1262+
uri: librariesURI,
1263+
name: libraryFolderName,
1264+
};
1265+
const folderByUri = workspace.getWorkspaceFolder(librariesURI);
1266+
if (folderByUri && folderByUri.name != libraryFolderName) {
1267+
// wrong name on libraries folder
1268+
workspace.updateWorkspaceFolders(folderByUri.index, 1, newLibraryFolder);
1269+
} else {
1270+
const folderByName = workspace.workspaceFolders?.find(
1271+
(folder) => folder.name == libraryFolderName
1272+
);
1273+
if (folderByName && folderByName.uri.toString != librariesURI.toString) {
1274+
if (folderByUri) {
1275+
// too many libraries folders
1276+
workspace.updateWorkspaceFolders(folderByName.index, 1);
1277+
} else {
1278+
// wrong root on libraries folder
1279+
workspace.updateWorkspaceFolders(
1280+
folderByName.index,
1281+
1,
1282+
newLibraryFolder
1283+
);
1284+
}
1285+
} else if (!folderByUri) {
1286+
// missing libraries folder
1287+
const workspaceCount = workspace.workspaceFolders?.length;
1288+
if (workspaceCount) {
1289+
workspace.updateWorkspaceFolders(
1290+
workspaceCount,
1291+
null,
1292+
newLibraryFolder
1293+
);
1294+
}
1295+
}
12521296
}
12531297
}
12541298

0 commit comments

Comments
 (0)