BetterCmdTab

Współtworzenie

Zbuduj BetterCmdTab ze źródeł, uruchom testy i doprowadź pull request do scalenia.

Mile widziane są zarówno zgłoszenia, jak i pull requesty — raporty błędów, pomysły na funkcje oraz zmiany kodu. Ta strona odzwierciedla plik CONTRIBUTING.md w repozytorium; jeśli treści kiedykolwiek się różnią, ten plik jest źródłem prawdy.

Podstawowe zasady

Te cztery zasady nie podlegają negocjacji — PR, który łamie jedną z nich, będzie wymagał zmian bez względu na jakość funkcji.

ZasadaUzasadnienie
Tylko AppKitBez SwiftUI, Catalyst i zewnętrznych frameworków UI. Przełącznik musi działać natywnie i otwierać się natychmiast.
Bez telemetriiBez analityki, raportowania awarii i ruchu sieciowego w tle. Dozwolone są wyłącznie żądania sprawdzające aktualizacje w GitHub Releases.
macOS 13.0 pozostaje minimalną wersjąFunkcje nowszych systemów są chronione przez if #available i mają łagodny mechanizm zastępczy.
Ścieżka krytyczna pozostaje szybkaWszystko, co działa podczas ⌘Tab, wykonuje się poza głównym wątkiem albo jest mierzone.

Budowanie

git clone https://github.com/rokartur/BetterCmdTab.git
cd BetterCmdTab
xcodebuild -scheme "BetterCmdTab Debug" -configuration Debug build

Wymagane są Xcode 16+ i SDK macOS 26. Ścieżki kodu Liquid Glass są ograniczone do macOS 26 — budowanie ze starszym SDK nadal działa, ale aplikacja korzysta wtedy z NSVisualEffectView w czasie działania.

Zanim uznasz, że zmiana nie działa, uruchom aplikację raz i przyznaj uprawnienie Dostępność. Bez niego przełącznik się nie uruchamia, więc ⌘Tab po prostu nic nie robi — zobacz Szybki start.

Uruchamianie testów

# whole suite
xcodebuild -scheme "BetterCmdTab Debug" -destination 'platform=macOS' test

# one suite
xcodebuild -scheme "BetterCmdTab Debug" -destination 'platform=macOS' \
  test -only-testing:BetterCmdTabTests/FuzzyMatchTests

Testy używają Swift Testing (import Testing, @Suite / @Test), a nie XCTest. Nie ma metod testXxx(), dlatego pojedynczy przypadek należy wskazać nazwą jego funkcji Swift:

xcodebuild -scheme "BetterCmdTab Debug" -destination 'platform=macOS' \
  test -only-testing:BetterCmdTabTests/FuzzyMatchTests/noMatch

Obejmują wyłącznie czystą logikę — metryki przełącznika, etykiety wierszy, filtrowanie katalogu, dopasowanie rozmyte, analizę aktualizacji, wybór Liquid Glass i przenośność ustawień. Zachowanie UI jest sprawdzane ręcznie: przełącznik potrzebuje działającego WindowServer i uprawnienia Dostępność, dlatego ten obszar nie działa w środowisku bez interfejsu graficznego i nie należy do testów jednostkowych.

Gdzie znajdują się poszczególne elementy

Kod jest niewielki. Od tych plików warto zacząć lekturę.

ŚcieżkaDziałanie
Input/HotkeyTap.swiftGlobalne przechwytywanie CGEvent we własnym wątku; wykrywa skrót ⌘Tab i blokuje natywny przełącznik
Switcher/SwitcherController.swiftMaszyna stanów — zaznaczanie, skok po literze, wyszukiwanie, przechodzenie do kart
Switcher/SwitcherView.swiftUkłada widoki listy / siatki / podglądu okien
Switcher/SwitcherPanel.swiftNieaktywujący panel i przypinanie jego aktywnego stanu
Catalog/AppCatalog.swiftWylicza aplikacje i okna przez Accessibility API
Catalog/AppCatalogCache.swiftPrzyrostowa pamięć podręczna zasilana obserwatorami AX i aktualizacjami MRU
Windows/Activator.swiftAktywowanie, podnoszenie, zamykanie, ukrywanie, kończenie
Windows/MRUTracker.swiftKolejność według ostatniego użycia
System/PrivateAPIs.swiftCały prywatny kod CGS / SkyLight, odizolowany w jednym pliku na potrzeby przeglądu
Settings/Natywne okno ustawień AppKit, jeden kontroler na panel

Dodawanie preferencji

Preferencje są kontraktem, a nie tylko zmienną — trzeba zaktualizować kilka elementów.

  1. Dodaj klucz do wyliczenia Keys w App/Preferences.swift, z prefiksem Switcher.. Ciąg klucza jest kontraktem: CatalogFilter i SwitcherController odczytują niektóre klucze bezpośrednio z UserDefaults w wątku tła, więc zmiana nazwy wymaga aktualizacji obu stron.
  2. Dodaj odpowiednią właściwość @Published z didSet, który ją zapisuje. Zabezpiecz zapis przez guard oldValue != newValue else { return } — to zabezpieczenie powstrzymuje reloadFromDefaults() przed ponownym zapisywaniem każdego klucza podczas importu.
  3. Dodaj odpowiedni odczyt do reloadFromDefaults() wraz z wartością domyślną.
  4. Udokumentuj ją w App/ConfigSchemaDocs.swift. Zasila to generowany schema.json, więc pominięty tutaj klucz jest prawidłowy, ale nieudokumentowany — bez uzupełniania w edytorze i dokumentacji po wskazaniu kursorem.
  5. Udostępnij ją we właściwym panelu ustawień. Wszystko, co niestabilne lub nowe, trafia do domyślnie wyłączonego panelu Eksperymentalne.
  6. Jeśli wpływa na czystą logikę, dodaj test.

Nowe klucze są automatycznie uwzględniane przez eksport/import i plik konfiguracyjny — oba mechanizmy przechodzą przez całą przestrzeń nazw Switcher.*, zamiast korzystać z ręcznie przygotowanej listy.

Dokumentacja konfiguracji na tej stronie jest generowana z kopii tego samego pliku schema.json. Po dodaniu preferencji odśwież ją, aby dokumentacja nie pozostawała w tyle — zobacz docs/README.md.

Lista kontrolna pull requestu

  • Projekt buduje się bez błędów i nowych ostrzeżeń.
  • Istniejące testy nadal przechodzą; nowa funkcja z czystą logiką zawiera co najmniej jeden test.
  • Bez zakomentowanego kodu, martwych gałęzi i pozostawionego print — logowanie przez Log.* (os.Logger).
  • Jeden logiczny zakres zmian na PR. Refaktoryzacje oddziel od zmian zachowania.
  • Komunikaty commitów mają postać type: short summaryfix:, feat:, perf:, refactor:, docs:, chore: — a treść wyjaśniająca dlaczego jest zawijana do około 72 znaków.

Zgłaszanie błędu

Otwórz zgłoszenie i podaj:

  1. Wersję macOS (sw_vers)
  2. Wersję BetterCmdTab (pasek menu → Informacje)
  3. Kroki odtworzenia — dokładną sekwencję klawiszy, otwarte aplikacje i używany monitor
  4. Oczekiwane zachowanie oraz to, co faktycznie się wydarzyło
  5. Krótkie nagranie ekranu, jeśli problem jest wizualny (migotanie fokusu, układ, renderowanie szkła)

W przypadku awarii dołącz plik .ips z ~/Library/Logs/DiagnosticReports/.

Proponowanie funkcji

Opisz oczekiwany sposób pracy, a nie implementację. „Chcę filtrować przełącznik według kategorii aplikacji” jest bardziej użyteczne niż „dodaj listę rozwijaną kategorii” — implementację można przedyskutować, ale to podstawowa potrzeba kieruje projektem.

Bezpieczeństwo

Jeśli znajdziesz lukę — cokolwiek, co pozwala zewnętrznej aplikacji odczytywać stan przełącznika, przechwytywać skróty lub zwiększać uprawnienia za pomocą Dostępności przyznanej BetterCmdTab — otwórz prywatne zgłoszenie bezpieczeństwa, a nie publiczne zgłoszenie.

Licencja

BetterCmdTab jest objęty licencją GPL v3. Wysyłając swój wkład, zgadzasz się, że Twoja praca również jest objęta tą licencją.

Na tej stronie