All GTK 3 CSS Nodes

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 是 informalexampleitemizedlist,則輸出此行。前者是畫出 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

發表留言