aboutsummaryrefslogblamecommitdiffstats
path: root/prompt_info/prompt_replace.pl
blob: 3b28a050acdede4712843ad5b15ac485590711e7 (plain) (tree)
1
2
3
4
5
6





                                                       






















                                                                            
                               
 
                                         
 































































                                                                   


                          
 

                                 
                                                      








                                                                




                                                           
 
          
 
                                                                        
 
                                                                        
 






                                                                             
 
               
                                                       
                                           
                                             
 

                                                                 
                                                                   

                               
                                                              
 




                                                                        

                                                                  
                                                             
 
                                         
                           




                                  


                           
            
                                                     


                           
















































                                                                      
                       

                                    
                               

                                                     
            
                             
                                                 






                                                                                 
                                            

         

 

                      
 








                                        
 

                    
                               
                        

 



                                                                     
 

                                                           
 

                                                      
 





                                                                         
 

 



                                                  
 




                                      



                 

                                                           




                                               
                                            





                                                             
 









                                                      
                                                





                                                                 
                                                    







                                                                 













                                                     


                                      
use strict;
use warnings;

use Irssi;
use Irssi::TextUI;              # for sbar_items_redraw
use Data::Dumper;



our $VERSION = "0.1";
our %IRSSI =
  (
   authors         => "shabble",
   contact         => 'shabble+irssi@metavore.org, shabble@#irssi/Freenode',
   name            => "prompt_info",
   description     => "Helper script for dynamically adding text "
   . "into the input-bar prompt.",
   license         => "Public Domain",
   changed         => "24/7/2010"
  );

sub DEBUG () { 1 }
#sub DEBUG () { 0 }

my $prompt_data = undef;
my $prompt_item = undef;

my $vis_enabled = 0;

my ($term_w, $term_h) = (0, 0);

my ($region_start, $region_end) = (0, 0);

# overlay  := { $num1 => line1, $num2 => line2 }
# line     := [ region, region, region ]
# region   := { start => x, end => y, ...? }

my $overlay;

my $prompt_format;
my $prompt_format_str = '';


sub _add_overlay_region {
    my ($line, $start, $end, $text, $len) = @_;
    my $region = { start => $start,
                   end => $end,
                   text => $text,
                   len => $len };

    my $o_line = $overlay->{$line};

    unless (defined $o_line) {
        $o_line = [];
        $overlay->{$line} = $o_line;
    }

    foreach my $cur_region (@$o_line) {
        if (_region_overlaps($cur_region, $region)) {
            # do something.
            print "Region overlaps";
            last;
        }
    }

    push @$o_line, $region;

}

sub _remove_overlay_region {
    my ($line, $start, $end) = @_;

    my $o_line = $overlay->{$line};
    return unless $o_line;

    my $i = 0;
    foreach my $region (@$o_line) {
        if ($region->{start} == $start && $region->{end} == $end) {
            last;
        }
        $i++;
    }
    splice @$o_line, $i, 1, (); # remove it.
}

sub _redraw_overlay {
    foreach my $line_num (sort keys %$overlay) {
        my $line = $overlay->{$line_num};

        foreach my $region (@$line) {
            Irssi::gui_printtext($region->{start}, $line_num,
                                 $region->{text});
        }
    }
}


init();

sub update_terminal_size {

    my @stty_lines = qx/stty -a/;
    my $line = $stty_lines[0];
    @stty_lines = ();           # don't need the rest.

    if ($line =~ m/\s*(\d+)\s*rows\s*;\s*(\d+)\s*columns\s*;/) {
        $term_h = $1;
        $term_w = $2;
    } else {
        print "Failed to detect terminal size";
    }
}

sub subcmd_handler {
    my ($data, $server, $item) = @_;
    $data =~ s/\s+$//g; # strip trailing whitespace.
    Irssi::command_runsub('prompt', $data, $server, $item);
}

sub init {

    Irssi::statusbar_item_register ('uberprompt', 0, 'uberprompt_draw');

    Irssi::settings_add_str('uberprompt', 'uberprompt_format', '[$*] ');

    Irssi::command_bind("prompt", \&subcmd_handler);
    Irssi::command_bind('prompt on', \&replace_prompt_items);
    Irssi::command_bind('prompt off', \&restore_prompt_items);
    Irssi::command_bind('prompt set',
                        sub { $prompt_data = shift; uberprompt_refresh(); });
    Irssi::command_bind('prompt clear',
                        sub { undef $prompt_data; uberprompt_refresh(); });

    # misc faff
    Irssi::command_bind('visual', \&cmd_toggle_visual);
    Irssi::command("^BIND meta-l /visual");
    Irssi::command_bind('menu', \&draw_menu);

    # redraw interception
    Irssi::signal_add_last('command redraw',   \&augment_redraw);
    Irssi::signal_add_first('gui key pressed', \&ctrl_l_intercept);

    # for updating the overlay.
    Irssi::signal_add_last ('gui key pressed', \&key_pressed);

    # things to refresh the overlay for.
    Irssi::signal_add('window changed',           \&uberprompt_refresh);
    Irssi::signal_add('window name changed',      \&uberprompt_refresh);
    Irssi::signal_add('window changed automatic', \&uberprompt_refresh);
    Irssi::signal_add('window item changed',      \&uberprompt_refresh);

    Irssi::signal_add('terminal resized', \&update_terminal_size);
    Irssi::signal_add('setup changed',    \&reload_settings);

    # so we know where the bottom line is
    update_terminal_size();

    # intialise the prompt format.
    reload_settings();

    # install our statusbars.
    replace_prompt_items();
}

sub UNLOAD {
    # remove uberprompt and return the original ones.
    restore_prompt_items();
}

sub reload_settings {
    my $new = Irssi::settings_get_str('uberprompt_format');
    if ($prompt_format_str ne $new) {
        print "Updated prompt format";
        $prompt_format_str = $new;
        Irssi::abstracts_register(['uberprompt', $prompt_format_str]);
    }
}

sub uberprompt_draw {
    my ($sb_item, $get_size_only) = @_;

    my $default_prompt = '';

    my $window = Irssi::active_win;

    # hack to produce the same defaults as prompt/prompt_empty sbars.

    if (scalar( () = $window->items )) {
        $default_prompt = '{uberprompt $[.15]itemname}';
    } else {
        $default_prompt = '{uberprompt $winname}';
    }

    my $p_copy = $prompt_data;

    if (defined $prompt_data) {
        # replace the special marker '$p' with the original prompt.
        $p_copy =~ s/\$p/$default_prompt/;
    } else {
        $p_copy = $default_prompt;
    }
    print "Redrawing with: $p_copy, size-only: $get_size_only";

    $prompt_item = $sb_item;

    $sb_item->default_handler($get_size_only, $p_copy, '', 0);
}

sub augment_redraw {
    print "Redraw called";
    uberprompt_refresh();
    Irssi::timeout_add_once(10, \&refresh_inputline, 0);
}

sub uberprompt_refresh {
    Irssi::statusbar_items_redraw('uberprompt');
}

sub cmd_toggle_visual {
    $vis_enabled = not $vis_enabled;
    if ($vis_enabled) {
        $region_start = _pos();
        $region_end   = 0; # reset end marker.
        print "visual mode started at $region_start";
    } else {
        $region_end = _pos();
        print "Visual mode ended at $region_end";

        if ($region_end > $region_start) {
            my $input = Irssi::parse_special('$L', 0, 0);
            my $str = substr($input, $region_start, $region_end - $region_start);
            print "Region selected: $str";
        } else {
            print "Invalid region selection: [ $region_start - $region_end ]";
            $region_start = $region_end = 0;
        }
    }
}

sub ctrl_l_intercept {
    my $key = shift;

    if ($key == 12) {
        print "C-l pressed";
        Irssi::command("redraw");
        Irssi::signal_stop();
    }
    if ($key == 10) {
        $region_end = $region_start = 0;
    }
}

sub key_pressed {
    my $key = shift;
    return unless $vis_enabled;
    refresh_inputline();
}

sub refresh_inputline {

    my $end_pos = $region_end;
    $end_pos  ||= _pos(); # if not set, take current position as end.

    my $len = $end_pos - $region_start;
    return unless $len; # no point drawing an empty overlay

    my $input = Irssi::parse_special('$L');
    my $offset = $prompt_item->{size} + $region_start;

    my $text = substr($input, $region_start, $len);

    print "printing '$text' at $offset [$region_start, $end_pos] ($len)";

    $text = '%k%2' . $text . '%n';
    _draw_overlay($offset, $text, $len);

}

sub _draw_overlay {
    my ($offset, $text, $len) = @_;
    Irssi::gui_printtext($offset, $term_h, $text);
}

sub _clear_overlay {
    Irssi::active_win->view->redraw();
}

sub _draw_overlay_menu {

    my $w = 10;

    my @lines = (
                 '%7+' . ('-' x $w) . '+%n',
                 sprintf('%%7|%%n%*s%%7|%%n', $w, 'bacon'),
                 sprintf('|%*s|', $w, 'bacon'),
                 sprintf('|%*s|', $w, 'bacon'),
                 sprintf('|%*s|', $w, 'bacon'),
                 sprintf('|%*s|', $w, 'bacon'),
                 sprintf('|%*s|', $w, 'bacon'),
                 '%7+' . ('-' x $w) . '+%n',
                );
    my $i = 10; # start vert offset.
    for my $line (@lines) {
        Irssi::gui_printtext(int ($term_w / 2), $i++, $line);
    }
}


sub replace_prompt_items {
    # remove existing ones.
    print "Removing original prompt" if DEBUG;

    _sbar_command('prompt', 'remove', 'prompt');
    _sbar_command('prompt', 'remove', 'prompt_empty');

    # add the new one.

    _sbar_command('prompt', 'add', 'uberprompt',
                  qw/-alignment left -before input -priority 0/);

}

sub restore_prompt_items {

    _sbar_command('prompt', 'remove', 'uberprompt');

    print "Restoring original prompt" if DEBUG;
    _sbar_command('prompt', 'add', 'prompt',
                  qw/-alignment left -before input -priority 0/);
    _sbar_command('prompt', 'add', 'prompt_empty',
                  qw/-alignment left -after prompt -priority 0/);
}

sub _sbar_command {
    my ($bar, $cmd, $item, @args) = @_;

    my $args_str = join ' ', @args;

    $args_str .= ' ' if length $args_str;

    my $command = sprintf 'STATUSBAR %s %s %s%s',
      $bar, $cmd, $args_str, defined($item)?$item:'';

    print "Running command: $command" if DEBUG;
    Irssi::command($command);
}

sub _pos {
    return Irssi::gui_input_get_pos();
}