Add support to view files affected by a revision

[?]
Apr 1, 2021, 12:07 AM
5AUENX2YJVFNKZUSPEPDNLLL7TKZS2WTFC6CABWSZK2EC4MNCRQAC

Dependencies

  • [2] ZCRW57C5 Improved support for revisions
  • [3] FRFFQV7V Basic show history support.
  • [4] 7L5LODGZ Parse changes from `pijul change`
  • [5] 6CR2EFUN First ChangeProvider implementation!!! Wheehooo
  • [6] QXUEMZ3B Initial CahngeProvider
  • [7] Q7FXTHVU First record support, YEAAAH, RECOOORD
  • [*] FNNW5IEA Added more plugin files to Pijul
  • [*] OPFG6CZ2 File status tracking supported.

Change contents

  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/revision/PijulVcsFileRevision.kt at line 25
    [2.2295][2.2295:2403]()
    val deleted: Boolean) : VcsFileRevisionEx(), Comparable<PijulVcsFileRevision> {
    [2.2295]
    [3.1489]
    val deleted: Boolean) : VcsFileRevisionEx(), Comparable<PijulVcsFileRevision> {
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulHistoryProvider.kt at line 3
    [3.4532]
    [2.3326]
    import com.github.jonathanxd.dracon.context.PijulVcsContext
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulHistoryProvider.kt at line 11
    [3.4846]
    [3.4846]
    import com.intellij.openapi.actionSystem.ActionManager
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulHistoryProvider.kt at line 14
    [3.4943]
    [3.4943]
    import com.intellij.openapi.components.service
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulHistoryProvider.kt at line 18
    [3.5083]
    [3.5083]
    import com.intellij.openapi.vcs.VcsActions
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulHistoryProvider.kt at line 20
    [3.5128]
    [3.5128]
    import com.intellij.openapi.vcs.annotate.ShowAllAffectedGenericAction
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulHistoryProvider.kt at line 24
    [3.5253]
    [2.3432]
    import com.intellij.vcs.history.VcsHistoryProviderEx
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulHistoryProvider.kt at line 26
    [2.3477]
    [3.5253]
    import java.nio.file.Paths
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulHistoryProvider.kt at line 30
    [3.5293][3.5293:5365]()
    class PijulHistoryProvider(val project: Project) : VcsHistoryProvider {
    [3.5293]
    [3.5365]
    class PijulHistoryProvider(val project: Project) : VcsHistoryProvider,
    VcsHistoryProviderEx {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulHistoryProvider.kt at line 41
    [3.5691][3.5691:5719]()
    return emptyArray()
    [3.5691]
    [3.5719]
    return arrayOf(
    ShowAllAffectedGenericAction.getInstance(),
    ActionManager.getInstance().getAction(VcsActions.ACTION_COPY_REVISION_NUMBER)
    )
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulHistoryProvider.kt at line 82
    [3.6970]
    [3.6970]
    override fun reportAppendableHistory(
    path: FilePath,
    startingRevision: VcsRevisionNumber?,
    partner: VcsAppendableHistorySessionPartner
    ) {
    reportAppendableHistory(path, partner)
    }
    override fun getLastRevision(filePath: FilePath): VcsFileRevision? {
    val ctx = this.project.service<PijulVcsContext>()
    val root = ctx.root
    val revisions = pijul(project).revisions(this.project, root, ctx.resolveUnderVcs(filePath))
    return revisions.result?.firstOrNull()
    }
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulHistoryProvider.kt at line 112
    [3.7565]
    [2.3657]
    // TODO: Should we limit to show only one revision when introspecting directories instead of all revisions?
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/pijul/Pijul.kt at line 17
    [3.1698]
    [9.4473]
    import com.github.jonathanxd.dracon.revision.PijulVcsFileRevision
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/pijul/Pijul.kt at line 106
    [2.5889]
    [2.5889]
    fun revisions(project: Project, root: Path, file: Path): PijulOperationResult<List<PijulVcsFileRevision>>
    fun allRevisions(project: Project, root: Path): PijulOperationResult<List<PijulRevisionNumber>>
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/pijul/Pijul.kt at line 118
    [3.13352]
    [3.4755]
    * Retrieves info about pijul channels.
    */
    @RequiresBackgroundThread
    fun channel(project: Project, root: Path): PijulOperationResult<ChannelInfo>
    /**
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/pijul/Pijul.kt at line 146
    [3.13855]
    [3.4805]
    * Retrieves change history
    */
    @RequiresBackgroundThread
    fun fileHistory(project: Project,
    root: Path,
    file: Path,
    consumer: (PijulLogEntry) -> Unit,
    errorConsumer: (PijulOperationResult<Unit>) -> Unit): PijulOperationResult<Unit>
    /**
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 3
    [3.2008]
    [3.61076]
    import com.github.jonathanxd.dracon.revision.PijulRevisionNumber
    import com.intellij.openapi.vcs.FileStatus
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 24
    [3.2154]
    [3.61469]
    val PijulLogEntry.revision: PijulRevisionNumber get() = PijulRevisionNumber(this.changeHash, this.date)
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 910
    [3.90451][3.90451:90462]()
    ")"
    [3.90451]
    ")"
    val HunkWithPath.status: FileStatus
    get() = (this as Hunk).status
    val Hunk.status: FileStatus
    get() = when(this) {
    is FileAddHunk -> FileStatus.ADDED
    is FileDelHunk -> FileStatus.DELETED
    is ReplacementHunk -> FileStatus.MODIFIED
    is EditHunk -> FileStatus.MODIFIED
    is MoveHunk -> FileStatus.SUPPRESSED
    else -> FileStatus.UNKNOWN
    }
  • file addition: dialog (----------)
    [9.107]
  • file addition: PijulExpertRecordDialogV2.kt (----------)
    [0.2837]
    package com.github.jonathanxd.dracon.dialog
    import com.github.jonathanxd.dracon.i18n.DraconBundle
    import com.intellij.openapi.application.ApplicationManager
    import com.intellij.openapi.fileTypes.FileTypeRegistry
    import com.intellij.openapi.project.Project
    import com.intellij.openapi.ui.DialogPanel
    import com.intellij.openapi.ui.DialogWrapper
    import com.intellij.openapi.ui.DialogWrapper.IdeModalityType
    import com.intellij.openapi.wm.WindowManager
    import com.intellij.ui.EditorTextField
    import com.intellij.ui.layout.panel
    import org.jetbrains.annotations.Nullable
    import java.awt.Component
    import java.awt.Window
    import java.awt.event.ComponentAdapter
    import java.awt.event.ComponentEvent
    import javax.swing.JComponent
    import java.awt.BorderLayout
    import java.awt.Dimension
    import javax.swing.JLabel
    import javax.swing.JPanel
    fun createPijulRecordDialog(project: Project, text: String): DialogPanel {
    val panel = panel {
    }
    val toml = FileTypeRegistry.getInstance().getFileTypeByExtension("toml")
    val editor = EditorTextField(text, project, toml)
    editor.preferredSize = Dimension(340, 460)
    panel.add(editor)
    return panel
    }
    class PijulExpertRecordDialogV2(val project: Project, val text: String) : DialogWrapper(project, true) {
    /*constructor(project: Project?, canBeParent: Boolean): super(project, canBeParent)
    constructor(project: Project?, canBeParent: Boolean, ideModalityType: IdeModalityType): super(project, canBeParent, ideModalityType)
    constructor(
    project: Project?,
    parentComponent: Component?,
    canBeParent: Boolean,
    ideModalityType: IdeModalityType
    ): super (project, parentComponent, canBeParent, ideModalityType, true)
    constructor(
    project: Project?,
    parentComponent: Component?,
    canBeParent: Boolean,
    ideModalityType: IdeModalityType,
    createSouth: Boolean
    ) : super(project, parentComponent, canBeParent, ideModalityType, createSouth)
    constructor(project: Project?): super(project)
    constructor(canBeParent: Boolean): super(canBeParent)
    constructor(canBeParent: Boolean, applicationModalIfPossible: Boolean): super(null, canBeParent, applicationModalIfPossible)
    constructor(project: Project?, canBeParent: Boolean, applicationModalIfPossible: Boolean): super(project, canBeParent, applicationModalIfPossible)
    constructor(parent: Component, canBeParent: Boolean): super(parent, canBeParent)*/
    init {
    init()
    title = DraconBundle.message("action.Pijul.ExpertRecord.text")
    }
    override fun createCenterPanel(): JComponent {
    val dialogPanel = JPanel(BorderLayout())
    val toml = FileTypeRegistry.getInstance().getFileTypeByExtension("toml")
    val editor = EditorTextField(this.text, this.project, toml)
    editor.preferredSize = Dimension(340, 460)
    dialogPanel.add(editor, BorderLayout.CENTER)
    return dialogPanel
    }
    }
  • file addition: PijulExpertRecordDialog.kt (----------)
    [0.2837]
    package com.github.jonathanxd.dracon.dialog
    import com.github.jonathanxd.dracon.completion.PijulRecordFileTextCompletionProvider
    import com.github.jonathanxd.dracon.i18n.DraconBundle
    import com.github.jonathanxd.dracon.pijul.NonZeroExitStatusCode
    import com.github.jonathanxd.dracon.pijul.SuccessStatusCode
    import com.github.jonathanxd.dracon.pijul.pijul
    import com.intellij.CommonBundle
    import com.intellij.ide.IdeBundle
    import com.intellij.lang.Language
    import com.intellij.notification.Notification
    import com.intellij.notification.NotificationGroup
    import com.intellij.notification.NotificationType
    import com.intellij.notification.Notifications
    import com.intellij.openapi.application.ApplicationManager
    import com.intellij.openapi.editor.Document
    import com.intellij.openapi.editor.ex.EditorEx
    import com.intellij.openapi.fileTypes.FileTypeRegistry
    import com.intellij.openapi.project.Project
    import com.intellij.openapi.ui.DialogEarthquakeShaker
    import com.intellij.openapi.ui.DialogWrapper
    import com.intellij.openapi.ui.DialogWrapper.DialogWrapperAction
    import com.intellij.openapi.ui.DialogWrapper.IdeModalityType
    import com.intellij.openapi.ui.ValidationInfo
    import com.intellij.openapi.ui.popup.JBPopupFactory
    import com.intellij.openapi.wm.IdeFocusManager
    import com.intellij.openapi.wm.WindowManager
    import com.intellij.psi.PsiFile
    import com.intellij.ui.EditorTextField
    import com.intellij.ui.LanguageTextField
    import com.intellij.ui.TextFieldWithAutoCompletion
    import com.intellij.ui.TextFieldWithAutoCompletionListProvider
    import com.intellij.util.containers.ContainerUtil
    import com.intellij.util.textCompletion.TextCompletionUtil
    import org.jetbrains.annotations.Nullable
    import java.awt.*
    import java.awt.event.*
    import java.beans.PropertyChangeEvent
    import java.beans.PropertyChangeListener
    import java.lang.Boolean
    import java.nio.file.Path
    import javax.swing.*
    open class PijulExpertRecordDialog(val project: Project,
    val vcsRoot: Path,
    val text: String) : DialogWrapper(project, true) {
    private val EXPERT_MODE_GROUP =
    NotificationGroup.createIdWithTitle("Expert Mode", DraconBundle.message("expert.mode.notification.group.id"))
    init {
    init()
    title = DraconBundle.message("action.Pijul.ExpertRecord.text")
    }
    //private lateinit var editor: EditorTextField
    //private lateinit var field: TextFieldWithAutoCompletion<String>
    private lateinit var editor: CustomEditorField
    override fun createCenterPanel(): JComponent {
    val dialogPanel = JPanel(BorderLayout())
    val tomlLanguage = Language.findLanguageByID("TOML")
    val ext = FileTypeRegistry.getInstance().getFileTypeByExtension("toml")
    val doc = LanguageTextField.createDocument(
    this.text,
    tomlLanguage,
    this.project,
    RecordDocumentCreator()
    )
    editor = CustomEditorField(tomlLanguage, project, this.text)
    /*val field = TextFieldWithAutoCompletion(this.project, Provider(), true, this.text)
    field.setOneLineMode(false)
    field.isViewer = false*/
    //editor = EditorTextField(doc, this.project, ext, false, false)
    editor.preferredSize = Dimension(800, 600)
    editor.setOneLineMode(false)
    editor.isViewer = false
    editor.isVisible = true
    editor.isEnabled = true
    //field.preferredSize = Dimension(800, 600)
    dialogPanel.add(editor, BorderLayout.CENTER)
    return dialogPanel
    }
    override fun createActions(): Array<Action> {
    return arrayOf(RecordAction(), this.cancelAction)
    }
    override fun doOKAction() {
    val record = pijul(this.project).recordFromString(this.project, this.vcsRoot, this.editor.text)
    if (record.statusCode is SuccessStatusCode) {
    val hash = record.result!!.substring("Hash:".length).trim()
    Notifications.Bus.notify(
    Notification(
    EXPERT_MODE_GROUP,
    DraconBundle.message("expert.mode.notification.title"),
    DraconBundle.message("expert.mode.notification.success", hash),
    NotificationType.ERROR,
    ),
    this.project
    )
    } else {
    record.statusCode as NonZeroExitStatusCode
    Notifications.Bus.notify(
    Notification(
    EXPERT_MODE_GROUP,
    DraconBundle.message("expert.mode.notification.title"),
    DraconBundle.message("expert.mode.notification.failure", record.statusCode.exitCode, record.statusCode.message),
    NotificationType.INFORMATION,
    ),
    this.project
    )
    }
    super.doOKAction()
    }
    protected inner class RecordAction() : DialogWrapper.DialogWrapperAction(DraconBundle.message("expert.mode.button.record")) {
    override fun doAction(e: ActionEvent?) {
    val infoList: List<ValidationInfo> = doValidateAll()
    if (infoList.isNotEmpty()) {
    val info = infoList[0]
    if (info.component != null && info.component!!.isVisible) {
    IdeFocusManager.getInstance(null).requestFocus(info.component!!, true)
    }
    updateErrorInfo(infoList)
    startTrackingValidation()
    if (ContainerUtil.exists(
    infoList
    ) { info1: ValidationInfo -> !info1.okEnabled }
    ) return
    }
    doOKAction()
    }
    init {
    addPropertyChangeListener { evt: PropertyChangeEvent ->
    if (NAME == evt.propertyName) {
    repaint()
    }
    }
    }
    }
    class Provider : TextFieldWithAutoCompletionListProvider<String>(listOf("author", "[[authors]]", "authors", "name", "full_name", "email")) {
    override fun getLookupString(item: String): String {
    return item
    }
    }
    class RecordDocumentCreator : TextCompletionUtil.DocumentWithCompletionCreator(
    TextFieldWithAutoCompletion.StringsCompletionProvider(listOf("author", "[[authors]]", "authors", "name", "full_name", "email"),null),
    true
    )
    }
    class CustomEditorField(language: Language?, project: Project, s: String) : LanguageTextField(language, project, s, PijulExpertRecordDialog.RecordDocumentCreator(), false) {
    override fun createEditor(): EditorEx {
    val editor = super.createEditor()
    editor.setVerticalScrollbarVisible(true)
    editor.setHorizontalScrollbarVisible(true)
    editor.setCaretEnabled(true)
    editor.isViewer = false
    editor.isOneLineMode = false
    val settings = editor.settings
    settings.isLineNumbersShown = true
    settings.isAutoCodeFoldingEnabled = true
    settings.isFoldingOutlineShown = true
    settings.isAllowSingleLogicalLineFolding = true
    settings.isRightMarginShown=true
    return editor
    }
    }
  • file addition: context (----------)
    [9.107]
  • file addition: PijulVcsContext.kt (----------)
    [0.13018]
    package com.github.jonathanxd.dracon.context
    import com.github.jonathanxd.dracon.PijulVcs
    import com.github.jonathanxd.dracon.pijulVcs
    import com.intellij.openapi.components.Service
    import com.intellij.openapi.components.serviceIfCreated
    import com.intellij.openapi.project.Project
    import com.intellij.openapi.vcs.FilePath
    import com.intellij.openapi.vcs.ProjectLevelVcsManager
    import com.intellij.openapi.vfs.VirtualFile
    import java.nio.file.Path
    import java.nio.file.Paths
    import kotlin.io.path.ExperimentalPathApi
    import kotlin.io.path.relativeTo
    @Service
    class PijulVcsContext(val project: Project) {
    val root by lazy {
    // Currently only supports a single vcs root for pijul.
    ProjectLevelVcsManager.getInstance(this.project).getRootsUnderVcs(pijulVcs(this.project))
    .first()
    .toNioPath()
    }
    @OptIn(ExperimentalPathApi::class)
    fun resolveUnderVcs(path: FilePath): Path =
    this.resolveUnderVcs(Paths.get(path.path))
    @OptIn(ExperimentalPathApi::class)
    fun resolveUnderVcs(path: VirtualFile): Path =
    this.resolveUnderVcs(path.toNioPath())
    @OptIn(ExperimentalPathApi::class)
    fun resolveUnderVcs(path: Path): Path =
    when {
    this.root.toAbsolutePath().toString() == path.toAbsolutePath().toString() -> this.root
    path.startsWith(this.root) -> path
    else -> this.root.relativize(path)
    }
    @OptIn(ExperimentalPathApi::class)
    fun resolveRelativeToRoot(path: Path): String =
    if (path.toAbsolutePath().equals(this.root.toAbsolutePath().toString()))
    ""
    else
    path.toAbsolutePath().relativeTo(this.root).toString()
    fun isRootPath(path: Path) =
    this.root.toAbsolutePath().toString() == path.toAbsolutePath().toString()
    }
  • file addition: completion (----------)
    [9.107]
  • file addition: PijulRecordFileTextCompletionProvider.kt (----------)
    [0.14863]
    package com.github.jonathanxd.dracon.completion
    import com.intellij.codeInsight.completion.CompletionParameters
    import com.intellij.codeInsight.completion.CompletionResultSet
    import com.intellij.codeInsight.lookup.CharFilter
    import com.intellij.util.textCompletion.TextCompletionProvider
    class PijulRecordFileTextCompletionProvider : TextCompletionProvider {
    override fun getAdvertisement(): String? {
    return null
    }
    override fun getPrefix(text: String, offset: Int): String? {
    return null
    }
    override fun applyPrefixMatcher(result: CompletionResultSet, prefix: String): CompletionResultSet =
    result.withPrefixMatcher(prefix)
    override fun acceptChar(c: Char): CharFilter.Result? {
    return null
    }
    override fun fillCompletionVariants(parameters: CompletionParameters, prefix: String, result: CompletionResultSet) {
    }
    }
  • file addition: PijulCompletionContributor.kt (----------)
    [0.14863]
    package com.github.jonathanxd.dracon.completion
    import com.intellij.codeInsight.completion.*
    import com.intellij.codeInsight.lookup.LookupElementBuilder
    import com.intellij.patterns.PlatformPatterns
    import com.intellij.util.ProcessingContext
    class PijulCompletionContributor : CompletionContributor() {
    init {
    extend(CompletionType.BASIC, PlatformPatterns.psiElement(), object : CompletionProvider<CompletionParameters>() {
    override fun addCompletions(
    parameters: CompletionParameters,
    context: ProcessingContext,
    result: CompletionResultSet
    ) {
    result.addElement(LookupElementBuilder.create("author"))
    result.addElement(LookupElementBuilder.create("[[authors]]"))
    result.addElement(LookupElementBuilder.create("authors"))
    result.addElement(LookupElementBuilder.create("name"))
    result.addElement(LookupElementBuilder.create("full_name"))
    result.addElement(LookupElementBuilder.create("email"))
    }
    })
    }
    }
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 21
    [3.4222]
    [9.11119]
    import com.github.jonathanxd.dracon.revision.PijulVcsFileRevision
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 36
    [3.6932]
    [9.11640]
    import com.intellij.vcs.log.impl.VcsUserImpl
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 259
    [10.3744]
    [9.13604]
    }
    override fun revisions(project: Project, root: Path, file: Path): PijulOperationResult<List<PijulVcsFileRevision>> {
    val historyList = mutableListOf<PijulVcsFileRevision>()
    val channels = this.channel(this.project, root)
    val currentChannel = channels.result?.channels?.firstOrNull { it.current }?.name
    val result = this.fileHistory(project, root, file, {
    it.hunks.filterIsInstance<HunkWithPath>().groupBy {
    it.resolvePath(root)
    }.forEach { (path, hunks) ->
    val deleted = hunks.any { it is FileDelHunk }
    historyList.add(
    PijulVcsFileRevision(
    this.project,
    root,
    path,
    PijulRevisionNumber(it.changeHash, it.date),
    it.authors.map { VcsUserImpl(it.name ?: "", it.email ?: "") }.filter { it.name.isNotEmpty() },
    it.message,
    currentChannel,
    deleted
    )
    )
    }
    }, {})
    return PijulOperationResult(result.operation, result.statusCode, historyList)
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 341
    [3.11223][3.17114:17237]()
    val logHashExecution = this.createExecPijulOperation(project, rootPath, listOf("log", "--hash-only"), delay = 10L)
    [3.11223]
    [3.17237]
    return this.fileHistory(project, rootPath, filePath, consumer, errorConsumer)
    }
    @OptIn(ExperimentalPathApi::class)
    override fun fileHistory(
    project: Project,
    root: Path,
    file: Path,
    consumer: (PijulLogEntry) -> Unit,
    errorConsumer: (PijulOperationResult<Unit>) -> Unit
    ): PijulOperationResult<Unit> {
    val ctx = project.service<PijulVcsContext>()
    val filePath = ctx.resolveUnderVcs(file)
    val isRootPath = ctx.isRootPath(filePath)
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 357
    [3.17238]
    [3.17238]
    val logHashExecution = this.createPainlessExecPijulOperation(project, root, listOf("log", "--hash-only"))
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 365
    [3.17477][3.17477:17533]()
    return hashes as PijulOperationResult<Unit>
    [3.17477]
    [3.17533]
    return hashes
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 374
    [3.17714][3.17714:17870]()
    val change = this.doExecutionWithMapper("change-$hash", this.createPainlessExecPijulOperation(project, rootPath, listOf("change", hash))) {
    [3.17714]
    [3.17870]
    val change = this.doExecutionWithMapper("change-$hash", this.createPainlessExecPijulOperation(project, root, listOf("change", hash))) {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 386
    [3.18310][2.8071:8141]()
    val hunkPath = hunk.resolvePath(rootPath)
    [3.18310]
    [2.8141]
    val hunkPath = hunk.resolvePath(root)
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 483
    [3.8515]
    [3.19677]
    override fun allRevisions(project: Project, root: Path): PijulOperationResult<List<PijulRevisionNumber>> {
    val log = this.log(project, root)
    return PijulOperationResult(log.operation, log.statusCode,
    log.result?.entries?.map {
    PijulRevisionNumber(it.changeHash, it.date)
    }
    )
    }
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 495
    [3.19816][3.19816:19923]()
    val channelOperation = this.createPainlessExecPijulOperation(project, rootPath, listOf("channel"))
    [3.19816]
    [3.5951]
    return this.channel(project, rootPath)
    }
    override fun channel(project: Project, root: Path): PijulOperationResult<ChannelInfo> {
    val channelOperation = this.createPainlessExecPijulOperation(project, root, listOf("channel"))
  • file addition: changes (----------)
    [9.107]
  • file addition: PijulCommittedChangesProvider.kt (----------)
    [0.19780]
    package com.github.jonathanxd.dracon.changes
    import com.github.jonathanxd.dracon.PijulVcs
    import com.github.jonathanxd.dracon.content.PijulContentRevision
    import com.github.jonathanxd.dracon.context.PijulVcsContext
    import com.github.jonathanxd.dracon.log.*
    import com.github.jonathanxd.dracon.pijul.pijul
    import com.github.jonathanxd.dracon.pijulVcs
    import com.github.jonathanxd.dracon.revision.PijulRevisionNumber
    import com.intellij.openapi.components.Service
    import com.intellij.openapi.components.service
    import com.intellij.openapi.project.Project
    import com.intellij.openapi.util.Pair
    import com.intellij.openapi.util.io.FileUtil
    import com.intellij.openapi.vcs.*
    import com.intellij.openapi.vcs.changes.Change
    import com.intellij.openapi.vcs.changes.ChangeList
    import com.intellij.openapi.vcs.changes.ChangesUtil
    import com.intellij.openapi.vcs.history.VcsFileRevision
    import com.intellij.openapi.vcs.history.VcsRevisionNumber
    import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings
    import com.intellij.openapi.vcs.versionBrowser.ChangesBrowserSettingsEditor
    import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList
    import com.intellij.openapi.vcs.versionBrowser.StandardVersionFilterComponent
    import com.intellij.openapi.vfs.VirtualFile
    import com.intellij.util.AsynchConsumer
    import com.intellij.vcs.CommittedChangeListForRevision
    import com.intellij.vcs.log.VcsFullCommitDetails
    import com.intellij.vcs.log.util.VcsLogUtil
    import com.intellij.vcsUtil.VcsUtil
    import org.jetbrains.annotations.NotNull
    import java.nio.file.Files
    import java.nio.file.Path
    import java.nio.file.Paths
    import java.util.*
    import javax.swing.JComponent
    @Service
    class PijulCommittedChangesProvider(val project: Project) : CommittedChangesProvider<CommittedChangeList, ChangeBrowserSettings> {
    override fun createFilterUI(showDateFilter: Boolean): ChangesBrowserSettingsEditor<ChangeBrowserSettings> =
    PijulVersionFilterComponent(showDateFilter)
    override fun getLocationFor(root: FilePath): RepositoryLocation {
    val ctx = this.project.service<PijulVcsContext>()
    val channel = pijul(this.project).channel(this.project, ctx.root).result?.channels?.firstOrNull { it.current }?.name ?: "unknown"
    return PijulRepositoryLocation(ctx.root, channel)
    }
    override fun getCommittedChanges(
    settings: ChangeBrowserSettings,
    location: RepositoryLocation,
    maxCount: Int
    ): MutableList<CommittedChangeList> {
    val changes = mutableListOf<CommittedChangeList>()
    this.getChanges(settings, location, maxCount) {
    changes.add(it)
    }
    return changes
    }
    override fun loadCommittedChanges(
    settings: ChangeBrowserSettings,
    location: RepositoryLocation,
    maxCount: Int,
    consumer: AsynchConsumer<in CommittedChangeList>
    ) {
    try {
    getChanges(settings, location, maxCount) {
    consumer.consume(it)
    }
    } finally {
    consumer.finished()
    }
    }
    private fun getChanges(settings: ChangeBrowserSettings,
    location: RepositoryLocation,
    maxCount: Int,
    consumer: (PijulCommittedChangeList) -> Unit) {
    val ctx = this.project.service<PijulVcsContext>()
    val filters = mutableListOf<(PijulLogEntry) -> Boolean>()
    val beforeRev = settings.changeBeforeFilter
    val afterRev = settings.changeAfterFilter
    val beforeDate = settings.dateBeforeFilter
    val afterDate = settings.dateAfterFilter
    val author = settings.userFilter
    if (beforeRev != null) {
    filters += { entry ->
    entry.date.toEpochSecond() < beforeRev
    }
    }
    if (afterRev != null) {
    filters += { entry ->
    entry.date.toEpochSecond() > afterRev
    }
    }
    if (beforeDate != null) {
    filters += { entry ->
    entry.date.toInstant().isBefore(beforeDate.toInstant())
    }
    }
    if (afterDate != null) {
    filters += { entry ->
    entry.date.toInstant().isAfter(afterDate.toInstant())
    }
    }
    if (author != null) {
    filters += { entry ->
    entry.authors.any { it.name == author }
    }
    }
    val allRevisions = pijul(this.project).allRevisions(this.project, ctx.root).result!!
    pijul(this.project).log(this.project, ctx.root).result?.entries?.filter {
    filters.all { filter -> filter(it) }
    }?.map { entry ->
    PijulCommittedChangeList(
    entry.message,
    "",
    entry.authors.firstOrNull()?.name ?: "No author",
    Date.from(entry.date.toInstant()),
    entry.hunks.filterIsInstance<HunkWithPath>().map { hunk ->
    val beforeRevision =
    if (hunk is FileAddHunk) null
    else findARevisionBefore(entry.changeHash, allRevisions)?.let {
    PijulContentRevision(
    ctx.root,
    hunk.resolvePath(ctx.root),
    it,
    this.project
    )
    }
    val afterRevision =
    if (hunk is FileDelHunk) null
    else PijulContentRevision(
    ctx.root,
    hunk.resolvePath(ctx.root),
    entry.revision,
    this.project
    )
    Change(
    beforeRevision,
    afterRevision,
    hunk.status
    )
    }.toMutableList(),
    entry.revision,
    false,
    pijulVcs(this.project)
    )
    }?.let { if (maxCount == -1) it else it.take(maxCount) }?.forEach {
    consumer(it)
    }
    }
    fun findARevisionBefore(current: String, allRevisions: List<PijulRevisionNumber>): PijulRevisionNumber? {
    for (i in allRevisions.indices) {
    if (current == allRevisions[i].hash) {
    return if (i == 0) {
    null
    } else {
    allRevisions[i - 1]
    }
    }
    }
    return null
    }
    override fun getColumns(): Array<ChangeListColumn<*>> {
    return arrayOf(
    ChangeListColumn.NUMBER,
    ChangeListColumn.DATE,
    ChangeListColumn.DESCRIPTION,
    ChangeListColumn.NAME
    )
    }
    override fun getUnlimitedCountValue(): Int = -1
    override fun getOneList(file: VirtualFile, number: VcsRevisionNumber): Pair<CommittedChangeList, FilePath>? {
    val ctx = this.project.service<PijulVcsContext>()
    val path = Paths.get(VcsUtil.getFilePath(file).path)
    val filePath = ctx.resolveUnderVcs(path)
    val allRevisions = pijul(this.project).allRevisions(this.project, ctx.root).result!!
    val rev = pijul(this.project).log(this.project, ctx.root).result?.entries?.filter {
    it.revision.hash == number.asString()
    }?.map { entry ->
    PijulCommittedChangeList(
    entry.message,
    "",
    entry.authors.firstOrNull()?.name ?: "No author",
    Date.from(entry.date.toInstant()),
    entry.hunks.filterIsInstance<HunkWithPath>().map { hunk ->
    val beforeRevision =
    if (hunk is FileAddHunk) null
    else findARevisionBefore(entry.changeHash, allRevisions)?.let {
    PijulContentRevision(
    ctx.root,
    hunk.resolvePath(ctx.root),
    it,
    this.project
    )
    }
    val afterRevision =
    if (hunk is FileDelHunk) null
    else PijulContentRevision(
    ctx.root,
    hunk.resolvePath(ctx.root),
    entry.revision,
    this.project
    )
    Change(
    beforeRevision,
    afterRevision,
    hunk.status
    )
    }.toMutableList(),
    entry.revision,
    false,
    pijulVcs(this.project)
    )
    }?.firstOrNull() ?: return null
    return Pair.create(rev, LocalFilePath(filePath, Files.isDirectory(filePath)))
    }
    }
    class PijulRepositoryLocation(val path: Path, val channel: String) : RepositoryLocation {
    override fun toPresentableString(): String =
    "${this.path}@${this.channel}"
    override fun getKey(): String =
    this.path.toString()
    override fun toString(): String = this.toPresentableString()
    }
    class PijulVersionFilterComponent(showDateFilter: Boolean) :
    StandardVersionFilterComponent<ChangeBrowserSettings>(showDateFilter) {
    override fun getComponent(): JComponent {
    return standardPanel as JComponent
    }
    init {
    init(ChangeBrowserSettings())
    }
    }
    class PijulCommittedChangeList(
    subject: String,
    comment: String,
    committerName: String,
    commitDate: Date,
    changes: MutableCollection<Change>,
    revisionNumber: VcsRevisionNumber,
    val modifiable: Boolean,
    val vcs: PijulVcs
    ) : CommittedChangeListForRevision(subject, comment, committerName, commitDate, changes, revisionNumber) {
    override fun isModifiable(): Boolean = this.modifiable
    override fun getNumber(): Long =
    this.revisionNumber.timestamp.toInstant().epochSecond
    override fun getRevisionNumber(): PijulRevisionNumber {
    return super.getRevisionNumber() as PijulRevisionNumber
    }
    override fun getVcs(): AbstractVcs = this.vcs
    }
  • file addition: PijulExpertRecord.kt (----------)
    [9.18106]
    package com.github.jonathanxd.dracon.actions
    import com.github.jonathanxd.dracon.dialog.PijulExpertRecordDialog
    import com.github.jonathanxd.dracon.dialog.createPijulRecordDialog
    import com.github.jonathanxd.dracon.pijul.pijul
    import com.intellij.openapi.actionSystem.AnActionEvent
    import com.intellij.openapi.fileEditor.FileEditorManager
    import com.intellij.openapi.fileEditor.OpenFileDescriptor
    import com.intellij.openapi.fileTypes.FileTypeRegistry
    import com.intellij.openapi.project.DumbAwareAction
    import com.intellij.openapi.vcs.ProjectLevelVcsManager
    import com.intellij.testFramework.LightVirtualFile
    import com.intellij.ui.layout.panel
    import kotlin.io.path.relativeTo
    class PijulExpertRecord : DumbAwareAction() {
    override fun actionPerformed(e: AnActionEvent) {
    val project = e.project!!
    val vcsManager = ProjectLevelVcsManager.getInstance(project)
    val root = vcsManager.allVcsRoots.first().path.toNioPath()
    val recordString = pijul(project).recordToString(project, root)
    if (recordString.result != null) {
    val toml = FileTypeRegistry.getInstance().getFileTypeByExtension("toml")
    //val editor = EditorTextField(recordString.result, this.project, )
    /*
    val psiFile = PsiDocumentManager.getInstance(editor.getProject()).getPsiFile(editor.getDocument())
    val element = psiFile!!.findElementAt(editor.getCaretModel().getOffset())
    val code: PsiExpressionCodeFragment = JavaCodeFragmentFactory.getInstance(editor.getProject())
    .createExpressionCodeFragment("", element, null, true)
    val document: Document? = PsiDocumentManager.getInstance(editor.getProject()).getDocument(code)
    val myInput = EditorTextField(document, editor.getProject(), JavaFileType.INSTANCE)
    */
    PijulExpertRecordDialog(project, root, recordString.result).showAndGet()
    /*FileEditorManager.getInstance(project).openTextEditor(
    OpenFileDescriptor(project, LightVirtualFile("record", toml, recordString.result)),
    true
    )*/
    }
    }
    }
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/PijulVcs.kt at line 13
    [9.24185]
    [3.16060]
    import com.github.jonathanxd.dracon.changes.PijulCommittedChangesProvider
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/PijulVcs.kt at line 23
    [9.24380]
    [9.24380]
    import com.intellij.openapi.vcs.CommittedChangesProvider
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/PijulVcs.kt at line 31
    [3.16362]
    [9.24475]
    import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/PijulVcs.kt at line 75
    [3.16577]
    [9.25245]
    override fun getCommittedChangesProvider(): CommittedChangesProvider<out CommittedChangeList, *>? =
    project.service<PijulCommittedChangesProvider>()