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