diff --git a/kpadgtk3 b/kpadgtk3 new file mode 100755 index 0000000..092893b Binary files /dev/null and b/kpadgtk3 differ diff --git a/kpadgtk3.pl b/kpadgtk3.pl index 4f268f3..0c1f587 100644 --- a/kpadgtk3.pl +++ b/kpadgtk3.pl @@ -1,17 +1,25 @@ #!/usr/bin/perl +use strict; +use warnings; use Gtk3 '-init'; use Glib qw(TRUE FALSE); use File::Glob; use FileHandle; use LWP::Simple; use Gtk3::SourceView; +use IPC::Open3; +use IO::Select; # Declare global variables -our $textbuffer; # SourceView buffer for the editor -our $textview; # SourceView widget -our $statusbar; # Status bar for feedback -our $open; # Current file path +our $textbuffer; # SourceView buffer for the editor +our $textview; # SourceView widget for editor +our $statusbar; # Status bar for feedback +our $open; # Current file path our $track = 'init'; # Tracks modifications +our $shell_buffer; # SourceView buffer for pshell +our $shell_view; # SourceView widget for pshell +our $shell_scrolled; # Scrolled window for pshell +our $shell_pid; # pshell process ID # Base directory setup (reused from your code) my ($ar) = @ARGV; @@ -166,6 +174,12 @@ my $which_line_item = Gtk3::MenuItem->new_with_label('Which Line?'); $which_line_item->signal_connect(activate => \&which_line_dialog); $tools_menu->append($which_line_item); +my $toggle_shell = Gtk3::MenuItem->new_with_label('Toggle pshell'); +$toggle_shell->signal_connect(activate => sub { + $shell_scrolled->set_visible(!$shell_scrolled->get_visible); +}); +$tools_menu->append($toggle_shell); + # HTML menu my $html_menu = Gtk3::Menu->new; my $html_item = Gtk3::MenuItem->new_with_label('HTML'); @@ -210,9 +224,13 @@ $about_item->signal_connect(activate => sub { }); $help_menu->append($about_item); -# Text view with SourceView +# Split pane for editor and pshell +my $paned = Gtk3::Paned->new('vertical'); +$vbox->pack_start($paned, TRUE, TRUE, 0); + +# Editor (SourceView) my $scrolled = Gtk3::ScrolledWindow->new(undef, undef); -$vbox->pack_start($scrolled, TRUE, TRUE, 0); +$paned->pack1($scrolled, TRUE, TRUE); $textview = Gtk3::SourceView::View->new; $textview->set_wrap_mode('word'); $textview->set_show_line_numbers(TRUE); @@ -224,6 +242,84 @@ my $language = $lang_manager->get_language('perl'); $textbuffer->set_language($language) if $language; $textbuffer->set_highlight_syntax(TRUE); +# pshell panel (SourceView) +$shell_scrolled = Gtk3::ScrolledWindow->new(undef, undef); +$paned->pack2($shell_scrolled, FALSE, TRUE); +$shell_view = Gtk3::SourceView::View->new; +$shell_view->set_wrap_mode('word'); +$shell_view->set_editable(TRUE); +$shell_scrolled->add($shell_view); +$shell_buffer = $shell_view->get_buffer; +my $shell_lang = $lang_manager->get_language('perl'); +$shell_buffer->set_language($shell_lang) if $shell_lang; +$shell_buffer->set_highlight_syntax(TRUE); +$shell_buffer->set_text("pshell:/home/kake26/projects/perl/kpadold> "); + +# Start pshell +my ($wtr, $rdr, $err); +my $pshell_path = "$basedir/pshell"; +if (!-x $pshell_path) { + $statusbar->push(0, "Error: pshell not found or not executable at $pshell_path"); +} else { + eval { + $shell_pid = open3($wtr, $rdr, $err, $pshell_path); + 1; + } or do { + $statusbar->push(0, "Failed to start pshell: $@"); + $shell_buffer->set_text("Error: Could not start pshell\n"); + }; + if ($shell_pid && defined $rdr && defined $err) { + # Ensure unbuffered output + select($wtr); $| = 1; select(STDOUT); + # Non-blocking read for pshell stdout and stderr + my $selector = IO::Select->new($rdr, $err); + Glib::IO->add_watch(fileno($rdr), ['in', 'hup'], sub { + my ($fileno, $condition) = @_; + if ($condition & 'in') { + my $output; + sysread($rdr, $output, 4096); # Increased buffer size + if ($output) { + $output =~ s/pshell:[^\n>]*> //g; # Strip prompt if included + $shell_buffer->insert_at_cursor($output); + $shell_view->scroll_to_iter($shell_buffer->get_end_iter, 0, FALSE, 0, 0); + } + } + return FALSE if $condition & 'hup'; + return TRUE; + }) if defined $rdr; + Glib::IO->add_watch(fileno($err), ['in', 'hup'], sub { + my ($fileno, $condition) = @_; + if ($condition & 'in') { + my $output; + sysread($err, $output, 4096); + if ($output) { + $output =~ s/pshell:[^\n>]*> //g; # Strip prompt if included + $shell_buffer->insert_at_cursor($output); + $shell_view->scroll_to_iter($shell_buffer->get_end_iter, 0, FALSE, 0, 0); + } + } + return FALSE if $condition & 'hup'; + return TRUE; + }) if defined $err; + } +} + +# Handle pshell input +$shell_view->signal_connect('key-press-event' => sub { + my ($widget, $event) = @_; + if ($event->keyval == Gtk3::Gdk::KEY_Return) { + my ($start, $end) = $shell_buffer->get_bounds; + my $text = $shell_buffer->get_text($start, $end, TRUE); + my ($cmd) = $text =~ /pshell:[^\n>]*> (.*?)$/s; + if (defined $cmd && defined $wtr) { + print $wtr "$cmd\n"; + $shell_buffer->insert_at_cursor("\npshell:$ENV{HOME}> "); + } + return TRUE; + } + return FALSE; +}); + # CSS styling for Kubuntu my $provider = Gtk3::CssProvider->new; $provider->load_from_data(' @@ -499,6 +595,8 @@ sub tapp { save_file(); } } + # Kill pshell process + kill 'TERM', $shell_pid if $shell_pid; Gtk3->main_quit; } diff --git a/pshell b/pshell new file mode 100755 index 0000000..916a622 Binary files /dev/null and b/pshell differ diff --git a/pshell_env.db b/pshell_env.db new file mode 100644 index 0000000..9d8e80f Binary files /dev/null and b/pshell_env.db differ diff --git a/pshell_history.db b/pshell_history.db new file mode 100644 index 0000000..dd2faee Binary files /dev/null and b/pshell_history.db differ