Skip to content

Commit db5b038

Browse files
authored
fix: remove getting skipped files popup (#68)
1 parent d434f0f commit db5b038

File tree

10 files changed

+365
-88
lines changed

10 files changed

+365
-88
lines changed

src/main/kotlin/com/github/monosoul/git/updateindex/extended/ExtendedUpdateIndexTask.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package com.github.monosoul.git.updateindex.extended
22

3+
import com.github.monosoul.git.updateindex.extended.changes.view.SkippedWorktreeFilesCache
34
import com.intellij.openapi.diagnostic.logger
45
import com.intellij.openapi.progress.ProgressIndicator
56
import com.intellij.openapi.progress.Task
67
import com.intellij.openapi.project.Project
8+
import com.intellij.openapi.vcs.changes.ChangesViewManager
79
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager
810
import com.intellij.openapi.vfs.VirtualFile
911
import com.intellij.vcsUtil.VcsUtil
@@ -29,6 +31,11 @@ class ExtendedUpdateIndexTask(
2931
files.forEach(vcsDirtyScopeManager::fileDirty)
3032
}
3133
}
34+
35+
logger.debug("Git update index command executed, refreshing Changes view")
36+
37+
SkippedWorktreeFilesCache.getInstance(project).clear()
38+
ChangesViewManager.getInstanceEx(project).scheduleRefresh()
3239
}
3340

3441
private fun GitLineHandler.runAndLog() = run(Git.getInstance()::runCommand)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.github.monosoul.git.updateindex.extended.changes.view
2+
3+
import com.github.monosoul.git.updateindex.extended.changes.view.Constants.SKIPPED_FILE
4+
import com.intellij.externalProcessAuthHelper.AuthenticationMode.NONE
5+
import com.intellij.openapi.project.Project
6+
import com.intellij.openapi.vcs.FilePath
7+
import com.intellij.openapi.vcs.ProjectLevelVcsManager
8+
import com.intellij.openapi.vcs.VcsException
9+
import com.intellij.openapi.vcs.VcsRoot
10+
import com.intellij.vcsUtil.VcsUtil
11+
import git4idea.GitUtil
12+
import git4idea.commands.Git
13+
import git4idea.commands.GitCommand.LS_FILES
14+
import git4idea.commands.GitCommandResult
15+
import git4idea.commands.GitLineHandler
16+
import org.jetbrains.annotations.Blocking
17+
18+
@Blocking
19+
fun getSkippedWorktreeFiles(project: Project): List<FilePath> {
20+
val vcsManager = ProjectLevelVcsManager.getInstance(project) ?: return emptyList()
21+
22+
return vcsManager.allVcsRoots.map(VcsRoot::getPath).map { vcsRoot ->
23+
GitLineHandler(project, vcsRoot, LS_FILES).apply {
24+
addParameters("-v")
25+
ignoreAuthenticationMode = NONE
26+
}.let(Git.getInstance()::runCommand).mapOrThrow { result ->
27+
result.filter {
28+
it.startsWith(SKIPPED_FILE)
29+
}.map {
30+
it.removePrefix("$SKIPPED_FILE ")
31+
}.map {
32+
VcsUtil.getFilePath(vcsRoot, GitUtil.unescapePath(it))
33+
}
34+
}
35+
}.flatten()
36+
}
37+
38+
@Throws(VcsException::class)
39+
private fun <T> GitCommandResult.mapOrThrow(mapper: (List<String>) -> T): T {
40+
throwOnError()
41+
42+
return mapper(output)
43+
}

src/main/kotlin/com/github/monosoul/git/updateindex/extended/changes/view/GetSkippedWorktreeFilesTask.kt

Lines changed: 0 additions & 48 deletions
This file was deleted.

src/main/kotlin/com/github/monosoul/git/updateindex/extended/changes/view/SkippedWorktreeChangesViewModifier.kt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,32 @@ import com.github.monosoul.git.updateindex.extended.changes.view.Constants.PROPE
44
import com.intellij.ide.util.PropertiesComponent
55
import com.intellij.openapi.diagnostic.debug
66
import com.intellij.openapi.diagnostic.logger
7-
import com.intellij.openapi.progress.ProgressManager
87
import com.intellij.openapi.project.Project
98
import com.intellij.openapi.vcs.changes.ChangesViewModifier
109
import com.intellij.openapi.vcs.changes.ui.ChangesViewModelBuilder
1110

1211
class SkippedWorktreeChangesViewModifier(private val project: Project) : ChangesViewModifier {
1312

14-
private val logger = logger<SkippedWorktreeChangesViewModifier>()
15-
1613
override fun modifyTreeModelBuilder(modelBuilder: ChangesViewModelBuilder) {
1714
val showSkippedTree = PropertiesComponent.getInstance().getBoolean(PROPERTY, false)
1815
if (!showSkippedTree) {
1916
logger.debug { "Show skipped files is turned off. Doing nothing." }
2017
return
2118
}
2219

23-
val skippedFiles = ProgressManager.getInstance().run(GetSkippedWorktreeFilesTask(project))
20+
val cache = SkippedWorktreeFilesCache.getInstance(project)
21+
val skippedFiles = cache.getOrLoad()
22+
23+
if (skippedFiles != null && skippedFiles.isNotEmpty()) {
24+
logger.debug { "Skipped files: $skippedFiles" }
2425

25-
logger.debug { "Skipped files: $skippedFiles" }
26+
val rootNode = ChangesBrowserSkippedWorktreeNode(project, skippedFiles)
27+
modelBuilder.insertSubtreeRoot(rootNode)
28+
modelBuilder.insertFilesIntoNode(skippedFiles.mapNotNull { it.virtualFile }, rootNode)
29+
}
30+
}
2631

27-
val rootNode = ChangesBrowserSkippedWorktreeNode(project, skippedFiles)
28-
modelBuilder.insertSubtreeRoot(rootNode)
29-
modelBuilder.insertFilesIntoNode(skippedFiles.mapNotNull { it.virtualFile }, rootNode)
32+
companion object {
33+
private val logger = logger<SkippedWorktreeChangesViewModifier>()
3034
}
3135
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.github.monosoul.git.updateindex.extended.changes.view
2+
3+
import com.intellij.openapi.components.Service
4+
import com.intellij.openapi.components.service
5+
import com.intellij.openapi.diagnostic.logger
6+
import com.intellij.openapi.project.Project
7+
import com.intellij.openapi.util.Disposer
8+
import com.intellij.openapi.vcs.FilePath
9+
import com.intellij.openapi.vcs.changes.ChangesViewManager
10+
import com.intellij.platform.ide.progress.withBackgroundProgress
11+
import kotlinx.coroutines.CoroutineScope
12+
import kotlinx.coroutines.Dispatchers
13+
import kotlinx.coroutines.ExperimentalCoroutinesApi
14+
import kotlinx.coroutines.SupervisorJob
15+
import kotlinx.coroutines.cancel
16+
import kotlinx.coroutines.launch
17+
import java.util.concurrent.atomic.AtomicReference
18+
19+
@Service(Service.Level.PROJECT)
20+
class SkippedWorktreeFilesCache(private val project: Project) {
21+
22+
@OptIn(ExperimentalCoroutinesApi::class)
23+
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO.limitedParallelism(1))
24+
private val cachedFiles = AtomicReference<List<FilePath>?>(null)
25+
26+
init {
27+
Disposer.register(project) { scope.cancel() }
28+
}
29+
30+
fun getOrLoad(): List<FilePath>? {
31+
val cached = cachedFiles.get()
32+
if (cached != null) {
33+
return cached
34+
}
35+
36+
scope.launch {
37+
try {
38+
val files = withBackgroundProgress(project, "Getting Skipped Files", cancellable = false) {
39+
getSkippedWorktreeFiles(project)
40+
}
41+
cachedFiles.set(files)
42+
ChangesViewManager.getInstanceEx(project).scheduleRefresh()
43+
} catch (e: Exception) {
44+
logger.warn("Failed to load skipped worktree files", e)
45+
}
46+
}
47+
48+
return null
49+
}
50+
51+
fun clear() {
52+
cachedFiles.set(null)
53+
}
54+
55+
/**
56+
* For testing purposes: set cached files directly without async loading
57+
*/
58+
internal fun setCachedFiles(files: List<FilePath>) {
59+
cachedFiles.set(files)
60+
}
61+
62+
companion object {
63+
private val logger = logger<SkippedWorktreeFilesCache>()
64+
65+
fun getInstance(project: Project): SkippedWorktreeFilesCache = project.service()
66+
}
67+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
<projectService
3636
serviceImplementation="com.github.monosoul.git.updateindex.extended.support.PresentationUpdater"/>
3737

38+
<projectService
39+
serviceImplementation="com.github.monosoul.git.updateindex.extended.changes.view.SkippedWorktreeFilesCache"/>
40+
3841
<vcs.changes.changesViewModifier
3942
implementation="com.github.monosoul.git.updateindex.extended.changes.view.SkippedWorktreeChangesViewModifier"/>
4043
</extensions>

src/test/kotlin/com/github/monosoul/git/updateindex/extended/ExtendedUpdateIndexTaskTest.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ package com.github.monosoul.git.updateindex.extended
22

33
import com.github.monosoul.git.updateindex.extended.ExtendedUpdateIndexTaskTest.FilesAndCommandArgumentsSource.NoVcsRoot
44
import com.github.monosoul.git.updateindex.extended.ExtendedUpdateIndexTaskTest.FilesAndCommandArgumentsSource.WithVcsRoot
5+
import com.github.monosoul.git.updateindex.extended.changes.view.SkippedWorktreeFilesCache
56
import com.intellij.mock.MockApplication
67
import com.intellij.mock.MockProject
78
import com.intellij.openapi.application.ApplicationManager.setApplication
89
import com.intellij.openapi.progress.ProgressIndicator
910
import com.intellij.openapi.util.Disposer.dispose
1011
import com.intellij.openapi.vcs.ProjectLevelVcsManager
12+
import com.intellij.openapi.vcs.changes.ChangesViewEx
13+
import com.intellij.openapi.vcs.changes.ChangesViewI
14+
import com.intellij.openapi.vcs.changes.ChangesViewManager
1115
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager
1216
import com.intellij.openapi.vfs.VirtualFile
1317
import git4idea.commands.Git
@@ -18,6 +22,7 @@ import io.mockk.every
1822
import io.mockk.impl.annotations.MockK
1923
import io.mockk.junit5.MockKExtension
2024
import io.mockk.mockk
25+
import io.mockk.spyk
2126
import io.mockk.verify
2227
import io.mockk.verifyAll
2328
import io.mockk.verifyOrder
@@ -56,6 +61,11 @@ internal class ExtendedUpdateIndexTaskTest {
5661
@MockK
5762
private lateinit var gitCommandResult: GitCommandResult
5863

64+
@MockK(relaxUnitFun = true)
65+
private lateinit var changesViewManager: ChangesViewManager
66+
67+
private lateinit var cache: SkippedWorktreeFilesCache
68+
5969
@BeforeEach
6070
fun setUp() {
6171
parent = TestDisposable()
@@ -68,6 +78,12 @@ internal class ExtendedUpdateIndexTaskTest {
6878
project.registerService(vcsManager, parent)
6979
project.registerService(dirtyScopeManager, parent)
7080
project.registerService(updateIndexLineHandlerFactory, parent)
81+
project.registerService<ChangesViewI>(changesViewManager, parent)
82+
project.registerService<ChangesViewEx>(changesViewManager, parent)
83+
84+
// Register the cache service with a spy to verify clear() calls
85+
cache = spyk(SkippedWorktreeFilesCache(project))
86+
project.registerService(SkippedWorktreeFilesCache::class.java, cache, parent)
7187

7288
every { updateIndexLineHandlerFactory.invoke(any(), any(), any()) } returns gitLineHandler
7389
every { git.runCommand(any<GitLineHandler>()) } returns gitCommandResult
@@ -98,6 +114,10 @@ internal class ExtendedUpdateIndexTaskTest {
98114
gitLineHandler wasNot Called
99115
dirtyScopeManager wasNot Called
100116
}
117+
verify {
118+
cache.clear()
119+
changesViewManager.scheduleRefresh()
120+
}
101121
}
102122

103123
@ParameterizedTest
@@ -127,6 +147,10 @@ internal class ExtendedUpdateIndexTaskTest {
127147
verify(exactly = files.size) {
128148
dirtyScopeManager.fileDirty(any<VirtualFile>())
129149
}
150+
verify {
151+
cache.clear()
152+
changesViewManager.scheduleRefresh()
153+
}
130154
}
131155

132156
@ParameterizedTest
@@ -159,6 +183,10 @@ internal class ExtendedUpdateIndexTaskTest {
159183
verify(exactly = files.size) {
160184
dirtyScopeManager.fileDirty(any<VirtualFile>())
161185
}
186+
verify {
187+
cache.clear()
188+
changesViewManager.scheduleRefresh()
189+
}
162190
}
163191

164192
private sealed class FilesAndCommandArgumentsSource(

src/test/kotlin/com/github/monosoul/git/updateindex/extended/changes/view/GetSkippedWorktreeFilesTaskTest.kt renamed to src/test/kotlin/com/github/monosoul/git/updateindex/extended/changes/view/GetSkippedWorktreeFilesKtTest.kt

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ import git4idea.config.GitExecutableManager
2424
import io.mockk.every
2525
import io.mockk.impl.annotations.MockK
2626
import io.mockk.junit5.MockKExtension
27-
import io.mockk.mockk
2827
import io.mockk.slot
2928
import io.mockk.verifyAll
29+
import kotlinx.coroutines.runBlocking
3030
import org.apache.commons.lang3.RandomStringUtils
3131
import org.junit.jupiter.api.AfterEach
3232
import org.junit.jupiter.api.BeforeEach
@@ -46,7 +46,7 @@ import kotlin.random.Random
4646
import kotlin.random.nextInt
4747

4848
@ExtendWith(MockKExtension::class)
49-
internal class GetSkippedWorktreeFilesTaskTest {
49+
internal class GetSkippedWorktreeFilesKtTest {
5050

5151
private lateinit var parent: TestDisposable
5252
private lateinit var application: MockApplication
@@ -70,8 +70,6 @@ internal class GetSkippedWorktreeFilesTaskTest {
7070
@MockK
7171
private lateinit var git: Git
7272

73-
private lateinit var task: GetSkippedWorktreeFilesTask
74-
7573
@BeforeEach
7674
fun setUp() {
7775
parent = TestDisposable()
@@ -95,8 +93,6 @@ internal class GetSkippedWorktreeFilesTaskTest {
9593
vcsRoot = VcsRoot(vcs, MockVirtualFile(true, "vcsRoot"))
9694

9795
every { vcsManager.allVcsRoots } returns arrayOf(vcsRoot)
98-
99-
task = GetSkippedWorktreeFilesTask(project)
10096
}
10197

10298
@AfterEach
@@ -112,8 +108,9 @@ internal class GetSkippedWorktreeFilesTaskTest {
112108
fun `should do nothing if the result doesn't contain skipped files`(result: GitCommandResult) {
113109
every { git.runCommand(any<GitLineHandler>()) } returns result
114110

115-
task.run(mockk())
116-
val actual = task.result
111+
val actual = runBlocking {
112+
getSkippedWorktreeFiles(project)
113+
}
117114

118115
expectThat(actual).isEmpty()
119116

@@ -125,8 +122,9 @@ internal class GetSkippedWorktreeFilesTaskTest {
125122
fun `should return a list of skipped files`(result: GitCommandResult) {
126123
every { git.runCommand(any<GitLineHandler>()) } returns result
127124

128-
task.run(mockk())
129-
val actual = task.result
125+
val actual = runBlocking {
126+
getSkippedWorktreeFiles(project)
127+
}
130128

131129
expectThat(actual)
132130
.hasSize(result.output.size)
@@ -141,10 +139,10 @@ internal class GetSkippedWorktreeFilesTaskTest {
141139
fun `should throw an exception in case of an error`(result: GitCommandResult) {
142140
every { git.runCommand(any<GitLineHandler>()) } returns result
143141

144-
task.run(mockk())
145-
146142
expectThrows<VcsException> {
147-
task.result
143+
runBlocking {
144+
getSkippedWorktreeFiles(project)
145+
}
148146
}.message isEqualTo result.errorOutputAsJoinedString
149147

150148
verifyGitCall()

0 commit comments

Comments
 (0)