Striped document

Answered

A very basic need: I have a custom file type representing natural language text, and I would like to have it striped (alternating between a white and a light grey background colour, for instance). I have been searching on IntelliJ's supprt pages and through uncle Google, but can't seem to find an easy solution. Of course, I *could* define a complete language syntax for this, but I think it should be more basic.

I have defined a file type for these files, (even though .txt would be all right), and I suspect there is a very easy way to tell Idea thet all .striped files are to be striped ...

What have I missed?

 
 
10 comments
Comment actions Permalink

One way is to use Annotator, use com.intellij.psi.PsiPlainText element containing all text of file and calculate TextRange for each line, then call com.intellij.lang.annotation.AnnotationHolder#createInfoAnnotation(com.intellij.openapi.util.TextRange, java.lang.String) + com.intellij.lang.annotation.Annotation#setTextAttributes to perform the coloring

0
Comment actions Permalink

Thanks.
But this will cause constant parsing of the file, won't it? The formatting I want is so basic that I feel an Annotator is the wrong way to go.
Is there a way to implement a custom JTextArea under the JB Editor or perhaps simply applying a custom EditorColorsScheme or something? Wouldn't that be better?

 
 
0
Comment actions Permalink

Ofcourse you could also provide a custom editor implementation and do all the highlighting in pure Swing. But then you'll lose all the builtin editing functionality from IDE.

0
Comment actions Permalink

OK, we'll go the Annotator way, then. I wrote a little parserDefinition based on the plaintext parser definition, so my .striped files are recognized as a special file type, and the annotator should only be triggered for them.

But then, I was looking for a way to add my file type to the list of files that have soft-wrapping enabled, but I cannot find the documentation explaining how a plugin can tamper with the global Idea settings. Could you point me in the right diretion?

Thanks in advance

 
 
0
Comment actions Permalink

Please call `com.intellij.openapi.editor.EditorSettings#setUseSoftWraps` from listener matching "your" editors (com.intellij.openapi.editor.event.EditorFactoryListener#editorCreated)

0
Comment actions Permalink

Oh, I really would prefer to add my file suffix to the already existing list of «soft-wrap-suffixes» in the global settings, since I then wouldn't have to double that setting within my plugin's own settings, but I guess this solution will do for now.

But once again thanks for a to-the-point and swift reply!

0
Comment actions Permalink

It is possible to modify the setting, but the other way is more clean and would not lead to persistent changes, e.g. when your plugin is uninstalled again.

0
Comment actions Permalink

Back to the stripes again. I now have three file types using the stripes annotation. Two of them are just based on the plaintext parser definition, the third has its own language definition with syntax highlighting and code folding. When I test my plugin and edit the text in a file of this latter type, idea hangs (not forever, but for quite long). If I revoke the stripes annotation from this document (comment out the <annotator> tag in the plugin.xml file) before testing, it runs smooth and swift again.

Could this be me implementing the annotation in a bad way? Here's my implementation:

override fun annotate(element: PsiElement, holder: AnnotationHolder) {

val document = PsiDocumentManager.getInstance(element.project).getDocument(element.containingFile) ?: return

for (i in 0 until document.lineCount) {
val range = TextRange(document.getLineStartOffset(i), document.getLineEndOffset(i) + 1)

holder.createInfoAnnotation(range, null).run {
if (element.textRange.contains(range) && i % 2 == 0) {
textAttributes = grey
} else {
textAttributes = white
}
}
} // end for loop

// ... so the holder has document.lineCount elements. Let's hope it will not slow us down.

}

companion object {
val grey = TextAttributesKey.createTextAttributesKey("GREY_LINE", HighlighterColors.TEXT).apply {
defaultAttributes.backgroundColor = Color(228, 228, 228) //Color.LIGHT_GRAY
}
val white = TextAttributesKey.createTextAttributesKey("WHITE_LINE", HighlighterColors.NO_HIGHLIGHTING).apply {
defaultAttributes.backgroundColor = Color.WHITE
}

}
 
 
 
 
 
 
0
Comment actions Permalink

You're recreating highlightings for the whole document on every single passed in PsiElement, which can be a lot during editing or other modifications of underlying Document. AFAIU A very simple strategy to optimize this could be by storing document.lineCount (e.g. as CachedValue in element.containingFile) and skip recreating all highlighters if it's unchanged from previous invocation.

0
Comment actions Permalink

Oh, yes, that certainly made a huge difference! For fun I did a println() to see how often the method was run:

if (document.lineCount == cachedLinecount) {
println("Not redoing ...")
return
}

... and it flooded the logs endlessly. No wonder Idea was syrup ...

Thanks again, Yann..

0

Please sign in to leave a comment.