Skip to content

Instantly share code, notes, and snippets.

@NinoScript
Last active November 20, 2025 02:11
Show Gist options
  • Select an option

  • Save NinoScript/2dfb983de3bf5620beb8304ce653e05c to your computer and use it in GitHub Desktop.

Select an option

Save NinoScript/2dfb983de3bf5620beb8304ce653e05c to your computer and use it in GitHub Desktop.
A method to get colorblind friendly version of Fork.app
#!/usr/bin/env bash
set -euo pipefail
# === CONFIGURATION ===
APP_SRC="/Applications/Fork.app"
APP_DEST="./Fork.app"
DYLIB_NAME="ColorTap.dylib"
COLOR_SRC="ColorTap.m"
INSERT_REPO="https://github.com/Tyilo/insert_dylib.git"
# === STEP 0: Fresh copy of Fork ===
echo "→ Copying Fork.app locally..."
rm -rf "$APP_DEST"
cp -R "$APP_SRC" .
# === STEP 1: Create ColorTap.m if missing ===
if [[ ! -f "$COLOR_SRC" ]]; then
cat >"$COLOR_SRC" <<'EOF'
// ColorTap.m — minimal Fork diff recolor
#import <Cocoa/Cocoa.h>
#import <objc/runtime.h>
static inline NSColor *RGB(int r,int g,int b,CGFloat a){
return [NSColor colorWithSRGBRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a];
}
static inline NSColor *RemovedLine(){return RGB(101,72,60,1);}
static inline NSColor *RemovedWord(){return RGB(174,95,52,1);}
static inline NSColor *AddedLine(){return RGB(39,69,111,1);}
static inline NSColor *AddedWord(){return RGB(39,85,149,1);}
static NSColor *OverrideForName(NSString *n){
if(!n)return nil;
static NSDictionary *m; static dispatch_once_t once;
dispatch_once(&once,^{
m=@{
@"diffaddedcolor":AddedLine(),
@"diffremovedcolor":RemovedLine(),
@"diffaddedhighlightbackgroundcolor":AddedWord(),
@"diffremovedhighlightbackgroundcolor":RemovedWord(),
@"mergeaddedbackgroundcolor":AddedLine(),
@"mergeremovedbackgroundcolor":RemovedLine(),
@"mergelocalbackgroundcolor":AddedLine(),
@"mergeremotebackgroundcolor":RemovedLine(),
@"mergeunmergedbackgroundcolor":AddedLine(),
};
});
return m[n.lowercaseString];
}
@interface NSColor(Tap)
+ (NSColor*)tap_colorNamed:(NSColorName)n;
+ (NSColor*)tap_colorNamed:(NSColorName)n bundle:(NSBundle*)b;
@end
@implementation NSColor(Tap)
+ (NSColor*)tap_colorNamed:(NSColorName)n{
NSColor*o=OverrideForName((NSString*)n);
return o?o:[self tap_colorNamed:n];
}
+ (NSColor*)tap_colorNamed:(NSColorName)n bundle:(NSBundle*)b{
NSColor*o=OverrideForName((NSString*)n);
return o?o:[self tap_colorNamed:n bundle:b];
}
@end
__attribute__((constructor))
static void tap_init(void){
Class c=object_getClass([NSColor class]);
struct{SEL a;SEL b;}p[]={{@selector(colorNamed:),@selector(tap_colorNamed:)},
{@selector(colorNamed:bundle:),@selector(tap_colorNamed:bundle:)}};
for(int i=0;i<2;i++){Method A=class_getClassMethod(c,p[i].a);
Method B=class_getClassMethod(c,p[i].b);
if(A&&B)method_exchangeImplementations(A,B);}
}
EOF
fi
# === STEP 2: Build dylib ===
echo "→ Building $DYLIB_NAME..."
SDK=$(xcrun --sdk macosx --show-sdk-path)
clang -arch arm64 -dynamiclib -fobjc-arc -isysroot "$SDK" -framework Cocoa \
-o "./$DYLIB_NAME" "./$COLOR_SRC"
codesign -f -s - "./$DYLIB_NAME"
# === STEP 3: Place dylib inside app ===
echo "→ Inserting into Fork.app..."
mkdir -p "$APP_DEST/Contents/Frameworks"
cp -f "./$DYLIB_NAME" "$APP_DEST/Contents/Frameworks/$DYLIB_NAME"
# === STEP 4: Build insert_dylib if missing ===
if [[ ! -x ./insert_dylib/insert_dylib ]]; then
echo "→ Building insert_dylib..."
rm -rf insert_dylib
git clone --depth=1 "$INSERT_REPO" insert_dylib
xcodebuild -project insert_dylib/insert_dylib.xcodeproj -scheme insert_dylib \
-configuration Release -arch arm64 build >/dev/null
fi
INS=$(find ~/Library/Developer/Xcode/DerivedData -type f -path "*/Release/insert_dylib" -perm +111 2>/dev/null | head -n1)
[[ -x "$INS" ]] || INS="./insert_dylib/insert_dylib"
# === STEP 5: Patch Fork binary ===
echo "→ Patching binary..."
"$INS" --inplace --strip-codesig \
@executable_path/../Frameworks/$DYLIB_NAME \
"$APP_DEST/Contents/MacOS/Fork"
# === STEP 6: Re-sign everything ad-hoc ===
echo "→ Re-signing..."
codesign -f -s - "$APP_DEST/Contents/Frameworks/$DYLIB_NAME"
codesign -f -s - "$APP_DEST/Contents/MacOS/Fork"
codesign -f -s - --deep "$APP_DEST"
# === STEP 7: Verify and launch ===
echo "→ Verifying patch..."
otool -L "$APP_DEST/Contents/MacOS/Fork" | grep "$DYLIB_NAME" || echo "⚠️ Missing link!"
echo "→ Launching Fork..."
open "$APP_DEST"
@NinoScript
Copy link
Author

Instructions:

mkdir colorblind
cd colorblind
curl -O https://gist.githubusercontent.com/NinoScript/2dfb983de3bf5620beb8304ce653e05c/raw/c80548c7077ce0245169657ab502dee67eecf026/recolor-fork.sh
chmod +x recolor-fork.sh
./recolor-fork.sh

@NinoScript
Copy link
Author

Note: Always be cautious when running code you find online.

@NinoScript
Copy link
Author

NinoScript commented Nov 18, 2025

Using these colors replicates the default Fork behavior:

static inline NSColor *RemovedLine(){return RGB(99,63,62,1);}
static inline NSColor *RemovedWord(){return RGB(159,67,71,1);}
static inline NSColor *AddedLine(){return RGB(58,92,63,1);}
static inline NSColor *AddedWord(){return RGB(56,132,66,1);}
Screenshot 2025-11-18 at 11 55 25 AM

These replicate GitHub's colorblind theme:

static inline NSColor *RemovedLine(){return RGB(44,31,26,1);}
static inline NSColor *RemovedWord(){return RGB(114,62,34,1);}
static inline NSColor *AddedLine(){return RGB(20,35,56,1);}
static inline NSColor *AddedWord(){return RGB(35,77,135,1);}
Screenshot 2025-11-18 at 11 57 57 AM

But I found that GitHub's darker colors do not work so well with the lighter background.
So in the script I used these values to have about the same brightness as Fork's colors, but the same hues as GitHub's colors.

static inline NSColor *RemovedLine(){return RGB(101,72,60,1);}
static inline NSColor *RemovedWord(){return RGB(174,95,52,1);}
static inline NSColor *AddedLine(){return RGB(39,69,111,1);}
static inline NSColor *AddedWord(){return RGB(39,85,149,1);}
Screenshot 2025-11-18 at 12 04 26 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment