Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / tools / perl-5.8.0 / lib / site_perl / 5.8.0 / sun4-solaris / Tk / TextEdit.pm
# Copyright (c) 1999 Greg Bartels. All rights reserved.
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
# Special thanks to Nick Ing-Simmons for pushing a lot of
# my text edit functionality into Text.pm and TextUndo.pm
# otherwise, this module would have been monstrous.
# Andy Worhal had it wrong, its "fifteen megabytes of fame"
# -Greg Bartels
package Tk::TextEdit;
use vars qw($VERSION);
$VERSION = '3.004'; # $Id: //depot/Tk8/Tk/TextEdit.pm#4 $
use Tk qw (Ev);
use AutoLoader;
use Text::Tabs;
use base qw(Tk::TextUndo);
Construct Tk::Widget 'TextEdit';
#######################################################################
#######################################################################
sub ClassInit
{
my ($class,$mw) = @_;
$class->SUPER::ClassInit($mw);
$mw->bind($class,'<F5>', 'IndentSelectedLines');
$mw->bind($class,'<F6>', 'UnindentSelectedLines');
$mw->bind($class,'<F7>', 'CommentSelectedLines');
$mw->bind($class,'<F8>', 'UncommentSelectedLines');
return $class;
}
# 8 horizontal pixels in the "space" character in default font.
my $tab_multiplier = 8;
sub debug_code_f1
{
my $w=shift;
}
sub debug_code_f2
{
my $w=shift;
}
#######################################################################
#######################################################################
sub InitObject
{
my ($w) = @_;
$w->SUPER::InitObject;
$w->{'INDENT_STRING'} = "\t"; # Greg mode=>"\t", Nick mode=>" "
$w->{'LINE_COMMENT_STRING'} = "#"; # assuming perl comments
my %pair_descriptor_hash =
(
'PARENS' => [ 'multiline', '(', ')', "[()]" ],
'CURLIES' => [ 'multiline', '{', '}', "[{}]" ],
'BRACES' => [ 'multiline', '[', ']', "[][]" ],
'DOUBLEQUOTE' => [ 'singleline', "\"","\"" ],
'SINGLEQUOTE' => [ 'singleline', "'","'" ],
);
$w->{'HIGHLIGHT_PAIR_DESCRIPTOR_HASH_REF'}=\%pair_descriptor_hash;
$w->tagConfigure
('CURSOR_HIGHLIGHT_PARENS', -foreground=>'white', -background=>'violet');
$w->tagConfigure
('CURSOR_HIGHLIGHT_CURLIES', -foreground=>'white', -background=>'blue');
$w->tagConfigure
('CURSOR_HIGHLIGHT_BRACES', -foreground=>'white', -background=>'purple');
$w->tagConfigure
('CURSOR_HIGHLIGHT_DOUBLEQUOTE', -foreground=>'black', -background=>'green');
$w->tagConfigure
('CURSOR_HIGHLIGHT_SINGLEQUOTE', -foreground=>'black', -background=>'grey');
$w->tagConfigure('BLOCK_HIGHLIGHT_PARENS', -background=>'red');
$w->tagConfigure('BLOCK_HIGHLIGHT_CURLIES', -background=>'orange');
$w->tagConfigure('BLOCK_HIGHLIGHT_BRACES', -background=>'red');
$w->tagConfigure('BLOCK_HIGHLIGHT_DOUBLEQUOTE', -background=>'red');
$w->tagConfigure('BLOCK_HIGHLIGHT_SINGLEQUOTE', -background=>'red');
$w->tagRaise('BLOCK_HIGHLIGHT_PARENS','CURSOR_HIGHLIGHT_PARENS');
$w->tagRaise('BLOCK_HIGHLIGHT_CURLIES','CURSOR_HIGHLIGHT_CURLIES');
$w->tagRaise('BLOCK_HIGHLIGHT_BRACES','CURSOR_HIGHLIGHT_BRACES');
$w->tagRaise('BLOCK_HIGHLIGHT_DOUBLEQUOTE','CURSOR_HIGHLIGHT_DOUBLEQUOTE');
$w->tagRaise('BLOCK_HIGHLIGHT_SINGLEQUOTE','CURSOR_HIGHLIGHT_SINGLEQUOTE');
$w->{'UPDATE_WIDGET_PERIOD'}=300; # how much time between each call.
$w->{'WINDOW_PLUS_AND_MINUS_VALUE'}=80;
$w->SetGUICallbackIndex(0);
$w->schedule_next_callback;
}
#######################################################################
sub cancel_current_gui_callback_and_restart_from_beginning
{
my ($w)=@_;
if(defined($w->{'UPDATE_WIDGET_AFTER_REFERENCE'}))
{$w->{'UPDATE_WIDGET_AFTER_REFERENCE'}->cancel();}
$w->SetGUICallbackIndex(0);
$w->schedule_next_callback;
}
sub schedule_next_callback
{
my ($w)=@_;
return if $w->NoMoreGUICallbacksToCall; #stops infinite recursive call.
$w->{'UPDATE_WIDGET_AFTER_REFERENCE'} = $w->after
($w->{'UPDATE_WIDGET_PERIOD'},
sub
{
$w->CallNextGUICallback;
$w->schedule_next_callback;
}
);
}
#######################################################################
# use these methods to pass the TextEdit widget an anonymous array
# of code references.
# any time the widget changes that requires the display to be updated,
# then these code references will be scheduled in sequence for calling.
# splitting them up allows them to be prioritized by order,
# and prevents the widget from "freezing" too long if they were
# one large callback. scheduling them apart allows the widget time
# to respond to user inputs.
#######################################################################
sub SetGUICallbacks
{
my ($w,$callback_array_ref) = @_;
$w->{GUI_CALLBACK_ARRAY_REF}=$callback_array_ref;
$w->SetGUICallbackIndex(0);
}
sub GetGUICallbacks
{
return shift->{GUI_CALLBACK_ARRAY_REF};
}
sub SetGUICallbackIndex
{
my ($w, $val)=@_;
$w->{GUI_CALLBACK_ARRAY_INDEX}=$val;
}
sub GetGUICallbackIndex
{
return shift->{GUI_CALLBACK_ARRAY_INDEX};
}
sub IncrementGUICallbackIndex
{
shift->{GUI_CALLBACK_ARRAY_INDEX} += 1;
}
sub NoMoreGUICallbacksToCall
{
my ($w) = @_;
return 0 unless defined ($w->{GUI_CALLBACK_ARRAY_REF});
return 0 unless defined ($w->{GUI_CALLBACK_ARRAY_INDEX});
my $arr_ref = $w->{GUI_CALLBACK_ARRAY_REF};
my $arr_ind = $w->{GUI_CALLBACK_ARRAY_INDEX};
return $arr_ind >= @$arr_ref;
}
sub CallNextGUICallback
{
my ($w) = @_;
return if $w->NoMoreGUICallbacksToCall;
my $arr_ref = $w->{GUI_CALLBACK_ARRAY_REF};
my $arr_ind = $w->{GUI_CALLBACK_ARRAY_INDEX};
&{$arr_ref->[$arr_ind]};
$w->IncrementGUICallbackIndex;
}
#######################################################################
#######################################################################
sub insert
{
my $w = shift;
$w->SUPER::insert(@_);
$w->cancel_current_gui_callback_and_restart_from_beginning;
}
sub delete
{
my $w = shift;
$w->SUPER::delete(@_);
$w->cancel_current_gui_callback_and_restart_from_beginning;
}
sub SetCursor
{
my $w = shift;
$w->SUPER::SetCursor(@_);
$w->cancel_current_gui_callback_and_restart_from_beginning;
}
sub OverstrikeMode
{
my ($w,$mode) = @_;
if (defined($mode))
{
$w->SUPER::OverstrikeMode($mode);
$w->cancel_current_gui_callback_and_restart_from_beginning;
}
return $w->SUPER::OverstrikeMode;
}
#######################################################################
# use yview on scrollbar to get fractional coordinates.
# scale this by the total length of the text to find the
# approximate start line of widget and end line of widget.
#######################################################################
sub GetScreenWindowCoordinates
{
my $w = shift;
my ($top_frac, $bot_frac) = $w->yview;
my $end_index = $w->index('end');
my ($lines,$columns) = split (/\./,$end_index);
my $window = $w->{'WINDOW_PLUS_AND_MINUS_VALUE'};
my $top_line = int(($top_frac * $lines) - $window);
$top_line = 0 if ($top_line < 0);
my $bot_line = int(($bot_frac * $lines) + $window);
$bot_line = $lines if ($bot_line > $lines);
my $top_index = $top_line . '.0';
my $bot_index = $bot_line . '.0';
$_[0] = $top_index;
$_[1] = $bot_index;
}
########################################################################
# take two indices as inputs.
# if they are on the same line or same column (accounting for tabs)
# then return 1
# else return 0
# (assume indices passed in are in line.column format)
########################################################################
sub IndicesLookGood
{
my ($w, $start, $end, $singleline) = @_;
return 0 unless ( (defined($start)) and (defined($end)));
my ($start_line, $start_column) = split (/\./,$start);
my ($end_line, $end_column) = split (/\./,$end);
##########################
# good if on the same line
##########################
return 1 if ($start_line == $end_line);
##########################
# if not on same line and its a singleline, its bad
##########################
return 0 if $singleline;
# get both lines, convert the tabs to spaces, and get the new column.
# see if they line up or not.
my $string;
$string = $w->get($start_line.'.0', $start_line.'.0 lineend');
$string = substr($string, 0, $start_column+1);
$string = expand($string);
$start_column = length($string);
$string = $w->get($end_line.'.0', $end_line.'.0 lineend');
$string = substr($string, 0, $end_column +1);
$string = expand($string);
$end_column = length($string);
##########################
# good if on the same column (adjusting for tabs)
##########################
return 1 if ($start_column == $end_column);
# otherwise its bad
return 0;
}
########################################################################
# if searching backward, count paranthesis until find a start parenthesis
# which does not have a forward match.
#
# (<= search backward will return this index
# ()
# START X HERE
# ( ( ) () )
# )<== search forward will return this index
#
# if searching forward, count paranthesis until find a end parenthesis
# which does not have a rearward match.
########################################################################
sub searchForBaseCharacterInPair
{
my
(
$w, $top_index, $searchfromindex, $bot_index,
$direction, $startchar, $endchar, $charpair
)=@_;
my ($plus_one_char, $search_end_index, $index_offset, $done_index);
if ($direction eq '-forward')
{
$plus_one_char = $endchar;
$search_end_index = $bot_index;
$index_offset = ' +1c';
$done_index = $w->index('end');
}
else
{
$plus_one_char = $startchar;
$search_end_index = $top_index;
$index_offset = '';
$done_index = '1.0';
}
my $at_done_index = 0;
my $count = 0;
my $char;
while(1)
{
$searchfromindex = $w->search
($direction, '-regexp', $charpair, $searchfromindex, $search_end_index );
last unless(defined($searchfromindex));
$char = $w->get($searchfromindex, $w->index($searchfromindex.' +1c'));
if ($char eq $plus_one_char)
{$count += 1;}
else
{$count -= 1;}
last if ($count==1);
# boundary condition exists when first char in widget is the match char
# need to be able to determine if search tried to go past index '1.0'
# if so, set index to undef and return.
if ( $at_done_index )
{
$searchfromindex = undef;
last;
}
$at_done_index = 1 if ($searchfromindex eq $done_index);
$searchfromindex=$w->index($searchfromindex . $index_offset);
}
return $searchfromindex;
}
########################################################################
# highlight a character pair that most closely brackets the cursor.
# allows you to pick and choose which ones you want to do.
########################################################################
sub HighlightParenthesisAroundCursor
{
my ($w)=@_;
$w->HighlightSinglePairBracketingCursor
( '(', ')', '[()]', 'CURSOR_HIGHLIGHT_PARENS','BLOCK_HIGHLIGHT_PARENS',0);
}
sub HighlightCurlyBracesAroundCursor
{
my ($w)=@_;
$w->HighlightSinglePairBracketingCursor
( '{', '}', '[{}]', 'CURSOR_HIGHLIGHT_CURLIES','BLOCK_HIGHLIGHT_CURLIES',0);
}
sub HighlightBracesAroundCursor
{
my ($w)=@_;
$w->HighlightSinglePairBracketingCursor
( '[', ']','[][]', 'CURSOR_HIGHLIGHT_BRACES','BLOCK_HIGHLIGHT_BRACES',0);
}
sub HighlightDoubleQuotesAroundCursor
{
my ($w)=@_;
$w->HighlightSinglePairBracketingCursor
( "\"", "\"", "\"", 'CURSOR_HIGHLIGHT_DOUBLEQUOTE','BLOCK_HIGHLIGHT_DOUBLEQUOTE',1);
}
sub HighlightSingleQuotesAroundCursor
{
my ($w)=@_;
$w->HighlightSinglePairBracketingCursor
( "'", "'", "'", 'CURSOR_HIGHLIGHT_SINGLEQUOTE','BLOCK_HIGHLIGHT_SINGLEQUOTE',1);
}
########################################################################
# highlight all the character pairs that most closely bracket the cursor.
########################################################################
sub HighlightAllPairsBracketingCursor
{
my ($w)=@_;
$w->HighlightParenthesisAroundCursor;
$w->HighlightCurlyBracesAroundCursor;
$w->HighlightBracesAroundCursor;
$w->HighlightDoubleQuotesAroundCursor;
$w->HighlightSingleQuotesAroundCursor;
}
########################################################################
# search for a pair of matching characters that bracket the
# cursor and tag them with the given tagname.
# startchar might be '['
# endchar would then be ']'
# tagname is a name of a tag, which has already been
# configured to highlight however the user wants them to behave.
# error tagname is the tag to highlight the chars with if there
# is a problem of some kind.
# singleline indicates whether the character pairs must occur
# on a single line. quotation marks are single line characters usually.
########################################################################
sub HighlightSinglePairBracketingCursor
{
my
(
$w, $startchar, $endchar, $charpair,
$good_tagname, $bad_tagname, $single_line
) = @_;
$single_line=0 unless defined($single_line);
$w->tagRemove($good_tagname, '1.0','end');
$w->tagRemove($bad_tagname, '1.0','end');
my $top_index; my $bot_index;
my $cursor = $w->index('insert');
if ($single_line)
{
$top_index = $w->index($cursor.' linestart');
$bot_index = $w->index($cursor.' lineend');
}
else
{
$w->GetScreenWindowCoordinates($top_index, $bot_index);
}
# search backward for the startchar
# $top_index, $searchfromindex, $bot_index,
# $direction, $startchar, $endchar, $charpair
my $startindex = $w->searchForBaseCharacterInPair
(
$top_index, $cursor, $bot_index,
'-backward', $startchar, $endchar, $charpair
);
# search forward for the endchar
my $endindex = $w->searchForBaseCharacterInPair
(
$top_index, $cursor, $bot_index,
'-forward', $startchar, $endchar, $charpair
);
return unless ((defined $startindex) and (defined $endindex));
my $final_tag = $bad_tagname;
if ($w->IndicesLookGood( $startindex, $endindex, $single_line))
{
$final_tag = $good_tagname;
}
$w->tagAdd($final_tag, $startindex, $w->index($startindex.'+1c') );
$w->tagAdd($final_tag, $endindex, $w->index( $endindex.'+1c') );
}
####################################################################
sub IndentSelectedLines
{
my($w)=@_;
$w->insertStringAtStartOfSelectedLines($w->{'INDENT_STRING'});
}
sub UnindentSelectedLines
{
my($w)=@_;
$w->deleteStringAtStartOfSelectedLines($w->{'INDENT_STRING'});
}
sub CommentSelectedLines
{
my($w)=@_;
$w->insertStringAtStartOfSelectedLines($w->{'LINE_COMMENT_STRING'});
}
sub UncommentSelectedLines
{
my($w)=@_;
$w->deleteStringAtStartOfSelectedLines($w->{'LINE_COMMENT_STRING'});
}
1;
__END__