fix: line doc cache invalidation after closing the first open project
This commit is contained in:
@@ -69,7 +69,7 @@ patchPluginXml {
|
||||
|
||||
<h2>中文更新说明:</h2>
|
||||
<ul>
|
||||
<li>2.21 增加 文件树注释 用 xml/html/vue 第 1 或第 2 行注释当文件注释
|
||||
<li>2.25 增加 文件树注释 用 xml/html/vue 第 1 或第 2 行注释当文件注释
|
||||
<li>2.24 增加 行末注释 Maven pom.xml \${} 注释
|
||||
<li>2.23 增加 行末注释 kotlin 注解注释
|
||||
<li>2.22 增加 文件树注释 ollama models 文件夹从 manifests 获取 blobs 文件注释
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package io.github.linwancen.plugin.show.cache;
|
||||
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.editor.LineExtensionInfo;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||
import io.github.linwancen.plugin.show.LineEnd;
|
||||
import io.github.linwancen.plugin.show.bean.LineInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -19,7 +17,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
public class LineEndCacheUtils {
|
||||
|
||||
@@ -28,6 +26,7 @@ public class LineEndCacheUtils {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LineEndCacheUtils.class);
|
||||
|
||||
public static final Map<Project, Map<VirtualFile, Map<Integer, LineEndCache>>> cache = new ConcurrentHashMap<>();
|
||||
public static final Map<Project, ScheduledFuture<?>> taskMap = new ConcurrentHashMap<>();
|
||||
|
||||
public static @Nullable Collection<LineExtensionInfo> get(@NotNull LineInfo info) {
|
||||
try {
|
||||
@@ -39,7 +38,7 @@ public class LineEndCacheUtils {
|
||||
@NotNull LineInfo oldInfo = lineCache.info;
|
||||
lineCache.info = info;
|
||||
lineCache.show = true;
|
||||
checkScheduleAndInit(info.project);
|
||||
TaskUtils.init(taskMap, info.project, cache, a -> cacheUpdate(info.project, a));
|
||||
@Nullable List<LineExtensionInfo> list = lineCache.map.get(info.text);
|
||||
// load from other line
|
||||
if (list == null && info.lineCount != oldInfo.lineCount) {
|
||||
@@ -66,87 +65,55 @@ public class LineEndCacheUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static volatile boolean isRun = false;
|
||||
|
||||
private static void checkScheduleAndInit(@NotNull Project project) {
|
||||
if (!isRun) {
|
||||
if (DumbService.isDumb(project)) {
|
||||
return;
|
||||
}
|
||||
synchronized (LineEndCacheUtils.class) {
|
||||
if (!isRun) {
|
||||
isRun = true;
|
||||
AppExecutorUtil.getAppScheduledExecutorService().scheduleWithFixedDelay(() -> {
|
||||
try {
|
||||
ReadAction.nonBlocking(LineEndCacheUtils::cacheUpdate)
|
||||
.inSmartMode(project)
|
||||
.submit(AppExecutorUtil.getAppExecutorService());
|
||||
} catch (ProcessCanceledException ignored) {
|
||||
} catch (Throwable e) {
|
||||
LOG.info("LineEndCacheUtils checkScheduleAndInit catch Throwable but log to record.", e);
|
||||
}
|
||||
}, 0L, 1L, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void cacheUpdate() {
|
||||
cache.forEach((project, fileMap) -> {
|
||||
try {
|
||||
if (project.isDisposed()) {
|
||||
cache.remove(project);
|
||||
private static void cacheUpdate(Project project, Map<VirtualFile, Map<Integer, LineEndCache>> fileMap) {
|
||||
try {
|
||||
fileMap.forEach((file, lineMap) -> lineMap.forEach((lineNumber, lineCache) -> {
|
||||
@NotNull LineInfo info = lineCache.info;
|
||||
@Nullable List<LineExtensionInfo> list = lineCache.map.get(info.text);
|
||||
if (!(lineCache.needUpdate() || list == null)) {
|
||||
return;
|
||||
}
|
||||
fileMap.forEach((file, lineMap) -> lineMap.forEach((lineNumber, lineCache) -> {
|
||||
@NotNull LineInfo info = lineCache.info;
|
||||
@Nullable List<LineExtensionInfo> list = lineCache.map.get(info.text);
|
||||
if (!(lineCache.needUpdate() || list == null)) {
|
||||
try {
|
||||
if (project.isDisposed() || DumbService.isDumb(project) || !file.isValid()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (project.isDisposed() || DumbService.isDumb(project)) {
|
||||
return;
|
||||
}
|
||||
@Nullable LineExtensionInfo lineExt = LineEnd.lineExt(info);
|
||||
@Nullable LineInfo info2 = LineInfo.of(info, lineNumber);
|
||||
if (info2 == null || !info2.text.equals(info.text)) {
|
||||
return;
|
||||
}
|
||||
@Nullable LineExtensionInfo lineExt = LineEnd.lineExt(info);
|
||||
@Nullable LineInfo info2 = LineInfo.of(info, lineNumber);
|
||||
if (info2 == null || !info2.text.equals(info.text)) {
|
||||
return;
|
||||
}
|
||||
if (list != null) {
|
||||
list.clear();
|
||||
}
|
||||
// fix delete line get doc from before line because PsiFile be not updated
|
||||
if ("}".equals(info.text.trim())) {
|
||||
return;
|
||||
}
|
||||
if (lineExt != null) {
|
||||
if (list != null) {
|
||||
list.clear();
|
||||
}
|
||||
// fix delete line get doc from before line because PsiFile be not updated
|
||||
if ("}".equals(info.text.trim())) {
|
||||
return;
|
||||
}
|
||||
if (lineExt != null) {
|
||||
if (list != null) {
|
||||
list.add(lineExt);
|
||||
} else {
|
||||
@NotNull ArrayList<LineExtensionInfo> lineExtList = new ArrayList<>(1);
|
||||
lineExtList.add(lineExt);
|
||||
lineCache.map.put(info.text, lineExtList);
|
||||
}
|
||||
}
|
||||
lineCache.updated();
|
||||
} catch (ProcessCanceledException ignore) {
|
||||
// ignore
|
||||
} catch (Throwable e) {
|
||||
@Nullable String msg = e.getMessage();
|
||||
if (msg == null || !msg.contains("File is not valid")) {
|
||||
LOG.info("LineEndCacheUtils lineMap.forEach catch Throwable but log to record.", e);
|
||||
list.add(lineExt);
|
||||
} else {
|
||||
@NotNull ArrayList<LineExtensionInfo> lineExtList = new ArrayList<>(1);
|
||||
lineExtList.add(lineExt);
|
||||
lineCache.map.put(info.text, lineExtList);
|
||||
}
|
||||
}
|
||||
}));
|
||||
} catch (ProcessCanceledException ignored) {
|
||||
} catch (IllegalStateException ignore) {
|
||||
// ignore inSmartMode(project) throw:
|
||||
// @NotNull method com/intellij/openapi/project/impl/ProjectImpl.getEarlyDisposable must not
|
||||
// return null
|
||||
} catch (Throwable e) {
|
||||
LOG.info("LineEndCacheUtils cache.forEach catch Throwable but log to record.", e);
|
||||
}
|
||||
});
|
||||
lineCache.updated();
|
||||
} catch (ProcessCanceledException ignored) {
|
||||
} catch (Throwable e) {
|
||||
@Nullable String msg = e.getMessage();
|
||||
if (msg == null || !msg.contains("File is not valid")) {
|
||||
LOG.info("LineEndCacheUtils lineMap.forEach catch Throwable but log to record.", e);
|
||||
}
|
||||
}
|
||||
}));
|
||||
} catch (ProcessCanceledException ignored) {
|
||||
} catch (IllegalStateException ignore) {
|
||||
// ignore inSmartMode(project) throw:
|
||||
// @NotNull method com/intellij/openapi/project/impl/ProjectImpl.getEarlyDisposable must not
|
||||
// return null
|
||||
} catch (Throwable e) {
|
||||
LOG.info("LineEndCacheUtils cache.forEach catch Throwable but log to record.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
51
src/main/java/io/github/linwancen/plugin/show/cache/TaskUtils.java
vendored
Normal file
51
src/main/java/io/github/linwancen/plugin/show/cache/TaskUtils.java
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package io.github.linwancen.plugin.show.cache;
|
||||
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class TaskUtils {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TaskUtils.class);
|
||||
|
||||
public static <T> void init(
|
||||
@NotNull Map<Project, ScheduledFuture<?>> taskMap,
|
||||
@NotNull Project project,
|
||||
@NotNull Map<Project, T> cache,
|
||||
@NotNull Consumer<T> func
|
||||
) {
|
||||
taskMap.computeIfAbsent(project,
|
||||
project1 -> AppExecutorUtil.getAppScheduledExecutorService().scheduleWithFixedDelay(() -> {
|
||||
try {
|
||||
ReadAction.nonBlocking(() -> {
|
||||
if (project.isDisposed()) {
|
||||
cache.remove(project);
|
||||
ScheduledFuture<?> task = taskMap.remove(project);
|
||||
if (task != null) {
|
||||
task.cancel(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
T t = cache.get(project);
|
||||
if (t == null) {
|
||||
return;
|
||||
}
|
||||
func.accept(t);
|
||||
})
|
||||
.inSmartMode(project)
|
||||
.submit(AppExecutorUtil.getAppExecutorService());
|
||||
} catch (ProcessCanceledException ignored) {
|
||||
} catch (Throwable e) {
|
||||
LOG.info("TaskUtils init catch Throwable but log to record.", e);
|
||||
}
|
||||
}, 0L, 1L, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
package io.github.linwancen.plugin.show.cache;
|
||||
|
||||
import com.intellij.ide.projectView.ProjectViewNode;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||
import io.github.linwancen.plugin.show.Tree;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -14,7 +12,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
public class TreeCacheUtils {
|
||||
|
||||
@@ -23,6 +21,7 @@ public class TreeCacheUtils {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TreeCacheUtils.class);
|
||||
|
||||
public static final Map<Project, Map<ProjectViewNode<?>, TreeCache>> cache = new ConcurrentHashMap<>();
|
||||
public static final Map<Project, ScheduledFuture<?>> taskMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Nullable
|
||||
public static String treeDoc(@NotNull ProjectViewNode<?> node, @NotNull Project project) {
|
||||
@@ -31,9 +30,9 @@ public class TreeCacheUtils {
|
||||
.computeIfAbsent(project, a -> new ConcurrentHashMap<>())
|
||||
.computeIfAbsent(node, a -> new TreeCache());
|
||||
treeCache.needUpdate = true;
|
||||
checkScheduleAndInit(project);
|
||||
TaskUtils.init(taskMap, project, cache, a -> cacheUpdate(project, a));
|
||||
return treeCache.doc;
|
||||
} catch (ProcessCanceledException e) {
|
||||
} catch (ProcessCanceledException ignored) {
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
LOG.info("TreeCacheUtils catch Throwable but log to record.", e);
|
||||
@@ -41,59 +40,28 @@ public class TreeCacheUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static volatile boolean isRun = false;
|
||||
|
||||
private static void checkScheduleAndInit(@NotNull Project project) {
|
||||
if (!isRun) {
|
||||
if (DumbService.isDumb(project)) {
|
||||
return;
|
||||
}
|
||||
synchronized (TreeCacheUtils.class) {
|
||||
if (!isRun) {
|
||||
isRun = true;
|
||||
AppExecutorUtil.getAppScheduledExecutorService().scheduleWithFixedDelay(() -> {
|
||||
try {
|
||||
ReadAction.nonBlocking(TreeCacheUtils::cacheUpdate)
|
||||
.inSmartMode(project)
|
||||
.submit(AppExecutorUtil.getAppExecutorService());
|
||||
} catch (Throwable e) {
|
||||
LOG.info("TreeCacheUtils checkScheduleAndInit catch Throwable but log to record.", e);
|
||||
private static void cacheUpdate(Project project, Map<ProjectViewNode<?>, TreeCache> nodeCache) {
|
||||
try {
|
||||
nodeCache.forEach((node, treeCache) -> {
|
||||
if (treeCache.needUpdate) {
|
||||
try {
|
||||
if (project.isDisposed() || DumbService.isDumb(project)) {
|
||||
return;
|
||||
}
|
||||
}, 0L, 1L, TimeUnit.SECONDS);
|
||||
treeCache.doc = Tree.treeDoc(node, project);
|
||||
treeCache.needUpdate = false;
|
||||
} catch (ProcessCanceledException ignored) {
|
||||
} catch (Throwable e) {
|
||||
LOG.info("TreeCacheUtils nodeCache.forEach catch Throwable but log to record.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (ProcessCanceledException ignored) {
|
||||
} catch (IllegalStateException ignore) {
|
||||
// ignore inSmartMode(project) throw:
|
||||
// @NotNull method com/intellij/openapi/project/impl/ProjectImpl.getEarlyDisposable must not return null
|
||||
} catch (Throwable e) {
|
||||
LOG.info("TreeCacheUtils cache.forEach catch Throwable but log to record.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void cacheUpdate() {
|
||||
cache.forEach((project, nodeCache) -> {
|
||||
try {
|
||||
if (project.isDisposed()) {
|
||||
cache.remove(project);
|
||||
return;
|
||||
}
|
||||
nodeCache.forEach((node, treeCache) -> {
|
||||
if (treeCache.needUpdate) {
|
||||
try {
|
||||
if (project.isDisposed() || DumbService.isDumb(project)) {
|
||||
return;
|
||||
}
|
||||
treeCache.doc = Tree.treeDoc(node, project);
|
||||
treeCache.needUpdate = false;
|
||||
} catch (ProcessCanceledException ignore) {
|
||||
// ignore
|
||||
} catch (Throwable e) {
|
||||
LOG.info("TreeCacheUtils nodeCache.forEach catch Throwable but log to record.", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (ProcessCanceledException ignored) {
|
||||
} catch (IllegalStateException ignore) {
|
||||
// ignore inSmartMode(project) throw:
|
||||
// @NotNull method com/intellij/openapi/project/impl/ProjectImpl.getEarlyDisposable must not return null
|
||||
} catch (Throwable e) {
|
||||
LOG.info("TreeCacheUtils cache.forEach catch Throwable but log to record.", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user