Skip to content

[Console] Running an Application in a Process without TTY can't keep Terminal size #19719

@ogizanagi

Description

@ogizanagi

All branches are concerned.

On OS X, in an iTerm window opened with < 120 columns.

The following script:

<?php
# output_something.php

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Console\Terminal;
use Symfony\Component\Process\Process;

require __DIR__.'/vendor/autoload.php';

(new Application('output_something'))
    ->register($commandName = 'ヽ(⌐■_■)ノ')
        ->addOption('no-more')
        ->setCode(function (InputInterface $input, OutputInterface $output) {
            $terminal = new Terminal();
            $io = new SymfonyStyle($input, $output);
            $io->note('Terminal width: '.$terminal->getWidth());
            $io->success('Success');

            if (!$input->getOption('no-more')) {
                (new Process('php output_something.php --no-more --ansi'))
//                    ->setTty(true)
                    ->run(function ($type, $buffer) use ($io) {
                        $io->write($buffer);
                    })
                ;
            }
        })
    ->getApplication()
    ->setDefaultCommand($commandName, true)
    ->run()
;

will output:

screenshot 2016-08-23 a 23 35 13

instead of:

screenshot 2016-08-23 a 23 35 29

Uncommenting the $process->setTty(true); line will resolve the issue.

However, it's not always convenient to enabled TTY mode and is not often used by third-party scripts.

For instance, with classical Composer post-install scripts, in which commands are executed in a process without TTY mode, it causes some issues on a small terminal width:

screenshot 2016-08-24 a 00 02 24

A quick solution to this (at least in 3.2) would be to set the COLUMNS & LINES env variables in order to reuse them in the process as soon as we run the Application. But I doubt this would be the best way to go.

Show quick fix sample for >= 3.2

diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php
index f0129d5..fa5e8d4 100644
--- a/src/Symfony/Component/Console/Application.php
+++ b/src/Symfony/Component/Console/Application.php
@@ -104,6 +104,8 @@ class Application
      */
     public function run(InputInterface $input = null, OutputInterface $output = null)
     {
+        $this->terminal->setEnv();
+
         if (null === $input) {
             $input = new ArgvInput();
         }
@@ -361,7 +363,7 @@ class Application
      * Adds an array of command objects.
      *
      * If a Command is not enabled it will not be added.
-     * 
+     *
      * @param Command[] $commands An array of commands
      */
     public function addCommands(array $commands)
diff --git a/src/Symfony/Component/Console/Terminal.php b/src/Symfony/Component/Console/Terminal.php
index 9189f2d..d36e333 100644
--- a/src/Symfony/Component/Console/Terminal.php
+++ b/src/Symfony/Component/Console/Terminal.php
@@ -52,6 +52,17 @@ class Terminal
         return self::$height;
     }

+    public function setEnv()
+    {
+        if (!trim(getenv('LINES'))) {
+            putenv('LINES=' . $this->getHeight());
+        }
+
+        if (!trim(getenv('COLUMNS'))) {
+            putenv('COLUMNS=' . $this->getWidth());
+        }
+    }
+
     private static function initDimensions()
     {
         if ('\\' === DIRECTORY_SEPARATOR) {

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions