1#!/usr/bin/env bash
2#
3# This code is released in public domain by Dave Davenport <qball@gmpclient.org>
4#
5
6
7ROFI=$(which rofi)
8SED=$(which sed)
9MKTEMP=$(which mktemp)
10
11if [ -z "${SED}" ]
12then
13    echo "Did not find 'sed', script cannot continue."
14    exit 1
15fi
16if [ -z "${MKTEMP}" ]
17then
18    echo "Did not find 'mktemp', script cannot continue."
19    exit 1
20fi
21if [ -z "${ROFI}" ]
22then
23    echo "Did not find rofi, there is no point to continue."
24    exit 1
25fi
26
27TMP_CONFIG_FILE=$(${MKTEMP}).rasi
28
29##
30# Array with parts to the found themes.
31# And array with the printable name.
32##
33declare -a themes
34declare -a theme_names
35
36##
37# Function that tries to find all installed rofi themes.
38# This fills in #themes array and formats a displayable string #theme_names
39##
40function find_themes()
41{
42    DIRS=${XDG_DATA_DIRS}
43    OLDIFS=${IFS}
44    IFS=:
45    if [ -z "${XDG_DATA_DIRS}" ]
46    then
47        echo "XDG_DATA_DIRS needs to be set for this script to function correctly."
48        echo -n "Using dirs from \$PATH: "
49        DIRS=
50        # Iterate over items in $PATH
51        for p in ${PATH}; do
52            # Remove trailing / if exists.
53            x=${p%/}
54            # remove both /bin and /sbin and /games from end
55            x=${x%/bin}
56            x=${x%/sbin}
57            x=${x%/games}
58            # Add /share
59            x=${x}/share
60            # Check if entry exists Prepend : so :${x}: matches nicely
61            case ":${DIRS}" in
62                *$x:*);;
63                *) DIRS+="$x:";;
64            esac
65        done
66        # Remove trailing :
67        DIRS=${DIRS%:}
68        echo "${DIRS}"
69    fi
70    # Add user dir.
71    DIRS+=":${XDG_DATA_HOME:-${HOME}/.local/share}"
72    DIRS+=":${XDG_CONFIG_HOME:-${HOME}/.config}"
73    for p in ${DIRS}; do
74    	p=${p%/}
75        TD=${p}/rofi/themes
76        if [ -n "${p}" ] && [ -d "${TD}" ]
77        then
78            echo "Checking themes in: ${TD}"
79            for file in ${TD}/*.rasi
80            do
81                if [ -f "${file}" ]
82                then
83                    themes+=(${file})
84                    FN=$(basename ${file})
85                    NAME=${FN%.*}
86                    USER=$(${SED} -n 's/^.*User: \(.*\)/\1/p' ${file} | head -n 1 )
87                    if [ -z "${USER}" ]
88                    then
89                        theme_names+=(${NAME})
90                    else
91                        theme_names+=("${NAME} by ${USER}")
92                    fi
93                fi
94           done
95        fi
96    done
97    IFS=${OLDIFS}
98
99}
100
101##
102# Create a copy of rofi
103##
104function create_config_copy()
105{
106    ${ROFI} -dump-config > ${TMP_CONFIG_FILE}
107    # remove theme entry.
108    sed -i 's/^\s*theme:\s\+".*"\s*;//g' ${TMP_CONFIG_FILE}
109}
110
111###
112# Print the list out so it can be displayed by rofi.
113##
114function create_theme_list()
115{
116    OLDIFS=${IFS}
117    IFS='|'
118    for themen in  ${theme_names[@]}
119    do
120        echo ${themen}
121    done
122    IFS=${OLDIFS}
123}
124
125##
126# Thee indicate what entry is selected.
127##
128declare -i SELECTED
129
130function select_theme ()
131{
132    local MORE_FLAGS=(-dmenu -format i -no-custom -p "Theme" -markup -config ${TMP_CONFIG_FILE} -i)
133    MORE_FLAGS+=(-kb-custom-1 "Alt-a")
134    MORE_FLAGS+=(-u 2,3 -a 4,5 )
135    local CUR="default"
136    while true
137    do
138        declare -i RTR
139        declare -i RES
140        local MESG="""You can preview themes by hitting <b>Enter</b>.
141<b>Alt-a</b> to accept the new theme.
142<b>Escape</b> to cancel
143Current theme: <b>${CUR}</b>"""
144        THEME_FLAG=
145        if [ -n "${SELECTED}" ]
146        then
147			THEME_FLAG="-theme ${themes[${SELECTED}]}"
148        fi
149		RES=$( create_theme_list | ${ROFI} ${THEME_FLAG} ${MORE_FLAGS[@]} -cycle -selected-row "${SELECTED}" -mesg "${MESG}")
150        RTR=$?
151        if [ ${RTR} = 10 ]
152        then
153            return 0;
154        elif [ ${RTR} = 1 ]
155        then
156            return 1;
157        elif [ ${RTR} = 65 ]
158        then
159            return 1;
160        fi
161        CUR=${theme_names[${RES}]}
162		SELECTED=${RES}
163    done
164}
165
166###
167# Create if not exists, then removes #include of .theme file (if present) and add the selected theme to the end.
168# Repeated calls should leave the config clean-ish
169###
170function set_theme()
171{
172    CDIR="${XDG_CONFIG_HOME:-${HOME}/.config}/rofi"
173    if [ ! -d "${CDIR}" ]
174    then
175        mkdir -p ${CDIR}
176    fi
177    if [ -f "${CDIR}/config.rasi" ]
178    then
179    	get_link=$(readlink -f "${CDIR}/config.rasi")
180        ${SED} -i "" "/@import.*/d" "${get_link}"
181        echo "@import \"${1}\"" >> "${get_link}"
182    else
183        if [ ! -e "${CDIR}/config" ]
184        then
185            # No file.
186            echo "rofi.theme: ${1}" >> "${CDIR}/config"
187        elif [ -f "${CDIR}/config" ]
188        then
189            # Regular file
190    		get_link=$(readlink -f "${CDIR}/config")
191            ${SED} -i "" "/rofi\.theme: .*\.rasi$/d" "${get_link}"
192            echo "rofi.theme: ${1}" >> "${get_link}"
193        fi
194	fi
195}
196
197############################################################################################################
198# Actual program execution
199###########################################################################################################
200##
201# Find all themes
202##
203find_themes
204
205##
206# Do check if there are themes.
207##
208if [ ${#themes[@]} = 0 ]
209then
210    ${ROFI} -e "No themes found."
211    exit 0
212fi
213
214##
215# Create copy of config to play with in preview
216##
217create_config_copy
218
219##
220# Show the themes to user.
221##
222if select_theme && [ -n "${SELECTED}" ]
223then
224    # Set theme
225    set_theme "${themes[${SELECTED}]}"
226fi
227
228##
229# Remove temp. config.
230##
231rm ${TMP_CONFIG_FILE}
232