1- 'use strict' ;
2-
31import * as child_process from 'child_process' ;
42import * as fs from 'fs' ;
53import * as https from 'https' ;
64import * as path from 'path' ;
75import * as url from 'url' ;
8- import { ExtensionContext , ProgressLocation , Uri , window , workspace , WorkspaceFolder } from 'vscode' ;
6+ import { env , ExtensionContext , ProgressLocation , Uri , window , workspace , WorkspaceFolder } from 'vscode' ;
97import { downloadFile , executableExists , userAgentHeader } from './utils' ;
108
119/** GitHub API release */
@@ -23,6 +21,43 @@ interface IAsset {
2321// On Windows the executable needs to be stored somewhere with an .exe extension
2422const exeExtension = process . platform === 'win32' ? '.exe' : '' ;
2523
24+ class MissingToolError extends Error {
25+ public readonly tool : string ;
26+ constructor ( tool : string ) {
27+ let prettyTool : string ;
28+ switch ( tool ) {
29+ case 'stack' :
30+ prettyTool = 'Stack' ;
31+ break ;
32+ case 'cabal' :
33+ prettyTool = 'Cabal' ;
34+ break ;
35+ case 'ghc' :
36+ prettyTool = 'GHC' ;
37+ break ;
38+ default :
39+ prettyTool = tool ;
40+ break ;
41+ }
42+ super ( `Project requires ${ prettyTool } but it isn't installed` ) ;
43+ this . tool = prettyTool ;
44+ }
45+
46+ public installLink ( ) : Uri | null {
47+ switch ( this . tool ) {
48+ case 'Stack' :
49+ return Uri . parse ( 'https://docs.haskellstack.org/en/stable/install_and_upgrade/' ) ;
50+ case 'Cabal' :
51+ case 'GHC' :
52+ return process . platform === 'win32'
53+ ? Uri . parse ( 'https://www.haskell.org/platform/index.html#windows' )
54+ : Uri . parse ( 'https://www.haskell.org/ghcup/' ) ;
55+ default :
56+ return null ;
57+ }
58+ }
59+ }
60+
2661/** Works out what the project's ghc version is, downloading haskell-language-server-wrapper
2762 * if needed. Returns null if there was an error in either downloading the wrapper or
2863 * in working out the ghc version
@@ -41,7 +76,15 @@ async function getProjectGhcVersion(context: ExtensionContext, dir: string, rele
4176 throw out . error ;
4277 }
4378 if ( out . status !== 0 ) {
44- throw Error ( `${ wrapper } --project-ghc-version exited with exit code ${ out . status } :\n${ out . stderr } ` ) ;
79+ const regex = / C r a d l e r e q u i r e s ( .+ ) b u t c o u l d n ' t f i n d i t / ;
80+ const res = regex . exec ( out . stderr ) ;
81+ if ( res ) {
82+ throw new MissingToolError ( res [ 1 ] ) ;
83+ }
84+
85+ throw Error (
86+ `${ wrapper } --project-ghc-version exited with exit code ${ out . status } :\n${ out . stdout } \n${ out . stderr } `
87+ ) ;
4588 }
4689 return out . stdout . trim ( ) ;
4790 }
@@ -87,16 +130,11 @@ async function getProjectGhcVersion(context: ExtensionContext, dir: string, rele
87130 * Downloads the latest haskell-language-server binaries from GitHub releases.
88131 * Returns null if it can't find any that match.
89132 */
90- export async function downloadServer (
133+ export async function downloadHaskellLanguageServer (
91134 context : ExtensionContext ,
92135 resource : Uri ,
93136 folder ?: WorkspaceFolder
94137) : Promise < string | null > {
95- // We only download binaries for haskell-language-server at the moment
96- if ( workspace . getConfiguration ( 'haskell' , resource ) . languageServerVariant !== 'haskell-language-server' ) {
97- return null ;
98- }
99-
100138 // Fetch the latest release from GitHub
101139 const releases : IRelease [ ] = await new Promise ( ( resolve , reject ) => {
102140 let data : string = '' ;
@@ -137,8 +175,19 @@ export async function downloadServer(
137175 try {
138176 ghcVersion = await getProjectGhcVersion ( context , dir , release ) ;
139177 } catch ( error ) {
140- // We couldn't figure out the right ghc version to download
141- window . showErrorMessage ( `Couldn't figure out what GHC version the project is using:\n${ error . message } ` ) ;
178+ if ( error instanceof MissingToolError ) {
179+ const link = error . installLink ( ) ;
180+ if ( link ) {
181+ if ( await window . showErrorMessage ( error . message , `Install ${ error . tool } ` ) ) {
182+ env . openExternal ( link ) ;
183+ }
184+ } else {
185+ await window . showErrorMessage ( error . message ) ;
186+ }
187+ } else {
188+ // We couldn't figure out the right ghc version to download
189+ window . showErrorMessage ( `Couldn't figure out what GHC version the project is using:\n${ error . message } ` ) ;
190+ }
142191 return null ;
143192 }
144193
0 commit comments