Allasso has asked for the wisdom of the Perl Monks concerning the following question:

I'm not sure if this problem is actually a perl issue, but I will start here.

I am running code to capture user input, attempting to do some stuff with the cursor conditionally (using system calls to tput) depending on which character is entered, then printing out each character so it appears on the screen (as they would if echo were enabled.) All works fine if the user is typing input, the problem appears if the input is pasted into the terminal. I've isolated the problem to observe that it seems related to making a system call in the loop. All the pasted characters get printed out okay, until the system call is made, where the next character prints, but none following get printed. If I don't make the system call, all characters get printed fine.

I have also observed that it doesn't matter what system call I make (eg, ls or whatever), the same thing happens, so it is not just related to calling tput.

I've reduced the code to minimally demonstrate the issue. In this example, if text is pasted in, only the first character gets printed. If the system call in the loop is commented out, then all the text gets printed as expected. Also note that one character will print, regardless of whether the system call comes before or after the print call. Also note that it doesn't matter if I use system() or backtick notation.

#!/usr/bin/perl $| = 1; use strict; use warnings; system "stty -icanon -isig -echo min 1 time 0"; system "tput clear"; print "enter some text:\n"; processText(); sub processText { while ( my $char = STDIN->getc() ) { if (ord($char) == 3) { # Ctrl-C system "stty icanon echo isig"; exit; } # System call causes only a single character to print out, apparen +tly can # be anything, eg `ls`. Get same behavior with shell exec using ba +ckticks. system "tput sc"; print($char); } } system "stty icanon echo isig";
  • Comment on Pasting text when capturing user input only prints one character if system call is made in the loop
  • Select or Download Code

Replies are listed 'Best First'.
Re: Pasting text when capturing user input only prints one character if system call is made in the loop
by haukex (Archbishop) on May 02, 2019 at 08:42 UTC

    I guess you're still trying to reinvent the Term::ReadLine wheel? ;-) In your previous thread you said "I am hopping around to different machines frequently ... especially say, a Mac that doesn't have dev tools installed, etc.". system calls to local tools isn't what I would call portable. I would recommend, like others have, using a module for this purpose. I might suggest that you could instead look at how to package modules with your scripts so that you don't need to install them everywhere - e.g. App::FatPacker or PAR-Packer.

      Thanks for the tip, I didn't realize you could package modules directly that way. I am sure it will come in handy in the future. ps, please see my latest general reply.

Re: Pasting text when capturing user input only prints one character if system call is made in the loop
by roboticus (Chancellor) on May 02, 2019 at 04:12 UTC

    Allasso:

    I expect you'll have a lot of trouble with trying to handle user input that way. When you call system, it forks off a new process which will inherit the standard input and output streams. I'd expect plenty of trouble with the other process possibly consuming/resetting the streams.

    Based on your post, I'd suggest you instead use Term::ReadKey to get the ability to act on individual keypresses.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: Pasting text when capturing user input only prints one character if system call is made in the loop
by holli (Abbot) on May 02, 2019 at 08:41 UTC
    ________________________________________ / You seem to be doing interactive \ | terminal stuff. You should have a look | \ at Curses. / ---------------------------------------- \ \ __ / \ | | @ @ | | || |/ || || |\_/| \___/
    Curses


    holli

    You can lead your users to water, but alas, you cannot drown them.
Re: Pasting text when capturing user input only prints one character if system call is made in the loop
by Allasso (Monk) on May 07, 2019 at 15:57 UTC

    Solution turned out to be simple, I don't need to use tput (and thus system calls) for cursor navigation, I can just print ANSI escape sequences.

    I wanted to wait before posting again until I felt confident there would be no more obstacles in my approach. The embedded editor is accomplishing its intended purpose, just need to hammer out some logic now. I probably shouldn't have used the word "portable", what I was meaning was mostly portable within my situation, which involves emulators in *nix environment, primarily on Macs. Unless there are some edge cases I haven't found yet, I don't think I will have any problems using ANSI escapes.

    As far as reinventing the wheel goes, this is something I am often accused of, and personally I have benefited much from the growth and enlightenment from doing so, and in the end I am usually more satisfied with the final product than taking the easier/mainstream approach. I truly believe that wheel reinventions share a great deal of credit for the level of technological advancement we have today.

    Thanks to everyone for all your input.

      As far as reinventing the wheel goes, this is something I am often accused of,

      It wasn't really meant as an accusation - it's something to be aware of. The context in which it is done matters - for example, I like to use these replacements for Test::Fatal and Test::Warnings, because they're nice and short yet complete (for my purposes), and I don't pull in extra dependencies for such short snippets. Using it as a learning experience is also a valid point, I also like to learn as much as I can about the topic I'm working on. I just think it should be considered whether this is just a little "personal helper script", or code that is going into production, in which case a module will most likely have more features, and it will (hopefully) get updates. I think a good way to look at it is whether this code might be maintained by others (which is very often the case), and one can ask oneself whether this is code one would like to inherit from someone else and maintain :-)

        Yes, I agree.