<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Lua on Tarragon</title><link>https://tarrragon.github.io/blog/tags/lua/</link><description>Recent content in Lua on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Mon, 29 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/lua/index.xml" rel="self" type="application/rss+xml"/><item><title>Lua 腳本語言</title><link>https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/lua-scripting-language/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/lua-scripting-language/</guid><description>&lt;p>Lua 是一個輕量級腳本語言，1993 年在巴西開發，名字是葡萄牙語的「月亮」。整個直譯器約 300KB，設計目標是&lt;strong>嵌入到其他程式當配置和擴展語言&lt;/strong>，不是當獨立的通用語言。&lt;/p>
&lt;p>Hyprland（v0.55+ 的配置格式）、Neovim（整個 plugin 和配置生態）、WezTerm（terminal emulator 配置）都用 Lua 作為配置語言。在 dotfile 管理的脈絡裡，Lua 是讀懂和寫好這些工具配置的前提知識。&lt;/p>
&lt;h2 id="配置檔用到的核心語法">配置檔用到的核心語法&lt;/h2>
&lt;h3 id="變數和型別">變數和型別&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;hello&amp;#34;&lt;/span> &lt;span class="c1">-- 字串&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">42&lt;/span> &lt;span class="c1">-- 數字&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">enabled&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span> &lt;span class="c1">-- 布林&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">nothing&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="c1">-- 空值（類似其他語言的 null）&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>local&lt;/code> 宣告區域變數。沒有 &lt;code>local&lt;/code> 的變數是全域的，配置檔裡幾乎都該用 &lt;code>local&lt;/code>。&lt;/p>
&lt;h3 id="table唯一的複合資料結構">Table：唯一的複合資料結構&lt;/h3>
&lt;p>Lua 只有一種複合型別——table，同時當 array 和 dictionary 用：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">-- 當 array（index 從 1 開始，不是 0）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">fruits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="s2">&amp;#34;apple&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;banana&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;cherry&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="n">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fruits&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="c1">-- &amp;#34;apple&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="c1">-- 當 dictionary&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> &lt;span class="n">gaps_in&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> &lt;span class="n">border_size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> &lt;span class="n">layout&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;dwindle&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="n">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">config.gaps_in&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">-- 5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="c1">-- 巢狀 table（配置檔最常見的形式）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">decoration&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl"> &lt;span class="n">rounding&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> &lt;span class="n">blur&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl"> &lt;span class="n">enabled&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl"> &lt;span class="n">size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">19&lt;/span>&lt;span class="cl"> &lt;span class="n">passes&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">20&lt;/span>&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">21&lt;/span>&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Hyprland 的 &lt;code>hl.config()&lt;/code> 接收的就是一個巢狀 table：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="n">hl.config&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl"> &lt;span class="n">general&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl"> &lt;span class="n">gaps_in&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl"> &lt;span class="n">gaps_out&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl"> &lt;span class="n">decoration&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl"> &lt;span class="n">rounding&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">9&lt;/span>&lt;span class="cl">&lt;span class="p">})&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="function">Function&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="kr">function&lt;/span> &lt;span class="nf">greet&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">who&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl"> &lt;span class="kr">return&lt;/span> &lt;span class="s2">&amp;#34;hello &amp;#34;&lt;/span> &lt;span class="o">..&lt;/span> &lt;span class="n">who&lt;/span> &lt;span class="c1">-- .. 是字串串接&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="kr">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="c1">-- 匿名 function（Neovim 配置常見）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="n">vim.keymap&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;n&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;leader&amp;gt;f&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kr">function&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl"> &lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;telescope.builtin&amp;#34;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">find_files&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">&lt;span class="kr">end&lt;/span>&lt;span class="p">)&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="條件判斷">條件判斷&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="kr">if&lt;/span> &lt;span class="n">hostname&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;work-laptop&amp;#34;&lt;/span> &lt;span class="kr">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- 工作機設定&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="kr">elseif&lt;/span> &lt;span class="n">hostname&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;home-desktop&amp;#34;&lt;/span> &lt;span class="kr">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- 家裡桌機設定&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="kr">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl"> &lt;span class="c1">-- 預設&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="kr">end&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>只有 &lt;code>nil&lt;/code> 和 &lt;code>false&lt;/code> 是 falsy。&lt;code>0&lt;/code> 和 &lt;code>&amp;quot;&amp;quot;&lt;/code> 是 truthy（跟 Python 不同）。&lt;/p>
&lt;h3 id="迴圈">迴圈&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">-- 數字 for（Hyprland 批次產生 workspace keybind）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="kr">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">9&lt;/span> &lt;span class="kr">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl"> &lt;span class="n">hl.bind&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;SUPER&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tostring&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s2">&amp;#34;workspace&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tostring&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="kr">end&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c1">-- 遍歷 table&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="kd">local&lt;/span> &lt;span class="n">tools&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="s2">&amp;#34;zsh&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;git&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;nvim&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;tmux&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="kr">for&lt;/span> &lt;span class="n">_&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tool&lt;/span> &lt;span class="kr">in&lt;/span> &lt;span class="n">ipairs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tools&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kr">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> &lt;span class="n">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tool&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="kr">end&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="模組化require">模組化（require）&lt;/h3>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-lua" data-lang="lua">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1">-- hyprland.lua 裡載入同目錄的其他 .lua 檔&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;keybinds&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">-- 載入 keybinds.lua&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;rules&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">-- 載入 rules.lua&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="n">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;appearance&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">-- 載入 appearance.lua&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>require()&lt;/code> 是 Lua 原生的模組載入，取代了舊 Hyprland &lt;code>.conf&lt;/code> 格式的 &lt;code>source = ...&lt;/code> 指令。&lt;/p>
&lt;h2 id="為什麼配置工具選-lua">為什麼配置工具選 Lua&lt;/h2>
&lt;p>Lua 被嵌入到配置層的原因是一組特定的 trade-off：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>比 JSON/TOML/YAML 強&lt;/strong>：有變數、迴圈、條件判斷。配置檔可以用 &lt;code>for&lt;/code> 產生重複項目、用 &lt;code>if&lt;/code> 處理機器差異，不需要外部 template engine&lt;/li>
&lt;li>&lt;strong>比 Python/JavaScript 輕&lt;/strong>：300KB 的直譯器可以嵌入 C/C++ 程式，不需要拖一個完整的 runtime&lt;/li>
&lt;li>&lt;strong>沙盒化容易&lt;/strong>：宿主程式可以控制 Lua 能存取哪些 API，限制配置檔的能力範圍&lt;/li>
&lt;/ul>
&lt;p>這也是 Neovim 從 VimScript 遷移到 Lua 的理由——plugin 生態需要一個真正的程式語言（有資料結構、有錯誤處理），但又不能讓配置檔變成一個安全隱患。&lt;/p></description><content:encoded><![CDATA[<p>Lua 是一個輕量級腳本語言，1993 年在巴西開發，名字是葡萄牙語的「月亮」。整個直譯器約 300KB，設計目標是<strong>嵌入到其他程式當配置和擴展語言</strong>，不是當獨立的通用語言。</p>
<p>Hyprland（v0.55+ 的配置格式）、Neovim（整個 plugin 和配置生態）、WezTerm（terminal emulator 配置）都用 Lua 作為配置語言。在 dotfile 管理的脈絡裡，Lua 是讀懂和寫好這些工具配置的前提知識。</p>
<h2 id="配置檔用到的核心語法">配置檔用到的核心語法</h2>
<h3 id="變數和型別">變數和型別</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="kd">local</span> <span class="n">name</span> <span class="o">=</span> <span class="s2">&#34;hello&#34;</span>       <span class="c1">-- 字串</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="kd">local</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">42</span>            <span class="c1">-- 數字</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kd">local</span> <span class="n">enabled</span> <span class="o">=</span> <span class="kc">true</span>        <span class="c1">-- 布林</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="kd">local</span> <span class="n">nothing</span> <span class="o">=</span> <span class="kc">nil</span>         <span class="c1">-- 空值（類似其他語言的 null）</span></span></span></code></pre></div><p><code>local</code> 宣告區域變數。沒有 <code>local</code> 的變數是全域的，配置檔裡幾乎都該用 <code>local</code>。</p>
<h3 id="table唯一的複合資料結構">Table：唯一的複合資料結構</h3>
<p>Lua 只有一種複合型別——table，同時當 array 和 dictionary 用：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- 當 array（index 從 1 開始，不是 0）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kd">local</span> <span class="n">fruits</span> <span class="o">=</span> <span class="p">{</span> <span class="s2">&#34;apple&#34;</span><span class="p">,</span> <span class="s2">&#34;banana&#34;</span><span class="p">,</span> <span class="s2">&#34;cherry&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="n">print</span><span class="p">(</span><span class="n">fruits</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>  <span class="c1">-- &#34;apple&#34;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1">-- 當 dictionary</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="kd">local</span> <span class="n">config</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">gaps_in</span> <span class="o">=</span> <span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="n">border_size</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">layout</span> <span class="o">=</span> <span class="s2">&#34;dwindle&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="n">print</span><span class="p">(</span><span class="n">config.gaps_in</span><span class="p">)</span>  <span class="c1">-- 5</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1">-- 巢狀 table（配置檔最常見的形式）</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="kd">local</span> <span class="n">decoration</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="n">rounding</span> <span class="o">=</span> <span class="mi">8</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="n">blur</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">        <span class="n">enabled</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">        <span class="n">size</span> <span class="o">=</span> <span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">        <span class="n">passes</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>Hyprland 的 <code>hl.config()</code> 接收的就是一個巢狀 table：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="n">general</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">        <span class="n">gaps_in</span> <span class="o">=</span> <span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">        <span class="n">gaps_out</span> <span class="o">=</span> <span class="mi">10</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="n">decoration</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">        <span class="n">rounding</span> <span class="o">=</span> <span class="mi">8</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><h3 id="function">Function</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="kd">local</span> <span class="kr">function</span> <span class="nf">greet</span><span class="p">(</span><span class="n">who</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="kr">return</span> <span class="s2">&#34;hello &#34;</span> <span class="o">..</span> <span class="n">who</span>   <span class="c1">-- .. 是字串串接</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kr">end</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1">-- 匿名 function（Neovim 配置常見）</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="n">vim.keymap</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&#34;n&#34;</span><span class="p">,</span> <span class="s2">&#34;&lt;leader&gt;f&#34;</span><span class="p">,</span> <span class="kr">function</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">    <span class="n">require</span><span class="p">(</span><span class="s2">&#34;telescope.builtin&#34;</span><span class="p">).</span><span class="n">find_files</span><span class="p">()</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="kr">end</span><span class="p">)</span></span></span></code></pre></div><h3 id="條件判斷">條件判斷</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="kr">if</span> <span class="n">hostname</span> <span class="o">==</span> <span class="s2">&#34;work-laptop&#34;</span> <span class="kr">then</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="c1">-- 工作機設定</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kr">elseif</span> <span class="n">hostname</span> <span class="o">==</span> <span class="s2">&#34;home-desktop&#34;</span> <span class="kr">then</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="c1">-- 家裡桌機設定</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="kr">else</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="c1">-- 預設</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="kr">end</span></span></span></code></pre></div><p>只有 <code>nil</code> 和 <code>false</code> 是 falsy。<code>0</code> 和 <code>&quot;&quot;</code> 是 truthy（跟 Python 不同）。</p>
<h3 id="迴圈">迴圈</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- 數字 for（Hyprland 批次產生 workspace keybind）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="kr">for</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">9</span> <span class="kr">do</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="n">hl.bind</span><span class="p">(</span><span class="s2">&#34;SUPER&#34;</span><span class="p">,</span> <span class="n">tostring</span><span class="p">(</span><span class="n">i</span><span class="p">),</span> <span class="s2">&#34;workspace&#34;</span><span class="p">,</span> <span class="n">tostring</span><span class="p">(</span><span class="n">i</span><span class="p">))</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="kr">end</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1">-- 遍歷 table</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="kd">local</span> <span class="n">tools</span> <span class="o">=</span> <span class="p">{</span> <span class="s2">&#34;zsh&#34;</span><span class="p">,</span> <span class="s2">&#34;git&#34;</span><span class="p">,</span> <span class="s2">&#34;nvim&#34;</span><span class="p">,</span> <span class="s2">&#34;tmux&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="kr">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">tool</span> <span class="kr">in</span> <span class="n">ipairs</span><span class="p">(</span><span class="n">tools</span><span class="p">)</span> <span class="kr">do</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="n">print</span><span class="p">(</span><span class="n">tool</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="kr">end</span></span></span></code></pre></div><h3 id="模組化require">模組化（require）</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">-- hyprland.lua 裡載入同目錄的其他 .lua 檔</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">require</span><span class="p">(</span><span class="s2">&#34;keybinds&#34;</span><span class="p">)</span>     <span class="c1">-- 載入 keybinds.lua</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">require</span><span class="p">(</span><span class="s2">&#34;rules&#34;</span><span class="p">)</span>        <span class="c1">-- 載入 rules.lua</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">require</span><span class="p">(</span><span class="s2">&#34;appearance&#34;</span><span class="p">)</span>   <span class="c1">-- 載入 appearance.lua</span></span></span></code></pre></div><p><code>require()</code> 是 Lua 原生的模組載入，取代了舊 Hyprland <code>.conf</code> 格式的 <code>source = ...</code> 指令。</p>
<h2 id="為什麼配置工具選-lua">為什麼配置工具選 Lua</h2>
<p>Lua 被嵌入到配置層的原因是一組特定的 trade-off：</p>
<ul>
<li><strong>比 JSON/TOML/YAML 強</strong>：有變數、迴圈、條件判斷。配置檔可以用 <code>for</code> 產生重複項目、用 <code>if</code> 處理機器差異，不需要外部 template engine</li>
<li><strong>比 Python/JavaScript 輕</strong>：300KB 的直譯器可以嵌入 C/C++ 程式，不需要拖一個完整的 runtime</li>
<li><strong>沙盒化容易</strong>：宿主程式可以控制 Lua 能存取哪些 API，限制配置檔的能力範圍</li>
</ul>
<p>這也是 Neovim 從 VimScript 遷移到 Lua 的理由——plugin 生態需要一個真正的程式語言（有資料結構、有錯誤處理），但又不能讓配置檔變成一個安全隱患。</p>
<h2 id="其他使用-lua-的場景">其他使用 Lua 的場景</h2>
<table>
  <thead>
      <tr>
          <th>場景</th>
          <th>用法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Neovim</td>
          <td>整個配置和 plugin 生態基於 Lua</td>
      </tr>
      <tr>
          <td>WezTerm</td>
          <td>terminal emulator 配置（<code>wezterm.lua</code>）</td>
      </tr>
      <tr>
          <td>Awesome WM</td>
          <td>X11 tiling WM 的配置和擴展</td>
      </tr>
      <tr>
          <td>Redis</td>
          <td><code>EVAL</code> 指令在 server 端執行 Lua script</td>
      </tr>
      <tr>
          <td>Nginx/OpenResty</td>
          <td>用 Lua 寫高效能的 request 處理邏輯</td>
      </tr>
      <tr>
          <td>遊戲</td>
          <td>World of Warcraft UI mod、Roblox、很多遊戲引擎的腳本層</td>
      </tr>
  </tbody>
</table>
<p>共同模式：一個用 C/C++ 寫的高效能核心，把 Lua 嵌入進去當配置和擴展語言。</p>
<h2 id="跟-pythonjavascript-的差異速查">跟 Python/JavaScript 的差異速查</h2>
<table>
  <thead>
      <tr>
          <th>項目</th>
          <th>Lua</th>
          <th>Python</th>
          <th>JavaScript</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Array index 起始</td>
          <td><strong>1</strong></td>
          <td>0</td>
          <td>0</td>
      </tr>
      <tr>
          <td>字串串接</td>
          <td><code>..</code></td>
          <td><code>+</code></td>
          <td><code>+</code></td>
      </tr>
      <tr>
          <td>不等於</td>
          <td><code>~=</code></td>
          <td><code>!=</code></td>
          <td><code>!==</code></td>
      </tr>
      <tr>
          <td>邏輯運算</td>
          <td><code>and</code> <code>or</code> <code>not</code></td>
          <td><code>and</code> <code>or</code> <code>not</code></td>
          <td><code>&amp;&amp;</code> <code>||</code> <code>!</code></td>
      </tr>
      <tr>
          <td>空值</td>
          <td><code>nil</code></td>
          <td><code>None</code></td>
          <td><code>null</code>/<code>undefined</code></td>
      </tr>
      <tr>
          <td>Falsy 值</td>
          <td><code>nil</code>, <code>false</code></td>
          <td><code>None</code>, <code>False</code>, <code>0</code>, <code>&quot;&quot;</code>, <code>[]</code></td>
          <td><code>null</code>, <code>undefined</code>, <code>false</code>, <code>0</code>, <code>&quot;&quot;</code></td>
      </tr>
      <tr>
          <td>沒有 <code>+=</code></td>
          <td><code>x = x + 1</code></td>
          <td><code>x += 1</code></td>
          <td><code>x += 1</code></td>
      </tr>
      <tr>
          <td>註解</td>
          <td><code>--</code></td>
          <td><code>#</code></td>
          <td><code>//</code></td>
      </tr>
      <tr>
          <td>多行註解</td>
          <td><code>--[[ ... ]]</code></td>
          <td><code>&quot;&quot;&quot; ... &quot;&quot;&quot;</code></td>
          <td><code>/* ... */</code></td>
      </tr>
  </tbody>
</table>
<p>寫 Hyprland 或 Neovim 配置用到的 Lua 知識量很小——主要是 table（配置結構）、for loop（批次 keybind）、if-else（機器差異）、require（模組拆分）。不需要學 metatable、coroutine、metatmethod 這些進階功能。</p>
]]></content:encoded></item></channel></rss>