Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

How to perldebug a Term::ReadLine application

by LanX (Saint)
on Dec 01, 2014 at 14:42 UTC ( [id://1108836]=CUFP: print w/replies, xml ) Need Help??

the problem

I recently heard monks complaining that applications using Term::ReadLine can't be debugged within the perldebugger b/c it's interface relies on Term::Readline.

the trick

here one solution (at least for linux) I wanted to have documented (before I forget it again ;)

call the script you want to debug (here calc_TRL.pl ) from a shell with

PERLDB_OPTS="TTY=`tty` ReadLine=0" xterm -e perl -d ./calc_TRL.pl

and a second xterm will be opened running the program.

how it works

a second xterm is started running the debugger, but b/c of the TTY setting in PERLDB_OPTS all debugger communication goes via the parent xterm , while the calc app normally displays in the child xterm .

ReadLine=0 tells the debugger not to rely on a working Term::ReadLine.

NB: It's important that calling the second xterm blocks the execution in the first xterm till it's finished. Like this keystrokes aren interpreted by two applications in the first xterm. Just put an & at the end to see how things get messed up otherwise if the shell tries to step in.

how it looks like

first xterm

becomes the front end for the debugger

> PERLDB_OPTS="TTY=`tty` ReadLine=0" xterm -e perl -d ./calc_TRL.pl Loading DB routines from perl5db.pl version 1.33 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(./calc_TRL.pl:2): my $term = Term::ReadLine->new('Simple Per +l calc'); DB<1> l 2==> my $term = Term::ReadLine->new('Simple Perl calc'); 3: my $prompt = "Enter code: "; 4: my $OUT = $term->OUT || \*STDOUT; 5: while ( $_ = $term->readline($prompt) ) { 6: my $res = eval($_); 7: warn $@ if $@; 8: print $OUT $res, "\n" unless $@; 9: $term->addhistory($_) if /\S/; 10 } 11 DB<1> b 9 DB<2> c main::(./calc_TRL.pl:9): $term->addhistory($_) if /\S/; DB<2> c main::(./calc_TRL.pl:9): $term->addhistory($_) if /\S/; DB<3>

as you see I get the lines from the app in the second xterm listed can set a breakpoint at the end of the loop and tell twice to continue till next breakpoint.

second xterm

runs the application, I'm asked to enter a calculation which is evaluated, interupted twice by a breakpoint at line 9.

Enter code: 1+2 3 Enter code: 4+4 8

the test script

> cat ./calc_TRL.pl use Term::ReadLine; my $term = Term::ReadLine->new('Simple Perl calc'); my $prompt = "Enter code: "; my $OUT = $term->OUT || \*STDOUT; while ( $_ = $term->readline($prompt) ) { my $res = eval($_); warn $@ if $@; print $OUT $res, "\n" unless $@; $term->addhistory($_) if /\S/; }

tested with Term::ReadLine::Gnu installed.

generalisation

you can use this approach whenever you want the debugger communication separated into a separate term. e.g. Curses::UI comes to mind

discussion

the solution is not "perfect", of course you need to arrange the windows and switch with Alt-Tab between them. (maybe screen could solve this or an emacs inegration)

Furthermore you won't have a history with arrow navigation within the debugger, cause TRL was disabled.

another approach is to communicate via sockets with a debugger run within emacs, since emacs has it's own TRL-emulation this shouldn't interfere.

see also Re: Testing terminal programs within emacs (SOLVED) for an approach to handle all this automatically, by restarting a script with altered environment and different terminal.

TIMTOWTDI

see perldebguts , perldebtut and perldeb,

Also "Pro Perl Debugging" book and various TK tools on CPAN.

Cheers Rolf

(addicted to the Perl Programming Language and ☆☆☆☆ :)

Replies are listed 'Best First'.
Re: How to perldebug a Term::ReadLine application (the other way round)
by LanX (Saint) on Dec 01, 2014 at 16:21 UTC
    Another ... maybe saner way ... to do it is to attach the application explicitely to another TTY.

    Ideally a module could sense if it's run within the debugger and automatically set the TTY.

    For instance xterm -e perl -e 'print `tty`;sleep' will show the TTY of this terminal ( /dev/pts/5 in this case) and sleep indefintely to not disturb the TTY output.

    the following script hardcodes that TTY into TRL:

    use Term::ReadLine; my $tty='/dev/pts/5'; open my $out,'>',$tty; open my $in,'<',$tty; my $term = Term::ReadLine->new('Simple Perl calc',$in,$out); my $prompt = "Enter code: "; my $OUT = $term->OUT || \*STDOUT; while ( $_ = $term->readline($prompt) ) { my $res = eval($_); warn $@ if $@; print $OUT $res, "\n" unless $@; $term->addhistory($_) if /\S/; }

    I have problems to figure out a nice way to automize it. Ideally I'd get the TTY of the spawned xterm returned.

    The only thing I figured out at the moment is to look into the proces table

    > ls -l /proc/31965/fd/ insgesamt 0 lrwx------ 1 lanx lanx 64 Dez 1 17:18 0 -> /dev/pts/5 lrwx------ 1 lanx lanx 64 Dez 1 17:18 1 -> /dev/pts/5 lrwx------ 1 lanx lanx 64 Dez 1 17:18 2 -> /dev/pts/5

    Cheers Rolf

    (addicted to the Perl Programming Language and ☆☆☆☆ :)

      Why not:

      DEBUG_TTY=`tty` xterm -e perl -d ./myRLprog.pl

      Then in myRLprog.pl, include:

      if (defined $ENV{DEBUG_TTY}) { my $tty = $ENV{DEBUG_TTY}; open my $out,'>',$tty; open my $in,'<',$tty; my $term = Term::ReadLine->new('Simple Perl calc',$in,$out); } else { ...; }

      Would that work?

        well this works

        PERLDB_OPTS="ReadLine=0" MASTER_TTY=`tty` xterm -e perl -d calc_TRL.pl

        with

        otherwise the debugger starts spontaneously to write to the master terminal, IMHO a bug somewhere between debugger and TRL.

        My former approach to redirect the app's tty to a slave terminal has the advantage to run without lost of features in IDEs like emacs.

        The slave terminal can also be an extra sub-window within the IDE running a terminal emulation.

        Cheers Rolf

        (addicted to the Perl Programming Language and ☆☆☆☆ :)

      As another possibility, maybe:

      TEMP=$(mktemp /tmp/temporary-file.XXXXXXXX) xterm -e bash -c "tty >$TEMP; sleep 24h" sleep 1 # give time for tty to run exec 9<$TEMP read -u 9 SLAVE_TTY exec 9<&- export SLAVE_TTY perl myRLprog.pl

      This can be done in a more Perl-ish way, but this is the general idea. (Except for xterm, tty and perl, the commands are built into bash.)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://1108836]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (6)
As of 2024-03-19 03:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found