Files @ 88ff60100e1b
Branch filter:

Location: majic-scripts/utils/cheatsheet_viewer.sh

branko
[cheatsheet_viewer.sh] Added command for displaying cheatsheets:

- Simplistic implementation that probably will not be as useful except
for testing things out.
#!/bin/bash
#
# cheatsheet_viewer.sh
#
# Copyright (C) 2025, Branko Majic <branko@majic.rs>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

# Treat unset variables as errors.
set -u

PROGRAM="cheatsheet_viewer.sh"
VERSION="0.0.1"

function usage() {
    cat <<EOF
$PROGRAM $VERSION, simple utility for viewing image cheatsheets

Usage:
  $PROGRAM [OPTIONS] list
  $PROGRAM [OPTIONS] info PROFILE
  $PROGRAM [OPTIONS] display [PROFILE]
EOF
}

function short_help() {
    cat <<EOF
$(usage)

For more details see $PROGRAM -h.
EOF
}

function long_help() {
    cat <<EOF
$(usage)

$PROGRAM is a simple utility for viewing image cheatsheets with
support for multiple profiles.

Cheatsheets are shown using the pqiv image viewer.

All configuration is stored under user's own home directory at:

  - ~/.config/cheatsheet_viewer/

Individual profiles are stored as sub-directories, with each
sub-directory representing an individual profile that can be
activated. Base directory for profiles is:

  - ~/.config/cheatsheet_viewer/profiles/

Each profile definition consists out of a number of configuration
files:

  - ~/.config/cheatsheet_viewer/profiles/PROFILE/cheatsheets (list of
    cheatsheet files, one per line, blank lines are ignored, lines
    starting with '#' are ignored)

Multiple commands are provided for working with the profiles and
displaying the cheatsheets.

list

  Lists the available profiles.

info PROFILE

  Arguments:

    PROFILE (profile name)

  Shows detailed information about user-specified profile, such as
  list of defined cheatsheets etc.

display [PROFILE]

  Arguments:

    PROFILE (profile name)

  Displays cheatsheets from the specified profile (default profile
  name is 'default').

$PROGRAM accepts the following options:

    -q
        Quiet mode.
    -d
        Enable debug mode.
    -v
        Show script version and licensing information.
    -h
        Show full help.

Please report bugs and send feature requests to <branko@majic.rs>.
EOF
}

function version() {
    cat <<EOF
$PROGRAM, version $VERSION

+-----------------------------------------------------------------------+
| Copyright (C) 2025, Branko Majic <branko@majic.rs>                    |
|                                                                       |
| This program is free software: you can redistribute it and/or modify  |
| it under the terms of the GNU General Public License as published by  |
| the Free Software Foundation, either version 3 of the License, or     |
| (at your option) any later version.                                   |
|                                                                       |
| This program is distributed in the hope that it will be useful,       |
| but WITHOUT ANY WARRANTY; without even the implied warranty of        |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
| GNU General Public License for more details.                          |
|                                                                       |
| You should have received a copy of the GNU General Public License     |
| along with this program.  If not, see <http://www.gnu.org/licenses/>. |
+-----------------------------------------------------------------------+

EOF
}


# Commands
# ========

#
# Lists available profiles.
#
# Arguments:
#
#   $1 (config_dir)
#     Base directory under which all configuration files are stored.
#
# Returns:
#   0 on success, 1 otherwise.
#
function command_list() {
    local config_dir="$1"
    local profiles_dir="$config_dir/profiles"

    shopt -s nullglob
    local profiles=("$profiles_dir"/*)
    shopt -u nullglob

    if (( ${#profiles[@]} == 0 )); then
        echo "No profiles defined under $profiles_dir"
        return 0
    fi

    echo "Available profiles:"
    echo
    for profile in "${profiles[@]}"; do
        echo "  - $(basename "$profile")"
    done
}


#
# Displays profile information.
#
# Arguments:
#
#   $1 (config_dir)
#     Base directory under which all configuration files are stored.
#
#   $2 (profile)
#     Profile name.
#
# Returns:
#   0 on success, 1 otherwise.
#
function command_info() {
    local config_dir="$1"
    local profile="$2"

    local profile_dir="$config_dir/profiles/$profile"
    local cheatsheets_file="$profile_dir/cheatsheets"

    local cheatsheets=()

    if [[ ! -d $profile_dir ]]; then
        error "No such profile found under $profile_dir"
        return 1
    fi

    if [[ -e $cheatsheets_file ]]; then
        readarray -t cheatsheets < <(grep --invert-match --extended-regexp "(^[[:blank:]]*#|^[[:blank:]]*$)" "$cheatsheets_file")
    fi

    echo "Profile $profile"
    echo "========${profile//?/=}"
    echo
    echo "Base directory:   $profile_dir"
    echo "Cheatsheets list: $cheatsheets_file"
    echo

    if (( ${#cheatsheets[@]} == 0 )); then
        echo "No configured cheatsheets."
    else
        echo "Configured cheatsheets:"
        echo
        for cheatsheet in "${cheatsheets[@]}"; do
            echo "  - $cheatsheet"
        done
    fi
}


#
# Displays configured cheatsheets from a profile.
#
# Arguments:
#
#   $1 (config_dir)
#     Base directory under which all configuration files are stored.
#
#   $2 (profile)
#     Profile name.
#
# Returns:
#   0 on success, 1 otherwise.
#
function command_display() {
    local config_dir="$1"
    local profile="$2"

    local profile_dir="$config_dir/profiles/$profile"
    local cheatsheets_file="$profile_dir/cheatsheets"

    local cheatsheets=()

    if [[ ! -d $profile_dir ]]; then
        error "No such profile found under $profile_dir"
        return 1
    fi

    if [[ -e $cheatsheets_file ]]; then
        readarray -t cheatsheets < <(grep --invert-match --extended-regexp "(^[[:blank:]]*#|^[[:blank:]]*$)" "$cheatsheets_file")
    fi

    if (( ${#cheatsheets[@]} == 0 )); then
        warning "No cheatsheets are defined under $cheatsheets_file"
        return 0
    fi

    local pqiv_options=(
        "--scale-mode-screen-fraction=1.0"
        "--zoom-level=1.0"
        "--transparent-background"
        "--hide-info-box"
        "--window-title=cheatsheet-viewer"
    )

    pqiv "${pqiv_options[@]}" "${cheatsheets[@]}" &
}


# Set-up colours for message printing if we're not piping and terminal is
# capable of outputting the colors.
_COLOR_TERMINAL=$(tput colors 2>&1)
if [[ -t 1 ]] && (( _COLOR_TERMINAL > 0 )); then
    _TEXT_BOLD=$(tput bold)
    _TEXT_WHITE=$(tput setaf 7)
    _TEXT_BLUE=$(tput setaf 6)
    _TEXT_GREEN=$(tput setaf 2)
    _TEXT_YELLOW=$(tput setaf 3)
    _TEXT_RED=$(tput setaf 1)
    _TEXT_RESET=$(tput sgr0)
else
    _TEXT_BOLD=""
    _TEXT_WHITE=""
    _TEXT_BLUE=""
    _TEXT_GREEN=""
    _TEXT_YELLOW=""
    _TEXT_RED=""
    _TEXT_RESET=""
fi

# Set-up functions for printing coloured messages.
function debug() {
    if [[ $DEBUG != 0 ]]; then
        echo "${_TEXT_BOLD}${_TEXT_BLUE}[DEBUG]${_TEXT_RESET}" "$@"
    fi
}

function info() {
    if [[ $QUIET == 0 ]]; then
        echo "${_TEXT_BOLD}${_TEXT_WHITE}[INFO] ${_TEXT_RESET}" "$@"
    fi
}

function success() {
    if [[ $QUIET == 0 ]]; then
        echo "${_TEXT_BOLD}${_TEXT_GREEN}[OK]   ${_TEXT_RESET}" "$@"
    fi
}

function warning() {
    echo "${_TEXT_BOLD}${_TEXT_YELLOW}[WARN] ${_TEXT_RESET}" "$@" >&2
}

function error() {
    echo "${_TEXT_BOLD}${_TEXT_RED}[ERROR]${_TEXT_RESET}" "$@" >&2
}

# Define error codes.
SUCCESS=0
ERROR_ARGUMENTS=1

# Disable debug and quiet modes by default.
DEBUG=0
QUIET=0

# Default paths, directories etc.
CONFIG_DIR="$HOME/.config/cheatsheet_viewer"

# If no arguments were given, just show usage help.
if [[ -z ${1-} ]]; then
    short_help
    exit "$SUCCESS"
fi

# Parse the arguments
while getopts "qdvh" opt; do
    case "$opt" in
        q) QUIET=1;;
        d) DEBUG=1;;
        v) version
           exit "$SUCCESS";;
        h) long_help
           exit "$SUCCESS";;
        *) short_help
           exit "$ERROR_ARGUMENTS";;
    esac
done
i=$OPTIND
shift $(( i-1 ))

# Quiet and debug are mutually exclusive.
if [[ $QUIET != 0 && $DEBUG != 0 ]]; then
    error "Quiet and debug options are mutually exclusive."
    exit "$ERROR_ARGUMENTS"
fi

COMMAND="${1-}"
shift

if [[ $COMMAND == list ]]; then

    command_list "$CONFIG_DIR"

elif [[ $COMMAND == info ]]; then

    PROFILE="${1-}"
    shift

    if [[ -z $PROFILE ]]; then
        error "Profile name must be specified."
        exit "$ERROR_ARGUMENTS"
    fi

    command_info "$CONFIG_DIR" "$PROFILE"

elif [[ $COMMAND == display ]]; then

    PROFILE="${1-default}"
    shift

    command_display "$CONFIG_DIR" "$PROFILE"

else

    error "Unsupported command: $COMMAND"
    exit "$ERROR_ARGUMENTS"

fi