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 comments

This is not possible now and frameworks where it appears use dialog rename. We would fix that one day for sure. Thanks

0

Today I've found out that stubs creation being invoked even for non-physical elements.
Currently i'm working on one Perl framework support and namespaces there defined by file path. So it's not possible correctly detect namespace from LightVirtualFile, which contains only the name.
Seems, that PsiElement#isPhysical call in IStubElementType#shouldCreateStub condition solved the problems, but in this case there is a question: should we allow to create stubs from non-physical elements at all?

UPD: Seems this is a bad way to solve the problem. LightVirtualFiles being used extensively. So how should I solve my problem?

0

On some configuration changes, i need to recursively re-index some directories. With progress bar and so on. These directories may contain thousands of files.
But I couldn't do that. Some ways leads UI thread to lock, others re-indexing without any indication and somehow locking VFS system. What is the proper way here?

0

FileBasedIndex#requestReindex and my own Task.Backgroundable using FileBasedIndexImpl#getChangedFileCount to show progress seems works fine. Is it ok?

0

Pre-formatting of large files may take few seconds (too many Psi changes) and seems it's been run in UI thread, so everything is frozen and no way to notify user that something good is going on, not bad :) Is it possble to do something here?

0

Got a problem with formatting.
I've got a multi-line string and don't want it content to be formatted anyhow. The string is a single leaf formatting block with absolute none indent:
http://joxi.ru/xAeGbp7tYXGJKm.png

But, after re-formatting, all lines (except first one) being indented (looks like normal-except-first)

http://joxi.ru/eAOqBZbt4kPwMm.png
And on next re-formatting, block moves further, because added spaces been lexed to the string content tokens.
It's current release of IDEA.
What am I doing wrong?

0

I asked someone at JetBrains a while ago about this, since I'll probably need to do something similar in my plugin for Clojure.

Firstly, one comment was that this is considered a very bad code smell, since it implies that the index doesn't depend just on the file content, and this is a very basic invariant in the IntelliJ indexing system. However for very flexible languages like Clojure (and Perl, I guess) this is a sad reality - sometimes you need some sort of config to interpret the code.

What he recommended was to go with FileBasedIndex.requestReindex(VirtualFile) - this will rebuild all indices for that file. I only asked about file based indexes since that's all I use, but I believe that should also refresh stub indices since they use file based indexes under the hood. If you need to reparse those files as well, use PushedFilePropertiesUpdater#filePropertiesChanged instead (you might need to implement FilePropertyPusher for this, I'm not sure).

If you have a lot of files to update he recommended entering dumb mode, using code similar to PushedFilePropertiesUpdaterImpl#scheduleDumbModeReindexingIfNeeded. I think this is only in recent versions and will need to be copied into your code if you're supporting older versions.

    DumbModeTask task = FileBasedIndexProjectHandler.createChangedFilesIndexingTask(myProject);
    if (task != null) {
      DumbService.getInstance(myProject).queueTask(task);
    }



I also asked about just restarting the daemon analyzer, in case my change only affects local symbol resolution, not indexing. Here's the magic incantation for that:


      ((PsiModificationTrackerImpl)PsiManager.getInstance(project).getModificationTracker()).incCounter()
      PsiManager.getInstance(project).dropResolveCaches()
      DaemonCodeAnalyzer.getInstance(project).restart()

I haven't actually implemented any of this yet, but that seems to be the recommended approach.
1

Thank you for detailed answer.

0

I'm a bit confused. Logically, TemplatePreprocessor should preprocess templates, but, according to existing interface it may only manipulate with file and editor.
Shouldn't it alter and return textToInsert or something?

0
getInstance().requestRebuild(INDEX_ID);
Rehighlight: FileContentUtilCore.reparseFiles(virtualFile)
0

Doesn't requestRebuild() rebuild that index for the entire project?

0

As far as I know - it does. So this way is not ok here.
And what rehighlight means? Re-run highlighter? Index statys same?

0

There is no such thing as project for indices, since latters are calculated for virtual files (consider having same file in several projects).
However, some project level settings can affect indices if they are applied with language level pusher's (e.g. JavaLanguageLevelPusher assigns project specific language level pusher).

0

Oh crap, so indexed data MUST be project independent?

0

Can you describe briefly how the FilePropertyPushers work?

0

Another question - in Clojure, I would like the user to be able to configure which forms may create global symbols since this cannot be determined from the form itself. Thinking about it, if this configuration is changed, the var index (for global symbols) must be updated. I can either calculate the affected files and refresh them using requestReindex(VirtualFile) or just refresh the index globally using requestRebuild(). Having this config be global is ok, it doesn't need to be project-specific. But if the user modifies this configuration, then when future projects are opened I will need to reindex those too. Can I create a configuration hash or version which is used in the calculation of when an index is out of date and needs to be rebuilt?

0

BTW Alexandr, it would be good to ask new questions like this in a new thread - this one is massive and getting hard to find things in!

0

FilePropertyPusher associates some persistent property (FileAttribute) with virtual file and request file reindex if property changes, indexer uses this property during indexing.
E.g. SQLDialectPusher can assign/push "MySql" or "Oracle" language for particular sql file and the property will affect syntax parser used during indexing.

One can have different project specific properties (configurations) assigned to virtual file until only one project with the file is open.
Note, that some FilePropertyPusher's have the properties on application level even if they look as project level properties, e.g. dialect mapping for sql file changed in one project will change it for all projects (so there is no problem with different project specific properties).

0

This is usecase of FileBasedIndex.requestRebuild, e.g. TODOIndex is rebuilt this way upon TODO configuration change

0

Great, thanks Maxim, that's very interesting.

0

Hi.

TemplatePreprocessor was introduced for preparing editor before template evaluation. E.g. it's used for wrapping html with CDATA tag when you try to expand html-template inside JSPX, so before actual template expanding JspxTemplatePreprocessor inserts "<![CDATA[  ]]>" element and moves caret inside it. Maybe the name for this class is not the best but we cannot change it now in order to keep backward compatibility. Anyway, I'll write a javadoc for it.

As for preprocessing template text, you may want to look at `com.intellij.codeInsight.template.TemplateSubstitutor`. The substitutor can read a template, modify its text and return the new one.

0

1) You need to make sure there is a single (leaf) block covering all the content which should not be modified. The block should cover all unmodifiable whitespaces (indents). Alternatevely you may need to use read-only spacing if there are multiple blocks.
2) You need to implement DisabledIndentRangesProvider interface if you don't want the lines to be indented in operations like "Surround With". It receives an element like, for example, a statement and should find all the text ranges inside it which should never be indented.

0

Thank you!

I've found the root of my problem. AbstractBlock#getSubBlocks invokes buildChildren without checking isLeaf so my block's isLeaf returned proper result, but buildChildren collected and wrapped subelements.

0

Exactly one year ago i've started to work on Perl plugin :) Hurray!

0

Please sign in to leave a comment.