Skip to content

Commit b01aa0f

Browse files
committed
Add Filesystem API to jars
1 parent c1d4ed5 commit b01aa0f

File tree

5 files changed

+321
-92
lines changed

5 files changed

+321
-92
lines changed

package.json

+20-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
{
@@ -563,31 +564,31 @@
563564
"commandPalette": [
564565
{
565566
"command": "metals.show-tasty",
566-
"when": "metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.tasty || metals:enabled && resourceExtname==.tasty-decoded"
567+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceExtname==.tasty-decoded"
567568
},
568569
{
569570
"command": "metals.show-cfr",
570-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.class || metals:enabled && resourceExtname==.cfr"
571+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.java || metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceExtname==.cfr"
571572
},
572573
{
573574
"command": "metals.show-javap",
574-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.class || metals:enabled && resourceExtname==.javap"
575+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.java || metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resourceExtname==.javap"
575576
},
576577
{
577578
"command": "metals.show-javap-verbose",
578-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.class || metals:enabled && resourceExtname==.javap-verbose"
579+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.java || metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resourceExtname==.javap-verbose"
579580
},
580581
{
581582
"command": "metals.show-semanticdb-compact",
582-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.semanticdb || metals:enabled && resourceExtname==.semanticdb-compact"
583+
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resourceExtname==.semanticdb-compact"
583584
},
584585
{
585586
"command": "metals.show-semanticdb-detailed",
586-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.semanticdb || metals:enabled && resourceExtname==.semanticdb-detailed"
587+
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resourceExtname==.semanticdb-detailed"
587588
},
588589
{
589590
"command": "metals.show-semanticdb-proto",
590-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.semanticdb || metals:enabled && resourceExtname==.semanticdb-proto"
591+
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceScheme == metalsfs && resourceExtname==.class || metals:enabled && resourceExtname==.semanticdb-proto"
591592
},
592593
{
593594
"command": "metals.reveal-active-file",
@@ -647,11 +648,11 @@
647648
},
648649
{
649650
"command": "metals.new-scala-file",
650-
"when": "metals:enabled"
651+
"when": "metals:enabled && resourceScheme != metalsfs"
651652
},
652653
{
653654
"command": "metals.new-java-file",
654-
"when": "metals:enabled"
655+
"when": "metals:enabled && resourceScheme != metalsfs"
655656
},
656657
{
657658
"command": "metals.new-scala-project",
@@ -685,12 +686,12 @@
685686
"explorer/context": [
686687
{
687688
"command": "metals.new-scala-file",
688-
"when": "metals:enabled",
689+
"when": "metals:enabled && resourceScheme != metalsfs",
689690
"group": "navigation@1"
690691
},
691692
{
692693
"command": "metals.new-java-file",
693-
"when": "metals:enabled",
694+
"when": "metals:enabled && resourceScheme != metalsfs",
694695
"group": "navigation@2"
695696
},
696697
{
@@ -702,37 +703,37 @@
702703
"metals.analyze": [
703704
{
704705
"command": "metals.show-tasty",
705-
"when": "metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.tasty || metals:enabled && resourceExtname==.tasty-decoded",
706+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceExtname==.tasty || metals:enabled && resourceExtname==.tasty-decoded",
706707
"group": "metals-1@1"
707708
},
708709
{
709710
"command": "metals.show-cfr",
710-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.class",
711+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.java || metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceScheme != metalsfs && resourceExtname==.class",
711712
"group": "metals-2@1"
712713
},
713714
{
714715
"command": "metals.show-javap",
715-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.class",
716+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.java || metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceExtname==.class",
716717
"group": "metals-3@1"
717718
},
718719
{
719720
"command": "metals.show-javap-verbose",
720-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.class",
721+
"when": "metals:enabled && resourceScheme != metalsfs && resourceExtname==.java || metals:enabled && resourceScheme != metalsfs && resourceExtname==.scala || metals:enabled && resourceExtname==.class",
721722
"group": "metals-3@2"
722723
},
723724
{
724725
"command": "metals.show-semanticdb-compact",
725-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.semanticdb",
726+
"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",
726727
"group": "metals-4@1"
727728
},
728729
{
729730
"command": "metals.show-semanticdb-detailed",
730-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.semanticdb",
731+
"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",
731732
"group": "metals-4@2"
732733
},
733734
{
734735
"command": "metals.show-semanticdb-proto",
735-
"when": "metals:enabled && resourceExtname==.java || metals:enabled && resourceExtname==.scala || metals:enabled && resourceExtname==.semanticdb",
736+
"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",
736737
"group": "metals-4@3"
737738
}
738739
],

src/extension.ts

+104-59
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,
@@ -79,7 +80,11 @@ import {
7980
startFindInFilesProvider,
8081
} from "./findInFiles";
8182
import * as ext from "./hoverExtension";
82-
import { decodeAndShowFile, MetalsFileProvider } from "./metalsContentProvider";
83+
import {
84+
decodeAndShowFile,
85+
DecodeExtension,
86+
MetalsFileProvider,
87+
} from "./metalsContentProvider";
8388
import {
8489
getJavaHomeFromConfig,
8590
getTextDocumentPositionParams,
@@ -91,6 +96,7 @@ import * as workbenchCommands from "./workbenchCommands";
9196
import { getServerVersion } from "./getServerVersion";
9297
import { getCoursierMirrorPath } from "./mirrors";
9398
import { DoctorProvider } from "./doctor";
99+
import MetalsFileSystemProvider from "./metalsFileSystemProvider";
94100

95101
const outputChannel = window.createOutputChannel("Metals");
96102
const openSettingsAction = "Open settings";
@@ -373,8 +379,8 @@ function launchMetals(
373379
documentSelector: [
374380
{ scheme: "file", language: "scala" },
375381
{ scheme: "file", language: "java" },
376-
{ scheme: "jar", language: "scala" },
377-
{ scheme: "jar", language: "java" },
382+
{ scheme: "metalsfs", language: "scala" },
383+
{ scheme: "metalsfs", language: "java" },
378384
],
379385
synchronize: {
380386
configurationSection: "metals",
@@ -449,6 +455,18 @@ function launchMetals(
449455
);
450456
}
451457

458+
function registerFileSystemProvider(
459+
scheme: string,
460+
provider: FileSystemProvider
461+
) {
462+
context.subscriptions.push(
463+
workspace.registerFileSystemProvider(scheme, provider, {
464+
isCaseSensitive: true,
465+
isReadonly: true,
466+
})
467+
);
468+
}
469+
452470
function registerTextDocumentContentProvider(
453471
scheme: string,
454472
provider: TextDocumentContentProvider
@@ -461,50 +479,21 @@ function launchMetals(
461479
const metalsFileProvider = new MetalsFileProvider(client);
462480

463481
registerTextDocumentContentProvider("metalsDecode", metalsFileProvider);
464-
registerTextDocumentContentProvider("jar", metalsFileProvider);
465-
466-
registerCommand("metals.show-cfr", async (uri: Uri) => {
467-
await decodeAndShowFile(client, metalsFileProvider, uri, "cfr");
468-
});
469-
470-
registerCommand("metals.show-javap-verbose", async (uri: Uri) => {
471-
await decodeAndShowFile(client, metalsFileProvider, uri, "javap-verbose");
472-
});
473-
474-
registerCommand("metals.show-javap", async (uri: Uri) => {
475-
await decodeAndShowFile(client, metalsFileProvider, uri, "javap");
476-
});
477-
478-
registerCommand("metals.show-semanticdb-compact", async (uri: Uri) => {
479-
await decodeAndShowFile(
480-
client,
481-
metalsFileProvider,
482-
uri,
483-
"semanticdb-compact"
484-
);
485-
});
486482

487-
registerCommand("metals.show-semanticdb-detailed", async (uri: Uri) => {
488-
await decodeAndShowFile(
489-
client,
490-
metalsFileProvider,
491-
uri,
492-
"semanticdb-detailed"
493-
);
494-
});
495-
496-
registerCommand("metals.show-semanticdb-proto", async (uri: Uri) => {
497-
await decodeAndShowFile(
498-
client,
499-
metalsFileProvider,
500-
uri,
501-
"semanticdb-proto"
502-
);
503-
});
504-
505-
registerCommand("metals.show-tasty", async (uri: Uri) => {
506-
await decodeAndShowFile(client, metalsFileProvider, uri, "tasty-decoded");
507-
});
483+
const decodeCommands: [string, DecodeExtension][] = [
484+
["cfr", "cfr"],
485+
["javap-verbose", "javap-verbose"],
486+
["javap", "javap"],
487+
["semanticdb-compact", "semanticdb-compact"],
488+
["semanticdb-detailed", "semanticdb-detailed"],
489+
["semanticdb-proto", "semanticdb-proto"],
490+
["tasty", "tasty-decoded"],
491+
];
492+
decodeCommands.forEach((command) =>
493+
registerCommand(`metals.show-${command[0]}`, async (uri: Uri) => {
494+
await decodeAndShowFile(client, metalsFileProvider, uri, command[1]);
495+
})
496+
);
508497

509498
registerCommand(
510499
"metals.restartServer",
@@ -647,7 +636,7 @@ function launchMetals(
647636
codeLensRefresher
648637
);
649638
languages.registerCodeLensProvider(
650-
{ scheme: "jar", language: "scala" },
639+
{ scheme: "metalsfs", language: "scala" },
651640
codeLensRefresher
652641
);
653642

@@ -714,6 +703,67 @@ function launchMetals(
714703
case ClientCommands.ReloadDoctor:
715704
doctorProvider.reloadOrRefreshDoctor(params);
716705
break;
706+
case "metals-create-library-filesystem": {
707+
const uri = params.arguments && params.arguments[0];
708+
if (typeof uri === "string") {
709+
const librariesURI = Uri.parse(uri);
710+
// filesystem is persistent across VSCode sessions so may already exist
711+
const libraryFolderName = "Metals - Libraries";
712+
const newLibraryFolder = {
713+
uri: librariesURI,
714+
name: libraryFolderName,
715+
};
716+
const folderByUri = workspace.getWorkspaceFolder(librariesURI);
717+
if (folderByUri && folderByUri.name != libraryFolderName) {
718+
// wrong name on libraries folder
719+
workspace.updateWorkspaceFolders(
720+
folderByUri.index,
721+
1,
722+
newLibraryFolder
723+
);
724+
} else {
725+
const folderByName = workspace.workspaceFolders?.find(
726+
(folder) => folder.name == libraryFolderName
727+
);
728+
if (
729+
folderByName &&
730+
folderByName.uri.toString != librariesURI.toString
731+
) {
732+
if (folderByUri) {
733+
// too many libraries folders
734+
workspace.updateWorkspaceFolders(folderByName.index, 1);
735+
} else {
736+
// wrong root on libraries folder
737+
workspace.updateWorkspaceFolders(
738+
folderByName.index,
739+
1,
740+
newLibraryFolder
741+
);
742+
}
743+
} else if (!folderByUri) {
744+
// missing libraries folder
745+
const workspaceCount = workspace.workspaceFolders?.length;
746+
if (workspaceCount)
747+
workspace.updateWorkspaceFolders(
748+
workspaceCount,
749+
0,
750+
newLibraryFolder
751+
);
752+
}
753+
}
754+
755+
const metalsFileSystemProvider = new MetalsFileSystemProvider(
756+
client,
757+
librariesURI
758+
);
759+
registerFileSystemProvider(
760+
librariesURI.scheme,
761+
metalsFileSystemProvider
762+
);
763+
metalsFileSystemProvider.reinitialiseURI(librariesURI);
764+
}
765+
break;
766+
}
717767
case ClientCommands.FocusDiagnostics:
718768
commands.executeCommand(ClientCommands.FocusDiagnostics);
719769
break;
@@ -873,7 +923,7 @@ function launchMetals(
873923
registerCommand("metals.reveal-active-file", () => {
874924
if (treeViews) {
875925
const editor = window.visibleTextEditors.find((e) =>
876-
isSupportedLanguage(e.document.languageId)
926+
isSupportedDocument(e.document)
877927
);
878928
if (editor) {
879929
const params = getTextDocumentPositionParams(editor);
@@ -950,7 +1000,6 @@ function launchMetals(
9501000
client,
9511001
findInFilesProvider,
9521002
findInFilesView,
953-
metalsFileProvider,
9541003
outputChannel
9551004
)
9561005
);
@@ -996,7 +1045,7 @@ function launchMetals(
9961045
);
9971046

9981047
window.onDidChangeActiveTextEditor((editor) => {
999-
if (editor && isSupportedLanguage(editor.document.languageId)) {
1048+
if (editor && isSupportedDocument(editor.document)) {
10001049
client.sendNotification(
10011050
MetalsDidFocus.type,
10021051
editor.document.uri.toString()
@@ -1252,15 +1301,11 @@ function detectLaunchConfigurationChanges() {
12521301
);
12531302
}
12541303

1255-
function isSupportedLanguage(languageId: TextDocument["languageId"]): boolean {
1256-
switch (languageId) {
1257-
case "scala":
1258-
case "sc":
1259-
case "java":
1260-
return true;
1261-
default:
1262-
return false;
1263-
}
1304+
function isSupportedDocument(textDocument: TextDocument): boolean {
1305+
return (
1306+
["metalsfs", "file"].includes(textDocument.uri.scheme) &&
1307+
["scala", "sc", "java"].includes(textDocument.languageId)
1308+
);
12641309
}
12651310

12661311
// NOTE(gabro): we would normally use the `configurationDefaults` contribution point in the

0 commit comments

Comments
 (0)