kitsunyan / pakku

Pacman wrapper with AUR support
GNU General Public License v3.0
130 stars 8 forks source link

Add support for pacman's progress bar Easter egg #59

Open omentic opened 3 years ago

omentic commented 3 years ago

This pull request implements replacing the ###--- progress bar with the -C o o style, based on /etc/pacman.conf. Since pakku wraps pacman in places, this will make both outputs look the same.

It also includes two commits I made to get Nim building that are probably poorly and unsafely done, and can be trashed if need be.

zqqw commented 3 years ago

Could you make a PR for the Easter Egg patch here for pakku-git: https://github.com/zqqw/pakku Although I could add it myself, it would make it easier to keep the history right with you as the author then. I don't think I can easily merge it as it is due to some minor changes in related areas. Sorry I didn't spot this sooner, fantastic idea! There are no warnings building pakku-git. Benjamin Shirley-Quirk's patch has fixed it and it builds with the current nim-git. I had to manually merge it in some places, here is the diff I ended up with if it makes it a bit easier, hope it's OK, apparently working anyway:

diff --git a/src/config.nim b/src/config.nim
index 1afa89a..c43890a 100644
--- a/src/config.nim
+++ b/src/config.nim
@@ -18,6 +18,7 @@ type
     arch: string,
     debug: bool,
     progressBar: bool,
+    chomp: bool,
     verbosePkgLists: bool,
     downloadTimeout: bool,
     pgpKeyserver: Option[string],
@@ -178,8 +179,8 @@ proc obtainConfig*(config: PacmanConfig): Config =
       [aurRepo, tra"wrong or NULL argument passed"], colorNeeded = some(color))

   ((config.common.dbs, config.common.arch, config.common.debug, config.common.progressBar,
-    config.common.verbosePkgLists, config.common.downloadTimeout, config.common.pgpKeyserver,
-    config.common.defaultRoot and config.sysrootOption.isNone,
+    config.common.chomp, config.common.verbosePkgLists, config.common.downloadTimeout,
+    config.common.pgpKeyserver, config.common.defaultRoot and config.sysrootOption.isNone,
     config.common.ignorePkgs, config.common.ignoreGroups),
     root, db, cache, userCacheInitial, userCacheCurrent, tmpRootInitial, tmpRootCurrent,
     color, aurRepo, aurComments, checkIgnored, ignoreArch, printAurNotFound, printLocalIsNewer,
diff --git a/src/feature/syncinstall.nim b/src/feature/syncinstall.nim
index 8f26d0d..68c0f27 100644
--- a/src/feature/syncinstall.nim
+++ b/src/feature/syncinstall.nim
@@ -42,7 +42,7 @@ proc createCloneProgress(config: Config, count: int, flexible: bool, printMode:
   (proc (update: int, terminate: int) {.closure.}, proc {.closure.}) =
   if count >= 1 and not printMode:
     let (update, terminate) = printProgressShare(config.common.progressBar,
-      tr"cloning repositories")
+      config.common.chomp, tr"cloning repositories")
     update(0, count)

     if flexible:
diff --git a/src/feature/syncsource.nim b/src/feature/syncsource.nim
index f966085..f16f7c6 100644
--- a/src/feature/syncsource.nim
+++ b/src/feature/syncsource.nim
@@ -130,7 +130,7 @@ proc cloneAndCopy(config: Config, quiet: bool, fullTargets: seq[FullPackageTarge
     newSeq[BaseTarget]())

   let (update, terminate) = if not quiet:
-      printProgressShare(config.common.progressBar, tr"cloning repositories")
+      printProgressShare(config.common.progressBar, config.common.chomp, tr"cloning repositories")
     else:
       (proc (i0: int, i1: int) {.sideEffect,closure.} = discard, proc () {.sideEffect,closure.} = discard)

diff --git a/src/format.nim b/src/format.nim
index bd6d393..a7be554 100644
--- a/src/format.nim
+++ b/src/format.nim
@@ -1,6 +1,6 @@
 import
   macros, options, posix, sequtils, strutils, sugar, times, unicode,
-  utils
+  utils, terminal

 type
   PackageLineFormat* = tuple[
@@ -299,7 +299,7 @@ macro choices*(choices: varargs[untyped]): untyped =
       else:
         error("error")

-proc printProgressFull*(bar: bool, title: string): ((string, float) -> void, () -> void) =
+proc printProgressFull*(bar: bool, chomp: bool, title: string): ((string, float) -> void, () -> void) =
   let width = getWindowSize().width

   if not bar or width <= 0:
@@ -313,16 +313,32 @@ proc printProgressFull*(bar: bool, title: string): ((string, float) -> void, ()
     var lastTime = startTime
     var lastProgress = 0f
     var averageSpeed = -1f
+    var mouth = "c"

     proc update(prefix: string, progress: float) {.sideEffect,closure.} =
       let progressTrim = max(min(1, progress + 0.005), 0)
       let progressStr = $(progressTrim * 100).int & "%"
       let paddedProgressStr = ' '.repeat(5 - progressStr.len) & progressStr

-      let indicator = if progressLen > 8: (block:
+      let indicator = if progressLen > 8:
           let fullLen = progressLen - 8
           let barLen = (fullLen.float * progressTrim).int
-          " [" & '#'.repeat(barLen) & '-'.repeat(fullLen - barLen) & "]")
+          if chomp: # This disregards the "Color" setting - but, so does pacman
+            var t: string
+            t.add(" [")
+            for i in countdown(fullLen, 1):
+              if i > fullLen - barLen:
+                t.add("-")
+              elif i == fullLen - barLen:
+                t.add(ansiForegroundColorCode(fgYellow) & mouth & ansiForegroundColorCode(fgWhite))
+              elif i mod 3 == 0:
+                t.add("o")
+              else:
+                t.add(" ")
+            t.add(ansiForegroundColorCode(fgDefault) & "]")
+            t
+          else:
+            " [" & '#'.repeat(barLen) & '-'.repeat(fullLen - barLen) & "]"
         else:
           ""

@@ -331,6 +347,10 @@ proc printProgressFull*(bar: bool, title: string): ((string, float) -> void, ()
         let speed = (progress - lastProgress) / (time - lastTime).float
         lastTime = time
         lastProgress = progress
+        if mouth == "c":
+          mouth = "C"
+        else:
+          mouth = "c"
         if averageSpeed < 0:
           averageSpeed = speed
         else:
@@ -347,9 +367,9 @@ proc printProgressFull*(bar: bool, title: string): ((string, float) -> void, ()
         else:
           "--:--"

-      stdout.write(prefix, title,
+      stdout.styledWrite(prefix, title,
         ' '.repeat(infoLen - prefix.runeLen - title.runeLen - 1 - timeLeft.len),
-        ' ', timeLeft, indicator, paddedProgressStr, "\x1b[0K\r")
+        " ", timeLeft, indicator, paddedProgressStr, "\x1b[0K\r")
       stdout.flushFile()

     proc terminate() {.sideEffect,closure.} =
@@ -359,8 +379,8 @@ proc printProgressFull*(bar: bool, title: string): ((string, float) -> void, ()

     (update, terminate)

-proc printProgressShare*(bar: bool, title: string): ((int, int) -> void, () -> void) =
-  let (updateFull, terminate) = printProgressFull(bar, title)
+proc printProgressShare*(bar: bool, chomp: bool, title: string): ((int, int) -> void, () -> void) =
+  let (updateFull, terminate) = printProgressFull(bar, chomp, title)

   proc update(current: int, total: int) {.sideEffect,closure.} =
     let prefix = if total > 0:
diff --git a/src/pacman.nim b/src/pacman.nim
index 5f1cb4a..561d2cb 100644
--- a/src/pacman.nim
+++ b/src/pacman.nim
@@ -350,6 +350,7 @@ proc createConfigFromTable(table: Table[string, string], dbs: seq[string]): Pacm
   let cacheRel = table.opt("CacheDir")
   let gpgRel = table.opt("GPGDir")
   let color = if table.hasKey("Color"): ColorMode.colorAuto else: ColorMode.colorNever
+  let chomp = table.hasKey("ILoveCandy")
   let verbosePkgLists = table.hasKey("VerbosePkgLists")
   let downloadTimeout = not table.hasKey("DisableDownloadTimeout")
   let arch = table.opt("Architecture").get("auto")
@@ -361,7 +362,7 @@ proc createConfigFromTable(table: Table[string, string], dbs: seq[string]): Pacm
     raise commandError(tr"can not get the architecture",
       colorNeeded = some(color.get))

-  ((dbs, archFinal, false, true, verbosePkgLists, downloadTimeout, none(string), true,
+  ((dbs, archFinal, false, true, chomp, verbosePkgLists, downloadTimeout, none(string), true,
     ignorePkgs, ignoreGroups), none(string), rootRel, dbRel, cacheRel, gpgRel, color)

 proc obtainPacmanConfig*(args: seq[Argument]): PacmanConfig =
@@ -440,7 +441,7 @@ proc obtainPacmanConfig*(args: seq[Argument]): PacmanConfig =
   let argsRootRel = rootRel.get("/")
   let defaultRoot = defaultRootRel == argsRootRel

-  let config: PacmanConfig = ((defaultConfig.common.dbs, arch, debug, progressBar,
+  let config: PacmanConfig = ((defaultConfig.common.dbs, arch, debug, progressBar, defaultConfig.common.chomp,
     defaultConfig.common.verbosePkgLists, defaultConfig.common.downloadTimeout and downloadTimeout,
     pgpKeyserver, defaultRoot, ignorePkgs + defaultConfig.common.ignorePkgs,
     ignoreGroups + defaultConfig.common.ignoreGroups),
omentic commented 3 years ago

Sure thing, let me know if the pull request I just opened works. I'm going to leave this one open too, just in case kitsunyan checks back in and decides to merge some stuff.