1.12 ★ External Comment for COBOL etc | 外部注释用于 COBOL 等

This commit is contained in:
林万程
2022-04-06 23:08:03 +08:00
parent ac4ed47c9f
commit 879d61e34a
45 changed files with 1625 additions and 88 deletions

View File

@@ -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 {

View File

@@ -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);
}
}

View File

@@ -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<ColoredFragment> 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<ColoredFragment> 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) {

View File

@@ -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<String> 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("<br>", "")).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("<br>", "")).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("<br>", "")).append(" ");
}
}
return false;
}
}

View File

@@ -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<String, Map<String, List<String>>> docMap,
@NotNull ProjectSettingsState set, @NotNull String... words) {
List<String> keywordDoc = list(docMap, words);
if (keywordDoc.size() >= set.extDocColumn) {
return keywordDoc.get(set.extDocColumn - 1);
}
return null;
}
@NotNull
private static List<String> list(@NotNull Map<String, Map<String, List<String>>> docMap, @NotNull String... words) {
for (Map.Entry<String, Map<String, List<String>>> entry : docMap.entrySet()) {
Map<String, List<String>> map = entry.getValue();
for (String word : words) {
List<String> wordDoc = map.get(word);
if (wordDoc != null) {
return wordDoc;
}
}
}
return Collections.emptyList();
}
}

View File

@@ -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<String, Map<String, List<String>>> 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<String, Map<String, List<String>>> docMap = ConfCache.docMap(project, file);
if (docMap.isEmpty()) {
return null;
}
Map<String, Map<String, List<String>>> 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<String, Map<String, List<String>>> keyMap, @NotNull Matcher matcher,
@NotNull Map<String, Map<String, List<String>>> docMap, @NotNull String[] words,
@NotNull Map<String, Map<String, List<String>>> 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<String, Map<String, List<String>>> docMap,
@NotNull Map<String, Map<String, List<String>>> 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<String, Map<String, List<String>>> 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(" ");
}
}
}

View File

@@ -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<String, Map<String, List<String>>> 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;
}
}

View File

@@ -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<VirtualFile, Map<String, List<String>>> KEY_CACHE = new ConcurrentHashMap<>();
private static final Map<VirtualFile, Map<String, List<String>>> DOC_CACHE = new ConcurrentHashMap<>();
private static final Map<VirtualFile, Map<String, List<String>>> TREE_CACHE = new ConcurrentHashMap<>();
private ConfCache() {}
@Nullable
public static Pattern pattern(@Nullable Project project, @NotNull VirtualFile file,
@NotNull Map<String, Map<String, List<String>>> keyMap) {
return ConfFactory.buildPattern(project, file.getPath(), keyMap);
}
@NotNull
public static Map<String, Map<String, List<String>>> keyMap(@Nullable Project project, @NotNull VirtualFile file) {
return ConfCacheGetUtils.get(file, KEY_MID_EXT, KEY_CACHE);
}
@NotNull
public static Map<String, Map<String, List<String>>> docMap(@Nullable Project project, @NotNull VirtualFile file) {
return ConfCacheGetUtils.get(file, DOC_MID_EXT, DOC_CACHE);
}
@NotNull
public static Map<String, Map<String, List<String>>> 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<VirtualFile, Map<String, List<String>>> cache) {
Map<String, List<String>> 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<VirtualFile> 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));
}
}
}

View File

@@ -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() {}
/**
* <br>file:
* <br>a/b/c.ext
* <br>
* <br>configure file priority:
* <br>a/b/c.ext.key.tsv
* <br>a/b/x.c.ext.key.tsv
* <br>a/b/ext.key.tsv
* <br>a/b/x.ext.key.tsv
* <br>a/c.ext.key.tsv
*
* @return {@code <sortKey, T>}
*/
@NotNull
static <T> TreeMap<String, T> get(@NotNull VirtualFile file,
@NotNull String confMidExt,
@NotNull Map<VirtualFile, T> cache) {
String path = file.getPath();
String name = file.getName();
String ext = file.getExtension();
if (ext == null) {
ext = "";
}
TreeMap<String, T> map = new TreeMap<>();
int max = path.length();
int length = String.valueOf(max).length();
for (Map.Entry<VirtualFile, T> 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);
}
}

View File

@@ -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<String, Pattern> 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<String, Map<String, List<String>>> map) {
Set<String> exclude = new LinkedSet<>();
StringBuilder sb = new StringBuilder();
for (Map<String, List<String>> keyMap : map.values()) {
// key() is escape
for (List<String> 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<String, List<String>> buildMap(@Nullable Project project, @NotNull String path,
@NotNull String[] lines, boolean isKey) {
Map<String, List<String>> map = new LinkedHashMap<>();
for (String line : lines) {
List<String> 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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -22,9 +22,9 @@ public class AppSettingsState implements PersistentStateComponent<AppSettingsSta
public boolean showTreeComment = true;
public boolean showLineEndComment = true;
@SuppressWarnings("all")
@SuppressWarnings("UseJBColor")
public Color lineEndColorBright = new Color(98, 151, 85);
@SuppressWarnings("all")
@SuppressWarnings("UseJBColor")
public Color lineEndColorDark = new Color(98, 151, 85);
public final TextAttributes lineEndTextAttr = new TextAttributes(new JBColor(lineEndColorBright, lineEndColorDark),
null, null, null, Font.ITALIC);
@@ -34,6 +34,7 @@ public class AppSettingsState implements PersistentStateComponent<AppSettingsSta
public boolean findElementRightToLeft = true;
public String lineEndPrefix = " //";
public int lineEndCount = 2;
public int lineEndLen = 0;
public boolean fromCall = true;
public boolean fromNew = true;
public boolean fromRef = true;

View File

@@ -1,7 +1,6 @@
package io.github.linwancen.plugin.show.settings;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.project.Project;
@@ -9,6 +8,8 @@ import com.intellij.util.xmlb.XmlSerializerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.regex.Pattern;
@State(
name = "io.github.linwancen.plugin.comment.settings.ProjectSettingsState",
storages = @Storage("ShowCommentProject.xml")
@@ -21,9 +22,11 @@ public class ProjectSettingsState implements PersistentStateComponent<ProjectSet
public String lineEndExclude = "";
public String[] lineEndIncludeArray = {};
public String[] lineEndExcludeArray = {};
public Pattern extReplaceToSpace = Pattern.compile("");
public int extDocColumn = 2;
public static ProjectSettingsState getInstance(Project project) {
return ServiceManager.getService(project, ProjectSettingsState.class);
return project.getService(ProjectSettingsState.class);
}
@Nullable