IntelliJ IDEA plugin development. Part 3
A bit of theory about projects and VFS. The previous part is here .
In IntelliJ IDEA, a project encapsulates all source codes, libraries, build scripts in a single organizational unit. All actions in IDEA take place in the context of the project. A project may contain collections of modules and libraries. Depending on the logical or functional requirements, you can create a single-module or multi-module project.
A module is a separate entity of functionality that can be launched, tested and debugged independently.
Modules include things like source code, build scripts, unit tests, etc. Each module in the project can use a specific SDK, or inherit the project SDK. Modules may depend on other modules in the project.
A library is compiled code in an archive (for example, a JAR file) on which modules depend.
IntelliJ IDEA Community Edition supports three types of libraries:
- module library - visible only in this module, information about it is saved in a * .iml file;
- project library - visible inside the entire project, information about it is saved in a * .ipr file;
- global library - information about it is stored in the applicationLibraries.xml file, the visibility of which applies to all projects.
Each project uses a Software Development Kit (SDK). For Java projects, there is a special type of SDK called the JDK (Java Development Kit). The SDK determines which API is used to build the project. In a multi-module project, by default, the SDK is inherited by all modules, but it is also possible to define separate SDKs for the respective modules.
Facet is the functionality associated with the module that tells how to interact with the contents of the module. A module can have multiple Facets.
IntelliJ IDEA Ultimate Edition has a setting in the project settings that allows you to assign Facets, unlike Community Edition, where Facet assignment is available only from the API.
From the point of view of the plugin developer, the structure of the project looks like the one shown in the figure below.
A project contains one or more modules. Each module includes the source code of the plugin and invokes an ordered set of entities related to the SDK and libraries. A module may have a Facets kit.
Work with project files, modules, libraries
IntelliJ IDEA saves configuration data to XML files. The list of these files depends on the format of the project.
For a file-based project format, the information is stored in the project file “plugin-name.ipr” itself. Information about the modules is stored in the "module-name.iml" files that are created for each module.
For a directory-based project format, the project settings are saved in several XML files in the .idea subdirectory. Each file is responsible for its own set of settings and has the corresponding name: projectCodeStyle.xml, encodings.xml, vcs.xml and so on. Module data is saved in * .iml files.
In order to work with projects and project files, there are several interfaces and classes:
- Project interface
- abstract class ProjectRootManager;
- ProjectManager abstract class
- ProjectFileIndex interface.
IntelliJ IDEA provides the following classes for working with modules:
- Abstract class ModuleManager;
- Module interface
- Abstract class ModuleRootManager;
- ModuleRootModel interface;
- class ModuleUtil;
- ModifiableModuleModel interface;
- ModifiableRootModel interface.
To get a list of libraries, you can list all the entities of the module and select instances of the LibraryOrderEntry interface. To get the classes contained in the library, you can use the Library.ModifiableModel.getUrls method.
For working with facet, there are classes DefaultFacetsProvider and Facet.
IntelliJ IDEA Virtual File System
Virtual File System (VFS) is an IntelliJ IDEA component that encapsulates most of the file functions. Serves for the following purposes:
- providing a universal API for working with files regardless of their physical location (on disk, in the archive, on an FTP server, etc.);
- tracking changes in files and providing both the old and new versions of their contents;
- Providing the ability to specify additional information for the file inside VFS.
In order to provide the last two functions, VFS creates snapshots (snapshots) of the contents on the hard drive. Only files that were requested at least once through the VFS programming interface and asynchronously update them in accordance with the changes occurring on the disk are included in the snapshot.
Snapshots work at the application level, so even with multiple links from various projects, the data is stored in a single copy.
All access operations go through a snapshot, if the requested information is not available, then it is loaded from disk. The contents of the files and the list of files in the directory are saved only if specific information is requested, in other cases only meta-information is saved (name, size, etc.).
All recording operations are synchronous, i.e. data is written to disk immediately.
IntelliJ IDEA performs an asynchronous operation to completely update content at startup. Also, by default, the update occurs when switching from another application, but this behavior can be configured on the “Settings | Synchronize files. "
The synchronization operation is based on timestamps; if the modification date has not changed, then IDEA does not update the contents of the file. Whenever possible, IntelliJ IDEA uses file observers built into the operating system (inotify, epoll, etc.).
Virtual file system events
All changes that occur with the virtual file system as a result of the update operation or due to user actions are called virtual file system events.
The most efficient way to monitor VFS events is to implement the BulkFileListener interface and subscribe to VirtualFileManager.VFS_CHANGES. This API provides a list of all changes that occurred during the update operation, which allows batch processing. An alternative way is to implement the VirtualFileListener interface and register it using VirtualFileManager.addFileListener (). This option allows you to process changes one by one.
Do not forget that the handlers work at the application level, therefore, receive events from all user-open projects. Therefore, in the first place, it is worth filtering out only events relevant to the active project.
During the update, events are generated only for files uploaded to the snapshot. Therefore, if a single file was uploaded via VirtualFile.findChild (), then the changes occurring with it will be monitored, but not with the neighbors in the directory.
In the next part: lexical, parsing, PSI, Stub index.