Skip to content

Commit

Permalink
chore: introduce flix.allJobsFinished
Browse files Browse the repository at this point in the history
  • Loading branch information
sockmaster27 committed Mar 25, 2024
1 parent d420b47 commit 8c9345c
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 5 deletions.
1 change: 1 addition & 0 deletions client/src/engine/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export enum Request {
internalMessage = 'ext/message', // Internal Extension Request
internalError = 'ext/error', // Internal Extension Request
internalFinishedJob = 'ext/finished', // Internal Extension Request
internalFinishedAllJobs = 'ext/finishedAll', // Internal Extension Request
internalDiagnostics = 'ext/diagnostics', // Internal Extension Request
internalReplaceConfiguration = 'ext/replaceConfiguration', // Internal Extension Request
}
14 changes: 12 additions & 2 deletions client/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ export async function activate(context: vscode.ExtensionContext, launchOptions:
registerCommand('flix.showAst', handlers.showAst(client))
registerCommand('flix.startRepl', handlers.startRepl(context, launchOptions))

// Register commands for testing

// Returns a promise resolving when all jobs are completely finished and the server is idle.
// While most other commands can be awaited directly, this is useful for stuff like file creation, which indirectely triggers an asynchronous job.
registerCommand('flix.allJobsFinished', handlers.allJobsFinished(client, eventEmitter))

// watch for changes on the file system (delete, create, rename .flix files)
flixWatcher = vscode.workspace.createFileSystemWatcher(FLIX_GLOB_PATTERN)
flixWatcher.onDidDelete((vsCodeUri: vscode.Uri) => {
Expand Down Expand Up @@ -246,19 +252,23 @@ async function startSession(
})

// Handle when server has answered back after getting the notification above
client.onNotification(jobs.Request.internalReady, function handler() {
client.onNotification(jobs.Request.internalReady, () => {
// waits for server to answer back after having started successfully
eventEmitter.emit(jobs.Request.internalReady)

// start the Flix runner (but only after the Flix LSP instance has started.)
handlers.initSharedRepl(context, launchOptions)
})

client.onNotification(jobs.Request.internalFinishedJob, function handler() {
client.onNotification(jobs.Request.internalFinishedJob, () => {
// only one job runs at once, so currently not trying to distinguish
eventEmitter.emit(jobs.Request.internalFinishedJob)
})

client.onNotification(jobs.Request.internalFinishedAllJobs, () =>
eventEmitter.emit(jobs.Request.internalFinishedAllJobs),
)

client.onNotification(jobs.Request.internalDiagnostics, handlePrintDiagnostics)

client.onNotification(jobs.Request.internalRestart, makeHandleRestartClient(context))
Expand Down
9 changes: 9 additions & 0 deletions client/src/handlers/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as vscode from 'vscode'
import { LanguageClient } from 'vscode-languageclient/node'
import { EventEmitter } from 'events'

import * as jobs from '../engine/jobs'
import ensureFlixExists from './../util/ensureFlixExists'
Expand Down Expand Up @@ -376,3 +377,11 @@ export function startRepl(context: vscode.ExtensionContext, launchOptions: Launc
flixTerminal?.show()
}
}

export function allJobsFinished(client: LanguageClient, eventEmitter: EventEmitter) {
return () =>
new Promise(resolve => {
client.sendNotification(jobs.Request.internalFinishedAllJobs)
eventEmitter.once(jobs.Request.internalFinishedAllJobs, resolve)
})
}
4 changes: 4 additions & 0 deletions server/src/engine/flix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,7 @@ export function enqueueJobWithFlattenedParams(request: jobs.Request, params?: an
}
return queue.enqueue(job)
}

export function unfinishedJobs() {
return queue.unfinishedJobs()
}
1 change: 1 addition & 0 deletions server/src/engine/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export enum Request {
internalMessage = 'ext/message', // Internal Extension Request
internalError = 'ext/error', // Internal Extension Request
internalFinishedJob = 'ext/finished', // Internal Extension Request
internalFinishedAllJobs = 'ext/finishedAll', // Internal Extension Request
internalDiagnostics = 'ext/diagnostics', // Internal Extension Request
internalReplaceConfiguration = 'ext/replaceConfiguration', // Internal Extension Request
}
Expand Down
7 changes: 7 additions & 0 deletions server/src/engine/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,10 @@ export async function terminateQueue() {
})
emptyQueue()
}

/**
* The number of jobs which have been added to the queue, but have yet to be processed.
*/
export function unfinishedJobs() {
return priorityQueue.length + taskQueue.length + socket.unprocessedRequests()
}
9 changes: 9 additions & 0 deletions server/src/engine/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,13 @@ function handleResponse(flixResponse: FlixResponse, job: jobs.EnqueuedJob) {
clearTimer(flixResponse.id)
// ask queue to process next item
setTimeout(queue.processQueue, 0)

eventEmitter.emit('any')
}

/**
* The number of sent requests which have not yet received a response.
*/
export function unprocessedRequests() {
return Object.keys(sentMessagesMap).length
}
17 changes: 17 additions & 0 deletions server/src/handlers/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,23 @@ export const handleShowAst = enqueueUnlessHasErrors(
hasErrorsHandlerForCommands,
)

/**
* Request a response to be sent when all jobs are finished.
*/
export function handleFinishedAllJobs() {
if (engine.unfinishedJobs() === 0) {
// If already idle, send notification immediately
sendNotification(jobs.Request.internalFinishedAllJobs)
} else {
socket.eventEmitter.on('any', function handler() {
if (engine.unfinishedJobs() === 0) {
sendNotification(jobs.Request.internalFinishedAllJobs)
socket.eventEmitter.removeListener('any', handler)
}
})
}
}

function makeShowAstJob(params: any) {
return {
request: jobs.Request.lspShowAst,
Expand Down
2 changes: 2 additions & 0 deletions server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ connection.onNotification(jobs.Request.apiRemJar, handlers.handleRemJar)
// Show ast
connection.onNotification(jobs.Request.lspShowAst, handlers.handleShowAst)

connection.onNotification(jobs.Request.internalFinishedAllJobs, handlers.handleFinishedAllJobs)

// Cleanup after exit
connection.onExit(handlers.handleExit)

Expand Down
17 changes: 14 additions & 3 deletions test/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,31 @@ export async function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms))
}

/**
* Waits for the processing of a newly added or deleted file to finish.
*/
async function processFileChange() {
// Wait for the file system watcher to pick up the change
await sleep(500)

// Wait for the compiler to process the change
await vscode.commands.executeCommand('flix.allJobsFinished')
}

/**
* Add a file with the given `uri` and `content`, and wait for the compiler to process this.
*/
export async function addFile(uri: vscode.Uri, content: string) {
await vscode.workspace.fs.writeFile(uri, Buffer.from(content))
await sleep(6000)
await processFileChange()
}

/**
* Copy the file from `from` to `to`, and wait for the compiler to process this.
*/
export async function copyFile(from: vscode.Uri, to: vscode.Uri) {
await vscode.workspace.fs.copy(from, to)
await sleep(6000)
await processFileChange()
}

/**
Expand All @@ -77,5 +88,5 @@ export async function copyFile(from: vscode.Uri, to: vscode.Uri) {
*/
export async function deleteFile(uri: vscode.Uri) {
await vscode.workspace.fs.delete(uri)
await sleep(2000)
await processFileChange()
}

0 comments on commit 8c9345c

Please sign in to comment.