File Coverage

blib/lib/Perl/LanguageServer/Workspace.pm
Criterion Covered Total %
statement 23 112 20.5
branch 0 38 0.0
condition 0 10 0.0
subroutine 8 19 42.1
pod 0 10 0.0
total 31 189 16.4


line stmt bran cond sub pod time code
1             package Perl::LanguageServer::Workspace ;
2              
3 1     1   26 use 5.006;
  1         3  
4 1     1   6 use strict;
  1         2  
  1         24  
5 1     1   5 use Moose ;
  1         3  
  1         8  
6              
7 1     1   6746 use File::Basename ;
  1         4  
  1         81  
8 1     1   7 use Coro ;
  1         3  
  1         75  
9 1     1   6 use Coro::AIO ;
  1         2  
  1         364  
10 1     1   9 use Data::Dump qw{dump} ;
  1         10  
  1         74  
11              
12             with 'Perl::LanguageServer::SyntaxChecker' ;
13             with 'Perl::LanguageServer::Parser' ;
14              
15 1     1   18 no warnings 'uninitialized' ;
  1         3  
  1         1752  
16              
17             # ---------------------------------------------------------------------------
18              
19             has 'config' =>
20             (
21             isa => 'HashRef',
22             is => 'ro'
23             ) ;
24              
25             has 'is_shutdown' =>
26             (
27             isa => 'Bool',
28             is => 'rw',
29             default => 0,
30             ) ;
31              
32             has 'files' =>
33             (
34             isa => 'HashRef',
35             is => 'rw',
36             default => sub { {} },
37             ) ;
38              
39             has 'folders' =>
40             (
41             isa => 'HashRef',
42             is => 'rw',
43             default => sub { {} },
44             ) ;
45              
46             has 'symbols' =>
47             (
48             isa => 'HashRef',
49             is => 'rw',
50             default => sub { {} },
51             ) ;
52              
53             has 'path_map' =>
54             (
55             isa => 'Maybe[ArrayRef]',
56             is => 'rw'
57             ) ;
58              
59             has 'file_filter_regex' =>
60             (
61             isa => 'Str',
62             is => 'rw',
63             default => '(?:\.pm|\.pl)$',
64             ) ;
65              
66             has 'ignore_dir' =>
67             (
68             isa => 'HashRef',
69             is => 'rw',
70             default => sub { { '.git' => 1, '.svn' => 1, '.vscode' => 1 } },
71             ) ;
72              
73             has 'perlcmd' =>
74             (
75             isa => 'Str',
76             is => 'rw',
77             default => $^X,
78             ) ;
79              
80             has 'perlinc' =>
81             (
82             isa => 'Maybe[ArrayRef]',
83             is => 'rw',
84             ) ;
85              
86             has 'show_local_vars' =>
87             (
88             isa => 'Maybe[Bool]',
89             is => 'rw',
90             ) ;
91              
92              
93             has 'parser_channel' =>
94             (
95             is => 'rw',
96             isa => 'Coro::Channel',
97             default => sub { Coro::Channel -> new }
98             ) ;
99              
100             has 'state_dir' =>
101             (
102             is => 'rw',
103             isa => 'Str',
104             lazy_build => 1,
105             clearer => 'clear_state_dir',
106             ) ;
107              
108             has 'disable_cache' =>
109             (
110             isa => 'Maybe[Bool]',
111             is => 'rw',
112             ) ;
113              
114             # ---------------------------------------------------------------------------
115              
116             sub logger
117             {
118 0     0 0   my $self = shift ;
119              
120 0           Perl::LanguageServer::logger (undef, @_) ;
121             }
122              
123             # ----------------------------------------------------------------------------
124              
125              
126             sub mkpath
127             {
128 0     0 0   my ($self, $dir) = @_ ;
129              
130 0           aio_stat ($dir) ;
131 0 0         if (! -d _)
132             {
133 0           $self -> mkpath (dirname($dir)) ;
134 0 0         aio_mkdir ($dir, 0755) and die "Cannot make $dir ($!)" ;
135             }
136             }
137              
138             # ---------------------------------------------------------------------------
139              
140             sub _build_state_dir
141             {
142 0     0     my ($self) = @_ ;
143              
144 0   0       my $root = $self -> config -> {rootUri} || 'file:///tmp' ;
145 0           my $rootpath = substr ($self -> uri_client2server ($root), 7) ;
146 0           $rootpath =~ s#^/(\w)%3A/#$1:/# ;
147 0           $rootpath .= '/.vscode/perl-lang' ;
148 0           print STDERR "state_dir = $rootpath\n" ;
149 0           $self -> mkpath ($rootpath) ;
150              
151 0           return $rootpath ;
152             }
153              
154             # ---------------------------------------------------------------------------
155              
156              
157             sub shutdown
158             {
159 0     0 0   my ($self) = @_ ;
160              
161 0           $self -> is_shutdown (1) ;
162             }
163              
164             # ---------------------------------------------------------------------------
165              
166             sub uri_server2client
167             {
168 0     0 0   my ($self, $uri) = @_ ;
169              
170 0           my $map = $self -> path_map ;
171 0 0         return $uri if (!$map) ;
172              
173             #print STDERR ">uri_server2client $uri\n", dump($map), "\n" ;
174 0           foreach my $m (@$map)
175             {
176 0 0         last if ($uri =~ s/$m->[0]/$m->[1]/) ;
177             }
178             #print STDERR "<uri_server2client $uri\n" ;
179              
180 0           return $uri ;
181             }
182              
183             # ---------------------------------------------------------------------------
184              
185             sub uri_client2server
186             {
187 0     0 0   my ($self, $uri) = @_ ;
188              
189 0           my $map = $self -> path_map ;
190 0 0         return $uri if (!$map) ;
191              
192             #print STDERR ">uri_client2server $uri\n" ;
193 0           foreach my $m (@$map)
194             {
195 0 0         last if ($uri =~ s/$m->[1]/$m->[0]/) ;
196             }
197             #print STDERR "<uri_client2server $uri\n" ;
198              
199 0           return $uri ;
200             }
201              
202             # ---------------------------------------------------------------------------
203              
204             sub file_server2client
205             {
206 0     0 0   my ($self, $fn) = @_ ;
207              
208 0           my $map = $self -> path_map ;
209 0 0         return $fn if (!$map) ;
210              
211 0           foreach my $m (@$map)
212             {
213             #print STDERR "file_server2client $m->[2] -> $m->[3] : $fn\n" ;
214 0 0         last if ($fn =~ s/$m->[2]/$m->[3]/) ;
215             }
216              
217 0           return $fn ;
218             }
219              
220             # ---------------------------------------------------------------------------
221              
222             sub file_client2server
223             {
224 0     0 0   my ($self, $fn) = @_ ;
225              
226 0           my $map = $self -> path_map ;
227 0 0         return $fn if (!$map) ;
228              
229 0           $fn =~ s/\\/\//g ;
230              
231 0           foreach my $m (@$map)
232             {
233             #print STDERR "file_client2server $m->[3] -> $m->[2] : $fn\n" ;
234 0 0         last if ($fn =~ s/$m->[3]/$m->[2]/) ;
235             }
236              
237 0           return $fn ;
238             }
239              
240             # ---------------------------------------------------------------------------
241              
242             sub add_path_mapping
243             {
244 0     0 0   my ($self, $fn_server, $fn_client) = @_ ;
245 0           my $map = $self -> path_map ;
246 0 0         $map = $self -> path_map ([]) if (!$map) ;
247              
248              
249 0           foreach my $m (@$map)
250             {
251             #print STDERR "add file_server2client $m->[2] -> $m->[3]\n" ;
252 0 0         return if ($fn_server eq $m->[2]) ;
253             }
254              
255 0           unshift @$map, ['file://' . $fn_server, 'file://' . $fn_client, $fn_server, $fn_client] ;
256 0           return ;
257             }
258              
259             # ---------------------------------------------------------------------------
260              
261             sub set_workspace_folders
262             {
263 0     0 0   my ($self, $workspace_folders) = @_ ;
264              
265 0           my $folders = $self -> folders ;
266 0           foreach my $ws (@$workspace_folders)
267             {
268 0           my $diruri = $self -> uri_client2server ($ws -> {uri}) ;
269              
270 0           my $dir = substr ($diruri, 7) ;
271 0           $dir =~ s#^/(\w)%3A/#$1:/# ;
272 0           $folders -> {$ws -> {uri}} = $dir ;
273             }
274             }
275              
276             # ---------------------------------------------------------------------------
277              
278             sub add_diagnostic_messages
279             {
280 0     0 0   my ($self, $server, $uri, $source, $messages, $version) = @_ ;
281              
282 0           my $files = $self -> files ;
283 0           $files -> {$uri}{messages}{$source} = $messages ;
284 0 0         $files -> {$uri}{messages_version} = $version if (defined ($version));
285              
286             # make sure all old messages associated with this uri are cleaned up
287 0 0         my %diags = ( map { $_ => [] } @{$files -> {$uri}{diags} || ['-'] } ) ;
  0            
  0            
288 0           foreach my $src (keys %{$files -> {$uri}{messages}})
  0            
289             {
290 0           my $msgs = $files -> {$uri}{messages}{$src} ;
291 0 0 0       if ($msgs && @$msgs)
292             {
293 0           my $line ;
294 0           my $lineno = 0 ;
295 0           my $filename ;
296 0           my $lastline = 1 ;
297 0           my $msg ;
298             my $severity ;
299 0           foreach $line (@$msgs)
300             {
301 0           ($filename, $lineno, $severity, $msg) = @$line ;
302 0 0         if ($lineno)
303             {
304 0 0         if ($msg)
305             {
306 0 0         my $diag =
307             {
308             # range: Range;
309             # severity?: DiagnosticSeverity;
310             # code?: number | string;
311             # codeDescription?: CodeDescription;
312             # source?: string;
313             # message: string;
314             # tags?: DiagnosticTag[];
315             # relatedInformation?: DiagnosticRelatedInformation[];
316             # data?: unknown;
317              
318             # DiagnosticSeverity
319             # const Error: 1 = 1;
320             # const Warning: 2 = 2;
321             # const Information: 3 = 3;
322             # const Hint: 4 = 4;
323              
324             # DiagnosticTag
325             # * Clients are allowed to render diagnostics with this tag faded out
326             # * instead of having an error squiggle.
327             # export const Unnecessary: 1 = 1;
328             # * Clients are allowed to rendered diagnostics with this tag strike through.
329             # export const Deprecated: 2 = 2;
330              
331             # DiagnosticRelatedInformation
332             # * Represents a related message and source code location for a diagnostic.
333             # * This should be used to point to code locations that cause or are related to
334             # * a diagnostics, e.g when duplicating a symbol in a scope.
335             #
336             # * The location of this related diagnostic information.
337             # location: Location;
338             # * The message of this related diagnostic information.
339             # message: string;
340              
341             range => { start => { line => $lineno-1, character => 0 }, end => { line => $lineno+0, character => 0 }},
342             ($severity?(severity => $severity + 0):()),
343             message => $msg,
344             source => $src,
345             } ;
346 0   0       $diags{$filename} ||= [] ;
347 0           push @{$diags{$filename}}, $diag ;
  0            
348             }
349 0           $lastline = $lineno ;
350 0           $lineno = 0 ;
351 0           $msg = '' ;
352             }
353             }
354             }
355             }
356 0           $files -> {$uri}{diags} = [keys %diags] ;
357              
358 0           foreach my $filename (keys %diags)
359             {
360 0           foreach my $filename (keys %diags)
361             {
362 0 0 0       my $fnuri = !$filename || $filename eq '-'?$uri:$self -> uri_server2client ('file://' . $filename) ;
363             my $result =
364             {
365             method => 'textDocument/publishDiagnostics',
366             params =>
367             {
368             uri => $fnuri,
369 0           diagnostics => $diags{$filename},
370             },
371             } ;
372              
373 0           $server -> send_notification ($result) ;
374             }
375             }
376             }
377              
378             # ---------------------------------------------------------------------------
379              
380              
381             1 ;
382