diff --git a/README.md b/README.md
index c920095..b7618c2 100644
--- a/README.md
+++ b/README.md
@@ -3,47 +3,94 @@ IDEA 智能注释插件
https://plugins.jetbrains.com/plugin/18553-show-comment
-English Notes:
+
+
+## Notes 说明
+
+
English Notes:
- Show javadoc comments at the Project view Tree structure
- Show javadoc comments at the end-of-line
- Show javadoc comments at "xx ClassNameOrSimpleName.json" and jump to field
-
- Config: settings -> Tools -> Show Comment Global/Project
+
- Config: settings -> Tools -> // Show Comment Global/Project
-Chinese Notes:
+
+External Comment:
+
+- Reload: Tools -> 🔄 // Reload External Comment
+
- path/[any][filename.]ext.tree.tsv // file and folder tree comment 📝 📁
+
- path/[any][filename.]ext.key.tsv // line keywords to split and comment
+
- path/[any][filename.]ext.doc.tsv // line words comment
+
- In path, "doc" can replace any, and can use % like in SQL
+
- The line in key.tsv would concat lines with `|` to regexp, longer str should in front, startWith `?` to exclude
+
- Chang tsv file in find pop window would not reload!
+
- The tsv conf file must could be search in "Go to File"(Ctrl + Shift + N)
+
+
+
+中文说明:
- 在结构树显示 文档注释
- 在行末尾显示 文档注释
- 支持 "xx 类全名或简名.json" 文档注释与跳转到字段
-
- 修改配置:设置 -> 工具 -> Show Comment Global/Project
+
- 修改配置:设置 -> 工具 -> // Show Comment Global/Project
-English Change Notes:
+外部注释:
+- 重新加载:工具 -> "🔄 // Reload External Comment"
+
- path/[any][filename.]ext.tree.tsv // 文件(夹)注释 📝 📁
+
- path/[any][filename.]ext.key.tsv // 切割关键字与注释
+
- path/[any][filename.]ext.doc.tsv // 词注释
+
- key.tsv 的每一行将会用`|`连接起来形成正则表达式,较长的关键字应该放在前面,用 `?` 开头排除
+
- doc 文件夹可以替换任何一层文件夹,可以像 SQL 那样用 % 模糊匹配
+
- 在搜索弹出窗中修改 tsv 文件将不会被重加载
+
- tsv 配置文件必须能被搜索(Ctrl + Shift + N)
+
+
+
+
+## Change Notes 更新说明
+
+English Change Notes:
+
+- 1.12 ★ External Comment for COBOL etc
- 1.11 Add json key jump to field
- 1.10 Add project-view-tree-comment for package from parent or other project
- 1.9 Add project-view-tree-comment for "xx ClassNameOrSimpleName.json" and SPI file
-
- 1.8 Add line-end-comment for "xx ClassNameOrSimpleName.json"
+
- 1.8 ★ line-end-comment for "xx ClassNameOrSimpleName.json"
- 1.7 Add line-end-comment setting for prefix and count
- 1.6 Add line-end-comment independent switch for call, new, ref
- 1.5 Add line-end-comment find next loop when none
- 1.4 Add line-end-comment find element right to left
-
- 1.3 Add project-view-tree-comment
+
- 1.3 ★ project-view-tree-comment
- 1.2 Add line-end-comment settings fro class prefix filter
- 1.1 Add line-end-comment settings for text color
-Chinese Change Notes:
+中文更新说明:
-- 1.11 增加 json 跳转到字段
+
- 1.12 ★ 外部注释用于 COBOL 等
+
- 1.11 增加 json 跳转到字段
- 1.10 增加 在父包和其他项目的包中获取 项目导航栏注释
- 1.9 增加 "xx 类全名或简名.json" 和 SPI 项目导航栏注释
-
- 1.8 增加 "xx 类全名或简名.json" 行末注释
+
- 1.8 ★ "xx 类全名或简名.json" 行末注释
- 1.7 增加 行末注释前缀和对象数设置
- 1.6 增加 行末调用,new,引用注释独立开关
- 1.5 增加 没有注释时循环查找下一个对象
- 1.4 增加 从右往左查找行末注释对象
-
- 1.3 增加 项目导航栏注释
+
- 1.3 ★ 项目导航栏注释
- 1.2 增加 行末注释类前缀配置
- 1.1 增加 行末文本颜色配置
-
\ No newline at end of file
+
+
+
+
+### Demo 示例
+
+See in IDEA with this plugin | 安装插件后用 IDEA 查看
+
+- [Java Doc Comment Demo | Java 文档注释](src/test/java/io/github/linwancen/plugin/show/demo/java/Call.java)
+- [JSON Doc Comment Demo | JSON 文档注释](src/test/java/io/github/linwancen/plugin/show/demo/json/base Pojo.json)
+- [External Comment Demo For COBOL | 外部注释 Demo](src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/BASE.cbl)
+ [COBOL Highlighting | COBOL 高亮配置](src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL_IDEA.md)
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 09e857a..d787acf 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,7 +4,7 @@ plugins {
}
group 'io.github.linwancen'
-version '1.11.0.' + (new Date().format('yyyy.MM.dd_HH.mm'))
+version '1.12.0.' + (new Date().format('yyyy.MM.dd_HH.mm'))
apply plugin: 'java'
@@ -37,32 +37,34 @@ patchPluginXml {
sinceBuild = '201.1'
untilBuild = ''
changeNotes = """
-English Change Notes:
+English Change Notes:
+- 1.12 ★ External Comment for COBOL etc
- 1.11 Add json key jump to field
- 1.10 Add project-view-tree-comment for package from parent or other project
- 1.9 Add project-view-tree-comment for "xx ClassNameOrSimpleName.json" and SPI file
-
- 1.8 Add line-end-comment for "xx ClassNameOrSimpleName.json"
+
- 1.8 ★ line-end-comment for "xx ClassNameOrSimpleName.json"
- 1.7 Add line-end-comment setting for prefix and count
- 1.6 Add line-end-comment independent switch for call, new, ref
- 1.5 Add line-end-comment find next loop when none
- 1.4 Add line-end-comment find element right to left
-
- 1.3 Add project-view-tree-comment
+
- 1.3 ★ project-view-tree-comment
- 1.2 Add line-end-comment settings fro class prefix filter
- 1.1 Add line-end-comment settings for text color
-Chinese Change Notes:
+中文更新说明:
+- 1.12 ★ 外部注释用于 COBOL 等
- 1.11 增加 json 跳转到字段
- 1.10 增加 在父包和其他项目的包中获取 项目导航栏注释
- 1.9 增加 "xx 类全名或简名.json" 和 SPI 项目导航栏注释
-
- 1.8 增加 "xx 类全名或简名.json" 行末注释
+
- 1.8 ★ "xx 类全名或简名.json" 行末注释
- 1.7 增加 行末注释前缀和对象数设置
- 1.6 增加 行末调用,new,引用注释独立开关
- 1.5 增加 没有注释时循环查找下一个对象
- 1.4 增加 从右往左查找行末注释对象
-
- 1.3 增加 项目导航栏注释
+
- 1.3 ★ 项目导航栏注释
- 1.2 增加 行末注释类前缀配置
- 1.1 增加 行末文本颜色配置
diff --git a/settings-offline.gradle b/settings-offline.gradle
new file mode 100644
index 0000000..68699c0
--- /dev/null
+++ b/settings-offline.gradle
@@ -0,0 +1,29 @@
+// gradle/init.d/init.gradle use allprojects {
+// settings.gradle use pluginManagement {
+pluginManagement {
+ repositories {
+ all { ArtifactRepository repo ->
+ if (repo instanceof MavenArtifactRepository) {
+ def url = repo.url.toString()
+ if (url.startsWith("https://repo1.maven.org/maven2")
+ || url.startsWith("https://jcenter.bintray.com/")
+ || url.startsWith("https://cache-redirector.jetbrains.com")) {
+ project.logger.lifecycle("remove Repository ${repo.url}.")
+ remove(repo)
+ }
+ }
+ }
+ mavenLocal()
+ maven { name "jetbrains-cache"; url "" }
+ maven { name "maven-cache"; url "" }
+ }
+ buildscript {
+ repositories {
+ mavenLocal()
+ maven { name "jetbrains-cache"; url "" }
+ }
+ }
+}
+
+rootProject.name = 'show-comment'
+
diff --git a/src/main/java/io/github/linwancen/plugin/show/JsonJump.java b/src/main/java/io/github/linwancen/plugin/show/JsonJump.java
index be56091..eb87627 100644
--- a/src/main/java/io/github/linwancen/plugin/show/JsonJump.java
+++ b/src/main/java/io/github/linwancen/plugin/show/JsonJump.java
@@ -13,7 +13,9 @@ import io.github.linwancen.plugin.show.json.JsonRef;
import io.github.linwancen.plugin.show.json.JsonUtils;
import org.jetbrains.annotations.NotNull;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
public class JsonJump extends PsiReferenceContributor {
diff --git a/src/main/java/io/github/linwancen/plugin/show/LineEnd.java b/src/main/java/io/github/linwancen/plugin/show/LineEnd.java
index 3aeecf5..1ab8ec5 100644
--- a/src/main/java/io/github/linwancen/plugin/show/LineEnd.java
+++ b/src/main/java/io/github/linwancen/plugin/show/LineEnd.java
@@ -14,6 +14,7 @@ import com.intellij.psi.javadoc.PsiDocComment;
import io.github.linwancen.plugin.show.doc.DocTextUtils;
import io.github.linwancen.plugin.show.line.LineDocLeftToRightUtils;
import io.github.linwancen.plugin.show.line.LineDocRightToLeftUtils;
+import io.github.linwancen.plugin.show.ext.LineExtUtils;
import io.github.linwancen.plugin.show.settings.AppSettingsState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -33,20 +34,23 @@ public class LineEnd extends EditorLinePainter {
if (DumbService.isDumb(project)) {
return null;
}
- FileViewProvider viewProvider = PsiManager.getInstance(project).findViewProvider(file);
- PsiDocComment docComment = doc(project, viewProvider, lineNumber);
- String comment = DocTextUtils.text(docComment);
- if (comment == null) {
+ if (!file.exists()) {
+ return null;
+ }
+ String doc = doc(project, file, lineNumber);
+ if (doc == null) {
return null;
}
TextAttributes textAttr = file.getFileType().equals(JsonFileType.INSTANCE)
? settings.lineEndJsonTextAttr
: settings.lineEndTextAttr;
- LineExtensionInfo info = new LineExtensionInfo(settings.lineEndPrefix + comment, textAttr);
+ LineExtensionInfo info = new LineExtensionInfo(settings.lineEndPrefix + doc, textAttr);
return Collections.singletonList(info);
}
- private static @Nullable PsiDocComment doc(Project project, FileViewProvider viewProvider, int lineNumber) {
+ private static @Nullable String doc(@NotNull Project project,
+ @NotNull VirtualFile file, int lineNumber) {
+ FileViewProvider viewProvider = PsiManager.getInstance(project).findViewProvider(file);
if (viewProvider == null) {
return null;
}
@@ -63,9 +67,13 @@ public class LineEnd extends EditorLinePainter {
if (startOffset == endOffset) {
return null;
}
- if (AppSettingsState.getInstance().findElementRightToLeft) {
- return LineDocRightToLeftUtils.rightDoc(viewProvider, startOffset, endOffset);
+ String ext = LineExtUtils.extDoc(project, file, document, startOffset, endOffset);
+ if (ext != null) {
+ return ext;
}
- return LineDocLeftToRightUtils.leftDoc(viewProvider, document, startOffset, endOffset);
+ PsiDocComment docComment = AppSettingsState.getInstance().findElementRightToLeft
+ ? LineDocRightToLeftUtils.rightDoc(viewProvider, startOffset, endOffset)
+ : LineDocLeftToRightUtils.leftDoc(viewProvider, document, startOffset, endOffset);
+ return DocTextUtils.text(docComment);
}
}
diff --git a/src/main/java/io/github/linwancen/plugin/show/Tree.java b/src/main/java/io/github/linwancen/plugin/show/Tree.java
index 73b0b7c..b0e2e5e 100644
--- a/src/main/java/io/github/linwancen/plugin/show/Tree.java
+++ b/src/main/java/io/github/linwancen/plugin/show/Tree.java
@@ -5,6 +5,7 @@ import com.intellij.ide.projectView.ProjectViewNode;
import com.intellij.ide.projectView.ProjectViewNodeDecorator;
import com.intellij.ide.projectView.impl.nodes.*;
import com.intellij.ide.util.treeView.PresentableNodeDescriptor.ColoredFragment;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
@@ -15,6 +16,7 @@ import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import io.github.linwancen.plugin.show.doc.DocTextUtils;
import io.github.linwancen.plugin.show.doc.DocUtils;
+import io.github.linwancen.plugin.show.ext.TreeExtUtils;
import io.github.linwancen.plugin.show.settings.AppSettingsState;
import org.jetbrains.annotations.Nullable;
@@ -34,25 +36,43 @@ public class Tree implements ProjectViewNodeDecorator {
if (DumbService.isDumb(project)) {
return;
}
-
- PsiDocComment docComment = nodeDoc(node, project);
- if (docComment == null) {
- return;
- }
-
- String commentText = DocTextUtils.text(docComment);
- if (commentText == null) {
- return;
- }
- List coloredText = data.getColoredText();
- if (coloredText.isEmpty()) {
- data.addText(data.getPresentableText(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
- }
- data.addText(commentText, SimpleTextAttributes.GRAY_ATTRIBUTES);
+ ApplicationManager.getApplication().runReadAction(() -> {
+ String doc = doc(node, project);
+ if (doc == null) {
+ return;
+ }
+ List coloredText = data.getColoredText();
+ if (coloredText.isEmpty()) {
+ data.addText(data.getPresentableText(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
+ }
+ data.addText(doc, SimpleTextAttributes.GRAY_ATTRIBUTES);
+ });
}
@Nullable
- private PsiDocComment nodeDoc(ProjectViewNode> node, Project project) {
+ private String doc(ProjectViewNode> node, Project project) {
+ String extDoc = extDoc(node, project);
+ if (extDoc != null) {
+ return extDoc;
+ }
+ PsiDocComment docComment = nodeDoc(node, project);
+ if (docComment == null) {
+ return null;
+ }
+ return DocTextUtils.text(docComment);
+ }
+
+ @Nullable
+ public static String extDoc(ProjectViewNode> node, Project project) {
+ VirtualFile file = node.getVirtualFile();
+ if (file == null) {
+ return null;
+ }
+ return TreeExtUtils.extDoc(project, file);
+ }
+
+ @Nullable
+ private static PsiDocComment nodeDoc(ProjectViewNode> node, Project project) {
if (node instanceof PsiFileNode) {
PsiFile psiFile = ((PsiFileNode) node).getValue();
return DocUtils.fileDoc(psiFile);
@@ -97,7 +117,7 @@ public class Tree implements ProjectViewNodeDecorator {
}
@Nullable
- private PsiDocComment dirDoc(PsiDirectory child) {
+ private static PsiDocComment dirDoc(PsiDirectory child) {
while (true) {
PsiDocComment docComment = DocUtils.dirDoc(child);
if (docComment != null) {
@@ -115,7 +135,7 @@ public class Tree implements ProjectViewNodeDecorator {
}
@Nullable
- private PsiDocComment packageDoc(PsiPackage child) {
+ private static PsiDocComment packageDoc(PsiPackage child) {
while (true) {
PsiDocComment docComment = DocUtils.packageDoc(child);
if (docComment != null) {
diff --git a/src/main/java/io/github/linwancen/plugin/show/doc/DocTextUtils.java b/src/main/java/io/github/linwancen/plugin/show/doc/DocTextUtils.java
index 2ed7b26..10ceab9 100644
--- a/src/main/java/io/github/linwancen/plugin/show/doc/DocTextUtils.java
+++ b/src/main/java/io/github/linwancen/plugin/show/doc/DocTextUtils.java
@@ -7,9 +7,6 @@ import com.intellij.psi.javadoc.PsiInlineDocTag;
import io.github.linwancen.plugin.show.settings.AppSettingsState;
import org.jetbrains.annotations.Nullable;
-import java.util.ArrayList;
-import java.util.List;
-
public class DocTextUtils {
private DocTextUtils() {}
@@ -20,30 +17,40 @@ public class DocTextUtils {
return null;
}
AppSettingsState appSettings = AppSettingsState.getInstance();
- List comments = new ArrayList<>();
+ int lineCount = 0;
+ StringBuilder sb = new StringBuilder();
PsiElement[] elements = psiDocComment.getDescriptionElements();
for (PsiElement element : elements) {
- if (element instanceof PsiDocToken) {
- PsiDocToken psiDocToken = (PsiDocToken) element;
- comments.add(psiDocToken.getText());
- } else if (element instanceof PsiInlineDocTag) {
- PsiInlineDocTag psiInlineDocTag = (PsiInlineDocTag) element;
- PsiElement[] children = psiInlineDocTag.getChildren();
- if (children.length > 2) {
- comments.add(children[2].getText());
- }
+ if (appendElementText(sb, element)) {
+ lineCount++;
}
- if (appSettings.lineEndCount > 0 && comments.size() >= appSettings.lineEndCount) {
+ if (appSettings.lineEndCount > 0
+ && lineCount >= appSettings.lineEndCount
+ || appSettings.lineEndLen > 0
+ && sb.length() >= appSettings.lineEndLen) {
break;
}
}
- if (comments.isEmpty()) {
+ if (sb.length() == 0) {
return null;
}
- StringBuilder sb = new StringBuilder(" ");
- for (String s : comments) {
- sb.append(s.trim().replace("
", "")).append(" ");
- }
+ sb.insert(0, " ");
return sb.toString();
}
+
+ private static boolean appendElementText(StringBuilder sb, PsiElement element) {
+ if (element instanceof PsiDocToken) {
+ PsiDocToken psiDocToken = (PsiDocToken) element;
+ sb.append(psiDocToken.getText().trim().replace("
", "")).append(" ");
+ return true;
+ }
+ if (element instanceof PsiInlineDocTag) {
+ PsiInlineDocTag psiInlineDocTag = (PsiInlineDocTag) element;
+ PsiElement[] children = psiInlineDocTag.getChildren();
+ if (children.length > 2) {
+ sb.append(children[2].getText().trim().replace("
", "")).append(" ");
+ }
+ }
+ return false;
+ }
}
diff --git a/src/main/java/io/github/linwancen/plugin/show/ext/DocMapUtils.java b/src/main/java/io/github/linwancen/plugin/show/ext/DocMapUtils.java
new file mode 100644
index 0000000..f99dcb8
--- /dev/null
+++ b/src/main/java/io/github/linwancen/plugin/show/ext/DocMapUtils.java
@@ -0,0 +1,38 @@
+package io.github.linwancen.plugin.show.ext;
+
+import io.github.linwancen.plugin.show.settings.ProjectSettingsState;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+class DocMapUtils {
+
+ private DocMapUtils() {}
+
+ @Nullable
+ static String get(@NotNull Map>> docMap,
+ @NotNull ProjectSettingsState set, @NotNull String... words) {
+ List keywordDoc = list(docMap, words);
+ if (keywordDoc.size() >= set.extDocColumn) {
+ return keywordDoc.get(set.extDocColumn - 1);
+ }
+ return null;
+ }
+
+ @NotNull
+ private static List list(@NotNull Map>> docMap, @NotNull String... words) {
+ for (Map.Entry>> entry : docMap.entrySet()) {
+ Map> map = entry.getValue();
+ for (String word : words) {
+ List wordDoc = map.get(word);
+ if (wordDoc != null) {
+ return wordDoc;
+ }
+ }
+ }
+ return Collections.emptyList();
+ }
+}
diff --git a/src/main/java/io/github/linwancen/plugin/show/ext/LineExtUtils.java b/src/main/java/io/github/linwancen/plugin/show/ext/LineExtUtils.java
new file mode 100644
index 0000000..8c78c73
--- /dev/null
+++ b/src/main/java/io/github/linwancen/plugin/show/ext/LineExtUtils.java
@@ -0,0 +1,105 @@
+package io.github.linwancen.plugin.show.ext;
+
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.vfs.VirtualFile;
+import io.github.linwancen.plugin.show.ext.conf.ConfCache;
+import io.github.linwancen.plugin.show.settings.ProjectSettingsState;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class LineExtUtils {
+
+ private LineExtUtils() {}
+
+ public static String extDoc(@NotNull Project project, @NotNull VirtualFile file,
+ @NotNull Document document, int startOffset, int endOffset) {
+ Map>> keyMap = ConfCache.keyMap(project, file);
+ if (keyMap.isEmpty()) {
+ return null;
+ }
+ Pattern pattern = ConfCache.pattern(project, file, keyMap);
+ if (pattern == null || pattern.pattern().length() == 0) {
+ return null;
+ }
+ Map>> docMap = ConfCache.docMap(project, file);
+ if (docMap.isEmpty()) {
+ return null;
+ }
+ Map>> treeMap = ConfCache.treeMap(project, file);
+ String text = document.getText(new TextRange(startOffset, endOffset));
+ String[] words = pattern.split(text);
+ Matcher matcher = pattern.matcher(text);
+ return extDoc(keyMap, matcher, docMap, words, treeMap, project);
+ }
+
+ @Nullable
+ private static String extDoc(@NotNull Map>> keyMap, @NotNull Matcher matcher,
+ @NotNull Map>> docMap, @NotNull String[] words,
+ @NotNull Map>> treeMap, @NotNull Project project) {
+ ProjectSettingsState set = ProjectSettingsState.getInstance(project);
+ Pattern extReplaceToSpace = set.extReplaceToSpace;
+ boolean isReplaceToSpace = extReplaceToSpace.pattern().length() != 0;
+ boolean haveDoc = false;
+ StringBuilder sb = new StringBuilder();
+ for (String s : words) {
+ if (appendDoc(set, sb, docMap, treeMap, extReplaceToSpace, isReplaceToSpace, s)) {
+ haveDoc = true;
+ }
+ appendKeyDoc(set, sb, keyMap, matcher);
+ }
+ if (!haveDoc) {
+ return null;
+ }
+ return sb.toString();
+ }
+
+ private static boolean appendDoc(ProjectSettingsState set, StringBuilder sb,
+ @NotNull Map>> docMap,
+ @NotNull Map>> treeMap,
+ Pattern extReplaceToSpace, boolean isReplaceToSpace, String word) {
+ word = word.trim();
+ if (isReplaceToSpace) {
+ word = extReplaceToSpace.matcher(word).replaceAll(" ");
+ }
+ if (word.length() == 0) {
+ return false;
+ }
+ String wordDoc = DocMapUtils.get(docMap, set, word);
+ if (wordDoc != null) {
+ sb.append(wordDoc);
+ return true;
+ }
+ String treeDoc = DocMapUtils.get(treeMap, set, word);
+ if (treeDoc != null) {
+ sb.append(treeDoc);
+ return true;
+ }
+ sb.append(word);
+ return false;
+ }
+
+ private static void appendKeyDoc(@NotNull ProjectSettingsState set, @NotNull StringBuilder sb,
+ @NotNull Map>> keyMap,
+ @NotNull Matcher matcher) {
+ if (!matcher.find()) {
+ return;
+ }
+ String keyword = matcher.group();
+ // "" if no doc
+ String keyDoc = DocMapUtils.get(keyMap, set, keyword);
+ if (keyDoc != null) {
+ sb.append(" ").append(keyDoc);
+ }
+ // no one space
+ if (sb.length() != 1) {
+ sb.append(" ");
+ }
+ }
+}
diff --git a/src/main/java/io/github/linwancen/plugin/show/ext/TreeExtUtils.java b/src/main/java/io/github/linwancen/plugin/show/ext/TreeExtUtils.java
new file mode 100644
index 0000000..a11205a
--- /dev/null
+++ b/src/main/java/io/github/linwancen/plugin/show/ext/TreeExtUtils.java
@@ -0,0 +1,29 @@
+package io.github.linwancen.plugin.show.ext;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import io.github.linwancen.plugin.show.ext.conf.ConfCache;
+import io.github.linwancen.plugin.show.settings.ProjectSettingsState;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Map;
+
+public class TreeExtUtils {
+
+ private TreeExtUtils() {}
+
+ public static String extDoc(@NotNull Project project, @NotNull VirtualFile file) {
+ Map>> docMap = ConfCache.treeMap(project, file);
+ ProjectSettingsState set = ProjectSettingsState.getInstance(project);
+ String[] words = {
+ file.getName(),
+ file.getNameWithoutExtension(),
+ };
+ String extDoc = DocMapUtils.get(docMap, set, words);
+ if (extDoc == null) {
+ return null;
+ }
+ return " " + extDoc;
+ }
+}
diff --git a/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfCache.java b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfCache.java
new file mode 100644
index 0000000..3fc5196
--- /dev/null
+++ b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfCache.java
@@ -0,0 +1,144 @@
+package io.github.linwancen.plugin.show.ext.conf;
+
+import com.intellij.notification.NotificationDisplayType;
+import com.intellij.notification.NotificationGroup;
+import com.intellij.notification.NotificationType;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+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 org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Pattern;
+
+/**
+ * call ConfFactory, ConfCacheGetUtils
+ */
+public class ConfCache {
+
+ private static final Pattern LINE_PATTERN = Pattern.compile("[\\r\\n]++");
+
+ static final String EXT = "tsv";
+ static final String KEY_MID_EXT = ".key";
+ static final String DOC_MID_EXT = ".doc";
+ static final String TREE_MID_EXT = ".tree";
+
+ private static final Map>> KEY_CACHE = new ConcurrentHashMap<>();
+ private static final Map>> DOC_CACHE = new ConcurrentHashMap<>();
+ private static final Map>> TREE_CACHE = new ConcurrentHashMap<>();
+
+ private ConfCache() {}
+
+ @Nullable
+ public static Pattern pattern(@Nullable Project project, @NotNull VirtualFile file,
+ @NotNull Map>> keyMap) {
+ return ConfFactory.buildPattern(project, file.getPath(), keyMap);
+ }
+
+ @NotNull
+ public static Map>> keyMap(@Nullable Project project, @NotNull VirtualFile file) {
+ return ConfCacheGetUtils.get(file, KEY_MID_EXT, KEY_CACHE);
+ }
+
+ @NotNull
+ public static Map>> docMap(@Nullable Project project, @NotNull VirtualFile file) {
+ return ConfCacheGetUtils.get(file, DOC_MID_EXT, DOC_CACHE);
+ }
+
+ @NotNull
+ public static Map>> treeMap(@Nullable Project project, @NotNull VirtualFile file) {
+ return ConfCacheGetUtils.get(file, TREE_MID_EXT, TREE_CACHE);
+ }
+
+ static void remove(@NotNull VirtualFile file, String name) {
+ if (name != null) {
+ int i = name.lastIndexOf('.');
+ name = name.substring(0, i);
+ } else {
+ name = file.getNameWithoutExtension();
+ }
+ if (name.endsWith(KEY_MID_EXT)) {
+ KEY_CACHE.remove(file);
+ } else if (name.endsWith(DOC_MID_EXT)) {
+ DOC_CACHE.remove(file);
+ } else if (name.endsWith(TREE_MID_EXT)) {
+ TREE_CACHE.remove(file);
+ }
+ }
+
+ static void copy(@NotNull VirtualFile file, @NotNull VirtualFile newFile) {
+ String name = file.getNameWithoutExtension();
+ if (name.endsWith(KEY_MID_EXT)) {
+ copyCache(file, newFile, KEY_CACHE);
+ } else if (name.endsWith(DOC_MID_EXT)) {
+ copyCache(file, newFile, DOC_CACHE);
+ } else if (name.endsWith(TREE_MID_EXT)) {
+ copyCache(file, newFile, TREE_CACHE);
+ }
+ }
+
+ private static void copyCache(@Nullable VirtualFile file, @NotNull VirtualFile newFile,
+ @NotNull Map>> cache) {
+ Map> map = cache.get(file);
+ if (map != null) {
+ cache.put(newFile, new LinkedHashMap<>(map));
+ }
+ }
+
+ private static final NotificationGroup LOAD_ALL_LOG =
+ new NotificationGroup("Ext Doc Conf Load All", NotificationDisplayType.BALLOON, true);
+
+ static void loadAll(@NotNull Project project) {
+ ApplicationManager.getApplication().runReadAction(() ->
+ DumbService.getInstance(project).runReadActionInSmartMode(() -> {
+ Collection files = FilenameIndex.getAllFilesByExt(project, EXT);
+ StringBuilder sb = new StringBuilder();
+ KEY_CACHE.clear();
+ DOC_CACHE.clear();
+ TREE_CACHE.clear();
+ for (VirtualFile file : files) {
+ load(project, file);
+ sb.append(file.getPath()).append("\n");
+ }
+ if (files.isEmpty()) {
+ return;
+ }
+ LOAD_ALL_LOG.createNotification("Ext doc conf load all complete", files.size() + " files",
+ sb.toString(), NotificationType.INFORMATION).notify(project);
+ }));
+ }
+
+ static void loadFile(@Nullable Project project, @NotNull VirtualFile file) {
+ ApplicationManager.getApplication().runReadAction(() -> ConfCache.load(project, file));
+ }
+
+ private static void load(@Nullable Project project, @NotNull VirtualFile file) {
+ if (!ConfCache.EXT.equals(file.getExtension())) {
+ return;
+ }
+ Document document = FileDocumentManager.getInstance().getDocument(file);
+ if (document == null) {
+ return;
+ }
+ String text = document.getText();
+ String name = file.getNameWithoutExtension();
+ // this pattern would skip empty line
+ String[] lines = LINE_PATTERN.split(text);
+ if (name.endsWith(KEY_MID_EXT)) {
+ KEY_CACHE.put(file, ConfFactory.buildMap(project, file.getPath(), lines, true));
+ } else if (name.endsWith(DOC_MID_EXT)) {
+ DOC_CACHE.put(file, ConfFactory.buildMap(project, file.getPath(), lines, false));
+ } else if (name.endsWith(TREE_MID_EXT)) {
+ TREE_CACHE.put(file, ConfFactory.buildMap(project, file.getPath(), lines, false));
+ }
+ }
+}
diff --git a/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfCacheGetUtils.java b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfCacheGetUtils.java
new file mode 100644
index 0000000..285604d
--- /dev/null
+++ b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfCacheGetUtils.java
@@ -0,0 +1,111 @@
+package io.github.linwancen.plugin.show.ext.conf;
+
+import com.intellij.openapi.vfs.VirtualFile;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+class ConfCacheGetUtils {
+
+ private static final String SKIP_PATH = "doc";
+ private static final String MATCH_STR = "%";
+
+ private ConfCacheGetUtils() {}
+
+ /**
+ *
file:
+ *
a/b/c.ext
+ *
+ *
configure file priority:
+ *
a/b/c.ext.key.tsv
+ *
a/b/x.c.ext.key.tsv
+ *
a/b/ext.key.tsv
+ *
a/b/x.ext.key.tsv
+ *
a/c.ext.key.tsv
+ *
+ * @return {@code }
+ */
+ @NotNull
+ static TreeMap get(@NotNull VirtualFile file,
+ @NotNull String confMidExt,
+ @NotNull Map cache) {
+ String path = file.getPath();
+ String name = file.getName();
+ String ext = file.getExtension();
+ if (ext == null) {
+ ext = "";
+ }
+ TreeMap map = new TreeMap<>();
+ int max = path.length();
+ int length = String.valueOf(max).length();
+ for (Map.Entry entry : cache.entrySet()) {
+ VirtualFile confFile = entry.getKey();
+ String confName = confFile.getNameWithoutExtension();
+ String confPath = confFile.getPath();
+ int level = level(path, confPath);
+ if (level == 0) {
+ continue;
+ }
+ String levelStr = StringUtils.leftPad(String.valueOf(max - level), length, '0');
+ if ((name + confMidExt).equals(confName)) {
+ map.put(levelStr + "\b" + confPath, entry.getValue());
+ } else if (confName.endsWith((name + confMidExt))) {
+ map.put(levelStr + "\t" + confPath, entry.getValue());
+ } else if ((ext + confMidExt).equals(confName)) {
+ map.put(levelStr + "\n" + confPath, entry.getValue());
+ } else if (confName.endsWith((ext + confMidExt))) {
+ map.put(levelStr + "\f" + confPath, entry.getValue());
+ }
+ }
+ return map;
+ }
+
+ private static int level(String path, String confPath) {
+ path = srcPath(path);
+ confPath = srcPath(confPath);
+ String[] paths = StringUtils.split(path, '/');
+ String[] confPaths = StringUtils.split(confPath, '/');
+ int length = confPaths.length;
+ if (length > paths.length) {
+ return 0;
+ }
+ for (int i = 0; i < length; i++) {
+ if (!match(paths[i], confPaths[i])) {
+ return i;
+ }
+ }
+ return length;
+ }
+
+ @NotNull
+ private static String srcPath(String path) {
+ int i = path.indexOf('!');
+ if (i != -1) {
+ return path.substring(i + 1);
+ }
+ i = path.indexOf("/resources");
+ if (i != -1) {
+ return path.substring(i + "/resources".length());
+ }
+ return path;
+ }
+
+ private static boolean match(String path, String confPath) {
+ if (confPath.equals(path) || SKIP_PATH.equals(confPath)) {
+ return true;
+ }
+ boolean end = false;
+ boolean start = false;
+ if (confPath.startsWith(MATCH_STR)) {
+ confPath = confPath.substring(1);
+ end = true;
+ }
+ if (confPath.endsWith(MATCH_STR)) {
+ confPath = confPath.substring(0, confPath.length() - 1);
+ start = true;
+ }
+ return end && path.endsWith(confPath) || start && path.startsWith(confPath);
+ }
+}
diff --git a/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfFactory.java b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfFactory.java
new file mode 100644
index 0000000..6e544ad
--- /dev/null
+++ b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfFactory.java
@@ -0,0 +1,98 @@
+package io.github.linwancen.plugin.show.ext.conf;
+
+import com.google.common.base.Splitter;
+import com.intellij.notification.NotificationDisplayType;
+import com.intellij.notification.NotificationGroup;
+import com.intellij.notification.NotificationType;
+import com.intellij.openapi.project.Project;
+import com.twelvemonkeys.util.LinkedSet;
+import groovy.json.StringEscapeUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Pattern;
+
+class ConfFactory {
+
+ private static final Pattern EMPTY_PATTERN = Pattern.compile("");
+ private static final Map PATTERN_CACHE = new ConcurrentHashMap<>();
+ private static final NotificationGroup REGEXP_LOG =
+ new NotificationGroup("Ext Doc Keyword Regexp Compile", NotificationDisplayType.TOOL_WINDOW, true);
+ private static final NotificationGroup DATA_LOG =
+ new NotificationGroup("Ext Doc Data", NotificationDisplayType.BALLOON, true);
+
+ private ConfFactory() {}
+
+ @Nullable
+ static Pattern buildPattern(@Nullable Project project, @NotNull String path,
+ @NotNull Map>> map) {
+ Set exclude = new LinkedSet<>();
+ StringBuilder sb = new StringBuilder();
+ for (Map> keyMap : map.values()) {
+ // key() is escape
+ for (List list : keyMap.values()) {
+ String key = list.get(0);
+ if (key.startsWith("?")) {
+ exclude.add(key.substring(1));
+ } else if (key.length() > 0 && !exclude.contains(key)) {
+ sb.append(key).append("|");
+ }
+ }
+ }
+ if (sb.length() > 0) {
+ sb.delete(sb.length() - 1, sb.length());
+ }
+ String regex = sb.toString();
+ Pattern pattern = PATTERN_CACHE.get(regex);
+ if (pattern != null) {
+ return pattern;
+ }
+ sb.insert(0, "\n");
+ sb.insert(0, path);
+ sb.insert(0, "\n");
+ try {
+ Pattern compile = Pattern.compile(regex);
+ PATTERN_CACHE.put(regex, compile);
+ REGEXP_LOG.createNotification("Ext doc keyword regexp compile success", regex.length() + " chars",
+ sb.toString(), NotificationType.INFORMATION).notify(project);
+ return compile;
+ } catch (Exception e) {
+ sb.insert(0, "\n");
+ sb.insert(0, e.getLocalizedMessage());
+ PATTERN_CACHE.put(regex, EMPTY_PATTERN);
+ REGEXP_LOG.createNotification("Ext doc keyword regexp compile fail", regex.length() + " chars",
+ sb.toString(), NotificationType.ERROR).notify(project);
+ return null;
+ }
+ }
+
+ public static final Pattern DEL_PATTERN = Pattern.compile("\\(\\?[^)]++\\)");
+
+ @NotNull
+ static Map> buildMap(@Nullable Project project, @NotNull String path,
+ @NotNull String[] lines, boolean isKey) {
+ Map> map = new LinkedHashMap<>();
+ for (String line : lines) {
+ List words = Splitter.on('\t').splitToList(line);
+ if (!words.isEmpty()) {
+ String key = words.get(0);
+ if (key.length() == 0) {
+ continue;
+ }
+ if (isKey) {
+ key = StringEscapeUtils.unescapeJava(key);
+ String del = DEL_PATTERN.matcher(key).replaceAll("");
+ if (del.length() != 0) {
+ key = del;
+ }
+ }
+ map.put(key, words);
+ }
+ }
+ DATA_LOG.createNotification("Ext doc file load complete", map.size() + " lines",
+ "\n" + path, NotificationType.INFORMATION).notify(project);
+ return map;
+ }
+}
diff --git a/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfFileChangeListener.java b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfFileChangeListener.java
new file mode 100644
index 0000000..fc802a8
--- /dev/null
+++ b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfFileChangeListener.java
@@ -0,0 +1,23 @@
+package io.github.linwancen.plugin.show.ext.conf;
+
+import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
+import com.intellij.openapi.fileEditor.FileEditorManagerListener;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * call ConfCache.loadFile
+ */
+public class ConfFileChangeListener implements FileEditorManagerListener {
+
+ @Override
+ public void selectionChanged(@NotNull FileEditorManagerEvent event) {
+ VirtualFile file = event.getOldFile();
+ if (file == null) {
+ return;
+ }
+ if (file.exists()) {
+ ConfCache.loadFile(event.getManager().getProject(), file);
+ }
+ }
+}
diff --git a/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfFileInitListener.java b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfFileInitListener.java
new file mode 100644
index 0000000..2f67883
--- /dev/null
+++ b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfFileInitListener.java
@@ -0,0 +1,17 @@
+package io.github.linwancen.plugin.show.ext.conf;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManagerListener;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * call ConfCache.loadAll
+ */
+public class ConfFileInitListener implements ProjectManagerListener {
+
+ @Override
+ public void projectOpened(@NotNull Project project) {
+ ConfCache.loadAll(project);
+ }
+
+}
diff --git a/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfFileListener.java b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfFileListener.java
new file mode 100644
index 0000000..a5cde1f
--- /dev/null
+++ b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ConfFileListener.java
@@ -0,0 +1,64 @@
+package io.github.linwancen.plugin.show.ext.conf;
+
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.newvfs.BulkFileListener;
+import com.intellij.openapi.vfs.newvfs.events.*;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+/**
+ * call ConfCache.loadFile, copy, remove
+ */
+public class ConfFileListener implements BulkFileListener {
+
+ @Override
+ public void after(@NotNull List extends VFileEvent> events) {
+ for (VFileEvent event : events) {
+ forEvent(event);
+ }
+ }
+
+ private static void forEvent(VFileEvent event) {
+ VirtualFile file = event.getFile();
+ if (file == null) {
+ return;
+ }
+ if (event instanceof VFilePropertyChangeEvent) {
+ VFilePropertyChangeEvent changeEvent = (VFilePropertyChangeEvent) event;
+ if ("name".equals(changeEvent.getPropertyName())) {
+ String oldName = changeEvent.getOldValue().toString();
+ if (oldName.endsWith(ConfCache.EXT)) {
+ // change cache too complicated so remove
+ ConfCache.remove(file, oldName);
+ }
+ }
+ }
+ if (!ConfCache.EXT.equals(file.getExtension())) {
+ return;
+ }
+ if (event instanceof VFileMoveEvent) {
+ return;
+ }
+ if (event instanceof VFileDeleteEvent) {
+ ConfCache.remove(file, null);
+ return;
+ }
+ if (event instanceof VFileCopyEvent) {
+ VFileCopyEvent copyEvent = (VFileCopyEvent) event;
+ VirtualFile newFile = copyEvent.findCreatedFile();
+ if (newFile == null) {
+ return;
+ }
+ try {
+ ConfCache.copy(file, newFile);
+ } catch (Exception ignored) {
+ // ignore
+ }
+ return;
+ }
+ // VFileCreateEvent
+ // VFileContentChangeEvent
+ ConfCache.loadFile(null, file);
+ }
+}
diff --git a/src/main/java/io/github/linwancen/plugin/show/ext/conf/ReloadExtDocAction.java b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ReloadExtDocAction.java
new file mode 100644
index 0000000..4272c72
--- /dev/null
+++ b/src/main/java/io/github/linwancen/plugin/show/ext/conf/ReloadExtDocAction.java
@@ -0,0 +1,20 @@
+package io.github.linwancen.plugin.show.ext.conf;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * call ConfCache.loadAll
+ */
+public class ReloadExtDocAction extends AnAction {
+ @Override
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+ ConfCache.loadAll(project);
+ }
+}
diff --git a/src/main/java/io/github/linwancen/plugin/show/line/LineDocRightToLeftUtils.java b/src/main/java/io/github/linwancen/plugin/show/line/LineDocRightToLeftUtils.java
index 54cdccf..20ac8ea 100644
--- a/src/main/java/io/github/linwancen/plugin/show/line/LineDocRightToLeftUtils.java
+++ b/src/main/java/io/github/linwancen/plugin/show/line/LineDocRightToLeftUtils.java
@@ -19,24 +19,18 @@ public class LineDocRightToLeftUtils {
// End is always white, can not -1 because @see class.name need it
PsiElement element = viewProvider.findElementAt(endOffset);
if (element == null) {
+ // one line end
return null;
}
- AppSettingsState instance = AppSettingsState.getInstance();
- PsiElement identifier;
- PsiDocComment psiDocComment;
+ AppSettingsState setting = AppSettingsState.getInstance();
while (true) {
- identifier = PsiTreeUtil.prevVisibleLeaf(element);
+ PsiElement identifier = PsiTreeUtil.prevVisibleLeaf(element);
if (identifier != null && identifier.getTextRange().getStartOffset() < startOffset) {
identifier = null;
}
- if (identifier == null || identifier instanceof PsiIdentifier) {
- if (instance.inJson && element.getLanguage().is(JsonLanguage.INSTANCE)) {
- return JsonDocUtils.jsonDoc(element, startOffset, endOffset);
- }
- psiDocComment = LineDocUtils.elementDoc(element, identifier, startOffset, endOffset);
- if (psiDocComment != null) {
- return psiDocComment;
- }
+ PsiDocComment docComment = psiDoc(setting, identifier, element, startOffset, endOffset);
+ if (docComment != null) {
+ return docComment;
}
if (identifier == null) {
return null;
@@ -44,4 +38,16 @@ public class LineDocRightToLeftUtils {
element = identifier;
}
}
+
+ public static PsiDocComment psiDoc(AppSettingsState setting,
+ PsiElement identifier, PsiElement element,
+ int startOffset, int endOffset) {
+ if (identifier != null && !(identifier instanceof PsiIdentifier)) {
+ return null;
+ }
+ if (setting.inJson && element.getLanguage().is(JsonLanguage.INSTANCE)) {
+ return JsonDocUtils.jsonDoc(element, startOffset, endOffset);
+ }
+ return LineDocUtils.elementDoc(element, identifier, startOffset, endOffset);
+ }
}
diff --git a/src/main/java/io/github/linwancen/plugin/show/settings/AppSettingsState.java b/src/main/java/io/github/linwancen/plugin/show/settings/AppSettingsState.java
index 0444af4..59fba7c 100644
--- a/src/main/java/io/github/linwancen/plugin/show/settings/AppSettingsState.java
+++ b/src/main/java/io/github/linwancen/plugin/show/settings/AppSettingsState.java
@@ -22,9 +22,9 @@ public class AppSettingsState implements PersistentStateComponent林万程
English Notes:
- Show javadoc comments at the Project view Tree structure
- Show javadoc comments at the end-of-line
- Show javadoc comments at "xx ClassNameOrSimpleName.json" and jump to field
-
- Config: settings -> Tools -> Show Comment Global/Project
+
- Config: settings -> Tools -> // Show Comment Global/Project
-Chinese Notes:
+
+External Comment:
+
+- Reload: Tools -> 🔄 // Reload External Comment
+
- path/[any][filename.]ext.tree.tsv // file and folder tree comment 📝 📁
+
- path/[any][filename.]ext.key.tsv // line keywords to split and comment
+
- path/[any][filename.]ext.doc.tsv // line words comment
+
- In path, "doc" can replace any, and can use % like in SQL
+
- The line in key.tsv would concat lines with `|` to regexp, longer str should in front, startWith `?` to exclude
+
- Chang tsv file in find pop window would not reload!
+
- The tsv conf file must could be search in "Go to File"(Ctrl + Shift + N)
+
+
+
+中文说明:
- 在结构树显示 文档注释
- 在行末尾显示 文档注释
- 支持 "xx 类全名或简名.json" 文档注释与跳转到字段
-
- 修改配置:设置 -> 工具 -> Show Comment Global/Project
+
- 修改配置:设置 -> 工具 -> // Show Comment Global/Project
+
+
+外部注释:
+
+- 重新加载:工具 -> "🔄 // Reload External Comment"
+
- path/[any][filename.]ext.tree.tsv // 文件(夹)注释 📝 📁
+
- path/[any][filename.]ext.key.tsv // 切割关键字与注释
+
- path/[any][filename.]ext.doc.tsv // 词注释
+
- key.tsv 的每一行将会用`|`连接起来形成正则表达式,较长的关键字应该放在前面,用 `?` 开头排除
+
- doc 文件夹可以替换任何一层文件夹,可以像 SQL 那样用 % 模糊匹配
+
- 在搜索弹出窗中修改 tsv 文件将不会被重加载
+
- tsv 配置文件必须能被搜索(Ctrl + Shift + N)
]]>
@@ -25,6 +51,21 @@ Chinese Notes:
com.intellij.modules.platform
com.intellij.modules.java
+
+
+
+
+
+
+
+
+
+
+
+
@@ -32,18 +73,24 @@ Chinese Notes:
+ displayName="// Show Comment Global"/>
+ displayName="// Show Comment Project"/>
+
+
+
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%em%/COBOL-compute-word.cbl.key.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%em%/COBOL-compute-word.cbl.key.tsv
new file mode 100644
index 0000000..90ce387
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%em%/COBOL-compute-word.cbl.key.tsv
@@ -0,0 +1,27 @@
+ COBOL 算数词汇【关键字】
+ ADD/SUBTRACT CORR WS-GROUP1 TO WS-GROUP2 // 数组间很少用
+ GIVING =>
+
+ ADD A B TO C D // C = A + B + C; D = A + B + D
+ ADD A B C TO D GIVING E // E = A + B + C + D
+ TO 是基本关键字 => 这里忽略
+ ADD +
+
+
+ SUBTRACT A B FROM C D // C = C - (A + B); D = D - (A + B)
+ SUBTRACT A B C FROM D GIVING E // E = D - (A + B + C)
+ SUBTRACT -
+ FROM 从
+
+
+ MULTIPLY A BY B C // B = A * B; C = A * C
+ MULTIPLY A BY B GIVING C // C = A * B
+ MULTIPLY *
+ BY by
+
+
+ DIVIDE A INTO B // B = B / A;
+ DIVIDE A BY B GIVING C REMAINDER D // C = A / B ... D
+ DIVIDE ÷
+ INTO 从
+ REMAINDER 余
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%em%/COBOL-compute.cbl.key.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%em%/COBOL-compute.cbl.key.tsv
new file mode 100644
index 0000000..5a610e5
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%em%/COBOL-compute.cbl.key.tsv
@@ -0,0 +1,6 @@
+ COBOL 算数符号【关键字】
+ COMPUTE
+ \+ +
+ \- -
+ \* *
+ \/ /
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%mo/COBOL-accept.cbl.doc.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%mo/COBOL-accept.cbl.doc.tsv
new file mode 100644
index 0000000..008bc65
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%mo/COBOL-accept.cbl.doc.tsv
@@ -0,0 +1,6 @@
+ COBOL 获取词汇(非必要)
+DATE 系统日期
+DATE YYYYMMDD 系统日期
+TIME 系统时间
+SYSIN 系统输入
+CONSOLE 控制台
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%mo/COBOL-accept.cbl.key.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%mo/COBOL-accept.cbl.key.tsv
new file mode 100644
index 0000000..d5b246c
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%mo/COBOL-accept.cbl.key.tsv
@@ -0,0 +1,3 @@
+ COBOL 获取【关键字】(非必要)
+ ACCEPT 获取
+ FROM 从
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%mo/COBOL-loop.cbl.key.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%mo/COBOL-loop.cbl.key.tsv
new file mode 100644
index 0000000..1059533
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%mo/COBOL-loop.cbl.key.tsv
@@ -0,0 +1,22 @@
+ COBOL 循环【关键字】(非必要)
+
+ PERFORM HELLO-WORLD THRU STRUCT
+ THRU ~
+
+ PERFORM A-PARA UNTIL COUNT=5
+ PERFORM A-PARA WITH TEST BEFORE UNTIL COUNT=5
+ PERFORM A-PARA WITH TEST AFTER UNTIL COUNT=5
+ UNTIL until
+ COUNT count
+ WITH TEST BEFORE before
+ WITH TEST AFTER after
+
+
+ PERFORM A-PARA 5 TIMES.
+(?=\d++ TIMES)
+
+ PERFORM A-PARA VARYING A FROM 1 BY 1 UNTIL A=5
+ VARYING varying
+
+ GO TO para-1 para-2 para-3 DEPENDING ON x.
+ DEPENDING ON switch
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%mo/COBOL-string.cbl.key.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%mo/COBOL-string.cbl.key.tsv
new file mode 100644
index 0000000..e60f523
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/%mo/COBOL-string.cbl.key.tsv
@@ -0,0 +1,31 @@
+ COBOL 字符串【关键字】(非必要)
+
+ INSPECT input-string
+ TALLYING output-count FOR ALL CHARACTERS
+ INSPECT
+ TALLYING
+ FOR ALL CHARACTERS
+
+
+ INSPECT input-string REPLACING ALL char1 BY char2.
+ REPLACING
+
+
+ STRING ws-string1 DELIMITED BY SPACE
+ ws-string2 DELIMITED BY SIZE
+ INTO ws-destination-string
+ WITH POINTER ws-count
+ ON OVERFLOW DISPLAY message1
+ NOT ON OVERFLOW DISPLAY message2
+ END-STRING.
+ STRING
+ DELIMITED
+ BY by
+
+
+ UNSTRING ws-string DELIMITED BY SPACE
+ INTO ws-str1, ws-str2
+ WITH POINTER ws-count
+ ON OVERFLOW DISPLAY message
+ NOT ON OVERFLOW DISPLAY message
+ END-UNSTRING.
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL-file.tsv.tree.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL-file.tsv.tree.tsv
new file mode 100644
index 0000000..7b50aea
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL-file.tsv.tree.tsv
@@ -0,0 +1,20 @@
+COBOL-file.tsv.tree.tsv 📝 COBOL 相关文件注释
+
+COBOL.cbl.key.tsv COBOL 必要【关键字】
+
+COBOL-struct.cbl.doc.tsv COBOL 文件结构【关键字】
+
+COBOL-data.cbl.key.tsv COBOL 数据部必要【关键字】
+COBOL-data-layout.cbl.key.tsv COBOL 数据布局【关键字】
+COBOL-data-type.cbl.key.tsv COBOL 数据类型【关键字】
+
+COBOL-compute.cbl.key.tsv COBOL 算数符号【关键字】
+COBOL-compute-word.cbl.key.tsv COBOL 算数词汇【关键字】
+
+COBOL-accept.cbl.doc.tsv COBOL 获取词汇(非必要)
+COBOL-accept.cbl.key.tsv COBOL 获取【关键字】(非必要)
+COBOL-loop.cbl.key.tsv COBOL 循环【关键字】(非必要)
+COBOL-string.cbl.key.tsv COBOL 字符串【关键字】(非必要)
+
+COBOL_IDEA.md COBOL IDEA 高亮设置
+COBOL_keyword1.md COBOL COBOL IDEA 高亮 普通关键字
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL-struct.cbl.doc.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL-struct.cbl.doc.tsv
new file mode 100644
index 0000000..47bea81
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL-struct.cbl.doc.tsv
@@ -0,0 +1,18 @@
+ COBOL 文件结构【关键字】
+
+IDENTIFICATION DIVISION 【标识部】
+
+ENVIRONMENT DIVISION 【环境部】
+SOURCE-COMPUTER (编译系统)
+OBJECT-COMPUTER (执行系统)
+CONFIGURATION SECTION [配置节]
+INPUT-OUTPUT SECTION [输入输出节]
+FILE-CONTROL (外部数据集)
+
+DATA DIVISION 【数据部】
+FILE SECTION [文件节]
+WORKING-STORAGE SECTION [工作存储节]
+LOCAL-STORAGE SECTION [本地存储节]
+LINKAGE SECTION [连接节]
+
+PROCEDURE DIVISION 【过程部】
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL.cbl.key.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL.cbl.key.tsv
new file mode 100644
index 0000000..35a2a62
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL.cbl.key.tsv
@@ -0,0 +1,29 @@
+ COBOL 必要【关键字】
+ key 文件的注释前面要有制表符
+ 长的要放在短的前面
+
+^.{7}
+\. .
+\, ,
+
+ INITIALIZE 初始化
+ MOVE
+ TO =>
+
+ IF if
+ 有些程序 THEN 没有换行所以要加这个关键字
+ THEN
+ NOT(?! '| ?=) !
+ AND (?!') &&
+ OR (?!') ||
+
+ 兼容单字符字典
+\=(?! ?') =
+> >
+< <
+
+ PERFORM call
+ WS-
+
+(? Settings -> Editor -> File Types
+- 文件 -> 设置 -> 编辑器 -> 文件类型
+
+## Syntax Highlighting
+
+Line comment: *
+
+## Keywords
+
+
+1 blue 蓝色
+
+
+[关键字1列表](COBOL_keyword1.md)
+
+
+2 Purple 紫色
+END-IF
+IF
+THEN
+
+
+
+3 cyanogen 青色
+INITIALIZE
+
+
+
+4 brown 褐色
+PERFORM
+
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL_keyword1.md b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL_keyword1.md
new file mode 100644
index 0000000..4b40391
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/COBOL_keyword1.md
@@ -0,0 +1,410 @@
+SET
+TO
+VARYING
+ACCEPT
+ACCESS
+ADD
+ADDRESS
+ADVANCING
+AFTER
+ALL
+ALPHABET
+ALPHABETIC
+ALPHABETIC-LOWER
+ALPHABETIC-UPPER
+ALPHANUMERIC
+ALPHANUMERIC-EDITED
+ALSO
+ALTER
+ALTERNATE
+AND
+ANY
+APPLY
+ARE
+AREA
+AREAS
+ASCENDING
+ASSIGN
+AT
+AUTHOR
+BASIS
+BEFORE
+BEGINNING
+BINARY
+BLANK
+BLOCK
+BOTTOM
+BY
+CALL
+CANCEL
+CBL
+CD
+CF
+CH
+CHARACTER
+CHARACTERS
+CLASS
+CLASS-ID
+CLOCK-UNITS
+CLOSE
+COBOL
+CODE
+CODE-SET
+COLLATING
+COLUMN
+COM-REG
+COMMA
+COMMON
+COMMUNICATION
+COMP
+COMP-1
+COMP-2
+COMP-3
+COMP-4
+COMP-5
+COMPUTATIONAL
+COMPUTATIONAL-1
+COMPUTATIONAL-2
+COMPUTATIONAL-3
+COMPUTATIONAL-4
+COMPUTATIONAL-5
+COMPUTE
+CONFIGURATION
+CONTAINS
+CONTENT
+CONTINUE
+CONTROL
+CONTROLS
+CONVERTING
+COPY
+CORR
+CORRESPONDING
+COUNT
+CURRENCY
+DATA
+DATE-COMPILED
+DATE-WRITTEN
+DAY
+DAY-OF-WEEK
+DBCS
+DE
+DEBUG-CONTENTS
+DEBUG-ITEM
+DEBUG-LINE
+DEBUG-NAME
+DEBUG-SUB-1
+DEBUG-SUB-2
+DEBUG-SUB-3
+DEBUGGING
+DECIMAL-POINT
+DECLARATIVES
+DELETE
+DELIMITED
+DELIMITER
+DEPENDING
+DESCENDING
+DESTINATION
+DETAIL
+DISPLAY
+DISPLAY-1
+DIVIDE
+DIVISION
+DOWN
+DUPLICATES
+DYNAMIC
+EGCS
+EGI
+EJECT
+ELSE
+EMI
+ENABLE
+END
+END-ADD
+END-CALL
+END-COMPUTE
+END-DELETE
+END-DIVIDE
+END-EVALUATE
+
+END-INVOKE
+END-MULTIPLY
+END-OF-PAGE
+END-PERFORM
+END-READ
+END-RECEIVE
+END-RETURN
+END-REWRITE
+END-SEARCH
+END-START
+END-STRING
+END-SUBTRACT
+END-UNSTRING
+END-WRITE
+ENDING
+ENTER
+ENTRY
+ENVIRONMENT
+EOP
+EQUAL
+ERROR
+ESI
+EVALUATE
+EVERY
+EXCEPTION
+EXIT
+EXTEND
+EXTERNAL
+FALSE
+FD
+FILE
+FILE-CONTROL
+FILLER
+FINAL
+FIRST
+FOOTING
+FOR
+FROM
+FUNCTION
+GENERATE
+GIVING
+GLOBAL
+GO
+GOBACK
+GREATER
+GROUP
+HEADINHIGH-VALUHIGH-VALUES
+I-O
+I-O-CONTROL
+ID
+IDENTIFICATION
+
+IN
+INDEX
+INDEXED
+INDICATE
+INHERITS
+INITIAL
+
+INITIATE
+INPUT
+INPUT-OUTPUT
+INSERT
+INSPECT
+INSTALLATION
+INTO
+INVALID
+INVOKE
+IS
+JUSJUSTIFIE
+KANJKE
+LABEL
+LAST
+LEADING
+LEFT
+LENGTH
+LESS
+LIMIT
+LIMITS
+LINAGE
+LINAGE-COUNTER
+LINE
+LINE-COUNTER
+LINES
+LINKAGE
+LOCAL-STORAGE
+LOCK
+LOW-VALUE
+LOW-VALUES
+MEMORY
+MERGE
+MESSAGE
+METACLASS
+METHOD
+METHOD-ID
+MODE
+MODULES
+MORE-LABELS
+MOVE
+MULTIPLE
+MULTIPLY
+NATIVE
+NATIVE_BINARY
+NEGATIVE
+NEXT
+NO
+NOT
+NULL
+NULLS
+NUMBER
+NUMERIC
+NUMERIC-EDITED
+OBJECT
+OBJECT-COMPUTER
+OCCURS
+OF
+OFF
+OMITTED
+ON
+OPEN
+OPTIONAL
+OR
+ORDER
+ORGANIZATION
+OTHER
+OUTPUT
+OVERFLOW
+OVERRIDE
+PACKED-DECIMAL
+PADDING
+PAGE
+PAGE-COUNTER
+PASSWORD
+
+PF
+PH
+PIC
+PICTURE
+PLUS
+POINTER
+POSITION
+POSITIVE
+PRINTING
+PROCEDURE
+PROCEDURE-POINTER
+PROCEDURES
+PROCEED
+PROCESSING
+PROGRAM
+PROGRAM-ID
+PURGE
+QUEUQUOTQUOTES
+RANDOM
+RD
+READ
+READY
+RECEIVE
+RECORD
+RECORDING
+RECORDS
+RECURSIVE
+REDEFINES
+REEL
+REFERENCE
+REFERENCES
+RELATIVE
+RELEASE
+RELOAD
+REMAINDER
+REMOVAL
+RENAMES
+REPLACE
+REPLACING
+REPORT
+REPORTING
+REPORTS
+REPOSITORY
+RERUN
+RESERVE
+RESET
+RETURN
+RETURN-CODE
+RETURNING
+REVERSED
+REWIND
+REWRITE
+RF
+RH
+RIGHT
+ROUNDED
+RUN
+SAME
+SD
+SEARCH
+SECTION
+SECURITY
+SEGMENT
+SEGMENT-LIMIT
+SELECT
+SELF
+SEND
+SENTENCE
+SEPARATE
+SEQUENCE
+SEQUENTIAL
+SERVICE
+SET
+SHIFT-IN
+SHIFT-OUT
+SIGN
+SIZE
+SKIP1
+SKIP2
+SKIP3
+SORT
+SORT-CONTROL
+SORT-CORE-SIZE
+SORT-FILE-SIZE
+SORT-MERGE
+SORT-MESSAGE
+SORT-MODE-SIZE
+SORT-RETURN
+SOURCE
+SOURCE-COMPUTER
+SPACE
+SPACES
+SPECIAL-NAMES
+STANDARD
+STANDARD-1
+STANDARD-2
+START
+STATUS
+STOP
+STRING
+SUB-QUEUE-1
+SUB-QUEUE-2
+SUB-QUEUE-3
+SUBTRACT
+SUM
+SUPER
+SUPPRESS
+SYMBOLIC
+SYNC
+SYNCHRONIZED
+TABLE
+TALLY
+TALLYING
+TAPE
+TERMINAL
+TERMINATE
+TEST
+TEXT
+THAN
+
+THROUGH
+THRU
+TIME
+TIMES
+TITLE
+TO
+TOP
+TRACE
+TRAILING
+TRUE
+TYPE
+UNIT
+UNSTRING
+UNTIL
+UP
+UPON
+USAGE
+USE
+USING
+VALUVALUEVARYING
+WHEN
+WHEN-COMPILED
+WITH
+WORDS
+WORKING-STORAGE
+WRITE
+WRITE-ONLY
+ZERZEROEZEROS
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/de%/COBOL-data-layout.cbl.key.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/de%/COBOL-data-layout.cbl.key.tsv
new file mode 100644
index 0000000..a856626
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/de%/COBOL-data-layout.cbl.key.tsv
@@ -0,0 +1,10 @@
+ COBOL 数据布局【关键字】
+
+ REDEFINES 重定义
+ RENAMES 重命名
+ USAGE IS
+ COMP 二进制整数
+ COMP-1 单精度浮点
+ COMP-2 双精度浮点
+ COMP-3 压缩十进制
+ COPY
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/de%/COBOL-data-type.cbl.key.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/de%/COBOL-data-type.cbl.key.tsv
new file mode 100644
index 0000000..0e1cc6c
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/de%/COBOL-data-type.cbl.key.tsv
@@ -0,0 +1,15 @@
+ COBOL 数据类型【关键字】
+
+ 66 重命名
+ 77 不能被细分项
+ 88 条件名
+
+9\( ( 数字
+A\( ( 字母
+X\( ( 字母数字
+V\( ( 隐式小数
+S\( ( 符号
+P\( ( 假定小数
+
+ 数据
+ VALUE =
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/de%/COBOL-data.cbl.key.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/de%/COBOL-data.cbl.key.tsv
new file mode 100644
index 0000000..dcb8c25
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/de%/COBOL-data.cbl.key.tsv
@@ -0,0 +1,5 @@
+ COBOL 数据部必要【关键字】
+^.{7} +\d{2}
+ PIC
+ COPY
+ REPLACING
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/ACCEPT.cbl b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/ACCEPT.cbl
new file mode 100644
index 0000000..b414e81
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/ACCEPT.cbl
@@ -0,0 +1,6 @@
+
+ ACCEPT HELLO-WORLD FROM DATE
+ ACCEPT HELLO-WORLD FROM DATE YYYYMMDD
+ ACCEPT HELLO-WORLD FROM TIME
+ ACCEPT HELLO-WORLD FROM SYSIN
+ ACCEPT HELLO-WORLD FROM CONSOLE
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/BASE.cbl b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/BASE.cbl
new file mode 100644
index 0000000..75e2074
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/BASE.cbl
@@ -0,0 +1,9 @@
+
+123456 INITIALIZE HELLO-WORLD
+ IF KEY = '1' AND KEY NOT = '2' AND (B OR NOT C) THEN
+ MOVE WS-HELLO-WORLD TO HELLO-WORLD
+ END IF
+ TABLE(STRUCT)
+ HELLO-WORLD(1:1)
+ PERFORM B001-A
+ * PERFORM STRUCT
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/COMPUTE.cbl b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/COMPUTE.cbl
new file mode 100644
index 0000000..a781717
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/COMPUTE.cbl
@@ -0,0 +1,10 @@
+
+ COMPUTE HELLO-WORLD = (A - B) * 100 / (C + D)
+ END-COMPUTE
+ ADD A TO B
+ ADD A B TO C D
+ SUBTRACT A FROM C
+ SUBTRACT A B FROM C D
+ MULTIPLY A BY B C
+ MULTIPLY A BY B GIVING C
+ DIVIDE A BY B GIVING C REMAINDER D
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/LOOP.cbl b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/LOOP.cbl
new file mode 100644
index 0000000..2d971a0
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/LOOP.cbl
@@ -0,0 +1,9 @@
+
+ PERFORM STRUCT THRU HELLO-WORLD
+ END-PERFORM.
+ PERFORM STRUCT UNTIL COUNT=5
+ PERFORM STRUCT WITH TEST BEFORE UNTIL COUNT=5
+ PERFORM STRUCT WITH TEST AFTER UNTIL COUNT=5
+ PERFORM STRUCT 5 TIMES
+ PERFORM STRUCT VARYING HELLO-WORLD FROM 1 BY 1 UNTIL HELLO-WORLD=5
+ GO TO STRUCT DEPENDING ON HELLO-WORLD.
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/STRUCT.cbl b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/STRUCT.cbl
new file mode 100644
index 0000000..e584ce9
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/demo/STRUCT.cbl
@@ -0,0 +1,22 @@
+
+ IDENTIFICATION DIVISION.
+ PROGRAM-ID. STRUCT.
+
+ ENVIRONMENT DIVISION.
+ SOURCE-COMPUTER. XXX-ZOS.
+ OBJECT-COMPUTER. XXX-ZOS.
+ CONFIGURATION SECTION.
+ INPUT-OUTPUT SECTION.
+ FILE-CONTROL.
+
+ DATA DIVISION.
+ FILE SECTION.
+ WORKING-STORAGE SECTION.
+ 01 WS-HELLO-WORLD PIC X(9) VALUE 10 .
+ LOCAL-STORAGE SECTION.
+ 01 HELLO-WORLD PIC X(9) VALUE 10 .
+ LINKAGE SECTION.
+ 01 A PIC 9(9) VALUE 10 .
+
+
+ PROCEDURE DIVISION.
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/doc/cbl.doc.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/doc/cbl.doc.tsv
new file mode 100644
index 0000000..2fe6d80
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/doc/cbl.doc.tsv
@@ -0,0 +1,9 @@
+KEY = '1' 字典1
+KEY NOT = '2' 非 字典2
+HELLO-WORLD 你好世界
+B001-A 程序A
+A a
+B b
+C c
+D d
+HELLO-WORLD(1:1 ( 状态1
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/doc/cbl.key.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/doc/cbl.key.tsv
new file mode 100644
index 0000000..ea0ec7e
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/doc/cbl.key.tsv
@@ -0,0 +1 @@
+TABLE\( 表(
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/doc/file.cbl.tree.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/doc/file.cbl.tree.tsv
new file mode 100644
index 0000000..14de759
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/doc/file.cbl.tree.tsv
@@ -0,0 +1,5 @@
+ACCEPT 获取示例
+BASE 基本示例
+COMPUTE ➗ 计算示例
+LOOP ♻ 循环示例
+STRUCT 结构示例
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/doc/file.tsv.tree.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/doc/file.tsv.tree.tsv
new file mode 100644
index 0000000..ddb8e4c
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/doc/file.tsv.tree.tsv
@@ -0,0 +1,4 @@
+cbl.doc.tsv 自定义注释
+cbl.key.tsv 自定义【关键字】
+file.cbl.tree.tsv 📝 本目录 cbl 文件注释
+file.tsv.tree.tsv 📝 本目录 tsv 文件注释
\ No newline at end of file
diff --git a/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/folder.tsv.tree.tsv b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/folder.tsv.tree.tsv
new file mode 100644
index 0000000..5eeb7a1
--- /dev/null
+++ b/src/test/java/io/github/linwancen/plugin/show/demo/ext/cobol/folder.tsv.tree.tsv
@@ -0,0 +1,6 @@
+folder.tsv.tree.tsv 📁 本目录文件夹注释
+demo 📝 示例
+%em% 前后 %s 匹配
+%mo 前 %s 匹配
+de% 后 %s 匹配
+doc doc 匹配
\ No newline at end of file