当前位置: 首页 > news >正文

wordpress green象山关键词seo排名

wordpress green,象山关键词seo排名,犀牛云网站建设,潮州东莞网站建设目标: 对于项目中的静态方法(主要是各种工具类里的静态方法),可以在输入方法名时直接提示相关的静态方法,选中后自动补全代码,并导入静态类。 设计: 初步构想,用户选择要导入的文…

目标:

对于项目中的静态方法(主要是各种工具类里的静态方法),可以在输入方法名时直接提示相关的静态方法,选中后自动补全代码,并导入静态类。

设计:

初步构想,用户选择要导入的文件夹,遍历文件夹下面文件的静态方法并存储,当用户输入时使用弹窗显示候选方法,选中后补全代码。
分解步骤为:

  1. 在设置页加入视图化操作,让用户选择文件夹路径;
  2. 通过持久化数据将选择的文件夹路径保存到本地;
  3. IDE打开时遍历本地保存的文件夹路径下的所有文件,得到所有静态方法;
  4. 用户输入时弹窗显示联想方法;
  5. 选中后自动补全;

开发:

1.搭建开发环境

JetBrains已经提供了纯样板模板,我们下载提供的插件模板 ,使用Android Studio (或IntelliJ IDEA )打开后,可以在gradle.properties中修改项目的属性,gradle.gradle.properties里各属性表示的意义如下

gradle.properties配置
  • pluginGrouppluginName_pluginVersion:插件名称与版本

  • pluginSinceBuildpluginUntilBuild:插件适用的IDE版本,从since到until,各种IDE的版本号可以在这个地方查阅内部编号范围

    Android Studio对应的IntelliJ 平台版本可以查阅Android Studio

  • pluginVerifierIdeVersions:用来检查IDE版本和插件之间兼容性

  • **platformType:**插件适用的IDE类型,IC指社区版,Android Studio基于社区版修改

  • platformPlugins: 声明插件依赖项

在这里插入图片描述

更多的属性可以查阅此链接

https://github.com/JetBrains/intellij-platform-plugin-template

https://github.com/JetBrains/gradle-intellij-plugin/blob/master/README.md#intellij-platform-properties

plugin.xml

文件位于src\main\resources\META-INF下

  • id:gradle.properties里的pluginName_

  • name: gradle.properties里的pluginName_

  • vendor:开发者的名字
    在这里插入图片描述

    添加依赖

在这里插入图片描述

build.gradle.kts

在intellij节点下加入一句intellij

alternativeIdePath = "H:\Android\Android Studio"

在这里插入图片描述

路径设置为本地Android Studio位置,这样在运行时会直接使用本地的AS调试,避免重新下载Android Studio。

settings.gradle.kts

修改项目名称

rootProject.name = "Plugin Template Hint"

配置完成后,点击右边的gradle的runide即可运行插件,如果开发过程中想进行调试可以右键选择debug模式。

在这里插入图片描述

2.设置页添加视图化操作

在IDE的设置页添加新UI,需要使用applicationConfigurable Extension Points。 先在plugin.xml里注册applicationConfigurable,并且新建类继承Configurable。插件的UI模块是在java的swing组件基础上直接包装了一层,可以直接使用。

    <extensions defaultExtensionNs="com.intellij">......<applicationConfigurable instance="com.plugin.hint.other.UtilsImportUI" /></extensions>
class UtilsImportUI : Configurable {private val persistentState: UtilsFolderSetting = ApplicationManager.getApplication().getComponent(UtilsFolderSetting::class.java)private var isModify = false//绘制界面,使用Swing组件override fun createComponent(): JComponent? {//......绘制代码此处省略}//控制按钮“Apply”是否可点击override fun isModified(): Boolean {return isModify}//"Apply"按钮点击事件override fun apply() {......persistentState!!.list = pathListpersistentState.loadState(persistentState)//持久化数据isModify = false                }//配置面板左边窗口的显示名称override fun getDisplayName(): String {return "Import Utils Files"}//调用IDE的文件管理器选择文件private fun dir(jPanel: JPanel): String {if (project == null) {project = guessCurrentProject(jPanel)}val fcDial = FileChooserFactory.getInstance().createFileChooser(fcDesc, project, null)val files = fcDial.choose(project)return if (files.isNotEmpty()) {files[0].path} else ""}	
}

上面省略了部分代码,主要是绘制界面、持久化数据、保存用户选中的文件位置,并进行相关的去重。

效果如下:

在这里插入图片描述

3.持久化数据

为了保存用户选择的文件夹路径,我们需要对数据进行持久化。
在plugin.xml里注册implementation-class,并且新建类继承PersistentStateComponent,其中,name为XML中根标记的名称,storages 为保存的文件的名称,默认位置是配置文件地址的options目录下(默认位置可以点击File -> Mange IDE Settings -> Export Settings 查看)。

我们将路径通过list保存,读取时

    <application-components><component><implementation-class>com.plugin.hint.other.UtilsFolderSetting</implementation-class></component></application-components>
@State(name = "searchUtilsPath", storages = [Storage(value = "searchUtilsPath.xml")])
class UtilsFolderSetting : PersistentStateComponent<UtilsFolderSetting?> {var list: MutableList<String> = ArrayList()override fun getState(): UtilsFolderSetting {return this}override fun loadState(state: UtilsFolderSetting) {XmlSerializerUtil.copyBean(state, this)}
}
4.启动时遍历文件,保存静态方法

工程模板service下有两个类MyApplicationServiceMyProjectService,分别是 application 级别的service和 project 级别的service,其实还有一个module 级别的service,但是并不推荐(性能原因)。其中MyApplicationService为全局单例,而MyProjectService会在对应范围的每个实例创建一个单独的服务实例。这里我们在MyProjectService里遍历文件夹路径,对所有文件进行解析,并保存静态方法。

 class MyProjectService(project: Project) {init {if (project.workspaceFile != null) {val persistentState = ApplicationManager.getApplication().getComponent(UtilsFolderSetting::class.java)val pathList = persistentState.list//得到持久化数据for (s in pathList) {//遍历文件夹路径UtilMethodsHandle.addPsiMethodByPath(s, project)}}}
}

persistentState 为得到的持久化数据,然后再对文件路径进行解析。
addPsiMethodByPath方法如下,逻辑可以看注释

    var globalPsiMethods = HashMap<String, List<PsiMethod>>()//遍历文件夹,解析文件,存储方法fun addPsiMethodByPath(path: String, project: Project) {val virtualFile = project.workspaceFile!!.fileSystem.findFileByPath(path) ?: returnif (virtualFile.isDirectory) {//如果是文件夹,递归遍历val virtualFiles = virtualFile.childrenfor (file in virtualFiles) {addPsiMethodByPath(file.path, project)}} else {//如果是文件,解析val psiFile = PsiManager.getInstance(project).findFile(virtualFile)//判断是否是java文件,后面看是否支持kotlin文件if (psiFile is PsiJavaFile) {val classes = psiFile.classes //遍历文件里的类,因为可能会有内部类for (aClass in classes) {val tempMethods = aClass.methodsval list: MutableList<PsiMethod> = ArrayList()//遍历类里面的方法for (method in tempMethods) {//判断是静态并且不是私有的方法if (method.hasModifierProperty(PsiModifier.STATIC)&& !method.hasModifierProperty(PsiModifier.PRIVATE)) {list.add(method)}}globalPsiMethods[path] = list}}}}

解释上面的代码,需要先了解IntelliJ平台的一些名称概念。

PSI 程序结构接口(Program Structure Interface),是IntelliJ平台中的一个层,负责解析文件并创建支持平台许多功能的语法和语义代码模型。

PSI File ,IDEA将文件结构抽象为接口,叫程序结构接口文件(PSI File),不同类型的文件解析后生成不同的PsiFile接口的实现类实例,这也是IDEA能够扩展支持多语言的基础。PsiFile类是所有PSI文件的公共基类,而在特定的语言文件通常是由它的子类来表示。例如,PsiJavaFile类表示Java文件,XmlFile类表示XML文件。

VirtualFileSystem 虚拟文件系统(VFS)是IntelliJ平台的组件,该组件封装了用于处理以Virtual File表示的文件的大部分活动。
它具有以下主要目的:
提供一个通用API来处理文件,而不管文件的实际位置如何(在磁盘上,在归档中,在HTTP服务器等上)
当检测到更改时,跟踪文件修改并提供文件内容的旧版本和新版本。
提供了将其他持久性数据与VFS中的文件相关联的可能性。
Virtual File System

上面的代码通过project得到VirtualFile,判断如果是文件夹,递归调用方法,否则返回相对应的PsiFile,接着判断如果是PsiJavaFile(因为项目有可能包含kotlin文件),则遍历PsiClass(有可能包含内部类)得到所有PsiMethod,最后判断method是否是静态的(method.hasModifierProperty(PsiModifier.STATIC))并且不是私有的(!method.hasModifierProperty(PsiModifier.PRIVATE)),最后加入列表。

5.用户输入时自动弹窗显示联想方法

这里的两种方案,其实最开始使用的是第一种方法,在IDE自带的代码补全弹窗里插入我们保存的方法,但是这种方案没有解决方法显示排序的问题,提供的 order="first"属性并没有生效,最后使用了第二种方案。这里记录一下,可能以后在写其他插件时会用到。

第一种方案:

我们在plugin.xml里注册CompletionContributor languageJAVA

    <extensions defaultExtensionNs="com.intellij">......<completion.contributorimplementationClass="com.plugin.hint.other.UtilsCompletionContributor" language="JAVA"order="first" /></extensions>

CompletionContributor,实现extend函数,有三个参数

  1. CompletionType:代码完成的类型,基本完成(BASIC)、智能类型(SMART)匹配完成,Settings/Preferences | Editor | General | Code Completion里可选.
    在这里插入图片描述
  2. ElementPattern:匹配类型,可以对返回的元素进行过滤
  3. CompletionProvider:内容提供者,我们在这里返回待选择的
class UtilsCompletionContributor : CompletionContributor() {//查找可以自动补全的代码init {extend(CompletionType.BASIC, PlatformPatterns.psiElement(), UtilsCompletionProvider())}
}

UtilsCompletionProvider类,继承CompletionProvider,重写addCompletions方法,将元素加入到CompletionResultSet

class UtilsCompletionProvider : CompletionProvider<CompletionParameters>() {//添加自动补全代码override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {val prefix = result.prefixMatcher.prefixif (prefix.isEmpty()) {return}for (methodList in UtilMethodsHandle.globalPsiMethods.values) {for (method in methodList) {var s: String? = ""if (method.containingClass != null) {s = method.containingClass!!.qualifiedName//类名称}val element: LookupElement = LookupElementBuilder.create(method).withTypeText(s)//右边文字//.withIcon(MethodIcon).withIcon(AllIcons.Nodes.MethodReference)//左边图标.withBoldness(true)//是否加粗//选中后的处理事件.withInsertHandler { context1: InsertionContext, lookupElement: LookupElement? ->context1.document.insertString(context1.startOffset, ".")context1.document.insertString(context1.tailOffset, "();")//导入所引用的类JavaCompletionUtil.insertClassReference(method.containingClass!!, context1.file, context1.startOffset)//移动光标到代码尾部               context1.editor.caretModel.moveToOffset(context1.tailOffset - 2)}//添加element到代码补全弹窗result.addElement(PrioritizedLookupElement.withPriority(element, Int.MAX_VALUE.toDouble()))}}

上面代码,先检测是否有匹配的,否则返回。然后循环创建LookupElement。InsertHandler为选中后的操作,在这里补全代码,引入当前方法所在类。

如上图,在自带的代码补全弹窗里添加了2条我们的方法。

第二种方案:
在用户输入后使用快捷键呼出代码补全弹窗,使用Action完成。IntelliJ 平台中的Action需要代码实现并且必须注册。注册决定了Action在 IDE UI 中出现的位置。实现并注册后,Action会接收来自 IntelliJ 平台的回调以响应用户。
1.创建UtilsAction类,继承 Action类。当使用键盘快捷键或从菜单、工具栏操作时,就会回调 Action 类的 actionPerformed 方法。
先在plugin.xml里注册Action,这里默认的快捷键是"control shift X"

    <actions><action class="com.plugin.hint.other.UtilsAction" description="方法提示" id="plugin.hint" text="hint"><add-to-group anchor="first" group-id="CodeCompletionGroup" /><keyboard-shortcut first-keystroke="control shift X" keymap="$default" /></action></actions>

效果如图,Code Completion组下添加了我们新建的Action,在这里也可以更改快捷键。
在这里插入图片描述
UtilsAction类里,我们在actionPerformed 方法里弹出代码补全弹窗。searchText为用户输入的需要补全的代码。LookupImpl为为代码补全的弹窗。选中逻辑与第一种方案一样。

class UtilsAction : AnAction() {override fun actionPerformed(e: AnActionEvent) {......//需要查找的字符val searchText = StringBuilder()//selectedText表示光标选中的文本,如果不为空,则查找选中的,没有就从光标位置向前拼接字符,一直到空格为止if (editor.selectionModel.selectedText == null|| editor.selectionModel.selectedText == "") {var indexText = document.text.subSequence(startOffset - 1, startOffset).toString()while (startOffset > 0 && nameMatch(indexText)) {searchText.insert(0, indexText)startOffset--indexText = document.text.subSequence(startOffset - 1, startOffset).toString()}} else {searchText.append(editor.selectionModel.selectedText)}if (project != null) {val lookup = obtainLookup(editor, project)for (methodList in UtilMethodsHandle.globalPsiMethods.values) {for (method in methodList) {var qualifiedName: String? = ""if (method.containingClass != null) {qualifiedName = method.containingClass!!.qualifiedName}LOG.info("actionPerformed: $method+$qualifiedName")if (!method.isValid) continue//检查元素是否有效,比如切换分支后就会失效//创建一个element,与第一种方案一样val element: LookupElement = LookupElementBuilder.create(method).withTypeText(qualifiedName).withIcon(MethodIcon)//.withIcon(AllIcons.Nodes.MethodReference).withBoldness(true)val item = CompletionResult.wrap(element, PlainPrefixMatcher(searchText.toString()), CompletionSorter.emptySorter())if (item != null) {//将element添加进去lookup.addItem(item.lookupElement, item.prefixMatcher)}}}lookup.addLookupListener(object : LookupListener {override fun itemSelected(event: LookupEvent) {//item选中事件,与val lookupElement = event.item as LookupElementif (lookupElement.psiElement is PsiMethod) {//如果选中的element是方法val psiMethod = lookupElement.psiElement as PsiMethod//得到上下文InsertionContextval insertionContext = InsertionContext(OffsetMap(document), Lookup.AUTO_INSERT_SELECT_CHAR, arrayOf(lookupElement), psiFile!!, editor, false)//val tailOffset = OffsetMap(document).getOffset(InsertionContext.TAIL_OFFSET)//如果是选中状态,计算开始位置需要减去字符长度if (startOffset == start) startOffset -= searchText.lengthdocument.insertString(startOffset, ".")document.insertString(insertionContext.tailOffset, "();")//导入所引用的类JavaCompletionUtil.insertClassReference(psiMethod.containingClass!!, psiFile, startOffset)//移动光标到代码尾部editor.caretModel.moveToOffset(insertionContext.tailOffset - 2)}}})lookup.showLookup()//显示弹窗}private fun obtainLookup(editor: Editor, project: Project): LookupImpl {val lookup = LookupManager.getInstance(project).createLookup(editor, LookupElement.EMPTY_ARRAY, "",DefaultArranger()) as LookupImpl/*        if (editor.isOneLineMode) {lookup.setCancelOnClickOutside(true)lookup.setCancelOnOtherWindowOpen(true)}*///lookup.lookupFocusDegree = if (autopopup) LookupFocusDegree.UNFOCUSED else LookupFocusDegree.FOCUSEDreturn lookup}}

这里使用的代码补全弹窗是系统自带的弹窗,在这里说一下怎么找到各种UI相对应的类。
我们需要启用内部模式。在idea.properties里添加idea.is.internal=true,保存并重启IDE。会看到Tool中多了一个选项Internal Actions,然后选择 UI -> UI Inspector,打开 UI 检查器,启用之后就可以以交互方式测试UI元素。查看时,将光标居中于UI元素上,使用Ctrl+Alt+鼠标左键即可显示UI元素的内部描述.。
效果如图,可以看到相关的类,然后就可以再去找到具体的实现方法。
在这里插入图片描述

最终效果如下:
在这里插入图片描述

相关资料

IntelliJ Platform SDK

使用PSI分析Java代码

Intellij IDEA 插件开发秘籍

http://www.ritt.cn/news/18746.html

相关文章:

  • 电脑建网站公关策划公司
  • 大渡口区网站建设百度提问
  • 还是新能源专业好阿里巴巴怎么优化关键词排名
  • 怎么在网上找做网站的客户百度热搜词排行榜
  • 做网站的支付怎么做营销推广
  • 深圳找网站建设公司谷歌浏览器官网入口
  • 建站cms源码上海app开发公司
  • 全国网站备案咨询电话seo优化效果怎么样
  • 上海十大网站建设怎么制作一个网页
  • 企业管理六大体系网站关键词搜索排名优化
  • 个人网站设计论文下载互联网营销师是干什么
  • 简单的旅游网站怎么做兰州正规seo整站优化
  • 数码网站模板免费域名申请个人网站
  • 系统开发人员有哪几类北京seo平台
  • 做淘宝客怎样建网站手机系统优化软件
  • 哪里找免费网站微营销是什么
  • 做阿里巴巴小企业网站泰州百度公司代理商
  • 网上做网站的自己的网站怎么建立
  • 广州购物网站公司地址抖音seo排名软件
  • 建设银行信用卡官网站首页海外推广渠道
  • 无锡网站开发befen什么是seo标题优化
  • 陕西咸阳网站建设旺道seo软件技术
  • 溧水网站建设北京搜索引擎关键词优化
  • 如何做网站销售滕州今日头条新闻
  • 网站推广在哪些平台做外链郑州seo网站排名
  • 禁止网页跳转微信小程序一键关键词优化
  • 郑州做旅游网站qq群怎么优化排名靠前
  • 怎么给自己的网站做优化站长工具seo综合查询
  • 什么是网站建设流程图百度客户服务电话
  • wordpress主题视频站百度认证营销顾问