Perl5 plugin for Intellij IDEA

Hi everyone.

Recently i've decided to try to make perl5 plugin for InterlliJ IDEA. I've seen feew attempts to start, but they've failed after creating four base classes :)

The problem with perl is his too free syntax, which requires a very custom lexer and parser. I've tried to port perl's original lexer, but it's too big, got lot of legacy stuff, so i've droped the idea.

Currently, i'm making lexer with JFlex and it works, but need tunings for different perlish situations. Anyway, some syntax is already highighted:
46fdd3eb65.jpg
The second problem is that language plugins development documentation looks outdated (of course, not so many readers), but examples helps in such cases. Sometimes...

But is there some gurus in language plugins who could help with tricky questions or just to save some time in useless tries?

Also, if you would like to participate in perl5 plugin development, you are welcome: https://github.com/hurricup/Perl5-IDEA

1
236 条评论
Avatar
Permanently deleted user

Seems the same. parameters contains all I need.

Other question:

Got tree like

namespace1
     sub1
     sub2
          namespace2
               sub3


Got namespace1 with 2 subs. In sub2 got other namespace and sub3 inside it.
Need to find all subs of namespace1. So traversing should follow all but other namespaces. Is it possible to do traversing with kinda stop-tokens?

0

If I understand the question correctly, what prevents you from just going up in the PSI hierarchy and stop whenever you encounter some stopping condition (e.g. a namespace)? PsiTreeUtil might be useful to you, especially getParentOfType with stopAt parameter.

0
Avatar
Permanently deleted user

Made a composite named element. It looks like:  <<'SQL'
and tree is

Composite
     Operator
     String
          Quote
          StringContent
          Quote

Real name is a StringContent inside it.
And here is the problem: IDEA highlighting element as renamable only if i put cursor before <<. And not if i put it in real name (SQL in my example)
Is there way to solve this?

Upd: Seems reference's range solved this problem.

More questions:

Where is the fancy in-place editing on rename?
Is reference should always be directed from usage to declaration?
How to override text in hint like: 'Show usages of Some Class Impl'?

0

It looks like your element needs to implement PsiNameIdentifierOwner and have StringContent as its name identifier.
References from declaration to itself are possible, but strange. It's not a reference, after all, it's just a name.
For in-place rename, please override com.intellij.lang.refactoring.RefactoringSupportProvider#isInplaceRenameAvailable. You might also need to extend VariableInplaceRenameHandler, as some plugins do.
For element presentations in UI, please look at ElementDescriptionProvider implementations and add your own.

1
Avatar
Permanently deleted user

My question about reference was: we should declare reference from usage to declaration, not vice versa.
:)

My composite element is Named element and it is implements PsiNameIdentifierOwner and string content being returned. Not working anyway :)

I'm afraid that my English serves me bad. here we go:

Perl code:

my $test = <<'eom';     

   This is a text     

    Some text     

   test text 

eom


Here we got two psi elements:
  • Opener: <<'eom'
  • End marker: eom


Got reference from end marker to the opener.
When i set cursor to the end marker - both names highlighted correctly and renaming works fine (not inplace, btw. isInplaceRenameAvailable is not enough).
But, to be able to rename both elements from opener, i need to set cursor in the beginning of opener. Not it's real name.
Opener implements PsiNameIdentifierOwner
String content is just a LeafPsiElement

What is wrong?

Upd: made almost same reference for functions in the current file: inplace editing works; for markers - not. Single difference about them: for functions nameIdentifier == this for opening marker - not.

0
Avatar
Permanently deleted user

One more question about references:

We have:

  • Funciton declaration
  • Function definition
  • Function usage


Do i get it right, that i need to make a reference from usage to definition and other reference from definition to declaration?

What is poly-reference for? Ambiguous search results?

0

This looks like XML, where start and end tag names are to be renamed simultaneously. I don't remember exactly how it works, but you can debug in the area of XmlTag and TagNameReference and see it yourself.

0

I'm not sure I understand the difference between declaration and definition. If it's like in C header files, then you'd have to have references from usages to either declaration or definition (whatever you find more convenient), and some other kind of navigation between decl and def. For example, Goto Implementation (ImplementationSearch extension) or just gutter icons (LineMarkerProvider, RelatedItemLineMarkerProvider).

0
Avatar
Permanently deleted user

Thanks. Yes, exactly like in C.

Function may be declared in Perl and defined in some C extension, not available in source code.

0
Avatar
Permanently deleted user

Is it possible to split one lexer token into several PSI elements?

Problem:

Perl variable consists of sigil and variable name: $varname

Would be really nice to lex it as PERL_VARIABLE but make PsiSigil and PsiVarName from it.

0

No, to achieve that you should have separate tokens.

0
Avatar
Permanently deleted user

Completion question:

Implemented stubs for defined functions (awesome facility,btw)
Trying to use it in autocompletion.

Situation:

Have namespace Foo with function somefunc. Canonical name for it is Foo::somefunc

Starting to type `some`
In completion contributor i add all defined subs names in canonical form.

Problem 1: seems prefix filters out canonical name from resultset because it's not start with `some`, but with `Foo`
Problem 2: tried to set prefixMatcher to "", result is now in there, but, after choose it, i'm getting like: someFoo::somefunc (prefix is not removed, because I've reset it)
What is the proper way here?

One more question, is it possible to control cursor position on autocompletion to be able to autocomplete blocks, for example, like "if()" with cursor between parenteses?

Upd: seems it's not prefix filters it's out. Because there are results wich are not starts from prefix. But something definetly does.

0

LookupElement can have several lookup strings (see getAllLookupStrings method). So you can add another lookup string, that just corresponds to the function name.

0
Avatar
Permanently deleted user

Like a charm, thanks.
I'm so excited, can't sleep :)

0
Avatar
Permanently deleted user

Is there any particular reason for changing any whitespace tokens to the TokenType.WHITE_SPACE while creating PsiWhitespace?
It's not possible to distinct newlines from spaces without checking token text.
PsiComment generation behaviour seems more logical: same Psi but different TokenType

0

I've never seen this. org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes#mNLS is a whitespace token with a distinct element type, which seems to be preserved in PSI. Maybe the reason is it participates in org.jetbrains.plugins.groovy.lang.lexer.TokenSets#WHITE_SPACES_SET?

0
Avatar
Permanently deleted user

Token is different, but PsiBuilderImpl just creating PsiWhiteSpaceImpl for tokens from whitespace set and there is:

 
public PsiWhiteSpaceImpl(CharSequence text) {
  super(TokenType.WHITE_SPACE, text);
}


Original token type lost...


Got new question:

We have, let's say, SDK. Libraries coming with perl and installed using perl's facilities.
I'd like to parse and index them and be able to navigate through them and so on.

But:
1. It's a pretty different index. Don't want to put it with my project entities.
2. Would be really nice to share that index between all projects on this machine.
3. All entities from such files should be immutable. Reference should work (click-navigation) but renaming - should not.

What is the best practice here?

0

In GroovyParserDefinition.getWhitespaceTokens only TokenType.WHITE_SPACE is returned. mNLS is considered just another token, visible to the parser, with a possibility to have a special PSI wrapper type.

1. FileBasedIndex processes SDKs and libraries of all modules, so you can add your Perl stuff as one of those. For both index and navigation, you need to parse them, maybe in some special way.
2. Indexing results will be shared in all projects using that library/SDK.
3. Override PsiElement.isWritable. In addition, document modifications outside the project trigger warnings in the IDE anyway.

0
Avatar
Permanently deleted user

But if i won't add newline to the spaces tokenset i'll need to handle them in parser, right? I'll check sources, thanks.

1. For project sources i'm using stubs to navigate from function usages to definitions. Is it possible to use stubs in external libaries too? Or FileBasedIndex is the only way here?
2. Do You mean FileBasedIndex ?

0

Yes, you need to handle them in the parser.

Stub index is also a kind of file-based index. You will probably need stubs, it's perfectly possible to to use them in whatever file the index processes.

0
Avatar
Permanently deleted user

How matching parentheses/braces/brackets being hilighted?

I've done nothing about it, but parentheses are highilghted, others are not.

Upd: my bracematcher provides 3 groups:  () [] {} all non-structural.

First two works, braces are not.

0

You need PairedBraceMatcherAdapter (or a simpler PairedBraceMatcher).

0
Avatar
Permanently deleted user

What is the PsiElement and tree lifespan? Is it safe (and make sense) to cache some search results in PsiElement?
Does tree being fully re-created on each editing operation? Or partially?

For example:
For each declared variable, i am searching for scope container.
I'd like to find variable scope container on first pass, store it and re-use them on next requests.

0
Avatar
Permanently deleted user

Sorry, my mistake. Misplaced close token for braces.

0
Avatar
Permanently deleted user

What is getCodeConstructStart in BraceMatcher for?
I wrote some code, put a breakpoint and nothing.

It has been invoked few times with strange offsets and thats all.

Questions:
1. When it's being invoked? (need to debug)
2. How it affects editor?

0

PSI tree is partially or fully replaced on document commit.

The result you cache may depend on different things, and different strategies can be used. If it depends just on the subtree structure, you can cache things in your PSI element itself and clear in clearCaches method. Otherwise you can use CachedValueManager.getCachedValue(psi, provider) and specify dependencies, when this cache should be cleared. If your cache uses resolve, typical dependency is PsiModificationTracker.MODIFICATION_COUNT.

I don't know what a scope container is. If it's something in the same file, the dependency is probably element.getContainingFile(). But if the search is fast and straightforward, like PsiTreeUtil.getParentOfType, I wouldn't cache the result at all.

0
Avatar
Permanently deleted user

How to annotate file in project files tree as containing error (red wave under it) if there are some problems in tree?

0
Avatar
Permanently deleted user

Usually the files with syntax errors (PsiErrorElement present) or semantic errors (some annotator has reported error) are marked red automatically. If for some bizarre reason you absolutely want to mark the file red, the WolfTheProblemSolver.getInstance(project).weHaveGotProblems() can be used. In this case, however, you have to go into the troubles of clearing errors manually via WolfTheProblemSolver.getInstance(project).clearProblems() whenever applicable.

0
Avatar
Permanently deleted user

When the code construct (i.e. a method, a class etc) is very long, if the construct start (typically the line containing the opening brace) is not visible, IDEA displays a tooltip showing this construct start when you click on the closing brace.
By overriding this method, you can tell IDEA which part of your code you want to show in this tooltip.

0
Avatar
Permanently deleted user

How to handle file moving? I need to adjust some names in perl code if lib file been moved/renamed.
Renaming i can catch in setName/checkSetName, but seems moving is not invoking them.

0

请先登录再写评论。