felixfbecker / vscode-php-intellisense

Advanced PHP IntelliSense for Visual Studio Code 🆚💬
MIT License
414 stars 88 forks source link

Set php executable path to docker or lando #471

Open martin-sweeny opened 4 years ago

martin-sweeny commented 4 years ago

The extension doesn't recognize php binaries residing in containers. Tools like Docker (and implementations like Devilbox or Lando) are becoming more and more popular, and are considered normal development environments by many.

Issue #150 addresses this but no good answer was proposed and it was closed without any commentary.

We need a way to use commands like (lando php or docker-compose exec php php) in place of the usual php binary

martin-sweeny commented 4 years ago

It looks like #448 also mentions using a Devilbox setup.

No, it's not possible because the PHP language server is written in PHP.

That shouldn't be a problem since there is a containerized php ready to go

alcohol commented 4 years ago

Was fiddling around a bit, bit couldn't manage to get it working.

Using the following bash script as a wrapper for running php inside a docker container and configuring it through php.executablePath:

~/bin/php

#!/usr/bin/env bash

if ! command -v docker >/dev/null 2>&1; then
  echo "Cannot run 'php', Docker not available" >&2
  exit 1
fi

tty=
tty -s && tty=--tty

docker run \
  $tty \
  --interactive \
  --rm \
  --init \
  --user $(id -u):$(id -g) \
  --cap-drop ALL \
  --read-only \
  --env HOME \
  --tmpfs /tmp \
  --publish 1337:1337 \
  --volume $HOME:$HOME \
  --volume /etc/passwd:/etc/passwd:ro \
  --volume /etc/group:/etc/group:ro \
  --volume "$(pwd)":/workdir \
  --workdir /workdir \
  --entrypoint /usr/local/bin/php \
  php:cli-alpine "$@"

exit $?

And modifying the following lines: https://github.com/felixfbecker/vscode-php-intellisense/blob/4898e75f4ec7aa030290ad71e3cfde347e6891df/src/extension.ts#L82-L109

To look like:

// Don't spawn a server and connect as a client, run the php-language-server.php as a server instead
server.listen(() => {
    // The server is implemented in PHP
    const childProcess = child_process_1.spawn(executablePath, [
        context.asAbsolutePath(path.join('vendor', 'felixfbecker', 'language-server', 'bin', 'php-language-server.php')),
        '--tcp-server=0.0.0.0:1337',
        '--memory-limit=' + memoryLimit,
    ])
    childProcess.stderr.on('data', (chunk) => {
        const str = chunk.toString()
        console.log('PHP Language Server:', str)
        client.outputChannel.appendLine(str)
    })
    // childProcess.stdout.on('data', (chunk: Buffer) => {
    //     console.log('PHP Language Server:', chunk + '')
    // })
    childProcess.on('exit', (code, signal) => {
        client.outputChannel.appendLine(`Language server exited ` + (signal ? `from signal ${signal}` : `with exit code ${code}`))
        if (code !== 0) {
            client.outputChannel.show()
        }
    })
    return childProcess
})

I can see the server spawning properly, but it doesn't seem to do anything:

DEBUG     Checking PHPLS_ALLOW_XDEBUG
DEBUG     The xdebug extension is not loaded
DEBUG     Server listening on 0.0.0.0:1337
NOTICE    PCNTL is not available. Only a single connection will be accepted
martin-sweeny commented 4 years ago

@alcohol I salute the good work, but I think this should be a feature of the extension, not the users' responsibility

alcohol commented 4 years ago

I know, I was just exploring the possibility of what it would take to submit a PR that could enable this functionality. So far, the amount of changes is rather minimal. One could put those behind configuration toggles and the extension would still work as-is and support execution within a Docker container. But as stated above, I did not yet manage to get it completely working.

alcohol commented 4 years ago

Unfortunately my experience with Javascript is rather limited in comparison to my experience with PHP and Docker and such. So I'm not sure how to proceed.

artm commented 4 years ago

The original code created a local node server that starts the language server in "tcp" mode that connects to this server over TCP. A socket to the local server is then passed to vscode / extension and when they talk to this server they actually talk to the language server.

The new code starts the language server in "tcp-server" mode, listening on port 1337 which is mapped between the container and the host. But it is still a socket to the local node server that is passed to vscode / extension, only now it isn't connected to the language server.

What I think should happen is: the language server should start just like now, then a socket should be created from "here" to the language server and it is this socket that has to be passed to resolve({ reader: socket, writer: socket });

The problem to overcome is that socket must be created asyncronously, after the language server has started and is listening.

kukocrunch commented 3 years ago

The only way for now to make the extension work is installing this Remote - Containers

After installation, you can attach your running containers (devilbox PHP for me) to your workspace and then you can install PHP-intellisense image

martin-sweeny commented 3 years ago

@kukocrunch good shit! I hopefully will not find myself working with php much in the future; but if I do, I'll give this a shot