Recently Written · git

sbm

dmenu bookmarks. Instantly fuzzy search thousands of bookmarks and plumb them. LOOKING FOR SUCKLESS SOFTWARE EDITION? GO TO sbm-suckless INSTEAD

git clone https://github.com/equwal/sbm

Log | Files | Refs


commit 2d25f2cd6c9f9d466d17c03d49d3c63cef601ec9
Spenser Truex <truex@equwal.com>
2026-09-20 22:29:48 -0700

macOS: a portable sbm.app in a DMG

contrib/macos/build-dmg.sh makes sbm-VERSION.dmg. sbm.app contains bm,
the bm-* tools and fzf for Intel and Apple silicon. It opens bm in a
Terminal window. The app has an ad-hoc signature only.

 .gitignore                 |  1 +
 README                     | 21 ++++++++++++++++
 contrib/macos/Info.plist   | 28 +++++++++++++++++++++
 contrib/macos/build-dmg.sh | 62 ++++++++++++++++++++++++++++++++++++++++++++++
 contrib/macos/sbm          | 14 +++++++++++
 contrib/macos/sbm-run      | 12 +++++++++
 6 files changed, 138 insertions(+)
diff --git a/.gitignore b/.gitignore
index 192f813..dca7fc0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ tags.*
 bm
 bmks
 sbm-*-setup.exe
+sbm-*.dmg
diff --git a/README b/README
index 8a8ddc0..119d66f 100644
--- a/README
+++ b/README
@@ -232,6 +232,27 @@ such as /dev/null. To remove sbm, use Apps in the Windows settings. The
 uninstaller keeps your bookmarks. contrib/windows/build-installer.sh makes
 the installer with NSIS.
 
+== macOS ==
+Get sbm-VERSION.dmg from a release on GitHub, and drag sbm.app to
+Applications. The app contains bm, the bm-* tools and fzf, so it needs no
+other software. sbm.app opens bm in a Terminal window. The first time, macOS
+asks if sbm can control Terminal.
+
+The app has no signature from a registered developer, so macOS stops it the
+first time. To open it, use Open Anyway in System Settings, Privacy &
+Security. Or remove the quarantine attribute:
+
+    xattr -dr com.apple.quarantine /Applications/sbm.app
+
+To open sbm with a key, make a shortcut with the action Open App in the
+Shortcuts app, and give it a keyboard shortcut. macOS has function keys up
+to F20. To use the tools in a shell, add these lines to ~/.zprofile:
+
+    PATH=/Applications/sbm.app/Contents/Resources/bin:$PATH
+    export SBM_OPEN=open SBM_COPY=pbcopy SBM_PASTE=pbpaste
+
+contrib/macos/build-dmg.sh makes the image on a Mac.
+
 == Tests ==
     make check
 
diff --git a/contrib/macos/Info.plist b/contrib/macos/Info.plist
new file mode 100644
index 0000000..57cdcd6
--- /dev/null
+++ b/contrib/macos/Info.plist
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>sbm</string>
+	<key>CFBundleExecutable</key>
+	<string>sbm</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.equwal.sbm</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>sbm</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>@VERSION@</string>
+	<key>CFBundleVersion</key>
+	<string>@VERSION@</string>
+	<key>LSMinimumSystemVersion</key>
+	<string>11.0</string>
+	<key>NSAppleEventsUsageDescription</key>
+	<string>sbm opens bm in a Terminal window.</string>
+</dict>
+</plist>
diff --git a/contrib/macos/build-dmg.sh b/contrib/macos/build-dmg.sh
new file mode 100755
index 0000000..5eb2577
--- /dev/null
+++ b/contrib/macos/build-dmg.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+# build-dmg.sh: make sbm-VERSION.dmg, the portable macOS edition, in the top
+# directory of the source. Run it on macOS:
+#
+#     sh contrib/macos/build-dmg.sh
+#
+# The image holds sbm.app. The app contains bm, the bm-* tools and fzf, so it
+# needs no other software. The script gets fzf from the fzf release on
+# GitHub. It stops if the SHA-256 sum of a download is not the expected one.
+
+set -e
+
+fzf_version=0.74.4
+fzf_amd64_sum=2d392b50be66e2ab104ccd52a6072df692b1f9b9c5b449a9c098de885f32c4c5
+fzf_arm64_sum=4f6a113bfc0c7959e0005c78d566a51afc4fcefc956f43735c62a9deb19e92ae
+
+here=$(cd "$(dirname "$0")" && pwd)
+top=$(cd "$here/../.." && pwd)
+version=$(sed -n 's/^VERSION=//p' "$top/config.mk")
+out=$top/sbm-$version.dmg
+
+work=${TMPDIR:-/tmp}/sbm-dmg.$$
+mkdir "$work"
+trap 'rm -rf "$work"' EXIT INT TERM
+app=$work/root/sbm.app
+mkdir -p "$app/Contents/MacOS"
+
+make -s -C "$top" install PREFIX="$app/Contents/Resources" >/dev/null
+cp "$here/sbm" "$app/Contents/MacOS/sbm"
+cp "$here/sbm-run" "$app/Contents/Resources/sbm-run"
+chmod 755 "$app/Contents/MacOS/sbm" "$app/Contents/Resources/sbm-run"
+sed "s/@VERSION@/$version/g" "$here/Info.plist" > "$app/Contents/Info.plist"
+plutil -lint "$app/Contents/Info.plist" >/dev/null
+
+url=https://github.com/junegunn/fzf/releases/download/v$fzf_version
+for arch in amd64 arm64; do
+    curl -fsSL -o "$work/fzf-$arch.tar.gz" \
+        "$url/fzf-$fzf_version-darwin_$arch.tar.gz"
+done
+shasum -a 256 -c >/dev/null <<EOF
+$fzf_amd64_sum  $work/fzf-amd64.tar.gz
+$fzf_arm64_sum  $work/fzf-arm64.tar.gz
+EOF
+for arch in amd64 arm64; do
+    mkdir "$work/$arch"
+    tar -xzf "$work/fzf-$arch.tar.gz" -C "$work/$arch"
+done
+# One fzf for Intel and Apple silicon.
+lipo -create -output "$app/Contents/Resources/bin/fzf" \
+    "$work/amd64/fzf" "$work/arm64/fzf"
+curl -fsSL -o "$app/Contents/Resources/fzf-LICENSE.txt" \
+    "https://raw.githubusercontent.com/junegunn/fzf/v$fzf_version/LICENSE"
+
+# The app has no signature from a registered developer. An ad-hoc signature
+# still lets macOS find a damaged app.
+codesign --force --deep --sign - "$app"
+
+ln -s /Applications "$work/root/Applications"
+hdiutil create -quiet -volname "sbm $version" -srcfolder "$work/root" \
+    -ov -format UDZO "$out"
+printf '%s\n' "$out"
diff --git a/contrib/macos/sbm b/contrib/macos/sbm
new file mode 100755
index 0000000..91094f8
--- /dev/null
+++ b/contrib/macos/sbm
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# sbm: the program of sbm.app. It opens a Terminal window that runs
+# sbm-run. The first time, macOS asks if sbm can control Terminal.
+
+run=$(cd "$(dirname "$0")/../Resources" && pwd)/sbm-run
+exec osascript \
+    -e 'on run argv' \
+    -e 'tell application "Terminal"' \
+    -e 'activate' \
+    -e 'do script (quoted form of item 1 of argv) & "; exit 0"' \
+    -e 'end tell' \
+    -e 'end run' \
+    "$run"
diff --git a/contrib/macos/sbm-run b/contrib/macos/sbm-run
new file mode 100755
index 0000000..2fb89c6
--- /dev/null
+++ b/contrib/macos/sbm-run
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# sbm-run: run bm with the tools in sbm.app. bm opens URLs in the default
+# browser and uses the clipboard of macOS. Settings in the environment win.
+
+bin=$(cd "$(dirname "$0")/bin" && pwd)
+PATH=$bin:$PATH
+SBM_OPEN=${SBM_OPEN:-open}
+SBM_COPY=${SBM_COPY:-pbcopy}
+SBM_PASTE=${SBM_PASTE:-pbpaste}
+export PATH SBM_OPEN SBM_COPY SBM_PASTE
+exec bm "$@"