Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

include php blade plugin in php cluster #7618

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

haidubogdan
Copy link

@haidubogdan haidubogdan commented Jul 29, 2024

Laravel is one of the most used frameworks in php, yet it still doesn't have support in Netbeans. (#7531 , #7231).
Mostly the main missing support is for blade templates syntax.

I've started to work on a plugin https://github.com/haidubogdan/netbeans-php-blade-plugin 3 years ago.
After using antlr as a lexer and parser, I found that scaling the plugin was much maintainable.
It's not the cleanest code, but I realized that I will always reach to the 99% finish status if I don't do the first pull request.

Most of the available features to be included are listed at https://github.com/haidubogdan/netbeans-php-blade-plugin.

  • syntax highlighting
  • blade syntax completion
  • declaration finder for specific blade template
    ....

And some are still missing

  • php embedded syntax validation
  • more advanced php syntax completion.

All feedbacks are welcome, I hope to reach nb 23 deployment :) .

TODO

  • Submit an ICLA (sent on 3 august)
  • Change to the full name in commits
  • Check the license of the image (no response received from Tailor [laravel], using personal icon)
  • Add unit tests
  • Write all features with screenshots

@ebarboni ebarboni requested a review from junichi11 July 29, 2024 08:56
@junichi11 junichi11 added the PHP [ci] enable extra PHP tests (php/php.editor) label Jul 30, 2024
@junichi11
Copy link
Member

First of all, thank you for your contribution!

I hope to reach nb 23 deployment

Unfortunately, it's too late. The feature freeze date is July 26th.

Please write all features of this module with screenshots here as well. (not only the link)

Please add unit tests for features. e.g. code completion, indexer, navigator, parser, lexer, formatter etc. (also see: CslTestBase.java)

Did you submit an ICLA?

Probably, it takes a lot of time to review this.

@junichi11 junichi11 requested a review from tmysik July 30, 2024 05:03
@junichi11 junichi11 added this to the NB24 milestone Jul 30, 2024
@haidubogdan
Copy link
Author

Hi,
thank you for your feedback.
I will prepare the unit tests. ( I hope the base parser unit test classes will be available now that it's included in the IDE folder).
I didn't submit the ICLA. I will read about it.

@junichi11
Copy link
Member

How did you generate icons? (Are there icons based on something?)

https://github.com/apache/netbeans/pull/7618/files#diff-24c53d9c7defe885e1ee8adee9ff009c57d69e75621ad84625d8f9eaa8d7c9e1

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove?

Comment on lines +44 to +47
final CompletionRequest request;
protected final ElementHandle element;
final String previewValue;
protected Directive directive;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are modifiers proper?

Comment on lines +90 to +94
formatter.appendHtml("<font>");
formatter.appendHtml("<b>");
formatter.appendText(previewValue);
formatter.appendHtml("</b>");
formatter.appendHtml("</font>");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// NOI18N

}
if (file != null) {
formatter.reset();
formatter.appendText(" ");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// NOI18N

@Override
public String getCustomInsertTemplate() {
if (namespace != null && namespace.length() > 0) {
return "\\" + namespace + "\\" + element.getName();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can change these("\\") to constants?


@Override
public String getRhsHtml(HtmlFormatter formatter) {
return "blade";
Copy link
Member

@junichi11 junichi11 Aug 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// NOI18N
the other strings as well

if (this.getElement().getFileObject() != null) {
return this.getElement().getFileObject().getNameExt();
}
return "custom directive";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check whether we should consider i18n

*/
@MimeRegistrations(value = {
@MimeRegistration(mimeType = "text/html", service = CompletionProvider.class),
@MimeRegistration(mimeType = "text/x-blade", service = CompletionProvider.class)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@MimeRegistration(mimeType = "text/x-blade", service = CompletionProvider.class)
@MimeRegistration(mimeType = BladeLanguage.MIME_TYPE, service = CompletionProvider.class)

}
break;
case HTML_COMPONENT_PREFIX:
String compPrefix = currentToken.getText().length() > 3 ? StringUtils.kebabToCamel(currentToken.getText().substring(3)) : "";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does 3 mean?
// NOI18N

} finally {
long time = System.currentTimeMillis() - startTime;
if (time > 2000){
LOGGER.log(Level.INFO, "Slow completion time detected. {0}ms", time);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// NOI18N

if (customDirective.name.startsWith(prefix)) {
resultSet.addItem(DirectiveCompletionBuilder.itemWithArg(
startOffset, carretOffset, prefix, customDirective.name,
"custom directive", doc, file));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// NOI18N

* @author bhaidu
*/
@MimeRegistrations(value = {
@MimeRegistration(mimeType = "text/x-php5", service = CompletionProvider.class, position = 102),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@MimeRegistration(mimeType = "text/x-php5", service = CompletionProvider.class, position = 102),
@MimeRegistration(mimeType = FileUtils.PHP_MIME_TYPE, service = CompletionProvider.class, position = 102),

doQuery(resultSet, doc, caretOffset);
long time = System.currentTimeMillis() - startTime;
if (time > 2000) {
LOGGER.log(Level.INFO, "Slow completion time detected. {0}ms", time);
Copy link
Member

@junichi11 junichi11 Aug 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// NOI18N
The other strings as well.

Comment on lines +30 to +33
public String name;
public String qualifiedClassName;

public Set<String> properties = new HashSet<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please reconsider visibility.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this class isn't used anywhere atm, but this looks like a potential candidate for a record in case this should stay.


public class ComponentsCompletionService {

@CheckForNull
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove?

return results;
}

public FileObject getComponentResourceFile(String componentId, String classQualifiedName, FileObject sourceFo) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ChekcForNull
// NOI18N

return null;
}

public FileObject getLivewireComponentResourceFile(String componentId, FileObject sourceFo) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ChekcForNull
// NOI18N

@junichi11
Copy link
Member

junichi11 commented Sep 3, 2024

Please check whether we should translate yourself once for strings of all files. (add // NOI18N or @Messages)
Please check whether annotations are needed. (e.g. @CheckForNull, @NullAllowed,...)

Copy link
Member

@mbien mbien left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't forget to hook the tests into CI so that we can let it run over this PR - just in case there are any surprises.

would look like:

- name: php.latte
run: ant $OPTS -f php/php.latte test

and someone can trigger the workflow once done

Comment on lines +319 to +326
String template = getItemText() + "($$${arg})\n\n${selection}${cursor}\n" + getEndTag(); // NOI18N

switch (getName()) {
case BladeDirectivesUtils.DIRECTIVE_FOREACH ->
template = getItemText() + "($$${array} as $$${item})\n${selection}${cursor}\n" + getEndTag(); // NOI18N
}

return template;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would build the template string only once:

return switch (getName()) {
    case DIRECTIVE_FOREACH ...
    default ...
};

Comment on lines +246 to +252
String template = getItemText() + "($$${arg})"; // NOI18N
switch (getName()) {
case BladeDirectivesUtils.DIRECTIVE_INCLUDE,
BladeDirectivesUtils.DIRECTIVE_EXTENDS ->
template = getItemText() + "('${path}')"; // NOI18N
}
return template;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same pattern here

Comment on lines +62 to +64
return this.cacheMap.keySet().parallelStream()
.filter(this::isExpired)
.collect(Collectors.toSet());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you sure parallelStream() is a good idea here? It always comes with setup and runtime overhead and all this stream does is to filter a set - so the parallel task itself is tiny.

I would only recommend using parallel streams if it is also demonstrated in a benchmark that they make a difference in that usecase.

Comment on lines +452 to +464
String template = getName() + "($$${arg})\n ${cursor}\n" + directive.endtag();

switch (getName()) {
case "@foreach": // NOI18N
template = getName() + "($$${array} as $$${item})\n ${selection}${cursor}\n" + directive.endtag();
break;
case "@section": // NOI18N
case "@session": // NOI18N
template = getName() + "('${id}')\n ${cursor}\n" + directive.endtag();
break;
}

return template;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same pattern here. The initial assignment can be moved into the default case.

Comment on lines +30 to +33
public String name;
public String qualifiedClassName;

public Set<String> properties = new HashSet<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this class isn't used anywhere atm, but this looks like a potential candidate for a record in case this should stay.

Comment on lines +40 to +44
public static final List<Integer> TOKENS_WITH_IDENTIFIABLE_PARAM = Arrays.asList(new Integer[]{
D_EXTENDS, D_INCLUDE, D_INCLUDE_IF, D_INCLUDE_WHEN,
D_INCLUDE_UNLESS, D_EACH, D_SECTION, D_HAS_SECTION, D_SECTION_MISSING,
D_PUSH, D_PUSH_IF, D_PREPEND, D_USE, D_INJECT, D_ASSET_BUNDLER
});
Copy link
Member

@mbien mbien Sep 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List.of would make this immutable. Should this be a Set? (see next comment)

Comment on lines +72 to +73
public static Token findForward(Document doc, Token start,
List<String> stopTokenText, List<String> openTokensText) {
Copy link
Member

@mbien mbien Sep 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the find* methods in this utility call contains on lists. It could be worth checking if this could be sets instead or Collection, so that the caller can decide when to pass a List or a Set. (set will have the faster contains call)

Comment on lines +178 to +184
List<Integer> tokensMatch = Arrays.asList(new Integer[]{
D_EXTENDS, D_INCLUDE, D_SECTION, D_HAS_SECTION,
D_INCLUDE_IF, D_INCLUDE_WHEN, D_INCLUDE_UNLESS, D_INCLUDE_FIRST,
D_EACH, D_PUSH, D_PUSH_IF, D_PREPEND
});

List<Integer> tokensStop = Arrays.asList(new Integer[]{HTML, BL_COMMA, BL_PARAM_CONCAT_OPERATOR});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constants and Set.of()?

Comment on lines +33 to +38
List<String> result = new ArrayList<>();
while (list.hasMoreElements()) {
result.add(list.nextElement());
}

return String.join("|", result);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

->

    return String.join("|", Collections.list(list));

Comment on lines +721 to +727
private static final String _serializedATNSegment0 =
"\u0004\u0000\u00ab\u0b4c\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+
"\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+
"\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+
"\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0002\u0000"+
"\u0007\u0000\u0002\u0001\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003"+
"\u0007\u0003\u0002\u0004\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006"+
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regarding generated code. I believe we ended up agreeing to try to generate antlr outputs during build but don't commit it to the repo. The reason is because generated antlr code is not very "stable", it produces huge diffs when the version updates and those aren't reviewable anyway. (e.g the marked section)

The second reason would be antlr updates, this makes sure the code fits to the version if someone happens to update the antlr lib at some point.

example: #7189, #7186 etc

cc @neilcsmith-net @lkishalmi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
do not merge Don't merge this PR, it is not ready or just demonstration purposes. PHP [ci] enable extra PHP tests (php/php.editor)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants