|
1 | 1 | import { LanguageClient, ServerOptions, LanguageClientOptions, StreamInfo } from 'vscode-languageclient/node'
|
2 | 2 | import { EvaluatableExpressionRequest } from './protocol'
|
3 | 3 |
|
| 4 | +import { spawn } from 'child_process' |
| 5 | + |
4 | 6 | import * as vscode from 'vscode'
|
5 | 7 | import { join } from 'path'
|
6 | 8 | import * as net from 'net'
|
@@ -92,7 +94,10 @@ function checkPlatform(): boolean {
|
92 | 94 |
|
93 | 95 | function getServerOptions(config: PhpactorConfig): ServerOptions {
|
94 | 96 | let serverOptions
|
95 |
| - if (!config.remote.enabled) { |
| 97 | + if (!config.remote.enabled && process.platform === 'win32') { |
| 98 | + // PHP on windows has problems with STDIO so we need special handling |
| 99 | + serverOptions = getWindowsServerOptions(config) |
| 100 | + } else if (!config.remote.enabled) { |
96 | 101 | // launch language server via stdio
|
97 | 102 | serverOptions = <ServerOptions>{
|
98 | 103 | run: {
|
@@ -133,6 +138,71 @@ function getServerOptions(config: PhpactorConfig): ServerOptions {
|
133 | 138 | return serverOptions
|
134 | 139 | }
|
135 | 140 |
|
| 141 | +function getWindowsServerOptions(config: PhpactorConfig): ServerOptions { |
| 142 | + // Find a free port, start PHPActor and connect to it |
| 143 | + const serverOptions = async () => { |
| 144 | + const findPort = new Promise<number>(resolve => { |
| 145 | + const server = net.createServer() |
| 146 | + server.listen(0, '127.0.0.1', () => { |
| 147 | + const freePort = (server.address()! as net.AddressInfo).port |
| 148 | + server.close() |
| 149 | + resolve(freePort) |
| 150 | + }) |
| 151 | + }) |
| 152 | + |
| 153 | + const freePort = await findPort |
| 154 | + |
| 155 | + const startServer = new Promise<void>((resolve, reject) => { |
| 156 | + const childProcess = spawn( |
| 157 | + config.executablePath, |
| 158 | + [config.path, 'language-server', `--address=127.0.0.1:${freePort}`, ...config.launchServerArgs], |
| 159 | + |
| 160 | + { |
| 161 | + env: { |
| 162 | + ...process.env, |
| 163 | + XDEBUG_MODE: 'debug', |
| 164 | + PHPACTOR_ALLOW_XDEBUG: '1', |
| 165 | + }, |
| 166 | + } |
| 167 | + ) |
| 168 | + |
| 169 | + childProcess.stderr.on('data', (chunk: Buffer) => { |
| 170 | + const str = chunk.toString() |
| 171 | + languageClient.outputChannel.appendLine(str) |
| 172 | + |
| 173 | + // when we get the first line, the server is running |
| 174 | + resolve() |
| 175 | + }) |
| 176 | + childProcess.on('exit', (code, signal) => { |
| 177 | + languageClient.outputChannel.appendLine( |
| 178 | + `Language server exited ` + (signal ? `from signal ${signal}` : `with exit code ${code}`) |
| 179 | + ) |
| 180 | + if (code !== 0) { |
| 181 | + languageClient.outputChannel.show() |
| 182 | + } |
| 183 | + |
| 184 | + reject(new Error('Language Server exited')) |
| 185 | + }) |
| 186 | + }) |
| 187 | + |
| 188 | + await startServer |
| 189 | + |
| 190 | + const socket = net.connect({ |
| 191 | + host: '127.0.0.1', |
| 192 | + port: freePort, |
| 193 | + }) |
| 194 | + |
| 195 | + const result = <StreamInfo>{ |
| 196 | + writer: socket, |
| 197 | + reader: socket, |
| 198 | + } |
| 199 | + |
| 200 | + return result |
| 201 | + } |
| 202 | + |
| 203 | + return serverOptions |
| 204 | +} |
| 205 | + |
136 | 206 | function createClient(config: PhpactorConfig): LanguageClient {
|
137 | 207 | const serverOptions = getServerOptions(config)
|
138 | 208 |
|
|
0 commit comments