feat(colors): colored output; removed colorutils
This commit is contained in:
@@ -10,7 +10,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "org.notevc"
|
group = "org.notevc"
|
||||||
version = "1.0.7"
|
version = "1.0.8"
|
||||||
|
|
||||||
buildConfig {
|
buildConfig {
|
||||||
buildConfigField("String", "VERSION", "\"${project.version}\"")
|
buildConfigField("String", "VERSION", "\"${project.version}\"")
|
||||||
@@ -26,7 +26,7 @@ dependencies {
|
|||||||
val junitVersion = "5.10.0"
|
val junitVersion = "5.10.0"
|
||||||
implementation(kotlin("stdlib"))
|
implementation(kotlin("stdlib"))
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
||||||
implementation("org.kargs:kargs:1.0.4")
|
implementation("org.kargs:kargs:1.0.8")
|
||||||
|
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
|
testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
|
||||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitVersion")
|
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitVersion")
|
||||||
|
|||||||
@@ -2,12 +2,17 @@ package org.notevc
|
|||||||
|
|
||||||
import org.notevc.core.Repository
|
import org.notevc.core.Repository
|
||||||
import org.notevc.commands.*
|
import org.notevc.commands.*
|
||||||
import org.notevc.utils.ColorUtils
|
|
||||||
import org.kargs.*
|
import org.kargs.*
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
|
val argsList = args.toMutableList()
|
||||||
|
|
||||||
// Create argument parser
|
// Create argument parser
|
||||||
val parser = Parser("notevc", ParserConfig(programVersion = Repository.VERSION))
|
val parser = Parser("notevc", ParserConfig(programVersion = Repository.VERSION, colorsEnabled = true))
|
||||||
|
|
||||||
|
if (argsList.remove("--no-color")) {
|
||||||
|
Colors.setGlobalColorsEnabled(false)
|
||||||
|
} else Colors.setGlobalColorsEnabled(true)
|
||||||
|
|
||||||
// Register subcommands
|
// Register subcommands
|
||||||
parser.subcommands(
|
parser.subcommands(
|
||||||
@@ -22,7 +27,7 @@ fun main(args: Array<String>) {
|
|||||||
|
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
try {
|
try {
|
||||||
parser.parse(args)
|
parser.parse(argsList.toTypedArray())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
kotlin.system.exitProcess(1)
|
kotlin.system.exitProcess(1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
package org.notevc.cli
|
|
||||||
@@ -7,12 +7,8 @@ import kotlinx.serialization.encodeToString
|
|||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import org.notevc.utils.ColorUtils
|
|
||||||
import kotlin.io.path.*
|
import kotlin.io.path.*
|
||||||
import org.kargs.Subcommand
|
import org.kargs.*
|
||||||
import org.kargs.ArgType
|
|
||||||
import org.kargs.Option
|
|
||||||
import org.kargs.Argument
|
|
||||||
|
|
||||||
class CommitCommand : Subcommand("commit", description = "Create a commit of changed files") {
|
class CommitCommand : Subcommand("commit", description = "Create a commit of changed files") {
|
||||||
val targetFile by Option(ArgType.readableFile(), longName = "file", shortName = "f", description = "Commit only a specific file")
|
val targetFile by Option(ArgType.readableFile(), longName = "file", shortName = "f", description = "Commit only a specific file")
|
||||||
@@ -30,7 +26,7 @@ class CommitCommand : Subcommand("commit", description = "Create a commit of cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.onSuccess { message -> println(message) }
|
result.onSuccess { message -> println(message) }
|
||||||
result.onFailure { error -> println("${ColorUtils.error("Error:")} ${error.message}") }
|
result.onFailure { error -> println("${Colors.error("Error:")} ${error.message}") }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createSingleFileCommit(repo: Repository, targetFile: String, message: String): String {
|
private fun createSingleFileCommit(repo: Repository, targetFile: String, message: String): String {
|
||||||
@@ -77,9 +73,9 @@ class CommitCommand : Subcommand("commit", description = "Create a commit of cha
|
|||||||
updateRepositoryHead(repo, commitHash, timestamp, message)
|
updateRepositoryHead(repo, commitHash, timestamp, message)
|
||||||
|
|
||||||
return buildString {
|
return buildString {
|
||||||
appendLine("${ColorUtils.success("Created commit")} ${ColorUtils.hash(commitHash)}")
|
appendLine("${Colors.success("Created commit")} ${Colors.yellow(commitHash)}")
|
||||||
appendLine("${ColorUtils.bold("Message:")} $message")
|
appendLine("${Colors.bold("Message:")} $message")
|
||||||
appendLine("${ColorUtils.bold("File:")} ${ColorUtils.filename(relativePath)} ${ColorUtils.dim("(${snapshot.blocks.size} blocks)")}")
|
appendLine("${Colors.bold("File:")} ${Colors.filename(relativePath)} ${Colors.dim("(${snapshot.blocks.size} blocks)")}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,16 +136,16 @@ class CommitCommand : Subcommand("commit", description = "Create a commit of cha
|
|||||||
updateRepositoryHead(repo, commitHash, timestamp, message)
|
updateRepositoryHead(repo, commitHash, timestamp, message)
|
||||||
|
|
||||||
return buildString {
|
return buildString {
|
||||||
appendLine("${ColorUtils.success("Created commit")} ${ColorUtils.hash(commitHash)}")
|
appendLine("${Colors.success("Created commit")} ${Colors.yellow(commitHash)}")
|
||||||
appendLine("${ColorUtils.bold("Message:")} $message")
|
appendLine("${Colors.bold("Message:")} $message")
|
||||||
appendLine("${ColorUtils.bold("Files committed:")} ${changedFiles.size}")
|
appendLine("${Colors.bold("Files committed:")} ${changedFiles.size}")
|
||||||
appendLine("${ColorUtils.bold("Total blocks:")} $totalBlocksStored")
|
appendLine("${Colors.bold("Total blocks:")} $totalBlocksStored")
|
||||||
appendLine()
|
appendLine()
|
||||||
changedFiles.forEach { fileInfo ->
|
changedFiles.forEach { fileInfo ->
|
||||||
val parts = fileInfo.split(" (")
|
val parts = fileInfo.split(" (")
|
||||||
val filename = parts[0]
|
val filename = parts[0]
|
||||||
val blockInfo = if (parts.size > 1) " (${parts[1]}" else ""
|
val blockInfo = if (parts.size > 1) " (${parts[1]}" else ""
|
||||||
appendLine(" ${ColorUtils.filename(filename)}${ColorUtils.dim(blockInfo)}")
|
appendLine(" ${Colors.filename(filename)}${Colors.dim(blockInfo)}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.notevc.commands
|
package org.notevc.commands
|
||||||
|
|
||||||
import org.notevc.core.*
|
import org.notevc.core.*
|
||||||
import org.notevc.utils.ColorUtils
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@@ -53,7 +52,7 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.onSuccess { message -> println(message) }
|
result.onSuccess { message -> println(message) }
|
||||||
result.onFailure { error -> println("${ColorUtils.error("Error:")} ${error.message}") }
|
result.onFailure { error -> println("${Colors.error("Error:")} ${error.message}") }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compareSpecificBlock(repo: Repository, commitHash: String?, blockHash: String, targetFile: String?): String {
|
private fun compareSpecificBlock(repo: Repository, commitHash: String?, blockHash: String, targetFile: String?): String {
|
||||||
@@ -66,13 +65,13 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
}
|
}
|
||||||
|
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
result.appendLine("${ColorUtils.bold("Block comparison:")} ${ColorUtils.hash(blockHash.take(8))}")
|
result.appendLine("${Colors.bold("Block comparison:")} ${Colors.yellow(blockHash.take(8))}")
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
|
|
||||||
// Get the commit snapshot if provided, otherwise use latest
|
// Get the commit snapshot if provided, otherwise use latest
|
||||||
val commitSnapshot = if (commitHash != null) {
|
val commitSnapshot = if (commitHash != null) {
|
||||||
val commit = findCommit(repo, commitHash)
|
val commit = findCommit(repo, commitHash)
|
||||||
?: throw Exception("Commit ${ColorUtils.hash(commitHash)} not found")
|
?: throw Exception("Commit ${Colors.yellow(commitHash)} not found")
|
||||||
val commitTime = Instant.parse(commit.timestamp)
|
val commitTime = Instant.parse(commit.timestamp)
|
||||||
blockStore.getLatestBlockSnapshotBefore(targetFile, commitTime)
|
blockStore.getLatestBlockSnapshotBefore(targetFile, commitTime)
|
||||||
} else {
|
} else {
|
||||||
@@ -94,41 +93,41 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
val newBlock = currentSnapshot.blocks.find { it.id.startsWith(blockHash) }
|
val newBlock = currentSnapshot.blocks.find { it.id.startsWith(blockHash) }
|
||||||
|
|
||||||
if (oldBlock == null && newBlock == null) {
|
if (oldBlock == null && newBlock == null) {
|
||||||
throw Exception("Block ${ColorUtils.hash(blockHash)} not found")
|
throw Exception("Block ${Colors.yellow(blockHash)} not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
val headingText = (newBlock?.heading ?: oldBlock?.heading ?: "").replace(Regex("^#+\\s*"), "").trim()
|
val headingText = (newBlock?.heading ?: oldBlock?.heading ?: "").replace(Regex("^#+\\s*"), "").trim()
|
||||||
|
|
||||||
result.appendLine("${ColorUtils.heading(headingText)} ${ColorUtils.dim("[${blockHash.take(8)}]")}")
|
result.appendLine("${Colors.heading(headingText)} ${Colors.dim("[${blockHash.take(8)}]")}")
|
||||||
result.appendLine("${ColorUtils.dim("─".repeat(70))}")
|
result.appendLine(Colors.dim("─".repeat(70)))
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
|
|
||||||
when {
|
when {
|
||||||
oldBlock == null && newBlock != null -> {
|
oldBlock == null && newBlock != null -> {
|
||||||
result.appendLine("${ColorUtils.success("This block was ADDED")}")
|
result.appendLine(Colors.green("This block was ADDED"))
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
val newContent = objectStore.getContent(newBlock.contentHash)
|
val newContent = objectStore.getContent(newBlock.contentHash)
|
||||||
if (newContent != null) {
|
if (newContent != null) {
|
||||||
newContent.lines().forEach { line ->
|
newContent.lines().forEach { line ->
|
||||||
result.appendLine("${ColorUtils.success("+ ")} $line")
|
result.appendLine("${Colors.green("+ ")} $line")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oldBlock != null && newBlock == null -> {
|
oldBlock != null && newBlock == null -> {
|
||||||
result.appendLine("${ColorUtils.error("This block was DELETED")}")
|
result.appendLine(Colors.error("This block was DELETED"))
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
val oldContent = objectStore.getContent(oldBlock.contentHash)
|
val oldContent = objectStore.getContent(oldBlock.contentHash)
|
||||||
if (oldContent != null) {
|
if (oldContent != null) {
|
||||||
oldContent.lines().forEach { line ->
|
oldContent.lines().forEach { line ->
|
||||||
result.appendLine("${ColorUtils.error("- ")} $line")
|
result.appendLine("${Colors.error("- ")} $line")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oldBlock != null && newBlock != null -> {
|
oldBlock != null && newBlock != null -> {
|
||||||
if (oldBlock.contentHash == newBlock.contentHash) {
|
if (oldBlock.contentHash == newBlock.contentHash) {
|
||||||
result.appendLine("${ColorUtils.dim("No changes")}")
|
result.appendLine(Colors.dim("No changes"))
|
||||||
} else {
|
} else {
|
||||||
result.appendLine("${ColorUtils.warning("Block was MODIFIED")}")
|
result.appendLine(Colors.warn("Block was MODIFIED"))
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
val oldContent = objectStore.getContent(oldBlock.contentHash)
|
val oldContent = objectStore.getContent(oldBlock.contentHash)
|
||||||
val newContent = objectStore.getContent(newBlock.contentHash)
|
val newContent = objectStore.getContent(newBlock.contentHash)
|
||||||
@@ -152,9 +151,9 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
|
|
||||||
// Find commits
|
// Find commits
|
||||||
val commit1 = findCommit(repo, hash1)
|
val commit1 = findCommit(repo, hash1)
|
||||||
?: throw Exception("Commit ${ColorUtils.hash(hash1)} not found")
|
?: throw Exception("Commit ${Colors.yellow(hash1)} not found")
|
||||||
val commit2 = findCommit(repo, hash2)
|
val commit2 = findCommit(repo, hash2)
|
||||||
?: throw Exception("Commit ${ColorUtils.hash(hash2)} not found")
|
?: throw Exception("Commit ${Colors.yellow(hash2)} not found")
|
||||||
|
|
||||||
val time1 = Instant.parse(commit1.timestamp)
|
val time1 = Instant.parse(commit1.timestamp)
|
||||||
val time2 = Instant.parse(commit2.timestamp)
|
val time2 = Instant.parse(commit2.timestamp)
|
||||||
@@ -170,9 +169,9 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
}
|
}
|
||||||
|
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
result.appendLine("${ColorUtils.bold("Comparing commits:")}")
|
result.appendLine(Colors.bold("Comparing commits:"))
|
||||||
result.appendLine(" ${ColorUtils.hash(hash1.take(8))} ${ColorUtils.dim(commit1.message)}")
|
result.appendLine(" ${Colors.yellow(hash1.take(8))} ${Colors.dim(commit1.message)}")
|
||||||
result.appendLine(" ${ColorUtils.hash(hash2.take(8))} ${ColorUtils.dim(commit2.message)}")
|
result.appendLine(" ${Colors.yellow(hash2.take(8))} ${Colors.dim(commit2.message)}")
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
|
|
||||||
var totalChanges = 0
|
var totalChanges = 0
|
||||||
@@ -184,7 +183,7 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
if (snapshot1 != null || snapshot2 != null) {
|
if (snapshot1 != null || snapshot2 != null) {
|
||||||
val changes = blockStore.compareBlocks(snapshot1, snapshot2)
|
val changes = blockStore.compareBlocks(snapshot1, snapshot2)
|
||||||
if (changes.isNotEmpty()) {
|
if (changes.isNotEmpty()) {
|
||||||
result.appendLine("${ColorUtils.filename(filePath)}:")
|
result.appendLine("${Colors.filename(filePath)}:")
|
||||||
result.append(formatBlockChanges(changes, objectStore))
|
result.append(formatBlockChanges(changes, objectStore))
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
totalChanges += changes.size
|
totalChanges += changes.size
|
||||||
@@ -193,9 +192,9 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (totalChanges == 0) {
|
if (totalChanges == 0) {
|
||||||
result.appendLine("${ColorUtils.dim("No differences found")}")
|
result.appendLine(Colors.dim("No differences found"))
|
||||||
} else {
|
} else {
|
||||||
result.appendLine("${ColorUtils.bold("Total changes:")} $totalChanges")
|
result.appendLine("${Colors.bold("Total changes:")} $totalChanges")
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.toString()
|
return result.toString()
|
||||||
@@ -208,7 +207,7 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
|
|
||||||
// Find commit
|
// Find commit
|
||||||
val commit = findCommit(repo, hash)
|
val commit = findCommit(repo, hash)
|
||||||
?: throw Exception("Commit ${ColorUtils.hash(hash)} not found")
|
?: throw Exception("Commit ${Colors.yellow(hash)} not found")
|
||||||
|
|
||||||
val commitTime = Instant.parse(commit.timestamp)
|
val commitTime = Instant.parse(commit.timestamp)
|
||||||
|
|
||||||
@@ -225,8 +224,8 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
}
|
}
|
||||||
|
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
result.appendLine("${ColorUtils.bold("Comparing working directory to commit:")}")
|
result.appendLine(Colors.bold("Comparing working directory to commit:"))
|
||||||
result.appendLine(" ${ColorUtils.hash(hash.take(8))} ${ColorUtils.dim(commit.message)}")
|
result.appendLine(" ${Colors.yellow(hash.take(8))} ${Colors.lightGray(commit.message)}")
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
|
|
||||||
var totalChanges = 0
|
var totalChanges = 0
|
||||||
@@ -247,7 +246,7 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
|
|
||||||
val changes = blockStore.compareBlocks(commitSnapshot, currentSnapshot)
|
val changes = blockStore.compareBlocks(commitSnapshot, currentSnapshot)
|
||||||
if (changes.isNotEmpty()) {
|
if (changes.isNotEmpty()) {
|
||||||
result.appendLine("${ColorUtils.filename(filePath)}:")
|
result.appendLine("${Colors.filename(filePath)}:")
|
||||||
result.append(formatBlockChanges(changes, objectStore))
|
result.append(formatBlockChanges(changes, objectStore))
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
totalChanges += changes.size
|
totalChanges += changes.size
|
||||||
@@ -256,9 +255,9 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (totalChanges == 0) {
|
if (totalChanges == 0) {
|
||||||
result.appendLine("${ColorUtils.dim("No differences found")}")
|
result.appendLine(Colors.dim("No differences found"))
|
||||||
} else {
|
} else {
|
||||||
result.appendLine("${ColorUtils.bold("Total changes:")} $totalChanges")
|
result.appendLine("${Colors.bold("Total changes:")} $totalChanges")
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.toString()
|
return result.toString()
|
||||||
@@ -282,7 +281,7 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
}
|
}
|
||||||
|
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
result.appendLine("${ColorUtils.bold("Changes in working directory:")}")
|
result.appendLine(Colors.bold("Changes in working directory:"))
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
|
|
||||||
var totalChanges = 0
|
var totalChanges = 0
|
||||||
@@ -294,16 +293,14 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
val parsedFile = blockParser.parseFile(content, filePath)
|
val parsedFile = blockParser.parseFile(content, filePath)
|
||||||
|
|
||||||
// Skip disabled files
|
// Skip disabled files
|
||||||
if (parsedFile.frontMatter?.isEnabled == false) {
|
if (parsedFile.frontMatter?.isEnabled == false) return@forEach
|
||||||
return@forEach
|
|
||||||
}
|
|
||||||
|
|
||||||
val latestSnapshot = blockStore.getLatestBlockSnapshot(filePath)
|
val latestSnapshot = blockStore.getLatestBlockSnapshot(filePath)
|
||||||
val currentSnapshot = createCurrentSnapshot(parsedFile, objectStore)
|
val currentSnapshot = createCurrentSnapshot(parsedFile, objectStore)
|
||||||
|
|
||||||
val changes = blockStore.compareBlocks(latestSnapshot, currentSnapshot)
|
val changes = blockStore.compareBlocks(latestSnapshot, currentSnapshot)
|
||||||
if (changes.isNotEmpty()) {
|
if (changes.isNotEmpty()) {
|
||||||
result.appendLine("${ColorUtils.filename(filePath)}:")
|
result.appendLine("${Colors.filename(filePath)}:")
|
||||||
result.append(formatBlockChanges(changes, objectStore))
|
result.append(formatBlockChanges(changes, objectStore))
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
totalChanges += changes.size
|
totalChanges += changes.size
|
||||||
@@ -312,9 +309,9 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (totalChanges == 0) {
|
if (totalChanges == 0) {
|
||||||
result.appendLine("${ColorUtils.dim("No changes detected - working directory clean")}")
|
result.appendLine(Colors.lightGray("No changes detected - working directory clean"))
|
||||||
} else {
|
} else {
|
||||||
result.appendLine("${ColorUtils.bold("Total changes:")} $totalChanges")
|
result.appendLine("${Colors.bold("Total changes:")} $totalChanges")
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.toString()
|
return result.toString()
|
||||||
@@ -330,42 +327,42 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
when (change.type) {
|
when (change.type) {
|
||||||
BlockChangeType.ADDED -> {
|
BlockChangeType.ADDED -> {
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
result.appendLine(" ${ColorUtils.success("+++")} ${ColorUtils.bold("ADDED")} ${ColorUtils.success("+++")} ${ColorUtils.heading(headingText)} ${ColorUtils.dim("[$blockId]")}")
|
result.appendLine(" ${Colors.green("+++")} ${Colors.bold("ADDED")} ${Colors.green("+++")} ${Colors.heading(headingText)} ${Colors.dim("[$blockId]")}")
|
||||||
result.appendLine(" ${ColorUtils.dim("─".repeat(60))}")
|
result.appendLine(" ${Colors.dim("─".repeat(60))}")
|
||||||
|
|
||||||
if (change.newHash != null) {
|
if (change.newHash != null) {
|
||||||
val content = objectStore.getContent(change.newHash)
|
val content = objectStore.getContent(change.newHash)
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
content.lines().take(5).forEach { line ->
|
content.lines().take(5).forEach { line ->
|
||||||
result.appendLine(" ${ColorUtils.success("+")} $line")
|
result.appendLine(" ${Colors.green("+")} $line")
|
||||||
}
|
}
|
||||||
if (content.lines().size > 5) {
|
if (content.lines().size > 5) {
|
||||||
result.appendLine(" ${ColorUtils.dim(" ... ${content.lines().size - 5} more lines")}")
|
result.appendLine(" ${Colors.dim(" ... ${content.lines().size - 5} more lines")}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BlockChangeType.DELETED -> {
|
BlockChangeType.DELETED -> {
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
result.appendLine(" ${ColorUtils.error("---")} ${ColorUtils.bold("DELETED")} ${ColorUtils.error("---")} ${ColorUtils.heading(headingText)} ${ColorUtils.dim("[$blockId]")}")
|
result.appendLine(" ${Colors.error("---")} ${Colors.bold("DELETED")} ${Colors.error("---")} ${Colors.heading(headingText)} ${Colors.dim("[$blockId]")}")
|
||||||
result.appendLine(" ${ColorUtils.dim("─".repeat(60))}")
|
result.appendLine(" ${Colors.dim("─".repeat(60))}")
|
||||||
|
|
||||||
if (change.oldHash != null) {
|
if (change.oldHash != null) {
|
||||||
val content = objectStore.getContent(change.oldHash)
|
val content = objectStore.getContent(change.oldHash)
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
content.lines().take(5).forEach { line ->
|
content.lines().take(5).forEach { line ->
|
||||||
result.appendLine(" ${ColorUtils.error("-")} $line")
|
result.appendLine(" ${Colors.error("-")} $line")
|
||||||
}
|
}
|
||||||
if (content.lines().size > 5) {
|
if (content.lines().size > 5) {
|
||||||
result.appendLine(" ${ColorUtils.dim(" ... ${content.lines().size - 5} more lines")}")
|
result.appendLine(" ${Colors.dim(" ... ${content.lines().size - 5} more lines")}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BlockChangeType.MODIFIED -> {
|
BlockChangeType.MODIFIED -> {
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
result.appendLine(" ${ColorUtils.warning("~~~")} ${ColorUtils.bold("MODIFIED")} ${ColorUtils.warning("~~~")} ${ColorUtils.heading(headingText)} ${ColorUtils.dim("[$blockId]")}")
|
result.appendLine(" ${Colors.warn("~~~")} ${Colors.bold("MODIFIED")} ${Colors.warn("~~~")} ${Colors.heading(headingText)} ${Colors.dim("[$blockId]")}")
|
||||||
result.appendLine(" ${ColorUtils.dim("─".repeat(60))}")
|
result.appendLine(" ${Colors.dim("─".repeat(60))}")
|
||||||
|
|
||||||
// Show detailed diff
|
// Show detailed diff
|
||||||
if (change.oldHash != null && change.newHash != null) {
|
if (change.oldHash != null && change.newHash != null) {
|
||||||
@@ -405,27 +402,27 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
when {
|
when {
|
||||||
oldLine == null && newLine != null -> {
|
oldLine == null && newLine != null -> {
|
||||||
// Addition
|
// Addition
|
||||||
diff.add("${ColorUtils.success("+ ")} $newLine")
|
diff.add("${Colors.green("+ ")} $newLine")
|
||||||
newIndex++
|
newIndex++
|
||||||
displayedLines++
|
displayedLines++
|
||||||
}
|
}
|
||||||
oldLine != null && newLine == null -> {
|
oldLine != null && newLine == null -> {
|
||||||
// Deletion
|
// Deletion
|
||||||
diff.add("${ColorUtils.error("- ")} $oldLine")
|
diff.add("${Colors.boldRed("- ")} $oldLine")
|
||||||
oldIndex++
|
oldIndex++
|
||||||
displayedLines++
|
displayedLines++
|
||||||
}
|
}
|
||||||
oldLine == newLine -> {
|
oldLine == newLine -> {
|
||||||
// Unchanged line (context)
|
// Unchanged line (context)
|
||||||
diff.add("${ColorUtils.dim(" ")} ${ColorUtils.dim(oldLine ?: "")}")
|
diff.add("${Colors.dim(" ")} ${Colors.dimWhite(oldLine ?: "")}")
|
||||||
oldIndex++
|
oldIndex++
|
||||||
newIndex++
|
newIndex++
|
||||||
displayedLines++
|
displayedLines++
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
// Modified line
|
// Modified line
|
||||||
diff.add("${ColorUtils.error("- ")} $oldLine")
|
diff.add("${Colors.boldRed("- ")} $oldLine")
|
||||||
diff.add("${ColorUtils.success("+ ")} $newLine")
|
diff.add("${Colors.green("+ ")} $newLine")
|
||||||
oldIndex++
|
oldIndex++
|
||||||
newIndex++
|
newIndex++
|
||||||
displayedLines += 2
|
displayedLines += 2
|
||||||
@@ -435,7 +432,7 @@ class DiffCommand : Subcommand("diff", description = "Show differences between c
|
|||||||
|
|
||||||
val remainingLines = (oldLines.size - oldIndex) + (newLines.size - newIndex)
|
val remainingLines = (oldLines.size - oldIndex) + (newLines.size - newIndex)
|
||||||
if (remainingLines > 0) {
|
if (remainingLines > 0) {
|
||||||
diff.add("${ColorUtils.dim(" ... $remainingLines more lines")}")
|
diff.add(Colors.dim(" ... $remainingLines more lines"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return diff
|
return diff
|
||||||
|
|||||||
@@ -2,10 +2,7 @@ package org.notevc.commands
|
|||||||
|
|
||||||
import org.notevc.core.Repository
|
import org.notevc.core.Repository
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import org.notevc.utils.ColorUtils
|
import org.kargs.*
|
||||||
import org.kargs.Subcommand
|
|
||||||
import org.kargs.Argument
|
|
||||||
import org.kargs.ArgType
|
|
||||||
|
|
||||||
class InitCommand : Subcommand("init", description = "Initialize a repository", aliases = listOf("i")) {
|
class InitCommand : Subcommand("init", description = "Initialize a repository", aliases = listOf("i")) {
|
||||||
val path by Argument(ArgType.existingDirectory(), "path", description = "Initialize in a specified directory", required = false)
|
val path by Argument(ArgType.existingDirectory(), "path", description = "Initialize in a specified directory", required = false)
|
||||||
@@ -19,13 +16,13 @@ class InitCommand : Subcommand("init", description = "Initialize a repository",
|
|||||||
repo.init().fold(
|
repo.init().fold(
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
val absolutePath = repo.path.toAbsolutePath().toString()
|
val absolutePath = repo.path.toAbsolutePath().toString()
|
||||||
"Initialized notevc repository in ${ColorUtils.filename(absolutePath)}"
|
"Initialized notevc repository in ${Colors.filename(absolutePath)}"
|
||||||
},
|
},
|
||||||
onFailure = { error -> throw Exception(error) }
|
onFailure = { error -> throw Exception(error) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
result.onSuccess { message -> println(message) }
|
result.onSuccess { message -> println(message) }
|
||||||
result.onFailure { error -> println("${ColorUtils.error("Error:")} ${error.message}") }
|
result.onFailure { error -> println("${Colors.error("Error:")} ${error.message}") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import org.notevc.core.*
|
|||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import org.notevc.utils.ColorUtils
|
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import kotlin.io.path.*
|
import kotlin.io.path.*
|
||||||
@@ -27,7 +26,7 @@ class LogCommand : Subcommand("log", description = "Show commit history with det
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.onSuccess { message -> println(message) }
|
result.onSuccess { message -> println(message) }
|
||||||
result.onFailure { error -> println("${ColorUtils.error("Error:")} ${error.message}") }
|
result.onFailure { error -> println("${Colors.error("Error:")} ${error.message}") }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateLog(repo: Repository, options: LogOptions): String {
|
private fun generateLog(repo: Repository, options: LogOptions): String {
|
||||||
@@ -111,10 +110,10 @@ class LogCommand : Subcommand("log", description = "Show commit history with det
|
|||||||
return commits.joinToString("\n") { commit ->
|
return commits.joinToString("\n") { commit ->
|
||||||
val fileInfo = if (options.showFiles) {
|
val fileInfo = if (options.showFiles) {
|
||||||
val stats = getCommitStats(repo, commit, options.targetFile)
|
val stats = getCommitStats(repo, commit, options.targetFile)
|
||||||
ColorUtils.dim(" (${stats.filesChanged} files, ${stats.totalBlocks} blocks)")
|
Colors.dim(" (${stats.filesChanged} files, ${stats.totalBlocks} blocks)")
|
||||||
} else ""
|
} else ""
|
||||||
|
|
||||||
"${ColorUtils.hash(commit.hash)} ${commit.message}$fileInfo"
|
"${Colors.yellow(commit.hash)} ${commit.message}$fileInfo"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,22 +126,23 @@ class LogCommand : Subcommand("log", description = "Show commit history with det
|
|||||||
val formattedDate = formatter.format(timestamp)
|
val formattedDate = formatter.format(timestamp)
|
||||||
|
|
||||||
buildString {
|
buildString {
|
||||||
appendLine("${ColorUtils.bold("commit")} ${ColorUtils.hash(commit.hash)}")
|
appendLine("${Colors.bold("commit")} ${Colors.yellow(commit.hash)}")
|
||||||
appendLine("${ColorUtils.bold("Author:")} ${ColorUtils.author(commit.author)}")
|
appendLine("${Colors.bold("Author:")} ${Colors.green(commit.author)}")
|
||||||
appendLine("${ColorUtils.bold("Date:")} ${ColorUtils.date(formattedDate)}")
|
appendLine("${Colors.bold("Date:")} ${Colors.dim(formattedDate)}")
|
||||||
|
|
||||||
if (options.showFiles) {
|
if (options.showFiles) {
|
||||||
val stats = getCommitStats(repo, commit, options.targetFile)
|
val stats = getCommitStats(repo, commit, options.targetFile)
|
||||||
appendLine("${ColorUtils.info("Files changed:")} ${stats.filesChanged}, ${ColorUtils.info("Total blocks:")} ${stats.totalBlocks}")
|
appendLine("${Colors.info("Files changed:")} ${stats.filesChanged}, ${Colors.info("Total blocks:")} ${stats.totalBlocks}")
|
||||||
|
|
||||||
if (stats.fileDetails.isNotEmpty()) {
|
if (stats.fileDetails.isNotEmpty()) {
|
||||||
appendLine()
|
appendLine()
|
||||||
stats.fileDetails.forEach { (file, blocks) ->
|
stats.fileDetails.forEach { (file, blocks) ->
|
||||||
appendLine(" ${ColorUtils.filename(file)} ${ColorUtils.dim("(${blocks.size} blocks)")}")
|
appendLine(" ${Colors.filename(file)} ${Colors.dim("(${blocks.size} blocks)")}")
|
||||||
blocks.forEach { block ->
|
blocks.forEach { block ->
|
||||||
val heading = block.heading.replace(Regex("^#+\\s*"), "").trim()
|
val heading = block.heading.replace(Regex("^#+\\s*"), "").trim()
|
||||||
appendLine(" - ${ColorUtils.hash(block.id.take(8))}: ${ColorUtils.heading(heading)}")
|
appendLine(" - ${Colors.yellow(block.id.take(8))}: ${Colors.magenta(heading)}")
|
||||||
}
|
}
|
||||||
|
appendLine()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.notevc.commands
|
package org.notevc.commands
|
||||||
|
|
||||||
import org.notevc.core.*
|
import org.notevc.core.*
|
||||||
import org.notevc.utils.ColorUtils
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@@ -35,7 +34,7 @@ class RestoreCommand : Subcommand("restore", description = "Restore files or blo
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.onSuccess { message -> println(message) }
|
result.onSuccess { message -> println(message) }
|
||||||
result.onFailure { error -> println("${ColorUtils.error("Error:")} ${error.message}") }
|
result.onFailure { error -> println("${Colors.error("Error:")} ${error.message}") }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreSpecificBlock(repo: Repository, commitHash: String, blockHash: String, targetFile: String): String {
|
private fun restoreSpecificBlock(repo: Repository, commitHash: String, blockHash: String, targetFile: String): String {
|
||||||
@@ -45,21 +44,21 @@ class RestoreCommand : Subcommand("restore", description = "Restore files or blo
|
|||||||
|
|
||||||
// Find the commit
|
// Find the commit
|
||||||
val commit = findCommit(repo, commitHash)
|
val commit = findCommit(repo, commitHash)
|
||||||
?: throw Exception("Commit ${ColorUtils.hash(commitHash)} not found")
|
?: throw Exception("Commit ${Colors.yellow(commitHash)} not found")
|
||||||
|
|
||||||
// Find the block snapshot for this file at the commit time
|
// Find the block snapshot for this file at the commit time
|
||||||
val commitTime = Instant.parse(commit.timestamp)
|
val commitTime = Instant.parse(commit.timestamp)
|
||||||
val snapshot = blockStore.getBlocksAtTime(targetFile, commitTime)
|
val snapshot = blockStore.getBlocksAtTime(targetFile, commitTime)
|
||||||
?: throw Exception("No snapshot found for ${ColorUtils.filename(targetFile)} at commit ${ColorUtils.hash(commitHash)}")
|
?: throw Exception("No snapshot found for ${Colors.filename(targetFile)} at commit ${Colors.yellow(commitHash)}")
|
||||||
|
|
||||||
// Find the specific block
|
// Find the specific block
|
||||||
val targetBlock = snapshot.find { it.id.startsWith(blockHash) }
|
val targetBlock = snapshot.find { it.id.startsWith(blockHash) }
|
||||||
?: throw Exception("Block ${ColorUtils.hash(blockHash)} not found in ${ColorUtils.filename(targetFile)} at commit ${ColorUtils.hash(commitHash)}")
|
?: throw Exception("Block ${Colors.yellow(blockHash)} not found in ${Colors.filename(targetFile)} at commit ${Colors.yellow(commitHash)}")
|
||||||
|
|
||||||
// Read current file
|
// Read current file
|
||||||
val filePath = repo.path.resolve(targetFile)
|
val filePath = repo.path.resolve(targetFile)
|
||||||
if (!filePath.exists()) {
|
if (!filePath.exists()) {
|
||||||
throw Exception("File ${ColorUtils.filename(targetFile)} does not exist")
|
throw Exception("File ${Colors.filename(targetFile)} does not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentContent = Files.readString(filePath)
|
val currentContent = Files.readString(filePath)
|
||||||
@@ -68,7 +67,7 @@ class RestoreCommand : Subcommand("restore", description = "Restore files or blo
|
|||||||
// Find the block to replace in current file
|
// Find the block to replace in current file
|
||||||
val currentBlockIndex = currentParsedFile.blocks.indexOfFirst { it.id.startsWith(blockHash) }
|
val currentBlockIndex = currentParsedFile.blocks.indexOfFirst { it.id.startsWith(blockHash) }
|
||||||
if (currentBlockIndex == -1) {
|
if (currentBlockIndex == -1) {
|
||||||
throw Exception("Block ${ColorUtils.hash(blockHash)} not found in current ${ColorUtils.filename(targetFile)}")
|
throw Exception("Block ${Colors.yellow(blockHash)} not found in current ${Colors.filename(targetFile)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the block
|
// Replace the block
|
||||||
@@ -82,7 +81,7 @@ class RestoreCommand : Subcommand("restore", description = "Restore files or blo
|
|||||||
Files.writeString(filePath, restoredContent)
|
Files.writeString(filePath, restoredContent)
|
||||||
|
|
||||||
val blockHeading = targetBlock.heading.replace(Regex("^#+\\s*"), "").trim()
|
val blockHeading = targetBlock.heading.replace(Regex("^#+\\s*"), "").trim()
|
||||||
return "${ColorUtils.success("Restored block")} ${ColorUtils.hash(blockHash.take(8))} ${ColorUtils.heading("\"$blockHeading\"")} in ${ColorUtils.filename(targetFile)} from commit ${ColorUtils.hash(commitHash)}"
|
return "${Colors.success("Restored block")} ${Colors.yellow(blockHash.take(8))} ${Colors.heading("\"$blockHeading\"")} in ${Colors.filename(targetFile)} from commit ${Colors.yellow(commitHash)}"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreSpecificFile(repo: Repository, commitHash: String, targetFile: String): String {
|
private fun restoreSpecificFile(repo: Repository, commitHash: String, targetFile: String): String {
|
||||||
@@ -92,15 +91,15 @@ class RestoreCommand : Subcommand("restore", description = "Restore files or blo
|
|||||||
|
|
||||||
// Find the commit
|
// Find the commit
|
||||||
val commit = findCommit(repo, commitHash)
|
val commit = findCommit(repo, commitHash)
|
||||||
?: throw Exception("Commit ${ColorUtils.hash(commitHash)} not found")
|
?: throw Exception("Commit ${Colors.yellow(commitHash)} not found")
|
||||||
|
|
||||||
// Find the block snapshot for this file at the commit time
|
// Find the block snapshot for this file at the commit time
|
||||||
val commitTime = Instant.parse(commit.timestamp)
|
val commitTime = Instant.parse(commit.timestamp)
|
||||||
val snapshot = blockStore.getLatestBlockSnapshotBefore(targetFile, commitTime)
|
val snapshot = blockStore.getLatestBlockSnapshotBefore(targetFile, commitTime)
|
||||||
?: throw Exception("No snapshot found for ${ColorUtils.filename(targetFile)} at commit ${ColorUtils.hash(commitHash)}")
|
?: throw Exception("No snapshot found for ${Colors.filename(targetFile)} at commit ${Colors.yellow(commitHash)}")
|
||||||
|
|
||||||
val blocks = blockStore.getBlocksAtTime(targetFile, commitTime)
|
val blocks = blockStore.getBlocksAtTime(targetFile, commitTime)
|
||||||
?: throw Exception("No blocks found for ${ColorUtils.filename(targetFile)} at commit ${ColorUtils.hash(commitHash)}")
|
?: throw Exception("No blocks found for ${Colors.filename(targetFile)} at commit ${Colors.yellow(commitHash)}")
|
||||||
|
|
||||||
// Reconstruct the file from blocks with frontmatter from snapshot
|
// Reconstruct the file from blocks with frontmatter from snapshot
|
||||||
val parsedFile = ParsedFile(
|
val parsedFile = ParsedFile(
|
||||||
@@ -116,7 +115,7 @@ class RestoreCommand : Subcommand("restore", description = "Restore files or blo
|
|||||||
Files.createDirectories(filePath.parent)
|
Files.createDirectories(filePath.parent)
|
||||||
Files.writeString(filePath, restoredContent)
|
Files.writeString(filePath, restoredContent)
|
||||||
|
|
||||||
return "${ColorUtils.success("Restored file")} ${ColorUtils.filename(targetFile)} ${ColorUtils.dim("(${blocks.size} blocks)")} from commit ${ColorUtils.hash(commitHash)}"
|
return "${Colors.success("Restored file")} ${Colors.filename(targetFile)} ${Colors.dim("(${blocks.size} blocks)")} from commit ${Colors.yellow(commitHash)}"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreEntireRepository(repo: Repository, commitHash: String): String {
|
private fun restoreEntireRepository(repo: Repository, commitHash: String): String {
|
||||||
@@ -126,7 +125,7 @@ class RestoreCommand : Subcommand("restore", description = "Restore files or blo
|
|||||||
|
|
||||||
// Find the commit
|
// Find the commit
|
||||||
val commit = findCommit(repo, commitHash)
|
val commit = findCommit(repo, commitHash)
|
||||||
?: throw Exception("Commit ${ColorUtils.hash(commitHash)} not found")
|
?: throw Exception("Commit ${Colors.yellow(commitHash)} not found")
|
||||||
|
|
||||||
val commitTime = Instant.parse(commit.timestamp)
|
val commitTime = Instant.parse(commit.timestamp)
|
||||||
|
|
||||||
@@ -134,7 +133,7 @@ class RestoreCommand : Subcommand("restore", description = "Restore files or blo
|
|||||||
val trackedFiles = getTrackedFilesAtCommit(repo, commitTime)
|
val trackedFiles = getTrackedFilesAtCommit(repo, commitTime)
|
||||||
|
|
||||||
if (trackedFiles.isEmpty()) {
|
if (trackedFiles.isEmpty()) {
|
||||||
throw Exception("No files found at commit ${ColorUtils.hash(commitHash)}")
|
throw Exception("No files found at commit ${Colors.yellow(commitHash)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
var restoredFiles = 0
|
var restoredFiles = 0
|
||||||
@@ -162,10 +161,10 @@ class RestoreCommand : Subcommand("restore", description = "Restore files or blo
|
|||||||
}
|
}
|
||||||
|
|
||||||
return buildString {
|
return buildString {
|
||||||
appendLine("${ColorUtils.success("Restored repository")} to commit ${ColorUtils.hash(commitHash)}")
|
appendLine("${Colors.success("Restored repository")} to commit ${Colors.yellow(commitHash)}")
|
||||||
appendLine("${ColorUtils.bold("Files restored:")} $restoredFiles")
|
appendLine("${Colors.bold("Files restored:")} $restoredFiles")
|
||||||
appendLine("${ColorUtils.bold("Total blocks:")} $totalBlocks")
|
appendLine("${Colors.bold("Total blocks:")} $totalBlocks")
|
||||||
appendLine("${ColorUtils.bold("Commit message:")} ${commit.message}")
|
appendLine("${Colors.bold("Commit message:")} ${commit.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.notevc.commands
|
package org.notevc.commands
|
||||||
|
|
||||||
import org.notevc.core.*
|
import org.notevc.core.*
|
||||||
import org.notevc.utils.ColorUtils
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@@ -30,7 +29,7 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.onSuccess { message -> println(message) }
|
result.onSuccess { message -> println(message) }
|
||||||
result.onFailure { error -> println("${ColorUtils.error("Error:")} ${error.message}") }
|
result.onFailure { error -> println("${Colors.error("Error:")} ${error.message}") }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showCommit(repo: Repository, commitHash: String, targetFile: String?): String {
|
private fun showCommit(repo: Repository, commitHash: String, targetFile: String?): String {
|
||||||
@@ -39,7 +38,7 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
|
|
||||||
// Find the commit
|
// Find the commit
|
||||||
val commit = findCommit(repo, commitHash)
|
val commit = findCommit(repo, commitHash)
|
||||||
?: throw Exception("Commit ${ColorUtils.hash(commitHash)} not found")
|
?: throw Exception("Commit ${Colors.yellow(commitHash)} not found")
|
||||||
|
|
||||||
val commitTime = Instant.parse(commit.timestamp)
|
val commitTime = Instant.parse(commit.timestamp)
|
||||||
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||||
@@ -48,11 +47,11 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
|
|
||||||
// Show commit header
|
// Show commit header
|
||||||
result.appendLine("${ColorUtils.bold("Commit:")} ${ColorUtils.hash(commit.hash)}")
|
result.appendLine("${Colors.bold("Commit:")} ${Colors.yellow(commit.hash)}")
|
||||||
result.appendLine("${ColorUtils.bold("Author:")} ${commit.author}")
|
result.appendLine("${Colors.bold("Author:")} ${commit.author}")
|
||||||
result.appendLine("${ColorUtils.bold("Date:")} ${formatter.format(commitTime)}")
|
result.appendLine("${Colors.bold("Date:")} ${formatter.format(commitTime)}")
|
||||||
if (commit.parent != null) {
|
if (commit.parent != null) {
|
||||||
result.appendLine("${ColorUtils.bold("Parent:")} ${ColorUtils.hash(commit.parent)}")
|
result.appendLine("${Colors.bold("Parent:")} ${Colors.yellow(commit.parent)}")
|
||||||
}
|
}
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
result.appendLine(" ${commit.message}")
|
result.appendLine(" ${commit.message}")
|
||||||
@@ -66,12 +65,12 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (filesToShow.isEmpty()) {
|
if (filesToShow.isEmpty()) {
|
||||||
result.appendLine("${ColorUtils.dim("No files found at this commit")}")
|
result.appendLine("${Colors.dim("No files found at this commit")}")
|
||||||
return result.toString()
|
return result.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show changes for each file
|
// Show changes for each file
|
||||||
result.appendLine("${ColorUtils.bold("Changes:")}")
|
result.appendLine("${Colors.bold("Changes:")}")
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
|
|
||||||
var totalAdded = 0
|
var totalAdded = 0
|
||||||
@@ -94,7 +93,7 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
val changes = blockStore.compareBlocks(parentSnapshot, currentSnapshot)
|
val changes = blockStore.compareBlocks(parentSnapshot, currentSnapshot)
|
||||||
|
|
||||||
if (changes.isNotEmpty()) {
|
if (changes.isNotEmpty()) {
|
||||||
result.appendLine("${ColorUtils.filename(filePath)}:")
|
result.appendLine("${Colors.filename(filePath)}:")
|
||||||
|
|
||||||
val added = changes.count { it.type == BlockChangeType.ADDED }
|
val added = changes.count { it.type == BlockChangeType.ADDED }
|
||||||
val modified = changes.count { it.type == BlockChangeType.MODIFIED }
|
val modified = changes.count { it.type == BlockChangeType.MODIFIED }
|
||||||
@@ -104,9 +103,9 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
totalModified += modified
|
totalModified += modified
|
||||||
totalDeleted += deleted
|
totalDeleted += deleted
|
||||||
|
|
||||||
if (added > 0) result.appendLine(" ${ColorUtils.success("+")} $added ${if (added == 1) "block" else "blocks"} added")
|
if (added > 0) result.appendLine(" ${Colors.boldGreen("+")} $added ${if (added == 1) "block" else "blocks"} added")
|
||||||
if (modified > 0) result.appendLine(" ${ColorUtils.warning("~")} $modified ${if (modified == 1) "block" else "blocks"} modified")
|
if (modified > 0) result.appendLine(" ${Colors.warn("~")} $modified ${if (modified == 1) "block" else "blocks"} modified")
|
||||||
if (deleted > 0) result.appendLine(" ${ColorUtils.error("-")} $deleted ${if (deleted == 1) "block" else "blocks"} deleted")
|
if (deleted > 0) result.appendLine(" ${Colors.error("-")} $deleted ${if (deleted == 1) "block" else "blocks"} deleted")
|
||||||
|
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
|
|
||||||
@@ -117,13 +116,13 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
|
|
||||||
when (change.type) {
|
when (change.type) {
|
||||||
BlockChangeType.ADDED -> {
|
BlockChangeType.ADDED -> {
|
||||||
result.appendLine(" ${ColorUtils.success("+")} ${ColorUtils.heading(headingText)} ${ColorUtils.dim("[$blockId]")}")
|
result.appendLine(" ${Colors.boldGreen("+")} ${Colors.heading(headingText)} ${Colors.dim("[$blockId]")}")
|
||||||
}
|
}
|
||||||
BlockChangeType.DELETED -> {
|
BlockChangeType.DELETED -> {
|
||||||
result.appendLine(" ${ColorUtils.error("-")} ${ColorUtils.heading(headingText)} ${ColorUtils.dim("[$blockId]")}")
|
result.appendLine(" ${Colors.error("-")} ${Colors.heading(headingText)} ${Colors.dim("[$blockId]")}")
|
||||||
}
|
}
|
||||||
BlockChangeType.MODIFIED -> {
|
BlockChangeType.MODIFIED -> {
|
||||||
result.appendLine(" ${ColorUtils.warning("~")} ${ColorUtils.heading(headingText)} ${ColorUtils.dim("[$blockId]")}")
|
result.appendLine(" ${Colors.warn("~")} ${Colors.heading(headingText)} ${Colors.dim("[$blockId]")}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,8 +133,8 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
|
|
||||||
// Summary
|
// Summary
|
||||||
if (totalAdded + totalModified + totalDeleted > 0) {
|
if (totalAdded + totalModified + totalDeleted > 0) {
|
||||||
result.appendLine("${ColorUtils.bold("Summary:")}")
|
result.appendLine("${Colors.bold("Summary:")}")
|
||||||
result.appendLine(" ${ColorUtils.success("+")} $totalAdded added, ${ColorUtils.warning("~")} $totalModified modified, ${ColorUtils.error("-")} $totalDeleted deleted")
|
result.appendLine(" ${Colors.boldGreen("+")} $totalAdded added, ${Colors.warn("~")} $totalModified modified, ${Colors.error("-")} $totalDeleted deleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.toString()
|
return result.toString()
|
||||||
@@ -190,7 +189,7 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
val blockStore = BlockStore(objectStore, repo.path.resolve("${Repository.NOTEVC_DIR}/blocks"))
|
val blockStore = BlockStore(objectStore, repo.path.resolve("${Repository.NOTEVC_DIR}/blocks"))
|
||||||
|
|
||||||
val commit = findCommit(repo, options.commitHash)
|
val commit = findCommit(repo, options.commitHash)
|
||||||
?: throw Exception("Commit ${ColorUtils.hash(options.commitHash)} not found")
|
?: throw Exception("Commit ${Colors.yellow(options.commitHash)} not found")
|
||||||
|
|
||||||
val commitTime = Instant.parse(commit.timestamp)
|
val commitTime = Instant.parse(commit.timestamp)
|
||||||
|
|
||||||
@@ -202,7 +201,7 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
?: throw Exception("No snapshot found for ${options.targetFile} at commit ${options.commitHash}")
|
?: throw Exception("No snapshot found for ${options.targetFile} at commit ${options.commitHash}")
|
||||||
|
|
||||||
val block = snapshot.blocks.find { it.id.startsWith(options.blockHash!!) }
|
val block = snapshot.blocks.find { it.id.startsWith(options.blockHash!!) }
|
||||||
?: throw Exception("Block ${ColorUtils.hash(options.blockHash!!)} not found")
|
?: throw Exception("Block ${Colors.yellow(options.blockHash!!)} not found")
|
||||||
|
|
||||||
val content = objectStore.getContent(block.contentHash)
|
val content = objectStore.getContent(block.contentHash)
|
||||||
?: throw Exception("Content not found for block")
|
?: throw Exception("Content not found for block")
|
||||||
@@ -210,12 +209,12 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
val headingText = block.heading.replace(Regex("^#+\\s*"), "").trim()
|
val headingText = block.heading.replace(Regex("^#+\\s*"), "").trim()
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
|
|
||||||
result.appendLine("${ColorUtils.bold("Block:")} ${ColorUtils.hash(block.id.take(8))}")
|
result.appendLine("${Colors.bold("Block:")} ${Colors.yellow(block.id.take(8))}")
|
||||||
result.appendLine("${ColorUtils.bold("Heading:")} ${ColorUtils.heading(headingText)}")
|
result.appendLine("${Colors.bold("Heading:")} ${Colors.heading(headingText)}")
|
||||||
result.appendLine("${ColorUtils.bold("File:")} ${ColorUtils.filename(options.targetFile)}")
|
result.appendLine("${Colors.bold("File:")} ${Colors.filename(options.targetFile)}")
|
||||||
result.appendLine("${ColorUtils.bold("Commit:")} ${ColorUtils.hash(commit.hash)}")
|
result.appendLine("${Colors.bold("Commit:")} ${Colors.yellow(commit.hash)}")
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
result.appendLine("${ColorUtils.dim("─".repeat(70))}")
|
result.appendLine("${Colors.dim("─".repeat(70))}")
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
result.append(content)
|
result.append(content)
|
||||||
|
|
||||||
@@ -228,7 +227,7 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
val blockParser = BlockParser()
|
val blockParser = BlockParser()
|
||||||
|
|
||||||
val commit = findCommit(repo, options.commitHash)
|
val commit = findCommit(repo, options.commitHash)
|
||||||
?: throw Exception("Commit ${ColorUtils.hash(options.commitHash)} not found")
|
?: throw Exception("Commit ${Colors.yellow(options.commitHash)} not found")
|
||||||
|
|
||||||
val commitTime = Instant.parse(commit.timestamp)
|
val commitTime = Instant.parse(commit.timestamp)
|
||||||
|
|
||||||
@@ -261,11 +260,11 @@ class ShowCommand : Subcommand("show", description = "Show detailed information
|
|||||||
val reconstructedContent = blockParser.reconstructFile(parsedFile)
|
val reconstructedContent = blockParser.reconstructFile(parsedFile)
|
||||||
|
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
result.appendLine("${ColorUtils.bold("File:")} ${ColorUtils.filename(options.targetFile)}")
|
result.appendLine("${Colors.bold("File:")} ${Colors.filename(options.targetFile)}")
|
||||||
result.appendLine("${ColorUtils.bold("Commit:")} ${ColorUtils.hash(commit.hash)}")
|
result.appendLine("${Colors.bold("Commit:")} ${Colors.yellow(commit.hash)}")
|
||||||
result.appendLine("${ColorUtils.bold("Blocks:")} ${blocks.size}")
|
result.appendLine("${Colors.bold("Blocks:")} ${blocks.size}")
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
result.appendLine("${ColorUtils.dim("─".repeat(70))}")
|
result.appendLine("${Colors.dim("─".repeat(70))}")
|
||||||
result.appendLine()
|
result.appendLine()
|
||||||
result.append(reconstructedContent)
|
result.append(reconstructedContent)
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,9 @@ package org.notevc.commands
|
|||||||
|
|
||||||
import org.notevc.core.*
|
import org.notevc.core.*
|
||||||
import org.notevc.utils.FileUtils
|
import org.notevc.utils.FileUtils
|
||||||
import org.notevc.utils.ColorUtils
|
|
||||||
import org.notevc.core.Repository.Companion.NOTEVC_DIR
|
import org.notevc.core.Repository.Companion.NOTEVC_DIR
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import org.kargs.Subcommand
|
import org.kargs.*
|
||||||
|
|
||||||
class StatusCommand : Subcommand("status", description = "Show status of tracked files", aliases = listOf("st")) {
|
class StatusCommand : Subcommand("status", description = "Show status of tracked files", aliases = listOf("st")) {
|
||||||
override fun execute() {
|
override fun execute() {
|
||||||
@@ -21,7 +20,7 @@ class StatusCommand : Subcommand("status", description = "Show status of tracked
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.onSuccess { output -> println(output) }
|
result.onSuccess { output -> println(output) }
|
||||||
result.onFailure { error -> println("${ColorUtils.error("Error:")} ${error.message}") }
|
result.onFailure { error -> println("${Colors.error("Error:")} ${error.message}") }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getRepositoryStatus(repo: Repository): RepositoryStatus {
|
private fun getRepositoryStatus(repo: Repository): RepositoryStatus {
|
||||||
@@ -111,35 +110,35 @@ class StatusCommand : Subcommand("status", description = "Show status of tracked
|
|||||||
|
|
||||||
// Modified files
|
// Modified files
|
||||||
grouped[FileStatusType.MODIFIED]?.let { modifiedFiles ->
|
grouped[FileStatusType.MODIFIED]?.let { modifiedFiles ->
|
||||||
output.appendLine(ColorUtils.bold("Modified files:"))
|
output.appendLine(Colors.bold("Modified files:"))
|
||||||
modifiedFiles.forEach { fileStatus ->
|
modifiedFiles.forEach { fileStatus ->
|
||||||
output.appendLine(" ${ColorUtils.filename(fileStatus.path)}")
|
output.appendLine(" ${Colors.filename(fileStatus.path)}")
|
||||||
fileStatus.blockChanges?.forEach { change ->
|
fileStatus.blockChanges?.forEach { change ->
|
||||||
val symbol = when (change.type) {
|
val symbol = when (change.type) {
|
||||||
BlockChangeType.MODIFIED -> ColorUtils.modified("~")
|
BlockChangeType.MODIFIED -> Colors.boldYellow("~")
|
||||||
BlockChangeType.ADDED -> ColorUtils.added("+")
|
BlockChangeType.ADDED -> Colors.boldGreen("+")
|
||||||
BlockChangeType.DELETED -> ColorUtils.deleted("-")
|
BlockChangeType.DELETED -> Colors.boldRed("-")
|
||||||
}
|
}
|
||||||
val heading = change.heading.replace(Regex("^#+\\s*"), "").trim()
|
val heading = change.heading.replace(Regex("^#+\\s*"), "").trim()
|
||||||
output.appendLine(" $symbol ${ColorUtils.heading(heading)}")
|
output.appendLine(" $symbol ${Colors.heading(heading)}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Untracked files
|
// Untracked files
|
||||||
grouped[FileStatusType.UNTRACKED]?.let { untrackedFiles ->
|
grouped[FileStatusType.UNTRACKED]?.let { untrackedFiles ->
|
||||||
output.appendLine(ColorUtils.bold("Untracked files:"))
|
output.appendLine(Colors.bold("Untracked files:"))
|
||||||
untrackedFiles.forEach { fileStatus ->
|
untrackedFiles.forEach { fileStatus ->
|
||||||
output.appendLine(" ${ColorUtils.untracked(fileStatus.path)} ${ColorUtils.dim("(${fileStatus.blockCount} blocks)")}")
|
output.appendLine(" ${Colors.dimWhite(fileStatus.path)} ${Colors.dim("(${fileStatus.blockCount} blocks)")}")
|
||||||
}
|
}
|
||||||
output.appendLine()
|
output.appendLine()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deleted files
|
// Deleted files
|
||||||
grouped[FileStatusType.DELETED]?.let { deletedFiles ->
|
grouped[FileStatusType.DELETED]?.let { deletedFiles ->
|
||||||
output.appendLine(ColorUtils.bold("Deleted files:"))
|
output.appendLine(Colors.bold("Deleted files:"))
|
||||||
deletedFiles.forEach { fileStatus ->
|
deletedFiles.forEach { fileStatus ->
|
||||||
output.appendLine(" ${ColorUtils.deleted(fileStatus.path)}")
|
output.appendLine(" ${Colors.boldRed(fileStatus.path)}")
|
||||||
}
|
}
|
||||||
output.appendLine()
|
output.appendLine()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
package org.notevc.utils
|
|
||||||
|
|
||||||
object ColorUtils {
|
|
||||||
// ANSI color codes
|
|
||||||
private const val RESET = "\u001B[0m"
|
|
||||||
private const val BOLD = "\u001B[1m"
|
|
||||||
private const val DIM = "\u001B[2m"
|
|
||||||
|
|
||||||
// Colors
|
|
||||||
private const val BLACK = "\u001B[30m"
|
|
||||||
private const val RED = "\u001B[31m"
|
|
||||||
private const val GREEN = "\u001B[32m"
|
|
||||||
private const val YELLOW = "\u001B[33m"
|
|
||||||
private const val BLUE = "\u001B[34m"
|
|
||||||
private const val MAGENTA = "\u001B[35m"
|
|
||||||
private const val CYAN = "\u001B[36m"
|
|
||||||
private const val WHITE = "\u001B[37m"
|
|
||||||
|
|
||||||
// Bright colors
|
|
||||||
private const val BRIGHT_RED = "\u001B[91m"
|
|
||||||
private const val BRIGHT_GREEN = "\u001B[92m"
|
|
||||||
private const val BRIGHT_YELLOW = "\u001B[93m"
|
|
||||||
private const val BRIGHT_BLUE = "\u001B[94m"
|
|
||||||
private const val BRIGHT_MAGENTA = "\u001B[95m"
|
|
||||||
private const val BRIGHT_CYAN = "\u001B[96m"
|
|
||||||
|
|
||||||
// Flag to force disable colors via --no-color flag
|
|
||||||
var forceDisableColors = false
|
|
||||||
|
|
||||||
// Check if colors should be enabled (disable in CI/pipes or via flag)
|
|
||||||
private val colorsEnabled: Boolean
|
|
||||||
get() = !forceDisableColors &&
|
|
||||||
System.getenv("NO_COLOR") == null &&
|
|
||||||
System.getenv("CI") == null &&
|
|
||||||
System.console() != null
|
|
||||||
|
|
||||||
// Function to disable colors programmatically
|
|
||||||
fun disableColors() {
|
|
||||||
forceDisableColors = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Public color functions
|
|
||||||
fun red(text: String): String = if (colorsEnabled) "$RED$text$RESET" else text
|
|
||||||
fun green(text: String): String = if (colorsEnabled) "$GREEN$text$RESET" else text
|
|
||||||
fun yellow(text: String): String = if (colorsEnabled) "$YELLOW$text$RESET" else text
|
|
||||||
fun blue(text: String): String = if (colorsEnabled) "$BLUE$text$RESET" else text
|
|
||||||
fun magenta(text: String): String = if (colorsEnabled) "$MAGENTA$text$RESET" else text
|
|
||||||
fun cyan(text: String): String = if (colorsEnabled) "$CYAN$text$RESET" else text
|
|
||||||
|
|
||||||
fun brightRed(text: String): String = if (colorsEnabled) "$BRIGHT_RED$text$RESET" else text
|
|
||||||
fun brightGreen(text: String): String = if (colorsEnabled) "$BRIGHT_GREEN$text$RESET" else text
|
|
||||||
fun brightYellow(text: String): String = if (colorsEnabled) "$BRIGHT_YELLOW$text$RESET" else text
|
|
||||||
fun brightBlue(text: String): String = if (colorsEnabled) "$BRIGHT_BLUE$text$RESET" else text
|
|
||||||
fun brightMagenta(text: String): String = if (colorsEnabled) "$BRIGHT_MAGENTA$text$RESET" else text
|
|
||||||
fun brightCyan(text: String): String = if (colorsEnabled) "$BRIGHT_CYAN$text$RESET" else text
|
|
||||||
|
|
||||||
fun bold(text: String): String = if (colorsEnabled) "$BOLD$text$RESET" else text
|
|
||||||
fun dim(text: String): String = if (colorsEnabled) "$DIM$text$RESET" else text
|
|
||||||
|
|
||||||
// Semantic colors for version control
|
|
||||||
fun success(text: String): String = brightGreen(text)
|
|
||||||
fun error(text: String): String = brightRed(text)
|
|
||||||
fun warning(text: String): String = brightYellow(text)
|
|
||||||
fun info(text: String): String = brightBlue(text)
|
|
||||||
fun hash(text: String): String = yellow(text)
|
|
||||||
fun filename(text: String): String = cyan(text)
|
|
||||||
fun heading(text: String): String = brightMagenta(text)
|
|
||||||
fun author(text: String): String = green(text)
|
|
||||||
fun date(text: String): String = dim(text)
|
|
||||||
|
|
||||||
// Status-specific colors
|
|
||||||
fun added(text: String): String = brightGreen(text)
|
|
||||||
fun modified(text: String): String = brightYellow(text)
|
|
||||||
fun deleted(text: String): String = brightRed(text)
|
|
||||||
fun untracked(text: String): String = red(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user