#!/usr/bin/env bash
# MARK-09, 11, 13, 14 live: look, output, Git, large files.
set -euo pipefail
root=$(cd "$(dirname "$0")/../.." && pwd)
[ "$(uname)" = Darwin ] || { echo "SKIP: macOS only"; exit 0; }
[ -d "${ELY_CEF:-$root/engines/cef}/Chromium Embedded Framework.framework" ] || {
echo "SKIP: no CEF; run scripts/fetch-cef.sh"
exit 0
}
command -v npm >/dev/null || { echo "SKIP: no npm"; exit 0; }
command -v pdftotext >/dev/null || { echo "SKIP: no pdftotext"; exit 0; }
[ -x "$root/engines/git/bin/git" ] || export ELY_GIT=${ELY_GIT:-$(command -v git)}
work=$(mktemp -d)
app=
trap 'if [ -n "$app" ]; then kill "$app" 2>/dev/null || true; wait "$app" 2>/dev/null || true; fi; pkill -f "$work" 2>/dev/null || true; rm -rf "$work"' EXIT
fail() {
echo "FAIL: $*" >&2
exit 1
}
"$root/scripts/build-mark-content.sh" >"$work/build" 2>&1 || fail "build: $(tail -n 5 "$work/build")"
cargo build -q -p ely-mark -p ely-tree -p ely-pdf --manifest-path "$root/Cargo.toml"
for tool in ax-values ax-press; do
swiftc -O -o "$work/$tool" "$root/tests/scripts/$tool.swift"
done
repo=$work/repo
mkdir -p "$repo/assets"
python3 -c 'import struct,zlib,sys
c=lambda t,d: struct.pack(">I",len(d))+t+d+struct.pack(">I",zlib.crc32(t+d))
open(sys.argv[1],"wb").write(b"\x89PNG\r\n\x1a\n"+c(b"IHDR",struct.pack(">IIBBBBB",1,1,8,2,0,0,0))+c(b"IDAT",zlib.compress(b"\0\xff\0\0"))+c(b"IEND",b""))' "$repo/assets/pic.png"
cp "$repo/assets/pic.png" "$repo/assets/high.png"
doc=$repo/t.md
printf '%s\n' '# Title' '' 'Some $x^2$ math.' '' '' '' "
" '' \
"
" '' '```mermaid' 'graph TD; A-->B' '```' '' \
'```mermaid' 'graph TD; SECRET_WORDS -->' '```' '' '
RAW TEXT
TWO
' '' \
"
" '' "
" '' \
"
" '' \
'$\privateDocumentToken$' '' '' '' 'END MARK' >"$doc"
git -C "$repo" init -q
git -C "$repo" -c user.name=t -c user.email=t@e.x add -A
git -C "$repo" -c user.name=t -c user.email=t@e.x commit -qm one
original=$(cat "$doc")
launch() {
ELY_LOG=info ELY_LOCALE=en ELY_NO_DIALOG=1 HOME="$work" \
"$root/target/debug/ely-mark" "$@" >"$work/log" 2>&1 &
app=$!
waits "mark: shown as"
osascript -e "tell application \"System Events\" to set frontmost of (first process whose unix id is $app) to true" -e 'delay 2' >/dev/null
}
waits() {
for _ in $(seq 160); do
grep -qF "$1" "$work/log" && return 0
kill -0 "$app" 2>/dev/null || fail "ElyMark quit: $(tail -n 5 "$work/log")"
sleep 0.25
done
fail "never saw '$1': $(grep -E 'mark:|office:' "$work/log" | tail -n 5)"
}
count() { grep -c "$1" "$work/log" || true; }
front() { osascript -e "tell application \"System Events\" to set frontmost of (first process whose unix id is $app) to true" -e 'delay 1' >/dev/null; }
key() { osascript -e "tell application \"System Events\" to $1" -e 'delay 0.8' >/dev/null; }
# The window's own titles; system menus list recent files too.
seen() { "$work/ax-values" "$app" | grep -v '^AXMenu' | grep -qF "title=$1"; }
press() {
for _ in $(seq 40); do
[ "$("$work/ax-press" "$app" "$@")" = pressed ] && { sleep 0.8; return 0; }
sleep 0.25
done
fail "could not press $*"
}
quit() {
kill "$app"
wait "$app" 2>/dev/null || true
app=
}
# Asks a `kind` export beside the document, maybe named `$2`.
ask_export() {
front
key 'keystroke "e" using command down'
press "$1"
press "Export…" AXButton
# The panel opens in the document's folder, the stem chosen.
sleep 3
[ -z "${2:-}" ] || key "keystroke \"$2\""
# The panel's own button: Return alone did not always save.
press Save AXButton
}
# Exports `kind`; waits for its log line.
export_as() {
local before failed
before=$(count "mark: exported")
failed=$(count "export failed")
ask_export "$@"
for _ in $(seq 160); do
[ "$(count "mark: exported")" -gt "$before" ] && return 0
[ "$(count "export failed")" -gt "$failed" ] && fail "export: $(grep "export failed" "$work/log" | tail -n 1)"
sleep 0.25
done
fail "no $1 export: $(grep -E "mark:|office:|dialog|panel" "$work/log" | tail -n 4)"
}
launch "$doc"
[ "$("$work/ax-press" $$ none)" != untrusted ] || fail "needs Accessibility permission"
# Git sees the file; its item opens ElyTree there.
for _ in $(seq 40); do seen "Git: unchanged" && break; sleep 0.25; done
seen "Git: unchanged" || fail "no Git state: $(grep 'git says' "$work/log" | tail -n 1)"
key 'keystroke "f" using command down'
key 'key code 53'
key 'key code 125 using command down'
key 'keystroke "Z"'
for _ in $(seq 60); do seen "Git: changed" && break; sleep 0.25; done
seen "Git: changed" || fail "Git missed the change: $(grep -E "git says|autosave|saved" "$work/log" | tail -n 4)"
printf '%s\n' "$original" >"$doc"
press "Git: changed"
for _ in $(seq 40); do pgrep -f "target/debug/ely-tree .*${repo#/private}" >/dev/null && break; sleep 0.25; done
pgrep -f "target/debug/ely-tree .*${repo#/private}" >/dev/null || fail "ElyTree did not open the repository"
# ElyTree takes the file itself and shows its history (§16).
waits "tree: file history of t.md"
pkill -f "target/debug/ely-tree .*${repo#/private}" || true
sleep 2
front
# Focus mode folds the chrome; the look outlives the app.
press "Focus Mode"
! seen "t.md" || fail "focus mode kept the tabs"
press "Serif Font"
quit
grep -q '"focus": true' "$work/Library/Application Support/ElyOffice/ely-mark/look.json" || fail "the look was not kept"
[ "$(cat "$doc")" = "$original" ] || fail "the look changed the file: $(cat "$doc")"
printf '# Other\n' >"$repo/b.md"
launch "$repo/b.md" "$doc"
! seen "t.md" || fail "focus mode did not come back"
press "Focus Mode"
seen "t.md" || fail "focus mode stayed"
# Tabs open in any order; t.md's page takes the keys.
press t.md
key 'keystroke "f" using command down'
key 'key code 53'
# Each export holds the whole document.
export_as HTML
html=$repo/t.html
grep -q 'class="katex' "$html" && grep -q '