feat: 2.20 support Vue src/router tree doc | 支持 Vue 路由标题文件树注释

This commit is contained in:
林万程
2025-01-29 22:25:17 +08:00
parent 035d8d590a
commit 49147b0e7b
23 changed files with 444 additions and 106 deletions

View File

@@ -14,7 +14,7 @@ Show doc comment in the Project view Tree, line End, json, other
<ul>
<li>Java, Kotlin, Groovy, Scala
<li>C/C++/OC, Python, Go, Rust, Ruby
<li>JS/TS, PHP, SQL
<li>HTML(Vue), JS/TS, PHP, SQL
<li>YAML/yml
</ul>
@@ -125,6 +125,7 @@ Show doc comment in the Project view Tree, line End, json, other
<h2>English Change Notes:</h2>
<ul>
<li>2.20 Add External Comment support Vue src/router tree doc
<li>2.19 ★ line-end-comment support HTML(Vue) Tag/Attr doc since 2022.3.1
<li>2.18 Add line-end-comment support injected language like SQL
<li>2.17 Add External Comment support *.key.regexp and MyBatis xml demo in Git
@@ -173,6 +174,7 @@ Show doc comment in the Project view Tree, line End, json, other
<h2>中文更新说明:</h2>
<ul>
<li>2.20 增加 外部注释 支持 Vue 路由标题文件树注释
<li>2.19 ★ 行末注释 支持 HTML(Vue) 标签/属性 注释从 2022.3.1 起
<li>2.18 增加 行末注释 支持注入语言如 SQL
<li>2.17 增加 tsv 注释 支持 *.key.regexp 与 Mybatis xml 示例在 Git

View File

@@ -4,7 +4,7 @@ plugins {
}
group 'io.github.linwancen'
version '2.19.0.' + (new Date().format('yyyy.MM.dd_HH.mm'))
version '2.20.0.' + (new Date().format('yyyy.MM.dd_HH.mm'))
repositories {
mavenCentral()
@@ -95,6 +95,7 @@ patchPluginXml {
changeNotes = """
<h2>English Change Notes:</h2>
<ul>
<li>2.20 Add External Comment support Vue src/router tree doc
<li>2.19 ★ line-end-comment support HTML(Vue) Tag/Attr doc since 2022.3.1
<li>2.18 Add line-end-comment support injected language like SQL
<li>2.17 Add External Comment support *.key.regexp and MyBatis xml demo in Git
@@ -143,6 +144,7 @@ patchPluginXml {
<h2>中文更新说明:</h2>
<ul>
<li>2.20 增加 外部注释 支持 Vue 路由标题文件树注释
<li>2.19 ★ 行末注释 支持 HTML(Vue) 标签/属性 注释从 2022.3.1 起
<li>2.18 增加 行末注释 支持注入语言如 SQL
<li>2.17 增加 tsv 注释 支持 *.key.regexp 与 Mybatis xml 示例在 Git

View File

@@ -139,6 +139,7 @@ public class LineEndCacheUtils {
}
}).inSmartMode(project).executeSynchronously();
}));
} catch (ProcessCanceledException ignored) {
} catch (IllegalStateException ignore) {
// ignore inSmartMode(project) throw:
// @NotNull method com/intellij/openapi/project/impl/ProjectImpl.getEarlyDisposable must not return null

View File

@@ -1,9 +1,9 @@
package io.github.linwancen.plugin.show.ext.conf.action;
package io.github.linwancen.plugin.show.ext.action;
import com.intellij.ide.actions.CopyReferenceAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import io.github.linwancen.plugin.show.ext.conf.ConfCache;
import io.github.linwancen.plugin.show.ext.listener.FileLoader;
import io.github.linwancen.plugin.show.settings.ShowBundle;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -29,7 +29,7 @@ public class ReloadExtDocAction extends CopyReferenceAction {
if (project == null) {
return;
}
ConfCache.loadAll(project);
FileLoader.EPN.getExtensionList().forEach(fileLoader -> fileLoader.loadAll(project));
} catch (Throwable t) {
LOG.info("ReloadExtDocAction catch Throwable but log to record.", t);
}

View File

@@ -1,11 +1,11 @@
package io.github.linwancen.plugin.show.ext.conf.action;
package io.github.linwancen.plugin.show.ext.action;
import com.intellij.ide.actions.CopyReferenceAction;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import io.github.linwancen.plugin.show.ext.conf.ConfCache;
import io.github.linwancen.plugin.show.ext.listener.FileLoader;
import io.github.linwancen.plugin.show.settings.ShowBundle;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -28,7 +28,7 @@ public class ResetExtDocAction extends CopyReferenceAction {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
try {
ConfCache.clearAll();
FileLoader.EPN.getExtensionList().forEach(FileLoader::clearAll);
@Nullable Project project = e.getProject();
if (project == null) {
return;

View File

@@ -0,0 +1,4 @@
/**
* call ConfCache clear and loadAll
*/
package io.github.linwancen.plugin.show.ext.action;

View File

@@ -1,11 +1,10 @@
package io.github.linwancen.plugin.show.ext.conf;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.FilenameIndex;
import io.github.linwancen.plugin.show.ext.listener.FileLoader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
@@ -23,7 +22,7 @@ import java.util.regex.Pattern;
/**
* call ConfFactory, ConfCacheGetUtils
*/
public class ConfCache {
public class ConfCache extends FileLoader {
private static final Logger LOG = LoggerFactory.getLogger(ConfCache.class);
static final String KEY_MID_EXT = ".key";
@@ -74,7 +73,13 @@ public class ConfCache {
return ConfCacheGetUtils.filterPath(JSON_CACHE, path);
}
public static void clearAll() {
@Override
public boolean skipExt(@Nullable String extension) {
return !TsvLoader.EXT.equals(extension) && !TsvLoader.REGEXP_EXT.equals(extension);
}
@Override
public void clearAll() {
EXT_IN_KEY_CACHE.clear();
KEY_CACHE.clear();
DOC_CACHE.clear();
@@ -82,11 +87,15 @@ public class ConfCache {
JSON_CACHE.clear();
}
public static void remove(@NotNull VirtualFile file, @Nullable String name) {
@Override
public void remove(@NotNull VirtualFile file, @Nullable String name) {
if (name != null) {
int i = name.lastIndexOf('.');
@NotNull String ext = name.substring(i + 1);
if (skipExt(ext)) return;
name = name.substring(0, i);
} else {
if (skipExt(file.getExtension())) return;
name = file.getNameWithoutExtension();
}
if (name.endsWith(KEY_MID_EXT)) {
@@ -100,8 +109,9 @@ public class ConfCache {
}
}
public static void copy(@NotNull VirtualFile file, @NotNull VirtualFile newFile) {
@NotNull String name = file.getNameWithoutExtension();
@Override
public void copyImpl(@NotNull VirtualFile file, @NotNull VirtualFile newFile) {
@NotNull String name = newFile.getNameWithoutExtension();
if (name.endsWith(KEY_MID_EXT)) {
copyCache(file, newFile, KEY_CACHE);
} else if (name.endsWith(DOC_MID_EXT)) {
@@ -121,46 +131,32 @@ public class ConfCache {
}
}
public static void loadAll(@NotNull Project project) {
ApplicationManager.getApplication().executeOnPooledThread(() ->
DumbService.getInstance(project).runReadActionInSmartMode(() ->
ApplicationManager.getApplication().runReadAction(() -> {
@NotNull Collection<VirtualFile> files = FilenameIndex.getAllFilesByExt(project,
TsvLoader.EXT);
@NotNull StringBuilder sb = new StringBuilder();
for (@NotNull VirtualFile file : files) {
load(file);
sb.append(file.getName()).append("\n");
}
@NotNull Collection<VirtualFile> files2 = FilenameIndex.getAllFilesByExt(project,
TsvLoader.REGEXP_EXT);
for (@NotNull VirtualFile file : files2) {
load(file);
sb.append(file.getName()).append("\n");
}
if (files.isEmpty()) {
return;
}
if (!project.isDisposed()) {
ProjectView.getInstance(project).refresh();
}
LOG.info("Ext doc conf load all complete {} files\n{}", files.size(), sb);
})));
}
public static void loadFile(@NotNull VirtualFile file, @Nullable Project project) {
if (!TsvLoader.EXT.equals(file.getExtension()) && !TsvLoader.REGEXP_EXT.equals(file.getExtension())) {
@Override
public void loadAllImpl(@NotNull Project project) {
@NotNull Collection<VirtualFile> files = FilenameIndex.getAllFilesByExt(project,
TsvLoader.EXT);
@NotNull StringBuilder sb = new StringBuilder();
for (@NotNull VirtualFile file : files) {
loadFileImpl(file, project);
sb.append(file.getName()).append("\n");
}
@NotNull Collection<VirtualFile> files2 = FilenameIndex.getAllFilesByExt(project,
TsvLoader.REGEXP_EXT);
for (@NotNull VirtualFile file : files2) {
loadFileImpl(file, project);
sb.append(file.getPath()).append("\n");
}
if (files.isEmpty()) {
return;
}
ApplicationManager.getApplication().invokeLater(() -> {
ConfCache.load(file);
if (project != null && !project.isDisposed()) {
ProjectView.getInstance(project).refresh();
}
});
if (!project.isDisposed()) {
ProjectView.getInstance(project).refresh();
}
LOG.info("Ext doc conf load all complete {} files\n{}", files.size(), sb);
}
private static void load(@NotNull VirtualFile file) {
@Override
public void loadFileImpl(@NotNull VirtualFile file, @Nullable Project project) {
@NotNull String name = file.getNameWithoutExtension();
if (name.endsWith(KEY_MID_EXT)) {
@NotNull String matchName = name.substring(0, name.length() - KEY_MID_EXT.length());

View File

@@ -46,7 +46,6 @@ class SpiltKeyWordPatternFactory {
}
sb.insert(0, "\n");
sb.insert(0, path);
sb.insert(0, "\n");
try {
@NotNull Pattern compile = Pattern.compile(regex);
PATTERN_CACHE.put(regex, compile);

View File

@@ -1,4 +0,0 @@
/**
* call ConfCache clear and loadAll
*/
package io.github.linwancen.plugin.show.ext.conf.action;

View File

@@ -1,4 +0,0 @@
/**
* call ConfCache.load etc.
*/
package io.github.linwancen.plugin.show.ext.conf.listener;

View File

@@ -1,10 +1,9 @@
package io.github.linwancen.plugin.show.ext.conf.listener;
package io.github.linwancen.plugin.show.ext.listener;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerListener;
import io.github.linwancen.plugin.show.ext.conf.ConfCache;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -13,11 +12,11 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* call ConfCache.loadAll
* call FileLoader.loadAll
*/
public class ConfFileInitListener implements DumbService.DumbModeListener, ProjectManagerListener {
public class FileLoadInitListener implements DumbService.DumbModeListener, ProjectManagerListener {
private static final Logger LOG = LoggerFactory.getLogger(ConfFileInitListener.class);
private static final Logger LOG = LoggerFactory.getLogger(FileLoadInitListener.class);
private static final Map<Project, Boolean> PROJECT_LOAD_MAP = new ConcurrentHashMap<>() {};
@Override
@@ -26,7 +25,7 @@ public class ConfFileInitListener implements DumbService.DumbModeListener, Proje
@NotNull Project[] projects = ProjectManager.getInstance().getOpenProjects();
for (@NotNull Project project : projects) {
PROJECT_LOAD_MAP.computeIfAbsent(project, k -> {
ConfCache.loadAll(project);
FileLoader.EPN.getExtensionList().forEach(fileLoader -> fileLoader.loadAll(project));
return true;
});
}

View File

@@ -0,0 +1,71 @@
package io.github.linwancen.plugin.show.ext.listener;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* ExtensionPointName: fileLoader
*/
public abstract class FileLoader {
public static final ExtensionPointName<FileLoader> EPN =
ExtensionPointName.create("io.github.linwancen.show-comment.fileLoader");
public abstract void clearAll();
/**
* not need skipFile(file) skipFile(newFile)
*/
public abstract void copyImpl(@NotNull VirtualFile file, @NotNull VirtualFile newFile);
public abstract void remove(@NotNull VirtualFile file, @Nullable String oldName);
public boolean skipFile(@NotNull VirtualFile file) {
return skipExt(file.getExtension());
}
public boolean skipExt(@Nullable String ext) {
return false;
}
/**
* protected because not in runReadAction & executeOnPooledThread
*/
protected abstract void loadAllImpl(Project project);
/**
* not need skipFile(file)
*/
protected abstract void loadFileImpl(@NotNull VirtualFile file, @Nullable Project project);
public void loadAll(@NotNull Project project) {
ApplicationManager.getApplication().executeOnPooledThread(() ->
DumbService.getInstance(project).runReadActionInSmartMode(() ->
ApplicationManager.getApplication().runReadAction(() ->
loadAllImpl(project))));
}
void loadFile(@NotNull VirtualFile file, @Nullable Project project) {
if (skipFile(file)) return;
if (project != null && DumbService.isDumb(project)) return;
ApplicationManager.getApplication().executeOnPooledThread(() ->
ApplicationManager.getApplication().runReadAction(() -> {
loadFileImpl(file, project);
if (!project.isDisposed()) {
ProjectView.getInstance(project).refresh();
}
}));
}
public void copy(@NotNull VirtualFile file, @NotNull VirtualFile newFile) {
if (skipFile(file)) return;
if (skipFile(newFile)) return;
copyImpl(file, newFile);
}
}

View File

@@ -1,4 +1,4 @@
package io.github.linwancen.plugin.show.ext.conf.listener;
package io.github.linwancen.plugin.show.ext.listener;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
@@ -7,7 +7,6 @@ import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.openapi.vfs.newvfs.events.VFileMoveEvent;
import com.intellij.openapi.vfs.newvfs.events.VFilePropertyChangeEvent;
import io.github.linwancen.plugin.show.ext.conf.ConfCache;
import io.github.linwancen.plugin.show.ext.conf.TsvLoader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -17,11 +16,11 @@ import org.slf4j.LoggerFactory;
import java.util.List;
/**
* call ConfCache.loadFile, copy, remove
* call FileLoader.loadFile, copy, remove
*/
public class ConfFileListener implements BulkFileListener {
public class FileOptListener implements BulkFileListener {
private static final Logger LOG = LoggerFactory.getLogger(ConfFileListener.class);
private static final Logger LOG = LoggerFactory.getLogger(FileOptListener.class);
@Override
public void after(@NotNull List<? extends VFileEvent> events) {
@@ -35,6 +34,7 @@ public class ConfFileListener implements BulkFileListener {
}
private static void forEvent(@NotNull VFileEvent event) {
@NotNull List<FileLoader> list = FileLoader.EPN.getExtensionList();
@Nullable VirtualFile file = event.getFile();
if (file == null) {
return;
@@ -46,17 +46,15 @@ public class ConfFileListener implements BulkFileListener {
@NotNull VFilePropertyChangeEvent changeEvent = (VFilePropertyChangeEvent) event;
if ("name".equals(changeEvent.getPropertyName())) {
String oldName = changeEvent.getOldValue().toString();
if (oldName.endsWith(TsvLoader.EXT) || oldName.endsWith(TsvLoader.REGEXP_EXT)) {
// change cache too complicated so remove
ConfCache.remove(file, oldName);
}
// change cache too complicated so remove
list.forEach(fileLoader -> fileLoader.remove(file, oldName));
}
}
if (!TsvLoader.EXT.equals(file.getExtension()) && !TsvLoader.REGEXP_EXT.equals(file.getExtension())) {
return;
}
if (event instanceof VFileDeleteEvent) {
ConfCache.remove(file, null);
list.forEach(fileLoader -> fileLoader.remove(file, null));
return;
}
if (event instanceof VFileCopyEvent) {
@@ -65,15 +63,17 @@ public class ConfFileListener implements BulkFileListener {
if (newFile == null) {
return;
}
try {
ConfCache.copy(file, newFile);
} catch (Exception ignored) {
// ignore
for (@NotNull FileLoader loader : list) {
try {
loader.copy(file, newFile);
} catch (Exception ignored) {
// ignore
}
}
return;
}
// VFileCreateEvent
// VFileContentChangeEvent
ConfCache.loadFile(file, null);
list.forEach(fileLoader -> fileLoader.loadFile(file, null));
}
}

View File

@@ -1,21 +1,20 @@
package io.github.linwancen.plugin.show.ext.conf.listener;
package io.github.linwancen.plugin.show.ext.listener;
import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
import com.intellij.openapi.fileEditor.FileEditorManagerListener;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import io.github.linwancen.plugin.show.ext.conf.ConfCache;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* call ConfCache.loadFile
* call FileLoader.loadFile
*/
public class ConfFileChangeListener implements FileEditorManagerListener {
public class FileSelectChangeListener implements FileEditorManagerListener {
private static final Logger LOG = LoggerFactory.getLogger(ConfFileChangeListener.class);
private static final Logger LOG = LoggerFactory.getLogger(FileSelectChangeListener.class);
@Override
public void selectionChanged(@NotNull FileEditorManagerEvent event) {
@@ -29,7 +28,7 @@ public class ConfFileChangeListener implements FileEditorManagerListener {
}
if (file.exists()) {
try {
ConfCache.loadFile(file, project);
FileLoader.EPN.getExtensionList().forEach(fileLoader -> fileLoader.loadFile(file, project));
} catch (Throwable e) {
LOG.info("ConfFileChangeListener catch Throwable but log to record.", e);
}

View File

@@ -0,0 +1,4 @@
/**
* Init and listen file change
*/
package io.github.linwancen.plugin.show.ext.listener;

View File

@@ -1,21 +1,27 @@
package io.github.linwancen.plugin.show.lang;
import com.intellij.ide.projectView.ProjectViewNode;
import com.intellij.lang.html.HTMLLanguage;
import com.intellij.lang.javascript.psi.JSPsiReferenceElement;
import com.intellij.model.psi.PsiSymbolReference;
import com.intellij.model.psi.PsiSymbolReferenceService;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import io.github.linwancen.plugin.show.bean.LineInfo;
import io.github.linwancen.plugin.show.bean.SettingsInfo;
import io.github.linwancen.plugin.show.lang.base.DocFilter;
import io.github.linwancen.plugin.show.lang.base.DocSkip;
import io.github.linwancen.plugin.show.lang.vue.VueRouterCache;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@@ -23,15 +29,17 @@ import java.util.List;
public class HtmlLangDoc extends JsLangDoc {
private static final Logger LOG = LoggerFactory.getLogger(HtmlLangDoc.class);
@Nullable
public static final Method WEB_DOC_METHOD;
@Nullable
public static final Method REF_METHOD;
static {
LANG_DOC_MAP.put(HTMLLanguage.INSTANCE.getID(), new HtmlLangDoc());
Method method = null;
Method refMethod = null;
@Nullable Method method = null;
@Nullable Method refMethod = null;
try {
Class<?> clazz = Class.forName("com.intellij.webSymbols.WebSymbol");
@NotNull Class<?> clazz = Class.forName("com.intellij.webSymbols.WebSymbol");
method = clazz.getMethod("getDescription");
// noinspection UnstableApiUsage
refMethod = PsiSymbolReferenceService.class.getMethod("getReferences", PsiElement.class);
@@ -52,6 +60,13 @@ public class HtmlLangDoc extends JsLangDoc {
return info.appSettings.showLineEndCommentJs || info.appSettings.showLineEndCommentHtml;
}
@Override
public @Nullable <T extends SettingsInfo> String treeDoc(@NotNull T info, @NotNull ProjectViewNode<?> node,
@NotNull Project project) {
@Nullable VirtualFile virtualFile = node.getVirtualFile();
return VueRouterCache.fileDoc(virtualFile);
}
/**
* Override like Java/Json/Html
*/
@@ -64,19 +79,19 @@ public class HtmlLangDoc extends JsLangDoc {
if (WEB_DOC_METHOD == null || !info.appSettings.showLineEndCommentHtml) {
return super.refDoc(info, ref);
}
PsiSymbolReferenceService service = PsiSymbolReferenceService.getService();
ArrayList<PsiSymbolReference> references = new ArrayList<>();
@NotNull PsiSymbolReferenceService service = PsiSymbolReferenceService.getService();
@NotNull ArrayList<PsiSymbolReference> references = new ArrayList<>();
try {
Object object = REF_METHOD.invoke(service, ref);
if (object instanceof Iterable) {
Iterable<?> objects = (Iterable<?>) object;
@NotNull Iterable<?> objects = (Iterable<?>) object;
for (Object o : objects) {
if (o instanceof PsiSymbolReference) {
references.add(((PsiSymbolReference) o));
}
}
}
} catch (ProcessCanceledException ignored) {
} catch (ProcessCanceledException | InvocationTargetException ignored) {
return super.refDoc(info, ref);
} catch (Exception e) {
LOG.warn("Web Tag Attr getReferences fail: ", e);

View File

@@ -31,8 +31,8 @@ public abstract class BaseLangDoc extends EditorLinePainter {
static {
try {
// for 2024.2
Class<?> clazz = Class.forName("io.github.linwancen.plugin.show.java.KotlinLangDoc");
BaseLangDoc lang = (BaseLangDoc) clazz.getConstructor().newInstance();
@NotNull Class<?> clazz = Class.forName("io.github.linwancen.plugin.show.java.KotlinLangDoc");
@NotNull BaseLangDoc lang = (BaseLangDoc) clazz.getConstructor().newInstance();
LANG_DOC_MAP.put("kotlin", lang);
} catch (Exception ignored) {}
}

View File

@@ -32,12 +32,12 @@ public class DocSkip {
public static <T extends SettingsInfo> boolean skipTagAttr(@NotNull T info, @NotNull PsiElement ref) {
if (ref instanceof XmlTag) {
String text = ((XmlTag) ref).getName();
@NotNull String text = ((XmlTag) ref).getName();
return skipText(info, text,
info.globalSettings.tagInclude, info.globalSettings.tagExclude,
info.projectSettings.tagInclude, info.projectSettings.tagExclude);
} else if (ref instanceof XmlAttribute) {
String text = ((XmlAttribute) ref).getName();
@NotNull String text = ((XmlAttribute) ref).getName();
return skipText(info, text,
info.globalSettings.attrInclude, info.globalSettings.attrExclude,
info.projectSettings.attrInclude, info.projectSettings.attrExclude);

View File

@@ -0,0 +1,237 @@
package io.github.linwancen.plugin.show.lang.vue;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.lang.ecmascript6.psi.ES6ExportDefaultAssignment;
import com.intellij.lang.ecmascript6.psi.ES6ImportCall;
import com.intellij.lang.ecmascript6.psi.ES6ImportedBinding;
import com.intellij.lang.javascript.psi.JSArrayLiteralExpression;
import com.intellij.lang.javascript.psi.JSExpression;
import com.intellij.lang.javascript.psi.JSLiteralExpression;
import com.intellij.lang.javascript.psi.JSObjectLiteralExpression;
import com.intellij.lang.javascript.psi.JSProperty;
import com.intellij.lang.javascript.psi.JSReferenceExpression;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import io.github.linwancen.plugin.show.ext.listener.FileLoader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* call ConfFactory, ConfCacheGetUtils
*/
public class VueRouterCache extends FileLoader {
private static final Logger LOG = LoggerFactory.getLogger(VueRouterCache.class);
private static final Map<VirtualFile, String> DOC_CACHE = new ConcurrentHashMap<>();
@Nullable
public static String fileDoc(@Nullable VirtualFile virtualFile) {
if (virtualFile == null) {
return null;
}
return DOC_CACHE.get(virtualFile);
}
@Override
public void clearAll() {
DOC_CACHE.clear();
}
@Override
public void remove(@NotNull VirtualFile file, @Nullable String oldName) {
if (oldName == null) {
DOC_CACHE.remove(file);
}
}
@Override
public boolean skipFile(@NotNull VirtualFile file) {
@Nullable String ext = file.getExtension();
return !file.getPath().contains("src/router") && !"js".equals(ext) && !"ts".equals(ext);
}
@Override
public void copyImpl(@NotNull VirtualFile file, @NotNull VirtualFile newFile) {
String s = DOC_CACHE.get(file);
if (s != null) {
DOC_CACHE.put(newFile, s);
}
}
@Override
public void loadAllImpl(@NotNull Project project) {
@NotNull Collection<VirtualFile> files = FilenameIndex.getVirtualFilesByName(project,
"package.json", GlobalSearchScope.projectScope(project));
@NotNull StringBuilder sb = new StringBuilder();
for (@NotNull VirtualFile file : files) {
VirtualFile parent = file.getParent();
if (parent == null) {
continue;
}
@Nullable VirtualFile src = parent.findChild("src");
if (src == null) {
continue;
}
@Nullable VirtualFile router = src.findChild("router");
if (router == null) {
continue;
}
VfsUtil.visitChildrenRecursively(router, new VirtualFileVisitor<Void>() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
if (file.isDirectory()) {
return super.visitFile(file);
}
loadFileImpl(file, project);
sb.append(file.getPath()).append("\n");
return super.visitFile(file);
}
});
}
if (files.isEmpty()) {
return;
}
if (!project.isDisposed()) {
ProjectView.getInstance(project).refresh();
}
LOG.info("Vue Router load all complete {} files\n{}", files.size(), sb);
}
@Override
public void loadFileImpl(@NotNull VirtualFile file, @Nullable Project project) {
if (project == null) {
return;
}
@Nullable PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
if (psiFile == null) {
return;
}
@Nullable ES6ExportDefaultAssignment export = PsiTreeUtil.findChildOfType(psiFile,
ES6ExportDefaultAssignment.class);
if (export == null) {
return;
}
@Nullable JSArrayLiteralExpression arr = PsiTreeUtil.findChildOfAnyType(export, JSArrayLiteralExpression.class);
if (arr == null) {
return;
}
parseArr(arr);
}
@Nullable
private static VirtualFile parseArr(JSArrayLiteralExpression arr) {
@Nullable VirtualFile virtualFile = null;
@NotNull List<JSObjectLiteralExpression> list = PsiTreeUtil.getChildrenOfTypeAsList(arr,
JSObjectLiteralExpression.class);
for (@NotNull JSObjectLiteralExpression obj : list) {
@Nullable String title = parseTitle(obj);
@Nullable JSProperty children = obj.findProperty("children");
if (children != null) {
@Nullable JSExpression value = children.getValue();
if (value instanceof JSArrayLiteralExpression) {
@NotNull JSArrayLiteralExpression childrenArr = (JSArrayLiteralExpression) value;
@Nullable VirtualFile subFile = parseArr(childrenArr);
// common component dir
if (subFile != null) {
VirtualFile file = subFile.getParent();
if (file != null && title != null) {
virtualFile = file;
DOC_CACHE.put(virtualFile, title);
}
}
}
}
if (title != null) {
VirtualFile file = parseComponent(obj);
if (file != null) {
virtualFile = file;
DOC_CACHE.put(virtualFile, title);
if ("index.vue".equals(virtualFile.getName())) {
virtualFile = virtualFile.getParent();
DOC_CACHE.put(virtualFile, title);
}
}
}
}
return virtualFile;
}
@Nullable
private static String parseTitle(@NotNull JSObjectLiteralExpression obj) {
@Nullable JSProperty meta = obj.findProperty("meta");
if (meta == null) {
return null;
}
@Nullable JSObjectLiteralExpression metaObj = meta.getObjectLiteralExpressionInitializer();
if (metaObj == null) {
return null;
}
@Nullable JSProperty titleProp = metaObj.findProperty("title");
if (titleProp == null) {
return null;
}
@Nullable JSExpression value = titleProp.getValue();
if (value instanceof JSLiteralExpression) {
return ((JSLiteralExpression) value).getStringValue();
}
return null;
}
@Nullable
private static VirtualFile parseComponent(@NotNull JSObjectLiteralExpression obj) {
@Nullable JSProperty component = obj.findProperty("component");
if (component == null) {
return null;
}
@Nullable PsiElement value = component.getValue();
if (value instanceof JSReferenceExpression) {
@NotNull JSReferenceExpression ref = (JSReferenceExpression) value;
@Nullable PsiElement resolve;
try {
resolve = ref.resolve();
} catch (Throwable ignored) {
return null;
}
// import A from ""
if (resolve instanceof ES6ImportedBinding) {
@NotNull ES6ImportedBinding binding = (ES6ImportedBinding) resolve;
@NotNull Collection<PsiElement> elements = binding.findReferencedElements();
for (@NotNull PsiElement element : elements) {
if (element instanceof PsiFile) {
return ((PsiFile) element).getVirtualFile();
}
}
}
// A = () => import('')
value = resolve;
}
// () => import("")
@Nullable ES6ImportCall importCall = PsiTreeUtil.findChildOfType(value, ES6ImportCall.class);
if (importCall == null) {
return null;
}
@NotNull Collection<PsiElement> elements = importCall.resolveReferencedElements();
for (PsiElement element : elements) {
PsiFile psiFile = PsiTreeUtil.getParentOfType(element, PsiFile.class);
if (psiFile != null) {
return psiFile.getVirtualFile();
}
}
return null;
}
}

View File

@@ -3,4 +3,8 @@
<editor.linePainter implementation="io.github.linwancen.plugin.show.lang.JsLangDoc"/>
<editor.linePainter implementation="io.github.linwancen.plugin.show.lang.HtmlLangDoc"/>
</extensions>
<extensions defaultExtensionNs="io.github.linwancen.show-comment">
<fileLoader implementation="io.github.linwancen.plugin.show.lang.vue.VueRouterCache"/>
</extensions>
</idea-plugin>

View File

@@ -12,7 +12,7 @@ Show doc comment in the Project view Tree, line End, json, other
<ul>
<li>Java, Kotlin, Groovy, Scala
<li>C/C++/OC, Python, Go, Rust, Ruby
<li>JS/TS, PHP, SQL
<li>HTML(Vue), JS/TS, PHP, SQL
<li>YAML/yml
</ul>
@@ -145,23 +145,30 @@ Show doc comment in the Project view Tree, line End, json, other
</extensions>
<applicationListeners>
<listener class="io.github.linwancen.plugin.show.ext.conf.listener.ConfFileListener"
<listener class="io.github.linwancen.plugin.show.ext.listener.FileOptListener"
topic="com.intellij.openapi.vfs.newvfs.BulkFileListener"/>
<listener class="io.github.linwancen.plugin.show.ext.conf.listener.ConfFileChangeListener"
<listener class="io.github.linwancen.plugin.show.ext.listener.FileSelectChangeListener"
topic="com.intellij.openapi.fileEditor.FileEditorManagerListener"/>
<listener class="io.github.linwancen.plugin.show.cache.CacheUpdateEditorListener"
topic="com.intellij.openapi.fileEditor.FileEditorManagerListener"/>
</applicationListeners>
<projectListeners>
<listener class="io.github.linwancen.plugin.show.ext.conf.listener.ConfFileInitListener"
<listener class="io.github.linwancen.plugin.show.ext.listener.FileLoadInitListener"
topic="com.intellij.openapi.project.ProjectManagerListener"/>
<listener class="io.github.linwancen.plugin.show.ext.conf.listener.ConfFileInitListener"
<listener class="io.github.linwancen.plugin.show.ext.listener.FileLoadInitListener"
topic="com.intellij.openapi.project.DumbService$DumbModeListener"/>
<listener class="io.github.linwancen.plugin.show.cache.CacheUpdateProjectListener"
topic="com.intellij.openapi.project.ProjectManagerListener"/>
</projectListeners>
<extensionPoints>
<extensionPoint name="fileLoader" dynamic="true" interface="io.github.linwancen.plugin.show.ext.listener.FileLoader"/>
</extensionPoints>
<extensions defaultExtensionNs="io.github.linwancen.show-comment">
<fileLoader implementation="io.github.linwancen.plugin.show.ext.conf.ConfCache"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<editor.linePainter implementation="io.github.linwancen.plugin.show.LineEnd"/>
<projectViewNodeDecorator implementation="io.github.linwancen.plugin.show.Tree"/>
@@ -189,13 +196,13 @@ Show doc comment in the Project view Tree, line End, json, other
<actions>
<action
id="io.github.linwancen.plugin.show.ext.conf.ReLoadExtDocAction"
class="io.github.linwancen.plugin.show.ext.conf.action.ReloadExtDocAction"
class="io.github.linwancen.plugin.show.ext.action.ReloadExtDocAction"
text="🔄 // Reload External Comment">
<add-to-group group-id="ToolsMenu"/>
</action>
<action
id="io.github.linwancen.plugin.show.ext.conf.action.ResetExtDocAction"
class="io.github.linwancen.plugin.show.ext.conf.action.ResetExtDocAction"
id="io.github.linwancen.plugin.show.ext.action.ResetExtDocAction"
class="io.github.linwancen.plugin.show.ext.action.ResetExtDocAction"
text="🆑 // Clear External Comment">
<add-to-group group-id="ToolsMenu"/>
</action>

View File

@@ -45,4 +45,7 @@ reload.ext.doc=\uD83D\uDD04 // Reload External Comment
reset.ext.doc=\uD83C\uDD91 // Clear External Comment
line.end.add=// Add Line Comment
line.end.copy=// Copy With Line Comment
load.vue.router=Load Vue Router
reload.vue.router=\uD83D\uDD04 Reload Vue Router
reset.vue.router=\uD83C\uDD91 Clear Vue Router
copy.class.method.or.file.line=Copy Class.Method / File:LineNum

View File

@@ -45,4 +45,7 @@ reload.ext.doc=\uD83D\uDD04 // \u91CD\u65B0\u8BFB\u53D6\u5916\u90E8\u6CE8\u91CA
reset.ext.doc=\uD83C\uDD91 // \u6E05\u7406\u5916\u90E8\u6CE8\u91CA
line.end.add=// \u6DFB\u52A0\u81EA\u52A8\u6CE8\u91CA
line.end.copy=// \u590D\u5236 \u5E26\u81EA\u52A8\u6CE8\u91CA
load.vue.router=\u8BFB\u53D6 Vue Router
reload.vue.router=\uD83D\uDD04 \u91CD\u65B0\u8BFB\u53D6 Vue \u8DEF\u7531
reset.vue.router=\uD83C\uDD91 \u6E05\u7406 Vue \u8DEF\u7531
copy.class.method.or.file.line=\u590D\u5236 \u7C7B.\u65B9\u6CD5 / \u6587\u4EF6:\u884C\u53F7