Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
nhedger committed Jul 21, 2024
1 parent 56ff0e5 commit 2976d81
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 24 deletions.
22 changes: 8 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,6 @@
},
"categories": ["Formatters", "Linters"],
"contributes": {
"icons": {
"my-icon-id": {
"description": "my icon",
"default": {
"fontPath": "myiconfont.woff",
"fontCharacter": "\\E001"
}
}
},
"configuration": {
"title": "Biome",
"properties": {
Expand All @@ -60,10 +51,12 @@
},
"biome.requireConfig": {
"type": "boolean",
"description": "Require a Biome configuration file to be present at the root of a workspace folder to enable Biome for that workspace folder.",
"description": "Require a Biome configuration file to be present for the extension to start.",
"markdownDescription": "If enabled, the extension will only start a Biome LSP session if a Biome configuration file is present at the root of a given Biome root. This can used to automatically prevent Biome from interfering with projects that do not use Biome.",
"default": false
},
"biome.roots": {
"markdownDescription": "**This setting should only be set at workspace folder level. It will be ignored in other cases.**\n\nBiome Roots are folders for which the extension will spawn an independent Biome LSP session. This is especially helpful for monorepos where the projects that use Biome may not necessarily be in the root of the workspace folder.",
"description": "Subfolders of a workspace folder in which to spawn a Biome Language Server instance. If empty, the Biome Language Server will be spawned in the workspace folder.",
"type": "array",
"items": {
Expand Down Expand Up @@ -104,10 +97,11 @@
}
]
},
"biome.lsp.tracing.enable": {
"type": "boolean",
"description": "Whether to enable tracing for the Biome Language Server",
"default": false
"biome.lsp.trace.server": {
"type": "string",
"enum": ["off", "messages", "compact", "verbose"],
"description": "Tracing level of the communications between the extension and the Biome Language Server.",
"default": "off"
}
}
},
Expand Down
45 changes: 45 additions & 0 deletions src/orchestrator.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import {
ProgressLocation,
type TextEditor,
type Uri,
type WorkspaceFolder,
window,
workspace,
} from "vscode";
import { Utils } from "vscode-uri";
import { Root } from "./root";
import { Session } from "./session";
import { state } from "./state";
import { config, logger } from "./utils";

export class Orchestrator {
/**
* Global Biome LSP session
*
* The global Biome session is used to provide LSP features to files that
* do not yet exist on disk, and thus do not have an associated root, or
* configuration file.
*
* This session is created on-demand when a so-called "untitled" file is
* opened.
*/
private globalSession: Session | undefined;

/**
* The Biome roots currently being tracked by the orchestrator.
*/
Expand Down Expand Up @@ -38,6 +52,14 @@ export class Orchestrator {
}
});

// Listen for the opening of untitled files to create a global session
if (window.activeTextEditor?.document.uri.scheme === "untitled") {
this.manageGlobalSessionLifecycle(window.activeTextEditor);
}
window.onDidChangeActiveTextEditor(async (editor) =>
this.manageGlobalSessionLifecycle(editor),
);

logger.debug("Biome LSP orchestrator initialized.");
}

Expand Down Expand Up @@ -166,4 +188,27 @@ export class Orchestrator {

return allRoots;
}

private async manageGlobalSessionLifecycle(editor?: TextEditor) {
if (!editor) return;

const uri = editor.document.uri;
if (uri.scheme === "untitled") {
await this.startGlobalSession();
} else {
await this.stopGlobalSession();
}
}

private async startGlobalSession() {
if (this.globalSession) return;
this.globalSession = new Session();
await this.globalSession.start();
}

private async stopGlobalSession() {
if (!this.globalSession) return;
await this.globalSession.destroy();
this.globalSession = undefined;
}
}
38 changes: 30 additions & 8 deletions src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
type ServerOptions,
TransportKind,
} from "vscode-languageclient/node";
import { findBiomeLocally } from "./locator/locator";
import { findBiomeGlobally, findBiomeLocally } from "./locator/locator";
import type { Root } from "./root";
import { subtractURI } from "./utils";
import { supportedLanguages } from "./utils";
Expand Down Expand Up @@ -42,32 +42,43 @@ export class Session extends EventEmitter {
/**
* The Biome root for the session
*/
private readonly root: Root,
private readonly root?: Root,
) {
super();

this.lspLogger = window.createOutputChannel(
`${displayName} LSP (${root.workspaceFolder.name}::${subtractURI(root.uri, root.workspaceFolder.uri).fsPath})`,
root?.workspaceFolder
? `${displayName} LSP (${root.workspaceFolder.name}::${subtractURI(root.uri, root.workspaceFolder.uri).fsPath})`
: `${displayName} LSP ${this.isGlobal ? "(global)" : ""}`.trim(),
{
log: true,
},
);

this.lspTraceLogger = window.createOutputChannel(
root.workspaceFolder
root?.workspaceFolder
? `${displayName} LSP trace (${root.workspaceFolder.name}::${subtractURI(root.uri, root.workspaceFolder.uri).fsPath})`
: "${displayName} LSP trace",
: `${displayName} LSP trace ${this.isGlobal ? "(global)" : ""}`.trim(),
{
log: true,
},
);
}

/**
* Returns whether the session is global
*/
public get isGlobal(): boolean {
return this.root === undefined;
}

/**
* Starts the LSP session
*/
public async start() {
this.bin = (await findBiomeLocally(this.root.uri)).uri;
this.bin = this.root
? (await findBiomeLocally(this.root.uri)).uri
: (await findBiomeGlobally()).uri;

if (this.client === undefined) {
this.createLanguageClient();
Expand Down Expand Up @@ -115,11 +126,13 @@ export class Session extends EventEmitter {
const clientOptions: LanguageClientOptions = {
outputChannel: this.lspLogger,
traceOutputChannel: this.lspTraceLogger,
documentSelector: this.generateDocumentSelector(),
documentSelector: this.root
? this.generateDocumentSelector()
: this.generateGlobalDocumentSelector(),
};

this.client = new LanguageClient(
`biome-${this.root.uri}`,
"biome.lsp",
"biome",
serverOptions,
clientOptions,
Expand All @@ -143,4 +156,13 @@ export class Session extends EventEmitter {
};
});
}

private generateGlobalDocumentSelector(): DocumentSelector {
return supportedLanguages.map((language) => {
return {
language,
scheme: "untitled",
};
});
}
}
47 changes: 45 additions & 2 deletions src/ui/status-bar/status-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,54 @@ export class StatusBar {
}

private update(state: State): void {
this.item.text = `${this.getStateIcon(state)} Biome (${state.activeRoot?.session})`;
this.item.tooltip = `Biome is ${state.state}`;
const { text, tooltip } = this.getStateTextAndTooltip(state);

this.item.text = `${this.getStateIcon(state)} ${text}`.trim();
this.item.tooltip = tooltip;
this.item.show();
}

/**
* Returns the text to display for the given state.
*/
private getStateTextAndTooltip(state: State): {
text: string;
tooltip: string;
} {
switch (state.state) {
case "initializing":
return {
text: "Biome",
tooltip: "Initializing",
};
case "starting":
return {
text: "Biome",
tooltip: "Starting",
};
case "started":
return {
text: "Biome",
tooltip: "Up and running",
};
case "stopping":
return {
text: "Biome",
tooltip: "Stopping",
};
case "stopped":
return {
text: "Biome",
tooltip: "Stopped",
};
default:
return {
text: "Biome",
tooltip: "Biome",
};
}
}

/**
* Returns the icon for the given state.
*/
Expand Down

0 comments on commit 2976d81

Please sign in to comment.