From ab187069b6776d65a2aac8896710587ea957143c Mon Sep 17 00:00:00 2001 From: Kate Date: Wed, 16 Oct 2024 12:39:03 +0100 Subject: [PATCH] Fix the detection of the current terminal size Tested on: * Linux/glibc * Linux/musl * macOS * FreeBSD * OpenBSD * NetBSD * Cygwin --- master_changes.md | 8 ++++++++ src/core/dune | 2 +- src/core/opamCommonStubs.c | 2 ++ src/core/opamStd.ml | 29 ++++++++++------------------- src/core/opamStubs.mli | 6 ++++++ src/core/opamStubs.unix.ml | 2 ++ src/core/opamUnix.c | 20 ++++++++++++++++++++ src/core/opamWin32Stubs.win32.ml | 4 ++++ 8 files changed, 53 insertions(+), 20 deletions(-) create mode 100644 src/core/opamUnix.c diff --git a/master_changes.md b/master_changes.md index cbc6f39abd5..d1c0aa9c44d 100644 --- a/master_changes.md +++ b/master_changes.md @@ -29,6 +29,10 @@ users) ## Remove +## UI + * [BUG] Fix the detection of the current terminal size [#6244 @kit-ty-kate - fix #6243] + * [BUG] Ensure the output of opam commands using a column style UI stay consistent accross environment by setting the number of columns to 80 if stdout is not a tty and if the `COLUMNS` env variable is not set [#6244 @kit-ty-kate] + ## Switch ## Config @@ -127,3 +131,7 @@ users) ## opam-format ## opam-core + * `OpamStd.Sys.{get_terminal_columns,uname,getconf,guess_shell_compat}`: Harden the process calls to account for failures [#6230 @kit-ty-kate - fix #6215] + * `OpamStd.Sys.{uname,getconf}`: now accepts only one argument as parameter, as per their documentation [#6230 @kit-ty-kate] + * `OpamStubs.get_stdout_ws_col`: new Unix-only function returning the number of columns of the current terminal window [#6244 @kit-ty-kate] + * `OpamSystem`: add `is_archive_from_string` that does the same than `is_archive` but without looking at the file, only analysing the string (extension) [#6219 @rjbou] diff --git a/src/core/dune b/src/core/dune index 4fa3e09cdc5..89beb7e47ea 100644 --- a/src/core/dune +++ b/src/core/dune @@ -19,7 +19,7 @@ (wrapped false)) (rule - (deps opamWindows.c opamInject.c) + (deps opamWindows.c opamInject.c opamUnix.c) (action (copy# opamCommonStubs.c opam_stubs.c))) (rule diff --git a/src/core/opamCommonStubs.c b/src/core/opamCommonStubs.c index 4687e5a69e6..55d0b0b8c1d 100644 --- a/src/core/opamCommonStubs.c +++ b/src/core/opamCommonStubs.c @@ -63,4 +63,6 @@ CAMLprim value opam_is_executable(value path) #ifdef _WIN32 #include "opamInject.c" #include "opamWindows.c" +#else +#include "opamUnix.c" #endif diff --git a/src/core/opamStd.ml b/src/core/opamStd.ml index 0452c306f62..828eccb56d5 100644 --- a/src/core/opamStd.ml +++ b/src/core/opamStd.ml @@ -936,25 +936,16 @@ module OpamSys = struct ) let get_terminal_columns () = - let fallback = 80 in - let cols = - match (* terminfo *) - Option.replace int_of_string_opt (process_in "tput" ["cols"]) - with - | Some x -> x - | None -> - try (* GNU stty *) - begin match - Option.map (fun x -> OpamString.split x ' ') - (process_in "stty" ["size"]) - with - | Some [_ ; v] -> int_of_string v - | _ -> failwith "stty" - end - with - | Failure _ -> fallback - in - if cols > 0 then cols else fallback + try int_of_string (Env.get "COLUMNS") with + | Not_found | Failure _ -> + let fallback = 80 in + let cols = + if tty_out then + OpamStubs.get_stdout_ws_col () + else + fallback + in + if cols > 0 then cols else fallback let win32_get_console_width default_columns = try diff --git a/src/core/opamStubs.mli b/src/core/opamStubs.mli index 726baf12226..53680b40b63 100644 --- a/src/core/opamStubs.mli +++ b/src/core/opamStubs.mli @@ -165,3 +165,9 @@ val getVersionInfo : string -> win32_version_info option val get_initial_environment : unit -> string list (** Windows only. Returns the environment which new processes would receive. *) + +val get_stdout_ws_col : unit -> int +(** Unix only. Returns the number of columns of the current terminal window + linked with stdout. If stdout isn't linked to any terminal + (e.g. redirection), then this function will return 0. A valid number + of columns should be strictly above 0. *) diff --git a/src/core/opamStubs.unix.ml b/src/core/opamStubs.unix.ml index a4aff833433..b1c957c2422 100644 --- a/src/core/opamStubs.unix.ml +++ b/src/core/opamStubs.unix.ml @@ -46,3 +46,5 @@ let getErrorMode = that's_a_no_no let setConsoleToUTF8 = that's_a_no_no let getVersionInfo = that's_a_no_no let get_initial_environment = that's_a_no_no + +external get_stdout_ws_col : unit -> int = "opam_stdout_ws_col" diff --git a/src/core/opamUnix.c b/src/core/opamUnix.c new file mode 100644 index 00000000000..8026609ca10 --- /dev/null +++ b/src/core/opamUnix.c @@ -0,0 +1,20 @@ +/**************************************************************************/ +/* */ +/* Copyright 2024 Kate Deplaix */ +/* */ +/* All rights reserved. This file is distributed under the terms of the */ +/* GNU Lesser General Public License version 2.1, with the special */ +/* exception on linking described in the file LICENSE. */ +/* */ +/**************************************************************************/ + +#include + +CAMLprim value opam_stdout_ws_col(value _unit) { + struct winsize win; + + if (-1 == ioctl(STDOUT_FILENO, TIOCGWINSZ, &win)) { + return Val_int(0); + } + return Val_int(win.ws_col); +} diff --git a/src/core/opamWin32Stubs.win32.ml b/src/core/opamWin32Stubs.win32.ml index c9286dee923..17425d855d2 100644 --- a/src/core/opamWin32Stubs.win32.ml +++ b/src/core/opamWin32Stubs.win32.ml @@ -47,3 +47,7 @@ external getErrorMode : unit -> int = "OPAMW_GetErrorMode" external setConsoleToUTF8 : unit -> unit = "OPAMW_SetConsoleToUTF8" external getVersionInfo : string -> 'a option = "OPAMW_GetVersionInfo" external get_initial_environment : unit -> string list = "OPAMW_CreateEnvironmentBlock" + +let that's_a_no_no _ = failwith "Unix only. This function isn't implemented." + +let get_stdout_ws_col = that's_a_no_no