From 15256a982eecb447b51562298e788e1a47b665f9 Mon Sep 17 00:00:00 2001 From: kake26 Date: Wed, 30 Apr 2025 17:15:28 -0500 Subject: [PATCH] Add pshell integration and clean up text editor code --- kpadgtk3.pl | 146 +++---------- moo.txt | 531 ++++++++++++++++++++++++++++++++++++++++++++++ pshell.kpd | 13 ++ pshell_history.db | Bin 12288 -> 12288 bytes 4 files changed, 577 insertions(+), 113 deletions(-) create mode 100644 moo.txt create mode 100644 pshell.kpd diff --git a/kpadgtk3.pl b/kpadgtk3.pl index 0c1f587..9f4537c 100644 --- a/kpadgtk3.pl +++ b/kpadgtk3.pl @@ -7,8 +7,6 @@ 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 @@ -16,10 +14,6 @@ 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; @@ -174,12 +168,6 @@ 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'); @@ -224,13 +212,9 @@ $about_item->signal_connect(activate => sub { }); $help_menu->append($about_item); -# 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); -$paned->pack1($scrolled, TRUE, TRUE); +$vbox->pack_start($scrolled, TRUE, TRUE, 0); $textview = Gtk3::SourceView::View->new; $textview->set_wrap_mode('word'); $textview->set_show_line_numbers(TRUE); @@ -242,84 +226,6 @@ 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(' @@ -380,11 +286,18 @@ sub open_file { 'Open File', $window, 'open', 'gtk-cancel' => 'cancel', 'gtk-ok' => 'ok' ); - $dialog->add_filter(Gtk3::FileFilter->new)->add_pattern('*.pl'); - $dialog->add_filter(Gtk3::FileFilter->new)->add_pattern('*'); - if ($dialog->run eq 'ok') { + my $pl_filter = Gtk3::FileFilter->new; + $pl_filter->set_name('Perl Scripts'); + $pl_filter->add_pattern('*.pl'); + $dialog->add_filter($pl_filter); + my $all_filter = Gtk3::FileFilter->new; + $all_filter->set_name('All Files'); + $all_filter->add_pattern('*'); + $dialog->add_filter($all_filter); + my $response = $dialog->run; + if ($response && $response eq 'ok') { my $filename = $dialog->get_filename; - if (open my $fh, '<', $filename) { + if ($filename && open my $fh, '<', $filename) { local $/; $textbuffer->set_text(<$fh>); close $fh; @@ -418,19 +331,28 @@ sub save_as_file { 'Save File', $window, 'save', 'gtk-cancel' => 'cancel', 'gtk-ok' => 'ok' ); - $dialog->add_filter(Gtk3::FileFilter->new)->add_pattern('*.pl'); - $dialog->add_filter(Gtk3::FileFilter->new)->add_pattern('*'); - if ($dialog->run eq 'ok') { + my $pl_filter = Gtk3::FileFilter->new; + $pl_filter->set_name('Perl Scripts'); + $pl_filter->add_pattern('*.pl'); + $dialog->add_filter($pl_filter); + my $all_filter = Gtk3::FileFilter->new; + $all_filter->set_name('All Files'); + $all_filter->add_pattern('*'); + $dialog->add_filter($all_filter); + my $response = $dialog->run; + if ($response && $response eq 'ok') { my $filename = $dialog->get_filename; - my ($start, $end) = $textbuffer->get_bounds; - my $text = $textbuffer->get_text($start, $end, TRUE); - if (open my $fh, '>', $filename) { - print $fh $text; - close $fh; - $statusbar->push(0, "Saved $filename"); - $open = $filename; - } else { - $statusbar->push(0, "Failed to save $filename"); + if ($filename) { + my ($start, $end) = $textbuffer->get_bounds; + my $text = $textbuffer->get_text($start, $end, TRUE); + if (open my $fh, '>', $filename) { + print $fh $text; + close $fh; + $statusbar->push(0, "Saved $filename"); + $open = $filename; + } else { + $statusbar->push(0, "Failed to save $filename"); + } } } $dialog->destroy; @@ -595,8 +517,6 @@ sub tapp { save_file(); } } - # Kill pshell process - kill 'TERM', $shell_pid if $shell_pid; Gtk3->main_quit; } diff --git a/moo.txt b/moo.txt new file mode 100644 index 0000000..9f4537c --- /dev/null +++ b/moo.txt @@ -0,0 +1,531 @@ +#!/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; + +# Declare global variables +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 + +# Base directory setup (reused from your code) +my ($ar) = @ARGV; +my $basedir; +if ($^O ne "Win32") { + if ($0 =~ /\//g) { + my @hd = split "/", $0; + pop @hd; # Remove filename + $basedir = join('/', @hd) || "."; + } else { + $basedir = "."; + } +} else { + $basedir = "."; +} + +# Main window +my $window = Gtk3::Window->new('toplevel'); +$window->set_title('KPad'); +$window->set_default_size(800, 600); +$window->signal_connect(destroy => sub { Gtk3->main_quit }); + +# Main layout +my $vbox = Gtk3::Box->new('vertical', 0); +$window->add($vbox); + +# Menu bar +my $menubar = Gtk3::MenuBar->new; +$vbox->pack_start($menubar, FALSE, FALSE, 0); + +# File menu +my $file_menu = Gtk3::Menu->new; +my $file_item = Gtk3::MenuItem->new_with_label('File'); +$file_item->set_submenu($file_menu); +$menubar->append($file_item); + +my $new_item = Gtk3::MenuItem->new_with_label('New'); +$new_item->signal_connect(activate => sub { + $textbuffer->set_text(''); + $statusbar->push(0, 'New file'); +}); +$file_menu->append($new_item); + +my $open_item = Gtk3::MenuItem->new_with_label('Open'); +$open_item->signal_connect(activate => \&open_file); +$file_menu->append($open_item); + +my $save_item = Gtk3::MenuItem->new_with_label('Save'); +$save_item->signal_connect(activate => \&save_file); +$file_menu->append($save_item); + +my $save_as_item = Gtk3::MenuItem->new_with_label('Save As'); +$save_as_item->signal_connect(activate => \&save_as_file); +$file_menu->append($save_as_item); + +my $exit_item = Gtk3::MenuItem->new_with_label('Exit'); +$exit_item->signal_connect(activate => \&tapp); +$file_menu->append($exit_item); + +# Edit menu +my $edit_menu = Gtk3::Menu->new; +my $edit_item = Gtk3::MenuItem->new_with_label('Edit'); +$edit_item->set_submenu($edit_menu); +$menubar->append($edit_item); + +my $undo_item = Gtk3::MenuItem->new_with_label('Undo'); +$undo_item->signal_connect(activate => sub { + $textbuffer->undo if $textbuffer->can_undo; + $statusbar->push(0, 'Undo'); +}); +$edit_menu->append($undo_item); + +my $redo_item = Gtk3::MenuItem->new_with_label('Redo'); +$redo_item->signal_connect(activate => sub { + $textbuffer->redo if $textbuffer->can_redo; + $statusbar->push(0, 'Redo'); +}); +$edit_menu->append($redo_item); + +my $cut_item = Gtk3::MenuItem->new_with_label('Cut'); +$cut_item->signal_connect(activate => sub { + $textbuffer->cut_clipboard(Gtk3::Clipboard::get('CLIPBOARD'), TRUE); +}); +$edit_menu->append($cut_item); + +my $copy_item = Gtk3::MenuItem->new_with_label('Copy'); +$copy_item->signal_connect(activate => sub { + $textbuffer->copy_clipboard(Gtk3::Clipboard::get('CLIPBOARD')); +}); +$edit_menu->append($copy_item); + +my $paste_item = Gtk3::MenuItem->new_with_label('Paste'); +$paste_item->signal_connect(activate => sub { + $textbuffer->paste_clipboard(Gtk3::Clipboard::get('CLIPBOARD'), undef, TRUE); +}); +$edit_menu->append($paste_item); + +my $select_all_item = Gtk3::MenuItem->new_with_label('Select All'); +$select_all_item->signal_connect(activate => sub { + $textbuffer->select_range($textbuffer->get_start_iter, $textbuffer->get_end_iter); +}); +$edit_menu->append($select_all_item); + +my $find_item = Gtk3::MenuItem->new_with_label('Find'); +$find_item->signal_connect(activate => sub { find_and_replace_dialog(1); }); +$edit_menu->append($find_item); + +my $replace_item = Gtk3::MenuItem->new_with_label('Find and Replace'); +$replace_item->signal_connect(activate => sub { find_and_replace_dialog(0); }); +$edit_menu->append($replace_item); + +# View menu (wrap options) +my $view_menu = Gtk3::Menu->new; +my $view_item = Gtk3::MenuItem->new_with_label('View'); +$view_item->set_submenu($view_menu); +$menubar->append($view_item); + +my $wrap_menu = Gtk3::Menu->new; +my $wrap_item = Gtk3::MenuItem->new_with_label('Wrap'); +$wrap_item->set_submenu($wrap_menu); +$view_menu->append($wrap_item); + +my $wrap_word = Gtk3::CheckMenuItem->new_with_label('Word'); +$wrap_word->signal_connect(toggled => sub { + $textview->set_wrap_mode($wrap_word->get_active ? 'word' : 'none'); +}); +$wrap_menu->append($wrap_word); + +my $wrap_char = Gtk3::CheckMenuItem->new_with_label('Char'); +$wrap_char->signal_connect(toggled => sub { + $textview->set_wrap_mode($wrap_char->get_active ? 'char' : 'none'); +}); +$wrap_menu->append($wrap_char); + +my $wrap_none = Gtk3::CheckMenuItem->new_with_label('None'); +$wrap_none->signal_connect(toggled => sub { + $textview->set_wrap_mode($wrap_none->get_active ? 'none' : 'none'); +}); +$wrap_menu->append($wrap_none); + +# Tools menu +my $tools_menu = Gtk3::Menu->new; +my $tools_item = Gtk3::MenuItem->new_with_label('Tools'); +$tools_item->set_submenu($tools_menu); +$menubar->append($tools_item); + +my $goto_line_item = Gtk3::MenuItem->new_with_label('Goto Line'); +$goto_line_item->signal_connect(activate => \&goto_line_dialog); +$tools_menu->append($goto_line_item); + +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); + +# HTML menu +my $html_menu = Gtk3::Menu->new; +my $html_item = Gtk3::MenuItem->new_with_label('HTML'); +$html_item->set_submenu($html_menu); +$menubar->append($html_item); + +my $fetch_item = Gtk3::MenuItem->new_with_label('Fetch a web resource...'); +$fetch_item->signal_connect(activate => \&fetch_html); +$html_menu->append($fetch_item); + +# Macros menu (plugins) +my $macros_menu = Gtk3::Menu->new; +my $macros_item = Gtk3::MenuItem->new_with_label('Macros'); +$macros_item->set_submenu($macros_menu); +$menubar->append($macros_item); + +my $exec_macro_item = Gtk3::MenuItem->new_with_label('Execute Macro'); +$exec_macro_item->signal_connect(activate => \&show_plugin_dialog); +$macros_menu->append($exec_macro_item); + +# Help menu +my $help_menu = Gtk3::Menu->new; +my $help_item = Gtk3::MenuItem->new_with_label('Help'); +$help_item->set_submenu($help_menu); +$menubar->append($help_item); + +my $help_topics_item = Gtk3::MenuItem->new_with_label('Help Topics...'); +$help_topics_item->signal_connect(activate => sub { + my $dialog = Gtk3::MessageDialog->new($window, 'modal', 'info', 'ok', + "Help topics for KPAD\nWell, this is a text/file editor mainly meant for scripting and programming use.\nLike notepad but made for the programmer."); + $dialog->run; + $dialog->destroy; +}); +$help_menu->append($help_topics_item); + +my $about_item = Gtk3::MenuItem->new_with_label('About KPAD...'); +$about_item->signal_connect(activate => sub { + my $dialog = Gtk3::MessageDialog->new($window, 'modal', 'info', 'ok', + "kPad\nby Paul Malcher\nVersion 6 Release\n"); + $dialog->run; + $dialog->destroy; +}); +$help_menu->append($about_item); + +# Editor (SourceView) +my $scrolled = Gtk3::ScrolledWindow->new(undef, undef); +$vbox->pack_start($scrolled, TRUE, TRUE, 0); +$textview = Gtk3::SourceView::View->new; +$textview->set_wrap_mode('word'); +$textview->set_show_line_numbers(TRUE); +$textview->set_auto_indent(TRUE); +$scrolled->add($textview); +$textbuffer = $textview->get_buffer; +my $lang_manager = Gtk3::SourceView::LanguageManager->get_default; +my $language = $lang_manager->get_language('perl'); +$textbuffer->set_language($language) if $language; +$textbuffer->set_highlight_syntax(TRUE); + +# CSS styling for Kubuntu +my $provider = Gtk3::CssProvider->new; +$provider->load_from_data(' + textview { font-family: Monospace; font-size: 12pt; } + button { color: black; background: #d3d3d3; } +'); +Gtk3::StyleContext::add_provider_for_screen( + Gtk3::Gdk::Screen::get_default, + $provider, + Gtk3::STYLE_PROVIDER_PRIORITY_APPLICATION +); + +# Status bar +$statusbar = Gtk3::Statusbar->new; +$vbox->pack_start($statusbar, FALSE, FALSE, 0); +$textbuffer->signal_connect('mark-set' => sub { + my ($buf, $iter, $mark) = @_; + if ($mark->get_name eq 'insert') { + my $line = $iter->get_line + 1; + $statusbar->push(0, "Line: $line"); + } +}); + +# Track modifications +$textbuffer->signal_connect('modified-changed' => sub { + $track = $textbuffer->get_text($textbuffer->get_start_iter, $textbuffer->get_end_iter, TRUE); +}); + +# Load file from ARGV +if ($ar) { + if (open my $fh, '<', $ar) { + local $/; + $textbuffer->set_text(<$fh>); + close $fh; + $statusbar->push(0, "Opened $ar"); + $open = $ar; + } else { + $statusbar->push(0, "Failed to open $ar"); + } +} + +# Plugin system +my @plugins; +my @n; +my $pls = 0; +while (<*.kpd>) { + push @plugins, $_; + open my $pin, '<', $_ or next; + my @gn = split '::', <$pin>; + $n[$pls] = $gn[2] eq 'auto' ? 'auto' : $gn[1]; + $pls++; +} +my $nop = grep { $_ ne 'auto' } @n; + +# File handling +sub open_file { + my $dialog = Gtk3::FileChooserDialog->new( + 'Open File', $window, 'open', + 'gtk-cancel' => 'cancel', 'gtk-ok' => 'ok' + ); + my $pl_filter = Gtk3::FileFilter->new; + $pl_filter->set_name('Perl Scripts'); + $pl_filter->add_pattern('*.pl'); + $dialog->add_filter($pl_filter); + my $all_filter = Gtk3::FileFilter->new; + $all_filter->set_name('All Files'); + $all_filter->add_pattern('*'); + $dialog->add_filter($all_filter); + my $response = $dialog->run; + if ($response && $response eq 'ok') { + my $filename = $dialog->get_filename; + if ($filename && open my $fh, '<', $filename) { + local $/; + $textbuffer->set_text(<$fh>); + close $fh; + $statusbar->push(0, "Opened $filename"); + $open = $filename; + } else { + $statusbar->push(0, "Failed to open $filename"); + } + } + $dialog->destroy; +} + +sub save_file { + if ($open) { + my ($start, $end) = $textbuffer->get_bounds; + my $text = $textbuffer->get_text($start, $end, TRUE); + if (open my $fh, '>', $open) { + print $fh $text; + close $fh; + $statusbar->push(0, "Saved $open"); + } else { + $statusbar->push(0, "Failed to save $open"); + } + } else { + save_as_file(); + } +} + +sub save_as_file { + my $dialog = Gtk3::FileChooserDialog->new( + 'Save File', $window, 'save', + 'gtk-cancel' => 'cancel', 'gtk-ok' => 'ok' + ); + my $pl_filter = Gtk3::FileFilter->new; + $pl_filter->set_name('Perl Scripts'); + $pl_filter->add_pattern('*.pl'); + $dialog->add_filter($pl_filter); + my $all_filter = Gtk3::FileFilter->new; + $all_filter->set_name('All Files'); + $all_filter->add_pattern('*'); + $dialog->add_filter($all_filter); + my $response = $dialog->run; + if ($response && $response eq 'ok') { + my $filename = $dialog->get_filename; + if ($filename) { + my ($start, $end) = $textbuffer->get_bounds; + my $text = $textbuffer->get_text($start, $end, TRUE); + if (open my $fh, '>', $filename) { + print $fh $text; + close $fh; + $statusbar->push(0, "Saved $filename"); + $open = $filename; + } else { + $statusbar->push(0, "Failed to save $filename"); + } + } + } + $dialog->destroy; +} + +# Find and replace dialog +sub find_and_replace_dialog { + my ($find_only) = @_; + my $dialog = Gtk3::Dialog->new($find_only ? 'Find' : 'Find and Replace', $window, 'modal', + 'gtk-ok', 'ok', 'gtk-cancel', 'cancel'); + my $find_entry = Gtk3::Entry->new; + my $replace_entry = Gtk3::Entry->new; + my $find_label = Gtk3::Label->new('Find:'); + $dialog->get_content_area->pack_start($find_label, FALSE, FALSE, 0); + $dialog->get_content_area->pack_start($find_entry, FALSE, FALSE, 0); + unless ($find_only) { + my $replace_label = Gtk3::Label->new('Replace with:'); + $dialog->get_content_area->pack_start($replace_label, FALSE, FALSE, 0); + $dialog->get_content_area->pack_start($replace_entry, FALSE, FALSE, 0); + } + $dialog->show_all; + if ($dialog->run eq 'ok') { + my $search = $find_entry->get_text; + my $replace = $replace_entry->get_text; + my $search_context = Gtk3::SourceView::SearchContext->new($textbuffer); + $search_context->set_search_text($search, []); + my $iter = $textbuffer->get_start_iter; + if (my ($match_start, $match_end) = $search_context->forward($iter)) { + $textbuffer->select_range($match_start, $match_end); + unless ($find_only) { + $search_context->replace($match_start, $match_end, $replace, -1); + $statusbar->push(0, "Replaced '$search' with '$replace'"); + } else { + $statusbar->push(0, "Found '$search'"); + } + } else { + $statusbar->push(0, "Text not found"); + } + } + $dialog->destroy; +} + +# Goto line dialog +sub goto_line_dialog { + my $dialog = Gtk3::Dialog->new('Goto Line', $window, 'modal', 'gtk-ok', 'ok', 'gtk-cancel', 'cancel'); + my $entry = Gtk3::Entry->new; + $dialog->get_content_area->pack_start($entry, FALSE, FALSE, 0); + $dialog->show_all; + if ($dialog->run eq 'ok') { + my $line = $entry->get_text; + if ($line =~ /^\d+$/) { + my $iter = $textbuffer->get_iter_at_line($line - 1); + $textbuffer->place_cursor($iter); + $textview->scroll_to_iter($iter, 0, TRUE, 0, 0.5); + } + } + $dialog->destroy; +} + +# Which line dialog +sub which_line_dialog { + my $iter = $textbuffer->get_iter_at_mark($textbuffer->get_insert); + my $line = $iter->get_line + 1; + my $dialog = Gtk3::MessageDialog->new($window, 'modal', 'info', 'ok', "Current line: $line"); + $dialog->run; + $dialog->destroy; +} + +# HTML fetch +sub fetch_html { + my $dialog = Gtk3::Dialog->new('HTML Source Fetch', $window, 'modal', 'gtk-ok', 'ok', 'gtk-cancel', 'cancel'); + my $label = Gtk3::Label->new('Fetch what:'); + my $entry = Gtk3::Entry->new; + $entry->set_text('http://'); + $dialog->get_content_area->pack_start($label, FALSE, FALSE, 0); + $dialog->get_content_area->pack_start($entry, FALSE, FALSE, 0); + $dialog->show_all; + if ($dialog->run eq 'ok') { + my $url = $entry->get_text; + my $contents = get($url); + if ($contents) { + $textbuffer->set_text($contents); + $statusbar->push(0, "Fetched $url"); + } else { + $statusbar->push(0, "Failed to fetch $url"); + } + } + $dialog->destroy; +} + +# Plugin dialog +sub show_plugin_dialog { + my $dialog = Gtk3::Dialog->new('Macro Execution Menu', $window, 'modal', 'gtk-close', 'close'); + my $label = Gtk3::Label->new('Double Click To Execute Macro'); + my $listbox = Gtk3::ListBox->new; + $dialog->get_content_area->pack_start($label, FALSE, FALSE, 0); + $dialog->get_content_area->pack_start($listbox, TRUE, TRUE, 0); + foreach my $name (@n) { + next if $name eq 'auto'; + my $row = Gtk3::ListBoxRow->new; + my $lbl = Gtk3::Label->new($name); + $row->add($lbl); + $listbox->add($row); + } + $listbox->signal_connect(row_activated => sub { + my ($lb, $row) = @_; + my $name = $row->get_child->get_text; + eplugin($name); + }); + $dialog->show_all; + $dialog->run; + $dialog->destroy; +} + +# Plugin execution +sub eplugin { + my ($v) = @_; + my $fp = 0; + while ($n[$fp] ne $v) { $fp++; } + $v = $plugins[$fp]; + open my $pe, '<', "$basedir/$v" or return; + my $tdata = do { local $/; <$pe> }; + close $pe; + $tdata =~ s/.*?\n//; # Skip first line + eval $tdata; + if ($@) { + my $error = $@; + my $dialog = Gtk3::MessageDialog->new($window, 'modal', 'error', 'ok', "Error: $error"); + $dialog->run; + $dialog->destroy; + } +} + +# Auto plugin execution +sub aeplugin { + for my $i (0..$#n) { + next unless $n[$i] eq 'auto'; + my $v = $plugins[$i]; + open my $pe, '<', "$basedir/$v" or next; + my $tdata = do { local $/; <$pe> }; + close $pe; + $tdata =~ s/.*?\n//; + eval $tdata; + if ($@) { + my $error = $@; + my $dialog = Gtk3::MessageDialog->new($window, 'modal', 'error', 'ok', "Error: $error"); + $dialog->run; + $dialog->destroy; + } + } +} + +# Shutdown handler +sub tapp { + if ($track ne 'init') { + my $dialog = Gtk3::MessageDialog->new( + $window, 'modal', 'question', 'yes-no', 'File contents have changed, save now?!' + ); + my $response = $dialog->run; + $dialog->destroy; + if ($response eq 'yes') { + save_file(); + } + } + Gtk3->main_quit; +} + +# Run auto plugins +my $arun = 0; +if ($arun eq '0') { + aeplugin(); +} + +# Show and start +$window->show_all; +Gtk3->main; \ No newline at end of file diff --git a/pshell.kpd b/pshell.kpd new file mode 100644 index 0000000..c135388 --- /dev/null +++ b/pshell.kpd @@ -0,0 +1,13 @@ +::RunPshellCmd:: +use strict; +my $dialog = Gtk3::Dialog->new('Run pshell Command', $::window, 'modal', 'gtk-ok', 'ok', 'gtk-cancel', 'cancel'); +my $entry = Gtk3::Entry->new; +$dialog->get_content_area->pack_start($entry, FALSE, FALSE, 0); +$dialog->show_all; +if ($dialog->run eq 'ok') { + my $cmd = $entry->get_text; + my $output = `$::basedir/pshell -e "$cmd" 2>&1` || "Error: pshell failed"; + $::textbuffer->insert_at_cursor("pshell output:\n$output\n"); + $::statusbar->push(0, "Ran pshell command"); +} +$dialog->destroy; \ No newline at end of file diff --git a/pshell_history.db b/pshell_history.db index dd2faeee6d255bb8ef5a1ecc883baf36c6e801dd..f712c8d8bd7a0401f9ff594b95badc022a49fb43 100644 GIT binary patch delta 126 zcmZojXh@hK&B!xR#+i|4W5N=CDQ>=N4E#^|Px7zhpUhvuAItB=ug=fI_mS_~W<`M= ze6o_My9$3Cc4H33Pwg&28LFq29jKpH^_^yn;KdfSW0q2*alXnCXyU* Swt*x&kS)GBT7HQDBR2pe6CW4= delta 55 zcmZojXh@hK&B!rP#+i|0W5N=CA$EQz2L7k~C;8X$Pv)=SkL7pTEU2Kv&m_q{d4s(8 L=4kmP0*vecuDlMe