Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

word auto-corrector in Curses::UI

by Bpl (Scribe)
on Jan 09, 2021 at 09:33 UTC ( [id://11126645]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monkers!
Some days ago I found online the excellent Curses::UI "graphic" library, so I started to write a simple text editor, using this code (one of the examples in the "example" path):
use strict; use Curses; use Cwd; use Curses::UI; # Load an initial file if an argument given on the command line. # If the file can't be found, assume that this is a new file. my $text = ""; my $currentfile = shift; if (defined $currentfile and -f $currentfile) { open F, "<$currentfile" or die "Can't read $currentfile: $!\n" +; while (<F>) { $text .= $_ } $currentfile = $currentfile; close F; } # We don't want STDERR output to clutter the screen. # # Hint: If you need STDERR, write it out to a file and put # a tail on that file to see the STDERR output. Example: #open STDERR, ">>/tmp/editor_errors.$$"; open STDERR, ">/dev/null"; # -------------------------------------------------------------------- +-- # Menu definition # -------------------------------------------------------------------- +-- my @menu = ( { -label => 'File', -submenu => [ { -label => 'Open file ^O', -value => \&open_dialog }, { -label => 'Save file ^S', -value => \&save_dialog }, { -label => 'Exit ^Q', -value => \&exit_dialog } ] }, { -label => 'Help', -submenu => [ { -label => 'About editor', -value => \&about_dialog } ] } ); # -------------------------------------------------------------------- +-- # Create widgets # -------------------------------------------------------------------- +-- # Create the root. Everything else will be built up from here. use Curses::UI; my $cui = new Curses::UI ( -clear_on_exit => 1 ); # Add the menu to the root. my $menu = $cui->add( 'menu','Menubar', -menu => \@menu, ); # Create the screen for the editor. my $screen = $cui->add( 'screen', 'Window', -padtop => 1, # leave space for the menu -border => 0, -ipad => 0, ); # We add the editor widget to this screen. my $editor = $screen->add( 'editor', 'TextEditor', -border => 1, -padtop => 0, -padbottom => 3, -showlines => 0, -sbborder => 0, -vscrollbar => 1, -hscrollbar => 1, -showhardreturns => 0, -wrapping => 0, # wrapping slows down the editor :-( -text => $text, ); # There is no need for the editor widget to loose focus, so # the "loose-focus" binding is disabled here. This also enables the # use of the "TAB" key in the editor, which is nice to have. $editor->clear_binding('loose-focus'); # Help information for the user. $screen->add( 'help', 'Label', -y => -2, -width => -1, -reverse => 1, -paddingspaces => 1, -text => " ^Q Quit from the program ^S save file" . " ^W toggle wrapping\n" . " ^X Open the menu ^O open file" . " ^R toggle hard returns viewing", ); # -------------------------------------------------------------------- +-- # Callback routines # -------------------------------------------------------------------- +-- sub open_dialog() { my $file = $cui->loadfilebrowser( -file => $currentfile, ); if (defined $file) { if (open F, "<$file") { my $text = ""; while (<F>) { $text .= $_ } close F; $editor->text($text); $editor->cursor_to_home; $currentfile = $file; } else { $cui->error(-message => "Can't read file \"$file\" +:\n$!"); } } } sub save_dialog() { my $file = $cui->savefilebrowser( -file => $currentfile, ); return unless defined $file; if (open F, ">$file") { print F $editor->text; if (close F) { $cui->dialog(-message => "File \"$file\"\nsuccessfully + saved"); $currentfile = $file; } else { $cui->error(-message => "Error on closing file \"$file +\":\n$!"); } } else { $cui->error(-message => "Can't write to $file:\n$!"); } } sub about_dialog() { $cui->dialog( -title => 'About editor', -message => "Program : Curses::UI Editor\n" . "Author : Maurice Makaay\n" . "\n" . "The sole purpose of this editor\n" . "is the demonstration of my perl\n" . "Curses::UI widget set." ); } sub exit_dialog() { my $return = $cui->dialog( -title => "Are you sure???", -buttons => ['yes', 'no'], -message => "Do you really want to quit?" ); exit(0) if $return; } # -------------------------------------------------------------------- +-- # The main loop of the program # -------------------------------------------------------------------- +-- $cui->set_binding(\&exit_dialog, "\cQ", "\cC"); $cui->set_binding(\&save_dialog, "\cS"); $cui->set_binding(\&open_dialog, "\cO"); $cui->set_binding(sub {shift()->getobj('menu')->focus}, "\cX", KEY_F(1 +0)); $cui->set_binding(sub { my $cui = shift; $cui->layout; $cui->draw; }, "\cL"); # Bring the focus to the editor widget. $editor->focus; $cui->mainloop;
Now I would like to add a global word auto-complete function which, given an array of similar words, clicking <TAB> autocomplete the current user- typed word. Online I found this:
https://metacpan.org/pod/Term::Complete
but unfortunately it doesn't work if I put this at the top of the script
$input = Complete('prompt_string', \@completion_list);

Thanks,
Edoardo Mantovani, 2020

Replies are listed 'Best First'.
Re: word auto-corrector in Curses::UI
by shmem (Chancellor) on Jan 09, 2021 at 10:51 UTC
    but unfortunately it doesn't work if I put this at the top of the script
    $input = Complete('prompt_string', \@completion_list);

    That's the wrong place. You probably must make the mainloop aware of tab completion via set_binding(), and handle the completion in a subroutine. Another candidate is add_callback().

    Edit:

    use Curses::UI; use Term::Complete; ... sub complete { my @words = ( 'perl', 'pepper', 'peace' ); # thanks marto! my $input = Complete('',\@words); $editor->add_string($input); } ... $cui->set_binding(\&complete,"\t");

    Note that with this binding you have to press <Tab> twice, one to invoke sub complete, then for the completion itself.

    You will have to get the substring upon which the completion was invoked and strip that from $input and handle the newline which ends the completion routine by repositioning the cursor. Or just do a screen redraw (bound to ^L).

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
      Wow, nice! Honestly I never though to bind the completition function with Curses::UI directly, Many thanks! Regards, Edoardo Mantovani
        EDIT:
        Aww, small problem now, it doesn't work! unfortunately when I double click TAB seems that the program pass to another perlio layer and not to STDIN! infact when I try to click the upside buttons (given by Curses::UI), I obtain the printing of the following lines to the screen:
        [M %! [ M#%![ M% ecc..

        which seems to be malformed input strings, probably there must be some
        pack($input)
        solution
        Regards,
        Edoardo Mantovani
Re: word auto-corrector in Curses::UI
by marto (Cardinal) on Jan 09, 2021 at 10:29 UTC

    Try this minimal example:

    #!/usr/bin/perl use strict; use warnings; use Term::Complete; my @words = ( 'perl', 'pepper', 'peace' ); Complete('', \@words);

    Tab completion from STDIN works as expected. Also, it's no longer 2020.

      Hi Marto!
      Yes, I know that works on STDIN, but when I try to do the same on Curses::UI it doesn't works,
      Unfortunately, IDK why Regards, Edoardo Mantovani, 2020

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (5)
As of 2024-04-23 18:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found