如何为IntelliJ自定义DSL插件实现Java类与方法自动补全功能
核心说明
IntelliJ平台已经内置了完整的Java项目结构缓存,你不需要自行扫描项目类文件,直接调用平台提供的PSI(程序结构接口)和全局索引能力即可实现需求。
具体实现步骤
1. 补全位置匹配校验
首先需要在CompletionContributor中先判断当前光标所处的位置:是taskClass=后的属性值区域,还是taskMethod=后的属性值区域,避免在无关位置弹出Java相关补全项。
- 如果你已经完成了DSL的PSI语法解析,直接匹配对应属性值的PSI节点类型即可
- 如果还未做完整语法解析,可以通过
PatternCondition匹配当前输入的前缀特征判断字段类型
2. 实现taskClass的Java类补全
调用平台内置的JavaPsiFacade工具类获取项目范围内所有可见Java类,构造补全项:
// 获取当前项目实例 Project project = completionParameters.getPosition().getProject(); // 定义搜索范围,可根据需求调整为项目范围/包含依赖范围/测试代码范围 GlobalSearchScope searchScope = GlobalSearchScope.allScope(project); // 遍历所有索引中的Java类 JavaPsiFacade.getInstance(project).getAllClassNames(searchScope, className -> { PsiClass targetClass = JavaPsiFacade.getInstance(project).findClass(className, searchScope); if (targetClass != null && targetClass.getQualifiedName() != null) { // 构造补全项,内置类图标、类型提示,自动匹配大小写 completionResultSet.addElement( LookupElementBuilder.create(targetClass.getQualifiedName()) .withIcon(targetClass.getIcon(0)) .withTypeText("Java Class") .withCaseSensitivity(false) ); } return true; });
3. 实现taskMethod的Java方法补全
首先解析当前行中taskClass对应的全限定类名,找到对应的PSI类实例后遍历其公开方法构造补全项:
// 从当前行文本中解析出已填写的taskClass值,例如com.example.Foo String selectedClassName = parseTaskClassFromCurrentLine(completionParameters.getPosition()); if (selectedClassName == null) { return; } // 查找对应的类PSI实例 PsiClass selectedClass = JavaPsiFacade.getInstance(project) .findClass(selectedClassName, GlobalSearchScope.allScope(project)); if (selectedClass == null) { return; } // 遍历类的所有公开非构造方法 for (PsiMethod method : selectedClass.getMethods()) { if (method.hasModifierProperty(PsiModifier.PUBLIC) && !method.isConstructor()) { String returnTypeText = method.getReturnType() == null ? "" : method.getReturnType().getPresentableText(); // 构造方法补全项 completionResultSet.addElement( LookupElementBuilder.create(method.getName()) .withIcon(method.getIcon(0)) .withTypeText(returnTypeText) .withCaseSensitivity(false) ); } }
可选优化点
- 可以通过
completionResultSet.getPrefixMatcher()过滤匹配用户已输入的前缀,减少无效补全项 - 如果不需要补全JDK或第三方依赖中的类,可将搜索范围替换为
GlobalSearchScope.projectScope(project)提升查询速度 - 对于大型项目可以启用补全项的懒加载逻辑,避免阻塞输入
内容的提问来源于stack exchange,提问作者Jens D
相关产品推荐
相关产品推荐

