From d9410422cc45fd4cf07098331cdf7853de7f2185 Mon Sep 17 00:00:00 2001 From: Krzysztof Cieslak Date: Mon, 5 Aug 2019 19:01:52 +0200 Subject: [PATCH] Add commands for installing and browsing Elm packages --- .vscode/settings.json | 3 +- client/src/elmPackage.ts | 147 +++++++++++++++++++++++++++++++++++++++ client/src/extension.ts | 3 + client/src/utils.ts | 27 +++++++ package.json | 12 ++++ 5 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 client/src/elmPackage.ts create mode 100644 client/src/utils.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 4a9bab7..b0b5bae 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,6 @@ "editor.insertSpaces": false, "tslint.enable": true, "typescript.tsc.autoDetect": "off", - "typescript.preferences.quoteStyle": "single" + "typescript.preferences.quoteStyle": "single", + "editor.tabSize": 2 } \ No newline at end of file diff --git a/client/src/elmPackage.ts b/client/src/elmPackage.ts new file mode 100644 index 0000000..0742fc9 --- /dev/null +++ b/client/src/elmPackage.ts @@ -0,0 +1,147 @@ +import * as vscode from 'vscode'; +import * as utils from './utils' + +const request = require('request'); +let packageTerminal: vscode.Terminal; + +interface ElmPackageQuickPickItem extends vscode.QuickPickItem { + info: any; +} + +function transformToPackageQuickPickItems( + packages: any[], +): ElmPackageQuickPickItem[] { + return Object.keys(packages).map((item: any) => { + return { label: item, description: item, info: packages[item] }; + }); +} + +function transformToPackageVersionQuickPickItems( + selectedPackage: ElmPackageQuickPickItem, +): vscode.QuickPickItem[] { + return selectedPackage.info.map((version: any) => { + return { label: version, description: null }; + }); +} + +function transformToQuickPickItems(packages: any[]): vscode.QuickPickItem[] { + return Object.keys(packages).map((item: any) => { + return { label: item, description: '', info: packages[item] }; + }); +} + +function getJSON(): Thenable { + return new Promise((resolve, reject) => { + request('https://package.elm-lang.org/all-packages', (err: any, _: any, body: any) => { + if (err) { + reject(err); + } else { + let json; + try { + json = JSON.parse(body); + } catch (e) { + reject(e); + } + resolve(json); + } + }); + }); +} + +function getInstallPackageCommand(packageToInstall: string): string { + const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration( + 'ElmLS', + ); + let t: string = config.get('elmLS.elmPath'); + t = t == undefined ? "elm" : t + + return t + ' install ' + packageToInstall; +} + +function installPackageInTerminal(packageToInstall: string) { + try { + let installPackageCommand = getInstallPackageCommand(packageToInstall); + if (packageTerminal !== undefined) { + packageTerminal.dispose(); + } + packageTerminal = vscode.window.createTerminal('Elm Package Install'); + let [ + installPackageLaunchCommand, + clearCommand, + ] = utils.getTerminalLaunchCommands(installPackageCommand); + packageTerminal.sendText(clearCommand, true); + packageTerminal.sendText(installPackageLaunchCommand, true); + packageTerminal.show(false); + } catch (error) { + vscode.window.showErrorMessage( + 'Cannot start Elm Package install. ' + error, + ); + } +} + +function browsePackage(): Thenable { + const quickPickPackageOptions: vscode.QuickPickOptions = { + matchOnDescription: true, + placeHolder: 'Choose a package', + }; + const quickPickVersionOptions: vscode.QuickPickOptions = { + matchOnDescription: false, + placeHolder: 'Choose a version, or press to browse the latest', + }; + + return getJSON() + .then(transformToPackageQuickPickItems) + .then(packages => + vscode.window.showQuickPick(packages, quickPickPackageOptions), + ) + .then(selectedPackage => { + if (selectedPackage === undefined) { + return; // no package + } + return vscode.window + .showQuickPick( + transformToPackageVersionQuickPickItems(selectedPackage), + quickPickVersionOptions, + ) + .then(selectedVersion => { + let uri = selectedVersion + ? vscode.Uri.parse( + 'https://package.elm-lang.org/packages/' + + selectedPackage.label + + '/' + + selectedVersion.label, + ) + : vscode.Uri.parse( + 'https://package.elm-lang.org/packages/' + + selectedPackage.label + + '/latest', + ); + vscode.commands.executeCommand('vscode.open', uri); + }) + .then(() => { }); + }); +} + +function runInstall(): Thenable { + const quickPickOptions: vscode.QuickPickOptions = { + matchOnDescription: true, + placeHolder: + 'Choose a package, or press to install all packages in elm-package.json', + }; + + return getJSON() + .then(transformToQuickPickItems) + .then(items => vscode.window.showQuickPick(items, quickPickOptions)) + .then(value => { + const packageName = value ? value.label : ''; + return installPackageInTerminal(packageName); + }); +} + + +export function activatePackage(): vscode.Disposable[] { + return [ + vscode.commands.registerCommand('elm.install', runInstall), + vscode.commands.registerCommand('elm.browsePackage', browsePackage), + ]; +} \ No newline at end of file diff --git a/client/src/extension.ts b/client/src/extension.ts index 720d36d..8215b48 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -17,6 +17,8 @@ import { RevealOutputChannelOn, } from "vscode-languageclient"; +import * as Package from "./elmPackage"; + let languageClient: LanguageClient; const elmJsonGlob = "**/elm.json"; @@ -164,6 +166,7 @@ function startClient(context: ExtensionContext, elmWorkspace: Uri) { // Start the client. This will also launch the server languageClient.start(); + Package.activatePackage() clients.set(elmWorkspace.fsPath, languageClient); } diff --git a/client/src/utils.ts b/client/src/utils.ts new file mode 100644 index 0000000..3135850 --- /dev/null +++ b/client/src/utils.ts @@ -0,0 +1,27 @@ +import * as vscode from 'vscode'; + +export const isWindows = process.platform === 'win32'; + +function isPowershell() { + try { + const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration( + 'ElmLS', + ); + const t: string = config.get('terminal.integrated.shell.windows'); + return t.toLowerCase().includes('powershell'); + } catch (error) { + return false; + } +} + +export function getTerminalLaunchCommands(command: string): [string, string] { + if (isWindows) { + if (isPowershell()) { + return [`cmd /c ${command}`, 'clear']; + } else { + return [`${command}`, 'cls']; + } + } else { + return [command, 'clear']; + } +} \ No newline at end of file diff --git a/package.json b/package.json index 4ea0134..310da7c 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,18 @@ "path": "./syntaxes/elm.json" } ], + "commands":[ + { + "command": "elm.install", + "title": "Install Package", + "category": "Elm" + }, + { + "command": "elm.browsePackage", + "title": "Browse Package", + "category": "Elm" + } + ], "configuration": { "type": "object", "title": "ElmLS",