diff --git a/.gitignore b/.gitignore
index df6966a..6c11680 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
.kotlin
.qodana
build
+.idea/
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index 05eca02..0000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/main/kotlin/com/github/yeoli/devlog/domain/memo/domain/Memo.kt b/src/main/kotlin/com/github/yeoli/devlog/domain/memo/domain/Memo.kt
index 626b566..e820a7f 100644
--- a/src/main/kotlin/com/github/yeoli/devlog/domain/memo/domain/Memo.kt
+++ b/src/main/kotlin/com/github/yeoli/devlog/domain/memo/domain/Memo.kt
@@ -1,8 +1,13 @@
package com.github.yeoli.devlog.domain.memo.domain
+import com.github.yeoli.devlog.domain.memo.repository.MemoState
import java.time.LocalDateTime
class Memo(
+ val id: Long,
+ val createdAt: LocalDateTime,
+ val updatedAt: LocalDateTime,
+
val content: String,
val commitHash: String? = null,
@@ -15,14 +20,33 @@ class Memo(
val visibleStart: Int? = null,
val visibleEnd: Int? = null
) {
- val id: Long = generateId()
- val createdAt: LocalDateTime = LocalDateTime.now()
- val updatedAt: LocalDateTime = LocalDateTime.now()
-
init {
validate()
}
+ constructor(
+ content: String,
+ commitHash: String?,
+ filePath: String?,
+ selectedCodeSnippet: String?,
+ selectionStart: Int?,
+ selectionEnd: Int?,
+ visibleStart: Int?,
+ visibleEnd: Int?
+ ) : this(
+ id = System.currentTimeMillis(),
+ createdAt = LocalDateTime.now(),
+ updatedAt = LocalDateTime.now(),
+ content = content,
+ commitHash = commitHash,
+ filePath = filePath,
+ selectedCodeSnippet = selectedCodeSnippet,
+ selectionStart = selectionStart,
+ selectionEnd = selectionEnd,
+ visibleStart = visibleStart,
+ visibleEnd = visibleEnd
+ )
+
private fun validate() {
if (selectionStart != null && selectionEnd != null) {
require(selectionStart <= selectionEnd) {
@@ -37,7 +61,18 @@ class Memo(
}
}
- private fun generateId(): Long {
- return System.currentTimeMillis()
- }
-}
\ No newline at end of file
+ fun toState(): MemoState =
+ MemoState(
+ id = this.id,
+ createdAt = this.createdAt.toString(),
+ updatedAt = this.updatedAt.toString(),
+ content = this.content,
+ commitHash = this.commitHash,
+ filePath = this.filePath,
+ selectedCodeSnippet = this.selectedCodeSnippet,
+ selectionStart = this.selectionStart,
+ selectionEnd = this.selectionEnd,
+ visibleStart = this.visibleStart,
+ visibleEnd = this.visibleEnd
+ )
+}
diff --git a/src/main/kotlin/com/github/yeoli/devlog/domain/memo/repository/MemoRepository.kt b/src/main/kotlin/com/github/yeoli/devlog/domain/memo/repository/MemoRepository.kt
new file mode 100644
index 0000000..1bb9ee8
--- /dev/null
+++ b/src/main/kotlin/com/github/yeoli/devlog/domain/memo/repository/MemoRepository.kt
@@ -0,0 +1,29 @@
+package com.github.yeoli.devlog.domain.memo.repository
+
+import com.intellij.openapi.components.PersistentStateComponent
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.State
+import com.intellij.openapi.components.Storage
+
+@State(
+ name = "DevLogMemoStorage",
+ storages = [Storage("devlog-memos.xml")]
+)
+@Service(Service.Level.PROJECT)
+class MemoRepository : PersistentStateComponent {
+ private var state = MemoStorageState()
+
+ override fun getState(): MemoStorageState = state
+
+ override fun loadState(state: MemoStorageState) {
+ this.state = state
+ }
+
+ fun save(memo: MemoState) {
+ state.memos.add(memo)
+ }
+
+ fun getAll(): List {
+ return state.memos
+ }
+}
diff --git a/src/main/kotlin/com/github/yeoli/devlog/domain/memo/repository/MemoState.kt b/src/main/kotlin/com/github/yeoli/devlog/domain/memo/repository/MemoState.kt
new file mode 100644
index 0000000..272f360
--- /dev/null
+++ b/src/main/kotlin/com/github/yeoli/devlog/domain/memo/repository/MemoState.kt
@@ -0,0 +1,33 @@
+package com.github.yeoli.devlog.domain.memo.repository
+
+import com.github.yeoli.devlog.domain.memo.domain.Memo
+import java.time.LocalDateTime
+
+data class MemoState(
+ var id: Long = 0L,
+ var createdAt: String,
+ var updatedAt: String,
+ var content: String = "",
+ var commitHash: String? = null,
+ var filePath: String? = null,
+ var selectedCodeSnippet: String? = null,
+ var selectionStart: Int? = null,
+ var selectionEnd: Int? = null,
+ var visibleStart: Int? = null,
+ var visibleEnd: Int? = null
+) {
+ fun toDomain(): Memo =
+ Memo(
+ id = this.id,
+ createdAt = this.createdAt.let { LocalDateTime.parse(it) },
+ updatedAt = this.updatedAt.let { LocalDateTime.parse(it) },
+ content = content,
+ commitHash = commitHash,
+ filePath = filePath,
+ selectedCodeSnippet = selectedCodeSnippet,
+ selectionStart = selectionStart,
+ selectionEnd = selectionEnd,
+ visibleStart = visibleStart,
+ visibleEnd = visibleEnd
+ )
+}
diff --git a/src/main/kotlin/com/github/yeoli/devlog/domain/memo/repository/MemoStorageState.kt b/src/main/kotlin/com/github/yeoli/devlog/domain/memo/repository/MemoStorageState.kt
new file mode 100644
index 0000000..9a555f2
--- /dev/null
+++ b/src/main/kotlin/com/github/yeoli/devlog/domain/memo/repository/MemoStorageState.kt
@@ -0,0 +1,6 @@
+package com.github.yeoli.devlog.domain.memo.repository
+
+class MemoStorageState(
+ var memos: MutableList = mutableListOf()
+) {
+}
diff --git a/src/main/kotlin/com/github/yeoli/devlog/domain/memo/service/MemoService.kt b/src/main/kotlin/com/github/yeoli/devlog/domain/memo/service/MemoService.kt
index 438465b..497471b 100644
--- a/src/main/kotlin/com/github/yeoli/devlog/domain/memo/service/MemoService.kt
+++ b/src/main/kotlin/com/github/yeoli/devlog/domain/memo/service/MemoService.kt
@@ -1,7 +1,9 @@
package com.github.yeoli.devlog.domain.memo.service
import com.github.yeoli.devlog.domain.memo.domain.Memo
+import com.github.yeoli.devlog.domain.memo.repository.MemoRepository
import com.ibm.icu.impl.IllegalIcuArgumentException
+import com.intellij.openapi.components.Service
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.fileEditor.FileDocumentManager
@@ -10,11 +12,14 @@ import com.intellij.openapi.project.Project
import git4idea.repo.GitRepositoryManager
import java.awt.Point
-class MemoService {
+@Service(Service.Level.PROJECT)
+class MemoService(private val project: Project) {
+
+ private val memoRepository = project.getService(MemoRepository::class.java)
private val logger = Logger.getInstance(MemoService::class.java)
- fun createMemo(content: String, project: Project): Memo? {
+ fun createMemo(content: String): Memo? {
val editor = getActiveEditor(project)
if (editor == null) {
logger.warn("[createMemo] editor가 null이므로 null을 반환합니다.")
@@ -74,4 +79,12 @@ class MemoService {
val repo = repoManager.repositories.firstOrNull() ?: return null
return repo.currentRevision
}
+
+ fun saveMemo(memo: Memo) {
+ try {
+ memoRepository.save(memo.toState())
+ } catch (e: Exception) {
+ logger.warn("[saveMemo] 메모 저장 중 알 수 없는 에러가 발생했습니다. ${e.message}", e)
+ }
+ }
}
\ No newline at end of file
diff --git a/src/test/kotlin/com/github/yeoli/devlog/domain/memo/domain/MemoTest.kt b/src/test/kotlin/com/github/yeoli/devlog/domain/memo/domain/MemoTest.kt
index 01ef4c5..4533a23 100644
--- a/src/test/kotlin/com/github/yeoli/devlog/domain/memo/domain/MemoTest.kt
+++ b/src/test/kotlin/com/github/yeoli/devlog/domain/memo/domain/MemoTest.kt
@@ -1,15 +1,13 @@
package com.github.yeoli.devlog.domain.memo.domain
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import kotlin.test.assertFailsWith
-import kotlin.test.assertNotNull
-import kotlin.test.assertTrue
+import com.github.yeoli.devlog.domain.memo.repository.MemoState
+import kotlin.test.*
class MemoTest {
@Test
- fun test_Memo_생성_성공() {
+ fun `test Memo 생성 성공`() {
+ // given & then
val memo = Memo(
content = "테스트 메모",
commitHash = "abc123",
@@ -21,6 +19,7 @@ class MemoTest {
visibleEnd = 20
)
+ // then
assertEquals("테스트 메모", memo.content)
assertEquals("abc123", memo.commitHash)
assertEquals("/path/SampleFile.kt", memo.filePath)
@@ -35,24 +34,69 @@ class MemoTest {
}
@Test
- fun test_Memo_생성_실패_selection_범위() {
+ fun `test Memo 생성 실패 selection 범위`() {
assertFailsWith {
Memo(
content = "잘못된 메모",
+ commitHash = "abc123",
+ filePath = "/path/SampleFile.kt",
+ selectedCodeSnippet = "val selected = 42",
selectionStart = 10,
- selectionEnd = 5
+ selectionEnd = 5,
+ visibleStart = null,
+ visibleEnd = null
)
}
}
@Test
- fun test_Memo_생성_실패_visible_범위() {
+ fun `test Memo 생성 실패 visible 범위`() {
+ // when & then
assertFailsWith {
Memo(
- content = "보이는 영역 오류",
+ content = "잘못된 메모",
+ commitHash = "abc123",
+ filePath = "/path/SampleFile.kt",
+ selectedCodeSnippet = "val selected = 42",
+ selectionStart = 5,
+ selectionEnd = 10,
visibleStart = 20,
visibleEnd = 10
)
}
}
+
+ @Test
+ fun `test MemoState 변환 성공`() {
+ // given
+ val memo = Memo(
+ content = "테스트 메모",
+ commitHash = "abc123",
+ filePath = "/path/SampleFile.kt",
+ selectedCodeSnippet = "val selected = 42",
+ selectionStart = 5,
+ selectionEnd = 10,
+ visibleStart = 1,
+ visibleEnd = 20
+ )
+
+ // when
+ val memoState: MemoState = memo.toState()
+
+ // then
+ assertEquals(memo.id, memoState.id)
+ assertEquals(memo.createdAt.toString(), memoState.createdAt)
+ assertEquals(memo.updatedAt.toString(), memoState.updatedAt)
+ assertEquals("테스트 메모", memoState.content)
+ assertEquals("abc123", memoState.commitHash)
+ assertEquals("/path/SampleFile.kt", memoState.filePath)
+ assertEquals("val selected = 42", memoState.selectedCodeSnippet)
+ assertEquals(5, memoState.selectionStart)
+ assertEquals(10, memoState.selectionEnd)
+ assertEquals(1, memoState.visibleStart)
+ assertEquals(20, memoState.visibleEnd)
+ assertTrue(memoState.id > 0)
+ assertNotNull(memoState.createdAt)
+ assertNotNull(memoState.updatedAt)
+ }
}
diff --git a/src/test/kotlin/com/github/yeoli/devlog/domain/memo/repository/MemoStateTest.kt b/src/test/kotlin/com/github/yeoli/devlog/domain/memo/repository/MemoStateTest.kt
new file mode 100644
index 0000000..9d232a9
--- /dev/null
+++ b/src/test/kotlin/com/github/yeoli/devlog/domain/memo/repository/MemoStateTest.kt
@@ -0,0 +1,48 @@
+package com.github.yeoli.devlog.domain.memo.repository
+
+import com.github.yeoli.devlog.domain.memo.domain.Memo
+import org.junit.jupiter.api.Test
+import java.time.LocalDateTime
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+class MemoStateTest {
+
+ @Test
+ fun `test 도메인 변환 성공`() {
+ // given
+ val memoState = MemoState(
+ id = 0L,
+ createdAt = LocalDateTime.now().toString(),
+ updatedAt = LocalDateTime.now().toString(),
+ content = "테스트 메모",
+ commitHash = "abc123",
+ filePath = "/path/SampleFile.kt",
+ selectedCodeSnippet = "val selected = 42",
+ selectionStart = 5,
+ selectionEnd = 10,
+ visibleStart = 1,
+ visibleEnd = 20
+ )
+
+ // when
+ val memo: Memo = memoState.toDomain()
+
+ // then
+ assertEquals(memo.id, memoState.id)
+ assertEquals(memo.createdAt.toString(), memoState.createdAt)
+ assertEquals(memo.updatedAt.toString(), memoState.updatedAt)
+ assertEquals("테스트 메모", memoState.content)
+ assertEquals("abc123", memoState.commitHash)
+ assertEquals("/path/SampleFile.kt", memoState.filePath)
+ assertEquals("val selected = 42", memoState.selectedCodeSnippet)
+ assertEquals(5, memoState.selectionStart)
+ assertEquals(10, memoState.selectionEnd)
+ assertEquals(1, memoState.visibleStart)
+ assertEquals(20, memoState.visibleEnd)
+ assertTrue(memoState.id > 0)
+ assertNotNull(memoState.createdAt)
+ assertNotNull(memoState.updatedAt)
+ }
+}
diff --git a/src/test/kotlin/com/github/yeoli/devlog/domain/memo/service/MemoServiceTest.kt b/src/test/kotlin/com/github/yeoli/devlog/domain/memo/service/MemoServiceTest.kt
index 816b289..6ee0d2c 100644
--- a/src/test/kotlin/com/github/yeoli/devlog/domain/memo/service/MemoServiceTest.kt
+++ b/src/test/kotlin/com/github/yeoli/devlog/domain/memo/service/MemoServiceTest.kt
@@ -14,7 +14,7 @@ import java.awt.Point
class MemoServiceTest : BasePlatformTestCase() {
- fun test_메모_생성_성공() {
+ fun `test 메모 생성 성공`() {
// given
val psiFile = myFixture.configureByText(
"SampleFile.kt",
@@ -41,7 +41,7 @@ class MemoServiceTest : BasePlatformTestCase() {
).line
// when
- val memo: Memo? = MemoService().createMemo(memoContent, project)
+ val memo: Memo? = MemoService(project).createMemo(memoContent)
// then
if (memo != null) {
assertEquals(memoContent, memo.content)
@@ -58,7 +58,7 @@ class MemoServiceTest : BasePlatformTestCase() {
}
- fun test_메모_생성_선택없음() {
+ fun `test 메모 생성 선택없음`() {
// given
val psiFile = myFixture.configureByText(
"SampleFile.kt",
@@ -84,7 +84,7 @@ class MemoServiceTest : BasePlatformTestCase() {
).line
// when
- val memo: Memo? = MemoService().createMemo(memoContent, project)
+ val memo: Memo? = MemoService(project).createMemo(memoContent)
// then
if (memo != null) {
assertEquals(memoContent, memo.content)
@@ -100,7 +100,7 @@ class MemoServiceTest : BasePlatformTestCase() {
}
}
- fun test_메모_생성_에디터없음_예외() {
+ fun `test 메모 생성 에디터 없음 예외`() {
// given
val psiFile = myFixture.configureByText(
"SampleFile.kt",
@@ -113,11 +113,11 @@ class MemoServiceTest : BasePlatformTestCase() {
assertNull("선택된 에디터가 없어야 합니다.", fileEditorManager.selectedTextEditor)
// expect
- val memo: Memo? = MemoService().createMemo("에디터 없음", project)
+ val memo: Memo? = MemoService(project).createMemo("에디터 없음")
assertNull(memo);
}
- fun test_메모_생성_파일경로없음() {
+ fun `test 메모 생성 파일경로 없음`() {
// given
myFixture.configureByText(
"SampleFile.kt",
@@ -149,7 +149,7 @@ class MemoServiceTest : BasePlatformTestCase() {
try {
// when
- val memo: Memo? = MemoService().createMemo(memoContent, project)
+ val memo: Memo? = MemoService(project).createMemo(memoContent)
// then
if (memo != null) {
@@ -166,4 +166,5 @@ class MemoServiceTest : BasePlatformTestCase() {
Disposer.dispose(mockDisposable)
}
}
+
}