#!/usr/local/bin/perl -w eval 'exec /usr/local/bin/perl -w -S $0 ${1+"$@"}' if 0; # not running under some shell use strict; use IO; use Socket; use IO::Socket; use Cwd; use vars qw($VERSION $portfile); $VERSION = '3.006'; # $Id: //depot/Tk8/ptked#23 $ my %opt; INIT { my $home = $ENV{'HOME'} || $ENV{'HOMEDRIVE'}.$ENV{'HOMEPATH'}; $portfile = "$home/.ptkedsn"; my $port = $ENV{'PTKEDPORT'}; return if $^C; getopts("s",\%opt); unless (defined $port) { if (open(SN,"$portfile")) { $port = ; close(SN); } } if (defined $port) { my $sock = IO::Socket::INET->new(PeerAddr => 'localhost', PeerPort => $port, Proto => 'tcp'); if ($sock) { binmode($sock); $sock->autoflush; foreach my $file (@ARGV) { unless (print $sock "$file\n") { die "Cannot print $file to socket:$!"; } print "Requested '$file'\n"; } $sock->close || die "Cannot close socket:$!"; exit(0); } else { warn "Cannot connect to server on $port:$!"; } } } use Tk; use Tk::DropSite qw(XDND KDE Sun); use Tk::DragDrop qw(XDND KDE Sun); use Tk::widgets qw(TextUndo Scrollbar Menu); use Getopt::Std; # use Tk::ErrorDialog; my $top = MainWindow->new(); if ($opt{'s'}) { my $sock = IO::Socket::INET->new(Listen => 5, Proto => 'tcp'); die "Cannot open listen socket:$!" unless defined $sock; binmode($sock); my $port = $sock->sockport; $ENV{'PTKEDPORT'} = $port; open(SN,">$portfile") || die "Cannot open $portfile:$!"; print SN $port; close(SN); print "Accepting connections on $port\n"; $top->fileevent($sock,'readable', sub { print "accepting $sock\n"; my $client = $sock->accept; if (defined $client) { binmode($client); print "Connection $client\n"; $top->fileevent($client,'readable',[\&EditRequest,$client]); } }); } Tk::Event::HandleSignals(); $SIG{'INT'} = sub { $top->WmDeleteWindow }; $top->iconify; $top->optionAdd('*TextUndo.Background' => '#fff5e1'); $top->fontCreate('ptked',-family => 'courier', -size => ($^O eq 'MSWin32' ? 11 : -12), -weight => 'normal', -slant => 'roman'); $top->optionAdd('*TextUndo.Font' => 'ptked'); foreach my $file (@ARGV) { Create_Edit($file); } sub EditRequest { my ($client) = @_; local $_; while (<$client>) { chomp($_); print "'$_'\n", Create_Edit($_); } warn "Odd $!" unless eof($client); $top->fileevent($client,'readable',''); print "Close $client\n"; $client->close; } MainLoop; unlink("$portfile"); exit(0); sub Create_Edit { my $path = shift; my $ed = $top->Toplevel(-title => $path); $ed->withdraw; $top->{'Edits'}++; $ed->OnDestroy([\&RemoveEdit,$top]); my $t = $ed->Scrolled('TextUndo', -wrap => 'none', -scrollbars => 'osre'); $t->pack(-expand => 1, -fill => 'both'); $t = $t->Subwidget('textundo'); my $menu = $t->menu; $menu->cascade(-label => '~Help', -menuitems => [ [Button => '~About...', -command => [\&About,$ed]], ]); $ed->configure(-menu => $menu); my $dd = $t->DragDrop(-event => ''); $t->bind(ref($t),'',\&Ouch); $t->bind(ref($t),'',\&Ouch); $t->bind(ref($t),'',\&Ouch); $dd->configure(-startcommand => sub { return 1 unless (eval { $t->tagNextrange(sel => '1.0','end')}); $dd->configure(-text => $t->get('sel.first','sel.last')); }); $t->DropSite(-motioncommand => sub { my ($x,$y) = @_; $t->markSet(insert => "\@$x,$y"); }, -dropcommand => [\&HandleDrop,$t], ); $ed->protocol('WM_DELETE_WINDOW',[ConfirmExit => $t]); $t->bind('',\&DoFind); $ed->idletasks; if (-e $path) { $t->Load($path); } else { $t->FileName($path); } $ed->deiconify; $t->update; $t->focus; } sub Ouch { warn join(',','Ouch',@_); } sub RemoveEdit { my $top = shift; if (--$top->{'Edits'} == 0) { $top->destroy unless $opt{'s'}; } } sub HandleDrop {my ($t,$seln,$x,$y) = @_; # warn join(',',Drop => @_); my $string; Tk::catch { $string = $t->SelectionGet(-selection => $seln,'FILE_NAME') }; if ($@) { Tk::catch { $string = $t->SelectionGet(-selection => $seln) }; if ($@) { my @targets = $t->SelectionGet(-selection => $seln, 'TARGETS'); $t->messageBox(-text => "Targets : ".join(' ',@targets)); } else { $t->markSet(insert => "\@$x,$y"); $t->insert(insert => $string); } } else { Create_Edit($string); } } my $str; sub DoFind { my $t = shift; $str = shift if (@_); my $posn = $t->index('insert+1c'); $t->tag('remove','sel','1.0','end'); local $_; while ($t->compare($posn,'<','end')) { my ($line,$col) = split(/\./,$posn); $_ = $t->get("$line.0","$posn lineend"); pos($_) = $col; if (/\G(.*)$str/g) { $col += length($1); $posn = "$line.$col"; $t->SetCursor($posn); $t->tag('add','sel',$posn,"$line.".pos($_)); $t->focus; return; } $posn = $t->index("$posn lineend + 1c"); } } sub AskFind { my ($t) = @_; unless (exists $t->{'AskFind'}) { my $d = $t->{'AskFind'} = $t->Toplevel(-popover => 'cursor', -popanchor => 'nw'); $d->title('Find...'); $d->withdraw; $d->transient($t->toplevel); my $e = $d->Entry->pack; $e->bind('', sub { $d->withdraw; DoFind($t,$e->get); }); $d->protocol(WM_DELETE_WINDOW =>[withdraw => $d]); } $t->{'AskFind'}->Popup; $t->update; $t->{'AskFind'}->focusNext; } sub About { my $mw = shift; $mw->Dialog(-text => <<"END",-popover => $mw)->Show; $0 version $VERSION perl$]/Tk$Tk::VERSION Copyright © 1995-2000 Nick Ing-Simmons. All rights reserved. This package is free software; you can redistribute it and/or modify it under the same terms as Perl itself. END } __END__ =head1 NAME ptked - an editor in Perl/Tk =head1 SYNOPSIS S< >B [I] =head1 DESCRIPTION B is a simple text editor based on perl/Tk's TextUndo widget. =cut