diff options
-rw-r--r-- | package.json | 4 | ||||
-rw-r--r-- | perlnavigator-0.2.4.vsix (renamed from perlnavigator-0.2.3.vsix) | bin | 1369917 -> 1372308 bytes | |||
-rw-r--r-- | server/src/completion.ts | 9 | ||||
-rw-r--r-- | server/src/hover.ts | 19 | ||||
-rw-r--r-- | server/src/parseDocument.ts | 5 | ||||
-rw-r--r-- | server/src/perl/Inquisitor.pm | 30 | ||||
-rw-r--r-- | server/src/perl/lib_bs22/pltags.pm | 18 | ||||
-rw-r--r-- | server/src/types.ts | 4 | ||||
-rw-r--r-- | testWorkspace/MyLib/ClassAccessor.pm | 17 | ||||
-rw-r--r-- | testWorkspace/MyLib/ClassTiny.pm | 11 | ||||
-rw-r--r-- | testWorkspace/MyLib/MyClass.pm | 2 | ||||
-rw-r--r-- | testWorkspace/MyLib/ObjectPad.pm | 18 | ||||
-rw-r--r-- | testWorkspace/MyLib/ObjectTiny.pm | 7 | ||||
-rw-r--r-- | testWorkspace/MySubClass.pm | 2 | ||||
-rw-r--r-- | testWorkspace/mainTest.pl | 32 |
15 files changed, 152 insertions, 26 deletions
diff --git a/package.json b/package.json index e5fc393..695f243 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Code navigation, autocompletion, syntax checking, and linting for Perl", "author": "bscan", "license": "MIT", - "version": "0.2.3", + "version": "0.2.4", "icon": "images/camel_icon.png", "repository": { "type": "git", @@ -25,7 +25,7 @@ "contributes": { "configuration": { "type": "object", - "title": "Perl Navigator configuration", + "title": "Perl Navigator", "properties": { "perlnavigator.perlPath": { "scope": "resource", diff --git a/perlnavigator-0.2.3.vsix b/perlnavigator-0.2.4.vsix Binary files differindex 3247552..ba1f2d6 100644 --- a/perlnavigator-0.2.3.vsix +++ b/perlnavigator-0.2.4.vsix diff --git a/server/src/completion.ts b/server/src/completion.ts index b7703cb..5596565 100644 --- a/server/src/completion.ts +++ b/server/src/completion.ts @@ -126,8 +126,8 @@ function getMatches(perlDoc: PerlDocument, symbol: string, replace: Range): Com let element = perlDoc.canonicalElems.get(elemName) || elements[0]; // Get the canonical (typed) element, otherwise just grab the first one. - // All plain and inherited subroutines should match with $self. We're excluding methods here because imports clutter the list, despite perl allowing them called on $self-> - if(bSelf && ["s", "i"].includes(element.type) ) elemName = `$self::${elemName}`; + // All plain and inherited subroutines should match with $self. We're excluding "t" here because imports clutter the list, despite perl allowing them called on $self-> + if(bSelf && ["s", "i", "o", "f"].includes(element.type) ) elemName = `$self::${elemName}`; if (goodMatch(perlDoc, elemName, qualifiedSymbol, bKnownObj)){ // Hooray, it's a match! @@ -139,7 +139,7 @@ function getMatches(perlDoc: PerlDocument, symbol: string, replace: Range): Com // Don't send invalid constructs if(/\-\>\w+::/.test(aligned) || // like FOO->BAR::BAZ - (/\-\>\w+$/.test(aligned) && !["s", "t", "i"].includes(element.type)) || // FOO->BAR if Bar is not a sub/method. + (/\-\>\w+$/.test(aligned) && !["s", "t", "i", "o", "f", "d"].includes(element.type)) || // FOO->BAR if Bar is not a sub/method. (/^\$.*::/.test(aligned)) // $Foo::Bar, I don't really hunt for these anyway ) return; @@ -162,6 +162,7 @@ function goodMatch(perlDoc: PerlDocument, elemName: string, qualifiedSymbol: str let modRg = /^(.+)::.*?$/; var match = modRg.exec(elemName); if(match && !perlDoc.imported.has(match[1])){ + // TODO: Allow completion on packages/class defined within the file itself (e.g. Foo->new, $foo->new already works) // Thing looks like a module, but was not explicitly imported return false; } else { @@ -208,7 +209,7 @@ function buildMatches(lookupName: string, elem: PerlElem, range: Range): Complet kind = CompletionItemKind.Reference; } else if (elem.type == PerlSymbolKind.Class){ // Loop labels kind = CompletionItemKind.Class; - } else if (elem.type == PerlSymbolKind.Field){ + } else if (elem.type == PerlSymbolKind.Field || elem.type == PerlSymbolKind.PathedField){ kind = CompletionItemKind.Field; } else if (elem.type == PerlSymbolKind.Phaser){ return []; diff --git a/server/src/hover.ts b/server/src/hover.ts index d556606..c5f9dc9 100644 --- a/server/src/hover.ts +++ b/server/src/hover.ts @@ -38,14 +38,16 @@ function buildHoverDoc(symbol: string, elem: PerlElem){ } else if (/^\$self/.test(symbol)) { desc += `${elem.package}`; } - } else if(elem.type == 'v'){ - // What should I show here? Nothing? Definition line? + } else if(elem.type == 'v'){ + // desc = `(variable) ${symbol}`; // Not very interesting info + } else if (elem.type == 'n'){ + desc = `(constant) ${symbol}`; } else if(elem.type == 'c'){ desc = `${elem.name}: ${elem.value}`; if(elem.package) desc += ` (${elem.package})` ; // Is this ever known? } else if(elem.type == 'h'){ desc = `${elem.name} (${elem.package})`; - } else if (elem.type == 's'){ + } else if (elem.type == 's' || elem.type == 'o'){ desc = `(subroutine) ${symbol}`; } else if (elem.type == 't' || elem.type == 'i'){ desc = `(subroutine) ${elem.name}`; @@ -54,9 +56,15 @@ function buildHoverDoc(symbol: string, elem: PerlElem){ desc = `(package) ${elem.name}`; } else if (elem.type == 'm'){ desc = `(module) ${elem.name}: ${elem.file}`; - } else if (elem.type == 'l'){ // Loop labels + } else if (elem.type == 'l'){ desc = `(label) ${symbol}`; - } else{ + } else if (elem.type == 'a'){ + desc = `(class) ${symbol}`; + } else if (elem.type == 'f' || elem.type == 'd'){ + desc = `(attribute) ${symbol}`; + } else if (elem.type == 'e'){ + desc = `(phase) ${symbol}`; + } else { // We should never get here desc = `Unknown: ${symbol}`; } @@ -64,4 +72,3 @@ function buildHoverDoc(symbol: string, elem: PerlElem){ return desc; } - diff --git a/server/src/parseDocument.ts b/server/src/parseDocument.ts index 24ccbb6..5c3dc57 100644 --- a/server/src/parseDocument.ts +++ b/server/src/parseDocument.ts @@ -68,6 +68,11 @@ function parseElem(perlTag: string, perlDoc: PerlDocument): void { perlDoc.canonicalElems.set(name, newElem); } + if (type == '1'){ + // This object is only intended as the canonicalLookup, not for anything else. + return; + } + addVal(perlDoc.elems, name, newElem); return; diff --git a/server/src/perl/Inquisitor.pm b/server/src/perl/Inquisitor.pm index 4dad35f..9e431f3 100644 --- a/server/src/perl/Inquisitor.pm +++ b/server/src/perl/Inquisitor.pm @@ -65,8 +65,8 @@ sub maybe_print_sub_info { my $meta = B::svref_2object($codeRef); $meta->isa('B::CV') or return 0; - my $file = $meta->START->isa('B::COP') ? $meta->START->file : $UNKNOWN; - my $line = $meta->START->isa('B::COP') ? $meta->START->line - 2: $UNKNOWN; + my ($file, $line, $subType) = resolve_file($meta, $subType); + my $pack = $UNKNOWN; my $subname = $UNKNOWN; $subname = SubUtilPP::subname($codeRef); @@ -86,6 +86,32 @@ sub maybe_print_sub_info { return 0; } +sub resolve_file { + my ($meta, $subType) = @_; + + my $file = ''; + my $line = ''; + + if ($meta->START->isa('B::COP')){ + $file = $meta->START->file; + $line = $meta->START->line - 2; + } elsif ($meta->GV->isa('B::GV')){ + if($meta->GV->FILE =~ /Class[\\\/](?:XS)?Accessor\.pm$/){ + # If something comes from XSAccessor or Accessor, it's an attribute (e.g. Moo, ClassAccessor), but we don't know where in the Moo class it's defined. + $subType = 'd'; + } + } + + # Moose (but not Moo) attributes return this for a file. + if ($file =~ /^accessor [\w:]+ \(defined at ([\w\\\/\.\s]+) line (\d+)\)$/){ + $file = $1; + $line = $2; + $subType = 'd'; + } + + return ($file, $line, $subType); +} + sub print_tag { # Dump details to STDOUT. Format depends on type my ($symbol, $type, $typeDetails, $file, $pack, $line, $value) = @_; diff --git a/server/src/perl/lib_bs22/pltags.pm b/server/src/perl/lib_bs22/pltags.pm index b08d158..16d8626 100644 --- a/server/src/perl/lib_bs22/pltags.pm +++ b/server/src/perl/lib_bs22/pltags.pm @@ -79,8 +79,6 @@ sub PackageEndLine { my $length; if ($extracted){ $length = $extracted =~ tr/\n//; # Count lines in sub definition - print "Found extracted wioth length $length\n"; - } my $count = 1; @@ -95,13 +93,10 @@ sub PackageEndLine { } if ($length){ - print "Found $length, but from where??\n"; # If we found a delimited package return $line_num + $length - $offset + 1; } else { # Run until end of package - print "Run forever\n"; - return $line_num + $#$paCode - $offset + 1; } } @@ -125,12 +120,16 @@ sub build_pltags { my $line = $code[$i]; + # Skip pod. Applied before stripping leading whitespace + next if ($line =~ /^=(?:pod|head|head1|head2|head3|head4|over|item|back|begin|end|for|encoding)/ .. $line =~ /^=cut/); + + if ($line =~ /#.*(\$\w+) isa ([\w:]+)\b/){ + MakeTag($1, $2, '1', $file, $line_number, $package_name, \@tags); + } + # Statement will be line with comments, whitespace and POD trimmed my $stmt; ($stmt = $line) =~ s/#.*//; - - # Skip pod. Applied before stripping leading whitespace - next if ($line =~ /^=(?:pod|head|head1|head2|head3|head4|over|item|back|begin|end|for|encoding)/ .. $line =~ /^=cut/); $stmt =~ s/^\s*//; $stmt =~ s/\s*$//; @@ -250,6 +249,9 @@ sub build_pltags { elsif ($stmt=~/^has(?:\s+|\()(?:["']|\$)?(\w+)\b/) { # Moo/Moose/Object::Pad/Moops/Corinna attributes MakeTag($1, "f", '', $file, $line_number, $package_name, \@tags); + # If you have a locally defined package/class Foo want to reference the attributes as Foo::attr or $foo->attr, you need the full path. + # Subs don't need this since we find them at compile time. We also find "d" types from imported packages in Inquisitor.pm + MakeTag("${package_name}::$1", "d", '', $file, $line_number, $package_name, \@tags); } elsif ($stmt=~/^around\s+["']?(\w+)\b/) { # Moo/Moose overriding subs. diff --git a/server/src/types.ts b/server/src/types.ts index fbefb23..dee2961 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -65,13 +65,15 @@ export enum PerlSymbolKind { ImportedSub = "t", Inherited = "i", Field = "f", + PathedField = "d", LocalSub = "s", LocalMethod = "o", LocalVar = "v", Constant = "n", Label = "l", Phaser = "e", - UseStatement = "u", + Canonical = "1", + // UseStatement = "u" . Reserved: used in pltags, but removed before symbol assignment. ImportedVar = "c", ImportedHash = "h", } diff --git a/testWorkspace/MyLib/ClassAccessor.pm b/testWorkspace/MyLib/ClassAccessor.pm new file mode 100644 index 0000000..95f1bc8 --- /dev/null +++ b/testWorkspace/MyLib/ClassAccessor.pm @@ -0,0 +1,17 @@ +package MyLib::ClassAccessor; + ## no critic (strict) +use base qw(Class::Accessor); +MyLib::ClassAccessor->follow_best_practice; +MyLib::ClassAccessor->mk_accessors(qw(name role salary)); + +# or if you prefer a Moose-like interface... + + +package MyLib::ClassAccessorAntlers; +use Class::Accessor "antlers"; +has name => ( is => "rw", isa => "Str" ); +has role => ( is => "rw", isa => "Str" ); +has salary => ( is => "rw", isa => "Num" ); + + +1;
\ No newline at end of file diff --git a/testWorkspace/MyLib/ClassTiny.pm b/testWorkspace/MyLib/ClassTiny.pm new file mode 100644 index 0000000..f25ab50 --- /dev/null +++ b/testWorkspace/MyLib/ClassTiny.pm @@ -0,0 +1,11 @@ +package MyLib::ClassTiny; +use strict; +use warnings; + +use Class::Tiny qw( ssn ), { + timestamp => sub { time } # attribute with default +}; + +1; + +1;
\ No newline at end of file diff --git a/testWorkspace/MyLib/MyClass.pm b/testWorkspace/MyLib/MyClass.pm index 920422b..810751d 100644 --- a/testWorkspace/MyLib/MyClass.pm +++ b/testWorkspace/MyLib/MyClass.pm @@ -11,7 +11,7 @@ sub new { sub overridden_method { my $self = shift; - print "In orverridden_method from MyClass\n"; + print "In overridden_method from MyClass\n"; } sub inherited_method { diff --git a/testWorkspace/MyLib/ObjectPad.pm b/testWorkspace/MyLib/ObjectPad.pm new file mode 100644 index 0000000..dbdbf5c --- /dev/null +++ b/testWorkspace/MyLib/ObjectPad.pm @@ -0,0 +1,18 @@ +use v5.26; +use Object::Pad; +package ObjectPad; +class ObjectPad; + +has $x :param = 0; +has $y :param = 0; + +method move ($dX, $dY) { + $x += $dX; + $y += $dY; +} + +method describe () { + print "A point at ($x, $y)\n"; +} + +1; diff --git a/testWorkspace/MyLib/ObjectTiny.pm b/testWorkspace/MyLib/ObjectTiny.pm new file mode 100644 index 0000000..cb81d12 --- /dev/null +++ b/testWorkspace/MyLib/ObjectTiny.pm @@ -0,0 +1,7 @@ +package MyLib::ObjectTiny; +use strict; +use warnings; + +use Object::Tiny qw{ bar baz }; + +1;
\ No newline at end of file diff --git a/testWorkspace/MySubClass.pm b/testWorkspace/MySubClass.pm index e677ebe..7f60c4b 100644 --- a/testWorkspace/MySubClass.pm +++ b/testWorkspace/MySubClass.pm @@ -18,7 +18,7 @@ sub new { sub overridden_method { my $self = shift; - print "In orverridden_method from MySubClass\n"; + print "In overridden_method from MySubClass\n"; } diff --git a/testWorkspace/mainTest.pl b/testWorkspace/mainTest.pl index dc70d8d..969bda1 100644 --- a/testWorkspace/mainTest.pl +++ b/testWorkspace/mainTest.pl @@ -18,6 +18,11 @@ use MyLib::NonPackage; use MyLib::MooseClass; use MyLib::MooClass; use MyLib::DBI; +use MyLib::ObjectPad; +use MyLib::ClassAccessor; +use MyLib::ClassTiny; +use MyLib::ObjectTiny; + use MySubClass; use constant MYCONSTANT => 6; @@ -106,7 +111,7 @@ my $otherObj = MyLib::MyOtherClass->new(); $otherObj->unique_method_name(); $otherObj->duplicate_method_name(); -my $unknownObj = $otherObj; +my $unknownObj = $otherObj; # Type hints: $unknownObj isa MyLib::MyOtherClass $unknownObj->duplicate_method_name(); my $mooObj = MyLib::MooClass->new(); @@ -115,6 +120,7 @@ print $mooObj->moo_attrib . "\n"; my $mooseObj = MyLib::MooseClass->new(); $mooseObj->moose_sub(); +$mooseObj->moose_attrib; # Better hover than the moo_attrib my $nonObject = MyLib::MooseClass->new()->moose_sub(); @@ -122,6 +128,19 @@ my $hiddenPackObj = MyLib::SubPackage->new(); my $dbh2 = MyLib::DBI->connect(); +my $padObj = ObjectPad->new(x => 5, y => 10); +$padObj->describe(); + +my $caObj = MyLib::ClassAccessor->new(); +my $caaObj = MyLib::ClassAccessorAntlers->new(); + +my $ctObj = MyLib::ClassTiny->new(); + +my $otObj = MyLib::ObjectTiny->new(); + +use attributes (); +print "ObjectPad attributes: " . attributes::get(\&ObjectPad::describe) . "\n"; + print "\nDone with test script\n"; package SameFilePackage; ## no critic (package) @@ -129,3 +148,14 @@ package SameFilePackage; ## no critic (package) sub same_file_package_sub { print "In same_file_package_sub\n"; } + + +package Foo { + use Moo; + has generic_attrib => (is => 'ro'); + + sub baz { + my $self = shift; + } +} + |