summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package.json4
-rw-r--r--perlnavigator-0.2.4.vsix (renamed from perlnavigator-0.2.3.vsix)bin1369917 -> 1372308 bytes
-rw-r--r--server/src/completion.ts9
-rw-r--r--server/src/hover.ts19
-rw-r--r--server/src/parseDocument.ts5
-rw-r--r--server/src/perl/Inquisitor.pm30
-rw-r--r--server/src/perl/lib_bs22/pltags.pm18
-rw-r--r--server/src/types.ts4
-rw-r--r--testWorkspace/MyLib/ClassAccessor.pm17
-rw-r--r--testWorkspace/MyLib/ClassTiny.pm11
-rw-r--r--testWorkspace/MyLib/MyClass.pm2
-rw-r--r--testWorkspace/MyLib/ObjectPad.pm18
-rw-r--r--testWorkspace/MyLib/ObjectTiny.pm7
-rw-r--r--testWorkspace/MySubClass.pm2
-rw-r--r--testWorkspace/mainTest.pl32
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
index 3247552..ba1f2d6 100644
--- a/perlnavigator-0.2.3.vsix
+++ b/perlnavigator-0.2.4.vsix
Binary files differ
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;
+ }
+}
+