File Coverage

blib/lib/Padre/Plugin/SpellCheck/Engine.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Padre::Plugin::SpellCheck::Engine;
2              
3 1     1   22215 use v5.10;
  1         4  
  1         54  
4 1     1   6 use warnings;
  1         3  
  1         51  
5 1     1   6 use strict;
  1         7  
  1         52  
6              
7             our $VERSION = '1.33';
8              
9 1     1   483 use Padre::Logger;
  0            
  0            
10             use Padre::Unload ();
11              
12             use Class::Accessor 'antlers';
13             has _ignore => ( is => 'rw', isa => 'Str' ); # list of words to ignore
14             has _speller => ( is => 'rw', isa => 'Str' ); # real text::Aspell object
15              
16             # FIXME: as soon as wxWidgets/wxPerl supports
17             # newer version 1.31_03
18             # number of UTF8 characters
19             # used in calculating current possition
20             has _utf_chars => ( is => 'rw', isa => 'Str' );
21              
22             my %MIMETYPE_MODE = (
23             'application/x-latex' => 'tex',
24             'text/html' => 'html',
25             'text/xml' => 'sgml',
26             );
27              
28              
29             #######
30             # new
31             #######
32             sub new {
33             my $class = shift; # What class are we constructing?
34             my $self = {}; # Allocate new memory
35             bless $self, $class; # Mark it of the right type
36             $self->_init(@_); # Call _init with remaining args
37             return $self;
38             }
39              
40              
41             #######
42             # Method _init
43             #######
44             sub _init {
45             my ( $self, $mimetype, $iso, $engine ) = @_;
46              
47             $self->_ignore( {} );
48             $self->_utf_chars(0);
49              
50             # create speller object
51             my $speller;
52             if ( $engine eq 'Aspell' ) {
53             require Text::Aspell;
54             $speller = Text::Aspell->new;
55              
56             $speller->set_option( 'sug-mode', 'normal' );
57             $speller->set_option( 'lang', $iso );
58              
59             if ( exists $MIMETYPE_MODE{$mimetype} ) {
60             if ( not defined $speller->set_option( 'mode', $MIMETYPE_MODE{$mimetype} ) ) {
61             my $err = $speller->errstr;
62             warn "Could not set Aspell mode '$MIMETYPE_MODE{$mimetype}': $err\n";
63             }
64             }
65              
66             } else {
67             require Text::Hunspell;
68              
69             #TODO add some checking
70             # You can use relative or absolute paths.
71             $speller = Text::Hunspell->new(
72             "/usr/share/hunspell/$iso.aff", # Hunspell affix file
73             "/usr/share/hunspell/$iso.dic" # Hunspell dictionary file
74             );
75             }
76              
77             TRACE( $speller->print_config ) if DEBUG;
78              
79             $self->_speller($speller);
80              
81             return;
82             }
83              
84              
85             #######
86             # Method check
87             #######
88             sub check {
89             my ( $self, $text ) = @_;
90             my $ignore = $self->_ignore;
91              
92             # iterate over word boundaries
93             while ( $text =~ /(.+?)(\b|\z)/g ) {
94             my $word = $1;
95              
96             # skip...
97             next unless defined $word; # empty strings
98             next unless $word =~ /^\p{Letter}+$/i; # non-spellable words
99              
100             # FIXME: when STC issues will be resolved:
101             # count number of UTF8 characters in ignored/correct words
102             # it's going to be used to calculate relative position
103             # of next problematic word
104             if ( exists $ignore->{$word} ) {
105             $self->_count_utf_chars($word);
106             next;
107             }
108              
109             if ( $self->_speller->check($word) ) {
110             $self->_count_utf_chars($word);
111             next;
112             }
113              
114             # oops! spell mistake!
115             my $pos = ( pos $text ) - ( length $word );
116              
117             return $word, $pos;
118             }
119              
120             # $text does not contain any error
121             return;
122             }
123              
124             #######
125             # Method set_ignore_word
126             #######
127             sub set_ignore_word {
128             my ( $self, $word ) = @_;
129              
130             $self->_ignore->{$word} = 1;
131              
132             return;
133             }
134              
135             #######
136             # Method get_suggestions
137             #######
138             sub get_suggestions {
139             my ( $self, $word ) = @_;
140              
141             return $self->_speller->suggest($word);
142             }
143              
144              
145             #######
146             #TODO FIXME: as soon as STC issues is resolved
147             #
148             sub _count_utf_chars {
149             my ( $self, $word ) = @_;
150              
151             foreach ( split //, $word ) {
152             $self->{_utf_chars}++ if ord($_) >= 128;
153             }
154              
155             return;
156             }
157              
158             1;
159              
160             __END__