#! /bin/bash # _ # ___ ___ _ __ | | ___ _ __ _ ___ _ __ # / __/ _ \| '_ \| |/ / | | |/ _` |/ _ \ '_ \ # | (_| (_) | | | | <| |_| | (_| | __/ | | | # \___\___/|_| |_|_|\_\\__, |\__, |\___|_| |_| # |___/ |___/ # # conkygen.sh # Create a Conky configuration file dynamically # # Copyright (c) 2020 Vintage Salt # Distributed under the terms of the MIT License # set -e # Read-only set-once variables declare -r _name="$(basename -- "$0")" # Options declare _optout="${XDG_CONFIG_HOME:-$HOME/.config}/conky/conky.conf" declare -i _optbar=1 declare -i _optgraph=1 declare -i _opthelp declare -i _optverbose declare -i _opttopitems=4 # Working variables declare -a _args declare _return # Helper functions log() { # Print a line to the terminal if _optverbose is greater than $2 # $2 defaults to 0 # loglevel 0: Daily-use messages # loglevel 1: Detailed but not quite debugging # loglevel 2: Definitely debugging [ -z "$1" ] && return 1 if (( _optverbose >= ${2:-0} )); then printf "%s\\n" "$1" fi } warn() { # Print a yellow line to the terminal, respecting _optverbose [ -z "$1" ] && return 1 if (( _optverbose >= ${2:-0} )); then if [ -t 1 ]; then printf "\\e[33m%s\\e[0m\\n" "$1" else printf "WARN: %s\\n" "$1" fi fi } error() { # Print a red line to the terminal, exit if $2 is specified [ -z "$1" ] && return 1 if [ -t 2 ]; then printf "\\e[31m%s\\e[0m\\n" "$1" 1>&2 else printf "ERROR: %s\\n" "$1" 1>&2 fi [ -z "$2" ] && return exit "${2:-1}" } has() { # Parse out all arguments and try to find them in path # If an argument cannot be found, set _return and fail for prog in "$@"; do if ! command -v "$prog" > /dev/null 2>&1; then _return="$prog" return 1 fi done return 0 } # Core program functions printhelp() { cat << EOF Usage: $_name [OPTION]... Generate a conky.conf configuration file in the current directory -o Specify output file. Defaults to ~/.config/conky/conky.conf -b Hide bars -g Hide graphs -h Print this help text -t Number of items to print in top lists. Defaults to 4 -v Print more status messages. Stacks Copyright (c) 2020 rehashedsalt@cock.li Licensed under the MIT license EOF } step_header() { # Clobber output file with header cat << EOF > "$_optout" -- vim: ts=4 sw=4 noet ai cindent syntax=lua -- WARNING: -- This file was generated with conkygen. See gen.sh if you need to edit this! -- Any changes you make here can and probably will be clobbered! EOF } step_config() { # Append config to the output file cat << EOF >> "$_optout" conky.config = { own_window = true, own_window_title = 'Conky', own_window_class = 'Conky', own_window_type = 'desktop', own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager', own_window_argb_visual = true, own_window_transparent = true, own_window_colour = '000000', double_buffer = true, cpu_avg_samples = 2, net_avg_samples = 2, no_buffers = true, update_interval = 1, use_xft = true, font = 'IBM Plex Sans:style=Light:size=9', default_color = '#ebdbb2', color1 = '282828', -- Background color2 = 'ebdbb2', -- Foreground color3 = '32302f', -- Background-alt color4 = 'b8bb26', -- Green (Battery) color6 = '8ec07c', -- Cyan (Network) color7 = 'fabd2f', -- Yellow (Disk) color8 = '83a598', -- Blue (CPU) color9 = 'de869b', -- Magenta (Memory) alignment = 'top_left', xinerama_head = 0, minimum_height = 0, minimum_width = 304, border_width = 0, border_outer_margin = 0, border_inner_margin = 16, gap_x = 22, gap_y = 66, format_human_readable = true, temperature_unit = "celsius", if_up_strictness = "link", default_bar_height = 11, default_bar_width = 130, default_graph_height = 36, draw_borders = true, draw_outline = false, draw_graph_borders = true, draw_shades = false } EOF } step_text() { local -r nproc="$(nproc)" # Generate our actual functional Conky stuff # Header cat <<- 'EOF' >> "$_optout" conky.text = [[ ${font IBM Plex Sans:style=Light:size=64}$alignr${time %l:%M %p}$font ${font IBM Plex Sans:style=Light:size=18}$alignr${time %A, %B %d, %Y}$font ${font IBM Plex Sans:style=Light:size=12}${acpitemp}°C$alignr${no_update $nodename_short}$font EOF # CPU info cat <<- 'EOF' >> "$_optout" ${color3}$hr$color ${font IBM Plex Sans:style=Medium:size=9}CPU$font: $freq_g GHz$alignr$cpu% EOF if (( _optgraph > 0 )); then local gpl=1 if (( nproc <= 2 )); then gpl=1 elif (( nproc <= 4 )); then gpl=2 elif (( nproc <= 8 )); then gpl=4 else gpl=8 fi local width=$(( ( 400 - ( gpl - 1 ) * 3 ) / gpl )) log "Generating $gpl graphs per row of CPU core stats" 1 log "Graphs will be $width wide" 2 local cpuinfo for i in $(seq 1 "$gpl" "$nproc"); do # Generate lines local line for j in $(seq 0 $(( gpl - 1 ))); do # Generate graphs local cpu=$(( i + j )) log "Generating graph for CPU $cpu" 2 if [ -z "$line" ]; then line="\${cpugraph cpu$cpu 36,$width}" else line="$line \${cpugraph cpu$cpu 36,$width}" fi done # Trim whitespace line="\${color8}${line%" "}\$color" log "Appending line: $line" 2 cpuinfo="$cpuinfo$line\n" unset line done while [ "$cpuinfo" != "${cpuinfo%\\n}" ]; do cpuinfo="${cpuinfo%\\n}" done echo -e "$cpuinfo" >> "$_optout" fi for i in $(seq $_opttopitems); do echo "\${color8}\${top name $i}\$color\$alignr\${top cpu $i}%" >> "$_optout" done # Memory info cat <<- 'EOF' >> "$_optout" ${color3}$hr$color ${font IBM Plex Sans:style=Medium:size=9}Memory$font: $mem / $memmax used$alignr$memperc% EOF if (( _optgraph > 0 )); then echo -e '${color9}${memgraph}$color' >> "$_optout" fi if (( _optbar > 0 )); then echo -e 'Memory$alignr$memeasyfree ${color9}${membar}$color' >> "$_optout" if [ -n "$(swapon)" ]; then echo "Swap\$alignr\$swapfree \${color9}\${swapbar}\$color" >> "$_optout" fi fi for i in $(seq $_opttopitems); do echo "\${color9}\${top_mem name $i}\$color\$alignr\${top_mem mem $i}%" >> "$_optout" done # Disk info cat <<- 'EOF' >> "$_optout" ${color3}$hr$color ${font IBM Plex Sans:style=Medium:size=9}Disk$font (R/W):$alignr${diskio /dev/sda} EOF if (( _optgraph > 0 )); then echo '${color7}${diskiograph_read /dev/sda 36,200} ${diskiograph_write /dev/sda 36,200}$color' >> "$_optout" fi # Mountpoint detection if (( _optbar > 0 )); then for mountpoint in / /home /var /usr /opt /boot /boot/efi; do if mountpoint $mountpoint > /dev/null 2>&1; then echo "$mountpoint\$alignr\${fs_free $mountpoint} \${color7}\${fs_bar $mountpoint}\$color" >> "$_optout" fi done fi for i in $(seq $_opttopitems); do echo "\${color7}\${top_io name $i}\$color\$alignr\${top_io io_perc $i}%" >> "$_optout" done # Networking cat <<-'EOF' >>"$_optout" ${color3}$hr$color ${font IBM Plex Sans:style=Medium:size=9}Network$font:${alignr}Default $gw_iface${if_up wlp1s0} EOF for interface in $(iw dev | awk '$1=="Interface"{print $2}'); do echo "$interface (U/D): \$alignr\${addr $interface} / \${wireless_essid $interface}" >> "$_optout" if (( _optgraph > 0 )); then echo "\${color6}\${upspeedgraph $interface 36,200} \${downspeedgraph $interface 36,200}\$color" >> "$_optout" fi done echo "]]" >> "$_optout" } genconfig() { log "Generating config: $_optout" step_header step_config step_text } # Main main() { # Parse out arguments while [ -n "$1" ]; do # Parse out flags while getopts ":bgho:t:v" opt; do case $opt in b) _optbar=0 ;; g) _optgraph=0 ;; o) _optout="$OPTARG" ;; h) _opthelp=1 ;; t) _opttopitems="$OPTARG" ;; v) _optverbose+=1 ;; :) error "Option requires argument: -$OPTARG" 2 ;; *) error "Invalid option: -$OPTARG" 2 ;; esac done # Store arguments shift $((OPTIND - 1)) if [ -n "$1" ]; then _args+=("$1") shift fi unset OPTIND done # Early hook for help [ -n "$_opthelp" ] && printhelp && exit 0 # Validate critical options if ! (( _opttopitems >= 0 )); then error "Option -t requires non-negative integer as argument" 2 fi # Validate core program dependencies log "Validating dependencies" 2 if ! has awk basename iw seq; then error "Failed to find program: $_return" 1 fi # Do the do genconfig exit 0 } main "$@"