File Coverage

blib/lib/PLS/Parser/DocumentSymbols.pm
Criterion Covered Total %
statement 24 75 32.0
branch 0 28 0.0
condition 0 15 0.0
subroutine 8 11 72.7
pod 0 2 0.0
total 32 131 24.4


line stmt bran cond sub pod time code
1              
2             use strict;
3 9     9   47 use warnings;
  9         18  
  9         712  
4 9     9   52  
  9         9  
  9         357  
5             use feature 'state';
6 9     9   61  
  9         18  
  9         1887  
7             use IO::Async::Function;
8 9     9   55 use IO::Async::Loop;
  9         71  
  9         354  
9 9     9   46 use Scalar::Util qw(blessed);
  9         18  
  9         325  
10 9     9   45  
  9         18  
  9         1468  
11             use PLS::Parser::Document;
12 9     9   55  
  9         9  
  9         586  
13             use constant {
14             PACKAGE => 4,
15 9         10471 FUNCTION => 12,
16             VARIABLE => 13,
17             CONSTANT => 14
18             };
19 9     9   69  
  9         10  
20             =head1 NAME
21              
22             PLS::Parser::DocumentSymbols
23              
24             =head1 DESCRIPTION
25              
26             This class parses a document to find all symbols.
27             It returns a hierachy of the symbols, so that a tree structure can be displayed.
28              
29             =cut
30              
31             {
32             my ($class, $uri) = @_;
33              
34 0     0 0   state $function;
35              
36 0           if (ref $function ne 'IO::Async::Function')
37             {
38 0 0         $function = IO::Async::Function->new(code => \&get_all_document_symbols);
39             IO::Async::Loop->new->add($function);
40 0           }
41 0            
42             my $text = PLS::Parser::Document->text_from_uri($uri);
43             return $function->call(args => [$class, $uri, $text]);
44 0           } ## end sub get_all_document_symbols_async
45 0            
46             {
47             my ($class, $uri, $text) = @_;
48              
49             my $document = PLS::Parser::Document->new(uri => $uri, text => $text);
50 0     0 0   return [] if (ref $document ne 'PLS::Parser::Document');
51              
52 0           my @roots;
53 0 0         $class->_get_all_document_symbols($document, $document->{document}, \@roots);
54              
55 0           my @package_roots;
56 0            
57             my $packages = $document->get_packages();
58 0            
59             foreach my $index (0 .. $#{$packages})
60 0           {
61             my $line_start = $packages->[$index]->lsp_line_number;
62 0           my $line_end = $index == $#{$packages} ? undef : $packages->[$index + 1]->lsp_line_number;
  0            
63             my $range = $packages->[$index]->range();
64 0            
65 0 0         push @package_roots,
  0            
66 0           {
67             name => $packages->[$index]->name,
68             kind => PACKAGE,
69             range => $range,
70             selectionRange => $range,
71             children => [grep { $_->{range}{start}{line} > $line_start and (not defined $line_end or $_->{range}{end}{line} < $line_end) } @roots]
72             };
73             } ## end foreach my $index (0 .. $#{...})
74 0 0 0        
  0            
75             unless (scalar @package_roots)
76             {
77             my $range = PLS::Parser::Element->new(element => $document->{document})->range();
78 0 0          
79             push @package_roots,
80 0           {
81             name => 'main',
82 0           kind => PACKAGE,
83             range => $range,
84             selectionRange => $range,
85             children => \@roots
86             };
87             } ## end unless (scalar @package_roots...)
88              
89             return \@package_roots;
90             } ## end sub get_all_document_symbols
91              
92 0           {
93             my ($class, $document, $scope, $roots, $current) = @_;
94              
95             my $array = ref $current eq 'HASH' ? $current->{children} : $roots;
96             return unless blessed($scope);
97 0     0      
98             if ($scope->isa('PPI::Document') or $scope->isa('PPI::Structure::Block'))
99 0 0         {
100 0 0         foreach my $child ($scope->children)
101             {
102 0 0 0       $class->_get_all_document_symbols($document, $child, $roots, $current);
    0 0        
    0 0        
    0 0        
103             }
104 0           } ## end if ($scope->isa('PPI::Document'...))
105             elsif ($scope->isa('PPI::Statement::Sub') or $scope->isa('PPI::Statement::Scheduled'))
106 0           {
107             # Don't show subroutine forward declarations
108             return unless blessed($scope->block);
109             return unless $scope->block->isa('PPI::Structure::Block');
110             my $range = PLS::Parser::Element->new(element => $scope)->range();
111              
112 0 0         $current = {
113 0 0         name => $scope->isa('PPI::Statement::Sub') ? $scope->name : $scope->type,
114 0           kind => FUNCTION,
115             range => $range,
116 0 0         selectionRange => $range,
117             children => []
118             };
119              
120             push @{$array}, $current;
121              
122             $class->_get_all_document_symbols($document, $scope->block, $roots, $current);
123             } ## end elsif ($scope->isa('PPI::Statement::Sub'...))
124 0           elsif ($scope->isa('PPI::Statement::Variable'))
  0            
125             {
126 0           push @{$array}, map {
127             my $range = $_->range();
128              
129             {
130 0           name => $_->name,
131 0           kind => VARIABLE,
132             range => $range,
133             selectionRange => $range
134 0           }
135             } map { @{$_->symbols} } @{$document->get_variable_statements($scope)};
136             } ## end elsif ($scope->isa('PPI::Statement::Variable'...))
137             elsif ($scope->isa('PPI::Statement::Include') and $scope->type eq 'use' and $scope->pragma eq 'constant')
138             {
139 0           push @{$array}, map {
  0            
  0            
  0            
140             my $range = $_->range();
141              
142             {
143 0           name => $_->name,
144 0           kind => CONSTANT,
145             range => $range,
146             selectionRange => $range
147 0           }
148             } @{$document->get_constants($scope)};
149             } ## end elsif ($scope->isa('PPI::Statement::Include'...))
150             } ## end sub _get_all_document_symbols
151              
152 0           1;
  0