NppLspClient icon indicating copy to clipboard operation
NppLspClient copied to clipboard

PHP Intelephense LSP server

Open diekaines opened this issue 1 month ago • 2 comments

Hi , great work I was testing a bit by using the LSP server of Intelephense for PHP ( https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client ) , docs https://intelephense.com/docs#configuration .

It has a trace option that shows all interaction/communication between VS CODE and the LSP.

What I noticed is:

1- there is no way to use/tell the LSP to send "markdown" for hover, its always sending plaintext and thus the text that comes back cant be stylized on the webview/hover. 2- seems the NPP plugin doesnt/yet support "workspace/configuration" 3- Somehow the "format file" messes up the document.

The configuration im using

[lspservers.php]
mode = "io"
executable = 'node'
args = 'C:\Users\john\.vscode\extensions\bmewburn.vscode-intelephense-client-1.15.1\node_modules\intelephense\lib\intelephense.js --stdio '
auto_start_server = false 
initialization_options = '{"storagePath":"C:\\temp\\intelephense","environment":{"includePaths":["C:\\www\\wp"]}, "intelephense":{"completion":{"insertUseDeclaration":true,"suggestObjectOperatorStaticMethods":true,"triggerParameterHints":true,"preferredFormat":"markdown"},"diagnostics":{"argumentCount":true},"format":{"hover":"markdown","completion":"markdown"},"files":{"hoverFormat":"markdown"}},"preferredMarkupKind":"markdown","hover":{"preferredFormat":"markdown"} }'

Thanks

diekaines avatar Nov 12 '25 17:11 diekaines

Hello, I can confirm that this is also happening to me – and to be honest, I'm a little confused as to why this is the case. Regarding what you found: As far as I know, there is only one place in the LSP specification where a client can define how the returned content of a hover request should be formatted, in the initialization request, and that is what NppLspClient does. (rust-analyzer sends markdown content). But you're right, VSCode displays markdown content, while NppLspClient only gets plaintext from the server. As for the formatting of the document, I need to check whether I am handling all possible cases of formatting return (probably not). What and how did you test regarding the workspace/configuration? Currently, only adding and removing project folders to/from the workspace dialog is supported.

Ekopalypse avatar Nov 13 '25 09:11 Ekopalypse

The specification clearly states that the order indicates the preferred format, and since NppLspClient sends “plaintext”, “markdown” the PHP language server sends plain text.

/**
 * Client supports the follow content formats if the content
 * property refers to a `literal of type MarkupContent`.
 * The order describes the preferred format of the client.
 */

I will probably introduce a new configuration setting that is set to “markdown”, “plaintext” by default, but can be overridden for all or only certain language servers.

The format problem is due to the fact that NppLspClient assumed that TextEdits always arrive in ascending line numbering. However, the PHP language server provides descending numbering, which I believe is actually correct. This means that NppLspClient will sort TextEdits itself in the next version.

Ekopalypse avatar Nov 13 '25 11:11 Ekopalypse

Hello

What and how did you test regarding the workspace/configuration?

By tracing the communication on VS CODE ( setting "intelephense.trace.server": "verbose" on settings.json ) it seems that the server is requesting "workspace/configuration" and the client in VS CODE its sending the extra configuration

Image

Also from the docs https://intelephense.com/docs#configuration

Intelephense supports the LSP workspace/didChangeConfiguration and workspace/configuration methods as a way of supplying configuration values to the server.

The configuration options for this LSP are on the package.json starting on line 112

What i tested was to tell LSP that I wanted also "wordpress" stub to be included but its not possible using "initializationOptions" since LSP doesnt expect/listens to stubs on that request so the only way ( according to the tracing on vscode ) is on "workspace/configuration"

Maybe we can have NppLspClient to read and send a configuration file for that language/lsp server? In other words, an option like "configuration_options" that points to a file

[lspservers.php]
......
initialization_options = ...
working_directory = '${workspaceFolder}'
configuration_options ="extra_workspace_configuration.js"
.......

Since I presume that each LSP server will have its own sets of configurations

Whats strange though, is that by tracing the communication in NPP i dont see the server asking for "workspace/configuration" but that might be because of the way of the LSP being used ( transport code ) but I see "didChangeConfiguration" capability support

To start the intelephense server:

intelephense {transport}

Where {transport} is one of:

--node-ipc
--stdio
--socket={number}
--pipe={string}

Thank you

diekaines avatar Nov 13 '25 14:11 diekaines

There is a language server field called “settings” that serves this purpose and must be a valid JSON string. Currently, it is only sent when the server is started, which means that no update is sent when editing the configuration file.

Something like

settings = '''{
"intelephense.files.exclude": {
	[
		"**/.git/**",
		"**/.svn/**",
		"**/.hg/**",
		"**/CVS/**",
		"**/.DS_Store/**",
		"**/node_modules/**",
		"**/bower_components/**",
		"**/vendor/**/{Tests,tests}/**",
		"**/.history/**",
		"**/vendor/**/vendor/**"
	]
}
}'''

Since VSCode is the de facto standard for communicating with language servers, I think it would be helpful to have a wrapper that reads content such as the “package.json” file, so you could simply copy and paste the configuration. If there is a JSON schema for this ... have to think about it.

Ekopalypse avatar Nov 13 '25 15:11 Ekopalypse

Hi there,

Tested a bit myself with that "settings" but didnt had any luck. More specificially I was trying to tell the server to load the "wordpress" stubs ( since those arent included by default ) but no luck with different formats ( like . notation or uncompressed JSON ) .

FYI: also noticed that the NPP clientinfo is empty on 'initialize'

On the other hand, i tested also with a simple nodejs application but still the reply was "plainText" for "textDocument/hover". Maybe its only "markdown" for VS CODE client.

Thanks

diekaines avatar Nov 13 '25 21:11 diekaines

but still the reply was "plainText"

Please excuse the confusion, but this is because the NppLspClient is currently sending the wrong preferred order. Since the hover dialog uses the webview component, I should have set Markdown as the preferred format.

clientinfo is empty on 'initialize'

Thank you, this will be fixed in the next version.

Tested a bit myself with that "settings" but didnt had any luck.

Okay, thanks for testing, I'll try to figure out where the problem lies.

Ekopalypse avatar Nov 14 '25 06:11 Ekopalypse

I think I've found the problem. It looks like the absence of an optional ClientCapabilities parameter called configuration is responsible for this (left side of the image below). When I define it and set it to false (right side of the image), the PHP server takes into account the changes announced via the workspace.didChangeConfiguration notification, but when I set it to true it doesn't work either. I receive the workspace/configuration request from the server and respond with the same configuration data that was used in the notification, so ... ??

Image

But there is another issue when I hover over var_dump for example

Image

in VSCode it looks like this

Image

For some reason, the Webview component does not recognize the link correctly. However, I must admit that I have no knowledge of HTML, CSS, PHP, or JavaScript. Therefore, it is possible, and likely the case, that my generated HTML code also needs to be adjusted.

    pub fn update(&mut self,  markdown: String) {
        if ! markdown.is_empty() {
            match &self.webview {
                Some(webview) => {
                    let html_code = to_html(&markdown);
                    let content = format!(r"<html><head><style>{}</style></head><body>{html_code}</body></html>", self.css);
                    webview.navigate(&content);
                    self.show();
                }
                None => {
                    error!("NO WEBVIEW found !!??");
                }
            }
        }
    }

and self.css is

self.css = format!(r##"
html, body {{
    background-color: {bg_color};
    color: {fg_color};
    font-family: "{font_name}";
    font-size: {font_size}px;

    line-height: 22px;
    word-wrap: break-word;
}}

body {{
	padding-top: 1em;
}}


code {{
	font-family: "{font_name}";
	font-size: 1em;
	line-height: 1.357em;
}}

pre {{
	background-color: {bg_color_a};
}}

h1, h2, h3, h4, h5, h6,
p, ol, ul, pre {{
	margin-top: 0;
}}

h1, h2, h3, h4, h5, h6 {{
	font-weight: normal;
	margin-bottom: 0.2em;
    color: orange;
}}

h1 {{
    font-size: 2em;
    margin-top: 0;
    padding-bottom: 0.3em;
    border-bottom-width: 1px;
    border-bottom-style: solid;
}}

h2 {{
    font-size: 1.5em;
    padding-bottom: 0.3em;
    border-bottom-width: 1px;
    border-bottom-style: solid;
}}

h3 {{
    font-size: 1.25em;
}}

h4 {{
    font-size: 1em;
}}

h5 {{
    font-size: 0.875em;
}}

h6 {{
    font-size: 0.85em;
}}

a {{
	text-decoration: none;
    color: DodgerBlue;
}}

/* Prevent `sub` and `sup` elements from affecting line height */
sub,
sup {{
	line-height: 0;
}}

ul ul,
ul ol,
ol ul,
ol ol {{
	margin-bottom: 0;
}}


a:hover {{
	text-decoration: underline;
}}

"##);

Ekopalypse avatar Nov 14 '25 11:11 Ekopalypse

Hi there

I see that let html_code = to_html(&markdown); searched a bit the repository but aside from this ticket its not being found elsewhere. So i dont which library/package provides that.

On VSCODE the reply from server for "textDocument/hover" has a marker for the language ```php and then the example/doc follows . Maybe the markdown parser doesnt have the capability for PHP ?

[Trace - 5:16:29 PM] Received response 'textDocument/hover - (13)' in 463ms.
Result: {
    "contents": {
        "kind": "markdown",
        "value": "__add\\_action__\n\n......\n\n```php\n<?php\nfunction add_action(\n    $hook_name.................."
    },
    "range": {
    .......
}

When i was testing with copy/pasting the responses from VSCode into "initialization_options" of NPP plugin , I got the language to show on the "view source" of the webview -> inspect and there were / but still the code wasnt formatted/colorized/linked

On the other hand, can you update the source code, maybe on a branch or as a ZIP on the RELEASES so I/we can play a bit ourselves?

Thanks

diekaines avatar Nov 14 '25 16:11 diekaines

Hi,

The problem with the workspace configuration request seems to be that, unlike notifications, intelephense must not be sent as the top node. I hope that other language servers expect the same.

searched a bit the repository

Yes, it's outdated because it's been completely rewritten in Rust.

let html_code = to_html(&markdown);

this comes from the markdown crate

I played around with the gfm option a little, and now it looks more like what you would expect.

Image

On the other hand, can you update ...

I planned to do this when the first beta version was released, as I also wanted to make the plugin available via PluginAdmin. The current roadmap looks like this

FOR BETA v.0.1.0-beta
    ✅ handle NPPN_GLOBALMODIFIED message
    ✅ the symbol dialog shows the "correct" hierarchy
    ✅ the hover dialog will hopefully get a proper web view - it got it, but I don't like it
    ✅ console dialog shows debug log
    ✅ all dialogs get their own configuration section to customize the colors
    ✅ the popup dialog is "glued" to its position (over Npps statusbar)
    ✅ implement warnings if faw is not used, popup as immediate actions and a one time description in the logs.
    ✅ support tcp transport mode
    ✅ having a way to jump through references, diagnostics
        ✅ references
        ✅ diagnostics
    ✅ create context menu helper to be used by all dialogs

    ⌛ new workspace dialog
    ⌛ call hierarchy dialog
    ⌛ support pipe mode
    ⌛ completion and signature dialogs that allow both to be shown at the same time
        ⌛ new signature dialog (maybe a new completion dialog as well)
    ⌛ symbols dialog
       ⌛  filter option for lsp request/response
        ❌   fuzzy filter option for ui
   ❌ documentation


FOR BETA v.0.2.0-beta
    ❌ create a dialog to stop selected servers
    ❌ rework diagnostics dialog
        - all files except the current one are folded, messages are sort by severity within the files
        - sort files by severity
        - sort messages by severity
    ❌ jumping to a reference does not work correctly if word wrap is used


FOR BETA v.0.3.0-beta
    ❌ performance release
        - reading/decoding incoming messages
        - logging to mmap file ??
        - ???
    ❌ check if lsp-/dialog actions can be improved

FOR BETA v.0.4.0-beta
    ❌ implement the remaining lsp methods

Ekopalypse avatar Nov 14 '25 20:11 Ekopalypse

That screenshot is looking really nice 👍

Looking forward to new alpha/beta releases and let me know if I can be of any help related to testing.

Thanks

diekaines avatar Nov 14 '25 22:11 diekaines

v.0.0.35-alpha released

Ekopalypse avatar Nov 15 '25 15:11 Ekopalypse