Giter Site home page Giter Site logo

perlnavigator's Introduction

Perl Navigator Language Server

Provides syntax checking, autocompletion, perlcritic, code navigation, hover for Perl.

Implemented as a Language Server using the Microsoft LSP libraries along with Perl doing the syntax checking and parsing.

Works on Windows, MacOS, and Linux. The vscode extension includes everything needed to work, no additional installation should be necessary. Works on almost any version of Perl, tested all the way back to Perl 5.8. Has full support for multi-root workspaces, single file editing, and multiple open windows.

Install the vscode extension from here: https://marketplace.visualstudio.com/items?itemName=bscan.perlnavigator

Currently Implemented Features:

  • Syntax Checking
  • Perl Critic static code analysis/suggestions
  • Documentation on hover and autocomplete
  • Subroutine signatures
  • Code Navigation ("Go To Definition") anywhere, including to installed modules and compile-time dependencies
  • Code formatting via Perl::Tidy
  • Imports cleanup via perlimports
  • Outline view
  • Smart context-aware autocompletion and navigation
  • Hover for more details about objects, subs, and modules
  • Syntax highlighting for Object::Pad, Moose, Zydeco, Dancer2, etc.
  • Support for Classes including Moo/Moose style classes

Visual Studio Code Demo

gif of Navigator in vscode

Vscode Installation

Install the VSCode extension and it should just work. All required dependencies are bundled with the extension. Please file a bug report if the Perl Navigator does not work out of the box. Perl::Critic and perlimports are not currently bundled and need to be installed independently, but the remaining features (e.g. navigation, autocomplete, syntax check) do not require it.

Perl paths

If you have a nonstandard install of Perl, please set the setting perlnavigator.perlPath. The subfolder ./lib will be added to your path automatically. You can also add additional include paths that will be added to the perl search path (@INC) via perlnavigator.includePaths. You can use $workspaceFolder in includePaths which will be replaced by the full folder path. If you have a multi-root workspace, each folder will be added to the path.

Perl Critic Customization

You should specify a Perl::Critic profile via perlnavigator.perlcriticProfile. You can use $workspaceFolder as a place holder here. If perlcriticProfile is not set, it will check for ~./perlcriticrc. If that also does not exist, a default profile will be used. This default profile is not very strict. The default severities are reasonable, (primarily used for coloring the squiggly underlines) but you can change perlnavigator.severity1 through severity5. Allowable options are error, warning, info, and hint.

Perl Tidy Customization

It is recommended to set perlnavigator.perltidyProfile if you would like customized formatting. Otherwise, the default settings will be used. I might create a default profile at some point.

Perlimports Customization

Perlimports offers additional diagnostics when imports can be cleaned up. When perlimports is enabled, "Format Document" and "Format Selection" will run perlimports in addition to perltidy. By default, perlimports is not enabled, but the diagnostics (linting) can be enabled with perlimportsLintEnabled, and the tidying can be enabled with perlimportsTidyEnabled. Perlimports can be customized with a profile using the perlnavigator.perlimportsProfile. Due to implementation limitations, perlimports requires a saved version of the file you are working on. If any results are unexpected, save the working file and try again.

Installation For Other Editors

Using NPM

The easiest way to install is using npm

sudo npm install -g perlnavigator-server

Which will install as /usr/bin/perlnavigator. This can be used as the command for most editors without any other arguments (i.e. --stdio can be omitted)

Using the binaries

Alternatively you can download binary releases for Windows, Linux, and MacOS here: https://github.com/bscan/PerlNavigator/releases

Building from source

You can also build from source if you prefer.

git clone https://github.com/bscan/PerlNavigator
cd PerlNavigator/
npm run ci-all
cd server/
npx tsc

Sublime Text

Sublime Text requires the following minimum settings under LSP settings (modify depending on your install location and editor)

{
    "clients": {
        "perlnavigator": {
            "enabled": true,
            "command": ["node", "C:\\temp\\PerlNavigator\\server\\out\\server.js","--stdio"],
            "selector": "source.perl",
        },
    }
}

gif of Navigator in sublime

Emacs

You can use perl navigator with either lsp-mode or eglot. Eglot is built-in starting with emacs version 29.

Emacs eglot

The following is a sample configuration file to use the navigator with emacs and a custom perl location. This config uses company-mode, but is not required.

 (setq-default eglot-workspace-configuration
                '((:perlnavigator . (:perlPath
                              "/path/to/perl"
                              :enableWarnings t))))

(with-eval-after-load 'eglot
  (add-to-list 'eglot-server-programs
               `((cperl-mode perl-mode) . ("/path/to/perlnavigator", "--stdio"))))

(global-company-mode)

(add-hook 'cperl-mode-hook 'eglot-ensure)
(add-hook 'perl-mode-hook 'eglot-ensure)

Emacs lsp-mode

You can also use lsp-mode with emacs if you prefer. No special configuration is required for lsp-mode. Perlnavigator is the default Perl language server in lsp-mode. If you have perlnavigator on your path (e,g. because you did sudo npm install -g perlnavigator-server or downloaded an executable from the latest releases), lsp-mode will find the executable automatically.

If you need to configure can use something similar to the following configuration. Additional details here

(use-package lsp-mode
  ...
  :custom (lsp-perlnavigator-executable (expand-file-name "~/path/to/perlnavigator))
  ...)

Neovim

Neovim requires nvim-lspconfig. An optional, but highly recommended, set of plugins is mason and mason-lspconfig which you can use to automatically install Perl Navigator.

The simplest configuration is the following:

require'lspconfig'.perlnavigator.setup{}

A configuration with a number of options set looks like:

require'lspconfig'.perlnavigator.setup{
    settings = {
      perlnavigator = {
          perlPath = 'perl',
          enableWarnings = true,
          perltidyProfile = '',
          perlcriticProfile = '',
          perlcriticEnabled = true,
      }
    }
}

coc.nvim

The configuration can be added directly to coc-settings (:CocConfig) like the following:

{
  "languageserver": {
    "perlnavigator": {
      "command": "node",
      "args": [
        "/path/to/PerlNavigator/server/out/server.js",
        "--stdio"
      ],
      "filetypes": ["perl"]
    }
  }
}

Or the coc-perl client extension can be used, simplifying overall configuration. A simple configuration to enable PerlNavigator, after installing coc-perl (:CocInstall coc-perl), looks like:

{
  "perl.navigator.enable": true,
  "perl.navigator.serverPath": "/path/to/PerlNavigator/server/out/server.js"
}

Kate

For the Kate editor, you'll need to Configure Kate -> LSP Client and add a config to the User Server Settings. The following is an example config (this example uses the release binaries).

{
  "servers":{
    "perl": {
      "command": ["d:\\Applications\\perlnavigator.exe", "--stdio"],
      "url": "https://github.com/bscan/PerlNavigator",
      "highlightingModeRegex": "^Perl$",
      "settings": {
        "perlnavigator": {
          "perlPath": "perl",
        }
      }
    }
  }
}

LiteXL

For the LiteXL editor, you need to download the LSP plugin first. Then in your init.lua file, add something similar to the following.

local lsp = require "plugins.lsp"

lsp.add_server {
  name = "perlnavigator",
  language = "Perl",
  file_patterns = { "%.pl$", "%.pm$" },
  command = { "perlnavigator" },
  settings = {
    perlnavigator = {
      -- The following setting is only needed if you want to set a custom perl path. It already defaults to "perl"
      perlPath = "perl"
    }
  }
}

Raku / Other Projects

For those interested in a Raku language server, check out: https://github.com/bscan/RakuNavigator

Licenses / Acknowledgments

The Perl Navigator is free software licensed under the MIT License. It has a number of bundled dependencies as well, all of which have their respective open source licenses included. This work is only possible due to Class::Inspector, Devel::Symdump, Perl::Critic, PPI, Perl::Tidy, perlimports, Sub::Util, Perl itself, Microsoft LSP libraries, and ideas from Perl::LanguageServer and PLS.

perlnavigator's People

Contributors

andrew-grechkin avatar bmeneg avatar bscan avatar evancarroll avatar iakobvs avatar jbob avatar ketbra avatar krzysckh avatar mark-5 avatar marlencrabapple avatar masterbirdy avatar nreilingh avatar oalders avatar oetiker avatar oschwald avatar rovertzxd avatar ulizama avatar whoissethdaniel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

perlnavigator's Issues

"Go to definition" on a subroutine fails for subs in different packages and lexical subs

The function "Go to Definition" fails to identify the correct definition if a subroutine with the same name is present in another package in the same file, or if the subroutine is a lexical sub.

Here's a demo code:

use strict;
package main;

sub show { print "main::show\n"; }

package Private {
    my sub show { print "lexical sub show in package Private\n"; }

    sub barf { 
        # This calls the lexical subroutine in package Private
        show(@_) # but find definition -> main::show
    }
}

package Inner {
    sub show {  print "Inner::show\n" }
}

# This calls main::show
show; # but find definition -> Inner::show

This code has three subroutines called show: "public" subroutines in packages main and Inner, and a lexical subroutine in package Private. When I invoke "Go to Definition" from the places where show is called, it does not select the correct one.

It seems that lexical subroutines are not found at all, and the namespace is ignored for public subroutines.

Make Autocomplete Case Insensitive

Currently, auto-complete appears to be case-insensitive, but it is not. This is because the vscode selector is case insensitive, but when it reloads the completion results, the navigator is case-sensitive. This causes confusing behaviors where the autocomplete will get lost. Let's move autocompletion toward entirely case-insensitive. I suspect this ticket is trickier than it sounds due to the autocompletion on arbitrary recognized objects.

CaseSensitive

Perlcritic failed with unknown error

I've just been messing around trying to get perlimports to work, but I'm struggling to get the extension up and running. My perl is managed via plenv. Here's the output I'm getting for perlcritic as well as the compilation check:

https://gist.github.com/oalders/fae520a36ea6cd197a31dbab226bb8f4

settings.json:

    "perlnavigator.includePaths": [
        "/Users/olaf/.plenv/versions/5.36.0/lib/perl5/site_perl/5.36.0/",
        "/Users/olaf/.plenv/versions/5.36.0/lib/perl5/5.36.0/",
    ],
    "perlnavigator.perlPath": "/Users/olaf/.plenv/versions/5.36.0/bin/perl",
    "perlnavigator.trace.server": "verbose",
    "perlnavigator.perlcriticProfile": "/Users/olaf/.perlcriticrc",
    "perlnavigator.perltidyProfile": "/Users/olaf/.perltidyrc",
    "perlnavigator.severity1": "error",
    "perlnavigator.severity2": "error",
    "perlnavigator.severity3": "error",
    "perlnavigator.severity4": "error",
    "perlnavigator.severity5": "error",

I'm not seeing any kind of output even for compilation errors. If I run this command in my terminal (inside and outside of VSCode) it works:

/Users/olaf/.plenv/versions/5.36.0/bin/perl -c -Mwarnings -M-warnings=redefine -I \
/Users/olaf/.plenv/versions/5.36.0/lib/perl5/site_perl/5.36.0/ -I \
/Users/olaf/.plenv/versions/5.36.0/lib/perl5/5.36.0/ -I \
/Users/olaf/.vscode/extensions/bscan.perlnavigator-0.3.0/server/src/perl -MInquisitor \
/Users/olaf/Documents/perl-scratch/foo.pl

Notable, it displays the compilation error in the terminal which I was expecting to see in VSCode.

Can't locate Carpzzzzz.pm in @INC (you may need to install the Carpzzzzz module) (@INC contains: /Users/olaf/.plenv/versions/5.36.0/lib/perl5/site_perl/5.36.0//darwin-2level /Users/olaf/.plenv/versions/5.36.0/lib/perl5/site_perl/5.36.0/ /Users/olaf/.plenv/versions/5.36.0/lib/perl5/5.36.0//darwin-2level /Users/olaf/.plenv/versions/5.36.0/lib/perl5/5.36.0/ /Users/olaf/.vscode/extensions/bscan.perlnavigator-0.3.0/server/src/perl /Users/olaf/.plenv/versions/5.36.0/lib/perl5/site_perl/5.36.0/darwin-2level /Users/olaf/.plenv/versions/5.36.0/lib/perl5/site_perl/5.36.0 /Users/olaf/.plenv/versions/5.36.0/lib/perl5/5.36.0/darwin-2level /Users/olaf/.plenv/versions/5.36.0/lib/perl5/5.36.0) at /Users/olaf/Documents/perl-scratch/foo.pl line 5.
BEGIN failed--compilation aborted at /Users/olaf/Documents/perl-scratch/foo.pl line 5.

Any tips would be appreciated!

Add Support for the Testing API

Add support for the vscode testing API. This would allow for auto-discovering and running t/*.t tests tests directly in vscode. Open to design decisions, but I suspect we should run them via https://perldoc.perl.org/TAP::Harness as it is a core module and we can leverage the perl interpreter setting (as opposed to requiring a user to specify a location for the prove binary).

This is what the API looks like for an example set of tests in Python.

https://code.visualstudio.com/api/extension-guides/testing
image

Support documentSymbols

When trying to use perlnavigator with nvim-navic I got the following warning:

nvim-navic: Server "perlnavigator" does not support documentSymbols, it responds with SymbolInformation format which has been deprecated in latest LSP specification.

It'll be very nice supporting this format to use nvim-navic with the upcoming winbar feature of neovim.

Ease support of remote environments

First of all, I totally admire the the work done in this project. This is the 3rd VS Code extension I'm trying today and so far seems quite promising, however, I need to give more context.

I'm currently trying to being using code-server in my development routine, since I was long yearning for a nice in-browser IDE that can be deployed on my in-office PC. The nature of my development environment happens to be that the code in the current workspace/project gets deployed onto remote machine(available via SSH) that contains all of the necessary dependencies, required for it to be successfully executed. Keeping the dependencies or trying to run them locally in a container is 99% unfeasible due to the architecture.

I however would fancy very much to have auto-completion and insight into all of the available code(the project and its 3rd party dependencies) on the office PC I run code-server from.

Due to glorious licensing issues, only VS Code currently has Remote Extensions support, so I can't utilize that for your extension.

I saw the discussion in #33 regarding executing Perl in Docker and I tried to do the same with SSH but failed since Perl scripts that make bulk of the actual work are hidden as assets of this add-on and path to them can't be mangled with via the configuration.

Thus, I propose those few following steps to improve the situation:

  • Isolate Perl code so that it can be built/delivered separately if required
  • Ensure that LSP Server code depends on Perl code only by execution and not by sharing files(this translates harder via stuff such as SSH)
  • Allow parametrize the path to the Perl code, instead of hard-coded path to the assets
  • Publish actual version of the extension to https://open-vsx.org/extension/bscan/perlnavigator so that other projects based off VS Code can have easier time accessing it

I assume that after this hopefully simple clean up, it would barely matter whether the environment is a container, a remote machine or something else, as long as execution of Perl code can be delegated there.

So far I've tried https://github.com/richterger/Perl-LanguageServer which has somewhat poor auto-completion and https://github.com/FractalBoy/perl-language-server which unexpectedly ceases to function over SSH, possibly because an issue similar to FractalBoy/perl-language-server#103 or not. So my hopes for "the third time is a charm" case are quite high =)

Object recognition, Autocomplete, and subroutine navigation not working

Hi bscan! Thanks for your hard work! We are looking for a perl language server to run on our remote servers at my work. We use carton to manage our perl imports and the settings we use are like so:

perlnavigator.perlPath: "<output of `carton exec -- which perl` here>",
perlnavigator.includePaths: [
    "$workspaceFolder/t/lib"
    // "$workspaceFolder/lib" imported by default
],

For whatever reason every module we use is identified on mouseover and navigable given everything in our carton exec -- perl -V's @INC and what is added manually above. Unfortunately no subroutines have mouse over identification or navigability and we cannot seem to get object recognition or autocomplete working. We use Moose heavily. Our repo is quite large. Please let me know if I can provide additional information.

package for npm

Is there any chance to package this up for whatever repository npm uses? I was looking at the other typescript servers that nvim-lspconfig and nvim-lsp-installer supports and all of them require just npm install <something>. Typically the <something> would be, say, perl-navigator-server or something like that.

Any chance of this? If not I'm sure it can be worked around, but will make it more difficult, I think.

How to add unit tests for criticWrapperl.pl ?

I am testing a regex criticWrapper.pl to fix #63, similar to what is done in adjustForKeywords():

$sSource = adjustForKeywords($sSource);

I would like to test this regex with different input files (the ones that are given to criticWrapper.pl on STDIN). My first thought was to use unit tests with e.g. Test::More. Where to put these tests? And how/when are they run? I can see one unit test is already present here:

https://github.com/bscan/PerlNavigator/blob/main/t/01_MyClass.t

Neovim docs in README

There should be a quick section about Neovim in the README, along with the sublime, vscode, etc... docs.

I can do this, but wanted to make sure you were aware.

FWIW, I've submitted a basic lspconfig configuration: neovim/nvim-lspconfig#1756
And I've submitted an installer for nvim-lsp-installer: williamboman/nvim-lsp-installer#522

I would recommend that people use the installer as, IMO, it makes everything a little bit easier. The installer takes advantage of the npm package you published awhile back. So remember to publish npm packages whenever you make changes.
Once the above PRs are merged I can write a section for the README that details all this.

Display a files path relative to scope of file in error message

When perlnavigator receives an error from (I assume) perlcritic, the entire absolute path to the file in question is displayed in the error. This is a bit unwieldy and at times can actually be useless (if the path is long enough to be obscured from the window).
Neovim
vscode

Other LSPs dont display the name of the current file in the error (likely as its assumed)
Example of PerlPLS
Neovim

Consider removing the current file's name from displayed error messages?

textDocument/definition not working for shared package variables

test.pm:

package perl_test;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw($SHARED_VAR shared_subroutine);
our $SHARED_VAR="BLAH";
sub shared_subroutine
{
  print "Shared routine\n";
}

test.pl:

use lib "./";
use test qw( shared_subroutine $SHARED_VAR );
&test::shared_subroutine();
test::shared_subroutine();
shared_subroutine();
print "$test::SHARED_VAR\n";
print "${test::SHARED_VAR}\n";
print "$SHARED_VAR\n" if $SHARED_VAR and ${SHARED_VAR};

textDocument/definition does not work on any of the above 5 instances of SHARED_VAR, but it does work for shared_routine...

Perl::Critic not working "out of the box"

First off, congratulations on a great extension. I'm running Strawberry perl 5.32.1 and VSCode 1.64.2 on Windows 10. I installed perlNavigator and disabled Perl Toolbox and perl-outline. Navigation, syntax checking, autocomplete and outline work as expected, but Perl::Critic doesn't flag any complaints. When I disable perlNavigator and re-enable Perl Toolbox, Perl::Critic flags as expected. Can you suggest what to check? Where do I find the LSP log?

Neovim configuration problem with includePaths

In my Neovim configuration I have the following variable which gets consumed by Mason:

local servers = {
  -- clangd = {},
  -- gopls = {},
  -- pyright = {},
  -- rust_analyzer = {},
  -- tsserver = {},

  sumneko_lua = {
    Lua = {
      diagnostics = { globals = { "vim" } },
      runtime = { version = "LuaJIT" },
      workspace = {
        checkThirdParty = false,
        library = vim.api.nvim_get_runtime_file("", true),
      },
      telemetry = { enable = false },
    },
  },
  perlnavigator = {
    includePaths = {
      "$workspaceFolder/www/perllib"
    }
  }
}

The problem is that I cannot seem to get perlnavigator to consume the includePaths array. Am I mislabeling something? As a stop-gap measure I have added a symlink in my workspaceFolder to the appropriate perllib directory, which is named "lib" as that's what seems to be available in the @inc when the diagnostics complain about not being able to find something: https://github.com/bscan/PerlNavigator/blob/main/server/src/utils.ts#L17 (this function does not seem to work properly for Neovim) and https://github.com/bscan/PerlNavigator/blob/main/server/src/utils.ts#L40 (sets the default that I'm seeing).

My Y problem could be described as: I want go to definition to work in Neovim for this old legacy project as it does in other IDEs / in other languages / in other projects.

Any assistance would be appreciated - sorry if this is not initially enough information to go on.

Correctly Parse Subroutines Following Fat Commas

When a user clicks or hovers on a word, the language server needs to parse out the relevant symbol underneath the cursor. There's a bug when a subroutine name is preceded by =>. The language server is picking this up as part of the symbol. The following code reproduces this issue and "world" returns no results for hover or go-to definition. The function getSymbol in utils.ts needs to be fixed.

sub world {
    return "world";
}

my $foo = {"Hello"=>world};

navigator fails to find modules in lib/perl5/x86_64-linux/

I have the Mouse.pm and Imager.pm modules installed via local::lib which installs in local_lib/lib/perl5/x86_64-linux/

The navigator reports any modules in x86_64-linux as unknown and needing to be installed.

Configuration is:

    "perlnavigator.perlPath": "/opt/perlbrew/perls/perl-5.34.0/bin/perl",
    "perlnavigator.includePaths": [
        "$workspaceFolder/local_lib",
        "$workspaceFolder/code",
    ],
    "perlnavigator.perltidyProfile": "/home/dev/.perltidyrc",
    "perlnavigator.perlcriticEnabled": false,
    "perlnavigator.includeLib": false,
    "perlnavigator.enableWarnings": false,

Document use $workspaceFolder in includePaths

In the "perlnavigator.includePaths" setting, it would be useful to support one or more variables so that you can specify relative paths. This would be useful if you have multiple projects with the same structure, so you don't have to copy-paste-modify a bunch of absolute paths into the Workspace Settings. For example, any of these variables: https://code.visualstudio.com/docs/editor/variables-reference or a custom variable (PLS uses $ROOT_PATH in that extension).

Alternatively, follow the Perl Language Server (PLS) extension example and include a separate setting for the cwd. This is less flexible but could work.

Provide Error Message on Settings Configuration

When a user enters a settings.perlPath, the Navigator should validate that the file exists and is a valid perl executable. If not, pop-up a nice error message to the user with the path attempted and suggested fix. See the following for references:

https://github.com/rust-lang/rust-analyzer/blob/7d1015b8d177a02dff03d2c70bc74e5d4ed34335/editors/code/src/main.ts#L19-L26

microsoft/vscode-languageserver-node@980bf45

Ensure this is designed in a way to support other error messages. For example, if Perl::Critic or Perl::Tidy are not installed, or if they throw errors such as invalid critic/tidy configuration settings, or if they fail for any reason (e.g. encodings).

Attempted to run perlimports lint: Error: Command failed

Hey. Get this error often. Sometimes disabling and reenabling the extension fixes it, sometimes it doesn't.

Attempted to run perlimports lint: Error: Command failed: perl /home/blingenau/.vscode-server/extensions/bscan.perlnavigator-0.3.1/server/src/perl/perlimportsWrapper.pl --lint --json --filename <path_to_file>

Add $workspaceFolder variable expansion to perltidyProfile setting

It would be helpful to be able to use the $workspaceFolder variable in perlnavigator.perltidyProfile similarly to how perlnavigator.includePaths currently works.

There was an attempt to do this with a commented version of the getTidyProfile() function the end of formatting.ts, but it seems to have been put on hold due to difficulty dealing with multi-root workspaces. Is it possible to enable this for only single-root workspaces and add an error log and/or documentation that it will not work for multi-root workspaces as a short-term work around?

function getTidyProfile (settings: NavigatorSettings): string[] {
let profileCmd: string[] = [];
if (settings.perltidyProfile) {
let profile = settings.perltidyProfile;
profileCmd.push('--profile');
profileCmd.push(profile);
}
return profileCmd;
}
// Deal with the $workspaceFolder functionality later:
// function getTidyProfile (workspaceFolders: WorkspaceFolder[] | null, settings: NavigatorSettings): string[] {
// let profileCmd: string[] = [];
// if (settings.perltidyProfile) {
// let profile = settings.perltidyProfile;
// if (/\$workspaceFolder/.test(profile)){
// if (workspaceFolders){
// // TODO: Fix this. Only uses the first workspace folder
// const workspaceUri = Uri.parse(workspaceFolders[0].uri).fsPath;
// profileCmd.push('--profile');
// profileCmd.push(profile.replace(/\$workspaceFolder/g, workspaceUri));
// } else {
// nLog("You specified $workspaceFolder in your perltidy path, but didn't include any workspace folders. Ignoring profile.", settings);
// }
// } else {
// profileCmd.push('--profile');
// profileCmd.push(profile);
// }
// }
// return profileCmd;
// }

Automatically detect additional workspace

I have a monorepo setup, where I have some code in the root of my repo, and other code in subdirectories.

RIght now, perlnavigator is only picking up that the root of my repo is the workspaceFolder, but not in my subdirectories. The subdir is just like any other standard perl dir, with lib/, t/, bin/ and the like. It even has a dist.ini.

Is there a way to automatically get perlnavigator to pick this up?

Resolve Circular Dependency Errors

When a circular dependency exists, the Navigator will throw "subroutine redefined" errors despite this not be an issue for Perl itself. This is due to the use of perl -c Foo.pm. I like the solution from Padre shown below:
https://github.com/PadreIDE/Padre/blob/master/lib/Padre/Document/Perl/Syntax.pm#L56

The idea is to first parse the Perl module manually to find the package name, and add this to the %INC. This could either be done in the Inquisitor.pm, or in getAdjustedPerlCode() in diagnostics.ts.

In addition to solving redefined errors, it will also fix the problem where a locally modified and unsaved module is being analyzed, and a circular dependency results in the saved version being loaded. This causes confusing issues on symbol exports and syntax checks.

image

Crashes when used with Emacs lsp-mode

Versions:

node - 17.3.0
tsc - 4.5.5
emacs - 27.2
perl - 5.34.0

The configuration for enabling the new lsp server was taken from your comment on reddit (https://www.reddit.com/r/perl/comments/suamcf/comment/hxg3evr/?utm_source=share&utm_medium=web2x&context=3)

Emacs config:

(use-package cperl-mode
  :ensure t
  :init (defalias 'perl-mode 'cperl-mode)
  :config
  (setq cperl-highlight-variables-indiscriminately t
	cperl-indent-level 4
        cperl-tab-always-indent nil
        cperl-continued-statement-offset 0
        cperl-indent-parens-as-block t
        cperl-close-paren-offset -4
        cperl-electric-keywords t
        cperl-label-offset 0)
  (lsp-register-client
   (make-lsp-client :new-connection (lsp-stdio-connection '("node" "/home/kiky/work/PerlNavigator/server/out/server.js" "--stdio"))
		    :major-modes '(cperl-mode perl-mode)
		    :priority 10
		    :server-id 'perl-ls))
  :hook
  (cperl-mode . lsp)
  (cperl-mode . (lambda () (add-hook 'before-save-hook 'perltidy-buffer))))

lsp-log:

Command "perl -MPerl::LanguageServer -e Perl::LanguageServer::run -- --port 13603 --version 2.1.0" is present on the path.
Command "node /home/kiky/work/PerlNavigator/server/out/server.js --stdio" is present on the path.
Found the following clients for /home/kiky/work/perl/sendmail.pl: (server-id perl-language-server, priority -1), (server-id perl-ls, priority 10)
The following clients were selected based on priority: (server-id perl-ls, priority 10)

perl-ls::stderr:

/home/kiky/work/PerlNavigator/server/out/utils.js:11
    settings.includePaths.forEach(path => {
                          ^

TypeError: Cannot read properties of undefined (reading 'forEach')
    at getIncPaths (/home/kiky/work/PerlNavigator/server/out/utils.js:11:27)
    at perlcompile (/home/kiky/work/PerlNavigator/server/out/diagnostics.js:15:60)
    at validatePerlDocument (/home/kiky/work/PerlNavigator/server/out/server.js:155:52)

Crashes when used with neovim LSP

Thanks for your work on this project thus far. I'm trying to get it going in neovim and have reached the limits of my knowledge here, so maybe you can help me out.

I can't quite work out what the issue is here, but it seems like it boils down to some method not being found in Perl Navigator? I've provided all of the info that seems relevant below. Let me know if there would be anything else that's helpful.

I'm on Arch Linux with a 64-bit kernel version 5.15.23, with a perlbrew managed Perl v5.34.0.

When I open a Perl source file in neovim, a message appears at the bottom saying: Client 1 quit with exit code 1 and signal 0

In :LspInfo it says 0 clients are attached to this buffer. It recognizes the config for Perl Navigator, says it's set to autostart and that it's executable, and the command matches what I've configured in the neovim config.

neovim's LSP debugging output:

[START][2022-02-17 10:17:27] LSP logging initiated
[INFO][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:261	"Starting RPC client"	{  args = { "/home/$USER/dev/PerlNavigator/server/out/server.js", "--stdio" },  cmd = "node",  extra = {    cwd = "/home/$USER/Sync/i7-dev/lutron"  }}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:347	"rpc.send"	{  id = 1,  jsonrpc = "2.0",  method = "initialize",  params = {    capabilities = {      callHierarchy = {        dynamicRegistration = false      },      textDocument = {        codeAction = {          codeActionLiteralSupport = {            codeActionKind = {              valueSet = { "", "Empty", "QuickFix", "Refactor", "RefactorExtract", "RefactorInline", "RefactorRewrite", "Source", "SourceOrganizeImports", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" }            }          },          dataSupport = true,          dynamicRegistration = false,          resolveSupport = {            properties = { "edit" }          }        },        completion = {          completionItem = {            commitCharactersSupport = false,            deprecatedSupport = false,            documentationFormat = { "markdown", "plaintext" },            preselectSupport = false,            snippetSupport = false          },          completionItemKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }          },          contextSupport = false,          dynamicRegistration = false        },        declaration = {          linkSupport = true        },        definition = {          linkSupport = true        },        documentHighlight = {          dynamicRegistration = false        },        documentSymbol = {          dynamicRegistration = false,          hierarchicalDocumentSymbolSupport = true,          symbolKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }          }        },        hover = {          contentFormat = { "markdown", "plaintext" },          dynamicRegistration = false        },        implementation = {          linkSupport = true        },        publishDiagnostics = {          relatedInformation = true,          tagSupport = {            valueSet = { 1, 2 }          }        },        references = {          dynamicRegistration = false        },        rename = {          dynamicRegistration = false,          prepareSupport = true        },        signatureHelp = {          dynamicRegistration = false,          signatureInformation = {            activeParameterSupport = true,            documentationFormat = { "markdown", "plaintext" },            parameterInformation = {              labelOffsetSupport = true            }          }        },        synchronization = {          didSave = true,          dynamicRegistration = false,          willSave = false,          willSaveWaitUntil = false        },        typeDefinition = {          linkSupport = true        }      },      window = {        showDocument = {          support = false        },        showMessage = {          messageActionItem = {            additionalPropertiesSupport = false          }        },        workDoneProgress = true      },      workspace = {        applyEdit = true,        configuration = true,        symbol = {          dynamicRegistration = false,          hierarchicalWorkspaceSymbolSupport = true,          symbolKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }          }        },        workspaceEdit = {          resourceOperations = { "rename", "create", "delete" }        },        workspaceFolders = true      }    },    clientInfo = {      name = "Neovim",      version = "0.6.1"    },    initializationOptions = vim.empty_dict(),    processId = 176397,    rootPath = "/home/$USER/Sync/i7-dev/lutron",    rootUri = "file:///home/$USER/Sync/i7-dev/lutron",    trace = "off",    workspaceFolders = { {        name = "/home/$USER/Sync/i7-dev/lutron",        uri = "file:///home/$USER/Sync/i7-dev/lutron"      } }  }}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  id = 1,  jsonrpc = "2.0",  result = {    capabilities = {      completionProvider = {        resolveProvider = false,        triggerCharacters = { "$", "@", "%", "-", ">", ":" }      },      definitionProvider = true,      documentSymbolProvider = true,      hoverProvider = true,      textDocumentSync = 2,      workspace = {        workspaceFolders = {          supported = true        }      },      workspaceSymbolProvider = true    }  }}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:347	"rpc.send"	{  jsonrpc = "2.0",  method = "initialized",  params = vim.empty_dict()}
[DEBUG][2022-02-17 10:17:27] .../lua/vim/lsp.lua:921	"LSP[perlnavigator]"	"server_capabilities"	{  completionProvider = {    resolveProvider = false,    triggerCharacters = { "$", "@", "%", "-", ">", ":" }  },  definitionProvider = true,  documentSymbolProvider = true,  hoverProvider = true,  textDocumentSync = 2,  workspace = {    workspaceFolders = {      supported = true    }  },  workspaceSymbolProvider = true}
[INFO][2022-02-17 10:17:27] .../lua/vim/lsp.lua:922	"LSP[perlnavigator]"	"initialized"	{  resolved_capabilities = {    call_hierarchy = false,    code_action = false,    code_lens = false,    code_lens_resolve = false,    completion = true,    declaration = false,    document_formatting = false,    document_highlight = false,    document_range_formatting = false,    document_symbol = true,    execute_command = false,    find_references = false,    goto_definition = true,    hover = true,    implementation = false,    rename = false,    signature_help = false,    signature_help_trigger_characters = {},    text_document_did_change = 2,    text_document_open_close = true,    text_document_save = true,    text_document_save_include_text = false,    text_document_will_save = false,    text_document_will_save_wait_until = false,    type_definition = false,    workspace_folder_properties = {      changeNotifications = false,      supported = true    },    workspace_symbol = true  }}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:347	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didOpen",  params = {    textDocument = {      languageId = "perl",      text = "#!/usr/bin/env perl\n\nuse 5.026;\n\nuse Mojo::Base -strict, -signatures;\nuse Mojo::Util qw(dumper trim);\nuse Mojo::IOLoop;\n\nuse FindBin qw($RealBin);\nuse lib \"$RealBin/lib/\";\nuse Lutron::Caseta;\n\nuse constant {\n  BRIDGE_HOST => 'lutron-02711e26',\n  BRIDGE_PORT => 8081,\n};\n\n\ndie \"Unable to create caseta object: $!\" unless\n  my $caseta = Lutron::Caseta->new(\n    host => BRIDGE_HOST,\n    port => BRIDGE_PORT,\n  );\n\n$caseta\n  ->ping\n  ->devices\n  ->set_level(1 => $ARGV[0] // 80)\n  ->status(1);\n\n$caseta->on(json_read => sub ($self, $json) {\n  printf \"\\n[[ %s ]] json_read\\n\", scalar localtime;\n});\n\n$caseta->on(pong => sub { say 'PONG!' });\n\n$caseta->on(zone_status => sub ($self, $status) {\n  say dumper $status;\n  say \"Zone Status: $status->{zone} = $status->{level}\";\n  #say $status->{level} if ($status->{zone} eq '/zone/1');\n});\n\n$caseta->on(devices => sub ($self, $devices) {\n  say \"Device Count: $devices->{device_count}\";\n  say \"Devices:\\n\", dumper $devices->{devices};\n  print \"Devices:\";\n  print \"\\n  \", join ' / ', $_->{FullyQualifiedName}->@*\n    for $devices->{devices}->@*;\n\n   print \"\\n\";\n});\n\n$caseta->listen;\n\n\n__DATA__\nJSON_READ:\n{\n  \"Body\" => {\n    \"ZoneStatus\" => {\n      \"Level\" => 0,\n      \"Zone\" => {\n        \"href\" => \"/zone/1\"\n      },\n      \"href\" => \"/zone/1/status\"\n    }\n  },\n  \"CommuniqueType\" => \"ReadResponse\",\n  \"Header\" => {\n    \"MessageBodyType\" => \"OneZoneStatus\",\n    \"StatusCode\" => \"200 OK\",\n    \"Url\" => \"/zone/1/status/level\"\n  }\n}\n\nJSON_READ:\n{\n  \"Body\" => {\n    \"PingResponse\" => {\n      \"LEAPVersion\" => \"1.109\"\n    }\n  },\n  \"CommuniqueType\" => \"ReadResponse\",\n  \"Header\" => {\n    \"MessageBodyType\" => \"OnePingResponse\",\n    \"StatusCode\" => \"200 OK\",\n    \"Url\" => \"/server/1/status/ping\"\n  }\n}\n\nJSON_READ:\n{\n  \"Body\" => {\n    \"Devices\" => [\n      {\n        \"DeviceRules\" => [\n          {\n            \"href\" => \"/devicerule/40\"\n          }\n        ],\n        \"DeviceType\" => \"SmartBridge\",\n        \"FirmwareImage\" => {\n          \"Firmware\" => {\n            \"DisplayName\" => \"06.09.01f000\"\n          },\n          \"Installed\" => {\n            \"Day\" => 28,\n            \"Hour\" => 3,\n            \"Minute\" => 47,\n            \"Month\" => 2,\n...\n        \"DeviceRules\" => [\n          {\n            \"href\" => \"/devicerule/40\"\n          }\n        ],\n        \"DeviceType\" => \"SmartBridge\",\n        \"FirmwareImage\" => {\n          \"Firmware\" => {\n            \"DisplayName\" => \"06.09.01f000\"\n          },\n          \"Installed\" => {\n            \"Day\" => 28,\n            \"Hour\" => 3,\n            \"Minute\" => 47,\n            \"Month\" => 2,\n            \"Second\" => 9,\n            \"Utc\" => \"-7:00:00\",\n            \"Year\" => 2019\n\n\n\ndef get_value(self, device_id):\n        \"\"\"\n        Will return the current level value for the device with the given ID.\n        :param device_id: device id, e.g. 5\n        :returns level value from 0 to 100\n        :rtype int\n        \"\"\"\n        zone_id = self._get_zone_id(device_id)\n        if zone_id:\n            cmd = {\n                \"CommuniqueType\": \"ReadRequest\",\n                \"Header\": {\"Url\": \"/zone/%s/status\" % zone_id}}\n            return self._writer.write(cmd)\n\n    def is_connected(self):\n        \"\"\"Will return True if currently connected to the Smart Bridge.\"\"\"\n        return self.logged_in\n\n    def is_on(self, device_id):\n        \"\"\"\n        Will return True is the device with the given ID is 'on'.\n        :param device_id: device id, e.g. 5\n        :returns True if level is greater than 0 level, False otherwise\n        \"\"\"\n        return self.devices[device_id]['current_state'] > 0\n\n    def set_value(self, device_id, value):\n        \"\"\"\n        Will set the value for a device with the given ID.\n        :param device_id: device id to set the value on\n        :param value: integer value from 0 to 100 to set\n        \"\"\"\n        zone_id = self._get_zone_id(device_id)\n        if zone_id:\n            cmd = {\n                \"CommuniqueType\": \"CreateRequest\",\n                \"Header\": {\"Url\": \"/zone/%s/commandprocessor\" % zone_id},\n                \"Body\": {\n                    \"Command\": {\n                        \"CommandType\": \"GoToLevel\",\n                        \"Parameter\": [{\"Type\": \"Level\", \"Value\": value}]}}}\n\n\n    def _load_devices(self):\n        \"\"\"Load the device list from the SSL LEAP server interface.\"\"\"\n        _LOG.debug(\"Loading devices\")\n        self._writer.write({\n            \"CommuniqueType\": \"ReadRequest\", \"Header\": {\"Url\": \"/device\"}})\n        device_json = yield from self._reader.read()\n        for device in device_json['Body']['Devices']:\n            _LOG.debug(device)\ndevice_id = device['href'][device['href'].rfind('/') + 1:]\n",      uri = "file:///home/$USER/Sync/i7-dev/lutron/lutron.pl",      version = 0    }  }}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  id = 0,  jsonrpc = "2.0",  method = "client/registerCapability",  params = {    registrations = { {        id = "c3d085c8-e4cb-4672-a4fa-3d66f64e6126",        method = "workspace/didChangeConfiguration",        registerOptions = vim.empty_dict()      } }  }}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  id = 1,  jsonrpc = "2.0",  method = "client/registerCapability",  params = {    registrations = { {        id = "ed6b0424-cf4a-4e48-8477-420355514614",        method = "workspace/didChangeWorkspaceFolders",        registerOptions = vim.empty_dict()      } }  }}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  id = 2,  jsonrpc = "2.0",  method = "workspace/configuration",  params = {    items = { {        scopeUri = "file:///home/$USER/Sync/i7-dev/lutron/lutron.pl",        section = "perlnavigator"      } }  }}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  id = 3,  jsonrpc = "2.0",  method = "workspace/configuration",  params = {    items = { {        scopeUri = "file:///home/$USER/Sync/i7-dev/lutron/lutron.pl",        section = "perlnavigator"      } }  }}
[WARN][2022-02-17 10:17:27] ...lsp/handlers.lua:109	"The language server perlnavigator triggers a registerCapability handler despite dynamicRegistration set to false. Report upstream, this warning is harmless"
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:464	"server_request: callback result"	{  result = vim.NIL,  status = true}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:347	"rpc.send"	{  id = 0,  jsonrpc = "2.0",  result = vim.NIL}
[WARN][2022-02-17 10:17:27] ...lsp/handlers.lua:109	"The language server perlnavigator triggers a registerCapability handler despite dynamicRegistration set to false. Report upstream, this warning is harmless"
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:464	"server_request: callback result"	{  result = vim.NIL,  status = true}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:347	"rpc.send"	{  id = 1,  jsonrpc = "2.0",  result = vim.NIL}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:464	"server_request: callback result"	{  result = { vim.NIL },  status = true}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:347	"rpc.send"	{  id = 2,  jsonrpc = "2.0",  result = { vim.NIL }}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:464	"server_request: callback result"	{  result = { vim.NIL },  status = true}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:347	"rpc.send"	{  id = 3,  jsonrpc = "2.0",  result = { vim.NIL }}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  id = 4,  jsonrpc = "2.0",  method = "workspace/workspaceFolders"}
[WARN][2022-02-17 10:17:27] .../lua/vim/lsp.lua:751	"server_request: no handler found for"	"workspace/workspaceFolders"
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:464	"server_request: callback result"	{  err = {    code = -32601,    message = "MethodNotFound",    <metatable> = {      __tostring = <function 1>    }  },  status = true}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:347	"rpc.send"	{  error = {    code = -32601,    message = "MethodNotFound",    <metatable> = {      __tostring = <function 1>    }  },  id = 4,  jsonrpc = "2.0"}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  id = 5,  jsonrpc = "2.0",  method = "workspace/workspaceFolders"}
[WARN][2022-02-17 10:17:27] .../lua/vim/lsp.lua:751	"server_request: no handler found for"	"workspace/workspaceFolders"
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:464	"server_request: callback result"	{  err = {    code = -32601,    message = "MethodNotFound",    <metatable> = {      __tostring = <function 1>    }  },  status = true}
[DEBUG][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:347	"rpc.send"	{  error = {    code = -32601,    message = "MethodNotFound",    <metatable> = {      __tostring = <function 1>    }  },  id = 5,  jsonrpc = "2.0"}
[ERROR][2022-02-17 10:17:27] .../vim/lsp/rpc.lua:420	"rpc"	"node"	"stderr"	"/home/$USER/Sync/i7-dev/PerlNavigator/server/node_modules/vscode-jsonrpc/lib/common/connection.js:477\n                        responsePromise.reject(new messages_1.ResponseError(error.code, error.message, error.data));\n                                               ^\n\nResponseError: MethodNotFound\n    at handleResponse (/home/$USER/Sync/i7-dev/PerlNavigator/server/node_modules/vscode-jsonrpc/lib/common/connection.js:477:48)\n    at processMessageQueue (/home/$USER/Sync/i7-dev/PerlNavigator/server/node_modules/vscode-jsonrpc/lib/common/connection.js:292:17)\n    at Immediate.<anonymous> (/home/$USER/Sync/i7-dev/PerlNavigator/server/node_modules/vscode-jsonrpc/lib/common/connection.js:276:13)\n    at processImmediate (node:internal/timers:464:21) {\n  code: -32601,\n  data: undefined\n}\n"

neovim version information:

:version
NVIM v0.6.1
Build type: Release
LuaJIT 2.1.0-beta3
Compiled by builduser

Features: +acl +iconv +tui

neovim lsp config for Perl Navigator (config hints from :help lspconfig-adding-servers):

local configs = require 'lspconfig.configs'
-- Check if the config is already defined (useful when reloading this file)
if not configs.perlnavigator then
  configs.perlnavigator = {
   default_config = {
     cmd = { "node", "/home/$USER/dev/PerlNavigator/server/out/server.js", "--stdio" },
     filetypes = { 'perl' };
     root_dir = function(fname)
       return lspconfig.util.find_git_ancestor(fname)
     end;
     settings = {};
   };
  }
end

lspconfig.perlnavigator.setup{}
❯ node --version
v16.13.2

Autocomplete $foo[ for arrays and hashes.

When an array variable exists such as @foo = (3,4,5);, the variable can also be used as $foo[1]. Currently, the Navigator only autocompletes on @foo, but not $foo. Please add this form of autocomplete for both arrays and hashes, and include the opening left bracket (or brace). The relevant code is in completion.ts

Add POD overview on hover in code and autocomplete

Having the documentation at hand would be a nice addition. This should be achievable with the perldoc utility using variations of perldoc -T -MPod::Simple::HTML <other arguments>. The formatter would default to Pod::Simple::HTML but would be customizable in the extension settings.

This feature could cover the perlfunc, perlapifunc, perlvar (respectively with the arguments -f, -a and -v) and modules.

Regarding the hover/autocomplete of module subroutines/constants/variables, it could just display the documentation of the whole module. As this level of granularity is not ideal, the process could be made a little more smart about those symbols. The idea would be to search after =headX or =item occurences followed by the symbol name in the POD and if results are found, the documentation would be scrolled to the first occurence. As the results might not be perfect, this could be an optional feature to toggle in the settings.

help at getting perlnavigator working

perl version: 5.36.0
perl path: /ur/bin/perl
ide/text editor: neovim, lunarvim. vscode
install method: Mason, vscode marketplace
setup method: lspconfig

hi, i wanted to start learning perl and wanted to get perlnavigator working with lunarvim and lsp but i can't get the completion to work.

i already opened an issue on lunarvim for this ages ago but couldn't find an answer to my problem i also tried to get perlnavigator working on neovim with lspconfig and the default config in the README however that also didn't work, i have also tried to download the perlnavigator extension for vscode and still didn't have any completion for perl.

i think perl navigator is working since it does give warnings like the one below:
image

i also had the same warnings come up in the vscode extension.

Again this is the first time i am using perl so is there more i have to configure or add to get the completion working.

Obscure formatting issue with Neovim

This may be specific to Neovim, but I don't know if it's a bug with Neovim or not.

Given this perl file:

#!/usr/bin/env perl

content;

If I now try to format this file the following is logged by Neovim to its LSP log:

[DEBUG][2022-03-17 21:02:15] .../lua/vim/lsp.lua:1023   "LSP[perlnavigator]"    "client.request"        1       "textDocument/formatting"       {
  options = {
    [""] = true,
    insertSpaces = false,
    tabSize = 8
  },
  textDocument = {
    uri = "file:///home/seth/src/toy/perl/t"
  }
}       <function 1>    1
[DEBUG][2022-03-17 21:02:15] .../vim/lsp/rpc.lua:347    "rpc.send"      {
  id = 2,
  jsonrpc = "2.0",
  method = "textDocument/formatting",
  params = {
    options = {
      [""] = true,
      insertSpaces = false,
      tabSize = 8
    },
    textDocument = {
      uri = "file:///home/seth/src/toy/perl/t"
    }
  }
}
[DEBUG][2022-03-17 21:02:15] .../vim/lsp/rpc.lua:454    "rpc.receive"   {
  id = 7,
  jsonrpc = "2.0",
  method = "workspace/workspaceFolders"
}
[TRACE][2022-03-17 21:02:15] .../lua/vim/lsp.lua:806    "server_request"        "workspace/workspaceFolders"    nil
[TRACE][2022-03-17 21:02:15] .../lua/vim/lsp.lua:809    "server_request: found handler for"     "workspace/workspaceFolders"
[TRACE][2022-03-17 21:02:15] ...lsp/handlers.lua:487    "default_handler"       "workspace/workspaceFolders"    {
  ctx = '{\n  client_id = 1,\n  method = "workspace/workspaceFolders"\n}'
}
[DEBUG][2022-03-17 21:02:15] .../vim/lsp/rpc.lua:464    "server_request: callback result"       {
  result = vim.NIL,
  status = true
}
[DEBUG][2022-03-17 21:02:15] .../vim/lsp/rpc.lua:347    "rpc.send"      {
  id = 7,
  jsonrpc = "2.0",
  result = vim.NIL
}
[ERROR][2022-03-17 21:02:15] .../vim/lsp/rpc.lua:73     "invalid header line %q"        "content;\nee4ffa34-a14f-4609-b2e4-bf23565f3262\nContent-Length: 157"

The last line is the error. I found this, not with the above file, but with a much more complicated file that had the word content in a couple of lines that looked like this:

  my ($body)
          = map { $_->content } $sent[0]{email}->object->parts;

I don't know if it's how the content is being sent, or what. I couldn't get any other LSP server to fail with the word content somewhere in it. Only PerlNavigator had this particular issue.

This is with the most recently published npm of PerlNavigator. Which I believe is 0.2.8.

sort ->new first always

When building a new object, ideally My::Package->new() should be listed first in autocomplete. This is almost correct currently, but not quite. When a user begins to type the ->, the new() gets lost. Update the sort order to always keep new at the top, unless it's already an $object. This will be nice to have other eyes on to consider the current sort order of packages, subroutines, etc.

Sorting

Show Subroutine Signatures

I would like to be able to view subroutine signatures as I type. This is how it looks in Python:
image

In Perl, we have the coderefs available for introspection. We should be able to deparse the coderef, inspect it, and return the signature. Make sure to remove $self if being called using -> notation. This task will likely be very tricky as it encompasses an end-to-end new feature.

https://stackoverflow.com/questions/63836449/how-do-i-get-the-signature-of-a-subroutine-in-runtime

https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_signatureHelp

Installation for other editors - missing cd command?

The installation instructions at https://github.com/bscan/PerlNavigator#installation-for-other-editors didn't work for me after the most recent change: I had to add a cd server before running tsc (the command was there in older versions of the instructions)

I am not at all familiar with typescript build processes, so I don't know whether the command has been accidentally deleted or whether my workaround was just pure luck - if that's the correct fix I can prepare a PR

publish npm fetchable package automatically

Now that there is an automatic build can it also publish the npm package whenever a build occurs?

For now the neovim installer depends on the npm package so any changes to the code should be published this way also.

I will also look at using the binaries that are being built. One reason I might not use the binaries is because the neovim installer has a very nice feature where it can show all the configuration elements iff there is a package.json in the installation directory. This gets lost if I use the binaries.

Add "Parsing Modes" to disable compiling

For security reasons, some people may want to disable compilation, but still use the tagger based autocompletion, Perl::Critic, Perl::Tidy, etc. Add a parsing mode setting, which will currently include perl -c and no compiling, but should also include a "tagging" based method in the future. This can probably be done by adding a BEGIN{exit(0)} at the top of the Perl script or similar technique.

Can the npm package be updated to latest version?

I recently managed to get PerlNavigator working on nvim quite easily using mason.nvim.

However, Mason pulls the LSP from npm instead of git. Currently, the npm package uses version 0.2.8.

Is there any chance the npm package be updated to the most recent version?

I did try to edit the installation instructions in mason.nvim to download the LSP from git but I haven't been able to get it working yet so npm seems to be the most straightforward method.

Completion works with neovim, but not very well

Completion works, however, the completions options are extremely limited. The completion menu doesn't suggest built in keywords like print, for example. If I type in p, the only option is the parent Module. The only other completion suggestions that show up are identifiers in the file I'm currently editing.

Not sure if it's a configuratoin problem but the same exact settings I'm using worked 100% with PLS language server module.

Non-functioning autocomplete/navigation in large codebase

I am attempting to run the extension in an environment with a fairly large perl codebase. My initial attempt showed navigation and autocomplete to be non-functional. The extension output log reported an error running modhunter (pasted below). The error appears to be thrown from the try loop on line 98 of server/src/navigation.ts. I tried experimenting with the buffer size passed to execFile on line 100 of the same file. Expanding it by a factor of 4 (though not 2) seemed to resolve the error and restore functionality.

const out = await async_execFile(settings.perlPath, perlParams, {timeout: 90000, maxBuffer: 3 * 1024 * 1024 * 4});

I wanted to know if there was a compelling reason for the buffer size here, or if the size was chosen somewhat arbitrarily. If the latter, is this something that could be expanded or made configurable so as to work on our large codebase?

Error message:
ModHunter failed. You will lose autocomplete on importing modules. Not a huge deal
RangeError [ERR_CHILD_PROCESS_STDIO_MAXBUFFER]: stdout maxBuffer length exceeded
at new NodeError (node:internal/errors:371:5)
at Socket.onChildStdout (node:child_process:461:14)
at Socket.emit (node:events:526:28)
at addChunk (node:internal/streams/readable:315:12)
at readableAddChunk (node:internal/streams/readable:285:11)
at Socket.Readable.push (node:internal/streams/readable:228:10)
at Pipe.onStreamRead (node:internal/stream_base_commons:190:23) {
code: 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER',

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.