From 90959a446585a8a8733257b95cd321466b14ddde Mon Sep 17 00:00:00 2001 From: Alejandro R Mosteo Date: Fri, 15 May 2020 19:57:33 +0200 Subject: [PATCH] Colorize output (#402) * Colorize log messages * Colorize entities: crates, milestones, dependencies --- .gitmodules | 3 + alire.gpr | 1 + alr_env.gpr | 1 + deps/ansi | 1 + src/alire/alire-conditional.ads | 2 +- src/alire/alire-crates-with_releases.adb | 15 +++ src/alire/alire-crates-with_releases.ads | 4 + src/alire/alire-dependencies-diffs.adb | 8 +- src/alire/alire-dependencies-graphs.adb | 4 +- src/alire/alire-dependencies.ads | 21 +++- src/alire/alire-interfaces.ads | 9 ++ src/alire/alire-milestones.ads | 23 +++- src/alire/alire-releases.adb | 2 +- src/alire/alire-releases.ads | 12 ++ src/alire/alire-solutions-diffs.adb | 37 +++--- src/alire/alire-solutions.adb | 15 ++- src/alire/alire-utils-tty.adb | 137 +++++++++++++++++++++++ src/alire/alire-utils-tty.ads | 94 ++++++++++++++++ src/alire/alire-utils-user_input.adb | 9 +- src/alr/alr-commands-get.adb | 2 +- src/alr/alr-commands-list.adb | 4 +- src/alr/alr-commands-search.adb | 37 +++--- src/alr/alr-commands.adb | 28 ++++- 23 files changed, 409 insertions(+), 60 deletions(-) create mode 160000 deps/ansi create mode 100644 src/alire/alire-utils-tty.adb create mode 100644 src/alire/alire-utils-tty.ads diff --git a/.gitmodules b/.gitmodules index 92512d3b..598852b2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -23,3 +23,6 @@ [submodule "testsuite/fixtures/crates/libhello_git"] path = testsuite/fixtures/crates/libhello_git url = https://github.com/alire-project/libhello.git +[submodule "deps/ansi"] + path = deps/ansi + url = https://github.com/mosteo/ansi-ada diff --git a/alire.gpr b/alire.gpr index 7839f98f..3170afc8 100644 --- a/alire.gpr +++ b/alire.gpr @@ -2,6 +2,7 @@ with "aaa"; with "ada_toml"; with "alire_common"; with "ajunitgen"; +with "ansi"; with "gnatcoll"; with "semantic_versioning"; with "simple_logging"; diff --git a/alr_env.gpr b/alr_env.gpr index d8c460ad..5368640f 100644 --- a/alr_env.gpr +++ b/alr_env.gpr @@ -6,6 +6,7 @@ aggregate project Alr_Env is "deps/aaa", "deps/ada-toml", "deps/ajunitgen", + "deps/ansi", "deps/gnatcoll-slim", "deps/semantic_versioning", "deps/simple_logging", diff --git a/deps/ansi b/deps/ansi new file mode 160000 index 00000000..27a89150 --- /dev/null +++ b/deps/ansi @@ -0,0 +1 @@ +Subproject commit 27a89150c1f5481a821722601a3b6d4a5368596c diff --git a/src/alire/alire-conditional.ads b/src/alire/alire-conditional.ads index 81c54e54..66de8f84 100644 --- a/src/alire/alire-conditional.ads +++ b/src/alire/alire-conditional.ads @@ -12,7 +12,7 @@ package Alire.Conditional with Preelaborate is ------------------ package For_Dependencies is new Conditional_Trees (Dependencies.Dependency, - Dependencies.Image); + Dependencies.TTY_Image); subtype Dependencies is For_Dependencies.Tree; subtype Platform_Dependencies is Conditional.Dependencies diff --git a/src/alire/alire-crates-with_releases.adb b/src/alire/alire-crates-with_releases.adb index dcaf5842..8ae9767b 100644 --- a/src/alire/alire-crates-with_releases.adb +++ b/src/alire/alire-crates-with_releases.adb @@ -4,6 +4,7 @@ with Alire.Origins; with Alire.Properties.Labeled; with Alire.Requisites; with Alire.TOML_Keys; +with Alire.Utils.TTY; with TOML; @@ -214,12 +215,26 @@ package body Alire.Crates.With_Releases is end if; end Description; + --------------------- + -- TTY_Description -- + --------------------- + + function TTY_Description (This : Crate) return String + is (Utils.TTY.Description (This.Description)); + ---------- -- Name -- ---------- function Name (This : Crate) return Crate_Name is (+(+This.Name)); + -------------- + -- TTY_Name -- + -------------- + + function TTY_Name (This : Crate) return String + is (Utils.TTY.Name (+This.Name)); + --------------- -- New_Crate -- --------------- diff --git a/src/alire/alire-crates-with_releases.ads b/src/alire/alire-crates-with_releases.ads index 0d0b9de8..e90da60c 100644 --- a/src/alire/alire-crates-with_releases.ads +++ b/src/alire/alire-crates-with_releases.ads @@ -16,6 +16,8 @@ package Alire.Crates.With_Releases is function Name (This : Crate) return Crate_Name; + function TTY_Name (This : Crate) return String; + procedure Add (This : in out Crate; Release : Releases.Release) with Pre => not This.Contains (Release.Version) or else @@ -33,6 +35,8 @@ package Alire.Crates.With_Releases is function Description (This : Crate) return Description_String; + function TTY_Description (This : Crate) return String; + function Externals (This : Crate) return Alire.Externals.Lists.List; function Releases (This : Crate) return Containers.Release_Set; diff --git a/src/alire/alire-dependencies-diffs.adb b/src/alire/alire-dependencies-diffs.adb index cf327ed8..12387a86 100644 --- a/src/alire/alire-dependencies-diffs.adb +++ b/src/alire/alire-dependencies-diffs.adb @@ -59,8 +59,8 @@ package body Alire.Dependencies.Diffs is for Dep of List loop Table .Append (" " & Icon) - .Append (+Dep.Crate) - .Append (Dep.Versions.Image) + .Append (TTY.Name (+Dep.Crate)) + .Append (TTY.Version (Dep.Versions.Image)) .Append (Comment) .New_Row; end loop; @@ -68,8 +68,8 @@ package body Alire.Dependencies.Diffs is begin if This.Contains_Changes then - Summarize (This.Added, "(added)", "✓"); - Summarize (This.Removed, "(removed)", "✗"); + Summarize (This.Added, "(added)", TTY.OK ("✓")); + Summarize (This.Removed, "(removed)", TTY.Emph ("✗")); Table.Print (Info); else Trace.Info (" No changes."); diff --git a/src/alire/alire-dependencies-graphs.adb b/src/alire/alire-dependencies-graphs.adb index 2c5cb061..58fe37a7 100644 --- a/src/alire/alire-dependencies-graphs.adb +++ b/src/alire/alire-dependencies-graphs.adb @@ -139,9 +139,9 @@ package body Alire.Dependencies.Graphs is Filtered : constant Graph := This.Filtering_Unused (Instance); begin for Dep of Filtered loop - Table.Append (Prefix & Instance (+Dep.Dependent).Milestone.Image); + Table.Append (Prefix & Instance (+Dep.Dependent).Milestone.TTY_Image); Table.Append ("-->"); - Table.Append (Instance (+Dep.Dependee).Milestone.Image); + Table.Append (Instance (+Dep.Dependee).Milestone.TTY_Image); Table.New_Row; end loop; diff --git a/src/alire/alire-dependencies.ads b/src/alire/alire-dependencies.ads index b4deb1ed..34e40d58 100644 --- a/src/alire/alire-dependencies.ads +++ b/src/alire/alire-dependencies.ads @@ -8,12 +8,15 @@ with Semantic_Versioning.Extended; with TOML; use all type TOML.Any_Value_Kind; +private with Alire.Utils.TTY; + package Alire.Dependencies with Preelaborate is -- A single dependency is a crate name plus a version set type Dependency (<>) is new Interfaces.Classificable -- since the crate name is the key + and Interfaces.Colorable and Interfaces.Tomifiable and Interfaces.Yamlable with private; @@ -36,6 +39,9 @@ package Alire.Dependencies with Preelaborate is function Image (Dep : Dependency) return String; -- Standard-style version image, e.g. "make^3.1" + overriding + function TTY_Image (Dep : Dependency) return String; + overriding function Key (Dep : Dependency) return String; @@ -62,8 +68,11 @@ package Alire.Dependencies with Preelaborate is private + package TTY renames Utils.TTY; + type Dependency (Name_Len : Natural) is new Interfaces.Classificable + and Interfaces.Colorable and Interfaces.Tomifiable and Interfaces.Yamlable with record @@ -97,11 +106,17 @@ private (New_Dependency (Allowed.Crate, Allowed.Versions)); function Image (Dep : Dependency) return String is - (if Dep = Unavailable + (if Dep = Unavailable then "Unavailable" + else (+Dep.Crate) & Dep.Versions.Image); + + overriding + function TTY_Image (Dep : Dependency) return String is + (if Dep = Unavailable + then + TTY.Version ("Unavailable") else - (Utils.To_Lower_Case (+Dep.Crate) - & Dep.Versions.Image)); + (TTY.Name (+Dep.Crate) & TTY.Version (Dep.Versions.Image))); overriding function To_YAML (Dep : Dependency) return String is diff --git a/src/alire/alire-interfaces.ads b/src/alire/alire-interfaces.ads index 750a3001..8d343da1 100644 --- a/src/alire/alire-interfaces.ads +++ b/src/alire/alire-interfaces.ads @@ -21,6 +21,15 @@ package Alire.Interfaces with Preelaborate is function Image (This : Imaginable) return String is abstract; + --------------- + -- Colorable -- + --------------- + + type Colorable is limited interface; + -- Types that can be displayed with ANSI colors/formatting + + function TTY_Image (This : Colorable) return String is abstract; + ---------------- -- Tomifiable -- ---------------- diff --git a/src/alire/alire-milestones.ads b/src/alire/alire-milestones.ads index 72a8e58b..b026e7b1 100644 --- a/src/alire/alire-milestones.ads +++ b/src/alire/alire-milestones.ads @@ -1,8 +1,12 @@ +with Alire.Interfaces; + with Semantic_Versioning.Extended; +private with Alire.Utils.TTY; + package Alire.Milestones with Preelaborate is - type Milestone (<>) is tagged private; + type Milestone (<>) is new Interfaces.Colorable with private; function "<" (L, R : Milestone) return Boolean; @@ -16,6 +20,9 @@ package Alire.Milestones with Preelaborate is function Image (M : Milestone) return String; + overriding + function TTY_Image (M : Milestone) return String; + ----------------------- -- Milestone parsing -- ----------------------- @@ -32,7 +39,9 @@ package Alire.Milestones with Preelaborate is private - type Milestone (Name_Len : Natural) is tagged record + package TTY renames Utils.TTY; + + type Milestone (Name_Len : Natural) is new Interfaces.Colorable with record Name : Crate_Name (1 .. Name_Len); Version : Semantic_Versioning.Version; end record; @@ -55,6 +64,14 @@ private is (M.Version); function Image (M : Milestone) return String is - (+M.Crate & "=" & Image (M.Version)); + ((+M.Crate) + & "=" + & Image (M.Version)); + + overriding + function TTY_Image (M : Milestone) return String is + (TTY.Name (+M.Crate) + & "=" + & TTY.Version (Image (M.Version))); end Alire.Milestones; diff --git a/src/alire/alire-releases.adb b/src/alire/alire-releases.adb index c45ec191..34fe769d 100644 --- a/src/alire/alire-releases.adb +++ b/src/alire/alire-releases.adb @@ -443,7 +443,7 @@ package body Alire.Releases is use GNAT.IO; begin -- MILESTONE - Put_Line (R.Milestone.Image & ": " & R.Description); + Put_Line (R.Milestone.TTY_Image & ": " & R.TTY_Description); if R.Provides /= R.Name then Put_Line ("Provides: " & (+R.Provides)); diff --git a/src/alire/alire-releases.ads b/src/alire/alire-releases.ads index 1263314e..8fb3da8f 100644 --- a/src/alire/alire-releases.ads +++ b/src/alire/alire-releases.ads @@ -21,6 +21,7 @@ with Semantic_Versioning; with TOML; private with Alire.OS_Lib; +private with Alire.Utils.TTY; package Alire.Releases with Preelaborate is @@ -122,10 +123,15 @@ package Alire.Releases with Preelaborate is function Name_Str (R : Release) return String is (+R.Name); + function TTY_Name (R : Release) return String; + function Description (R : Release) return Description_String; -- Returns the description for the crate, which is also stored as a -- property of the release. + function TTY_Description (R : Release) return String; + -- Colorized description + function Long_Description (R : Release) return String; -- Returns the long description for the crate, which is also stored as a -- property of the release. @@ -325,6 +331,9 @@ private function Name (R : Release) return Crate_Name is (R.Name); + function TTY_Name (R : Release) return String + is (Utils.TTY.Name (+R.Name)); + function Provides (R : Release) return Crate_Name is (if UStrings.Length (R.Alias) = 0 then R.Name @@ -365,6 +374,9 @@ private (Conditional.Enumerate (R.Properties).Filter (Alire.TOML_Keys.Description).First_Element.Image, ' ')); + function TTY_Description (R : Release) return String + is (Utils.TTY.Description (R.Description)); + function Is_Pinned (R : Release) return Boolean is (R.Pinned); diff --git a/src/alire/alire-solutions-diffs.adb b/src/alire/alire-solutions-diffs.adb index 089a530d..1187cd76 100644 --- a/src/alire/alire-solutions-diffs.adb +++ b/src/alire/alire-solutions-diffs.adb @@ -1,8 +1,11 @@ with Alire.Containers; with Alire.Utils.Tables; +with Alire.Utils.TTY; package body Alire.Solutions.Diffs is + package TTY renames Utils.TTY; + use type Semantic_Versioning.Version; ------------------ @@ -130,14 +133,14 @@ package body Alire.Solutions.Diffs is if Former.Status = Needed and then Latter.Status = Needed then if Former.Version < Latter.Version then - return ", upgraded from " & Former.Version.Image; + return ", upgraded from " & TTY.Version (Former.Version.Image); elsif Former.Version = Latter.Version then return ", version unchanged"; else - return ", downgraded from " & Former.Version.Image; + return ", downgraded from " & TTY.Version (Former.Version.Image); end if; elsif Former.Status = Needed and then Latter.Status /= Needed then - return " from " & Former.Version.Image; + return " from " & TTY.Version (Former.Version.Image); else -- Pinned, nothing else to say return ""; @@ -192,26 +195,26 @@ package body Alire.Solutions.Diffs is Table.Append (Prefix & (case This.Change (Key (I)) is - when Added => "✓", - when Removed => "✗", - when External => "↪", - when Upgraded => "⭧", - when Downgraded => "⭨", - when Pinned => "⊙", -- ⍟⟟⫯🞊⊙⊛ - when Unpinned => "𐩒", -- 📍🖈○⚪⭘ - when Unchanged => "=", - when Unsolved => "⚠")); + when Added => TTY.OK ("✓"), + when Removed => TTY.Emph ("✗"), + when External => TTY.Warn ("↪"), + when Upgraded => TTY.OK ("⭧"), + when Downgraded => TTY.Warn ("⭨"), + when Pinned => TTY.OK ("⊙"), + when Unpinned => TTY.Emph ("𐩒"), + when Unchanged => TTY.OK ("="), + when Unsolved => TTY.Error ("⚠"))); -- Always show crate name - Table.Append (+Key (I)); + Table.Append (TTY.Name (+Key (I))); -- Show most precise version available if Latter.Status in Hinted | Needed then - Table.Append (Best_Version (Latter)); + Table.Append (TTY.Version (Best_Version (Latter))); else - Table.Append (Best_Version (Former)); + Table.Append (TTY.Version (Best_Version (Former))); end if; -- Finally show an explanation of the change depending on @@ -224,9 +227,9 @@ package body Alire.Solutions.Diffs is when Removed => "removed", when External => "external", when Upgraded => "upgraded from " - & Semver.Image (Former.Version), + & TTY.Version (Semver.Image (Former.Version)), when Downgraded => "downgraded from " - & Semver.Image (Former.Version), + & TTY.Version (Semver.Image (Former.Version)), when Pinned => "pinned" & Pin_Change_Summary (Former, Latter), when Unpinned => "unpinned" diff --git a/src/alire/alire-solutions.adb b/src/alire/alire-solutions.adb index 79406c7b..f3c4c7ac 100644 --- a/src/alire/alire-solutions.adb +++ b/src/alire/alire-solutions.adb @@ -5,11 +5,14 @@ with Alire.OS_Lib.Subprocess; with Alire.Paths; with Alire.Solutions.Diffs; with Alire.Utils.Tables; +with Alire.Utils.TTY; with Semantic_Versioning; package body Alire.Solutions is + package TTY renames Utils.TTY; + ------------- -- Changes -- ------------- @@ -79,9 +82,9 @@ package body Alire.Solutions is if not This.Releases.Is_Empty then Trace.Log ("Dependencies (solution):", Level); for Rel of This.Releases loop - Trace.Log (" " & Rel.Milestone.Image + Trace.Log (" " & Rel.Milestone.TTY_Image & (if Rel.Is_Pinned - then " (pinned)" + then TTY.Emph (" (pinned)") else "") & (if Detailed then " (origin: " & @@ -97,7 +100,7 @@ package body Alire.Solutions is if not This.Hints.Is_Empty then Trace.Log ("Dependencies (external):", Level); for Dep of This.Hints loop - Trace.Log (" " & Dep.Image, Level); + Trace.Log (" " & Dep.TTY_Image, Level); -- Look for hints. If we are relying on workspace -- information the index may not be loaded, or have @@ -110,7 +113,7 @@ package body Alire.Solutions is (Name => Dep.Crate, Env => Alire.Properties.No_Properties) loop - Trace.Log (" Hint: " & Hint, Level); + Trace.Log (TTY.Emph (" Hint: ") & Hint, Level); end loop; end if; end loop; @@ -151,8 +154,8 @@ package body Alire.Solutions is for Release of This.Releases loop if Release.Is_Pinned then Table - .Append (+Release.Name) - .Append (Release.Version.Image) + .Append (Release.TTY_Name) + .Append (TTY.Version (Release.Version.Image)) .New_Row; end if; end loop; diff --git a/src/alire/alire-utils-tty.adb b/src/alire/alire-utils-tty.adb new file mode 100644 index 00000000..b70eb21c --- /dev/null +++ b/src/alire/alire-utils-tty.adb @@ -0,0 +1,137 @@ +with Simple_Logging.Decorators; + +package body Alire.Utils.TTY is + + use all type ANSI.Colors; + use all type ANSI.Styles; + + type States is (Disabled, Enabled, Default); + + Status : States := Default; + + function Regular_Decorator (Level : Simple_Logging.Levels; + Message : String) return String; + + function Verbose_Decorator (Level : Simple_Logging.Levels; + Message : String) return String; + + --------------- + -- Use_Color -- + --------------- + + function Use_Color return Boolean is + (case Status is + when Enabled => True, + when Disabled => False, + when Default => Simple_Logging.Is_TTY); + + ------------------- + -- Disable_Color -- + ------------------- + + procedure Disable_Color is + begin + Status := Disabled; + end Disable_Color; + + ------------------ + -- Enable_Color -- + ------------------ + + procedure Enable_Color (Force : Boolean := False) is + begin + + -- Enable when appropriate + + if Force or else Simple_Logging.Is_TTY then + Status := Enabled; + end if; + + -- Set debug colors. When Detail/Debug are also enabled, we add the + -- "info:" prefix to otherwise normal output, so it's seen more easily. + + if Use_Color then + case Log_Level is + when Always .. Info => + Simple_Logging.Decorators.Level_Decorator := + Regular_Decorator'Access; + when others => + Simple_Logging.Decorators.Level_Decorator := + Verbose_Decorator'Access; + end case; + end if; + end Enable_Color; + + ------------ + -- Format -- + ------------ + + function Format (Text : String; + Fore : ANSI.Colors := ANSI.Default; + Back : ANSI.Colors := ANSI.Default; + Style : ANSI.Styles := ANSI.Default) + return String + is + use ANSI; + begin + if not Use_Color then + return Text; + end if; + + return + ((if Fore /= Default then Foreground (Fore) else "") + & (if Back /= Default then Background (Fore) else "") + & (if Style /= Default then ANSI.Style (Style, On) else "") + & Text + & (if Fore /= Default then Foreground (Default) else "") + & (if Back /= Default then Background (Default) else "") + & (if Style /= Default then ANSI.Style (Style, Off) else "")); + end Format; + + ----------------------- + -- Regular_Decorator -- + ----------------------- + + function Regular_Decorator (Level : Simple_Logging.Levels; + Message : String) return String is + (case Level is + when Info => Message, + when others => Verbose_Decorator (Level, Message)); + + ----------------------- + -- Verbose_Decorator -- + ----------------------- + + function Verbose_Decorator (Level : Simple_Logging.Levels; + Message : String) return String + is + use ANSI; + begin + return + (case Level is + when Always => Message, + when Error => + ANSI.Wrap (Text => "error:", + Style => Bright, + Foreground => ANSI.Foreground (Red)) & " " & Message, + when Warning => + ANSI.Wrap (Text => "warn:", + Style => Bright, + Foreground => ANSI.Foreground (Yellow)) & " " & Message, + when Info => + ANSI.Wrap (Text => "info:", + Style => Bright, + Foreground => ANSI.Foreground (Green)) & " " & Message, + when Detail => + ANSI.Wrap (Text => "detail:", + Style => Bright, + Foreground => ANSI.Foreground (Cyan)) & " " & Message, + when Debug => + ANSI.Wrap (Text => "debug:", + Style => Default, + Foreground => ANSI.Foreground (Grey)) & " " + & ANSI.Wrap (Text => Message, + Style => Dim)); + end Verbose_Decorator; + +end Alire.Utils.TTY; diff --git a/src/alire/alire-utils-tty.ads b/src/alire/alire-utils-tty.ads new file mode 100644 index 00000000..3dd1f8b7 --- /dev/null +++ b/src/alire/alire-utils-tty.ads @@ -0,0 +1,94 @@ +with ANSI; + +package Alire.Utils.TTY with Preelaborate is + + -- Color/Formatting related subprograms. These won't have any + -- effect if a redirection of output is detected, or if global + -- flag Simple_Logging.Is_TTY is false. + + -- Re-expose for clients + package ANSI renames Standard.ANSI; + + procedure Disable_Color; + -- Disables color/formatting output even when TTY is capable + + procedure Enable_Color (Force : Boolean := False); + -- Prepares colors for the logging messages. Unless Force, will do nothing + -- if a console redirection is detected. + + function Format (Text : String; + Fore : ANSI.Colors := ANSI.Default; + Back : ANSI.Colors := ANSI.Default; + Style : ANSI.Styles := ANSI.Default) + return String; + -- Wrap text with the appropriate ANSI sequences. Following text will be + -- unaffected. Default colors are interpreted as no change of color (will + -- result in no color sequences), not as setting the default color (which + -- is always set after a color change). + + ------------------------ + -- Predefined formats -- + ------------------------ + + function OK (Text : String) return String; + -- Bold Light_Green + + function Emph (Text : String) return String; + -- Something to highligth not negatively, bold cyan + + function Error (Text : String) return String; + -- Bold Red + + function Warn (Text : String) return String; + -- Bold Yellow + + function Bold (Text : String) return String; + + function Name (Text : String) return String; + -- Bold Default for crate names + + function Description (Text : String) return String; + -- Not bold cyan for crate descriptions + + function Version (Text : String) return String; + -- For versions/version sets, bold magenta + +private + + function OK (Text : String) return String is + (Format (Text, + Fore => ANSI.Light_Green, + Style => ANSI.Bright)); + + function Emph (Text : String) return String is + (Format (Text, + Fore => ANSI.Cyan, + Style => ANSI.Bright)); + + function Error (Text : String) return String is + (Format (Text, + Fore => ANSI.Red, + Style => ANSI.Bright)); + + function Warn (Text : String) return String is + (Format (Text, + Fore => ANSI.Yellow, + Style => ANSI.Bright)); + + function Bold (Text : String) return String is + (Format (Text, + Style => ANSI.Bright)); + + function Name (Text : String) return String is + (Bold (Text)); + + function Description (Text : String) return String is + (Format (Text, + Fore => ANSI.Light_Cyan)); + + function Version (Text : String) return String is + (Format (Text, + Fore => ANSI.Magenta, + Style => ANSI.Bright)); + +end Alire.Utils.TTY; diff --git a/src/alire/alire-utils-user_input.adb b/src/alire/alire-utils-user_input.adb index 55c74a1c..3fe3381a 100644 --- a/src/alire/alire-utils-user_input.adb +++ b/src/alire/alire-utils-user_input.adb @@ -4,6 +4,7 @@ with Ada.Characters.Handling; with Interfaces.C_Streams; with Alire.Config; +with Alire.Utils.TTY; package body Alire.Utils.User_Input is @@ -49,10 +50,14 @@ package body Alire.Utils.User_Input is begin for Kind in Answer_Kind loop if Valid (Kind) then - TIO.Put ("[" & Answer_Char (Kind) & "] " & Img (Kind) & " "); + TIO.Put ("[" + & (if Kind = Default + then TTY.Bold ("" & Answer_Char (Kind)) + else "" & Answer_Char (Kind)) + & "] " & Img (Kind) & " "); end if; end loop; - TIO.Put ("(default is " & Img (Default) & ") "); + TIO.Put ("(default is " & TTY.Bold (Img (Default)) & ") "); end Print_Valid_Answers; ----------- diff --git a/src/alr/alr-commands-get.adb b/src/alr/alr-commands-get.adb index eae31881..3bd5e67f 100644 --- a/src/alr/alr-commands-get.adb +++ b/src/alr/alr-commands-get.adb @@ -132,7 +132,7 @@ package body Alr.Commands.Get is Trace.Info (""); - Trace.Log (Rel.Milestone.Image & " successfully retrieved" + Trace.Log (Rel.Milestone.TTY_Image & " successfully retrieved" & (if Cmd.Build then (if Build_OK then " and built." diff --git a/src/alr/alr-commands-list.adb b/src/alr/alr-commands-list.adb index e818227c..2fa700f5 100644 --- a/src/alr/alr-commands-list.adb +++ b/src/alr/alr-commands-list.adb @@ -39,8 +39,8 @@ package body Alr.Commands.List is then Found := Found + 1; Table.New_Row; - Table.Append (+Crate.Name); - Table.Append (Crate.Description); + Table.Append (Crate.TTY_Name); + Table.Append (Crate.TTY_Description); end if; Busy.Step; end loop; diff --git a/src/alr/alr-commands-search.adb b/src/alr/alr-commands-search.adb index 711241ac..320742a2 100644 --- a/src/alr/alr-commands-search.adb +++ b/src/alr/alr-commands-search.adb @@ -7,6 +7,7 @@ with Alire.Releases; with Alire.Solutions; with Alire.Solver; with Alire.Utils.Tables; +with Alire.Utils.TTY; with Alr.Platform; with Alr.Utils; @@ -15,6 +16,8 @@ with Semantic_Versioning; package body Alr.Commands.Search is + package TTY renames Alire.Utils.TTY; + ------------- -- Execute -- ------------- @@ -24,6 +27,11 @@ package body Alr.Commands.Search is Found : Natural := 0; Tab : Alire.Utils.Tables.Table; + Flag_System : constant String := TTY.OK ("S"); + Flag_Unav : constant String := TTY.Error ("U"); + Flag_Unsolv : constant String := TTY.Error ("X"); + Flag_External : constant String := TTY.Warn ("E"); + ------------------ -- List_Release -- ------------------ @@ -44,10 +52,11 @@ package body Alr.Commands.Search is then Found := Found + 1; Tab.New_Row; - Tab.Append (+R.Name); + Tab.Append (TTY.Name (+R.Name)); Tab.Append - ((if R.Origin.Is_System then "S" else " ") & - (if R.Is_Available (Platform.Properties) then " " else "U") & + ((if R.Origin.Is_System then Flag_System else " ") & + (if R.Is_Available (Platform.Properties) + then " " else Flag_Unav) & (if R.Origin.Is_System then " " else (if Solver.Is_Resolvable (R.Dependencies (Platform.Properties), @@ -57,9 +66,9 @@ package body Alr.Commands.Search is Detecting => Solver.Dont_Detect, Hinting => Solver.Hint)) then " " - else "X"))); - Tab.Append (Semantic_Versioning.Image (R.Version)); - Tab.Append (R.Description); + else Flag_Unsolv))); + Tab.Append (TTY.Version (Semantic_Versioning.Image (R.Version))); + Tab.Append (TTY.Description (R.Description)); Tab.Append (R.Notes); end if; end List_Release; @@ -74,11 +83,11 @@ package body Alr.Commands.Search is Found := Found + 1; Tab.New_Row; Tab.Append (+Name); - Tab.Append ("E" & - (if Cmd.Detect then "U" else " ") & + Tab.Append (Flag_External & + (if Cmd.Detect then Flag_Unav else " ") & " "); Tab.Append ("external"); - Tab.Append (Alire.Index.Crate (Name).Description); + Tab.Append (Alire.Index.Crate (Name).TTY_Description); Tab.Append (Ext.Image); end List_Undetected; @@ -114,11 +123,11 @@ package body Alr.Commands.Search is Requires_Full_Index; - Tab.Append ("NAME"); - Tab.Append ("STATUS"); - Tab.Append ("VERSION"); - Tab.Append ("DESCRIPTION"); - Tab.Append ("NOTES"); + Tab.Append (TTY.Bold ("NAME")); + Tab.Append (TTY.Bold ("STATUS")); + Tab.Append (TTY.Bold ("VERSION")); + Tab.Append (TTY.Bold ("DESCRIPTION")); + Tab.Append (TTY.Bold ("NOTES")); declare Busy : Simple_Logging.Ongoing := diff --git a/src/alr/alr-commands.adb b/src/alr/alr-commands.adb index 208ffb0f..abe11a37 100644 --- a/src/alr/alr-commands.adb +++ b/src/alr/alr-commands.adb @@ -11,10 +11,12 @@ with Alire.Config; with Alire.Features.Index; with Alire.Index; with Alire.Lockfiles; +with Alire.Platforms; with Alire.Roots; with Alire.Roots.Check_Valid; with Alire.Solutions; with Alire.Utils.Tables; +with Alire.Utils.TTY; with Alr.Commands.Build; with Alr.Commands.Clean; @@ -87,6 +89,9 @@ package body Alr.Commands is Prefer_Oldest : aliased Boolean := False; -- Catches the --prefer-oldest policy switch + No_Color : aliased Boolean := False; + -- Force-disable color output + No_TTY : aliased Boolean := False; -- Used to disable control characters in output @@ -181,6 +186,11 @@ package body Alr.Commands is "-n", "--non-interactive", "Assume default answers for all user prompts"); + Define_Switch (Config, + No_Color'Access, + Long_Switch => "--no-color", + Help => "Disables colors in output"); + Define_Switch (Config, No_TTY'Access, Long_Switch => "--no-tty", @@ -584,6 +594,20 @@ package body Alr.Commands is -- At this point the command and all unknown switches are in -- Raw_Arguments. + if No_TTY then + Simple_Logging.Is_TTY := False; + end if; + + if Platform.Operating_System in Alire.Platforms.Windows or else + No_Color or else + No_TTY + then + Alire.Utils.TTY.Disable_Color; + else + Alire.Utils.TTY.Enable_Color (Force => False); + -- This may still not enable color if TTY is detected to be incapable + end if; + if Raw_Arguments.Is_Empty then Trace.Error ("No command given"); Display_Usage; @@ -628,10 +652,6 @@ package body Alr.Commands is Alire.Config.Set_Path (Command_Line_Config_Path.all); end if; - if No_TTY then - Simple_Logging.Is_TTY := False; - end if; - exception when Exit_From_Command_Line | Invalid_Switch | Invalid_Parameter => -- Getopt has already displayed some help -- 2.39.5