how to work back from a psiElement to the versioned library that provided the file?
I noticed that that libraries that use gobject introspection, such as gtk, glib and gimp have gobject introspection files containing xml of all their types, classes and methods: This would be useful to generate on-the-fly documentation for these libraries.
However the problem that I am running into, is that clion workspace/project model doesn't seem to know anything about which package (pkg-config, from meson in this case) provided the file.
See this one from gimp for example

and this can be used to created html docs on the fly like so:

At the moment, the docs are pretty basic:

So I think it would be straightforward to display that html in the doc hover, but I need to work back from (for example) hovering a “gtk_box_new” function, whcih is provided by gtk+-3.0 :
Dump of properties of psiElement above:
acquire: {CACHED_SMART_POINTER_KEY=java.lang.ref.SoftReference@30a10704, Original element=psi:range=(436,450),type=Identikit(class='com.intellij.psi.impl.source.tree.LeafPsiElement', elementType=IDENTIFIER, fileLanguage='ObjectiveC'), SEM=SemData{count=0}}argumentList: nullarrayLengths: []baseIcon: PatchedRasterizedImageDataLoader(classLoader=PluginClassLoader(plugin=PluginDescriptor(name=CIDR Base, id=com.intellij.cidr.base, descriptorPath=plugin.xml, path=~/.gradle/caches/8.13/transforms/043ce6f9136bf368ebef038438c7b070/transformed/CLion-2025.1.1/plugins/cidr-base-plugin, version=251.25410.104, package=null, isBundled=true), packagePrefix=null, state=active, parents=PluginDescriptor(name=Native Debugging Support, id=com.intellij.nativeDebug, descriptorPath=plugin.xml, path=~/.gradle/caches/8.13/transforms/043ce6f9136bf368ebef038438c7b070/transformed/CLion-2025.1.1/plugins/nativeDebug-plugin, version=251.25410.104, package=null, isBundled=true), ), path=icons/expui/codeAssistantFunction.svg)children: [OCParameterList]class: class com.jetbrains.cidr.lang.psi.impl.OCDeclaratorImplcomplexOffset: 7387343749120containingFile: OCFile:gimpframe.hcontainingOCFile: OCFile:gimpframe.hcontext: OCFunctionDeclaration(gimp_frame_new)declarationContext: com.jetbrains.cidr.lang.symbols.DeclarationContext@2fb9cfd0empty: falseextendedContext: OCFunctionDeclaration(gimp_frame_new)firstChild: PsiElement(OCPunctuator:*)identifyingElement: PsiElement(IDENTIFIER)initializerList: nullinitializer: nullinitializers: []language: Language: ObjectiveClastChild: OCParameterListlocalSymbol: FUNCTION_PREDECLARATION《》[gimp_frame_new]@gimpframe.h:1720manager: {}modifiersText: *name: gimp_frame_newnameIdentifier: PsiElement(IDENTIFIER)namespaceQualifier: nullnavigationElement: OCDeclarator(gimp_frame_new)nextSibling: PsiElement(OCPunctuator:;)node: Element(DECLARATOR)opaque: {CACHED_SMART_POINTER_KEY=java.lang.ref.SoftReference@30a10704, Original element=psi:range=(436,450),type=Identikit(class='com.intellij.psi.impl.source.tree.LeafPsiElement', elementType=IDENTIFIER, fileLanguage='ObjectiveC'), SEM=SemData{count=0}}originalElement: OCDeclarator(gimp_frame_new)ownDeclarations: []ownReferences: []parameterList: OCParameterListparent: OCFunctionDeclaration(gimp_frame_new)physical: trueplain: {CACHED_SMART_POINTER_KEY=java.lang.ref.SoftReference@30a10704, Original element=psi:range=(436,450),type=Identikit(class='com.intellij.psi.impl.source.tree.LeafPsiElement', elementType=IDENTIFIER, fileLanguage='ObjectiveC'), SEM=SemData{count=0}}pointerToFunction: falsepossibleStructMember: false....presentation: com.jetbrains.cidr.lang.navigation.OCSymbolPresentation@7c57192fprevSibling: PsiWhiteSpaceproject: Project(name=gimp-lqr-plugin, containerState=COMPONENT_CREATED, componentStore=/home/user/git/gimp-lqr-plugin)rangeInCallElement: (2,16)rangeWithMacros: (1718,1761)rawType: OCFunctionType[GtkWidget *(const gchar *)]reference: com.jetbrains.cidr.lang.psi.impl.OCDeclaratorImpl$MyReference@373bdc0creferences: [com.jetbrains.cidr.lang.psi.impl.OCDeclaratorImpl$MyReference@373bdc0c]resolvedType: OCFunctionType[GtkWidget *(const gchar *)]resolveScope: com.intellij.openapi.roots.impl.LibraryScopeCache$1[com.intellij.openapi.module.impl.scopes.LibraryRuntimeClasspathScope@4154f]startOffsetInParent: 10symbol: FUNCTION_PREDECLARATION《》[gimp_frame_new]@gimpframe.h:1720symbolName: gimp_frame_newtemplateArgumentList: nulltext: * gimp_frame_new (const gchar *label)textLength: 43textOffset: 1720textRange: (1718,1761)textRangeInParent: (10,53)textWithMacros: * gimp_frame_new (const gchar *label)type: OCFunctionType[GtkWidget *(const gchar *)]userDataEmpty: falseuserDataString: {CACHED_SMART_POINTER_KEY=java.lang.ref.SoftReference@30a10704, Original element=psi:range=(436,450),type=Identikit(class='com.intellij.psi.impl.source.tree.LeafPsiElement', elementType=IDENTIFIER, fileLanguage='ObjectiveC'), SEM=SemData{count=0}}userMap: {CACHED_SMART_POINTER_KEY=java.lang.ref.SoftReference@30a10704, Original element=psi:range=(436,450),type=Identikit(class='com.intellij.psi.impl.source.tree.LeafPsiElement', elementType=IDENTIFIER, fileLanguage='ObjectiveC'), SEM=SemData{count=0}}useScope: Union: (com.jetbrains.cidr.lang.search.scopes.OCSearchScopeService$1[com.intellij.core.CoreProjectScopeBuilder$ContentSearchScope@3],Libraries)valid: truevisibilitySupported: falsewritable: false
I can extract from the containingOCFile the absolute path to the providing library like so:
val virtualFile = element.containingFile?.virtualFileprintln("containingFile?.virtualFile = $virtualFile")
and that will give me:/usr/include/gimp-3.0/libgimpwidgets/gimpframe.h
Which is a good start. I could do some regular expression to pull the “gimp-3.0” out of the string. But it seems to me that projects build with meson or Makefile in clion, already know where the file came from, so clion, knows which library that path maps to?
How to pull this information out of clion in a plugin?
The idea being, that if this can be done for gimp-3.0, it can also be done for all the libraries that have gobject introspection data, which is quite a lot:
[gimp-lqr-plugin] $ find /usr/share/ -type f -name ‘*.gir’/usr/share/gir-1.0/Libxfce4util-1.0.gir/usr/share/gir-1.0/Xfconf-0.gir/usr/share/gir-1.0/Libxfce4ui-2.0.gir/usr/share/gir-1.0/Garcon-1.0.gir/usr/share/gir-1.0/GarconGtk-1.0.gir/usr/share/gir-1.0/Libxfce4panel-2.0.gir/usr/share/gir-1.0/ICal-3.0.gir/usr/share/gir-1.0/ICalGLib-3.0.gir/usr/share/gir-1.0/GIRepository-3.0.gir/usr/share/gir-1.0/GLib-2.0.gir/usr/share/gir-1.0/GLibUnix-2.0.gir/usr/share/gir-1.0/GModule-2.0.gir/usr/share/gir-1.0/GObject-2.0.gir/usr/share/gir-1.0/Gio-2.0.gir/usr/share/gir-1.0/GioUnix-2.0.gir/usr/share/gir-1.0/DBus-1.0.gir/usr/share/gir-1.0/DBusGLib-1.0.gir/usr/share/gir-1.0/GIRepository-2.0.gir/usr/share/gir-1.0/GL-1.0.gir/usr/share/gir-1.0/Vulkan-1.0.gir/usr/share/gir-1.0/cairo-1.0.gir/usr/share/gir-1.0/fontconfig-2.0.gir/usr/share/gir-1.0/freetype2-2.0.gir/usr/share/gir-1.0/libxml2-2.0.gir/usr/share/gir-1.0/win32-1.0.gir/usr/share/gir-1.0/xfixes-4.0.gir/usr/share/gir-1.0/xft-2.0.gir/usr/share/gir-1.0/xlib-2.0.gir/usr/share/gir-1.0/xrandr-1.3.gir/usr/share/gir-1.0/GdkPixbuf-2.0.gir
Please sign in to leave a comment.
The issue seems to be that according to the docs here : https://plugins.jetbrains.com/docs/intellij/library.html?from=jetbrains.org
val module = ModuleUtilCore.findModuleForPsiElement(element)should return something, but its always null for me. It seems like meson must know this information, but clion doesn't have access to it?
ok, I see I was looking at the element and not the containingFile, but even looking at the right element, I get
So its just a generic container for all the include paths. However, clion clearly does know which library is which, because I have 4 different gtkbox.h on my system in the include paths:
$ find /usr/include/ -name gtkbox.h/usr/include/gtk-3.0/gtk/gtkbox.h/usr/include/gtk-2.0/gtk/gtkbox.h/usr/include/gtk-1.2/gtk/gtkbox.h/usr/include/gtk-4.0/gtk/gtkbox.hand its picking the right one, so its either got the meson external model available, or its making a guess, or something
Hello!
Sorry for the delay in response. Could you please clarify if you're creating a plugin for CLion Nova or CLion Classic?
I am using classic
Currently I don't see any documentation or examples on how one would go about developing a plugin for nova, and nova seems buggy (indexing failing and hanging) so would leave that until it was stable and documented