commit 701fffebad34d0f36f5fd2165569f42d177ffef9 from: ale date: Thu Jul 23 18:48:00 2026 UTC Implementa estado de archivos read-only vía got status GotCommandLineWrapper centraliza la ejecución de got (GeneralCommandLine + ExecUtil) y parsea 'got status' (formato XY path). GotChangeProvider mapea los códigos de estado a FileStatus y reporta al ChangelistBuilder. GotContentRevision expone el contenido base ('got cat -c :base -P') como beforeRevision, para que el preview de diff del panel de Commit funcione. commit - 8f270315ac1a03425e7daccc1db3b14cd7080df8 commit + 701fffebad34d0f36f5fd2165569f42d177ffef9 blob - /dev/null blob + 5d5d3b53a52c1f7cb2b933f3284eaa56abb6524a (mode 644) --- /dev/null +++ src/main/kotlin/dev/nezzontli/gotvcs/GotChangeProvider.kt @@ -0,0 +1,67 @@ +package dev.nezzontli.gotvcs + +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.vcs.FileStatus +import com.intellij.openapi.vcs.changes.Change +import com.intellij.openapi.vcs.changes.ChangeListManagerGate +import com.intellij.openapi.vcs.changes.ChangeProvider +import com.intellij.openapi.vcs.changes.ChangelistBuilder +import com.intellij.openapi.vcs.changes.CurrentContentRevision +import com.intellij.openapi.vcs.changes.LocallyDeletedChange +import com.intellij.openapi.vcs.changes.VcsDirtyScope +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.vcsUtil.VcsUtil +import java.io.File + +class GotChangeProvider(private val commandLine: GotCommandLineWrapper) : ChangeProvider { + + override fun getChanges( + dirtyScope: VcsDirtyScope, + builder: ChangelistBuilder, + progress: ProgressIndicator, + addGate: ChangeListManagerGate, + ) { + for (root in dirtyScope.affectedContentRoots) { + val workDir = File(root.path) + val entries = commandLine.status(workDir) + + for (entry in entries) { + val absoluteFile = File(workDir, entry.path) + val filePath = VcsUtil.getFilePath(absoluteFile, false) + + when (entry.code) { + '?' -> { + val virtualFile = LocalFileSystem.getInstance().findFileByIoFile(absoluteFile) + if (virtualFile != null) builder.processUnversionedFile(virtualFile) + } + + '!' -> builder.processLocallyDeletedFile(LocallyDeletedChange(filePath, filePath.path)) + + 'M', 'm', 'C' -> { + val status = if (entry.code == 'C') FileStatus.MERGED_WITH_CONFLICTS else FileStatus.MODIFIED + val before = GotContentRevision(filePath, workDir, entry.path, commandLine) + val after = CurrentContentRevision(filePath) + builder.processChange(Change(before, after, status), GotVcs.getKey()) + } + + 'A' -> { + val after = CurrentContentRevision(filePath) + builder.processChange(Change(null, after, FileStatus.ADDED), GotVcs.getKey()) + } + + 'D' -> { + val before = GotContentRevision(filePath, workDir, entry.path, commandLine) + builder.processChange(Change(before, null, FileStatus.DELETED), GotVcs.getKey()) + } + + else -> Unit + } + } + } + } + + override fun isModifiedDocumentTrackingRequired(): Boolean = false + + override fun doCleanup(files: MutableList) = Unit +} blob - /dev/null blob + ac1cc93524bbae9807b2bb24fc2210a6b8af6352 (mode 644) --- /dev/null +++ src/main/kotlin/dev/nezzontli/gotvcs/GotCommandLineWrapper.kt @@ -0,0 +1,58 @@ +package dev.nezzontli.gotvcs + +import com.intellij.execution.ExecutionException +import com.intellij.execution.configurations.GeneralCommandLine +import com.intellij.execution.util.ExecUtil +import com.intellij.openapi.vcs.VcsException +import java.io.File +import java.nio.charset.StandardCharsets + +data class GotStatusEntry(val code: Char, val stagedCode: Char, val path: String) + +/** + * Centraliza todas las invocaciones al binario `got`. La ruta de abajo es la + * del store de Nix resuelta al momento de escribir este código + * (readlink -f /etc/profiles/per-user/ale/bin/idea muestra el store path del + * IDE; el de got se resolvió igual desde /run/current-system/sw/bin/got). + * Cambia con cada rebuild del sistema -> deuda para GotConfigurable (Fase 6). + */ +class GotCommandLineWrapper { + + private fun binaryPath(): String { + val nixPath = File("/run/current-system/sw/bin/got") + return if (nixPath.canExecute()) nixPath.path else "got" + } + + private fun run(workDir: File, vararg args: String): String { + val commandLine = GeneralCommandLine(binaryPath(), *args) + .withWorkDirectory(workDir) + .withCharset(StandardCharsets.UTF_8) + val output = try { + ExecUtil.execAndGetOutput(commandLine) + } catch (e: ExecutionException) { + throw VcsException("No se pudo ejecutar got ${args.joinToString(" ")}: ${e.message}", e) + } + if (output.exitCode != 0) { + throw VcsException("got ${args.joinToString(" ")} salió con código ${output.exitCode}: ${output.stderr.trim()}") + } + return output.stdout + } + + @Throws(VcsException::class) + fun status(workDir: File): List { + val output = run(workDir, "status") + return output.lineSequence() + .filter { it.isNotBlank() } + .map { line -> + val code = line[0] + val stagedCode = line.getOrElse(1) { ' ' } + val path = line.substring(minOf(3, line.length)) + GotStatusEntry(code, stagedCode, path) + } + .toList() + } + + @Throws(VcsException::class) + fun catAtBase(workDir: File, relativePath: String): String = + run(workDir, "cat", "-c", ":base", "-P", relativePath) +} blob - /dev/null blob + 71fc5d1ce6d080d0810c34ed9caf00cac683e449 (mode 644) --- /dev/null +++ src/main/kotlin/dev/nezzontli/gotvcs/GotContentRevision.kt @@ -0,0 +1,23 @@ +package dev.nezzontli.gotvcs + +import com.intellij.openapi.vcs.FilePath +import com.intellij.openapi.vcs.VcsException +import com.intellij.openapi.vcs.changes.ContentRevision +import com.intellij.openapi.vcs.history.VcsRevisionNumber +import java.io.File + +/** Contenido de un archivo en el commit base del work tree, vía `got cat -c :base`. */ +class GotContentRevision( + private val filePath: FilePath, + private val workDir: File, + private val relativePath: String, + private val commandLine: GotCommandLineWrapper, +) : ContentRevision { + + @Throws(VcsException::class) + override fun getContent(): String = commandLine.catAtBase(workDir, relativePath) + + override fun getFile(): FilePath = filePath + + override fun getRevisionNumber(): VcsRevisionNumber = VcsRevisionNumber.NULL +}