All GTK 3 CSS Nodes
【摘要】提供一個能將所有 GTK 3 CSS nodes 收集成一個檔案的 BASH 指令,並詳細說明之。
【目錄】
【前言】
【指令解析】
A. 基本設定
B. 主要指令
C. 加入 html5 檔尾並結束程式
【後語】
【附錄】
【前言】
一、設定 GTK 3 的樣式時,一定會用到 CSS nodes 和 style properties。但這些資料分散在各個 widget 的說明中,不利查詢。如果集中到一個檔案裡,會比較方便。本文敘述收集 nodes 的方法,另一篇敘述收集 style properties 的方法。
二、本文約半年前曾在 Google 的 Blogger 發表過,近日再度檢視,更新後發表於此。
三、來源資料是官網的 “GTK 3 Reference Manual“,目前的版本是 3.24.13。下載的檔案應是 gtk3-html-3.24.13.tar.gz,以下假設解開在自家的 $HOME/Documents/gtk3-html-3.24.13/ 目錄中。
四、收集的方法是用常見的 BASH 和 Linux 指令,作業系統是 Debian GNU/Linux 10。
五、最後的【附錄】有完整的指令,可以複製到一個空白檔案中,假設檔名是 get_css_nodes.sh
,執行 bash get_css_nodes.sh
即可。
【指令解析】
仔細觀察參考手冊 widget 的說明,可以知道每個都是 .html 檔,而且語法結構相當規律。html 文件有固定的 tags (標籤),我們就利用這些特性,搜尋各個 html 文件中的某些特定標籤,將相關的內容輸出到一個檔案裡。以下依序說明每個指令。
A. 基本設定
⒈ 指定參考手冊所在的目錄
PathIn=$HOME/Documents/gtk3-html-3.24.13
⒉ 指定輸出檔的目錄和檔名
假設是自己的 Documents 目錄,檔名可以自訂。
PathOut=$HOME/Documents FileOut=GTK3-css_nodes.html
提醒:若已有此檔,會被覆寫。
⒊ 複製樣式檔
官方參考手冊中,每個 widget 的 html 檔都使用同一個 CSS 樣式檔。我們從這些 html 檔取出資料,也要用這個樣式檔,才能正確顯示結果。
cp ${PathIn}/style.css ${PathOut}
⒋ 新增或清空輸出檔
: > ${PathOut}/${FileOut}
⒌ 加入 html5 檔頭
因為輸出的檔案也是 html 格式,所以頭尾要有基本的 elements。
echo '<!DOCTYPE html>' >> ${PathOut}/${FileOut} echo '<html>' >> ${PathOut}/${FileOut} echo '<head>' >> ${PathOut}/${FileOut} echo ' <title>CSS Nodes</title>' >> ${PathOut}/${FileOut} echo ' <meta charset="UTF-8">' >> ${PathOut}/${FileOut} echo ' <link rel="stylesheet" href="style.css" type="text/css">' >> ${PathOut}/${FileOut} echo '</head>' >> ${PathOut}/${FileOut} echo '<body>' >> ${PathOut}/${FileOut}
B. 主要指令
⒈ 每個 widget 的 html 檔名都是以 Gtk
開頭,所以可以很容易地找出來。
for FileIn in $(ls ${PathIn}/Gtk*.html) do
⒉ 這些說明檔在敘述 nodes 時,都分在 “CSS nodes" 一節。所以逐行讀入時,就檢查是否有此內容。一開始還沒有時,先將標記設為 0。
Flag1=0
⒊ “CSS nodes" 用的是標題 <h3> 的標籤,而其後的內容是在 <div> 標籤中。這也要有個標記,才知道內容的開始與結束。
Flag2=0
⒋ 逐行讀入。
while read do
⒌ 檢查所需資料是否開始。
if [[ ${REPLY} =~ .*\>CSS\ nodes\<.* ]]
${REPLY}
就是剛讀入的那一行。但其他地方也可能有 “CSS nodes",所以連前後的角括號(<h3>CSS nodes</h3>)也包括在內。
⒍ 若是,表示所需內容開始。
then Flag1=1
⒎ 取出 Widget 名稱;先從全路徑中取出檔名,再去掉副檔名。
FileIn=`basename ${FileIn}` && WidgetName=${FileIn::(-5)}
因為不是每個 widget 都有 node,所以等確定有了以後,才記錄 Widget 名稱,而不是一開始就記錄。
⒏ 輸出 Widget 名稱並設為標題放大字體,以便區別各個 widget。
echo "<h3>${WidgetName}</h3>" >> ${PathOut}/${FileOut}
⒐ 去讀下一行。
continue fi
⒑ 以上的 if
是找到開頭處,以下收集內容,並看內容是否結束。
if [[ ${Flag1} -eq 1 ]] then
⒒ 若欲收集的資料已開始,會有多種狀況,一一處理。這些狀況全憑多次試驗而來。
第一種狀況:若開始一個 <div>,要加以標記。
if [[ ${REPLY} =~ .*\<div\ class=\"informalexample\" || ${REPLY} =~ .*\<div\ class=\"itemizedlist\" ]] then Flag2=1
⒓ 若其 class 是 informalexample
或 itemizedlist
,則輸出此行。前者是畫出 nodes 的階層關係圖,後者只出現在 GtkPlacesSidebar 中,其 nodes 是用列舉的。
echo "${REPLY}" >> ${PathOut}/${FileOut}
⒔ 去讀下一行。
continue fi
⒕ 第二種狀況:若一個 </div> 結束,表示是所需內容的最後一行,標記之並輸出此行。
if [[ ${Flag2} -eq 1 && ${REPLY} =~ .*\</div.* ]] then Flag2=0 echo "${REPLY}" >> ${PathOut}/${FileOut} continue fi
⒖ 第三種狀況:若前無 <div> ,而遇到 </div> 或下一節開始,表示所需資料結束,便不再讀取此檔。
if [[ ${Flag2} -eq 0 ]] && [[ ${REPLY} =~ .*\</div.* || ${REPLY} =~ .*\<div\ class=\"refsect.* ]] then break fi
⒗ 其他狀況表示正在所需內容中的某一行,所以單純輸出此行。
echo "${REPLY}" >> ${PathOut}/${FileOut} fi
done < ${FileIn}
這是讀入某一檔。
done
這是結束讀入所有 Gtk*.html。
C. 加入 html5 檔尾並結束程式
echo '</body>' >> ${PathOut}/${FileOut} echo '</html>' >> ${PathOut}/${FileOut} exit
【後語】
從上述的內容可知,指令決定於官方參考手冊的 html 語法。所以,可以預見的是當這些語法改變時,指令可能也要修正。
【附錄】
#!/usr/bin/bash PathIn=$HOME/Documents/gtk3-html-3.24.13 PathOut=$HOME/Documents FileOut=GTK3-css_nodes.html cp -f ${PathIn}/style.css ${PathOut} : > ${PathOut}/${FileOut} echo '<!DOCTYPE html>' >> ${PathOut}/${FileOut} echo '<html>' >> ${PathOut}/${FileOut} echo '<head>' >> ${PathOut}/${FileOut} echo ' <title>CSS Nodes</title>' >> ${PathOut}/${FileOut} echo ' <meta charset="UTF-8">' >> ${PathOut}/${FileOut} echo ' <link rel="stylesheet" href="style.css" type="text/css">' >> ${PathOut}/${FileOut} echo '</head>' >> ${PathOut}/${FileOut} echo '<body>' >> ${PathOut}/${FileOut} for FileIn in $(ls ${PathIn}/Gtk*.html) do Flag1=0 Flag2=0 while read do if [[ ${REPLY} =~ .*\>CSS\ nodes\<.* ]] then Flag1=1 FileIn=`basename ${FileIn}` && WidgetName=${FileIn::(-5)} echo "<h3>${WidgetName}</h3>" >> ${PathOut}/${FileOut} continue fi if [[ ${Flag1} -eq 1 ]] then if [[ ${REPLY} =~ .*\<div\ class=\"informalexample\" || ${REPLY} =~ .*\<div\ class=\"itemizedlist\" ]] then Flag2=1 echo "${REPLY}" >> ${PathOut}/${FileOut} continue fi if [[ ${Flag2} -eq 1 && ${REPLY} =~ .*\</div.* ]] then Flag2=0 echo "${REPLY}" >> ${PathOut}/${FileOut} continue fi if [[ ${Flag2} -eq 0 ]] && [[ ${REPLY} =~ .*\</div.* || ${REPLY} =~ .*\<div\ class=\"refsect.* ]] then break fi echo "${REPLY}" >> ${PathOut}/${FileOut} fi done < ${FileIn} done echo '</body>' >> ${PathOut}/${FileOut} echo '</html>' >> ${PathOut}/${FileOut} exit