Since i am currently working on a little tool for synching my old macbook pro, my workstation at home and my work thinkpad - I want to highlight a part of the lua configuration for said tool as bash, not as a lua string.
I use this tool (mehr2
) to keep my installed packages on all systems in sync.
I plan to use the following configuration file:
1MEHR2 = {
2 packages = {
3 default = {
4 "git",
5 "picom",
6 "fish",
7 "imagemagick",
8 "firefox",
9 "flameshot",
10 "pipewire",
11 "dunst",
12 "rofi",
13 "i3",
14 "acpi",
15 "zathura",
16 "curl",
17 },
18 apt = { "build-essentials" },
19 pacman = { "base-devel", "pamixer", "hugo", "go", "ghostty" },
20 scratch = {
21 {
22 identifier = "rustup",
23 needs = { "curl" },
24 update = "rustup update",
25 script = [[
26 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
27 rustup component add rust-docs
28 rustup component add cargo
29 rustup component add clippy
30 rustup component add rustfmt
31 ]]
32 }
33 },
34 {
35 -- see: https://github.com/neovim/neovim/blob/master/BUILD.md
36 identifier = "nvim",
37 git = "github.com/neovim/neovim",
38 needs = { "make", "cmake", "gcc" },
39 branch = "nightly",
40 script = [[
41 make CMAKE_BUILD_TYPE=Release
42 make install
43 ]]
44 }
45 },
46 {
47 -- see: https://github.com/ziglang/zig/wiki/Install-Zig-from-a-Package-Manager
48 identifier = "zig",
49 execute_for = { "apt" },
50 update = "snap refresh zig",
51 needs = { "snap" },
52 script = "snap install zig --classic --beta"
53 },
54 {
55 -- see: https://ghostty.org/docs/install/build
56 identifier = "ghostty",
57 execute_for = { "apt" },
58 git = "github.com/ghostty-org/ghostty",
59 needs = { "zig", "gtk4" },
60 script = "zig build -p /usr -Doptimize=ReleaseFast"
61 },
62 {
63 identifier = "go",
64 execute_for = { "apt" },
65 script = [[
66 VERSION=$(curl -s "https://go.dev/VERSION?m=text" | head -n1)
67 wget https://go.dev/dl/$VERSION.linux-amd64.tar.gz
68 rm -rf /usr/local/go
69 tar -C /usr/local -xzf $VERSION.linux-amd64.tar.gz
70 ]]
71 },
72 {
73 -- see: https://gohugo.io/installation/linux/#build-from-source
74 identifier = "hugo",
75 execute_for = { "apt" },
76 needs = { "go" },
77 script = "go install github.com/gohugoio/hugo@latest"
78 },
79 },
80 cargo = { "exa", "bat", "ripgrep", "yazi" }
81 }
82}
The default
array defines packages the current package manager would install.
The packages in the apt
, pacman
and cargo
arrays are only installed if
the corresponding package manager is executable on the target machine (some
differ in names, depending on the package manager, so I install them
specifically). However each entry in the scratch
array is executed if any of
the entries in the execute_for
field are found on the system. The execution
is done by passing the value of the script
field to bash. If the
execute_for
field is missing, the array entry is executed every time.
Since the script
field contains a bash script, i want it to be highlighted as
such. Neovim and treesitter enable this exact usecase.
Neovim setup
I use packer to install treesitter:
1-- .config/nvim/lua/teo/packer.lua
2
3-- packer installation
4local fn = vim.fn
5local install_path = fn.stdpath('data') .. '/site/pack/packer/start/packer.nvim'
6if fn.empty(fn.glob(install_path)) > 0 then
7 packer_bootstrap = fn.system({ 'git', 'clone', '--depth', '1', 'https://github.com/wbthomason/packer.nvim',
8 install_path })
9 download_result = fn.system({ 'ls', '-l', install_path })
10 print("download_result: " .. download_result)
11end
12
13vim.cmd [[packadd packer.nvim]]
14
15return require('packer').startup(function(use)
16 -- syntax highlighting and parser
17 use { 'nvim-treesitter/nvim-treesitter', run = ':TSUpdate' }
18end)
:PackerSync
will synchronise your neovim instance to your configuration
and install treesitter.
Treesitter setup
I configure treesitter in a minimalistic way:
1-- .config/nvim/after/plugin/treesitter.lua
2
3require'nvim-treesitter.configs'.setup {
4 ensure_installed = { "c", "lua", "rust", "javascript", "css", "html", "markdown", "javascript"},
5 sync_install = false,
6 auto_install = true,
7 highlight = {
8 enable = true,
9 additional_vim_regex_highlighting = false,
10 },
11}
Injections
Queries are S-expressions and documented here
Treesitter injections are placed at
.config/nvim/queries/<filetype>/injections.scm
1 and contain
configurations treesitter injects into files with the corresponding filetype.
For my specific usecase I search for the script
table property/field:
1; Inject into script = [[...]] as bash
2((field
3 name: (identifier) @_name
4 value: (string
5 content: (string_content) @injection.content
6 (#eq? @_name "script")
7 (#set! injection.language "bash")
8 )))
The injection works by quering the treesitter tree (inspectable via
:InspectTree
) for a field
where its value is a string and its name is equal
to "script"
. If so the string content is set to be highlighted as bash: