#!/bin/zsh
# Build script for neovim
#
# Task 1b-4 (M2): attempted USE_BUNDLED=OFF + PREFER_LUA=ON (consume our
# system libuv/msgpack-c/unibilium/libtermkey/libvterm/tree-sitter + lua).
# That failed: neovim's cmake.deps subproject requires an EXACT Lua 5.1
# (find_package(Lua 5.1 EXACT)) to link against for either the "prefer lua"
# path (real PUC Lua 5.1) OR the default LuaJIT path - and our system `lua`
# port is 5.4.8 (no 5.1-ABI package exists in zports). Per task brief
# fallback: keep USE_BUNDLED=ON (neovim builds its own private copies of
# these deps, using the bundled LuaJIT engine) rather than sink more time
# chasing a Lua 5.1 system package that doesn't exist yet. tree-sitter
# parsers were already being pre-staged this way regardless of the flag.
#
# cmake on Hammerhead has no HTTPS support, so every ExternalProject source
# tarball cmake.deps would otherwise fetch itself must be pre-staged with
# curl into .deps/build/downloads/<subdir>/<file> first.

set -e

PORTDIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)

cd "$SRCDIR"

# LuaJIT's own Makefile probes whether $(TARGET_CC) emits eh_frame/
# __unwind_info sections in a bare test compile (no -funwind-tables) to
# decide whether to auto-define -DLUAJIT_UNWIND_EXTERNAL. GCC 14 on
# Hammerhead doesn't default to -fasynchronous-unwind-tables the way
# glibc/Linux x86_64 GCC does, so the probe comes back empty and
# lj_err.c's LJ_TARGET_X64 unwind path hits its
# "#error Broken build system" guard. Patch cmake.deps' BuildLuajit.cmake
# to force -DLUAJIT_UNWIND_EXTERNAL directly instead of relying on the
# probe.
for p in "$PORTDIR"/patches/*.patch; do
    [ -f "$p" ] || continue
    echo "==> Applying patch: $(basename "$p")"
    patch -p1 < "$p"
done

# Create cmake Platform module for Hammerhead (illumos derivative)
# cmake doesn't recognize Hammerhead and won't set UNIX=TRUE without this
mkdir -p "$SRCDIR/.cmake/Platform"
echo 'include(Platform/SunOS)' > "$SRCDIR/.cmake/Platform/Hammerhead.cmake"

MODPATH="$SRCDIR/.cmake"

export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig:/usr/lib/pkgconfig:$PKG_CONFIG_PATH"
export CMAKE_PREFIX_PATH="$PREFIX:$CMAKE_PREFIX_PATH"

# -D__illumos__: bundled tree-sitter (and possibly other deps) gate their
# <endian.h> #include on __linux__/__illumos__/*BSD/etc; our GCC 14
# toolchain defines __sun/__SVR4 but not __illumos__, tripping
# "#error platform not supported" even though Hammerhead's libc DOES ship
# a POSIX-style <endian.h> with le16toh/be16toh (verified at
# /usr/include/endian.h). Each dep in cmake.deps is its own fresh
# ExternalProject_Add cmake invocation (only CMAKE_BUILD_TYPE is
# propagated via DEPS_CMAKE_ARGS - CMAKE_C_FLAGS passed to the outer
# `cmake -S cmake.deps -B .deps` configure does NOT flow down to
# sub-projects), so export it via the CFLAGS env var instead: cmake's
# project() seeds CMAKE_C_FLAGS from $CFLAGS on first configure, and
# ExternalProject_Add's cmake subprocess inherits our environment.
export CFLAGS="${CFLAGS:-} -D__illumos__"

# coral's build wrapper exports DESTDIR=$PKGDIR globally so a package's
# own `make install`/`cmake --install` stages into the pkg dir. That
# environment variable bleeds into cmake.deps's bundled sub-builds too
# (e.g. LuaJIT's Makefile does `DPREFIX = $(DESTDIR)$(PREFIX)`), so
# instead of installing into .deps/usr as intended, luajit/libuv/etc were
# silently installing under $PKGDIR/<absolute .deps/usr path> - meaning
# .deps/usr never got populated and every downstream dep
# (lpeg/luv - "lua.h: No such file", "missing LUAJIT_LIBRARIES") failed to
# find them. Unset it for the whole cmake.deps phase; it gets re-exported
# below just before neovim's own `cmake --install build`, which is the
# only step that should honor it.
unset DESTDIR

# Pre-download every bundled dependency cmake.deps will build with
# USE_BUNDLED=ON (default LuaJIT engine): libuv, luajit, lpeg, unibilium,
# luv, utf8proc, plus the tree-sitter runtime + parsers used for
# :checkhealth/help/runtime syntax. GETTEXT/LIBICONV are MSVC-only and
# WASMTIME/UNCRUSTIFY/LUA_DEV_DEPS/XXD/WIN32YANK are Windows- or
# lint/test-only - not needed for a plain Unix build, so they are skipped.
DLDIR="$SRCDIR/.deps/build/downloads"

echo "Pre-downloading bundled dependencies..."
while IFS=' ' read -r name url; do
    [[ -z "$name" || -z "$url" ]] && continue
    local subdir=""
    case "$name" in
        LIBUV_URL)               subdir="libuv" ;;
        LUAJIT_URL)               subdir="luajit" ;;
        LPEG_URL)                 subdir="lpeg" ;;
        UNIBILIUM_URL)            subdir="unibilium" ;;
        LUV_URL)                  subdir="luv" ;;
        LUA_COMPAT53_URL)         subdir="lua_compat53" ;;
        UTF8PROC_URL)             subdir="utf8proc" ;;
        TREESITTER_URL)           subdir="treesitter" ;;
        TREESITTER_C_URL)         subdir="treesitter_c" ;;
        TREESITTER_LUA_URL)       subdir="treesitter_lua" ;;
        TREESITTER_VIM_URL)       subdir="treesitter_vim" ;;
        TREESITTER_VIMDOC_URL)    subdir="treesitter_vimdoc" ;;
        TREESITTER_QUERY_URL)     subdir="treesitter_query" ;;
        TREESITTER_MARKDOWN_URL)  subdir="treesitter_markdown" ;;
        *)                        continue ;;
    esac
    local fname="${url##*/}"
    mkdir -p "$DLDIR/$subdir"
    if [[ ! -f "$DLDIR/$subdir/$fname" ]]; then
        echo "  Downloading $subdir/$fname ..."
        curl -fsSL -o "$DLDIR/$subdir/$fname" "$url"
    fi
done < cmake.deps/deps.txt

# Build the cmake.deps subproject with the default USE_BUNDLED=ON (private
# copies of libuv/luajit/lpeg/unibilium/luv/utf8proc/tree-sitter, all
# statically linked into nvim - no system Lua 5.1 required).
# -D__illumos__: bundled tree-sitter's portable/endian.h gates its
# `#include <endian.h>` branch on __linux__/__illumos__/*BSD/etc; our GCC
# 14 toolchain defines __sun/__SVR4 but not __illumos__, so it falls
# through to "#error platform not supported" even though Hammerhead's
# libc DOES ship a POSIX-style <endian.h> with le16toh/be16toh (verified
# at /usr/include/endian.h). Define the macro ourselves rather than patch
# every upstream file that checks for it.
cmake -S cmake.deps -B .deps -G Ninja \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_MODULE_PATH="$MODPATH" \
    -DCMAKE_C_COMPILER=/usr/bin/cc \
    -DCMAKE_C_FLAGS="-D__illumos__"

cmake --build .deps

# Build neovim against the bundled deps just built above.
cmake -B build -G Ninja \
    -DCMAKE_BUILD_TYPE=RelWithDebInfo \
    -DCMAKE_MODULE_PATH="$MODPATH" \
    -DCMAKE_C_COMPILER=/usr/bin/cc \
    -DCMAKE_C_FLAGS="-D__illumos__" \
    -DCMAKE_INSTALL_PREFIX=$PREFIX \
    -DCMAKE_INSTALL_RPATH=$PREFIX/lib \
    -DENABLE_JEMALLOC=OFF

cmake --build build

# Install - restore DESTDIR (unset above for the cmake.deps phase) so this
# final install stages into $PKGDIR as coral expects.
export DESTDIR="$PKGDIR"
cmake --install build

# Create vi/vim symlinks
ln -sf nvim "$PKGDIR$PREFIX/bin/vim"
ln -sf nvim "$PKGDIR$PREFIX/bin/vi"
