Skip to content

Commit

Permalink
Merge branch 'master' of github.com:yatli/fsharp-language-server
Browse files Browse the repository at this point in the history
  • Loading branch information
Yatao Li committed Jul 31, 2019
2 parents 338b3e9 + 9baed63 commit 5684180
Show file tree
Hide file tree
Showing 7 changed files with 448 additions and 75 deletions.
29 changes: 29 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml

trigger:
- master

pool:
vmImage: 'windows-latest'
steps:
- task: UseDotNet@2
displayName: 'Use .NET Core sdk'
inputs:
packageType: sdk
includePreviewVersions: true
version: 3.0.100-preview6-012264
installationPath: $(Agent.ToolsDirectory)/dotnet
- task: NuGetToolInstaller@1
- task: PowerShell@2
inputs:
filePath: 'pack.ps1'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: 'publish'
ArtifactName: 'drop'
publishLocation: 'Container'


49 changes: 19 additions & 30 deletions client/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { workspace, ExtensionContext, commands, StatusBarItem, TerminalResult }
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'coc.nvim';
import { NotificationType } from 'vscode-jsonrpc';
import { Range } from 'vscode-languageserver-protocol';
import {OperatingSystem, currentPlatform, languageServerExe, downloadLanguageServer} from './platform'


async function getCurrentSelection(mode: string) {
Expand Down Expand Up @@ -115,19 +116,27 @@ function registerREPL(context: ExtensionContext, __: string) {
export async function activate(context: ExtensionContext) {

// The server is packaged as a standalone command
let serverMain = context.asAbsolutePath(binName());
let serverMain = context.asAbsolutePath(languageServerExe);

if (!fs.existsSync(serverMain)) {
let item = workspace.createStatusBarItem(0, {progress: true})
item.text = "Downloading F# Language Server"
item.show()
await downloadLanguageServer()
item.dispose()
}

// Make sure the server is executable
fs.chmodSync(serverMain, '755')
if (currentPlatform.operatingSystem !== OperatingSystem.Windows) {
fs.chmodSync(serverMain, "755")
}

let serverOptions: ServerOptions = {
command: serverMain,
args: [],
transport: TransportKind.stdio
}

workspace.addRootPatterns('fsharp', ['*.fsproj', '*.fsx', 'projects.assets.json', '.vim', '.git', '.hg'])

// Options to control the language client
let clientOptions: LanguageClientOptions = {
// Register the server for F# documents
Expand All @@ -138,6 +147,8 @@ export async function activate(context: ExtensionContext) {
// Notify the server about file changes to F# project files contain in the workspace
fileEvents: [
workspace.createFileSystemWatcher('**/*.fsproj'),
workspace.createFileSystemWatcher('**/*.fs'),
workspace.createFileSystemWatcher('**/*.fsi'),
workspace.createFileSystemWatcher('**/*.fsx'),
workspace.createFileSystemWatcher('**/project.assets.json')
]
Expand Down Expand Up @@ -227,38 +238,16 @@ function createProgressListeners(client: LanguageClient) {
this.statusBarItem = null
}
}

// Use custom notifications to drive progressListener
client.onNotification(new NotificationType('fsharp/startProgress'), (start: StartProgress) => {
client.onNotification('fsharp/startProgress', (start: StartProgress) => {
progressListener.startProgress(start);
});
client.onNotification(new NotificationType('fsharp/incrementProgress'), (fileName: string) => {
client.onNotification('fsharp/incrementProgress', (fileName: string) => {
progressListener.incrementProgress(fileName);
});
client.onNotification(new NotificationType('fsharp/endProgress'), () => {
client.onNotification('fsharp/endProgress', () => {
progressListener.endProgress();
});
}

function binName(): string {
var baseParts = ['out', 'server'];
var pathParts = getPathParts(process.platform);
var fullParts = baseParts.concat(pathParts);

return path.join(...fullParts);
}

function getPathParts(platform: string): string[] {
switch (platform) {
case 'win32':
return ['win10-x64', 'FSharpLanguageServer.exe'];

case 'linux':
return ['linux-x64', 'FSharpLanguageServer'];

case 'darwin':
return ['osx.10.11-x64', 'FSharpLanguageServer'];
}

throw `unsupported platform: ${platform}`;
}

103 changes: 103 additions & 0 deletions client/platform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/

import { workspace } from 'coc.nvim'
import {sleep} from "./utils"
import fs = require("fs");
import path = require("path");
import process = require("process");
import { IncomingMessage, RequestOptions, Agent } from 'http'
import { parse } from 'url'
const tunnel = require('tunnel')
const followRedirects = require("follow-redirects")
const unzip = require("extract-zip");
const rimraf = require("rimraf")

export enum OperatingSystem {
Unknown,
Windows,
MacOS,
Linux,
}

export interface IPlatformDetails {
operatingSystem: OperatingSystem;
isOS64Bit: boolean;
isProcess64Bit: boolean;
}

export function getPlatformDetails(): IPlatformDetails {
let operatingSystem = OperatingSystem.Unknown;

if (process.platform === "win32") {
operatingSystem = OperatingSystem.Windows;
} else if (process.platform === "darwin") {
operatingSystem = OperatingSystem.MacOS;
} else if (process.platform === "linux") {
operatingSystem = OperatingSystem.Linux;
}

const isProcess64Bit = process.arch === "x64";

return {
operatingSystem,
isOS64Bit: isProcess64Bit || process.env.hasOwnProperty("PROCESSOR_ARCHITEW6432"),
isProcess64Bit,
};
}

export const currentPlatform = getPlatformDetails()
export const languageServerDirectory = path.join(__dirname, "..", "server")
const languageServerZip = languageServerDirectory + ".zip"
const URL_Windows = "https://github.com/yatli/coc-fsharp/releases/download/RELEASE/coc-fsharp-win10-x64.zip"
const URL_Osx = "https://github.com/yatli/coc-fsharp/releases/download/RELEASE/coc-fsharp-osx.10.11-x64.zip"
const URL_Linux = "https://github.com/yatli/coc-fsharp/releases/download/RELEASE/coc-fsharp-linux-x64.zip"

export const languageServerExe = (() => {
if (currentPlatform.operatingSystem === OperatingSystem.Windows)
return path.join(languageServerDirectory, "FSharpLanguageServer.exe")
else
return path.join(languageServerDirectory, "FSharpLanguageServer")
})()

export async function downloadLanguageServer() {

if(fs.existsSync(languageServerDirectory)){
rimraf.sync(languageServerDirectory)
}

let url = (()=>{
switch(currentPlatform.operatingSystem) {
case OperatingSystem.Windows: return URL_Windows
case OperatingSystem.Linux: return URL_Linux
case OperatingSystem.MacOS: return URL_Osx
default: throw "Unsupported operating system"
}
})().replace("RELEASE", "v0.2.0")

fs.mkdirSync(languageServerDirectory)

await new Promise<void>((resolve, reject) => {
const req = followRedirects.https.request(url, (res: IncomingMessage) => {
if (res.statusCode != 200) {
reject(new Error(`Invalid response from ${url}: ${res.statusCode}`))
return
}
let file = fs.createWriteStream(languageServerZip)
let stream = res.pipe(file)
stream.on('finish', resolve)
})
req.on('error', reject)
req.end()
})

await new Promise<void>((resolve, reject) => {
unzip(languageServerZip, {dir: languageServerDirectory}, (err: any) => {
if(err) reject(err)
else resolve()
})
})

fs.unlinkSync(languageServerZip)
}
58 changes: 58 additions & 0 deletions client/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/

"use strict";

import fs = require("fs");
import os = require("os");
import path = require("path");
import { Uri } from 'coc.nvim'

export function fileURLToPath(x: string) {
return Uri.parse(x).fsPath
}

export function sleep(ms: number) {
return new Promise((resolve, __) => setTimeout(resolve, ms))
}

export function ensurePathExists(targetPath: string) {
// Ensure that the path exists
try {
fs.mkdirSync(targetPath);
} catch (e) {
// If the exception isn't to indicate that the folder exists already, rethrow it.
if (e.code !== "EEXIST") {
throw e;
}
}
}

export function getPipePath(pipeName: string) {
if (os.platform() === "win32") {
return "\\\\.\\pipe\\" + pipeName;
} else {
// Windows uses NamedPipes where non-Windows platforms use Unix Domain Sockets.
// This requires connecting to the pipe file in different locations on Windows vs non-Windows.
return path.join(os.tmpdir(), `CoreFxPipe_${pipeName}`);
}
}

export function checkIfFileExists(filePath: string): boolean {
try {
fs.accessSync(filePath, fs.constants.R_OK);
return true;
} catch (e) {
return false;
}
}

export function getTimestampString() {
const time = new Date();
return `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}]`;
}

export function isWindowsOS(): boolean {
return os.platform() === "win32";
}
21 changes: 15 additions & 6 deletions pack.ps1
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
$plat = "win10-x64","linux-x64","osx.10.11-x64"

New-Item -ItemType Directory -Force -Name out
New-Item -ItemType Directory -Force -Name publish
New-Item -ItemType Directory -Force -Name bin
Remove-Item bin/* -Recurse -Force
Remove-Item out/* -Recurse -Force
New-Item -ItemType Directory -Force out/server
Remove-Item publish/* -Recurse -Force

# client

npm install
npm run compile
npm pack --silent
Move-Item *.tgz publish/

# server

$plat = "win10-x64","linux-x64","osx.10.11-x64"

foreach($i in $plat) {
foreach ($i in $plat) {
dotnet publish -f netcoreapp2.2 -c Release --self-contained `
-r $i src/FSharpLanguageServer -o ./out/server/$i
-r $i src/FSharpLanguageServer -o ./bin/$i
Compress-Archive -Path ./bin/$i/* -DestinationPath publish/coc-fsharp-$i.zip -Force
}

npm pack
Loading

0 comments on commit 5684180

Please sign in to comment.