Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
38 changes: 38 additions & 0 deletions server/src/engine/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2020 Thomas Plougsgaard
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export interface UserConfiguration {
extraJvmArgs: string
extraFlixArgs: string
}

/**
* Payload sent from the client via the `internalReady` notification.
*
* In single-file mode (no folder open) `workspaceFolders` is omitted and
* `workspaceFiles` contains only the currently open `.flix` file(s).
*/
export interface StartEngineInput {
flixFilename: string
workspaceFolders?: string[]
extensionPath: string
extensionVersion: string
globalStoragePath: string
workspaceFiles: string[]
workspacePkgs: string[]
workspaceJars: string[]
userConfiguration: UserConfiguration
}
4 changes: 3 additions & 1 deletion server/src/engine/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@
* limitations under the License.
*/

export * from './flix'
export * from './config'
export * from './process'
export * from './workspace'
119 changes: 3 additions & 116 deletions server/src/engine/flix.ts → server/src/engine/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,38 +20,16 @@ import javaVersion from '../util/javaVersion'
import { ChildProcess, spawn } from 'child_process'
import { getPortPromise } from 'portfinder'

import { UserConfiguration, StartEngineInput } from './config'
import { initWorkspaceFiles } from './workspace'
import * as jobs from './jobs'
import * as queue from './queue'
import * as socket from './socket'
import { USER_MESSAGE } from '../util/userMessages'

export interface UserConfiguration {
extraJvmArgs: string
extraFlixArgs: string
}

/**
* Payload sent from the client via the `internalReady` notification.
*
* In single-file mode (no folder open) `workspaceFolders` is omitted and
* `workspaceFiles` contains only the currently open `.flix` file(s).
*/
export interface StartEngineInput {
flixFilename: string
workspaceFolders?: string[]
extensionPath: string
extensionVersion: string
globalStoragePath: string
workspaceFiles: string[]
workspacePkgs: string[]
workspaceJars: string[]
userConfiguration: UserConfiguration
}

let flixInstance: ChildProcess | undefined = undefined
let startEngineInput: StartEngineInput
let flixRunning: boolean = false
let currentWorkspaceFiles: Set<string> = new Set()

export function isRunning() {
return flixRunning
Expand Down Expand Up @@ -81,7 +59,7 @@ export async function start(input: StartEngineInput) {

const { flixFilename, extensionPath, workspaceFiles, workspacePkgs, workspaceJars } = input

currentWorkspaceFiles = new Set(workspaceFiles)
initWorkspaceFiles(workspaceFiles)

// Check for valid Java version
const { majorVersion, versionString } = await javaVersion(extensionPath)
Expand Down Expand Up @@ -175,94 +153,3 @@ export async function stop() {
flixInstance.kill()
}
}

/**
* Add the given `uri` to the workspace.
*/
export function addUri(uri: string) {
currentWorkspaceFiles.add(uri)

const job: jobs.Job = {
request: jobs.Request.apiAddUri,
uri,
}
queue.enqueue(job)
}

/**
* Handle a change in the file with the given `uri`.
*
* If this URI has not already been added to the workspace via {@linkcode addUri},
* it will be ignored, making it safe to call this function on any file.
*/
export function updateUri(uri: string, src: string) {
if (!currentWorkspaceFiles.has(uri)) {
return
}

// Including the source code in the job is necessary because the file might not yet have been saved
const job: jobs.Job = {
request: jobs.Request.apiAddUri,
uri,
src,
}

queue.enqueue(job)
}

/**
* Remove the given `uri` from the workspace.
*/
export function remUri(uri: string) {
currentWorkspaceFiles.delete(uri)

const job: jobs.Job = {
request: jobs.Request.apiRemUri,
uri,
}
queue.enqueue(job)
}

export function addPkg(uri: string) {
const job: jobs.Job = {
request: jobs.Request.apiAddPkg,
uri,
}
queue.enqueue(job)
}

export function remPkg(uri: string) {
const job: jobs.Job = {
request: jobs.Request.apiRemPkg,
uri,
}
queue.enqueue(job)
}

export function addJar(uri: string) {
const job: jobs.Job = {
request: jobs.Request.apiAddJar,
uri,
}
queue.enqueue(job)
}

export function remJar(uri: string) {
const job: jobs.Job = {
request: jobs.Request.apiRemJar,
uri,
}
queue.enqueue(job)
}

export function enqueueJobWithFlattenedParams(request: jobs.Request, params?: any) {
const job: jobs.Job = {
request,
...(params || {}),
}
return queue.enqueue(job)
}

export function unfinishedJobs() {
return queue.unfinishedJobs()
}
2 changes: 1 addition & 1 deletion server/src/engine/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import * as engine from './flix'
import * as engine from './process'
import * as jobs from './jobs'
import * as socket from './socket'
import { fileURLToPath } from 'url'
Expand Down
115 changes: 115 additions & 0 deletions server/src/engine/workspace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright 2020 Thomas Plougsgaard
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as jobs from './jobs'
import * as queue from './queue'

let currentWorkspaceFiles: Set<string> = new Set()

export function initWorkspaceFiles(files: string[]) {
currentWorkspaceFiles = new Set(files)
}

/**
* Add the given `uri` to the workspace.
*/
export function addUri(uri: string) {
currentWorkspaceFiles.add(uri)

const job: jobs.Job = {
request: jobs.Request.apiAddUri,
uri,
}
queue.enqueue(job)
}

/**
* Handle a change in the file with the given `uri`.
*
* If this URI has not already been added to the workspace via {@linkcode addUri},
* it will be ignored, making it safe to call this function on any file.
*/
export function updateUri(uri: string, src: string) {
if (!currentWorkspaceFiles.has(uri)) {
return
}

// Including the source code in the job is necessary because the file might not yet have been saved
const job: jobs.Job = {
request: jobs.Request.apiAddUri,
uri,
src,
}

queue.enqueue(job)
}

/**
* Remove the given `uri` from the workspace.
*/
export function remUri(uri: string) {
currentWorkspaceFiles.delete(uri)

const job: jobs.Job = {
request: jobs.Request.apiRemUri,
uri,
}
queue.enqueue(job)
}

export function addPkg(uri: string) {
const job: jobs.Job = {
request: jobs.Request.apiAddPkg,
uri,
}
queue.enqueue(job)
}

export function remPkg(uri: string) {
const job: jobs.Job = {
request: jobs.Request.apiRemPkg,
uri,
}
queue.enqueue(job)
}

export function addJar(uri: string) {
const job: jobs.Job = {
request: jobs.Request.apiAddJar,
uri,
}
queue.enqueue(job)
}

export function remJar(uri: string) {
const job: jobs.Job = {
request: jobs.Request.apiRemJar,
uri,
}
queue.enqueue(job)
}

export function enqueueJobWithFlattenedParams(request: jobs.Request, params?: any) {
const job: jobs.Job = {
request,
...(params || {}),
}
return queue.enqueue(job)
}

export function unfinishedJobs() {
return queue.unfinishedJobs()
}
69 changes: 69 additions & 0 deletions server/src/handlers/editing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2020 Thomas Plougsgaard
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { DocumentFormattingParams, TextEdit } from 'vscode-languageserver'

import * as jobs from '../engine/jobs'
import * as engine from '../engine'
import * as socket from '../engine/socket'

import { makePositionalHandler, makeEnqueuePromise, makeDefaultResponseHandler } from './util'

/**
* @function
*/
export const handleComplete = makePositionalHandler(jobs.Request.lspComplete)

/**
* @function
*/
export const handleHover = makePositionalHandler(jobs.Request.lspHover)

export const handleSignature = makePositionalHandler(jobs.Request.lspSignature)

/**
* @function
*/
export const handleRename = makeEnqueuePromise(makeRenameJob, makeDefaultResponseHandler) as (
params: any,
) => Promise<any>

function makeRenameJob(params: any) {
return {
request: jobs.Request.lspRename,
uri: params.textDocument.uri,
position: params.position,
newName: params.newName,
}
}

/**
* Handle document formatting requests.
*
* @param params - The document formatting parameters.
* @returns A promise that resolves to an array of text edits.
*/
export const handleDocumentFormatting = (params: DocumentFormattingParams): Promise<TextEdit[]> => {
const uri = params.textDocument?.uri
const options = params.options

return new Promise<TextEdit[]>(function (resolve) {
const job = engine.enqueueJobWithFlattenedParams(jobs.Request.lspFormatting, { uri, options })
socket.eventEmitter.once(job.id, ({ result }: socket.FlixResponse) => {
resolve((result ?? []) as unknown as TextEdit[])
})
})
}
7 changes: 6 additions & 1 deletion server/src/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@
* limitations under the License.
*/

export * from './handlers'
export * from './lifecycle'
export * from './navigation'
export * from './editing'
export * from './symbols'
export * from './semantic'
export * from './resources'
Loading
Loading