Skip to content

Commit f8f93b5

Browse files
committed
refactor: reimplement interactions with files to use the VFS
1 parent 61b30da commit f8f93b5

17 files changed

Lines changed: 339 additions & 241 deletions

src/main/kotlin/com/github/lppedd/cc/CCExtensions.kt

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.intellij.codeInsight.template.impl.TemplateManagerImpl
66
import com.intellij.codeInsight.template.impl.TemplateState
77
import com.intellij.openapi.actionSystem.Presentation
88
import com.intellij.openapi.application.ApplicationManager
9+
import com.intellij.openapi.application.ReadAction
910
import com.intellij.openapi.application.ex.ApplicationUtil
1011
import com.intellij.openapi.diagnostic.Logger
1112
import com.intellij.openapi.editor.Document
@@ -14,19 +15,24 @@ import com.intellij.openapi.editor.EditorModificationUtil
1415
import com.intellij.openapi.editor.ex.util.EditorUtil
1516
import com.intellij.openapi.progress.ProcessCanceledException
1617
import com.intellij.openapi.progress.ProgressManager
18+
import com.intellij.openapi.project.BaseProjectDirectories.Companion.getBaseDirectories
19+
import com.intellij.openapi.project.Project
1720
import com.intellij.openapi.ui.DialogWrapper
1821
import com.intellij.openapi.util.IconLoader
1922
import com.intellij.openapi.util.Key
2023
import com.intellij.openapi.util.TextRange
24+
import com.intellij.openapi.vfs.LocalFileSystem
2125
import com.intellij.openapi.vfs.VFileProperty
2226
import com.intellij.openapi.vfs.VirtualFile
27+
import com.intellij.openapi.vfs.newvfs.FileSystemInterface
2328
import com.intellij.psi.PsiDocumentManager
2429
import com.intellij.psi.PsiElement
2530
import com.intellij.psi.PsiFile
2631
import com.intellij.ui.TextFieldWithAutoCompletionListProvider
2732
import com.intellij.ui.scale.JBUIScale
2833
import java.awt.Color
2934
import java.awt.Robot
35+
import java.io.ByteArrayInputStream
3036
import java.io.InputStream
3137
import java.util.concurrent.CancellationException
3238
import javax.swing.Action
@@ -40,6 +46,26 @@ import kotlin.internal.InlineOnly
4046
import kotlin.math.max
4147
import kotlin.math.min
4248

49+
// region Project
50+
51+
internal fun Project.findRootDir(): VirtualFile? {
52+
val baseDir = getBaseDirectories()
53+
54+
if (baseDir.isNotEmpty()) {
55+
return baseDir.first()
56+
}
57+
58+
// The base path is not prefixed with a file:// schema
59+
val basePath = this.basePath
60+
61+
if (basePath != null) {
62+
return LocalFileSystem.getInstance().findFileByPath(basePath)
63+
}
64+
65+
return null
66+
}
67+
68+
// endregion
4369
// region PsiElement
4470

4571
@InlineOnly
@@ -124,6 +150,21 @@ internal inline val VirtualFile.isHidden: Boolean
124150
internal inline val VirtualFile.isSymlink: Boolean
125151
get() = `is`(VFileProperty.SYMLINK)
126152

153+
internal fun VirtualFile.getReliableInputStream(): InputStream {
154+
val fs = this.fileSystem
155+
156+
if (fs is FileSystemInterface) {
157+
return fs.getInputStream(this)
158+
}
159+
160+
// Avoid using VirtualFile.getInputStream as it strips the file BOM
161+
val content = ReadAction.compute<ByteArray, Throwable> {
162+
contentsToByteArray(/* cacheContent = */ false)
163+
}
164+
165+
return ByteArrayInputStream(content)
166+
}
167+
127168
// endregion
128169
// region PsiFile
129170

@@ -431,13 +472,6 @@ internal inline fun ListSelectionModel.selectedIndices(): IntArray {
431472
return rv
432473
}
433474

434-
internal fun Throwable.readableMessage(): String =
435-
if (localizedMessage?.isNotBlank() == true) {
436-
localizedMessage
437-
} else {
438-
this::class.simpleName ?: "Anonymous exception object"
439-
}
440-
441475
@Suppress("SameParameterValue")
442476
internal inline fun <T> Logger.runAndLogError(defaultValue: T, block: () -> T): T {
443477
contract {

src/main/kotlin/com/github/lppedd/cc/CCNotification.kt

Lines changed: 0 additions & 16 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.github.lppedd.cc
2+
3+
import com.intellij.notification.NotificationGroupManager
4+
import com.intellij.notification.NotificationType
5+
import com.intellij.openapi.components.Service
6+
import com.intellij.openapi.project.Project
7+
8+
/**
9+
* @author Edoardo Luppi
10+
*/
11+
@Service(Service.Level.PROJECT)
12+
internal class CCNotificationService(private val project: Project) {
13+
private companion object {
14+
private val group = NotificationGroupManager.getInstance().getNotificationGroup("com.github.lppedd.cc.notifications")
15+
}
16+
17+
fun notifyError(message: String) {
18+
val notification = group.createNotification("Conventional Commit", message, NotificationType.ERROR)
19+
notification.notify(project)
20+
}
21+
}

src/main/kotlin/com/github/lppedd/cc/api/impl/InternalCommitTokenProvider.kt

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ package com.github.lppedd.cc.api.impl
22

33
import com.github.lppedd.cc.CC
44
import com.github.lppedd.cc.CCBundle
5-
import com.github.lppedd.cc.CCNotification
5+
import com.github.lppedd.cc.CCNotificationService
66
import com.github.lppedd.cc.api.*
77
import com.github.lppedd.cc.configuration.CCTokensService
8-
import com.github.lppedd.cc.configuration.SchemaValidationException
8+
import com.github.lppedd.cc.configuration.CCTokensService.TokensModel
9+
import com.github.lppedd.cc.configuration.CoAuthorsResult
10+
import com.github.lppedd.cc.configuration.TokensResult
911
import com.intellij.openapi.components.service
1012
import com.intellij.openapi.diagnostic.logger
11-
import com.intellij.openapi.progress.ProcessCanceledException
1213
import com.intellij.openapi.project.Project
1314
import javax.swing.Icon
1415

@@ -25,34 +26,22 @@ internal class InternalCommitTokenProvider(private val project: Project) :
2526
private val logger = logger<InternalCommitTokenProvider>()
2627
}
2728

28-
private val tokensService = project.service<CCTokensService>()
29-
private val defaults
30-
get() = try {
31-
tokensService.getTokens()
32-
} catch (e: ProcessCanceledException) {
33-
throw e
34-
} catch (e: Exception) {
35-
logger.debug("Error while reading the custom tokens file", e)
36-
notifyErrorToUser(e)
37-
tokensService.getBundledTokens()
38-
}
39-
4029
override fun getId(): String =
4130
ID
4231

4332
override fun getPresentation(): ProviderPresentation =
4433
DefaultProviderPresentation
4534

4635
override fun getCommitTypes(prefix: String): Collection<CommitType> =
47-
defaults.types.map { (key, value) -> DefaultCommitToken(key, value.description) }
36+
getTokens().types.map { (key, value) -> DefaultCommitToken(key, value.description) }
4837

4938
override fun getCommitScopes(type: String): Collection<CommitScope> {
50-
val defaultType = defaults.types[type] ?: return emptyList()
39+
val defaultType = getTokens().types[type] ?: return emptyList()
5140
return defaultType.scopes.map { DefaultCommitToken(it.name, it.description) }
5241
}
5342

5443
override fun getCommitFooterTypes(): Collection<CommitFooterType> =
55-
defaults.footerTypes.map { (key, value) -> DefaultCommitToken(key, value.description) }
44+
getTokens().footerTypes.map { (key, value) -> DefaultCommitToken(key, value.description) }
5645

5746
override fun getCommitFooterValues(
5847
footerType: String,
@@ -61,24 +50,40 @@ internal class InternalCommitTokenProvider(private val project: Project) :
6150
subject: String?,
6251
): Collection<CommitFooterValue> {
6352
if ("co-authored-by".equals(footerType, ignoreCase = true)) {
64-
return tokensService.getCoAuthors()
65-
.take(3)
66-
.map { DefaultCommitToken(it, "", true) }
53+
val tokensService = project.service<CCTokensService>()
54+
55+
when (val result = tokensService.getCoAuthors()) {
56+
is CoAuthorsResult.Success -> {
57+
return result.coAuthors.take(3).map { DefaultCommitToken(it, "", true) }
58+
}
59+
is CoAuthorsResult.Failure -> {
60+
logger.debug("Error while getting co-authors", result.message)
61+
}
62+
}
6763
}
6864

69-
val defaultFooterType = defaults.footerTypes[footerType] ?: return emptyList()
65+
val defaultFooterType = getTokens().footerTypes[footerType] ?: return emptyList()
7066
return defaultFooterType.values.map { DefaultCommitToken(it.name, it.description) }
7167
}
7268

73-
private fun notifyErrorToUser(e: Exception) {
74-
val details = if (e is SchemaValidationException) {
75-
CCBundle["cc.notifications.schema.validation"]
76-
} else {
77-
CCBundle["cc.notifications.schema.seeLogs"]
78-
}
69+
private fun getTokens(): TokensModel {
70+
val tokensService = project.service<CCTokensService>()
7971

80-
val message = CCBundle["cc.notifications.schema", details]
81-
CCNotification.createErrorNotification(message).notify(project)
72+
@Suppress("LoggingSimilarMessage")
73+
return when (val result = tokensService.getTokens()) {
74+
is TokensResult.Success -> result.tokens
75+
is TokensResult.FileError -> {
76+
logger.error("Error while getting tokens", result.message)
77+
tokensService.getBundledTokens()
78+
}
79+
is TokensResult.SchemaError -> {
80+
logger.debug("Error while getting tokens", result.failure)
81+
val details = CCBundle["cc.notifications.schema.validation"]
82+
val message = CCBundle["cc.notifications.schema", details]
83+
project.service<CCNotificationService>().notifyError(message)
84+
tokensService.getBundledTokens()
85+
}
86+
}
8287
}
8388

8489
private object DefaultProviderPresentation : ProviderPresentation {

src/main/kotlin/com/github/lppedd/cc/configuration/CCMainConfigurable.kt

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.github.lppedd.cc.configuration
33
import com.github.lppedd.cc.CC
44
import com.github.lppedd.cc.CCBundle
55
import com.intellij.openapi.components.service
6+
import com.intellij.openapi.diagnostic.logger
67
import com.intellij.openapi.options.SearchableConfigurable
78
import com.intellij.openapi.project.Project
89
import com.intellij.openapi.util.Disposer
@@ -12,6 +13,10 @@ import javax.swing.JComponent
1213
* @author Edoardo Luppi
1314
*/
1415
internal class CCMainConfigurable(private val project: Project) : SearchableConfigurable {
16+
private companion object {
17+
private val logger = logger<CCMainConfigurable>()
18+
}
19+
1520
private val tokensService = project.service<CCTokensService>()
1621
private val configService = project.service<CCConfigService>()
1722
private val disposable = Disposer.newDisposable("CCMainConfigurable")
@@ -32,10 +37,17 @@ internal class CCMainConfigurable(private val project: Project) : SearchableConf
3237
gui.customTokensFilePath = configService.customFilePath
3338
gui.customCoAuthorsFilePath = configService.customCoAuthorsFilePath
3439

35-
val tokens = try {
36-
tokensService.getTokens()
37-
} catch (_: Exception) {
38-
tokensService.getBundledTokens()
40+
@Suppress("LoggingSimilarMessage")
41+
val tokens = when (val result = tokensService.getTokens()) {
42+
is TokensResult.Success -> result.tokens
43+
is TokensResult.FileError -> {
44+
logger.debug("Error while getting tokens", result.message)
45+
tokensService.getBundledTokens()
46+
}
47+
is TokensResult.SchemaError -> {
48+
logger.debug("Error while getting tokens", result.failure)
49+
tokensService.getBundledTokens()
50+
}
3951
}
4052

4153
gui.setTokens(tokens.types)
@@ -59,11 +71,17 @@ internal class CCMainConfigurable(private val project: Project) : SearchableConf
5971
configService.customCoAuthorsFilePath = gui.customCoAuthorsFilePath
6072
configService.customFilePath = gui.customTokensFilePath
6173

62-
try {
63-
val tokens = tokensService.getTokens()
64-
gui.setTokens(tokens.types)
65-
} catch (_: Exception) {
66-
gui.revalidate()
74+
@Suppress("LoggingSimilarMessage")
75+
when (val result = tokensService.getTokens()) {
76+
is TokensResult.Success -> gui.setTokens(result.tokens.types)
77+
is TokensResult.FileError -> {
78+
logger.debug("Error while getting tokens", result.message)
79+
gui.revalidate()
80+
}
81+
is TokensResult.SchemaError -> {
82+
logger.debug("Error while getting tokens", result.failure)
83+
gui.revalidate()
84+
}
6785
}
6886

6987
// Notify that settings have been changed

0 commit comments

Comments
 (0)