10000 [Console] allow multiline responses to console questions by ramsey · Pull Request #37683 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Console] allow multiline responses to console questions #37683

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 12, 2020
Merged

[Console] allow multiline responses to console questions #37683

merged 1 commit into from
Aug 12, 2020

Conversation

ramsey
Copy link
Contributor
@ramsey ramsey commented Jul 28, 2020
Q A
Branch? master
Bug fix? no
New feature? yes
Deprecations? no
Tickets n/a
License MIT
Doc PR symfony/symfony-docs#14002

By default, the question helper stops reading user input when it receives a newline character (i.e., when the user hits ENTER once). However, with this feature, developers may specify that the response to a question should allow multiline answers by passing true to setMultiline().

Multiline questions stop reading user input after receiving three newline characters in a row (i.e., the user hits ENTER three times) or an end-of-transmission control character (Ctrl-D on Unix systems or Ctrl-Z on Windows).

If a user enters a newline character without input, control is returned to the question class, where the input may be validated to prompt the user again (in the case of a required question), or control may be passed along to the rest of the script.

@nicolas-grekas
Copy link
Member
nicolas-grekas commented Jul 29, 2020

Thanks for the PR. Is there any prior art on the topic where 3 ENTER exits the stream? How discoverable is this? Instead, should we add a line to remind ppl how to exit such questions?

@ramsey
Copy link
Contributor Author
ramsey commented Jul 29, 2020

Good questions.

I cannot find any prior art for this pattern. I had thought that commitizen prompts the user in this way, but after testing again just now, it continues after a single newline character.

Here is my use-case for this: I am working on a Conventional Commits plugin for CaptainHook. According to the Conventional Commits specification, "a commit body is free-form and MAY consist of any number of newline separated paragraphs." My goal is to prompt the user to enter a longer description (the body), allowing them to enter multiple paragraphs, bullet lists, etc. as part of the body.

Originally, I thought to use 2 newlines (i.e., when a user is finished, they'd hit ENTER twice to continue to the next prompt), but this prevents the user from being able to create multiple paragraphs (with a single newline between them). The only solution I could think of was to assume two empty newlines meant that the user is ready to continue. This happens when the user hits ENTER three times in a row.

Another option the user may take is to use Ctrl+D (on Unix) or Ctrl+Z (on Windows) to send the end-of-transmission control character, which fgetc() reads as EOF.

I have documented this in symfony/symfony-docs#14002, but I agree that hitting ENTER 3 times or using Ctrl+D or Ctrl+Z may not be intuitive or easily discoverable.

I'm open to other ideas for how to handle this.

@noniagriconomie
Copy link
Contributor

@ramsey

I'm open to other ideas for how to handle this.

The symfony maker bundle, for example, suffix the question with an hint. And I think ppl know/are familiar with this DX.

https://github.com/symfony/maker-bundle/blob/master/src/Maker/MakeEntity.php#L288
New property name (press <return> to stop adding fields):

Maybe it is possible, when the Question::isMultiline() true to add such suffix text after the question, prompting the dev with the option(s) to exit. The documentation is a must have, but here it can help also to discover this.

That being said, I got no opinion on the exit keyboard shortcut(s) (as we can not use Return) :)

8000
@ramsey
Copy link
Contributor Author
ramsey commented Jul 31, 2020

The keyboard shortcuts I mentioned work by default (since fgetc() interprets them as EOF), but they differ depending on the platform. The question here is around the use of hitting Enter/Return three times to continue. At this time, I don't have any alternate suggestions for a better DX.

@nicolas-grekas
Copy link
Member

What about removing the 3-enter case, and always display the hint about CTRL+D/Z?

@ramsey
Copy link
Contributor Author
ramsey commented Aug 1, 2020

I'd be fine with that. Is the hint something that the helper can add by default, or is it something that all implementors need to append to their question text?

@nicolas-grekas
Copy link
Member

The helper should add the hint ideally to me.

@ramsey
Copy link
Contributor Author
ramsey commented Aug 11, 2020

Updated to include feedback. The build failure does not appear related to this PR; the master branch is also failing.

@ramsey
Copy link
Contributor Author
ramsey commented Aug 11, 2020

Here's a simple console script to show this working: https://gist.github.com/ramsey/1b7b19356b7e542d3c885ed4f82e4d82

ramsey added a commit to ramsey/conventional-commits that referenced this pull request Aug 12, 2020
@fabpot
Copy link
Member
fabpot commented Aug 12, 2020

Thank you @ramsey.

@fabpot fabpot merged commit d2b5ee0 into symfony:master Aug 12, 2020
@ramsey ramsey deleted the feature/console-multiline-response branch August 12, 2020 19:59
xabbuh added a commit to symfony/symfony-docs that referenced this pull request Aug 21, 2020
… (ramsey)

This PR was merged into the master branch.

Discussion
----------

[Console] allow multiline responses to console questions

Documentation for new multiline responses feature proposed in symfony/symfony#37683

Commits
-------

e82b66b [Console] allow multiline responses to console questions
@epitre
Copy link
Contributor
epitre commented Sep 29, 2020

Hi,

As I said in the example, I tried the new multiline option.
If I ask a question AFTER using the multiline option in a previous question, then it seems that the ctrl+d is kind of saved, and the command gets aborted.

Do you also have this problem @ramsey ?

@epitre
Copy link
Contributor
epitre commented Sep 29, 2020

I opened a PR : #38345

Sorry, something went wrong.

chalasr added a commit that referenced this pull request Sep 30, 2020
…'t close input (ramsey)

This PR was squashed before being merged into the 5.2-dev branch (closes #38351).

Discussion
----------

[Console] clone stream on multiline questions so EOT doesn't close input

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | N/A
| License       | MIT
| Doc PR        | N/A

This fixes a bug in the multiline question feature that was introduced in #37683.

Today, @epitre commented on #37683 (comment):

> If I ask a question AFTER using the multiline option in a previous question, then it seems that the ctrl+d is kind of saved, and the command gets aborted.

I'm honestly not sure how I missed this while working on #37683, since I was testing it with multiple questions, but I think it might have resulted from some of the back-and-forth and the lack of ability to effectively test the EOT character from a unit test.

The solution was to _clone_ the input stream resource and use the clone to read the multiline input and capture the EOT byte. In this way, the primary input stream is not closed by the EOT.

This is similar to @epitre's solution in #38345, but I'm using the `uri` and `mode` from `stream_get_meta_data()` to create the new stream, and if the existing stream has any data and is seekable and writable (like the streams used in the tests), I add the data to the clone and seek to the same offset.

I've ensured that this solution works on a question that is in the middle of a series of other questions, and I've tested in on *nix and Windows. I've also improved the tests for multiline questions. While I'm unable to test (with a unit test) that an EOT character effectively stops reading from STDIN while continuing to the next question and prompt, I feel confident that the tests here provide sufficient coverage.

Commits
-------

ec688a3 [Console] clone stream on multiline questions so EOT doesn't close input
symfony-splitter pushed a commit to symfony/console that referenced this pull request Sep 30, 2020
…'t close input (ramsey)

This PR was squashed before being merged into the 5.2-dev branch (closes #38351).

Discussion
----------

[Console] clone stream on multiline questions so EOT doesn't close input

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | N/A
| License       | MIT
| Doc PR        | N/A

This fixes a bug in the multiline question feature that was introduced in #37683.

Today, @epitre commented on symfony/symfony#37683 (comment):

> If I ask a question AFTER using the multiline option in a previous question, then it seems that the ctrl+d is kind of saved, and the command gets aborted.

I'm honestly not sure how I missed this while working on #37683, since I was testing it with multiple questions, but I think it might have resulted from some of the back-and-forth and the lack of ability to effectively test the EOT character from a unit test.

The solution was to _clone_ the input stream resource and use the clone to read the multiline input and capture the EOT byte. In this way, the primary input stream is not closed by the EOT.

This is similar to @epitre's solution in symfony/symfony#38345, but I'm using the `uri` and `mode` from `stream_get_meta_data()` to create the new stream, and if the existing stream has any data and is seekable and writable (like the streams used in the tests), I add the data to the clone and seek to the same offset.

I've ensured that this solution works on a question that is in the middle of a series of other questions, and I've tested in on *nix and Windows. I've also improved the tests for multiline questions. While I'm unable to test (with a unit test) that an EOT character effectively stops reading from STDIN while continuing to the next question and prompt, I feel confident that the tests here provide sufficient coverage.

Commits
-------

ec688a361e [Console] clone stream on multiline questions so EOT doesn't close input
@nicolas-grekas nicolas-grekas modified the milestones: next, 5.2 Oct 5, 2020
@fabpot fabpot mentioned this pull request Oct 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants
0