~ubuntu-branches/ubuntu/maverick/padre/maverick

« back to all changes in this revision

Viewing changes to lib/Padre/Document/Perl.pm

  • Committer: Bazaar Package Importer
  • Author(s): Damyan Ivanov
  • Date: 2009-10-29 17:40:10 UTC
  • mto: (10.1.1 sid) (1.2.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20091029174010-v9ryrnscjm4gg0x2
Tags: upstream-0.48.ds2
ImportĀ upstreamĀ versionĀ 0.48.ds2

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
use YAML::Tiny      ();
10
10
use Padre::Document ();
11
11
use Padre::Util     ();
 
12
use Padre::Perl     ();
 
13
use Padre::Document::Perl::Beginner;
12
14
 
13
 
our $VERSION = '0.42';
 
15
our $VERSION = '0.48';
14
16
our @ISA     = 'Padre::Document';
15
17
 
 
18
 
 
19
 
 
20
 
 
21
 
16
22
#####################################################################
17
23
# Padre::Document::Perl Methods
18
24
 
 
25
# Ticket #637:
19
26
# TODO watch out! These PPI methods may be VERY expensive!
20
27
# (Ballpark: Around 1 Gigahertz-second of *BLOCKING* CPU per 1000 lines)
21
28
# Check out Padre::Task::PPI and its subclasses instead!
107
114
        # configuration variable
108
115
        my $limit;
109
116
        if ( $module eq 'Padre::Document::Perl::PPILexer' ) {
110
 
                $limit = 2000;
 
117
                $limit = 4000;
111
118
        } elsif ( $module eq 'Padre::Document::Perl::Lexer' ) {
112
 
                $limit = 2000;
 
119
                $limit = 4000;
113
120
        } elsif ( $module eq 'Padre::Plugin::Kate' ) {
114
 
                $limit = 2000;
 
121
                $limit = 4000;
115
122
        }
116
123
 
117
124
        my $length = $self->{original_content} ? length $self->{original_content} : 0;
130
137
}
131
138
 
132
139
 
 
140
 
 
141
 
 
142
 
133
143
#####################################################################
134
144
# Padre::Document Document Analysis
135
145
 
 
146
sub guess_filename {
 
147
        my $self = shift;
 
148
 
 
149
        # Don't attempt a content-based guess if the file already has a name.
 
150
        if ( $self->filename ) {
 
151
                return $self->SUPER::guess_filename;
 
152
        }
 
153
 
 
154
        # Is this a script?
 
155
        my $text = $self->text_get;
 
156
        if ( $text =~ /^\#\![^\n]*\bperl\b/s ) {
 
157
 
 
158
                # It's impossible to predict the name of a script in
 
159
                # advance, but lets default to a standard "script.pl"
 
160
                return 'script.pl';
 
161
        }
 
162
 
 
163
        # Is this a module
 
164
        if ( $text =~ /\bpackage\s*([\w\:]+)/s ) {
 
165
 
 
166
                # Take the last section of the package name, and use that
 
167
                # as the file.
 
168
                my $name = $1;
 
169
                $name =~ s/.*\://;
 
170
                return "$name.pm";
 
171
        }
 
172
 
 
173
        # Otherwise, no idea
 
174
        return undef;
 
175
}
 
176
 
136
177
my $keywords;
137
178
 
138
179
sub keywords {
173
214
                ? $self->store_in_tempfile
174
215
                : $self->filename;
175
216
 
176
 
        # Run with the same Perl that launched Padre
177
 
        # TODO: get preferred Perl from configuration
178
 
        my $perl = Padre->perl_interpreter;
 
217
        # Run with console Perl to prevent unexpected results under wperl
 
218
        # The configuration values is cheaper to get compared to cperl(),
 
219
        # try it first.
 
220
        my $perl = $config->run_perl_cmd;
 
221
 
 
222
        # Warn if the Perl interpreter is not executable:
 
223
        if ( defined($perl) and ( $perl ne '' ) and ( !-x $perl ) ) {
 
224
                my $ret = Wx::MessageBox(
 
225
                        Wx::gettext(
 
226
                                sprintf( '%s seems to be no executable Perl interpreter, use the system default perl instead?', $perl )
 
227
                        ),
 
228
                        Wx::gettext('Run'),
 
229
                        Wx::wxYES_NO | Wx::wxCENTRE,
 
230
                        Padre->ide->wx->main,
 
231
                );
 
232
                $perl = Padre::Perl::cperl()
 
233
                        if $ret == Wx::wxYES;
 
234
 
 
235
        } else {
 
236
                $perl = Padre::Perl::cperl();
 
237
        }
179
238
 
180
239
        # Set default arguments
181
240
        my %run_args = (
189
248
                $run_args{$arg} = Padre::DB::History->previous($type) if Padre::DB::History->previous($type);
190
249
        }
191
250
 
 
251
        # (Ticket #530) Pack args here, because adding the space later confuses the called Perls @ARGV
 
252
        my $Script_Args = '';
 
253
        $Script_Args = ' ' . $run_args{script} if defined( $run_args{script} ) and ( $run_args{script} ne '' );
 
254
 
192
255
        my $dir = File::Basename::dirname($filename);
193
256
        chdir $dir;
194
257
        return $debug
195
 
                ? qq{"$perl" -Mdiagnostics(-traceonly) $run_args{interpreter} "$filename" $run_args{script}}
196
 
                : qq{"$perl" $run_args{interpreter} "$filename" $run_args{script}};
 
258
                ? qq{"$perl" -Mdiagnostics(-traceonly) $run_args{interpreter} "$filename"$Script_Args}
 
259
                : qq{"$perl" $run_args{interpreter} "$filename"$Script_Args};
197
260
}
198
261
 
199
262
sub pre_process {
201
264
 
202
265
        if ( Padre->ide->config->editor_beginner ) {
203
266
                require Padre::Document::Perl::Beginner;
204
 
                my $b = Padre::Document::Perl::Beginner->new;
 
267
                my $b = Padre::Document::Perl::Beginner->new( document => $self );
205
268
                if ( $b->check( $self->text_get ) ) {
206
269
                        return 1;
207
270
                } else {
250
313
        }
251
314
        $self->{last_syncheck_md5} = $md5;
252
315
 
253
 
        my $nlchar = "\n";
254
 
        if ( $self->get_newline_type eq 'WIN' ) {
255
 
                $nlchar = "\r\n";
256
 
        } elsif ( $self->get_newline_type eq 'MAC' ) {
257
 
                $nlchar = "\r";
258
 
        }
 
316
        my $nlchar = $self->newline;
259
317
 
260
318
        require Padre::Task::SyntaxChecker::Perl;
261
319
        my %check = (
285
343
        }
286
344
}
287
345
 
 
346
# Run the checks for common beginner errors
 
347
sub beginner_check {
 
348
        my $self = shift;
 
349
 
 
350
        # TODO: Make this cool
 
351
        # It isn't, because it should show _all_ warnings instead of one and
 
352
        # it should at least go to the line it's complaining about.
 
353
        # Ticket #534
 
354
 
 
355
        my $Beginner = Padre::Document::Perl::Beginner->new(
 
356
                document => $self,
 
357
                editor   => $self->editor
 
358
        );
 
359
 
 
360
        $Beginner->check( $self->text_get );
 
361
 
 
362
        my $error = $Beginner->error;
 
363
 
 
364
        if ($error) {
 
365
                Padre->ide->wx->main->error( Wx::gettext("Error:\n") . $error );
 
366
        } else {
 
367
                Padre->ide->wx->main->message( Wx::gettext('No errors found.') );
 
368
        }
 
369
 
 
370
        return 1;
 
371
}
 
372
 
288
373
sub get_outline {
289
374
        my $self = shift;
290
375
        my %args = @_;
360
445
        $cursor_col = length($line_content) - 1 if $cursor_col >= length($line_content);
361
446
        my $col = $cursor_col;
362
447
 
363
 
        # find start of symbol TODO: This could be more robust, no?
 
448
        # find start of symbol
 
449
        # TODO: This could be more robust, no?
 
450
        # Ticket #639
364
451
        while (1) {
365
452
                if ( $col <= 0 or substr( $line_content, $col, 1 ) =~ /^[^#\w:\']$/ ) {
366
453
                        last;
417
504
        return ();
418
505
}
419
506
 
 
507
 
 
508
 
 
509
 
 
510
 
420
511
#####################################################################
421
512
# Padre::Document Document Manipulation
422
513
 
464
555
        return ();
465
556
}
466
557
 
 
558
sub extract_subroutine {
 
559
        my ( $self, $newname ) = @_;
 
560
 
 
561
        my $editor = $self->editor;
 
562
        my $code   = $editor->GetSelectedText();
 
563
 
 
564
        my $sub_comment = <<EOC;
 
565
 
566
# New subroutine extracted.
 
567
#
 
568
EOC
 
569
 
 
570
        # we want to get a list of the subroutines to pick where to place
 
571
        # the new sub
 
572
        my @functions = $self->get_functions;
 
573
 
 
574
        #print "printing the functions: " . join( "\n", @functions );
 
575
 
 
576
        # Show a list of functions
 
577
        require Padre::Wx::Dialog::RefactorSelectFunction;
 
578
        my $dialog = Padre::Wx::Dialog::RefactorSelectFunction->new( $editor->main, \@functions );
 
579
        $dialog->show();
 
580
        if ( $dialog->{cancelled} ) {
 
581
                return ();
 
582
        }
 
583
 
 
584
        # testing for now hard set:
 
585
        #my $subname = 'testing2';
 
586
        # check if canceled:
 
587
 
 
588
        my $subname = $dialog->get_function_name;
 
589
 
 
590
        # get the new code, replace the selection
 
591
        require Devel::Refactor;
 
592
        my $refactory = Devel::Refactor->new;
 
593
        my ( $new_sub_call, $new_code ) = $refactory->extract_subroutine( $newname, $code, 1 );
 
594
 
 
595
        # make the change to the selected text
 
596
        $editor->BeginUndoAction(); # do the edit atomically
 
597
        $editor->ReplaceSelection($new_sub_call);
 
598
 
 
599
        # with the change made
 
600
        # locate the function:
 
601
        my ( $start, $end ) = Padre::Util::get_matches(
 
602
                $editor->GetText,
 
603
                $self->get_function_regex($subname),
 
604
                $editor->GetSelection,  # Provides two params
 
605
        );
 
606
        unless ( defined $start ) {
 
607
 
 
608
                # This needs to now rollback the
 
609
                # the changes made with the editor
 
610
                $editor->Undo();
 
611
                $editor->EndUndoAction();
 
612
 
 
613
                # Couldn't find it
 
614
                # should be dialog
 
615
                #print "Couldn't find the sub: $subname\n";
 
616
                return;
 
617
        }
 
618
 
 
619
        # now instert the text into the right location
 
620
        my $data = Wx::TextDataObject->new;
 
621
        $data->SetText( $sub_comment . $new_code );
 
622
        my $length = $data->GetTextLength;
 
623
 
 
624
        $editor->InsertText( $start, $data->GetText );
 
625
        $editor->EndUndoAction();
 
626
 
 
627
        return ();
 
628
 
 
629
}
 
630
 
 
631
# This sub handles a cached C-Tags - Parser object which is much faster
 
632
# than recreating it on every autocomplete
 
633
 
 
634
sub _perltags_parser {
 
635
        my $self = shift;
 
636
 
 
637
        require Parse::ExuberantCTags;
 
638
 
 
639
        my $perltags_file = $self->{_perltags_file};
 
640
 
 
641
        # Temporary until this is configurable:
 
642
        if ( !defined($perltags_file) ) {
 
643
                $self->{_perltags_file} = File::Spec->catfile( $ENV{PADRE_HOME}, 'perltags' );
 
644
                $perltags_file = $self->{_perltags_file};
 
645
        }
 
646
 
 
647
        # If we don't have a file (none specified in config, for example), return undef
 
648
        # as the object and noone will try to use it
 
649
        return undef if !defined($perltags_file);
 
650
 
 
651
        my $parser;
 
652
 
 
653
        # Use the cached parser if
 
654
        #  - there is one
 
655
        #  - the last check is younger than 5 seconds (don't check the file again)
 
656
        #    or the file's mtime matches our cached mtime
 
657
        if (    defined( $self->{_perltags_parser} )
 
658
                and defined( $self->{_perltags_parser_time} )
 
659
                and (  ( $self->{_perltags_parser_last} > ( time - 5 ) )
 
660
                        or ( $self->{_perltags_parser_time} == ( stat($perltags_file) )[9] ) )
 
661
                )
 
662
        {
 
663
                $parser = $self->{_perltags_parser};
 
664
                $self->{_perltags_parser_last} = time;
 
665
        } else {
 
666
                $parser                        = Parse::ExuberantCTags->new($perltags_file);
 
667
                $self->{_perltags_parser}      = $parser;
 
668
                $self->{_perltags_parser_time} = ( stat($perltags_file) )[9];
 
669
                $self->{_perltags_parser_last} = time;
 
670
        }
 
671
 
 
672
        return $parser;
 
673
}
 
674
 
467
675
sub autocomplete {
468
676
        my $self = shift;
469
677
 
489
697
        # i) hack Perl::Tags to be better (including inheritance)
490
698
        # j) add inheritance support
491
699
        # k) figure out how to do method auto-comp. on objects
492
 
        require Parse::ExuberantCTags;
493
700
 
494
701
        # check for variables
 
702
 
 
703
        # (Ticket #676)
 
704
 
495
705
        if ( $prefix =~ /([\$\@\%\*])(\w+(?:::\w+)*)$/ ) {
496
706
                my $prefix = $2;
497
707
                my $type   = $1;
498
 
                my $parser = Parse::ExuberantCTags->new( File::Spec->catfile( $ENV{PADRE_HOME}, 'perltags' ) );
 
708
                my $parser = $self->_perltags_parser;
499
709
                if ( defined $parser ) {
500
710
                        my $tag = $parser->findTag( $prefix, partial => 1 );
501
711
                        my @words;
519
729
                }
520
730
        }
521
731
 
 
732
        # check for hashs
 
733
        elsif ( $prefix =~ /(\$\w+(?:\-\>)?)\{([\'\"]?)([\$\&]?\w*)$/ ) {
 
734
                my $hashname   = $1;
 
735
                my $textmarker = $2;
 
736
                my $keyprefix  = $3;
 
737
 
 
738
                my $last = $editor->GetLength();
 
739
                my $text = $editor->GetTextRange( 0, $last );
 
740
 
 
741
                my %words;
 
742
                while ( $text =~ /\Q$hashname\E\{(([\'\"]?)\Q$keyprefix\E.+?\2)\}/g ) {
 
743
                        $words{$1} = 1;
 
744
                }
 
745
 
 
746
                return (
 
747
                        length( $textmarker . $keyprefix ),
 
748
                        sort {
 
749
                                my $a1 = $a;
 
750
                                my $b1 = $b;
 
751
                                $a1 =~ s/^([\'\"])(.+)\1/$2/;
 
752
                                $b1 =~ s/^([\'\"])(.+)\1/$2/;
 
753
                                $a1 cmp $b1;
 
754
                                } ( keys(%words) )
 
755
                );
 
756
 
 
757
        }
 
758
 
522
759
        # check for methods
523
760
        elsif ( $prefix =~ /(?![\$\@\%\*])(\w+(?:::\w+)*)\s*->\s*(\w*)$/ ) {
524
761
                my $class  = $1;
525
762
                my $prefix = $2;
526
763
                $prefix = '' if not defined $prefix;
527
 
                my $parser = Parse::ExuberantCTags->new( File::Spec->catfile( $ENV{PADRE_HOME}, 'perltags' ) );
 
764
                my $parser = $self->_perltags_parser;
528
765
                if ( defined $parser ) {
529
766
                        my $tag = ( $prefix eq '' ) ? $parser->firstTag() : $parser->findTag( $prefix, partial => 1 );
530
767
                        my @words;
549
786
        # check for packages
550
787
        elsif ( $prefix =~ /(?![\$\@\%\*])(\w+(?:::\w+)*)/ ) {
551
788
                my $prefix = $1;
552
 
                my $parser = Parse::ExuberantCTags->new( File::Spec->catfile( $ENV{PADRE_HOME}, 'perltags' ) );
 
789
                my $parser = $self->_perltags_parser;
 
790
 
553
791
                if ( defined $parser ) {
554
792
                        my $tag = $parser->findTag( $prefix, partial => 1 );
555
793
                        my @words;
580
818
        my $post_text = $editor->GetTextRange( $first, $last );
581
819
 
582
820
        my $regex;
583
 
        eval { $regex = qr{\b($prefix\w+(?:::\w+)*)\b} };
 
821
        eval { $regex = qr{\b(\Q$prefix\E\w+(?:::\w+)*)\b} };
584
822
        if ($@) {
585
823
                return ("Cannot build regex for '$prefix'");
586
824
        }
597
835
        return ( length($prefix), @words );
598
836
}
599
837
 
 
838
sub newline_keep_column {
 
839
        my $self = shift;
 
840
 
 
841
        my $editor = $self->editor or return;
 
842
        my $pos    = $editor->GetCurrentPos;
 
843
        my $line   = $editor->LineFromPosition($pos);
 
844
        my $first  = $editor->PositionFromLine($line);
 
845
        my $col    = $pos - $editor->PositionFromLine( $editor->LineFromPosition($pos) );
 
846
        my $text   = $editor->GetTextRange( $first, ( $pos - $first ) );
 
847
 
 
848
        $editor->AddText( $self->newline );
 
849
 
 
850
        $pos   = $editor->GetCurrentPos;
 
851
        $first = $editor->PositionFromLine( $editor->LineFromPosition($pos) );
 
852
 
 
853
        #       my $col2 = $pos - $first;
 
854
        #       $editor->AddText( ' ' x ( $col - $col2 ) );
 
855
 
 
856
        # TODO: Remove the part made by auto-ident before addtext:
 
857
        $text =~ s/[^\s\t\r\n]/ /g;
 
858
        $editor->AddText($text);
 
859
 
 
860
        $editor->SetCurrentPos( $first + $col );
 
861
 
 
862
        return 1;
 
863
}
 
864
 
600
865
sub event_on_char {
601
866
        my ( $self, $editor, $event ) = @_;
 
867
 
 
868
        my $config = Padre->ide->config;
 
869
        my $main   = Padre->ide->wx->main;
 
870
 
602
871
        $editor->Freeze;
603
872
 
604
873
        my $selection_exists = 0;
609
878
 
610
879
        my $key = $event->GetUnicodeKey;
611
880
 
612
 
        if ( Padre->ide->config->autocomplete_brackets ) {
 
881
        my $pos   = $editor->GetCurrentPos;
 
882
        my $line  = $editor->LineFromPosition($pos);
 
883
        my $first = $editor->PositionFromLine($line);
 
884
        my $last  = $editor->PositionFromLine( $line + 1 ) - 1;
 
885
 
 
886
        if ( $config->autocomplete_brackets ) {
613
887
                my %table = (
614
888
                        34  => 34,  # " "
615
889
                        39  => 39,  # ' '
618
892
                        91  => 93,  # [ ]
619
893
                        123 => 125, # { }
620
894
                );
621
 
                my $pos = $editor->GetCurrentPos;
622
895
                if ( $table{$key} ) {
623
896
                        if ($selection_exists) {
624
897
                                my $start = $editor->GetSelectionStart;
631
904
                                if ( $editor->GetTextLength > $pos ) {
632
905
                                        $nextChar = $editor->GetTextRange( $pos, $pos + 1 );
633
906
                                }
634
 
                                unless ( defined($nextChar)
635
 
                                        && ord($nextChar) == $table{$key} )
 
907
                                unless ( defined($nextChar) && ord($nextChar) == $table{$key}
 
908
                                        and ( !$config->autocomplete_multiclosebracket ) )
636
909
                                {
637
910
                                        $editor->AddText( chr( $table{$key} ) );
638
911
                                        $editor->CharLeft;
641
914
                }
642
915
        }
643
916
 
 
917
        # This only matches if all conditions are met:
 
918
        #  - config option enabled
 
919
        #  - none of the following keys pressed: a-z, A-Z, 0-9, _
 
920
        #  - cursor position is at end of line
 
921
        if ($config->autocomplete_method
 
922
                and (  ( $key < 48 )
 
923
                        or ( ( $key > 57 ) and ( $key < 65 ) )
 
924
                        or ( ( $key > 90 ) and ( $key < 95 ) )
 
925
                        or ( $key == 96 )
 
926
                        or ( $key > 122 ) )
 
927
                and ( $pos == $last )
 
928
                )
 
929
        {
 
930
 
 
931
                # from beginning to current position
 
932
                my $prefix = $editor->GetTextRange( 0, $pos );
 
933
 
 
934
                # methods can't live outside packages, so ignore them
 
935
                if ( $prefix =~ /package / ) {
 
936
                        my $linetext = $editor->GetTextRange( $first, $last );
 
937
 
 
938
                        # we only match "sub foo" at the beginning of a line
 
939
                        # but no inline subs (eval, anonymus, etc.)
 
940
                        # The end-of-subname match is included in the first if
 
941
                        # which match the last key pressed (which is not part of
 
942
                        # $linetext at this moment:
 
943
                        if ( $linetext =~ /^sub[\s\t]+\w+$/ ) {
 
944
 
 
945
                                # Add the default skeleton of a method,
 
946
                                # the \t should be replaced by
 
947
                                # (space * current_indent_width)
 
948
                                $editor->AddText( ' {'
 
949
                                                . $self->newline . "\t"
 
950
                                                . 'my $self = shift;'
 
951
                                                . $self->newline . "\t"
 
952
                                                . $self->newline . '}'
 
953
                                                . $self->newline
 
954
                                                . $self->newline );
 
955
 
 
956
                                # Ready for typing in the new method:
 
957
                                $editor->GotoPos( $last + 23 );
 
958
 
 
959
                        }
 
960
                }
 
961
        }
 
962
 
644
963
        $editor->Thaw;
 
964
 
 
965
        $main->on_autocompletion if $config->autocomplete_always;
 
966
 
645
967
        return;
646
968
}
647
969
 
657
979
        my $pos;
658
980
        if ( $event->isa("Wx::MouseEvent") ) {
659
981
                my $point = $event->GetPosition();
660
 
                $pos = $editor->PositionFromPoint($point);
661
 
        } else {
 
982
                if ( $point != Wx::wxDefaultPosition ) {
 
983
 
 
984
                        # Then it is really a mouse event...
 
985
                        # On Windows, context menu is faked
 
986
                        # as a Mouse event
 
987
                        $pos = $editor->PositionFromPoint($point);
 
988
                }
 
989
        }
 
990
 
 
991
        unless ($pos) {
662
992
 
663
993
                # Fall back to the cursor position
664
 
                $editor->GetCurrentPos();
 
994
                $pos = $editor->GetCurrentPos();
665
995
        }
666
996
 
667
997
        my $introduced_separator = 0;
784
1114
        } # end if control-click
785
1115
}
786
1116
 
 
1117
#
 
1118
# Returns Perl's Help Provider
 
1119
#
 
1120
sub get_help_provider {
 
1121
        require Padre::HelpProvider::Perl;
 
1122
        return Padre::HelpProvider::Perl->new;
 
1123
}
 
1124
 
 
1125
#
 
1126
# Returns Perl's Quick Fix Provider
 
1127
#
 
1128
sub get_quick_fix_provider {
 
1129
        require Padre::QuickFixProvider::Perl;
 
1130
        return Padre::QuickFixProvider::Perl->new;
 
1131
}
 
1132
 
787
1133
1;
788
1134
 
789
1135
# Copyright 2008-2009 The Padre development team as listed in Padre.pm.