前端也學一下 Lua 呀

語言: CN / TW / HK

為什麼要學 lua ?

  • neovim/nvchad/... 支持 lua 寫配置文件
  • WezTerm 也是用 lua 寫配置文件

用 lua 寫配置,其實更多的是傾向於嵌入式編程,寫配置用 json/toml/yaml/xml 等文件可能更加好一點

安裝

以 linux 為例,windows 和 macOS 差不多(也是使用 brew 安裝,更加方便)

sh curl -R -O http://www.lua.org/ftp/lua-5.4.4.tar.gz tar zxf lua-5.4.4.tar.gz cd lua-5.4.4 make all test sudo make install which lua # 檢查 lua 命令

repl 環境和文件運行

  • lua 的 repl 環境
  • 在文件編寫 .lua 文件,然後使用 lua 命令運

這裏使用第二種 lua 文件運行,瞭解 lua 的模塊化,從而能組成一個完整的程序

第一個 lua 程序

```shell touch index.lua nvim index.lua

print("hello world") ```

  • 增加 shebang 開頭註釋不需要 lua 運行

```

!/usr/local/bin/lua

print("hello world") ```

變量

  • 全局變量(注意:沒有聲明)
  • 本地變量(使用 local 聲明)
  • 函數聲明變量 (使用 function 聲明)
  • 表中域 t = {} t["k"] = "v"
  • 代碼塊中的變量 (代碼使用 縮頸和關鍵字包含,沒有 {} 包含)
  • 變量賦值
    • 使用 , 分割變量 x, y = y, x

lua 類型系統

沒有類型標註,使用 type 判斷類型

|類型|type|説明| |---|---|---| |nil|type(nil) -> nil|nil 表示空,相當於:false。 一個未定義的變量使用時是 nil| |string|type("hello world") -> string|字符串支持單雙引號| |boolean|type(false) -> boolean|false/true| |number|3.14 * 2 -> number|雙精度實浮點型| |function|type(print) -> function|Lua或C函數| |userdata|type(io.stdin) -> userdata|表示任意存儲在變量中的C數據結構| |thread|type(type) -> thread|表示執行的獨立線路,用於執行協同程序| |table|type({}) -> table|"關聯數組"(associative arrays|

註釋

  • 單行註釋: --
  • 多行註釋

lua --[[ print("not work, commented") --]]

字符串

  • 塊狀字符串 [[]] 操作符
  • 字符串拼接 .. 操作符
  • 字符串長度 #"your string" # 號操作符

字符串的隱式操作行為,就不在這裏討論了,或者有時間在補充。

Lua 字串操作內置函數

函數與函數調用以及函數返回值

  • 聲明一個命名函數 function end 關鍵字

lua function fn_name(params) // your lua function code end fn_name("a")

  • 聲明一個匿名函數

匿名函數一般考慮作為另一個函數的參數

lua function fn_name(params,fn) -- your lua function code end fn_name("a", function(p) return a end );

  • lua 函數支持多值返回

循環

  • while
  • for
  • repleat until

for 循環語法

```lua

for var=exp1,exp2,exp3 do
-- <執行體>
end
```

跳出循環

  • break
  • goto

if then else 的

lua if (nil) then -- your code end

Lua 中 false/nil 是假,0 是真(這一點與 javascript 是不一致)

Lua 表達式

Lua 5.4 表達式與操作符 與其他的語言大同小於

數組

  • 本質是線性表
  • 數組使用 {member} 包裹元素,使用 [index] 訪問,與 javascript 有很大區別
  • lua 數組索引從 1 開始
  • 一維數組
  • 二維數組
  • 數組循環

迭代器

  • for-in迭代
    • ipairs 迭代函數
    • pairs

用於創建不同的數據數據類型,如上面已經提及的數組,還有字典類型等

表的 crud

  • table.concat 拼接(增加)
  • table.insert 插入(增加)
  • table.remove 移除 (移除)
  • table.sort 排序

模塊與包

從 Lua 5.1 開始,Lua 加入了標準的模塊管理機制, Lua 的就是一個 table

定義一個 模塊

```lua module = {} -- 定義一個module

return module -- 返回一個 module ```

給 module 添加變量

```lua module = {} -- 定義一個module

module.ct = "this is a constant"

-- 共有函數, 沒有 pub 之類的關鍵偶 function module.fn() -- your fn body end -- 私有函數 local function module.fnp() -- your private fn body end -- 在共有函數中,調用私有函數 function module.func3()\     func2()\ end

return module -- 返回一個 module ```

模塊是編程核心,更好的組織代碼,也是能看懂被人組織代碼的基礎

導入模塊

lua require("<module_name>") -- 有括號包裹 require "<module_name>" -- 沒有括號包裹 local m = require("<module_name>") -- 定義別名

錯誤處理

  • 語法錯誤
  • 運行錯誤
  • 處理錯誤
    • 斷言函數 assert
    • 拋出錯誤函數 error
    • pcall(protected call)函數
    • xpcall 函
    • debug 錯誤庫
      • debug.debug
      • debug.traceback

Lua 垃圾回收

Lua 採用了自動內存管理。 這意味着你不用操心新創建的對象需要的內存如何分配出來, 也不用考慮在對象不再被使用後怎樣釋放它們所佔用的內存。

nvchad 配置 nvim

NvChad

加載 lua 文件

  • nvim 首先讀取 init.lua 文件
  • 然後使用 packer 管理 nvim 插件

wexterm 配置文件

安裝

image.png

配置文件

sh md ~/.config/wexterm/wexterm.lua

  • 默認使用 bash 打開

```lua local wezterm = require "wezterm"

local LEFT_ARROW = utf8.char(0xff0b3) local SOLID_LEFT_ARROW = utf8.char(0xff0b2) local SOLID_RIGHT_ARROW = utf8.char(0xff0b0) local scrollback_lines = 200000;

local COLORS = { "#3c1361", "#52307c", "#663a82", "#7c5295", "#b491c8" }

local launch_menu = {}

if wezterm.target_triple == "x86_64-pc-windows-msvc" then ssh_cmd = { "powershell.exe" }

table.insert( launch_menu, { label = "PowerShell", args = { "powershell.exe", "-NoLogo" } } )

table.insert( launch_menu, { label = "Bash", args = { "C:/Program Files/Git/bin/bash.exe", "-li" } } )

table.insert( launch_menu, { label = "CMD", args = { "cmd.exe" } } )

end

function recompute_padding(window) local window_dims = window:get_dimensions() local overrides = window:get_config_overrides() or {} if not window_dims.is_full_screen then if not overrides.window_padding then return end overrides.window_padding = nil else local third = math.floor(window_dims.pixel_width / 3) local new_padding = { left = third, right = third, top = 0, bottom = 0 } if overrides.window_padding and new_padding.left == overrides.window_padding.left then return end overrides.window_padding = new_padding end window:set_config_overrides(overrides) end

wezterm.on( "window-config-reloaded", function(window) recompute_padding(window) end )

wezterm.on( "trigger-nvim-with-scrollback", function(window, pane) local scrollback = pane:get_lines_as_text(scrollback_lines) local name = os.tmpname() local f = io.open(name, "w+") f:write(scrollback) f:flush() f:close() window:perform_action(wezterm.action { SpawnCommandInNewTab = { args = { "nvim", name } } }, pane)

wezterm.sleep_ms(1000)
os.remove(name)

end )

wezterm.on( "window-resized", function(window, pane) recompute_padding(window) end )

wezterm.on( "open-uri", function(window, pane, uri) local start, match_end = uri:find("file://") if start == 1 then local file = uri:sub(match_end + 1) window:perform_action( wezterm.action { SpawnCommandInNewWindow = { args = { "nu", "-c", "nvim " .. file } } }, pane ) return false end end )

wezterm.on( "toggle-opacity", function(window, pane) local overrides = window:get_config_overrides() or {} if not overrides.window_background_opacity then overrides.window_background_opacity = 0.5 else overrides.window_background_opacity = nil end window:set_config_overrides(overrides) end )

local mouse_bindings = { -- 右鍵粘貼 { event = { Down = { streak = 1, button = "Right" } }, mods = "NONE", action = wezterm.action { PasteFrom = "Clipboard" } }, -- Change the default click behavior so that it only selects -- text and doesn't open hyperlinks { event = { Up = { streak = 1, button = "Left" } }, mods = "NONE", action = wezterm.action { CompleteSelection = "PrimarySelection" } }, -- and make CTRL-Click open hyperlinks { event = { Up = { streak = 1, button = "Left" } }, mods = "CTRL", action = "OpenLinkAtMouseCursor" } }

function font_with_fallback(name, params) -- local names = { name, "Hack" } local names = { "CaskaydiaCove Nerd Font Mono", "CaskaydiaCove Nerd Font Mono" } return wezterm.font_with_fallback(names, params) end

wezterm.on( "toggle-ligature", function(window, pane) local overrides = window:get_config_overrides() or {} if not overrides.font then overrides.font = font_with_fallback("Hack", {}) overrides.font_rules = { { italic = false, intensity = "Normal", font = font_with_fallback("Hack", {}) }, { italic = false, intensity = "Bold", font = font_with_fallback("Hack", {}) }, { italic = true, intensity = "Normal", font = font_with_fallback("Hack", {}) }, { italic = true, intensity = "Bold", font = font_with_fallback("Hack", {}) } } else overrides.font = nil overrides.font_rules = nil overrides.font_antialias = nil end window:set_config_overrides(overrides) end )

local default_prog = { "C:/Program Files/Git/bin/bash.exe" }

return { window_decorations = "RESIZE", native_macos_fullscreen_mode = true, tab_max_width = 16, enable_scroll_bar = true, initial_rows = 20, initial_cols = 80, window_background_opacity = 0.85, window_padding = { left = 5, right = 5, top = 5, bottom = 5 }, text_background_opacity = 1,

exit_behavior = "Close", font_size = 11, font = font_with_fallback("Hack", {}), font_rules = { { italic = false, intensity = "Normal", font = font_with_fallback("Hack", {}) }, { italic = false, intensity = "Bold", font = font_with_fallback("Hack", {}) }, { italic = true, intensity = "Normal", font = font_with_fallback("Hack", {}) }, { italic = true, intensity = "Bold", font = font_with_fallback("Hack", {}) } }, colors = { tab_bar = { background = "#0b0022", active_tab = { bg_color = "#3c1361", fg_color = "#c0c0c0", intensity = "Normal" }, inactive_tab = { bg_color = "#1b1032", fg_color = "#808080", }, inactive_tab_hover = { bg_color = "#3b3052", fg_color = "#909090" } }

}, tab_bar_style = { active_tab_left = wezterm.format( { { Background = { Color = "#0b0022" } }, { Foreground = { Color = "#3c1361" } }, { Text = SOLID_LEFT_ARROW } } ), active_tab_right = wezterm.format( { { Background = { Color = "#0b0022" } }, { Foreground = { Color = "#3c1361" } }, { Text = SOLID_RIGHT_ARROW } } ), inactive_tab_left = wezterm.format( { { Background = { Color = "#0b0022" } }, { Foreground = { Color = "#1b1032" } }, { Text = SOLID_LEFT_ARROW } } ), inactive_tab_right = wezterm.format( { { Background = { Color = "#0b0022" } }, { Foreground = { Color = "#1b1032" } }, { Text = SOLID_RIGHT_ARROW } } ) }, window_close_confirmation = "NeverPrompt", window_background_image_hsb = { brightness = 0.8, hue = 1.0, saturation = 1.0 }, inactive_pane_hsb = { brightness = 0.8, hue = 1.0, saturation = 0.8 }, launch_menu = launch_menu, check_for_updates = false, enable_tab_bar = true, show_tab_index_in_tab_bar = true, adjust_window_size_when_changing_font_size = false, mouse_bindings = mouse_bindings, default_prog = default_prog, unix_domains = { { name = 'wsl', serve_command = { 'wsl', 'wezterm-mux-server', '--daemonize' }, }, }, -- default_gui_startup_args = { 'connect', 'wsl' }, } ```

小結

  • 瞭解 lua 基本語法與模塊機制
  • 為 nvim/nvchad 使用 lua 寫配置文件準備
  • 為 wezterm 跨平台 使用 lua 寫配置文件
  • 後面具體在 windows/linux/macOS 實際使用體驗後寫一篇關於 wezterm 的文章
  • 配置文件對 lua 的要求對別低,採用編程的方式寫配置文件,靈活度極高

參考