Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code lens for running main #28

Merged
merged 6 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 4 additions & 2 deletions src/effektManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ export class EffektManager {
* Gets the command arguments for starting the Effekt server.
* @returns An array of command arguments.
*/
public getEffektArgs(): string[] {
public getEffektArgs(server: boolean = true): string[] {
const args: string[] = [];
const effektBackend = this.config.get<string>("backend");
const effektLib = this.config.get<string>("lib");
Expand All @@ -519,7 +519,9 @@ export class EffektManager {
const folders = vscode.workspace.workspaceFolders || [];
folders.forEach(folder => args.push("--includes", folder.uri.fsPath));

args.push("--server");
if (server) {
args.push("--server");
}
return args;
}
}
85 changes: 84 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import { EffektManager } from './effektManager';
import { Monto } from './monto';

import * as net from 'net';
import * as path from 'path';

let client: LanguageClient;
let effektManager: EffektManager;
let effektRepl: vscode.Terminal | null = null;

function registerCommands(context: vscode.ExtensionContext) {
context.subscriptions.push(
Expand All @@ -18,10 +20,70 @@ function registerCommands(context: vscode.ExtensionContext) {
vscode.commands.registerCommand('effekt.restartServer', async () => {
await client?.stop();
client?.start();
})
}),
vscode.commands.registerCommand('effekt.runFile', runEffektFile),
);
}

async function getEffektRepl() {
if (effektRepl === null || effektRepl.exitStatus !== undefined) {
const effektExecutable = await effektManager.locateEffektExecutable();
effektRepl = vscode.window.createTerminal({
name: 'Effekt REPL',
shellPath: effektExecutable.path,
shellArgs: effektManager.getEffektArgs(/* server = */ false),
isTransient: true, // Don't persist across VSCode restarts
});
effektRepl.show();
}
return effektRepl;
}

async function runEffektFile(uri: vscode.Uri) {
// Save the document if it has unsaved changes
const document = await vscode.workspace.openTextDocument(uri);
if (document.isDirty) {
await document.save();
}
Comment on lines +39 to +43
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried out a version where this was a pop-up, but it was annoying -- I never want to run the stale version that I can't see...


const repl = await getEffektRepl();

const relativePath = vscode.workspace.asRelativePath(uri);
const parsedPath = path.parse(relativePath);

// Remove .effekt or .effekt.md extension
const moduleName = parsedPath.base.replace(/\.effekt(\.md)?$/, '');

const module = path.join(parsedPath.dir, moduleName).split(path.sep).join('/');

repl.sendText(':reset')
repl.sendText(`import ${module}`);
repl.sendText('main()');
repl.show();
}

class EffektRunCodeLensProvider implements vscode.CodeLensProvider {
public provideCodeLenses(document: vscode.TextDocument): vscode.CodeLens[] {
const codeLenses: vscode.CodeLens[] = [];
const text = document.getText();
const mainFunctionRegex = /^def\s+main\s*\(\s*\)/gm;
let match: RegExpExecArray | null;

while ((match = mainFunctionRegex.exec(text)) !== null) {
const line = document.lineAt(document.positionAt(match.index).line);
const range = new vscode.Range(line.range.start, line.range.end);

codeLenses.push(new vscode.CodeLens(range, {
title: '$(play) Run',
command: 'effekt.runFile',
arguments: [document.uri]
}));
}

return codeLenses;
}
}

export async function activate(context: vscode.ExtensionContext) {
effektManager = new EffektManager();

Expand All @@ -32,6 +94,27 @@ export async function activate(context: vscode.ExtensionContext) {

registerCommands(context);

// Register the CodeLens provider
context.subscriptions.push(
vscode.languages.registerCodeLensProvider(
{ language: 'effekt', scheme: 'file' },
new EffektRunCodeLensProvider()
),
vscode.languages.registerCodeLensProvider(
{ language: 'literate effekt', scheme: 'file' },
new EffektRunCodeLensProvider()
)
);

// Clean up REPL when closed
context.subscriptions.push(
vscode.window.onDidCloseTerminal(terminal => {
if (terminal === effektRepl) {
effektRepl = null;
}
})
);

const config = vscode.workspace.getConfiguration("effekt");

let serverOptions: ServerOptions;
Expand Down