aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-07-09 10:57:56 +0200
committerDanilo M. <danix@danix.xyz>2026-07-09 10:57:56 +0200
commit2c6e860df7e394fff4753796128fd50ce5c04ef3 (patch)
treea4b437d0e042ecdd8b20fe3bbd85db12199b737f
parent9d7531f5c430d540845a7558359b3baef58b06ce (diff)
downloadmkhintfile-2c6e860df7e394fff4753796128fd50ce5c04ef3.tar.gz
mkhintfile-2c6e860df7e394fff4753796128fd50ce5c04ef3.zip
feat: --info/-i shows category/program header + README
-rwxr-xr-xmkhint75
-rwxr-xr-xtests/mkhint_test.sh42
2 files changed, 115 insertions, 2 deletions
diff --git a/mkhint b/mkhint
index 8f964a8..bbbce55 100755
--- a/mkhint
+++ b/mkhint
@@ -796,6 +796,74 @@ EOF
fi
}
+# --info/-i: show a package's category/program path (green on a TTY) then its
+# README, paged only when it doesn't fit the terminal.
+show_info() {
+ local pkg="$1"
+ if [[ -z "$pkg" ]]; then
+ echo "Error: --info requires a package name" >&2
+ exit 1
+ fi
+
+ # Find the category dir(s): REPO_DIR/*/pkg/
+ local -a matches=()
+ local d
+ for d in "${REPO_DIR%/}"/*/"$pkg"/; do
+ [[ -d "$d" ]] && matches+=("$d")
+ done
+ if [[ ${#matches[@]} -eq 0 ]]; then
+ echo "Error: package not found in ${REPO_DIR%/}: $pkg" >&2
+ exit 2
+ fi
+ if [[ ${#matches[@]} -gt 1 ]]; then
+ echo "Error: multiple matches for $pkg in ${REPO_DIR%/}:" >&2
+ printf ' %s\n' "${matches[@]}" >&2
+ exit 2
+ fi
+
+ local dir="${matches[0]%/}"
+ local category; category=$(basename "$(dirname "$dir")")
+
+ # Green header on a TTY (same gate as --list).
+ local g_on="" g_off=""
+ if [[ -n "$MKHINT_FORCE_COLOR" || -t 1 ]]; then
+ if command -v tput &>/dev/null && tput setaf 2 &>/dev/null; then
+ g_on=$(tput setaf 2); g_off=$(tput sgr0)
+ else
+ g_on=$'\033[32m'; g_off=$'\033[0m'
+ fi
+ fi
+ local header="${g_on}${category}/${pkg}${g_off}"
+
+ local readme="${dir}/README"
+ if [[ ! -f "$readme" ]]; then
+ printf '%s\n' "$header"
+ echo "(no README)"
+ exit 0
+ fi
+
+ # Non-TTY, or README fits: print inline. Else page with header pinned.
+ local rows; rows="${LINES:-}"
+ [[ -z "$rows" ]] && command -v tput &>/dev/null && rows=$(tput lines 2>/dev/null)
+ [[ -z "$rows" ]] && rows=24
+ local lines; lines=$(wc -l < "$readme")
+
+ if [[ ! -t 1 || "$lines" -le "$rows" ]]; then
+ printf '%s\n' "$header"
+ cat "$readme"
+ exit 0
+ fi
+
+ # Page: header as line 1 so it survives; pin it if pager is less.
+ local pager="${PAGER:-less}"
+ if [[ "$(basename "$pager")" == "less" ]]; then
+ { printf '%s\n' "$header"; cat "$readme"; } | less -R --header=1
+ else
+ { printf '%s\n' "$header"; cat "$readme"; } | $pager
+ fi
+ exit 0
+}
+
# Emit the TOML section label for a package: bare if the name is a valid
# bare key ([A-Za-z0-9_] only), otherwise double-quoted. nvchecker (and TOML)
# require quoting for names containing '.', '-', etc.
@@ -1468,8 +1536,8 @@ check_updates() {
# Main function
main() {
local parsed
- parsed=$(getopt -o vV:f:n:lcCdNhRF \
- --long version,set-version:,hintfile:,new:,list,clean,check,delete,no-dl,help,review,fix-current,force \
+ parsed=$(getopt -o vV:f:n:i:lcCdNhRF \
+ --long version,set-version:,hintfile:,new:,info:,list,clean,check,delete,no-dl,help,review,fix-current,force \
-n 'mkhint' -- "$@") || { show_help; exit 1; }
eval set -- "$parsed"
@@ -1635,6 +1703,9 @@ main() {
fix-current)
fix_current
;;
+ info)
+ show_info "$INFO_PKG"
+ ;;
update)
check_wget
if [[ -z "$VERSION" ]]; then
diff --git a/tests/mkhint_test.sh b/tests/mkhint_test.sh
index 271e68e..2af6188 100755
--- a/tests/mkhint_test.sh
+++ b/tests/mkhint_test.sh
@@ -2108,6 +2108,48 @@ assert_not_contains "no alpha" "$ex_out" 'alpha'
assert_not_contains "no gamma" "$ex_out" 'gamma'
NVCHECKER_CONFIG="$MOCK_BASE/nvchecker.toml"
+# README fixture for --info tests (curl dir already exists in setup)
+cat > "$MOCK_REPO/network/curl/README" << 'EOF'
+curl is a tool to transfer data from or to a server.
+It supports many protocols.
+EOF
+
+# ── T-INFO1: --info existing pkg with README → header + README (non-TTY) ───────
+echo ""
+echo "T-INFO1: --info prints category/pkg header + README"
+run_mkhint -i curl > "$MOCK_BASE/info1.out" 2>&1
+assert_contains "info header path" "$MOCK_BASE/info1.out" 'network/curl'
+assert_contains "info README body" "$MOCK_BASE/info1.out" 'transfer data from or to a server'
+
+# ── T-INFO2: --info pkg without README → header + (no README) ──────────────────
+echo ""
+echo "T-INFO2: --info pkg with no README notes it"
+# clion dir exists, no README written
+run_mkhint -i clion > "$MOCK_BASE/info2.out" 2>&1
+info2_rc=$?
+assert_contains "info2 header" "$MOCK_BASE/info2.out" 'development/clion'
+assert_contains "info2 no README" "$MOCK_BASE/info2.out" 'no README'
+assert_exit_code "info2 exit 0" 0 "$info2_rc"
+
+# ── T-INFO3: --info missing pkg → exit 2 ──────────────────────────────────────
+echo ""
+echo "T-INFO3: --info missing pkg exits 2"
+set +e
+run_mkhint -i doesnotexist > "$MOCK_BASE/info3.out" 2>&1
+info3_rc=$?
+set -e
+assert_exit_code "info3 exit 2" 2 "$info3_rc"
+assert_contains "info3 error msg" "$MOCK_BASE/info3.out" 'not found'
+
+# ── T-INFO4: --info combined with -V → mutually exclusive, exit 1 ──────────────
+echo ""
+echo "T-INFO4: --info + -V mutually exclusive"
+set +e
+run_mkhint -i curl -V 9.9.9 > "$MOCK_BASE/info4.out" 2>&1
+info4_rc=$?
+set -e
+assert_exit_code "info4 exit 1" 1 "$info4_rc"
+
# ─── SUMMARY ──────────────────────────────────────────────────────────────────
teardown