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