File Coverage

blib/lib/Tk/ROSyntaxText.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Tk::ROSyntaxText;
2              
3 1     1   54483 use strict;
  1         3  
  1         46  
4 1     1   6 use warnings;
  1         2  
  1         131  
5              
6             our $VERSION = '1.001';
7              
8 1     1   806 use Tk;
  0            
  0            
9             use base qw{Tk::Derived Tk::ROText};
10              
11             use Syntax::Highlight::Engine::Kate::All;
12             use Syntax::Highlight::Engine::Kate 0.06;
13             use Carp;
14              
15             Construct Tk::Widget q{ROSyntaxText};
16              
17             my %DEFAULT_SHEK_OPTION_FOR = (
18             Alert => [ -background => q{#ffffff}, -foreground => q{#0000ff} ],
19             BaseN => [ -background => q{#ffffff}, -foreground => q{#007f00} ],
20             BString => [ -background => q{#ffffff}, -foreground => q{#c9a7ff} ],
21             Char => [ -background => q{#ffffff}, -foreground => q{#ff00ff} ],
22             Comment => [ -background => q{#ffffff}, -foreground => q{#7f7f7f} ],
23             DataType => [ -background => q{#ffffff}, -foreground => q{#0000ff} ],
24             DecVal => [ -background => q{#ffffff}, -foreground => q{#00007f} ],
25             Error => [ -background => q{#ffffff}, -foreground => q{#ff0000} ],
26             Float => [ -background => q{#ffffff}, -foreground => q{#00007f} ],
27             Function => [ -background => q{#ffffff}, -foreground => q{#007f00} ],
28             IString => [ -background => q{#ffffff}, -foreground => q{#ff0000} ],
29             Keyword => [ -background => q{#ffffff}, -foreground => q{#7f007f} ],
30             Normal => [ -background => q{#ffffff}, -foreground => q{#000000} ],
31             Operator => [ -background => q{#ffffff}, -foreground => q{#ffa500} ],
32             Others => [ -background => q{#ffffff}, -foreground => q{#b03060} ],
33             RegionMarker => [ -background => q{#ffffff}, -foreground => q{#96b9ff} ],
34             Reserved => [ -background => q{#ffffff}, -foreground => q{#9b30ff} ],
35             String => [ -background => q{#ffffff}, -foreground => q{#ff0000} ],
36             Variable => [ -background => q{#ffffff}, -foreground => q{#0000ff} ],
37             Warning => [ -background => q{#ffffff}, -foreground => q{#0000ff} ],
38             );
39              
40             my $MAX_OUTPUT_FRAG_LENGTH = 127; # arbitrary
41             my $DEFAULT_ENGINE_SYNTAX_TYPE = q{Normal};
42             my $ERR_BAD_ENGINE_SYNTAX_TYPE
43             = q{Unknown type (%s) encountered for text (%s). Using default.};
44              
45             my $DEFAULT_BG = q{#ffffff};
46             my $DEFAULT_FG = q{#000000};
47             my $DEFAULT_FONT = [qw{
48             -family Courier -size 10 -weight normal -slant roman
49             -underline 0 -overstrike 0
50             }];
51             my @DEFAULT_SPACING = qw{-spacing1 1 -spacing2 2 -spacing3 2};
52              
53             my $TAG_NAME_PREFIX = q{shek_};
54             my $SHEK_OPTION_PREFIX = q{-shek_};
55             my (%tag_name_for, %shek_option_name_for);
56              
57             my %DARK_STYLE = (
58             -foreground => q{#ffffff},
59             -background => q{#000000},
60             -shek_Alert =>
61             [ -background => q{#000000}, -foreground => q{#66ff66} ],
62             -shek_BaseN =>
63             [ -background => q{#000000}, -foreground => q{#0099ff} ],
64             -shek_BString =>
65             [ -background => q{#000000}, -foreground => q{#cc99ff} ],
66             -shek_Char =>
67             [ -background => q{#000000}, -foreground => q{#9966cc} ],
68             -shek_Comment =>
69             [ -background => q{#000000}, -foreground => q{#666666} ],
70             -shek_DataType =>
71             [ -background => q{#000000}, -foreground => q{#0066ff} ],
72             -shek_DecVal =>
73             [ -background => q{#000000}, -foreground => q{#00ccff} ],
74             -shek_Error =>
75             [ -background => q{#000000}, -foreground => q{#ff3333} ],
76             -shek_Float =>
77             [ -background => q{#000000}, -foreground => q{#339999} ],
78             -shek_Function =>
79             [ -background => q{#000000}, -foreground => q{#00ffff} ],
80             -shek_IString =>
81             [ -background => q{#000000}, -foreground => q{#ff6699} ],
82             -shek_Keyword =>
83             [ -background => q{#000000}, -foreground => q{#ffff00} ],
84             -shek_Normal =>
85             [ -background => q{#000000}, -foreground => q{#ffffff} ],
86             -shek_Operator =>
87             [ -background => q{#000000}, -foreground => q{#cc6633} ],
88             -shek_Others =>
89             [ -background => q{#000000}, -foreground => q{#cc9966} ],
90             -shek_RegionMarker =>
91             [ -background => q{#000000}, -foreground => q{#99ccff} ],
92             -shek_Reserved =>
93             [ -background => q{#000000}, -foreground => q{#9999ff} ],
94             -shek_String =>
95             [ -background => q{#000000}, -foreground => q{#00cc00} ],
96             -shek_Variable =>
97             [ -background => q{#000000}, -foreground => q{#33cccc} ],
98             -shek_Warning =>
99             [ -background => q{#000000}, -foreground => q{#ff9933} ],
100             );
101              
102             sub Populate {
103             my ($self, $args) = @_;
104              
105             $self->SUPER::Populate($args);
106              
107             $self->ConfigSpecs(
108             q{-char_subs} => [qw{PASSIVE charSubs CharSubs}, {}],
109             q{-custom_config} => [qw{PASSIVE customConfig CustomConfig}, {}],
110             q{-dark_style} => [qw{PASSIVE darkStyle DarkStyle}, 0],
111             q{-syntax_lang} => [qw{PASSIVE syntaxLang SyntaxLang Perl}],
112              
113             q{-shek_Alert} => [qw{PASSIVE shekAlert ShekAlert},
114             $DEFAULT_SHEK_OPTION_FOR{Alert}],
115             q{-shek_BaseN} => [qw{PASSIVE shekBaseN ShekBaseN},
116             $DEFAULT_SHEK_OPTION_FOR{BaseN}],
117             q{-shek_BString} => [qw{PASSIVE shekBString ShekBString},
118             $DEFAULT_SHEK_OPTION_FOR{BString}],
119             q{-shek_Char} => [qw{PASSIVE shekChar ShekChar},
120             $DEFAULT_SHEK_OPTION_FOR{Char}],
121             q{-shek_Comment} => [qw{PASSIVE shekComment ShekComment},
122             $DEFAULT_SHEK_OPTION_FOR{Comment}],
123             q{-shek_DataType} => [qw{PASSIVE shekDataType ShekDataType},
124             $DEFAULT_SHEK_OPTION_FOR{DataType}],
125             q{-shek_DecVal} => [qw{PASSIVE shekDecVal ShekDecVal},
126             $DEFAULT_SHEK_OPTION_FOR{DecVal}],
127             q{-shek_Error} => [qw{PASSIVE shekError ShekError},
128             $DEFAULT_SHEK_OPTION_FOR{Error}],
129             q{-shek_Float} => [qw{PASSIVE shekFloat ShekFloat},
130             $DEFAULT_SHEK_OPTION_FOR{Float}],
131             q{-shek_Function} => [qw{PASSIVE shekFunction ShekFunction},
132             $DEFAULT_SHEK_OPTION_FOR{Function}],
133             q{-shek_IString} => [qw{PASSIVE shekIString ShekIString},
134             $DEFAULT_SHEK_OPTION_FOR{IString}],
135             q{-shek_Keyword} => [qw{PASSIVE shekKeyword ShekKeyword},
136             $DEFAULT_SHEK_OPTION_FOR{Keyword}],
137             q{-shek_Normal} => [qw{PASSIVE shekNormal ShekNormal},
138             $DEFAULT_SHEK_OPTION_FOR{Normal}],
139             q{-shek_Operator} => [qw{PASSIVE shekOperator ShekOperator},
140             $DEFAULT_SHEK_OPTION_FOR{Operator}],
141             q{-shek_Others} => [qw{PASSIVE shekOthers ShekOthers},
142             $DEFAULT_SHEK_OPTION_FOR{Others}],
143             q{-shek_RegionMarker} => [qw{PASSIVE shekRegionMarker ShekRegionMarker},
144             $DEFAULT_SHEK_OPTION_FOR{RegionMarker}],
145             q{-shek_Reserved} => [qw{PASSIVE shekReserved ShekReserved},
146             $DEFAULT_SHEK_OPTION_FOR{Reserved}],
147             q{-shek_String} => [qw{PASSIVE shekString ShekString},
148             $DEFAULT_SHEK_OPTION_FOR{String}],
149             q{-shek_Variable} => [qw{PASSIVE shekVariable ShekVariable},
150             $DEFAULT_SHEK_OPTION_FOR{Variable}],
151             q{-shek_Warning} => [qw{PASSIVE shekWarning ShekWarning},
152             $DEFAULT_SHEK_OPTION_FOR{Warning}],
153             );
154              
155             $self->configure(
156             -background => $DEFAULT_BG,
157             -foreground => $DEFAULT_FG,
158             -font => $DEFAULT_FONT,
159             @DEFAULT_SPACING,
160             );
161             }
162              
163             sub Tk::Widget::ScrlROSyntaxText {
164             my ($parent, @options) = @_;
165              
166             my %default_options = (
167             -wrap => q{none},
168             -scrollbars => q{osoe},
169             );
170              
171             return $parent->Scrolled('ROSyntaxText' => (%default_options, @options));
172             }
173              
174             sub insert {
175             my ($self, $text) = @_;
176              
177             $self->delete(q{1.0} => q{end});
178              
179             $self->SUPER::insert(q{1.0} => q{});
180              
181             $self->_insert_highlighted_text($text);
182              
183             return;
184             }
185              
186             sub _insert_highlighted_text {
187             my ($self, $text) = @_;
188              
189             foreach my $shek_name (keys %DEFAULT_SHEK_OPTION_FOR) {
190             $tag_name_for{$shek_name} = $TAG_NAME_PREFIX . $shek_name;
191             $shek_option_name_for{$shek_name} = $SHEK_OPTION_PREFIX . $shek_name;
192             }
193              
194             my $ro_engine = $self->_get_syntax_engine();
195              
196             my $rh_subs = $ro_engine->substitutions();
197             my $have_subs = %{$rh_subs} ? 1 : 0;
198              
199             $self->_configure_tags($ro_engine->formatTable());
200              
201             my @frag_type_pairs = $ro_engine->highlight($text);
202              
203             while (@frag_type_pairs) {
204             my $frag = shift @frag_type_pairs;
205             my $type = shift @frag_type_pairs;
206              
207             if (! (defined($type) && $type)) {
208             $type = $DEFAULT_ENGINE_SYNTAX_TYPE;
209             }
210              
211             if (exists $tag_name_for{$type}) {
212             my $output_text
213             = $have_subs
214             ? join(q{}, map { exists($rh_subs->{$_}) ? $rh_subs->{$_} : $_
215             } split(//, $frag))
216             : $frag;
217              
218             $self->SUPER::insert(q{insert}, $output_text, $tag_name_for{$type});
219             }
220             else {
221             my $out_frag = length($frag) > $MAX_OUTPUT_FRAG_LENGTH
222             ? substr($frag, 0, $MAX_OUTPUT_FRAG_LENGTH - 4) . q{ ...}
223             : $frag;
224             croak sprintf($ERR_BAD_ENGINE_SYNTAX_TYPE => $type, $out_frag);
225             }
226             }
227              
228             $self->update();
229              
230             return;
231             }
232              
233             sub _configure_tags {
234             my ($self, $rh_format) = @_;
235              
236             foreach my $shek_name (keys %DEFAULT_SHEK_OPTION_FOR) {
237             $self->tagConfigure(
238             $tag_name_for{$shek_name}, @{$rh_format->{$shek_name}}
239             );
240             }
241              
242             return;
243             }
244              
245             sub _get_syntax_engine {
246             my ($self) = @_;
247              
248             $self->_customise_configuration();
249              
250             my $lang = $self->cget(q{-syntax_lang});
251             my $rh_subs = $self->cget(q{-char_subs});
252             my $rh_format = {
253             map { $_ => $self->cget($shek_option_name_for{$_})
254             } keys %shek_option_name_for
255             };
256              
257             my $ro_engine = Syntax::Highlight::Engine::Kate->new(
258             language => $lang,
259             substitutions => $rh_subs,
260             format_table => $rh_format,
261             );
262              
263             return $ro_engine;
264             }
265              
266             sub _customise_configuration {
267             my ($self) = @_;
268              
269             my %custom_config = %{$self->cget(q{-custom_config})};
270              
271             if (exists $custom_config{q{-dark_style}}) {
272             $self->configure(
273             q{-dark_style} => delete($custom_config{q{-dark_style}})
274             );
275             }
276              
277             if (exists $custom_config{q{-custom_config}}) {
278             my $discard = delete($custom_config{q{-custom_config}});
279             }
280              
281             my %new_config_for = (
282             ( $self->cget(q{-dark_style}) ? %DARK_STYLE : () ),
283             %custom_config
284             );
285              
286             foreach my $option (keys %new_config_for) {
287             $self->configure($option => $new_config_for{$option});
288             }
289              
290             return;
291             }
292              
293              
294             1;
295              
296             __END__