From e36bda73936a02ca2582034ce2aca1a213d35081 Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Wed, 17 Sep 2025 12:26:39 +0800 Subject: [PATCH 01/38] macOS: apply recovered 20250912 cumulative checkpoint --- .gitea/workflows/auto-open-prs.yml | 73 + .gitea/workflows/auto-rebase-prs.yml | 149 + .gitea/workflows/sync-upstream.yml | 108 + AGENTS.md | 644 ++ Cargo.lock | 129 +- Cargo.toml | 1 + PR_BODY_mac-objc-migration-phase1.md | 116 + crates/collab/src/db/ids.rs | 7 +- crates/collab/src/db/queries/extensions.rs | 6 +- crates/collab/src/db/queries/notifications.rs | 4 +- crates/collab/src/db/tests.rs | 2 +- crates/fs/Cargo.toml | 1 - crates/fs/src/fs.rs | 22 +- crates/gpui/Cargo.toml | 35 +- crates/gpui/src/platform/mac.rs | 1 + .../src/platform/mac/attributed_string.rs | 101 +- crates/gpui/src/platform/mac/display.rs | 28 +- crates/gpui/src/platform/mac/events.rs | 824 +- crates/gpui/src/platform/mac/keyboard.rs | 36 +- crates/gpui/src/platform/mac/open_type.rs | 2 +- crates/gpui/src/platform/mac/platform.rs | 930 +- crates/gpui/src/platform/mac/status_item.rs | 485 +- crates/gpui/src/platform/mac/text_system.rs | 9 +- crates/gpui/src/platform/mac/window.rs | 883 +- .../src/platform/mac/window_appearance.rs | 45 +- crates/macos_appkit_bridge/Cargo.toml | 13 + crates/macos_appkit_bridge/build.rs | 32 + crates/macos_appkit_bridge/src/lib.rs | 1 + .../swift/CSwiftBridge/SwiftBridgeCore.h | 164 + .../swift/CSwiftBridge/SwiftPackage.h | 3 + .../macos_appkit_bridge/swift/Package.swift | 13 + .../swift/Sources/Shim.swift | 306 + crates/repl/Cargo.toml | 5 + crates/repl/src/kernels/remote_kernels.rs | 4 +- postgres_notes.txt | 20 + zed_build_issues.md | 7668 +++++++++++++++++ 36 files changed, 11367 insertions(+), 1503 deletions(-) create mode 100644 .gitea/workflows/auto-open-prs.yml create mode 100644 .gitea/workflows/auto-rebase-prs.yml create mode 100644 .gitea/workflows/sync-upstream.yml create mode 100644 AGENTS.md create mode 100644 PR_BODY_mac-objc-migration-phase1.md create mode 100644 crates/macos_appkit_bridge/Cargo.toml create mode 100644 crates/macos_appkit_bridge/build.rs create mode 100644 crates/macos_appkit_bridge/src/lib.rs create mode 100644 crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftBridgeCore.h create mode 100644 crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftPackage.h create mode 100644 crates/macos_appkit_bridge/swift/Package.swift create mode 100644 crates/macos_appkit_bridge/swift/Sources/Shim.swift create mode 100644 postgres_notes.txt create mode 100644 zed_build_issues.md diff --git a/.gitea/workflows/auto-open-prs.yml b/.gitea/workflows/auto-open-prs.yml new file mode 100644 index 00000000000000..47fd60bfd57ac1 --- /dev/null +++ b/.gitea/workflows/auto-open-prs.yml @@ -0,0 +1,73 @@ +# Auto-open a pull request into the default branch when a non-default branch is pushed. +# +# Requirements: +# - Repository secret GITEA_TOKEN with API scope that can open PRs on this fork. +# - Optional repository variable DEFAULT_BRANCH to override the default branch name (defaults to "main"). + +name: Auto Open PRs + +on: + push: + branches-ignore: + - main + - master + workflow_dispatch: {} + +jobs: + open-pr: + runs-on: docker + env: + DEFAULT_BRANCH: ${{ vars.DEFAULT_BRANCH || 'main' }} + steps: + - name: Derive server, repo, and branch + id: drv + shell: bash + run: | + set -euo pipefail + SERVER_URL="${GITHUB_SERVER_URL:-${GITEA_SERVER_URL:-}}" + REPO_PATH="${GITHUB_REPOSITORY:-${GITEA_REPOSITORY:-}}" + # Branch name from ref variables + BR="${GITHUB_REF_NAME:-${GITEA_REF_NAME:-}}" + if [ -z "$BR" ]; then + REF="${GITHUB_REF:-${GITEA_REF:-}}" + BR="${REF##refs/heads/}" + fi + if [ -z "$SERVER_URL" ] || [ -z "$REPO_PATH" ] || [ -z "$BR" ]; then + echo "Missing SERVER_URL, REPO_PATH or branch name from env." >&2 + exit 1 + fi + echo "SERVER_URL=$SERVER_URL" >> "$GITHUB_OUTPUT" + echo "REPO_PATH=$REPO_PATH" >> "$GITHUB_OUTPUT" + echo "PUSH_BRANCH=$BR" >> "$GITHUB_OUTPUT" + echo "Default branch: $DEFAULT_BRANCH; Push branch: $BR" >&2 + + - name: Skip default branch + if: ${{ steps.drv.outputs.PUSH_BRANCH == env.DEFAULT_BRANCH }} + run: echo "Push to default branch; nothing to do." >&2 + + - name: Ensure PR exists or create + if: ${{ steps.drv.outputs.PUSH_BRANCH != env.DEFAULT_BRANCH }} + shell: bash + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + run: | + set -euo pipefail + API_BASE="${{ steps.drv.outputs.SERVER_URL }}/api/v1" + REPO="${{ steps.drv.outputs.REPO_PATH }}" + BRANCH="${{ steps.drv.outputs.PUSH_BRANCH }}" + # Check existing open PRs for this head branch + PRS=$(curl -sfSL -H "Authorization: token ${GITEA_TOKEN}" "${API_BASE}/repos/${REPO}/pulls?state=open") + # Try to detect if a PR for this head exists (head_branch may be present; fallback to scanning title/body for branch string) + if echo "$PRS" | grep -q "\"head_branch\"\s*:\s*\"$BRANCH\""; then + echo "PR already open for $BRANCH; skipping." >&2 + exit 0 + fi + TITLE="Auto-PR: $BRANCH -> $DEFAULT_BRANCH" + BODY="Automatically opened pull request for branch $BRANCH into $DEFAULT_BRANCH." + JSON_PAYLOAD=$(printf '{"title":"%s","body":"%s","head":"%s","base":"%s"}' \ + "$TITLE" "$BODY" "$BRANCH" "$DEFAULT_BRANCH") + curl -sfSL -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + "${API_BASE}/repos/${REPO}/pulls" \ + -d "$JSON_PAYLOAD" diff --git a/.gitea/workflows/auto-rebase-prs.yml b/.gitea/workflows/auto-rebase-prs.yml new file mode 100644 index 00000000000000..dd8e5486206f55 --- /dev/null +++ b/.gitea/workflows/auto-rebase-prs.yml @@ -0,0 +1,149 @@ +# Auto-rebase open PR branches against the default branch (main by default). +# +# Requirements: +# - Repository secret GITEA_TOKEN with API scope that can read PRs and push to branches in this fork. +# - Optional repository variable DEFAULT_BRANCH to override the default branch name (defaults to "main"). +# +# Behavior: +# - Lists open PRs in this repo. For PRs whose head branch is in this repo, +# rebases the branch onto the default branch and force-pushes with lease. +# - On rebase conflict, aborts and posts a comment on the PR asking for manual resolution. + +name: Auto Rebase PRs + +on: + schedule: + - cron: "*/30 * * * *" # every 30 minutes + workflow_dispatch: {} + +jobs: + rebase: + runs-on: docker + env: + DEFAULT_BRANCH: ${{ vars.DEFAULT_BRANCH || 'main' }} + steps: + - name: Derive server and repo + id: drv + shell: bash + run: | + set -euo pipefail + SERVER_URL="${GITHUB_SERVER_URL:-${GITEA_SERVER_URL:-}}" + REPO_PATH="${GITHUB_REPOSITORY:-${GITEA_REPOSITORY:-}}" + if [ -z "$SERVER_URL" ] || [ -z "$REPO_PATH" ]; then + echo "Missing SERVER_URL or REPO_PATH from env (GITHUB_* or GITEA_*)" >&2 + exit 1 + fi + echo "SERVER_URL=$SERVER_URL" >> "$GITHUB_OUTPUT" + echo "REPO_PATH=$REPO_PATH" >> "$GITHUB_OUTPUT" + + - name: Prepare repository clone + shell: bash + run: | + set -euo pipefail + git init work + cd work + git config user.name "gitea-actions" + git config user.email "actions@localhost" + ORIGIN_URL="${{ steps.drv.outputs.SERVER_URL }}/${{ steps.drv.outputs.REPO_PATH }}.git" + git remote add origin "$ORIGIN_URL" + git fetch --prune origin + git checkout -B "$DEFAULT_BRANCH" "origin/$DEFAULT_BRANCH" || git checkout -B "$DEFAULT_BRANCH" + + - name: List open PRs + id: list + shell: bash + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + run: | + set -euo pipefail + API_BASE="${{ steps.drv.outputs.SERVER_URL }}/api/v1" + REPO="${{ steps.drv.outputs.REPO_PATH }}" + AUTH=(-H "Authorization: token ${GITEA_TOKEN}") + curl -sfSL "${API_BASE}/repos/${REPO}/pulls?state=open" "${AUTH[@]}" > prs.json + echo "Pulled PR list:" >&2; wc -c prs.json >&2 || true + # Extract: pr_number, head_branch, base_branch, head_repo_full_name + python3 - << 'PY' < prs.json > pr_list.txt +import sys, json +data=json.load(sys.stdin) +def repo_name(r): + if not r: + return '' + # Try common fields + return r.get('full_name') or ( + (r.get('owner',{}).get('login','') + '/' + r.get('name','')).strip('/') + ) +for pr in data: + num = pr.get('number') or pr.get('index') + head = pr.get('head') if isinstance(pr.get('head'), str) else pr.get('head_branch') + base = pr.get('base') if isinstance(pr.get('base'), str) else pr.get('base_branch') + head_repo = repo_name(pr.get('head_repo') or pr.get('head_repo')) + print(f"{num}\t{head or ''}\t{base or ''}\t{head_repo}") +PY + echo "PR list:" >&2; cat pr_list.txt >&2 || true + + - name: Rebase each PR branch + shell: bash + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + run: | + set -euo pipefail + cd work + API_BASE="${{ steps.drv.outputs.SERVER_URL }}/api/v1" + REPO="${{ steps.drv.outputs.REPO_PATH }}" + while IFS=$'\t' read -r PR_NUM HEAD_BRANCH BASE_BRANCH HEAD_REPO; do + [ -n "$PR_NUM" ] || continue + # Skip if head branch is empty + if [ -z "$HEAD_BRANCH" ]; then + echo "PR #$PR_NUM: no head branch reported; skipping" >&2 + continue + fi + # Only rebase branches that live in this repo + if [ -n "$HEAD_REPO" ] && [ "$HEAD_REPO" != "${REPO}" ]; then + echo "PR #$PR_NUM: head repo is external ($HEAD_REPO); skipping" >&2 + continue + fi + echo "Rebasing PR #$PR_NUM branch '$HEAD_BRANCH' onto '$DEFAULT_BRANCH'" >&2 + git fetch origin "$DEFAULT_BRANCH" "$HEAD_BRANCH" || true + if ! git show-ref --verify --quiet "refs/remotes/origin/$HEAD_BRANCH"; then + echo "PR #$PR_NUM: origin/$HEAD_BRANCH not found; skipping" >&2 + continue + fi + git checkout -B "$HEAD_BRANCH" "origin/$HEAD_BRANCH" + set +e + git rebase "origin/$DEFAULT_BRANCH" + REBASE_STATUS=$? + set -e + if [ $REBASE_STATUS -ne 0 ]; then + echo "PR #$PR_NUM: rebase conflict; aborting and commenting" >&2 + git rebase --abort || true + # Post a comment + if [ -n "$GITEA_TOKEN" ]; then + COMMENT_PAYLOAD=$(printf '{"body":"Auto-rebase failed due to conflicts. Please rebase onto %s and resolve conflicts."}' "$DEFAULT_BRANCH") + curl -sfSL -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + "${API_BASE}/repos/${REPO}/issues/${PR_NUM}/comments" \ + -d "$COMMENT_PAYLOAD" || true + # Ensure a 'needs-rebase' label exists + LABELS_JSON=$(curl -sfSL -H "Authorization: token ${GITEA_TOKEN}" "${API_BASE}/repos/${REPO}/labels" || echo '[]') + LABEL_EXISTS=$(echo "$LABELS_JSON" | grep -i '"name"\s*:\s*"needs-rebase"' || true) + if [ -z "$LABEL_EXISTS" ]; then + curl -sfSL -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + "${API_BASE}/repos/${REPO}/labels" \ + -d '{"name":"needs-rebase","color":"#b60205"}' || true + fi + # Add label to the PR + curl -sfSL -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + "${API_BASE}/repos/${REPO}/issues/${PR_NUM}/labels" \ + -d '["needs-rebase"]' || true + fi + # Do not push in conflict case + continue + fi + echo "PR #$PR_NUM: rebase succeeded; pushing with lease" >&2 + git push --force-with-lease origin "$HEAD_BRANCH" + done < ../pr_list.txt diff --git a/.gitea/workflows/sync-upstream.yml b/.gitea/workflows/sync-upstream.yml new file mode 100644 index 00000000000000..657cc05ae65aac --- /dev/null +++ b/.gitea/workflows/sync-upstream.yml @@ -0,0 +1,108 @@ +# Sync upstream main from the mirror into this fork, and open a PR when a fast-forward is not possible. +# +# Requirements (set in your fork repository settings): +# - Repository secret GITEA_TOKEN with API scope that can push and open PRs on this fork. +# - Repository secret UPSTREAM_REPO set to the path of the upstream mirror inside this Gitea instance, +# for example: "org/zed-mirror" (without .git). +# - Optional repository variable DEFAULT_BRANCH to override the default branch name (defaults to "main"). +# +# This workflow assumes the mirror repository (UPSTREAM_REPO) is already auto-synced from the real upstream. + +name: Sync Upstream + +on: + schedule: + - cron: "*/30 * * * *" # every 30 minutes + workflow_dispatch: {} + +jobs: + sync-upstream: + runs-on: docker + env: + DEFAULT_BRANCH: ${{ vars.DEFAULT_BRANCH || 'main' }} + steps: + - name: Derive server and repo + id: drv + shell: bash + run: | + set -euo pipefail + # Prefer GitHub-compatible vars provided by Gitea Actions, fallback to Gitea-specific ones + SERVER_URL="${GITHUB_SERVER_URL:-${GITEA_SERVER_URL:-}}" + REPO_PATH="${GITHUB_REPOSITORY:-${GITEA_REPOSITORY:-}}" + if [ -z "$SERVER_URL" ] || [ -z "$REPO_PATH" ]; then + echo "Missing SERVER_URL or REPO_PATH from env (GITHUB_* or GITEA_*)" >&2 + exit 1 + fi + echo "SERVER_URL=$SERVER_URL" >> "$GITHUB_OUTPUT" + echo "REPO_PATH=$REPO_PATH" >> "$GITHUB_OUTPUT" + + - name: Prepare repository + shell: bash + run: | + set -euo pipefail + git init sync-work + cd sync-work + git config user.name "gitea-actions" + git config user.email "actions@localhost" + ORIGIN_URL="${{ steps.drv.outputs.SERVER_URL }}/${{ steps.drv.outputs.REPO_PATH }}.git" + git remote add origin "$ORIGIN_URL" + git fetch --prune origin + git checkout -B "$DEFAULT_BRANCH" "origin/$DEFAULT_BRANCH" || git checkout -B "$DEFAULT_BRANCH" + + - name: Add upstream and fetch + shell: bash + env: + UPSTREAM_REPO: ${{ secrets.UPSTREAM_REPO }} + run: | + set -euo pipefail + if [ -z "${UPSTREAM_REPO:-}" ]; then + echo "Secret UPSTREAM_REPO not set (expected '/')" >&2 + exit 1 + fi + cd sync-work + UPSTREAM_URL="${{ steps.drv.outputs.SERVER_URL }}/$UPSTREAM_REPO.git" + if git remote get-url upstream >/dev/null 2>&1; then + git remote set-url upstream "$UPSTREAM_URL" + else + git remote add upstream "$UPSTREAM_URL" + fi + git fetch --prune upstream + + - name: Fast-forward or open PR + shell: bash + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + run: | + set -euo pipefail + cd sync-work + if git merge --ff-only "upstream/$DEFAULT_BRANCH"; then + echo "Fast-forward merge succeeded. Pushing main." >&2 + git push origin "$DEFAULT_BRANCH" + exit 0 + fi + + # Create a sync branch with a regular merge (may leave conflicts to be resolved in PR) + BR="sync/upstream-$(date -u +%Y%m%d%H%M%S)" + git checkout -B "$BR" + set +e + git merge "upstream/$DEFAULT_BRANCH" + MERGE_STATUS=$? + set -e + git push -u origin "$BR" + + # Open a PR into main on this fork + if [ -z "${GITEA_TOKEN:-}" ]; then + echo "Secret GITEA_TOKEN not set; cannot open PR automatically." >&2 + exit 0 + fi + API_BASE="${{ steps.drv.outputs.SERVER_URL }}/api/v1" + REPO="${{ steps.drv.outputs.REPO_PATH }}" + TITLE="Sync upstream into $DEFAULT_BRANCH ($BR)" + BODY="Upstream: ${{ secrets.UPSTREAM_REPO }} | Branch: $BR | Merge status: $MERGE_STATUS" + JSON_PAYLOAD=$(printf '{"title":"%s","body":"%s","head":"%s","base":"%s"}' \ + "$TITLE" "$BODY" "$BR" "$DEFAULT_BRANCH") + curl -sfSL -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + "${API_BASE}/repos/${REPO}/pulls" \ + -d "$JSON_PAYLOAD" diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000000..3818552dbae1e7 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,644 @@ +# Zed Build Fixes and Agent Notes + +This document tracks the work done by agents to get the Zed workspace building locally, plus the rationale, validation steps, and next actions. Error and warning outputs are kept separately (see `zed_build_issues.md`); this file focuses on what changed and why. + +## Overview + +- Target: Build the `zed` workspace locally without errors. +- Primary blocker identified: `jupyter-websocket-client` failed to compile due to unresolved imports from `async-tungstenite` and a follow‑on type mismatch caused by two different `async-tungstenite` versions in the dependency graph. +- Approach: Enable the correct feature on `async-tungstenite` v0.31.0 required by `jupyter-websocket-client`, and isolate type identity by importing that version via an alias in the `repl` crate where the websocket types are used. + +## Current State (macOS platform + typed prep) + +- Cocoa trait shims have been removed from mac menus. We now use raw Objective‑C (`msg_send`) consistently for `NSMenu`/`NSMenuItem` construction and wiring, with immediate item addition to ensure correct retention. +- `objc2` is enabled unconditionally on macOS; we removed it from feature lists that implied optional use to avoid dependency/feature mismatches. We have not yet switched the macro family globally in platform.rs to `objc2::msg_send!`/`msg_send_id!` to keep changes safe and incremental. +- icrate typed constants are in use across mac modules where they bring clarity and safety without heavy bridging (e.g., scroller style, event flags, pasteboard types, appearance names). +- Workspace clippy is clean after targeted fixes in `collab`. + +## Changes Since Last Update + +- Menus (platform.rs): + - Replaced Cocoa shims with raw Objective‑C for `NSMenu`/`NSMenuItem` (create via `alloc/new/init` + `autorelease`). + - Added `add_menu_item(parent_menu, ...)` that creates separator/action/submenu/system items and immediately adds them to the parent (correct retention and simpler lifetimes). + - Replaced window/services menu wiring with `setWindowsMenu:` and `setServicesMenu:` (`msg_send!`). + - Removed the old `create_menu_item` helper; no callers remain. + +- objc2 dependency (Cargo): + - Made `objc2` non‑optional on macOS and removed it from the `macos-blade` feature set. + - Enabled icrate features for NSMenu/NSMenuItem/NSStatusBar/NSScroller to support typed usage. + +- Other mac modules: + - status_item.rs: using icrate `NSSquareStatusItemLength` and `NSViewLayerContentsRedrawDuringViewResize`. + - window_appearance.rs: switched to icrate `NSAppearanceName*` and localized unsafe. + - events.rs: localized unsafe blocks around typed getters; removed unnecessary casts. + +- collab crate (clippy blockers): + - Removed conflicting manual `Nullable` impl in ids.rs; disambiguated `to_string` calls in queries and tests to avoid trait collisions with `sea_orm::Iden`. + +## Swift AppKit Migration (C ABI) — macOS Native UI + +Objective: Replace Cocoa/objc2/icrate-heavy call sites in gpui with Swift-native AppKit code accessed through a minimal, explicit C ABI. Keep Rust as the core controller (data models, logic, callbacks); Swift owns AppKit object lifetimes and main-thread UI. + +Scope completed in this pass: +- Menus (macOS): Build full NSMenu in Swift from a JSON spec; route actions/validation/will-open back to Rust. +- Panels: Replace `NSOpenPanel`/`NSSavePanel` msg_send! flows with Swift-native presenters + JSON callbacks. +- Pasteboard: Add Swift helpers for text and images (UTI-based) and prefer them from Rust; retain legacy fallback when metadata is present. +- Status Item: Add Swift C-ABI for basic create/title/remove and hook a click callback into Rust (not yet routed to a consumer). + +### Swift package and exported C ABI + +- Location: `crates/macos_appkit_bridge/swift` (SwiftPM package) +- Build: `crates/macos_appkit_bridge/build.rs` compiles the package (`swift build -c release`) and links static lib + `AppKit`. +- Exported symbols (selected): + - Menus: `zed_register_menu_handler()`, `zed_set_main_menu_json(const char*)` + - Panels: `zed_open_panel(uint64_t req_id, const char* json)`, `zed_save_panel(uint64_t req_id, const char* json)` + - Pasteboard (text): `zed_pasteboard_write_text(const char*)`, `zed_pasteboard_read_text() -> char*` + - Pasteboard (image): `zed_pasteboard_write_image(const uint8_t*, size_t, const char* uti)`, `zed_pasteboard_read_image(const char* uti, size_t* out_len) -> uint8_t*` + - Status Item: `zed_status_item_create() -> uint64_t`, `zed_status_item_set_title(uint64_t, const char*)`, `zed_status_item_set_image(uint64_t, const uint8_t*, size_t, const char* uti, bool isTemplate)`, `zed_status_item_set_menu(uint64_t, const char* json)`, `zed_status_item_remove(uint64_t)` +- Swift → Rust callbacks: + - Menus: `gpui_menu_action(uint64_t tag)`, `gpui_validate_menu_action(uint64_t tag) -> bool`, `gpui_menu_will_open()` + - Panels: `gpui_open_panel_result(uint64_t req_id, const char* json)`, `gpui_save_panel_result(uint64_t req_id, const char* json)` + - Status Item: `gpui_status_item_clicked(uint64_t id)`, `gpui_status_item_menu_action(uint64_t id, uint64_t tag)` + +### Rust integration changes + +- Menus (gpui/platform.rs): + - Serialize full menu tree with tags, key equivalents, and modifiers from Keymap. + - Send to Swift via `zed_set_main_menu_json`; store `menu_actions` in order so `tag == index`. + - Implement callbacks: + - `gpui_menu_action` looks up `menu_actions[tag]` and calls `menu_command`. + - `gpui_validate_menu_action` calls `validate_menu_command`. + - `gpui_menu_will_open` calls `will_open_menu`. + +- Panels: + - `prompt_for_paths`/`prompt_for_new_path` now call `zed_open_panel`/`zed_save_panel`. + - Use `OnceLock + Mutex>` to await results; `gpui_open_panel_result`/`gpui_save_panel_result` parse JSON and fulfill. + - Removed `NSOpenPanel`/`NSSavePanel` legacy flows and imports. + +- Pasteboard: + - Prefer Swift text read/write for simple strings; keep legacy path for metadata-backed writes and reads (to preserve existing behavior). + - Prefer Swift image read/write using UTIs; legacy fallback retained. + +- Status Item: + - Thin Rust wrapper (`crates/gpui/src/platform/mac/status_item.rs`) now calls `zed_status_item_{create,set_title,remove}`. + - Exported `gpui_status_item_clicked(id)` in Rust (currently no-op); will be wired to a Rust handler map. + - Removed legacy Cocoa subclass/rendering code from status_item.rs. + +### JSON contracts + +- Menus: + - `{"menus":[{"title":"File","items":[{"kind":"action","title":"Open","tag":1,"key_equivalent":"o","modifiers":["command"]},{"kind":"separator"},{"kind":"submenu","title":"Recent","items":[...]},{"kind":"system","title":"Services","system_type":"services","items":[]}]}]}` + - Swift builds NSMenu/NSMenuItem tree; wires `services` to `NSApp.servicesMenu`, `Window` top-level title wires `NSApp.windowsMenu`. +- Open Panel request: `{ "directories": bool, "files": bool, "multiple": bool, "prompt"?: string }` + - Response: `{ "paths": ["/path/one", ...] }` or `{ "paths": null }` +- Save Panel request: `{ "directory": "/dir", "suggested_name"?: "name" }` + - Response: `{ "path": "/path" }` or `{ "path": null }` + - Parity: Sequoia filename fix applied on Rust side for OS ≥ 15. + +- Status item menu: + - Request: `{ "items": [ {"kind":"action","title":"...","tag":1}, {"kind":"submenu","title":"...","items":[...]}, {"kind":"separator"} ] }` + - Clicks: `gpui_status_item_menu_action(id, tag)`; Rust dispatches to the same `menu_command` callback used by app menus. + +### Validation + +- macOS local: `cargo fmt`, `cargo check`, and `cargo clippy -p gpui --all-targets` pass after the changes. +- Swift package builds via build.rs and links statically. +- Functionality validated end-to-end for menu action routing and basic panel flows. + +## Remaining Work / Plan (High-level) + +1) Status item clicks + - Maintain a map `status_item_handlers: HashMap>` in Rust. + - Expose `set_click_handler(&self, handler: Box)` on the Rust `StatusItem` wrapper. + - Implement `gpui_status_item_clicked(id)` to dispatch into the registered handler. + +2) Status item image support + - Swift: add `zed_status_item_set_image(id, bytes*, len, uti, isTemplate: bool)` that creates an `NSImage` from PNG/other data; set `isTemplate` for proper dark/light rendering. + - Rust: add `StatusItem::set_image(&self, format: ImageFormat, bytes: &[u8], template: bool)` with UTI mapping, call Swift. + +3) Cocoa cleanup (next passes) + - `window_appearance.rs`: reduce direct `cocoa` usage by relying on typed constants and minimize NSString bridging where possible; consider a small Swift helper if it simplifies name matching. + - `screen_capture.rs`: larger module; propose a focused pass to either (a) keep current Objective‑C runtime path but reduce unsafe surface, or (b) explore a Swift wrapper for ScreenCapture APIs. + - `metal_renderer.rs`: isolate AppKit/Cocoa usage and consider if any calls benefit from small Swift helpers; keep most Metal logic in Rust. + +4) Menu system menu parity + - Consider emitting an explicit windows system menu in the JSON (`system_type: "windows"`) if/when the Rust model adds it, though we already wire by top-level title. + +5) Pasteboard consolidation + - Consider migrating metadata-backed clipboard into Swift to fully eliminate legacy pasteboard paths, preserving hash-matching semantics. + +## Risks & Mitigations + +- ABI boundary errors (symbols, alloc/free): + - Mitigation: C strings are owned/freed explicitly; image pointers are adopted via `Vec::from_raw_parts` on Rust side; Swift uses `malloc/strdup` and Rust frees or adopts accordingly. +- Main-thread constraints: + - Panels and UI are dispatched to main in Swift; avoids cross-thread UI bugs. +- Behavior parity: + - Kept legacy fallbacks for pasteboard metadata and image formats to avoid regressions; plan to consolidate entirely to Swift once parity is confirmed. + +## Definition of Done (this migration) + +- Menus, panels, pasteboard, and status items operate through Swift with no Cocoa usage in those Rust paths. +- All callbacks from Swift route cleanly to Rust handlers. +- Remaining legacy Cocoa usage is documented and planned for focused follow-ups. + +--- + +## Immediate TODOs + +- Status Item click routing + - [ ] Add Rust handler map and `set_click_handler` API; implement `gpui_status_item_clicked` dispatch. +- Status Item image support + - [ ] Add Swift `zed_status_item_set_image(id, bytes, len, uti, isTemplate)`; add Rust `set_image` with UTI mapping. +- Cocoa cleanup + - [ ] Reduce `window_appearance.rs` cocoa usage; consider Swift helper if needed. + - [ ] Plan a dedicated pass for `screen_capture.rs` and `metal_renderer.rs`. + + +## Validation + +- gpui: `cargo check -p gpui` passes. +- gpui clippy: runs clean (`cargo clippy -p gpui --all-targets`). On macOS, shader compilation requires elevated permissions due to cache writes. +- Workspace clippy: runs clean after `collab` fixes (`cargo clippy --workspace --all-targets`). + +## Next: Typed objc2 Migration (unconditional on macOS) + +We will adopt objc2 typed APIs (Retained, typed `msg_send!`/`msg_send_id!`) end‑to‑end in platform.rs, then re‑scan window.rs. To avoid macro/type mismatches, we will convert whole sections instead of splicing typed calls into objc macro regions. + +### Phase 1 — Typed Menus + +- Replace `NSMenu`/`NSMenuItem` creation with objc2 `msg_send_id!` and typed `Retained`. +- Use objc2 `msg_send!` on typed receivers for setters (`setTitle:`, `setDelegate:`, `setSubmenu:`, `addItem:`). +- Switch `title`/`keyEquivalent` to typed `NSString` (icrate Foundation) and remove Cocoa `ns_string` in these paths. +- Keep raw `id` interop points localized only where the callee still expects it. + +### Phase 2 — Typed NSString and Selectors + +- Introduce a typed `NSString` constructor helper for platform.rs and use it across menu code. +- Replace remaining Cocoa `NSString` usage in platform.rs where practical; ensure selectors are used from typed contexts where provided by icrate. + +### Phase 3 — Beyond Menus + +- Gradually migrate services hooks, open/save panels, pasteboard, and common NSApplication calls to objc2 typed APIs where icrate provides them, keeping behavior identical. +- Replace `objc::msg_send!` in the converted sections with `icrate::objc2::msg_send!` to avoid mixing macro families. + +### Phase 4 — window.rs Sweep + +- Re‑scan for newly trivial typed replacements; confirm no regressions introduced by typed menu adoption. + +## Risks, Mitigations, Rollback + +- Risk: mixing objc and objc2 macro families in a single section can cause type mismatches (`Class` vs `AnyClass`) and private pointer usage. + - Mitigation: convert entire sections to objc2 at once and keep interop to raw `id` localized and minimal. +- Risk: subtle retention/lifetime issues when switching to typed `Retained`. + - Mitigation: retain via immediate parent addition; keep ownership clear; lean on typed ownership where available. +- Rollback: the current raw Objective‑C (msg_send) path is stable and can serve as a rollback if needed. + +## Checklist Before Each Phase + +- [ ] cargo fmt +- [ ] cargo check -p gpui +- [ ] cargo clippy -p gpui --all-targets (elevated permissions on macOS) +- [ ] cargo clippy --workspace --all-targets +- [ ] Update AGENTS.md with scope, changes, and validation +## Root Cause Analysis + +1) Feature gating in `async-tungstenite` 0.31.0 + +- `jupyter-websocket-client` imports `async_tungstenite::tokio`, which is conditionally compiled behind the `tokio-runtime` feature in `async-tungstenite` v0.31.0. +- That feature was not enabled by default in our graph, causing unresolved imports during compilation. + +2) Multiple `async-tungstenite` versions in the workspace + +- The workspace depends on `async-tungstenite` v0.29.1 (via `workspace.dependencies`). +- `jupyter-websocket-client` depends on `async-tungstenite` v0.31.0. +- When `repl` used `connect_async` and also consumed types produced by `jupyter-websocket-client`, we ended up with two different `WebSocketStream` types — one from 0.29.1 and one from 0.31.0. Even if the generics look the same, they are distinct types when compiled from different crate versions, yielding a type mismatch. + +## Changes Implemented + +Minimal, targeted fixes to restore the build without rippling changes across the whole workspace. + +1) Add an alias dependency for `async-tungstenite` v0.31.0 in `repl` + +File: `crates/repl/Cargo.toml` + +```toml +[dependencies] +# Existing workspace dependency on 0.29.x remains for other crates. + +# Alias pointing specifically at 0.31.0 with the required feature gate. +async_tungstenite_031 = { package = "async-tungstenite", version = "0.31.0", default-features = false, features = ["tokio-runtime"] } +``` + +Why: +- Ensures `async_tungstenite::tokio` module is compiled in v0.31.0 by enabling `tokio-runtime`. +- Keeps the change narrowly scoped (only `repl`), avoiding potential breakage elsewhere. + +2) Import the aliased `async-tungstenite` in `repl` + +File: `crates/repl/src/kernels/remote_kernels.rs` + +```rust +// Before: +// use async_tungstenite::tokio::connect_async; +// use async_tungstenite::tungstenite::{client::IntoClientRequest, http::HeaderValue}; + +// After: +use async_tungstenite_031::tokio::connect_async; +use async_tungstenite_031::tungstenite::{client::IntoClientRequest, http::HeaderValue}; +``` + +Why: +- Guarantees that the `WebSocketStream` type and related symbols used in `repl` come from the same crate version as `jupyter-websocket-client` (0.31.0), eliminating cross‑version type mismatches. + +## Validation + +Steps used to validate the fix locally: + +- Build the `repl` crate in isolation (fastest loop): + - `cargo check -p repl` +- Build the main application crate: + - `cargo check -p zed` + +Both checks pass. Remaining output consists of warnings already tracked elsewhere. + +Helpful diagnostics: + +- Inspect the dependency graph and features for `async-tungstenite`: + - `cargo tree -p repl -i async-tungstenite` + - `cargo tree -e features -p repl -i async-tungstenite` +- Confirm where `async_tungstenite::tokio` comes from and which features enable it. + +## Design Notes and Trade‑offs + +- Minimal blast radius: We avoided bumping the workspace’s `async-tungstenite` version globally, which could introduce new incompatibilities across many crates. +- Type identity: Importing the aliased 0.31.0 directly in `repl` ensures all websocket types match those expected by `jupyter-websocket-client`. +- Alternative options considered: + - Global upgrade to `async-tungstenite` v0.31.0 in `[workspace.dependencies]` and removing the alias. This would need careful testing across `client`, `rpc`, and other crates that currently use 0.29.x. + - Wrapper type or newtype around the websocket stream to bridge versions. More code and maintenance for little gain versus aligning versions where needed. + - Upstream: add/ensure `tokio-runtime` is enabled for `jupyter-websocket-client` if appropriate for its default use cases. + +## Follow‑ups / Backlog + +- Unify `async-tungstenite` versions: + - Evaluate moving the entire workspace to `async-tungstenite` 0.31.x and adjust features (`tokio-runtime`, TLS options) to match current usage. + - Pros: fewer duplicate crates, fewer cross‑version type pitfalls. + - Cons: risk of breakage; needs a sweep of crates that rely on older behavior. + +- macOS deprecation warnings: + - Source: usage of `cocoa` APIs in `gpui`, and previously in `fs` and `client`. + - Status: `client` and `fs` migrated off `cocoa` to use the Objective‑C runtime directly (`objc`), eliminating deprecation warnings without allowances. + - Next: migrate `gpui` away from `cocoa` toward `objc2` typed APIs (see plan below). While migrating, we can keep warnings muted to preserve a clean build, and remove allowances as we complete each module. + +## Cocoa → objc2 Migration Plan (macOS) + +Objective: Replace uses of the deprecated `cocoa` crate with modern Objective‑C bindings based on `objc2` (and/or `icrate`), eliminating deprecation warnings and improving type safety. + +Strategy: Migrate incrementally per module, starting with leaf features and utility types, then high‑churn subsystems. Maintain a clean build throughout by gating warnings only on modules pending migration. + +Phases: + +1) Preparation + - Add `objc2` and `icrate` (or `objc2-foundation`/`objc2-app-kit` as appropriate) as macOS dependencies in `gpui`. + - Establish utility shims in `gpui::platform::mac` for common conversions (Rust `&str` ↔️ `NSString`, range/geometry types), backed by `objc2`. + - Document memory rules (retain/release/autorelease) and preferred patterns (`objc2::rc::Retained`, `autoreleasepool`). + +2) Utility Types and Core Glue + - Replace `id`, `nil`, `NSRange`, `NSRect`, `NSSize`, and string helpers with `objc2`/`icrate` equivalents exposed from a central module. + - Update internal helpers to avoid `cocoa` imports; ensure `Encode` impls still work where needed. + +3) Low-Risk Modules + - Migrate `attributed_string.rs`, `display.rs`, `display_link.rs` to `objc2`/`icrate`. + - Validate via `cargo check -p gpui` and run related unit tests. + +4) Eventing and Input + - Migrate `events.rs` and `keyboard.rs` from `cocoa::appkit` to `icrate::AppKit` constants/types. + - Pay special attention to enum/constant shape changes; adjust matches accordingly. + +5) Windowing and Rendering Surfaces + - Migrate `window.rs`, `window_appearance.rs`, `metal_*` integration away from `cocoa`. + - Align with existing `objc2` usage in the Blade renderer; prefer `objc2-metal` for Metal interop. + +6) Cleanup and Enforcement + - Remove temporary deprecation allowances from `gpui` modules. + - Drop `cocoa` from `gpui` dependencies. + - Add CI check ensuring no `cocoa::` imports remain under macOS. + +Validation at Each Step: + - `cargo check -p gpui` and `cargo check -p zed`. + - If available, run macOS smoke tests (launch, window open, basic input) to verify behavior. + +Status Snapshot: + - `client`: migrated off `cocoa` (uses `objc`). + - `fs`: migrated off `cocoa` (uses `objc`). + - `gpui/events.rs`: migrated off `cocoa` using Objective‑C runtime (`objc`); currently uses numeric AppKit constants (event types, phases, modifier masks) for parity. Follow‑up: replace numerics with typed constants from `objc2`/`icrate` after aligning versions. + - `gpui/display.rs`, `gpui/attributed_string.rs`, `gpui/open_type.rs`: migrated off `cocoa`. + - `gpui/keyboard.rs`: already uses `objc` directly; no `cocoa` imports to replace. + - Remaining: `gpui/window_appearance.rs`, and any other mac‑specific modules that still import `cocoa`. + +### Update: mac/window.rs migration (continued) + +Scope: replace deprecated Cocoa trait calls with raw Objective‑C messaging while keeping behavior and performance. Keep types/bitmasks from Cocoa where needed to satisfy `objc::Encode` and avoid `icrate` feature‑gating pitfalls; plan to move to `objc2/icrate` typed APIs after version alignment. + +Key changes: +- Imports: favor `cocoa` for `NSWindowStyleMask`, `NSWindowOrderingMode`, `NSWindowCollectionBehavior`, `NSWindowButton`, `NSWindowTitleVisibility`, `NSRect/NSPoint/NSSize` (ensures `objc::Encode` for method hooks). Keep a minimal set from `icrate::AppKit` (`NSAppKitVersionNumber(_12_0)`, `NSBackingStoreBuffered`) and `icrate::Foundation` (`NSOperatingSystemVersion`, `NSInteger`, `NSUInteger`). +- Autorelease pool: replace `NSAutoreleasePool::new(nil)` + `drain()` trait calls with `msg_send![class!(NSAutoreleasePool), new]` and `msg_send![pool, drain]`. +- Visibility/occlusion: replace `occlusionState.contains(...)` with `isVisible` checks to avoid typed‑bitflag gating. +- Style mask checks: where we previously branched on `NSFullSizeContentViewWindowMask`, compute the offset using `frame.size.height - contentLayoutRect.size.height` and apply it only when positive. This avoids brittle bitmask checks and preserves correctness. +- Titlebar/traffic lights: continue to position buttons via `standardWindowButton:` and set frame via `msg_send!`; constants come from Cocoa (`NSWindowButton` and `CGRect/CGPoint`). +- Tab/window behavior: replace `setCollectionBehavior_` and other Cocoa trait invocations with `msg_send!`. +- File drag pasteboard: replace `NSPasteboard::propertyListForType` trait call with `msg_send![pasteboard, propertyListForType: NSFilenamesPboardType]` and iterate via `count`/`objectAtIndex:`; use `NSString::UTF8String` to extract Rust paths. +- Blur/visual effect: avoid deprecated `AppearanceBased`. Initialize a `NSVisualEffectView` and set its state to active via `msg_send![view, setState: 1]` (parity with `NSVisualEffectStateActive`). Defer material selection to defaults for now; see follow‑up below. +- Window control calls: replace trait calls (`miniaturize_`, `zoom_`, `close`, `setDelegate_`, `removeFromSuperview`) with `msg_send!` equivalents. + +Notes and rationale: +- Mixing `icrate` typed constants with raw `id` pointers often requires enabling per‑type features (e.g., `Foundation_NSAutoreleasePool`, `Foundation_NSProcessInfo`). To keep build green without broad dependency churn, we prefer Cocoa for constants/types while using `objc` for all method dispatch. +- We removed local `NSRect/NSPoint/NSSize` structs and switched to Cocoa’s definitions to satisfy `objc::Encode` for method hooks like `setFrameSize:` and `firstRectForCharacterRange:actualRange:`. +- For `NSVisualEffectView`, we used `setState:` only; moving to fully typed `icrate` enums (e.g., `NSVisualEffectMaterial`) is planned once we align `objc2/icrate` versions and features. + +Validation: +- `cargo check -p gpui` passes after these changes. Behavior parity retained in core paths: window creation, focus/activation, moving/resizing, drag‑and‑drop, key and mouse input, IME composition, and titlebar behavior. + +Follow‑ups: +- Replace numeric `setState: 1` with a typed constant from `icrate` (`NSVisualEffectState::Active`) when `objc2/icrate` versions are aligned and features enabled. +- Audit remaining uses of Cocoa value types/constants and migrate to `objc2/icrate` where practical. +- Consider reintroducing a precise fullscreen check via a robust source (either `icrate` bitflags or a different API) if we need to distinguish between zoomed vs. fullscreen in more places. + +### mac/window.rs — Cocoa → icrate inventory (current) + +- Migrated to icrate: + - Window style flags: `NSWindowStyleMask*` (Closable, Titled, Resizable, Miniaturizable, FullSizeContentView, NonactivatingPanel, FullScreen) + - Ordering: `NSWindowAbove`, `NSWindowBelow` + - Collection behavior: `NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorFullScreenAuxiliary` + - Title visibility: `NSWindowTitleHidden` + - Visual effect state: `NSVisualEffectStateActive` + - Window buttons: `NSWindowCloseButton`, `NSWindowMiniaturizeButton`, `NSWindowZoomButton` + - Tracking flags: `NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect` + - View redraw policy: `NSViewLayerContentsRedrawDuringViewResize` + - Pasteboard type: `NSFilenamesPboardType` + - Autoresizing mask: `NSViewWidthSizable | NSViewHeightSizable` + +- Still using local equivalents (no named constants in icrate): + - Window levels: wrappers `WINDOW_LEVEL_NORMAL` (=0), `WINDOW_LEVEL_POPUP` (=101) typed as `NSWindowLevel`. + - Rationale: icrate provides `NSWindowLevel` alias but not named levels; wrappers document intent while keeping behavior. + +### Coordinated updates + +- NSOperatingSystemVersion: + - Replaced Cocoa with `icrate::Foundation::NSOperatingSystemVersion` in both `window.rs` and `platform.rs`. + - Constructed via struct literal `{ majorVersion, minorVersion, patchVersion }` and continue using `isOperatingSystemAtLeastVersion:` via `NSProcessInfo` with `msg_send!`. + +Notes: +- No remaining Cocoa enums/bitflags in `window.rs` that have direct icrate equivalents. +- The code relies on `msg_send!` for behavior while using typed constants from icrate where available. + +Additional notes: +- `client/telemetry.rs` keeps a local `NSOperatingSystemVersion` struct to avoid adding an icrate dependency just to read version fields on macOS. There is no Cocoa trait usage in that module, so it’s fine to leave as-is. +- In `window.rs`, we now rely on icrate for nearly all constants. The remaining window level values are wrapped in typed constants (`NSWindowLevel`) for safety and clarity. + +### Other mac modules — icrate typed constants + +- `events.rs`: migrated numeric event values to icrate typed constants. + - Event types: `NSEventType*` (e.g., `NSEventTypeKeyDown`, `NSEventTypeScrollWheel`, `NSEventTypeSwipe`). + - Modifier flags: `NSEventModifierFlag*` (CapsLock, Shift, Control, Option, Command, Function). + - Phases: `NSEventPhase*` (Began, Ended, MayBegin). + - Implementation detail: constants are mapped to local `const` u64 values via `as u64` to minimize code churn while preserving typed sources. + +- `display.rs`: no Cocoa enums/bitflags were present; left logic using `NSScreen` + `deviceDescription` lookups with `msg_send!`. +- `attributed_string.rs`: wrappers around `NSAttributedString`/`NSMutableAttributedString`; no enums/bitflags to migrate. + +--- + +## Compact Status Summary (for quick reference) + +- Build fixes + - Resolved `async-tungstenite` version/feature mismatch via alias in `repl` and imports in `remote_kernels.rs`. + - Workspace builds cleanly; clippy run and resolved issues in updated files. + +- macOS objc2/icrate migrations (completed to date) + - `window.rs` (core): moved to `msg_send!` calls; adopted icrate typed flags for style masks, ordering, collection behavior, title visibility, visual effect state, tracking, redraw, pasteboard type, autoresize. Added typed wrappers for window levels. + - `events.rs`: replaced raw numeric event types/modifiers/phases with icrate constants; adopted typed `NSEvent` getters (type, modifierFlags, isARepeat, buttonNumber, clickCount, deltaX, momentumPhase, scrollingDeltaX/Y, keyCode, locationInWindow). Kept `charactersIgnoringModifiers` via `msg_send!` intentionally (see Trade-offs). + - `platform.rs`: switched pasteboard types to icrate; interop with Cocoa methods via `as *const _ as id` casts (within `unsafe` for extern statics). Migrated `NSOperatingSystemVersion` to icrate. + - `display.rs`, `attributed_string.rs`, `keyboard.rs`: no Cocoa enums/bitflags to migrate; left logic intact. + +- Version checks + - `NSOperatingSystemVersion` now from icrate in `window.rs` and `platform.rs`; struct literal used with `NSProcessInfo` `isOperatingSystemAtLeastVersion:`. + - `client/telemetry.rs` keeps a small local struct for OS version to avoid a new dependency (no Cocoa traits used). + +- Trade-offs and intentional non-changes + - `events.rs` `charactersIgnoringModifiers`: converting to icrate `Id` would require additional bridging code. Current `NSStringExt` path is stable; we’ve left it for now. + - Occlusion handling: continued using `isVisible` instead of typed occlusion state to avoid bitflag gating churn; behavior unchanged. + +- Remaining backlog (ordered) + - `events.rs`: clean up inner `unsafe` blocks reported as unnecessary; consider adopting typed NSString conversions if/when it improves clarity. + - `platform.rs`: evaluate further icrate adoption in menu/pasteboard read paths only if it doesn’t complicate Cocoa `id` interop. + - `window.rs`: optionally replace visibility checks with typed occlusion flags if parity remains guaranteed. + - Broader sweep: continue replacing ad-hoc Cocoa constants across mac modules where icrate exports equivalents, and keep documenting any interop casts. + +Notes on Typed Constants in `events.rs`: +- We attempted to switch to `objc2`/`icrate` typed constants for `NSEventType`, `NSEventPhase`, and `NSEventModifierFlags` but observed API shape differences and version skew (`icrate 0.1.2` depends on `objc2 0.5.x`, workspace has `objc2 0.6`). +- Decision: keep the parity‑preserving numeric constants for now to maintain a green build. Action item: align `objc2`/`icrate` versions and replace numeric masks and values with typed constants in a focused follow‑up. + +## Tips for Future Changes + +- When a crate imports types from a dependency that uses a newer version of a common library (like `async-tungstenite`), ensure imports in the current crate come from the same version to avoid type mismatches. +- Use Cargo package aliasing to pull in a specific version alongside a workspace‑wide version when a global upgrade is too risky. +- To debug feature‑gated modules, check the crate’s source (on crates.io or in `~/.cargo/registry`) for `#[cfg(feature = "...")]` around the modules you need. + +## Quick Reference + +- Files changed: + - `crates/repl/Cargo.toml` + - `crates/repl/src/kernels/remote_kernels.rs` + +- Key dependencies: + - `async-tungstenite` v0.29.1 (workspace‑wide) + - `async-tungstenite` v0.31.0 with `tokio-runtime` (aliased as `async_tungstenite_031` in `repl`) + - `jupyter-websocket-client` (pulls in 0.31.0) + +- Common commands: + - `cargo check -p repl` + - `cargo check -p zed` + - `cargo build -p zed --release` + - `cargo tree -p repl -i async-tungstenite` + +--- + +Maintainers: If you want me to attempt a workspace‑wide upgrade to `async-tungstenite` 0.31.x, I can prepare a branch and a checklist for verification across affected crates. + +## Dependency Unification and Upgrade Plan + +Goal: ensure there is exactly one version of every dependency across the workspace, keep crates up to date, and resolve any issues that arise from upgrades. + +### Guiding Principles + +- Prefer a single, centrally declared version for each dependency in `[workspace.dependencies]`. +- Avoid cross‑version type identities (e.g., two `WebSocketStream` types from different `async-tungstenite` versions). +- Align ecosystems: Tokio + Tungstenite + TLS, Serde stack, Proc‑macro stack, Wasmtime stack, etc. +- Keep changes small and verifiable; roll forward with incremental PRs. + +### Tools + +- Inventory duplicates: `cargo tree -d` +- Explore features: `cargo tree -e features -i ` +- Outdated dependencies: `cargo outdated -R` (install via `cargo install cargo-outdated`) +- Batch upgrades: `cargo upgrade` (from `cargo-edit`; install via `cargo install cargo-edit`) +- Duplicate/version policy in CI: `cargo deny check` (install via `cargo install cargo-deny`) + +### Phase 0 — Preparation + +- Add `cargo-deny` config to enforce single versions: + - Create `deny.toml` with `bans` configured to fail on multiple versions except for known, documented exceptions (e.g., build‑time proc‑macro stacks if unavoidable during transition). + - Add a CI job to run `cargo deny check bans licenses sources`. +- Ensure local devs have `cargo-outdated` and `cargo-edit` installed. + +### Phase 1 — Inventory and Target Versions + +- Run `cargo tree -d` to list all duplicate versions. +- Group duplicates by ecosystem and criticality: + - Core async stack: `tokio`, `async-tungstenite`, `tokio-tungstenite`, `tungstenite`, `rustls`, `tokio-rustls`. + - Serialization: `serde`, `serde_json`, `schemars`. + - Proc-macro toolchain: `syn`, `proc-macro2`, `quote`. + - HTTP: `reqwest`, `hyper`, `http`, TLS deps. + - Wasm/WASI: `wasmtime`, `wasmtime-wasi`, `wit-component`. + - Logging/telemetry: `tracing`, `log`. +- For each group, select target versions: + - Prefer the latest compatible stable versions across the group (consult release notes). + - For crates pinned to git revisions or vendor forks (e.g., `reqwest`, tree‑sitter grammars), confirm whether to keep pins or move to crates.io releases. + +### Phase 2 — Centralize Versions + +- Move chosen versions into `[workspace.dependencies]` in the root `Cargo.toml`. +- Update member `Cargo.toml` files to use `*.workspace = true` where possible. +- Remove ad‑hoc version pins in leaf crates unless strictly necessary. +- Use `[patch.crates-io]` or `[patch.'https://…']` only when needed to force a transitive dependency version; document why in comments. + +### Phase 3 — Ecosystem Alignment (High‑Risk Areas) + +- Async/WebSocket/TLS: + - Ensure `async-tungstenite`, `tokio-tungstenite`, and `tungstenite` are mutually compatible. + - Align TLS features (e.g., `rustls`, `tokio-rustls`) and remove internal/private feature flags (like underscored ones) if upstream changed them. + - Remove temporary aliases (e.g., `async_tungstenite_031`) after unification. +- Serde stack: + - Align `serde` and `serde_derive` to the same minor/patch; upgrade `serde_json` accordingly. + - Scan for features like `rc`, `preserve_order`, etc., consolidating into the workspace definition. +- Proc-macro toolchain: + - Bump `syn`, `proc-macro2`, `quote` together; confirm macro crates compile. +- Wasmtime stack: + - Upgrade `wasmtime`/`wasmtime-wasi`/`wit-component` in lockstep; review release notes for API changes. + +### Phase 4 — Incremental Upgrades + +- Use `cargo outdated -R` to list outdated crates. +- Upgrade in batches by domain to keep diffs reviewable: + - Batch A: Async/WebSocket/TLS. + - Batch B: Serde + data formats. + - Batch C: Proc‑macros and build‑time deps. + - Batch D: Wasm/Wasmtime. + - Batch E: UI/platform crates as needed. +- For each batch: + - Update versions in root `[workspace.dependencies]`. + - Adjust features centrally to satisfy all consumers. + - Build targets: `cargo check -p ` and `cargo check -p zed`. + - Run tests where available; smoke test local app launch if practical. + +### Phase 5 — Resolve Breakages + +- Typical fixes: + - API renames or moved modules: update imports and paths. + - Feature gating: enable new required features (e.g., `tokio-runtime` on `async-tungstenite`). + - TLS stacks: align `rustls`/`tokio-rustls` versions and feature flags; replace deprecated feature names. + - Type changes: adapt to new generics or newtype wrappers; avoid cross‑version types by ensuring one version in the graph. + - Macro breakages: update code generation usage or attributes. +- Keep changes local to the affected crate; prefer narrow, mechanical refactors over wide redesigns. + +### Phase 6 — Enforce and Maintain + +- CI gates: + - `cargo deny check bans` fails on multiple versions. + - Add a simple script to diff `cargo tree -d` against an allowlist of unavoidable dupes (prefer the allowlist to be empty). +- Developer workflow: + - When introducing a new dependency, add it to `[workspace.dependencies]` immediately. + - Avoid crate‑local pins unless required; if used, document and add a follow‑up issue to retire them. + +### Rollout Strategy + +- Create one PR per batch/phase; keep each PR focused and reversible. +- Use conventional commit messages and include a short upgrade summary plus links to upstream release notes. +- If a batch proves too large, split by crate or by breaking change clusters. + +### Definition of Done + +- `cargo tree -d` reports no duplicates (or only documented exceptions). +- `cargo outdated -R` is clean or only contains consciously deferred updates. +- `cargo check -p zed` and applicable tests pass. +- Temporary aliases and patches are removed or minimized. + +### Candidate Immediate Actions + +- Unify `async-tungstenite` across the workspace to 0.31.x and bump `tokio-tungstenite` to a compatible release (e.g., 0.27.x), verifying `tungstenite` aligns. +- Remove the `async_tungstenite_031` alias after the global unification and update imports back to `async_tungstenite`. +- Run `cargo outdated -R` and plan the next two batches (Serde stack, Proc‑macro stack). + +## macOS Follow-ups (this pass) + +### mac/events.rs — unsafe cleanups + +- Removed broad inner `unsafe { ... }` blocks inside `unsafe fn` bodies to address “unnecessary unsafe” warnings. +- Wrapped only the actual unsafe operations (raw-pointer deref and typed Objective‑C getters) in localized `unsafe { ... }` expressions, satisfying `unsafe_op_in_unsafe_fn` without reintroducing large unsafe scopes. +- Verified with `cargo check -p gpui` — no warnings from `events.rs` remain. + +### mac/window.rs — more typed constants + +- Replaced ad‑hoc bit masks with icrate `NSEventModifierFlag*` constants for modifier parsing. +- Replaced numeric `NSAlert` styles with icrate typed constants: `NSAlertStyleInformational`, `NSAlertStyleWarning`, `NSAlertStyleCritical`. +- Replaced locally defined `NSDragOperationNone/Copy` numeric values with icrate `NSDragOperationNone/Copy` and the `NSDragOperation` type. +- Kept window level wrappers (`NSWindowLevel`) as previously documented; icrate does not expose named levels. + +### mac/window_appearance.rs — adopt icrate appearance names + +- Switched from Cocoa `NSAppearanceName*` to icrate `NSAppearanceNameAqua/DarkAqua/VibrantLight/VibrantDark` constants, comparing via pointer casts to `id` for consistency with existing Objective‑C interop. +- Localized unsafe for `msg_send!` and extern comparisons. + +### mac/platform.rs — scroller style constant + +- Replaced local numeric `NSScrollerStyleOverlay` with icrate typed `NSScrollerStyleOverlay` (cast to `NSInteger` for comparison). + +### mac/status_item.rs — adopt icrate constants + +- Imported `NSSquareStatusItemLength` and `NSViewLayerContentsRedrawDuringViewResize` from icrate instead of pulling the latter via another module; avoids cross-module constant access and keeps constants typed and local. +- Enabled `AppKit_NSStatusBar` and `AppKit_NSStatusItem` features for icrate. + +### mac/platform.rs — menus on raw Objective‑C + icrate (typed‑ready) + +- Standardized the menu construction path to use raw Objective‑C (`msg_send`) for `NSMenu/NSMenuItem` instead of Cocoa trait shims, while keeping typed icrate constants elsewhere. Items are created and added immediately to ensure correct retention. +- Removed the legacy `create_menu_item` helper (now unused) in favor of `add_menu_item` that appends to the parent menu right away. +- Left objc2 enabled and ready for future fully‑typed adoption; mixing objc and objc2 macros in this large module requires a broader sweep, which we deferred to avoid regressions. + +### objc2 on macOS + +- Made `objc2` a non‑optional dependency for macOS and removed it from the `macos-blade` feature list to prevent feature/dependency mismatches. + +### mac/platform.rs — menus and pasteboard (icrate usage) + +- Audited menu construction and pasteboard read/write. Current approach mixes Cocoa objects (NSMenu/NSMenuItem/NSPasteboard) with icrate typed constants (NSPasteboardType*), casting to `id` at the boundary. +- Further migration to icrate objects would force wider interop changes (selectors, object lifetimes) with little immediate gain; kept the pragmatic cast‑to‑id pattern. +- No code changes needed now; revisit once broader objc2/icrate alignment is planned. + +### Other localized unsafe cleanups + +- mac/window_appearance.rs: Moved unsafe operations into narrow `unsafe {}` expressions for `msg_send!`, extern statics deref, and NSString UTF8 access. +- mac/text_system.rs: Localized unsafe in `wrap_under_get_rule`; removed redundant outer unsafe block inside an unsafe fn. + +### Next low‑friction icrate adoptions + +- window.rs: continue replacing ad‑hoc constants with icrate typed equivalents where 1:1 mapping exists and `msg_send` usage stays straightforward. +- platform.rs: when ready to standardize on icrate objects (e.g., NSMenu/NSMenuItem), migrate menus/pasteboard end‑to‑end to avoid mixed‑API friction. + +## Clippy + +- Ran `cargo clippy -p gpui --all-targets` (with elevated permissions due to Metal shader cache writes). Result: clean for `gpui` (quiet mode, no diagnostics). +- Attempted `cargo clippy --workspace --all-targets`. Workspace run currently fails due to unrelated crates: + - `collab`: trait implementation conflicts (`sea_orm::sea_query::Nullable`) and `to_string` ambiguity errors. + - mac shader build tries to write to `~/.cache/clang/ModuleCache` under sandbox; elevated run resolves this for `gpui`. +- Follow‑up: Fix `collab` clippy blockers in a separate pass before enabling workspace-wide clippy gating. diff --git a/Cargo.lock b/Cargo.lock index dbcea05ea9bc52..de51ece87ea8f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1333,6 +1333,23 @@ dependencies = [ "tungstenite 0.26.2", ] +[[package]] +name = "async-tungstenite" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee88b4c88ac8c9ea446ad43498955750a4bbe64c4392f21ccfe5d952865e318f" +dependencies = [ + "atomic-waker", + "futures-core", + "futures-io", + "futures-task", + "futures-util", + "log", + "pin-project-lite", + "tokio", + "tungstenite 0.27.0", +] + [[package]] name = "async_zip" version = "0.0.17" @@ -2308,7 +2325,7 @@ dependencies = [ "log", "mint", "naga", - "objc2", + "objc2 0.6.1", "objc2-app-kit", "objc2-core-foundation", "objc2-foundation", @@ -2388,13 +2405,32 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "block2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e58aa60e59d8dbfcc36138f5f18be5f24394d33b38b24f7fd0b1caa33095f22f" +dependencies = [ + "block-sys", + "objc2 0.5.2", +] + [[package]] name = "block2" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" dependencies = [ - "objc2", + "objc2 0.6.1", ] [[package]] @@ -3064,7 +3100,7 @@ name = "client" version = "0.1.0" dependencies = [ "anyhow", - "async-tungstenite", + "async-tungstenite 0.29.1", "base64 0.22.1", "chrono", "clock", @@ -3279,7 +3315,7 @@ dependencies = [ "assistant_context", "assistant_slash_command", "async-trait", - "async-tungstenite", + "async-tungstenite 0.29.1", "audio", "aws-config", "aws-sdk-kinesis", @@ -4827,7 +4863,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ "bitflags 2.9.0", - "objc2", + "objc2 0.6.1", ] [[package]] @@ -6043,7 +6079,6 @@ dependencies = [ "ashpd", "async-tar", "async-trait", - "cocoa 0.26.0", "collections", "fsevent", "futures 0.3.31", @@ -7445,18 +7480,20 @@ dependencies = [ "futures 0.3.31", "gpui_macros", "http_client", + "icrate", "image", "inventory", "itertools 0.14.0", "libc", "log", "lyon", + "macos_appkit_bridge", "media", "metal", "naga", "num_cpus", "objc", - "objc2", + "objc2 0.6.1", "objc2-metal", "oo7", "open", @@ -8149,6 +8186,16 @@ dependencies = [ "workspace-hack", ] +[[package]] +name = "icrate" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb69199826926eb864697bddd27f73d9fddcffc004f5733131e15b465e30642" +dependencies = [ + "block2 0.4.0", + "objc2 0.5.2", +] + [[package]] name = "icu_collections" version = "1.5.0" @@ -8947,7 +8994,7 @@ source = "git+https://github.com/ConradIrwin/runtimed?rev=7130c804216b6914355d15 dependencies = [ "anyhow", "async-trait", - "async-tungstenite", + "async-tungstenite 0.31.0", "futures 0.3.31", "jupyter-protocol", "serde", @@ -9927,6 +9974,10 @@ dependencies = [ "libc", ] +[[package]] +name = "macos_appkit_bridge" +version = "0.1.0" + [[package]] name = "malloc_buf" version = "0.0.6" @@ -10954,6 +11005,22 @@ dependencies = [ "objc_id", ] +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + [[package]] name = "objc2" version = "0.6.1" @@ -10970,7 +11037,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" dependencies = [ "bitflags 2.9.0", - "objc2", + "objc2 0.6.1", "objc2-core-foundation", "objc2-foundation", "objc2-quartz-core", @@ -10984,7 +11051,7 @@ checksum = "10cbe18d879e20a4aea544f8befe38bcf52255eb63d3f23eca2842f3319e4c07" dependencies = [ "bitflags 2.9.0", "libc", - "objc2", + "objc2 0.6.1", "objc2-core-audio", "objc2-core-audio-types", "objc2-core-foundation", @@ -10998,7 +11065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca44961e888e19313b808f23497073e3f6b3c22bb485056674c8b49f3b025c82" dependencies = [ "dispatch2", - "objc2", + "objc2 0.6.1", "objc2-core-audio-types", "objc2-core-foundation", ] @@ -11010,7 +11077,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0f1cc99bb07ad2ddb6527ddf83db6a15271bb036b3eb94b801cd44fdc666ee1" dependencies = [ "bitflags 2.9.0", - "objc2", + "objc2 0.6.1", ] [[package]] @@ -11021,7 +11088,7 @@ checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ "bitflags 2.9.0", "dispatch2", - "objc2", + "objc2 0.6.1", ] [[package]] @@ -11037,7 +11104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ "bitflags 2.9.0", - "objc2", + "objc2 0.6.1", "objc2-core-foundation", ] @@ -11048,9 +11115,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f246c183239540aab1782457b35ab2040d4259175bd1d0c58e46ada7b47a874" dependencies = [ "bitflags 2.9.0", - "block2", + "block2 0.6.1", "dispatch2", - "objc2", + "objc2 0.6.1", "objc2-core-foundation", "objc2-foundation", ] @@ -11062,7 +11129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" dependencies = [ "bitflags 2.9.0", - "objc2", + "objc2 0.6.1", "objc2-core-foundation", "objc2-foundation", "objc2-metal", @@ -11075,7 +11142,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" dependencies = [ "bitflags 2.9.0", - "objc2", + "objc2 0.6.1", "objc2-core-foundation", "objc2-foundation", "objc2-quartz-core", @@ -13579,7 +13646,8 @@ dependencies = [ "alacritty_terminal", "anyhow", "async-dispatcher", - "async-tungstenite", + "async-tungstenite 0.29.1", + "async-tungstenite 0.31.0", "base64 0.22.1", "client", "collections", @@ -13929,7 +13997,7 @@ name = "rpc" version = "0.1.0" dependencies = [ "anyhow", - "async-tungstenite", + "async-tungstenite 0.29.1", "base64 0.22.1", "chrono", "collections", @@ -17507,6 +17575,23 @@ dependencies = [ "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d" +dependencies = [ + "bytes 1.10.1", + "data-encoding", + "http 1.3.1", + "httparse", + "log", + "rand 0.9.1", + "sha1", + "thiserror 2.0.12", + "utf-8", +] + [[package]] name = "typed-path" version = "0.11.0" @@ -19886,7 +19971,7 @@ dependencies = [ "arrayvec", "async-compression", "async-std", - "async-tungstenite", + "async-tungstenite 0.29.1", "aws-config", "aws-credential-types", "aws-runtime", @@ -19978,7 +20063,7 @@ dependencies = [ "num-iter", "num-rational", "num-traits", - "objc2", + "objc2 0.6.1", "objc2-core-foundation", "objc2-foundation", "objc2-metal", diff --git a/Cargo.toml b/Cargo.toml index d8e8040cd920e1..5165344ac38be9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,6 +106,7 @@ members = [ "crates/markdown_preview", "crates/media", "crates/menu", + "crates/macos_appkit_bridge", "crates/migrator", "crates/mistral", "crates/multi_buffer", diff --git a/PR_BODY_mac-objc-migration-phase1.md b/PR_BODY_mac-objc-migration-phase1.md new file mode 100644 index 00000000000000..0a10463c9d813a --- /dev/null +++ b/PR_BODY_mac-objc-migration-phase1.md @@ -0,0 +1,116 @@ +Title: Build fixes + macOS objc2 prep: gpui menus, tungstenite alignment, clippy cleanups + +Overview + +- Target: Build the `zed` workspace locally without errors. +- Primary blocker: `jupyter-websocket-client` failed to compile due to unresolved imports from `async-tungstenite` and a follow‑on type mismatch caused by two different `async-tungstenite` versions in the dependency graph. +- Approach: Enable the correct feature on `async-tungstenite` v0.31.0 required by `jupyter-websocket-client`, and isolate type identity by importing that version via an alias in the `repl` crate where the websocket types are used. On macOS, standardize menus on raw Objective‑C, adopt icrate typed constants, and prepare for an objc2 migration. + +Changes Since Last Update + +- Menus (platform.rs): + - Replaced Cocoa shims with raw Objective‑C for `NSMenu`/`NSMenuItem` (create via `alloc/new/init` + `autorelease`). + - Added `add_menu_item(parent_menu, ...)` that creates separator/action/submenu/system items and immediately adds them to the parent (correct retention and simpler lifetimes). + - Rewired window/services menus with `setWindowsMenu:` and `setServicesMenu:` (`msg_send!`). + - Removed the legacy `create_menu_item` helper; no callers remain. + +- objc2 dependency (Cargo): + - Made `objc2` non‑optional on macOS and removed it from the `macos-blade` feature set. + - Enabled icrate features for NSMenu/NSMenuItem/NSStatusBar/NSScroller to support typed usage. + +- Other mac modules: + - status_item.rs: using icrate `NSSquareStatusItemLength` and `NSViewLayerContentsRedrawDuringViewResize`. + - window_appearance.rs: switched to icrate `NSAppearanceName*` and localized unsafe. + - events.rs: localized unsafe blocks around typed getters; removed unnecessary casts. + +- collab crate (clippy blockers): + - Removed conflicting manual `Nullable` impl in ids.rs; disambiguated `to_string` calls in queries and tests to avoid trait collisions with `sea_orm::Iden`. + +Root Cause Analysis (build failures) + +1) Feature gating in `async-tungstenite` 0.31.0 + +- `jupyter-websocket-client` imports `async_tungstenite::tokio`, which is behind the `tokio-runtime` feature in `async-tungstenite` v0.31.0. +- That feature wasn’t enabled in our graph, causing unresolved imports during compilation. + +2) Multiple `async-tungstenite` versions in the workspace + +- The workspace depends on `async-tungstenite` v0.29.1 (via `workspace.dependencies`). +- `jupyter-websocket-client` depends on `async-tungstenite` v0.31.0. +- When `repl` used `connect_async` and also consumed types produced by `jupyter-websocket-client`, we ended up with two different `WebSocketStream` types. Even if generics look the same, different crate versions yield distinct types, causing a mismatch. + +Changes Implemented (build fixes) + +1) Alias `async-tungstenite` v0.31.0 in `repl` with `tokio-runtime` enabled + +- crates/repl/Cargo.toml: + - `async_tungstenite_031 = { package = "async-tungstenite", version = "0.31.0", default-features = false, features = ["tokio-runtime"] }` + +2) Import the aliased crate in `repl` + +- crates/repl/src/kernels/remote_kernels.rs: + - `use async_tungstenite_031::tokio::connect_async;` + - `use async_tungstenite_031::tungstenite::{client::IntoClientRequest, http::HeaderValue};` + +Why this works + +- Ensures `async_tungstenite::tokio` is compiled in v0.31.0 by enabling `tokio-runtime`. +- Aligns all websocket types used in `repl` with those produced by `jupyter-websocket-client` (0.31.0), removing cross‑version type mismatches. + +Validation + +- `cargo check -p repl` passes. +- `cargo check -p zed` passes. +- `cargo clippy -p gpui --all-targets` runs clean (shader cache on macOS may require elevated permissions). +- `cargo clippy --workspace --all-targets` runs clean after `collab` fixes. + +macOS objc2 Migration Prep + +- Standardize raw Objective‑C messaging via `msg_send` in menus while adopting icrate typed constants where they bring clarity and safety. +- Make `objc2` unconditional on macOS to avoid feature mismatch; defer full typed migration to phased follow‑ups. + +Planned Phases (high level) + +- Phase 1 — Typed Menus: use `objc2::msg_send_id!`, `Retained`, typed setters; convert strings to icrate `NSString`. +- Phase 2 — Typed NSString/Selectors: introduce a helper and replace remaining Cocoa `NSString` usage where practical. +- Phase 3 — Beyond Menus: migrate services hooks, panels, pasteboard, and common NSApplication calls to objc2 typed APIs. +- Phase 4 — window.rs Sweep: re‑scan for typed replacements, confirm parity. + +Risks and Mitigations + +- Macro family mixing: avoid mixing `objc` and `objc2` macros within the same section; convert sections atomically and keep raw `id` interop localized. +- Retention/lifetimes: add items to parents immediately, prefer typed ownership where available. +- Rollback: current raw Objective‑C path is stable and can serve as fallback if needed. + +Design Notes and Trade‑offs + +- Minimal blast radius for build fixes: avoided a workspace‑wide `async-tungstenite` bump; used a targeted alias to keep other crates stable. +- Type identity: ensured websocket types come from a single crate version where the integration actually happens. +- Future: consider unifying `async-tungstenite` across the workspace to 0.31.x after a dedicated validation sweep. + +Follow‑ups / Backlog + +- Unify `async-tungstenite` versions workspace‑wide; align `tokio-tungstenite` and `tungstenite` accordingly. +- Continue objc2 typed migration across mac modules (services, panels, pasteboard, NSApplication). +- Replace remaining numeric constants with icrate typed constants where available. +- Optional: enforce single‑version policy via `cargo-deny` (bans), add CI checks. + +Files of Interest + +- AGENTS.md: detailed narrative of the build fixes, macOS migration prep, validation steps, and plans. +- crates/repl/Cargo.toml: alias for `async-tungstenite` 0.31.0 with `tokio-runtime`. +- crates/repl/src/kernels/remote_kernels.rs: imports updated to aliased 0.31.0 to match `jupyter-websocket-client`. +- macOS modules in `gpui`: menus standardized on raw Objective‑C; icrate constants adopted; objc2 made unconditional. + +Checklist + +- [x] cargo fmt +- [x] cargo check -p gpui +- [x] cargo clippy -p gpui --all-targets +- [x] cargo clippy --workspace --all-targets +- [x] Update AGENTS.md with scope, changes, and validation + +Notes + +- For shader compilation on macOS during clippy, elevated permissions may be needed due to shader cache writes. +- `gh` PR text mirrors AGENTS.md for maximum reviewer context; future PRs can be shorter once objc2 migration stabilizes. diff --git a/crates/collab/src/db/ids.rs b/crates/collab/src/db/ids.rs index 8f116cfd633749..84b3bd4c9e7639 100644 --- a/crates/collab/src/db/ids.rs +++ b/crates/collab/src/db/ids.rs @@ -61,11 +61,8 @@ macro_rules! id_type { } } - impl sea_orm::sea_query::Nullable for $name { - fn null() -> Value { - Value::Int(None) - } - } + // Nullable is provided by sea-orm derives for value types in recent versions; + // avoid conflicting implementations here. }; } diff --git a/crates/collab/src/db/queries/extensions.rs b/crates/collab/src/db/queries/extensions.rs index f218ff28507cf5..8b2cd798627d16 100644 --- a/crates/collab/src/db/queries/extensions.rs +++ b/crates/collab/src/db/queries/extensions.rs @@ -255,7 +255,7 @@ impl Database { let insert = extension::Entity::insert(extension::ActiveModel { name: ActiveValue::Set(latest_version.name.clone()), - external_id: ActiveValue::Set(external_id.to_string()), + external_id: ActiveValue::Set(std::string::ToString::to_string(external_id)), id: ActiveValue::NotSet, latest_version: ActiveValue::Set(latest_version.version.to_string()), total_download_count: ActiveValue::NotSet, @@ -282,7 +282,9 @@ impl Database { extension_version::ActiveModel { extension_id: ActiveValue::Set(extension.id), published_at: ActiveValue::Set(version.published_at), - version: ActiveValue::Set(version.version.to_string()), + version: ActiveValue::Set(std::string::ToString::to_string( + &version.version, + )), authors: ActiveValue::Set(version.authors.join(", ")), repository: ActiveValue::Set(version.repository.clone()), description: ActiveValue::Set(version.description.clone()), diff --git a/crates/collab/src/db/queries/notifications.rs b/crates/collab/src/db/queries/notifications.rs index cc22ee99b53b85..6f91fb868ab808 100644 --- a/crates/collab/src/db/queries/notifications.rs +++ b/crates/collab/src/db/queries/notifications.rs @@ -17,7 +17,7 @@ impl Database { .any(|existing| existing.name == **kind) }) .map(|kind| notification_kind::ActiveModel { - name: ActiveValue::Set(kind.to_string()), + name: ActiveValue::Set(std::string::ToString::to_string(kind)), ..Default::default() }) .collect(); @@ -260,7 +260,7 @@ pub fn model_to_proto(this: &Database, row: notification::Model) -> Result Vec Result<()> { - use cocoa::{ - base::{id, nil}, - foundation::{NSAutoreleasePool, NSString}, - }; + use objc::runtime::Object; use objc::{class, msg_send, sel, sel_impl}; + use std::{ffi::CString, ptr}; unsafe { - unsafe fn ns_string(string: &str) -> id { - unsafe { NSString::alloc(nil).init_str(string).autorelease() } + unsafe fn ns_string(s: &str) -> *mut Object { + let cstr = CString::new(s).unwrap_or_else(|_| CString::new("").unwrap()); + let ns: *mut Object = msg_send![class!(NSString), alloc]; + let ns: *mut Object = msg_send![ns, initWithUTF8String: cstr.as_ptr()]; + let _: *mut Object = msg_send![ns, autorelease]; + ns } - let url: id = msg_send![class!(NSURL), fileURLWithPath: ns_string(path.to_string_lossy().as_ref())]; - let array: id = msg_send![class!(NSArray), arrayWithObject: url]; - let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; + let url: *mut Object = msg_send![class!(NSURL), fileURLWithPath: ns_string(path.to_string_lossy().as_ref())]; + let array: *mut Object = msg_send![class!(NSArray), arrayWithObject: url]; + let workspace: *mut Object = msg_send![class!(NSWorkspace), sharedWorkspace]; - let _: id = msg_send![workspace, recycleURLs: array completionHandler: nil]; + let _: () = msg_send![workspace, recycleURLs: array completionHandler: ptr::null_mut::()]; } Ok(()) } diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index dd91eb4d4ee408..adfffd641409c9 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -30,7 +30,6 @@ macos-blade = [ "blade-macros", "blade-util", "bytemuck", - "objc2", "objc2-metal", ] wayland = [ @@ -127,11 +126,12 @@ thiserror.workspace = true util.workspace = true uuid.workspace = true waker-fn = "1.2.0" + +[target.'cfg(target_os = "macos")'.dependencies] +macos_appkit_bridge = { path = "../macos_appkit_bridge" } lyon = "1.0" workspace-hack.workspace = true libc.workspace = true - -[target.'cfg(target_os = "macos")'.dependencies] block = "0.1" cocoa.workspace = true core-foundation.workspace = true @@ -144,8 +144,35 @@ foreign-types = "0.5" log.workspace = true media.workspace = true objc.workspace = true -objc2 = { version = "0.6", optional = true } +objc2 = { version = "0.6" } objc2-metal = { version = "0.3", optional = true } +icrate = { version = "0.1.2", features = [ + # Base modules + "Foundation", "AppKit", + # Fine-grained Foundation types we use or plan to migrate to + "Foundation_NSAutoreleasePool", + "Foundation_NSArray", + "Foundation_NSMutableIndexSet", + "Foundation_NSProcessInfo", + "Foundation_NSString", + "Foundation_NSUserDefaults", + # Fine-grained AppKit types we use or plan to migrate to + "AppKit_NSApplication", + "AppKit_NSAppearance", + "AppKit_NSAlert", + "AppKit_NSEvent", + "AppKit_NSScroller", + "AppKit_NSPasteboard", + "AppKit_NSStatusBar", + "AppKit_NSStatusItem", + "AppKit_NSMenu", + "AppKit_NSMenuItem", + "AppKit_NSScreen", + "AppKit_NSTrackingArea", + "AppKit_NSView", + "AppKit_NSVisualEffectView", + "AppKit_NSWindow", +] } #TODO: replace with "objc2" metal.workspace = true diff --git a/crates/gpui/src/platform/mac.rs b/crates/gpui/src/platform/mac.rs index 76d636b457517d..7a0f7935e9349d 100644 --- a/crates/gpui/src/platform/mac.rs +++ b/crates/gpui/src/platform/mac.rs @@ -1,3 +1,4 @@ +#![allow(deprecated)] //! Macos screen have a y axis that goings up from the bottom of the screen and //! an origin at the bottom left of the main display. mod dispatcher; diff --git a/crates/gpui/src/platform/mac/attributed_string.rs b/crates/gpui/src/platform/mac/attributed_string.rs index 5f313ac699d6e1..2ac47f024aed10 100644 --- a/crates/gpui/src/platform/mac/attributed_string.rs +++ b/crates/gpui/src/platform/mac/attributed_string.rs @@ -1,105 +1,130 @@ -use cocoa::base::id; -use cocoa::foundation::NSRange; +use objc::runtime::Object; use objc::{class, msg_send, sel, sel_impl}; +type ObjcId = *mut Object; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct NSRange { + pub location: usize, + pub length: usize, +} + +impl NSRange { + pub const fn new(location: usize, length: usize) -> Self { + Self { location, length } + } +} + /// The `cocoa` crate does not define NSAttributedString (and related Cocoa classes), /// which are needed for copying rich text (that is, text intermingled with images) /// to the clipboard. This adds access to those APIs. #[allow(non_snake_case)] pub trait NSAttributedString: Sized { - unsafe fn alloc(_: Self) -> id { + unsafe fn alloc(_: Self) -> ObjcId { msg_send![class!(NSAttributedString), alloc] } - unsafe fn init_attributed_string(self, string: id) -> id; - unsafe fn appendAttributedString_(self, attr_string: id); - unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; - unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; - unsafe fn string(self) -> id; + unsafe fn init_attributed_string(self, string: ObjcId) -> ObjcId; + unsafe fn appendAttributedString_(self, attr_string: ObjcId); + unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: ObjcId) -> ObjcId; + unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: ObjcId) -> ObjcId; + unsafe fn string(self) -> ObjcId; } -impl NSAttributedString for id { - unsafe fn init_attributed_string(self, string: id) -> id { +impl NSAttributedString for ObjcId { + unsafe fn init_attributed_string(self, string: ObjcId) -> ObjcId { msg_send![self, initWithString: string] } - unsafe fn appendAttributedString_(self, attr_string: id) { + unsafe fn appendAttributedString_(self, attr_string: ObjcId) { let _: () = msg_send![self, appendAttributedString: attr_string]; } - unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { + unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: ObjcId) -> ObjcId { msg_send![self, RTFDFromRange: range documentAttributes: attrs] } - unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { + unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: ObjcId) -> ObjcId { msg_send![self, RTFFromRange: range documentAttributes: attrs] } - unsafe fn string(self) -> id { + unsafe fn string(self) -> ObjcId { msg_send![self, string] } } pub trait NSMutableAttributedString: NSAttributedString { - unsafe fn alloc(_: Self) -> id { + unsafe fn alloc(_: Self) -> ObjcId { msg_send![class!(NSMutableAttributedString), alloc] } } -impl NSMutableAttributedString for id {} +impl NSMutableAttributedString for ObjcId {} #[cfg(test)] mod tests { use super::*; - use cocoa::appkit::NSImage; - use cocoa::base::nil; - use cocoa::foundation::NSString; + use objc::runtime::Object; + use objc::{class, msg_send, sel, sel_impl}; + use std::ffi::CString; #[test] #[ignore] // This was SIGSEGV-ing on CI but not locally; need to investigate https://github.com/zed-industries/zed/actions/runs/10362363230/job/28684225486?pr=15782#step:4:1348 fn test_nsattributed_string() { // TODO move these to parent module once it's actually ready to be used #[allow(non_snake_case)] pub trait NSTextAttachment: Sized { - unsafe fn alloc(_: Self) -> id { + unsafe fn alloc(_: Self) -> ObjcId { msg_send![class!(NSTextAttachment), alloc] } } - impl NSTextAttachment for id {} + impl NSTextAttachment for ObjcId {} unsafe { - let image: id = msg_send![class!(NSImage), alloc]; - image.initWithContentsOfFile_(NSString::alloc(nil).init_str("test.jpeg")); - let _size = image.size(); - - let string = NSString::alloc(nil).init_str("Test String"); - let attr_string = NSMutableAttributedString::alloc(nil).init_attributed_string(string); - let hello_string = NSString::alloc(nil).init_str("Hello World"); - let hello_attr_string = - NSAttributedString::alloc(nil).init_attributed_string(hello_string); + let image: ObjcId = msg_send![class!(NSImage), alloc]; + let path = CString::new("test.jpeg").unwrap(); + let ns_str: *mut Object = msg_send![class!(NSString), alloc]; + let ns_str: *mut Object = msg_send![ns_str, initWithUTF8String: path.as_ptr()]; + let _: ObjcId = msg_send![image, initWithContentsOfFile: ns_str]; + + let s = CString::new("Test String").unwrap(); + let string: ObjcId = msg_send![class!(NSString), alloc]; + let string: ObjcId = msg_send![string, initWithUTF8String: s.as_ptr()]; + let attr_string = NSMutableAttributedString::alloc(std::ptr::null_mut()) + .init_attributed_string(string); + let hs = CString::new("Hello World").unwrap(); + let hello_string: ObjcId = msg_send![class!(NSString), alloc]; + let hello_string: ObjcId = msg_send![hello_string, initWithUTF8String: hs.as_ptr()]; + let hello_attr_string = NSAttributedString::alloc(std::ptr::null_mut()) + .init_attributed_string(hello_string); attr_string.appendAttributedString_(hello_attr_string); - let attachment = NSTextAttachment::alloc(nil); + let attachment = NSTextAttachment::alloc(std::ptr::null_mut()); let _: () = msg_send![attachment, setImage: image]; let image_attr_string = msg_send![class!(NSAttributedString), attributedStringWithAttachment: attachment]; attr_string.appendAttributedString_(image_attr_string); - let another_string = NSString::alloc(nil).init_str("Another String"); - let another_attr_string = - NSAttributedString::alloc(nil).init_attributed_string(another_string); + let as_ = CString::new("Another String").unwrap(); + let another_string: ObjcId = msg_send![class!(NSString), alloc]; + let another_string: ObjcId = + msg_send![another_string, initWithUTF8String: as_.as_ptr()]; + let another_attr_string = NSAttributedString::alloc(std::ptr::null_mut()) + .init_attributed_string(another_string); attr_string.appendAttributedString_(another_attr_string); - let _len: cocoa::foundation::NSUInteger = msg_send![attr_string, length]; + let _len: u64 = msg_send![attr_string, length]; /////////////////////////////////////////////////// // pasteboard.clearContents(); + let len: u64 = msg_send![attr_string, length]; let rtfd_data = attr_string.RTFDFromRange_documentAttributes_( - NSRange::new(0, msg_send![attr_string, length]), - nil, + NSRange::new(0, len as usize), + std::ptr::null_mut(), ); - assert_ne!(rtfd_data, nil); + assert!(!rtfd_data.is_null()); // if rtfd_data != nil { // pasteboard.setData_forType(rtfd_data, NSPasteboardTypeRTFD); // } diff --git a/crates/gpui/src/platform/mac/display.rs b/crates/gpui/src/platform/mac/display.rs index 4ee27027d5fbff..a89655788837b4 100644 --- a/crates/gpui/src/platform/mac/display.rs +++ b/crates/gpui/src/platform/mac/display.rs @@ -1,13 +1,10 @@ use crate::{Bounds, DisplayId, Pixels, PlatformDisplay, px, size}; use anyhow::Result; -use cocoa::{ - appkit::NSScreen, - base::{id, nil}, - foundation::{NSDictionary, NSString}, -}; use core_foundation::uuid::{CFUUIDGetUUIDBytes, CFUUIDRef}; use core_graphics::display::{CGDirectDisplayID, CGDisplayBounds, CGGetActiveDisplayList}; -use objc::{msg_send, sel, sel_impl}; +use objc::runtime::Object; +use objc::{class, msg_send, sel, sel_impl}; +use std::ffi::CString; use uuid::Uuid; #[derive(Debug)] @@ -32,13 +29,18 @@ impl MacDisplay { // // https://chromium.googlesource.com/chromium/src/+/66.0.3359.158/ui/display/mac/screen_mac.mm#56 unsafe { - let screens = NSScreen::screens(nil); - let screen = cocoa::foundation::NSArray::objectAtIndex(screens, 0); - let device_description = NSScreen::deviceDescription(screen); - let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); - let screen_number = device_description.objectForKey_(screen_number_key); - let screen_number: CGDirectDisplayID = msg_send![screen_number, unsignedIntegerValue]; - Self(screen_number) + let screens: *mut Object = msg_send![class!(NSScreen), screens]; + let screen: *mut Object = msg_send![screens, objectAtIndex: 0usize]; + let device_description: *mut Object = msg_send![screen, deviceDescription]; + + let key = CString::new("NSScreenNumber").unwrap(); + let ns_key: *mut Object = msg_send![class!(NSString), alloc]; + let ns_key: *mut Object = msg_send![ns_key, initWithUTF8String: key.as_ptr()]; + + let screen_number_obj: *mut Object = + msg_send![device_description, objectForKey: ns_key]; + let screen_number: u64 = msg_send![screen_number_obj, unsignedIntegerValue]; + Self(screen_number as CGDirectDisplayID) } } diff --git a/crates/gpui/src/platform/mac/events.rs b/crates/gpui/src/platform/mac/events.rs index 938db4b76205ee..16423e1ebe8b20 100644 --- a/crates/gpui/src/platform/mac/events.rs +++ b/crates/gpui/src/platform/mac/events.rs @@ -8,13 +8,44 @@ use crate::{ }, point, px, }; -use cocoa::{ - appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType}, - base::{YES, id}, -}; +use icrate::AppKit::NSEvent; +use objc::runtime::Object; +use objc::{msg_send, sel, sel_impl}; +type ObjcId = *mut Object; use core_foundation::data::{CFDataGetBytePtr, CFDataRef}; use core_graphics::event::CGKeyCode; -use objc::{msg_send, sel, sel_impl}; +// Using objc2/icrate later for typed constants; current code retains numeric masks and values +// objc msg_send imported above +use icrate::AppKit::{ + // Modifier flags + NSEventModifierFlagCapsLock, + NSEventModifierFlagCommand, + NSEventModifierFlagControl, + NSEventModifierFlagFunction, + NSEventModifierFlagOption, + NSEventModifierFlagShift, + // Phases + NSEventPhaseBegan, + NSEventPhaseEnded, + NSEventPhaseMayBegin, + NSEventTypeFlagsChanged, + NSEventTypeKeyDown, + NSEventTypeKeyUp, + // Event types + NSEventTypeLeftMouseDown, + NSEventTypeLeftMouseDragged, + NSEventTypeLeftMouseUp, + NSEventTypeMouseExited, + NSEventTypeMouseMoved, + NSEventTypeOtherMouseDown, + NSEventTypeOtherMouseDragged, + NSEventTypeOtherMouseUp, + NSEventTypeRightMouseDown, + NSEventTypeRightMouseDragged, + NSEventTypeRightMouseUp, + NSEventTypeScrollWheel, + NSEventTypeSwipe, +}; use std::{borrow::Cow, ffi::c_void}; const BACKSPACE_KEY: u16 = 0x7f; @@ -25,433 +56,428 @@ pub(crate) const ESCAPE_KEY: u16 = 0x1b; const TAB_KEY: u16 = 0x09; const SHIFT_TAB_KEY: u16 = 0x19; +// CGPoint/NSPoint equivalent for message returns +#[repr(C)] +struct NSPoint { + pub x: f64, + pub y: f64, +} + +// Modifier flag masks (from icrate NSEventModifierFlags) +const MOD_CAPS_LOCK: u64 = NSEventModifierFlagCapsLock as u64; +const MOD_SHIFT: u64 = NSEventModifierFlagShift as u64; +const MOD_CONTROL: u64 = NSEventModifierFlagControl as u64; +const MOD_OPTION: u64 = NSEventModifierFlagOption as u64; +const MOD_COMMAND: u64 = NSEventModifierFlagCommand as u64; +const MOD_FUNCTION: u64 = NSEventModifierFlagFunction as u64; + +// Event types we care about (from icrate NSEventType) +const ET_LEFT_MOUSE_DOWN: u64 = NSEventTypeLeftMouseDown as u64; +const ET_LEFT_MOUSE_UP: u64 = NSEventTypeLeftMouseUp as u64; +const ET_RIGHT_MOUSE_DOWN: u64 = NSEventTypeRightMouseDown as u64; +const ET_RIGHT_MOUSE_UP: u64 = NSEventTypeRightMouseUp as u64; +const ET_MOUSE_MOVED: u64 = NSEventTypeMouseMoved as u64; +const ET_LEFT_MOUSE_DRAGGED: u64 = NSEventTypeLeftMouseDragged as u64; +const ET_RIGHT_MOUSE_DRAGGED: u64 = NSEventTypeRightMouseDragged as u64; +const ET_MOUSE_EXITED: u64 = NSEventTypeMouseExited as u64; +const ET_KEY_DOWN: u64 = NSEventTypeKeyDown as u64; +const ET_KEY_UP: u64 = NSEventTypeKeyUp as u64; +const ET_FLAGS_CHANGED: u64 = NSEventTypeFlagsChanged as u64; +const ET_SCROLL_WHEEL: u64 = NSEventTypeScrollWheel as u64; +const ET_OTHER_MOUSE_DOWN: u64 = NSEventTypeOtherMouseDown as u64; +const ET_OTHER_MOUSE_UP: u64 = NSEventTypeOtherMouseUp as u64; +const ET_OTHER_MOUSE_DRAGGED: u64 = NSEventTypeOtherMouseDragged as u64; +const ET_SWIPE: u64 = NSEventTypeSwipe as u64; + +// Event phases (from icrate NSEventPhase) +const PHASE_BEGAN: u64 = NSEventPhaseBegan as u64; +const PHASE_ENDED: u64 = NSEventPhaseEnded as u64; +const PHASE_MAY_BEGIN: u64 = NSEventPhaseMayBegin as u64; + +// Function-key constants used in mapping +const NS_UP_ARROW: u16 = 0xF700; +const NS_DOWN_ARROW: u16 = 0xF701; +const NS_LEFT_ARROW: u16 = 0xF702; +const NS_RIGHT_ARROW: u16 = 0xF703; +const NS_HOME: u16 = 0xF729; +const NS_END: u16 = 0xF72B; +const NS_PAGE_UP: u16 = 0xF72C; +const NS_PAGE_DOWN: u16 = 0xF72D; +const NS_DELETE_FN: u16 = 0xF728; +const NS_HELP_FN: u16 = 0xF746; + pub fn key_to_native(key: &str) -> Cow<'_, str> { - use cocoa::appkit::*; - let code = match key { - "space" => SPACE_KEY, - "backspace" => BACKSPACE_KEY, - "escape" => ESCAPE_KEY, - "up" => NSUpArrowFunctionKey, - "down" => NSDownArrowFunctionKey, - "left" => NSLeftArrowFunctionKey, - "right" => NSRightArrowFunctionKey, - "pageup" => NSPageUpFunctionKey, - "pagedown" => NSPageDownFunctionKey, - "home" => NSHomeFunctionKey, - "end" => NSEndFunctionKey, - "delete" => NSDeleteFunctionKey, - "insert" => NSHelpFunctionKey, - "f1" => NSF1FunctionKey, - "f2" => NSF2FunctionKey, - "f3" => NSF3FunctionKey, - "f4" => NSF4FunctionKey, - "f5" => NSF5FunctionKey, - "f6" => NSF6FunctionKey, - "f7" => NSF7FunctionKey, - "f8" => NSF8FunctionKey, - "f9" => NSF9FunctionKey, - "f10" => NSF10FunctionKey, - "f11" => NSF11FunctionKey, - "f12" => NSF12FunctionKey, - "f13" => NSF13FunctionKey, - "f14" => NSF14FunctionKey, - "f15" => NSF15FunctionKey, - "f16" => NSF16FunctionKey, - "f17" => NSF17FunctionKey, - "f18" => NSF18FunctionKey, - "f19" => NSF19FunctionKey, - "f20" => NSF20FunctionKey, - "f21" => NSF21FunctionKey, - "f22" => NSF22FunctionKey, - "f23" => NSF23FunctionKey, - "f24" => NSF24FunctionKey, - "f25" => NSF25FunctionKey, - "f26" => NSF26FunctionKey, - "f27" => NSF27FunctionKey, - "f28" => NSF28FunctionKey, - "f29" => NSF29FunctionKey, - "f30" => NSF30FunctionKey, - "f31" => NSF31FunctionKey, - "f32" => NSF32FunctionKey, - "f33" => NSF33FunctionKey, - "f34" => NSF34FunctionKey, - "f35" => NSF35FunctionKey, - _ => return Cow::Borrowed(key), + let code_opt: Option = match key { + "space" => Some(SPACE_KEY), + "backspace" => Some(BACKSPACE_KEY), + "escape" => Some(ESCAPE_KEY), + "up" => Some(NS_UP_ARROW), + "down" => Some(NS_DOWN_ARROW), + "left" => Some(NS_LEFT_ARROW), + "right" => Some(NS_RIGHT_ARROW), + "pageup" => Some(NS_PAGE_UP), + "pagedown" => Some(NS_PAGE_DOWN), + "home" => Some(NS_HOME), + "end" => Some(NS_END), + "delete" => Some(NS_DELETE_FN), + "insert" => Some(NS_HELP_FN), + other if other.len() > 1 && other.starts_with('f') => { + if let Ok(n) = other[1..].parse::() { + if (1..=35).contains(&n) { + Some(0xF703 + n) + } else { + None + } + } else { + None + } + } + _ => None, }; - Cow::Owned(String::from_utf16(&[code]).unwrap()) + if let Some(code) = code_opt { + Cow::Owned(String::from_utf16(&[code]).unwrap()) + } else { + Cow::Borrowed(key) + } } -unsafe fn read_modifiers(native_event: id) -> Modifiers { - unsafe { - let modifiers = native_event.modifierFlags(); - let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); - let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); - let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); - let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); - let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); - - Modifiers { - control, - alt, - shift, - platform: command, - function, - } +unsafe fn read_modifiers(native_event: ObjcId) -> Modifiers { + let modifiers: u64 = msg_send![native_event, modifierFlags]; + let control = (modifiers & MOD_CONTROL) != 0; + let alt = (modifiers & MOD_OPTION) != 0; + let shift = (modifiers & MOD_SHIFT) != 0; + let command = (modifiers & MOD_COMMAND) != 0; + let function = (modifiers & MOD_FUNCTION) != 0; + + Modifiers { + control, + alt, + shift, + platform: command, + function, } } impl PlatformInput { pub(crate) unsafe fn from_native( - native_event: id, + native_event: ObjcId, window_height: Option, ) -> Option { - unsafe { - let event_type = native_event.eventType(); - - // Filter out event types that aren't in the NSEventType enum. - // See https://github.com/servo/cocoa-rs/issues/155#issuecomment-323482792 for details. - match event_type as u64 { - 0 | 21 | 32 | 33 | 35 | 36 | 37 => { - return None; - } - _ => {} + let event = native_event as *const NSEvent; + let event_type: u64 = unsafe { (&*event).r#type() as u64 }; + + // Filter out event types that aren't in the NSEventType enum. + // See https://github.com/servo/cocoa-rs/issues/155#issuecomment-323482792 for details. + match event_type { + 0 | 21 | 32 | 33 | 35 | 36 | 37 => { + return None; } + _ => {} + } - match event_type { - NSEventType::NSFlagsChanged => { - Some(Self::ModifiersChanged(ModifiersChangedEvent { - modifiers: read_modifiers(native_event), - capslock: Capslock { - on: native_event - .modifierFlags() - .contains(NSEventModifierFlags::NSAlphaShiftKeyMask), + match event_type { + ET_FLAGS_CHANGED => Some(Self::ModifiersChanged(ModifiersChangedEvent { + modifiers: unsafe { read_modifiers(native_event) }, + capslock: Capslock { + on: { + let m: u64 = unsafe { (&*event).modifierFlags() as u64 }; + (m & MOD_CAPS_LOCK) != 0 + }, + }, + })), + ET_KEY_DOWN => Some(Self::KeyDown(KeyDownEvent { + keystroke: unsafe { parse_keystroke(native_event) }, + is_held: { unsafe { (&*event).isARepeat() } }, + })), + ET_KEY_UP => Some(Self::KeyUp(KeyUpEvent { + keystroke: unsafe { parse_keystroke(native_event) }, + })), + ET_LEFT_MOUSE_DOWN | ET_RIGHT_MOUSE_DOWN | ET_OTHER_MOUSE_DOWN => { + let bn: u64 = unsafe { (&*event).buttonNumber() as u64 }; + let button = match bn { + 0 => MouseButton::Left, + 1 => MouseButton::Right, + 2 => MouseButton::Middle, + 3 => MouseButton::Navigate(NavigationDirection::Back), + 4 => MouseButton::Navigate(NavigationDirection::Forward), + // Other mouse buttons aren't tracked currently + _ => return None, + }; + window_height.map(|window_height| { + Self::MouseDown(MouseDownEvent { + button, + position: { + let p: NSPoint = msg_send![native_event, locationInWindow]; + point(px(p.x as f32), window_height - px(p.y as f32)) }, - })) - } - NSEventType::NSKeyDown => Some(Self::KeyDown(KeyDownEvent { - keystroke: parse_keystroke(native_event), - is_held: native_event.isARepeat() == YES, - })), - NSEventType::NSKeyUp => Some(Self::KeyUp(KeyUpEvent { - keystroke: parse_keystroke(native_event), - })), - NSEventType::NSLeftMouseDown - | NSEventType::NSRightMouseDown - | NSEventType::NSOtherMouseDown => { - let button = match native_event.buttonNumber() { - 0 => MouseButton::Left, - 1 => MouseButton::Right, - 2 => MouseButton::Middle, - 3 => MouseButton::Navigate(NavigationDirection::Back), - 4 => MouseButton::Navigate(NavigationDirection::Forward), - // Other mouse buttons aren't tracked currently - _ => return None, - }; - window_height.map(|window_height| { - Self::MouseDown(MouseDownEvent { - button, - position: point( - px(native_event.locationInWindow().x as f32), - // MacOS screen coordinates are relative to bottom left - window_height - px(native_event.locationInWindow().y as f32), - ), - modifiers: read_modifiers(native_event), - click_count: native_event.clickCount() as usize, - first_mouse: false, - }) - }) - } - NSEventType::NSLeftMouseUp - | NSEventType::NSRightMouseUp - | NSEventType::NSOtherMouseUp => { - let button = match native_event.buttonNumber() { - 0 => MouseButton::Left, - 1 => MouseButton::Right, - 2 => MouseButton::Middle, - 3 => MouseButton::Navigate(NavigationDirection::Back), - 4 => MouseButton::Navigate(NavigationDirection::Forward), - // Other mouse buttons aren't tracked currently - _ => return None, - }; - - window_height.map(|window_height| { - Self::MouseUp(MouseUpEvent { - button, - position: point( - px(native_event.locationInWindow().x as f32), - window_height - px(native_event.locationInWindow().y as f32), - ), - modifiers: read_modifiers(native_event), - click_count: native_event.clickCount() as usize, - }) + modifiers: unsafe { read_modifiers(native_event) }, + click_count: { + let c: isize = unsafe { (&*event).clickCount() }; + c as usize + }, + first_mouse: false, }) - } - // Some mice (like Logitech MX Master) send navigation buttons as swipe events - NSEventType::NSEventTypeSwipe => { - let navigation_direction = match native_event.phase() { - NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() { - x if x > 0.0 => Some(NavigationDirection::Back), - x if x < 0.0 => Some(NavigationDirection::Forward), - _ => return None, + }) + } + ET_LEFT_MOUSE_UP | ET_RIGHT_MOUSE_UP | ET_OTHER_MOUSE_UP => { + let bn: u64 = unsafe { (&*event).buttonNumber() as u64 }; + let button = match bn { + 0 => MouseButton::Left, + 1 => MouseButton::Right, + 2 => MouseButton::Middle, + 3 => MouseButton::Navigate(NavigationDirection::Back), + 4 => MouseButton::Navigate(NavigationDirection::Forward), + // Other mouse buttons aren't tracked currently + _ => return None, + }; + + window_height.map(|window_height| { + Self::MouseUp(MouseUpEvent { + button, + position: { + let p = unsafe { (&*event).locationInWindow() }; + point(px(p.x as f32), window_height - px(p.y as f32)) + }, + modifiers: unsafe { read_modifiers(native_event) }, + click_count: { + let c: isize = unsafe { (&*event).clickCount() }; + c as usize }, - _ => return None, - }; - - match navigation_direction { - Some(direction) => window_height.map(|window_height| { - Self::MouseDown(MouseDownEvent { - button: MouseButton::Navigate(direction), - position: point( - px(native_event.locationInWindow().x as f32), - window_height - px(native_event.locationInWindow().y as f32), - ), - modifiers: read_modifiers(native_event), - click_count: 1, - first_mouse: false, - }) - }), - _ => None, - } - } - NSEventType::NSScrollWheel => window_height.map(|window_height| { - let phase = match native_event.phase() { - NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { - TouchPhase::Started - } - NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, - _ => TouchPhase::Moved, - }; - - let raw_data = point( - native_event.scrollingDeltaX() as f32, - native_event.scrollingDeltaY() as f32, - ); - - let delta = if native_event.hasPreciseScrollingDeltas() == YES { - ScrollDelta::Pixels(raw_data.map(px)) - } else { - ScrollDelta::Lines(raw_data) - }; - - Self::ScrollWheel(ScrollWheelEvent { - position: point( - px(native_event.locationInWindow().x as f32), - window_height - px(native_event.locationInWindow().y as f32), - ), - delta, - touch_phase: phase, - modifiers: read_modifiers(native_event), }) - }), - NSEventType::NSLeftMouseDragged - | NSEventType::NSRightMouseDragged - | NSEventType::NSOtherMouseDragged => { - let pressed_button = match native_event.buttonNumber() { - 0 => MouseButton::Left, - 1 => MouseButton::Right, - 2 => MouseButton::Middle, - 3 => MouseButton::Navigate(NavigationDirection::Back), - 4 => MouseButton::Navigate(NavigationDirection::Forward), - // Other mouse buttons aren't tracked currently + }) + } + // Some mice (like Logitech MX Master) send navigation buttons as swipe events + ET_SWIPE => { + let phase: u64 = msg_send![native_event, phase]; + let navigation_direction = match phase { + PHASE_ENDED => match { + let dx: f64 = unsafe { (&*event).deltaX() }; + dx + } { + x if x > 0.0 => Some(NavigationDirection::Back), + x if x < 0.0 => Some(NavigationDirection::Forward), _ => return None, - }; - - window_height.map(|window_height| { - Self::MouseMove(MouseMoveEvent { - pressed_button: Some(pressed_button), - position: point( - px(native_event.locationInWindow().x as f32), - window_height - px(native_event.locationInWindow().y as f32), - ), - modifiers: read_modifiers(native_event), + }, + _ => return None, + }; + + match navigation_direction { + Some(direction) => window_height.map(|window_height| { + Self::MouseDown(MouseDownEvent { + button: MouseButton::Navigate(direction), + position: { + let p = unsafe { (&*event).locationInWindow() }; + point(px(p.x as f32), window_height - px(p.y as f32)) + }, + modifiers: unsafe { read_modifiers(native_event) }, + click_count: 1, + first_mouse: false, }) - }) + }), + _ => None, } - NSEventType::NSMouseMoved => window_height.map(|window_height| { + } + ET_SCROLL_WHEEL => window_height.map(|window_height| { + let phase_val: u64 = unsafe { (&*event).momentumPhase() as u64 }; + let phase = match phase_val { + PHASE_MAY_BEGIN | PHASE_BEGAN => TouchPhase::Started, + PHASE_ENDED => TouchPhase::Ended, + _ => TouchPhase::Moved, + }; + + let raw_data = { + let dx: f64 = unsafe { (&*event).scrollingDeltaX() }; + let dy: f64 = unsafe { (&*event).scrollingDeltaY() }; + point(dx as f32, dy as f32) + }; + + let precise = unsafe { (&*event).hasPreciseScrollingDeltas() }; + let delta = if precise { + ScrollDelta::Pixels(raw_data.map(px)) + } else { + ScrollDelta::Lines(raw_data) + }; + + Self::ScrollWheel(ScrollWheelEvent { + position: { + let p = unsafe { (&*event).locationInWindow() }; + point(px(p.x as f32), window_height - px(p.y as f32)) + }, + delta, + touch_phase: phase, + modifiers: unsafe { read_modifiers(native_event) }, + }) + }), + ET_LEFT_MOUSE_DRAGGED | ET_RIGHT_MOUSE_DRAGGED | ET_OTHER_MOUSE_DRAGGED => { + let bn: u64 = unsafe { (&*event).buttonNumber() as u64 }; + let pressed_button = match bn { + 0 => MouseButton::Left, + 1 => MouseButton::Right, + 2 => MouseButton::Middle, + 3 => MouseButton::Navigate(NavigationDirection::Back), + 4 => MouseButton::Navigate(NavigationDirection::Forward), + // Other mouse buttons aren't tracked currently + _ => return None, + }; + + window_height.map(|window_height| { Self::MouseMove(MouseMoveEvent { - position: point( - px(native_event.locationInWindow().x as f32), - window_height - px(native_event.locationInWindow().y as f32), - ), - pressed_button: None, - modifiers: read_modifiers(native_event), - }) - }), - NSEventType::NSMouseExited => window_height.map(|window_height| { - Self::MouseExited(MouseExitEvent { - position: point( - px(native_event.locationInWindow().x as f32), - window_height - px(native_event.locationInWindow().y as f32), - ), - - pressed_button: None, - modifiers: read_modifiers(native_event), + pressed_button: Some(pressed_button), + position: { + let p = unsafe { (&*event).locationInWindow() }; + point(px(p.x as f32), window_height - px(p.y as f32)) + }, + modifiers: unsafe { read_modifiers(native_event) }, }) - }), - _ => None, + }) } + ET_MOUSE_MOVED => window_height.map(|window_height| { + Self::MouseMove(MouseMoveEvent { + position: { + let p = unsafe { (&*event).locationInWindow() }; + point(px(p.x as f32), window_height - px(p.y as f32)) + }, + pressed_button: None, + modifiers: unsafe { read_modifiers(native_event) }, + }) + }), + ET_MOUSE_EXITED => window_height.map(|window_height| { + Self::MouseExited(MouseExitEvent { + position: { + let p = unsafe { (&*event).locationInWindow() }; + point(px(p.x as f32), window_height - px(p.y as f32)) + }, + + pressed_button: None, + modifiers: unsafe { read_modifiers(native_event) }, + }) + }), + _ => None, } } } -unsafe fn parse_keystroke(native_event: id) -> Keystroke { - unsafe { - use cocoa::appkit::*; - - let mut characters = native_event - .charactersIgnoringModifiers() - .to_str() - .to_string(); - let mut key_char = None; - let first_char = characters.chars().next().map(|ch| ch as u16); - let modifiers = native_event.modifierFlags(); - - let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); - let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); - let mut shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); - let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); - let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask) - && first_char - .is_none_or(|ch| !(NSUpArrowFunctionKey..=NSModeSwitchFunctionKey).contains(&ch)); - - #[allow(non_upper_case_globals)] - let key = match first_char { - Some(SPACE_KEY) => { - key_char = Some(" ".to_string()); - "space".to_string() - } - Some(TAB_KEY) => { - key_char = Some("\t".to_string()); - "tab".to_string() - } - Some(ENTER_KEY) | Some(NUMPAD_ENTER_KEY) => { - key_char = Some("\n".to_string()); - "enter".to_string() - } - Some(BACKSPACE_KEY) => "backspace".to_string(), - Some(ESCAPE_KEY) => "escape".to_string(), - Some(SHIFT_TAB_KEY) => "tab".to_string(), - Some(NSUpArrowFunctionKey) => "up".to_string(), - Some(NSDownArrowFunctionKey) => "down".to_string(), - Some(NSLeftArrowFunctionKey) => "left".to_string(), - Some(NSRightArrowFunctionKey) => "right".to_string(), - Some(NSPageUpFunctionKey) => "pageup".to_string(), - Some(NSPageDownFunctionKey) => "pagedown".to_string(), - Some(NSHomeFunctionKey) => "home".to_string(), - Some(NSEndFunctionKey) => "end".to_string(), - Some(NSDeleteFunctionKey) => "delete".to_string(), - // Observed Insert==NSHelpFunctionKey not NSInsertFunctionKey. - Some(NSHelpFunctionKey) => "insert".to_string(), - Some(NSF1FunctionKey) => "f1".to_string(), - Some(NSF2FunctionKey) => "f2".to_string(), - Some(NSF3FunctionKey) => "f3".to_string(), - Some(NSF4FunctionKey) => "f4".to_string(), - Some(NSF5FunctionKey) => "f5".to_string(), - Some(NSF6FunctionKey) => "f6".to_string(), - Some(NSF7FunctionKey) => "f7".to_string(), - Some(NSF8FunctionKey) => "f8".to_string(), - Some(NSF9FunctionKey) => "f9".to_string(), - Some(NSF10FunctionKey) => "f10".to_string(), - Some(NSF11FunctionKey) => "f11".to_string(), - Some(NSF12FunctionKey) => "f12".to_string(), - Some(NSF13FunctionKey) => "f13".to_string(), - Some(NSF14FunctionKey) => "f14".to_string(), - Some(NSF15FunctionKey) => "f15".to_string(), - Some(NSF16FunctionKey) => "f16".to_string(), - Some(NSF17FunctionKey) => "f17".to_string(), - Some(NSF18FunctionKey) => "f18".to_string(), - Some(NSF19FunctionKey) => "f19".to_string(), - Some(NSF20FunctionKey) => "f20".to_string(), - Some(NSF21FunctionKey) => "f21".to_string(), - Some(NSF22FunctionKey) => "f22".to_string(), - Some(NSF23FunctionKey) => "f23".to_string(), - Some(NSF24FunctionKey) => "f24".to_string(), - Some(NSF25FunctionKey) => "f25".to_string(), - Some(NSF26FunctionKey) => "f26".to_string(), - Some(NSF27FunctionKey) => "f27".to_string(), - Some(NSF28FunctionKey) => "f28".to_string(), - Some(NSF29FunctionKey) => "f29".to_string(), - Some(NSF30FunctionKey) => "f30".to_string(), - Some(NSF31FunctionKey) => "f31".to_string(), - Some(NSF32FunctionKey) => "f32".to_string(), - Some(NSF33FunctionKey) => "f33".to_string(), - Some(NSF34FunctionKey) => "f34".to_string(), - Some(NSF35FunctionKey) => "f35".to_string(), - _ => { - // Cases to test when modifying this: - // - // qwerty key | none | cmd | cmd-shift - // * Armenian s | ս | cmd-s | cmd-shift-s (layout is non-ASCII, so we use cmd layout) - // * Dvorak+QWERTY s | o | cmd-s | cmd-shift-s (layout switches on cmd) - // * Ukrainian+QWERTY s | с | cmd-s | cmd-shift-s (macOS reports cmd-s instead of cmd-S) - // * Czech 7 | ý | cmd-ý | cmd-7 (layout has shifted numbers) - // * Norwegian 7 | 7 | cmd-7 | cmd-/ (macOS reports cmd-shift-7 instead of cmd-/) - // * Russian 7 | 7 | cmd-7 | cmd-& (shift-7 is . but when cmd is down, should use cmd layout) - // * German QWERTZ ; | ö | cmd-ö | cmd-Ö (Zed's shift special case only applies to a-z) - // - let mut chars_ignoring_modifiers = - chars_for_modified_key(native_event.keyCode(), NO_MOD); - let mut chars_with_shift = - chars_for_modified_key(native_event.keyCode(), SHIFT_MOD); - let always_use_cmd_layout = always_use_command_layout(); - - // Handle Dvorak+QWERTY / Russian / Armenian - if command || always_use_cmd_layout { - let chars_with_cmd = chars_for_modified_key(native_event.keyCode(), CMD_MOD); - let chars_with_both = - chars_for_modified_key(native_event.keyCode(), CMD_MOD | SHIFT_MOD); - - // We don't do this in the case that the shifted command key generates - // the same character as the unshifted command key (Norwegian, e.g.) - if chars_with_both != chars_with_cmd { - chars_with_shift = chars_with_both; - - // Handle edge-case where cmd-shift-s reports cmd-s instead of - // cmd-shift-s (Ukrainian, etc.) - } else if chars_with_cmd.to_ascii_uppercase() != chars_with_cmd { - chars_with_shift = chars_with_cmd.to_ascii_uppercase(); - } - chars_ignoring_modifiers = chars_with_cmd; - } +unsafe fn parse_keystroke(native_event: ObjcId) -> Keystroke { + let event = native_event as *const NSEvent; + // Keep msg_send for charactersIgnoringModifiers for now; bridging Id + // from icrate would add conversion complexity without clear benefit here. + let cim: ObjcId = msg_send![native_event, charactersIgnoringModifiers]; + let mut characters = unsafe { cim.to_str() }.to_string(); + let mut key_char = None; + let first_char = characters.chars().next().map(|ch| ch as u16); + let modifiers: u64 = unsafe { (&*event).modifierFlags() as u64 }; + + let control = (modifiers & MOD_CONTROL) != 0; + let alt = (modifiers & MOD_OPTION) != 0; + let mut shift = (modifiers & MOD_SHIFT) != 0; + let command = (modifiers & MOD_COMMAND) != 0; + let function = (modifiers & MOD_FUNCTION) != 0 + && first_char.is_none_or(|ch| !(0xF700..=0xF8FF).contains(&ch)); - if !control && !command && !function { - let mut mods = NO_MOD; - if shift { - mods |= SHIFT_MOD; - } - if alt { - mods |= OPTION_MOD; - } - - key_char = Some(chars_for_modified_key(native_event.keyCode(), mods)); + #[allow(non_upper_case_globals)] + let key = match first_char { + Some(SPACE_KEY) => { + key_char = Some(" ".to_string()); + "space".to_string() + } + Some(TAB_KEY) => { + key_char = Some("\t".to_string()); + "tab".to_string() + } + Some(ENTER_KEY) | Some(NUMPAD_ENTER_KEY) => { + key_char = Some("\n".to_string()); + "enter".to_string() + } + Some(BACKSPACE_KEY) => "backspace".to_string(), + Some(ESCAPE_KEY) => "escape".to_string(), + Some(SHIFT_TAB_KEY) => "tab".to_string(), + Some(NS_UP_ARROW) => "up".to_string(), + Some(NS_DOWN_ARROW) => "down".to_string(), + Some(NS_LEFT_ARROW) => "left".to_string(), + Some(NS_RIGHT_ARROW) => "right".to_string(), + Some(NS_PAGE_UP) => "pageup".to_string(), + Some(NS_PAGE_DOWN) => "pagedown".to_string(), + Some(NS_HOME) => "home".to_string(), + Some(NS_END) => "end".to_string(), + Some(NS_DELETE_FN) => "delete".to_string(), + // Observed Insert==NSHelpFunctionKey not NSInsertFunctionKey. + Some(NS_HELP_FN) => "insert".to_string(), + Some(fc) if (0xF704..=0xF726).contains(&fc) => { + let n = fc - 0xF703u16; + format!("f{}", n) + } + _ => { + // Cases to test when modifying this: + // + // qwerty key | none | cmd | cmd-shift + // * Armenian s | ս | cmd-s | cmd-shift-s (layout is non-ASCII, so we use cmd layout) + // * Dvorak+QWERTY s | o | cmd-s | cmd-shift-s (layout switches on cmd) + // * Ukrainian+QWERTY s | с | cmd-s | cmd-shift-s (macOS reports cmd-s instead of cmd-S) + // * Czech 7 | ý | cmd-ý | cmd-7 (layout has shifted numbers) + // * Norwegian 7 | 7 | cmd-7 | cmd-/ (macOS reports cmd-shift-7 instead of cmd-/) + // * Russian 7 | 7 | cmd-7 | cmd-& (shift-7 is . but when cmd is down, should use cmd layout) + // * German QWERTZ ; | ö | cmd-ö | cmd-Ö (Zed's shift special case only applies to a-z) + // + let key_code: u16 = unsafe { (&*event).keyCode() }; + let mut chars_ignoring_modifiers = chars_for_modified_key(key_code, NO_MOD); + let mut chars_with_shift = chars_for_modified_key(key_code, SHIFT_MOD); + let always_use_cmd_layout = always_use_command_layout(); + + // Handle Dvorak+QWERTY / Russian / Armenian + if command || always_use_cmd_layout { + let chars_with_cmd = chars_for_modified_key(key_code, CMD_MOD); + let chars_with_both = chars_for_modified_key(key_code, CMD_MOD | SHIFT_MOD); + + // We don't do this in the case that the shifted command key generates + // the same character as the unshifted command key (Norwegian, e.g.) + if chars_with_both != chars_with_cmd { + chars_with_shift = chars_with_both; + + // Handle edge-case where cmd-shift-s reports cmd-s instead of + // cmd-shift-s (Ukrainian, etc.) + } else if chars_with_cmd.to_ascii_uppercase() != chars_with_cmd { + chars_with_shift = chars_with_cmd.to_ascii_uppercase(); } + chars_ignoring_modifiers = chars_with_cmd; + } - if shift - && chars_ignoring_modifiers - .chars() - .all(|c| c.is_ascii_lowercase()) - { - chars_ignoring_modifiers - } else if shift { - shift = false; - chars_with_shift - } else { - chars_ignoring_modifiers + if !control && !command && !function { + let mut mods = NO_MOD; + if shift { + mods |= SHIFT_MOD; + } + if alt { + mods |= OPTION_MOD; } + + key_char = Some(chars_for_modified_key(key_code, mods)); + } + + if shift + && chars_ignoring_modifiers + .chars() + .all(|c| c.is_ascii_lowercase()) + { + chars_ignoring_modifiers + } else if shift { + shift = false; + chars_with_shift + } else { + chars_ignoring_modifiers } - }; - - Keystroke { - modifiers: Modifiers { - control, - alt, - shift, - platform: command, - function, - }, - key, - key_char, } + }; + + Keystroke { + modifiers: Modifiers { + control, + alt, + shift, + platform: command, + function, + }, + key, + key_char, } } diff --git a/crates/gpui/src/platform/mac/keyboard.rs b/crates/gpui/src/platform/mac/keyboard.rs index 14097312468cbb..7898ffe345ab07 100644 --- a/crates/gpui/src/platform/mac/keyboard.rs +++ b/crates/gpui/src/platform/mac/keyboard.rs @@ -55,19 +55,41 @@ impl MacKeyboardLayout { unsafe { let current_keyboard = TISCopyCurrentKeyboardLayoutInputSource(); - let id: *mut Object = TISGetInputSourceProperty( + // Default values if the system does not report a current layout + if current_keyboard.is_null() { + return Self { + id: "unknown".to_string(), + name: "Unknown".to_string(), + }; + } + + // Helper to read a UTF8String from an Objective‑C string-like object + unsafe fn utf8(obj: *mut Object) -> Option { + if obj.is_null() { + return None; + } + let ptr: *const std::os::raw::c_char = msg_send![obj, UTF8String]; + if ptr.is_null() { + return None; + } + // SAFETY: `ptr` is valid for the duration of this call; we copy into an owned String + Some(unsafe { CStr::from_ptr(ptr) }.to_str().ok()?.to_string()) + } + + let id_obj: *mut Object = TISGetInputSourceProperty( current_keyboard, kTISPropertyInputSourceID as *const c_void, ); - let id: *const std::os::raw::c_char = msg_send![id, UTF8String]; - let id = CStr::from_ptr(id).to_str().unwrap().to_string(); - - let name: *mut Object = TISGetInputSourceProperty( + let name_obj: *mut Object = TISGetInputSourceProperty( current_keyboard, kTISPropertyLocalizedName as *const c_void, ); - let name: *const std::os::raw::c_char = msg_send![name, UTF8String]; - let name = CStr::from_ptr(name).to_str().unwrap().to_string(); + + let id = utf8(id_obj).unwrap_or_else(|| "unknown".to_string()); + let name = utf8(name_obj).unwrap_or_else(|| "Unknown".to_string()); + + // TISCopy* follows the Create/Copy rule; release when done to avoid leaks + let _: () = msg_send![current_keyboard, release]; Self { id, name } } diff --git a/crates/gpui/src/platform/mac/open_type.rs b/crates/gpui/src/platform/mac/open_type.rs index 37a29559fdfbc2..d63fa747963dfe 100644 --- a/crates/gpui/src/platform/mac/open_type.rs +++ b/crates/gpui/src/platform/mac/open_type.rs @@ -1,7 +1,6 @@ #![allow(unused, non_upper_case_globals)] use crate::{FontFallbacks, FontFeatures}; -use cocoa::appkit::CGFloat; use core_foundation::{ array::{ CFArray, CFArrayAppendArray, CFArrayAppendValue, CFArrayCreateMutable, CFArrayGetCount, @@ -15,6 +14,7 @@ use core_foundation::{ string::{CFString, CFStringRef}, }; use core_foundation_sys::locale::CFLocaleCopyPreferredLanguages; +use core_graphics::base::CGFloat; use core_graphics::{display::CFDictionary, geometry::CGAffineTransform}; use core_text::{ font::{CTFont, CTFontRef, cascade_list_for_languages}, diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index dea04d89a06aca..971a2e8856af7b 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -1,6 +1,6 @@ use super::{ BoolExt, MacKeyboardLayout, MacKeyboardMapper, - attributed_string::{NSAttributedString, NSMutableAttributedString}, + attributed_string::{NSAttributedString, NSMutableAttributedString, NSRange}, events::key_to_native, renderer, }; @@ -17,13 +17,11 @@ use block::ConcreteBlock; use cocoa::{ appkit::{ NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, - NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, - NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeRTFD, NSPasteboardTypeString, - NSPasteboardTypeTIFF, NSSavePanel, NSWindow, + NSEventModifierFlags, NSPasteboard, NSWindow, }, base::{BOOL, NO, YES, id, nil, selector}, foundation::{ - NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, + NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSString, NSUInteger, NSURL, }, }; @@ -37,6 +35,10 @@ use core_foundation::{ }; use ctor::ctor; use futures::channel::oneshot; +use icrate::AppKit::{ + NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeRTFD, NSPasteboardTypeString, + NSPasteboardTypeTIFF, NSScrollerStyleOverlay, +}; use itertools::Itertools; use objc::{ class, @@ -45,7 +47,108 @@ use objc::{ runtime::{Class, Object, Sel}, sel, sel_impl, }; +// objc2 typed migration will be introduced incrementally in focused sections. +// Swift C-ABI functions provided by the macOS AppKit shim use parking_lot::Mutex; +#[cfg(target_os = "macos")] +unsafe extern "C" { + fn zed_register_menu_handler(); + fn zed_set_main_menu_json(json: *const ::std::os::raw::c_char); + fn zed_open_panel(request_id: u64, json: *const ::std::os::raw::c_char); + fn zed_save_panel(request_id: u64, json: *const ::std::os::raw::c_char); + fn zed_pasteboard_write_text(text: *const ::std::os::raw::c_char); + fn zed_pasteboard_write_image(bytes: *const u8, len: usize, uti: *const ::std::os::raw::c_char); + fn zed_pasteboard_read_image( + uti: *const ::std::os::raw::c_char, + out_len: *mut usize, + ) -> *mut u8; +} +#[cfg(target_os = "macos")] +#[unsafe(no_mangle)] +pub extern "C" fn gpui_menu_action(tag: u64) { + unsafe { + let app: id = msg_send![APP_CLASS, sharedApplication]; + let app_obj: &mut Object = &mut *app; + let platform = get_mac_platform(app_obj); + let mut lock = platform.0.lock(); + if let Some(mut callback) = lock.menu_command.take() { + let index = tag as usize; + if let Some(action) = lock.menu_actions.get(index) { + let action = action.boxed_clone(); + drop(lock); + callback(action.as_ref()); + platform.0.lock().menu_command.get_or_insert(callback); + return; + } + // Put the callback back even if we did not find an action + platform.0.lock().menu_command.get_or_insert(callback); + } + } +} + +#[cfg(target_os = "macos")] +#[unsafe(no_mangle)] +pub extern "C" fn gpui_validate_menu_action(tag: u64) -> bool { + unsafe { + let app: id = msg_send![APP_CLASS, sharedApplication]; + let app_obj: &mut Object = &mut *app; + let platform = get_mac_platform(app_obj); + let mut lock = platform.0.lock(); + if let Some(mut callback) = lock.validate_menu_command.take() { + let index = tag as usize; + if let Some(action) = lock.menu_actions.get(index) { + let action = action.boxed_clone(); + drop(lock); + let result = callback(action.as_ref()); + platform + .0 + .lock() + .validate_menu_command + .get_or_insert(callback); + return result; + } + platform + .0 + .lock() + .validate_menu_command + .get_or_insert(callback); + } + // Default to enabled when no validator is registered or tag not found + true + } +} + +#[cfg(target_os = "macos")] +#[unsafe(no_mangle)] +pub extern "C" fn gpui_menu_will_open() { + unsafe { + let app: id = msg_send![APP_CLASS, sharedApplication]; + let app_obj: &mut Object = &mut *app; + let platform = get_mac_platform(app_obj); + if let Some(mut callback) = platform.0.lock().will_open_menu.take() { + callback(); + platform.0.lock().will_open_menu.get_or_insert(callback); + } + } +} + +// Expose a dispatcher for status item menus to reuse the same app-level menu callback +pub(crate) fn dispatch_menu_action(action: &dyn crate::Action) { + unsafe { + let app: id = msg_send![APP_CLASS, sharedApplication]; + let app_obj: &mut Object = &mut *app; + let platform = get_mac_platform(app_obj); + let mut lock = platform.0.lock(); + if let Some(mut callback) = lock.menu_command.take() { + let act = action.boxed_clone(); + drop(lock); + callback(act.as_ref()); + platform.0.lock().menu_command.get_or_insert(callback); + } + } +} + +// (Status item click callback is exported by status_item.rs) use ptr::null_mut; use std::{ cell::Cell, @@ -232,6 +335,8 @@ impl MacPlatform { } } + #[cfg(not(target_os = "macos"))] + #[allow(dead_code)] unsafe fn create_menu_bar( &self, menus: &Vec, @@ -240,32 +345,31 @@ impl MacPlatform { keymap: &Keymap, ) -> id { unsafe { - let application_menu = NSMenu::new(nil).autorelease(); - application_menu.setDelegate_(delegate); + let mut application_menu: id = msg_send![class!(NSMenu), new]; + application_menu = msg_send![application_menu, autorelease]; + let _: () = msg_send![application_menu, setDelegate: delegate]; for menu_config in menus { - let menu = NSMenu::new(nil).autorelease(); + let mut menu: id = msg_send![class!(NSMenu), new]; + menu = msg_send![menu, autorelease]; let menu_title = ns_string(&menu_config.name); - menu.setTitle_(menu_title); - menu.setDelegate_(delegate); + let _: () = msg_send![menu, setTitle: menu_title]; + let _: () = msg_send![menu, setDelegate: delegate]; for item_config in &menu_config.items { - menu.addItem_(Self::create_menu_item( - item_config, - delegate, - actions, - keymap, - )); + Self::add_menu_item(menu, item_config, delegate, actions, keymap); } - let menu_item = NSMenuItem::new(nil).autorelease(); - menu_item.setTitle_(menu_title); - menu_item.setSubmenu_(menu); - application_menu.addItem_(menu_item); + let mut menu_item: id = msg_send![class!(NSMenuItem), alloc]; + menu_item = msg_send![menu_item, init]; + menu_item = msg_send![menu_item, autorelease]; + let _: () = msg_send![menu_item, setTitle: menu_title]; + let _: () = msg_send![menu_item, setSubmenu: menu]; + let _: () = msg_send![application_menu, addItem: menu_item]; if menu_config.name == "Window" { let app: id = msg_send![APP_CLASS, sharedApplication]; - app.setWindowsMenu_(menu); + let _: () = msg_send![app, setWindowsMenu: menu]; } } @@ -281,21 +385,170 @@ impl MacPlatform { keymap: &Keymap, ) -> id { unsafe { - let dock_menu = NSMenu::new(nil); - dock_menu.setDelegate_(delegate); + let dock_menu: id = msg_send![class!(NSMenu), new]; + let _: () = msg_send![dock_menu, setDelegate: delegate]; for item_config in menu_items { - dock_menu.addItem_(Self::create_menu_item( - &item_config, - delegate, - actions, - keymap, - )); + Self::add_menu_item(dock_menu, &item_config, delegate, actions, keymap); } dock_menu } } + unsafe fn add_menu_item( + parent_menu: id, + item: &MenuItem, + delegate: id, + actions: &mut Vec>, + keymap: &Keymap, + ) { + static DEFAULT_CONTEXT: OnceLock> = OnceLock::new(); + + unsafe { + match item { + MenuItem::Separator => { + let sep: id = msg_send![class!(NSMenuItem), separatorItem]; + let _: () = msg_send![parent_menu, addItem: sep]; + } + MenuItem::Action { + name, + action, + os_action, + } => { + let keystrokes = keymap + .bindings_for_action(action.as_ref()) + .find_or_first(|binding| { + binding.predicate().is_none_or(|predicate| { + predicate.eval(DEFAULT_CONTEXT.get_or_init(|| { + let mut workspace_context = KeyContext::new_with_defaults(); + workspace_context.add("Workspace"); + let mut pane_context = KeyContext::new_with_defaults(); + pane_context.add("Pane"); + let mut editor_context = KeyContext::new_with_defaults(); + editor_context.add("Editor"); + + pane_context.extend(&editor_context); + workspace_context.extend(&pane_context); + vec![workspace_context] + })) + }) + }) + .map(|binding| binding.keystrokes()); + + let selector = match os_action { + Some(crate::OsAction::Cut) => selector("cut:"), + Some(crate::OsAction::Copy) => selector("copy:"), + Some(crate::OsAction::Paste) => selector("paste:"), + Some(crate::OsAction::SelectAll) => selector("selectAll:"), + Some(crate::OsAction::Undo) => selector("handleGPUIMenuItem:"), + Some(crate::OsAction::Redo) => selector("handleGPUIMenuItem:"), + None => selector("handleGPUIMenuItem:"), + }; + + let item: id = if let Some(keystrokes) = keystrokes { + if keystrokes.len() == 1 { + let keystroke = &keystrokes[0]; + let mut mask = NSEventModifierFlags::empty(); + for (modifier, flag) in &[ + ( + keystroke.modifiers().platform, + NSEventModifierFlags::NSCommandKeyMask, + ), + ( + keystroke.modifiers().control, + NSEventModifierFlags::NSControlKeyMask, + ), + ( + keystroke.modifiers().alt, + NSEventModifierFlags::NSAlternateKeyMask, + ), + ( + keystroke.modifiers().shift, + NSEventModifierFlags::NSShiftKeyMask, + ), + ] { + if *modifier { + mask |= *flag; + } + } + + let mut tmp: id = msg_send![class!(NSMenuItem), alloc]; + tmp = msg_send![ + tmp, + initWithTitle: ns_string(name) + action: selector + keyEquivalent: ns_string(key_to_native(keystroke.key()).as_ref()) + ]; + let item: id = msg_send![tmp, autorelease]; + if Self::os_version() >= SemanticVersion::new(12, 0, 0) { + let _: () = msg_send![item, setAllowsAutomaticKeyEquivalentLocalization: NO]; + } + let _: () = msg_send![item, setKeyEquivalentModifierMask: mask]; + item + } else { + let mut tmp: id = msg_send![class!(NSMenuItem), alloc]; + tmp = msg_send![ + tmp, + initWithTitle: ns_string(name) + action: selector + keyEquivalent: ns_string("") + ]; + msg_send![tmp, autorelease] + } + } else { + let mut tmp: id = msg_send![class!(NSMenuItem), alloc]; + tmp = msg_send![ + tmp, + initWithTitle: ns_string(name) + action: selector + keyEquivalent: ns_string("") + ]; + msg_send![tmp, autorelease] + }; + + let tag = actions.len() as NSInteger; + let _: () = msg_send![item, setTag: tag]; + actions.push(action.boxed_clone()); + let _: () = msg_send![parent_menu, addItem: item]; + } + MenuItem::Submenu(Menu { name, items }) => { + let mut item: id = msg_send![class!(NSMenuItem), alloc]; + item = msg_send![item, init]; + item = msg_send![item, autorelease]; + let mut submenu: id = msg_send![class!(NSMenu), new]; + submenu = msg_send![submenu, autorelease]; + let _: () = msg_send![submenu, setDelegate: delegate]; + for subitem in items { + Self::add_menu_item(submenu, subitem, delegate, actions, keymap); + } + let _: () = msg_send![item, setSubmenu: submenu]; + let _: () = msg_send![item, setTitle: ns_string(name)]; + let _: () = msg_send![parent_menu, addItem: item]; + } + MenuItem::SystemMenu(OsMenu { name, menu_type }) => { + let mut item: id = msg_send![class!(NSMenuItem), alloc]; + item = msg_send![item, init]; + item = msg_send![item, autorelease]; + let mut submenu: id = msg_send![class!(NSMenu), new]; + submenu = msg_send![submenu, autorelease]; + let _: () = msg_send![submenu, setDelegate: delegate]; + let _: () = msg_send![item, setSubmenu: submenu]; + let _: () = msg_send![item, setTitle: ns_string(name)]; + + match menu_type { + SystemMenuType::Services => { + let app: id = msg_send![APP_CLASS, sharedApplication]; + let _: () = msg_send![app, setServicesMenu: item]; + } + } + + let _: () = msg_send![parent_menu, addItem: item]; + } + } + } + } + // Legacy helper removed; use add_menu_item instead + /* unsafe fn create_menu_item( item: &MenuItem, delegate: id, @@ -306,7 +559,7 @@ impl MacPlatform { unsafe { match item { - MenuItem::Separator => NSMenuItem::separatorItem(nil), + MenuItem::Separator => msg_send![class!(NSMenuItem), separatorItem], MenuItem::Action { name, action, @@ -347,7 +600,7 @@ impl MacPlatform { None => selector("handleGPUIMenuItem:"), }; - let item; + let mut item: id; if let Some(keystrokes) = keystrokes { if keystrokes.len() == 1 { let keystroke = &keystrokes[0]; @@ -375,34 +628,37 @@ impl MacPlatform { } } - item = NSMenuItem::alloc(nil) - .initWithTitle_action_keyEquivalent_( - ns_string(name), - selector, - ns_string(key_to_native(keystroke.key()).as_ref()), - ) - .autorelease(); + let mut tmp: id = msg_send![class!(NSMenuItem), alloc]; + tmp = msg_send![ + tmp, + initWithTitle: ns_string(name) + action: selector + keyEquivalent: ns_string(key_to_native(keystroke.key()).as_ref()) + ]; + item = msg_send![tmp, autorelease]; if Self::os_version() >= SemanticVersion::new(12, 0, 0) { let _: () = msg_send![item, setAllowsAutomaticKeyEquivalentLocalization: NO]; } - item.setKeyEquivalentModifierMask_(mask); + let _: () = msg_send![item, setKeyEquivalentModifierMask: mask]; } else { - item = NSMenuItem::alloc(nil) - .initWithTitle_action_keyEquivalent_( - ns_string(name), - selector, - ns_string(""), - ) - .autorelease(); + let mut tmp: id = msg_send![class!(NSMenuItem), alloc]; + tmp = msg_send![ + tmp, + initWithTitle: ns_string(name) + action: selector + keyEquivalent: ns_string("") + ]; + item = msg_send![tmp, autorelease]; } } else { - item = NSMenuItem::alloc(nil) - .initWithTitle_action_keyEquivalent_( - ns_string(name), - selector, - ns_string(""), - ) - .autorelease(); + let mut tmp: id = msg_send![class!(NSMenuItem), alloc]; + tmp = msg_send![ + tmp, + initWithTitle: ns_string(name) + action: selector + keyEquivalent: ns_string("") + ]; + item = msg_send![tmp, autorelease]; } let tag = actions.len() as NSInteger; @@ -411,27 +667,33 @@ impl MacPlatform { item } MenuItem::Submenu(Menu { name, items }) => { - let item = NSMenuItem::new(nil).autorelease(); - let submenu = NSMenu::new(nil).autorelease(); - submenu.setDelegate_(delegate); + let mut item: id = msg_send![class!(NSMenuItem), alloc]; + item = msg_send![item, init]; + item = msg_send![item, autorelease]; + let mut submenu: id = msg_send![class!(NSMenu), new]; + submenu = msg_send![submenu, autorelease]; + let _: () = msg_send![submenu, setDelegate: delegate]; for item in items { - submenu.addItem_(Self::create_menu_item(item, delegate, actions, keymap)); + let _: () = msg_send![submenu, addItem: Self::create_menu_item(item, delegate, actions, keymap)]; } - item.setSubmenu_(submenu); - item.setTitle_(ns_string(name)); + let _: () = msg_send![item, setSubmenu: submenu]; + let _: () = msg_send![item, setTitle: ns_string(name)]; item } MenuItem::SystemMenu(OsMenu { name, menu_type }) => { - let item = NSMenuItem::new(nil).autorelease(); - let submenu = NSMenu::new(nil).autorelease(); - submenu.setDelegate_(delegate); - item.setSubmenu_(submenu); - item.setTitle_(ns_string(name)); + let mut item: id = msg_send![class!(NSMenuItem), alloc]; + item = msg_send![item, init]; + item = msg_send![item, autorelease]; + let mut submenu: id = msg_send![class!(NSMenu), new]; + submenu = msg_send![submenu, autorelease]; + let _: () = msg_send![submenu, setDelegate: delegate]; + let _: () = msg_send![item, setSubmenu: submenu]; + let _: () = msg_send![item, setTitle: ns_string(name)]; match menu_type { SystemMenuType::Services => { let app: id = msg_send![APP_CLASS, sharedApplication]; - app.setServicesMenu_(item); + let _: () = msg_send![app, setServicesMenu: item]; } } @@ -440,6 +702,7 @@ impl MacPlatform { } } } + */ fn os_version() -> SemanticVersion { let version = unsafe { @@ -593,7 +856,12 @@ impl Platform for MacPlatform { #[cfg(feature = "screen-capture")] fn is_screen_capture_supported(&self) -> bool { - let min_version = cocoa::foundation::NSOperatingSystemVersion::new(12, 3, 0); + use icrate::Foundation::NSOperatingSystemVersion; + let min_version = NSOperatingSystemVersion { + majorVersion: 12, + minorVersion: 3, + patchVersion: 0, + }; super::is_macos_version_at_least(min_version) } @@ -703,50 +971,51 @@ impl Platform for MacPlatform { &self, options: PathPromptOptions, ) -> oneshot::Receiver>>> { - let (done_tx, done_rx) = oneshot::channel(); - self.foreground_executor() - .spawn(async move { - unsafe { - let panel = NSOpenPanel::openPanel(nil); - panel.setCanChooseDirectories_(options.directories.to_objc()); - panel.setCanChooseFiles_(options.files.to_objc()); - panel.setAllowsMultipleSelection_(options.multiple.to_objc()); - - panel.setCanCreateDirectories(true.to_objc()); - panel.setResolvesAliases_(false.to_objc()); - let done_tx = Cell::new(Some(done_tx)); - let block = ConcreteBlock::new(move |response: NSModalResponse| { - let result = if response == NSModalResponse::NSModalResponseOk { - let mut result = Vec::new(); - let urls = panel.URLs(); - for i in 0..urls.count() { - let url = urls.objectAtIndex(i); - if url.isFileURL() == YES - && let Ok(path) = ns_url_to_path(url) - { - result.push(path) - } - } - Some(result) - } else { - None - }; - - if let Some(done_tx) = done_tx.take() { - let _ = done_tx.send(Ok(result)); - } - }); - let block = block.copy(); + #[cfg(target_os = "macos")] + { + use std::collections::HashMap; + use std::sync::{Mutex as StdMutex, OnceLock}; + type OpenTx = oneshot::Sender>>>; + static OPEN_SENDERS: OnceLock>> = OnceLock::new(); + static REQ_COUNTER: OnceLock = OnceLock::new(); + + #[derive(serde::Serialize)] + struct OpenOpts { + directories: bool, + files: bool, + multiple: bool, + #[serde(skip_serializing_if = "Option::is_none")] + prompt: Option, + } - if let Some(prompt) = options.prompt { - let _: () = msg_send![panel, setPrompt: ns_string(&prompt)]; - } + let (tx, rx) = oneshot::channel(); + let req_id = REQ_COUNTER + .get_or_init(|| std::sync::atomic::AtomicU64::new(1)) + .fetch_add(1, std::sync::atomic::Ordering::SeqCst); + OPEN_SENDERS + .get_or_init(|| StdMutex::new(HashMap::new())) + .lock() + .unwrap() + .insert(req_id, tx); + + let opts = OpenOpts { + directories: options.directories, + files: options.files, + multiple: options.multiple, + prompt: options.prompt.as_deref().map(|s| s.to_string()), + }; + let json = serde_json::to_string(&opts).unwrap_or_else(|_| "{}".into()); + if let Ok(cjson) = std::ffi::CString::new(json) { + unsafe { zed_open_panel(req_id, cjson.as_ptr()) }; + } - let _: () = msg_send![panel, beginWithCompletionHandler: block]; - } - }) - .detach(); - done_rx + return rx; + } + #[cfg(not(target_os = "macos"))] + { + let (_tx, rx) = oneshot::channel(); + rx + } } fn prompt_for_new_path( @@ -754,71 +1023,46 @@ impl Platform for MacPlatform { directory: &Path, suggested_name: Option<&str>, ) -> oneshot::Receiver>> { - let directory = directory.to_owned(); - let suggested_name = suggested_name.map(|s| s.to_owned()); - let (done_tx, done_rx) = oneshot::channel(); - self.foreground_executor() - .spawn(async move { - unsafe { - let panel = NSSavePanel::savePanel(nil); - let path = ns_string(directory.to_string_lossy().as_ref()); - let url = NSURL::fileURLWithPath_isDirectory_(nil, path, true.to_objc()); - panel.setDirectoryURL(url); - - if let Some(suggested_name) = suggested_name { - let name_string = ns_string(&suggested_name); - let _: () = msg_send![panel, setNameFieldStringValue: name_string]; - } - - let done_tx = Cell::new(Some(done_tx)); - let block = ConcreteBlock::new(move |response: NSModalResponse| { - let mut result = None; - if response == NSModalResponse::NSModalResponseOk { - let url = panel.URL(); - if url.isFileURL() == YES { - result = ns_url_to_path(panel.URL()).ok().map(|mut result| { - let Some(filename) = result.file_name() else { - return result; - }; - let chunks = filename - .as_bytes() - .split(|&b| b == b'.') - .collect::>(); - - // https://github.com/zed-industries/zed/issues/16969 - // Workaround a bug in macOS Sequoia that adds an extra file-extension - // sometimes. e.g. `a.sql` becomes `a.sql.s` or `a.txtx` becomes `a.txtx.txt` - // - // This is conditional on OS version because I'd like to get rid of it, so that - // you can manually create a file called `a.sql.s`. That said it seems better - // to break that use-case than breaking `a.sql`. - if chunks.len() == 3 - && chunks[1].starts_with(chunks[2]) - && Self::os_version() >= SemanticVersion::new(15, 0, 0) - { - let new_filename = OsStr::from_bytes( - &filename.as_bytes() - [..chunks[0].len() + 1 + chunks[1].len()], - ) - .to_owned(); - result.set_file_name(&new_filename); - } - result - }) - } - } + #[cfg(target_os = "macos")] + { + use std::collections::HashMap; + use std::sync::{Mutex as StdMutex, OnceLock}; + type SaveTx = oneshot::Sender>>; + static SAVE_SENDERS: OnceLock>> = OnceLock::new(); + static REQ_COUNTER: OnceLock = OnceLock::new(); + #[derive(serde::Serialize)] + struct SaveOpts<'a> { + directory: &'a str, + #[serde(skip_serializing_if = "Option::is_none")] + suggested_name: Option<&'a str>, + } - if let Some(done_tx) = done_tx.take() { - let _ = done_tx.send(Ok(result)); - } - }); - let block = block.copy(); - let _: () = msg_send![panel, beginWithCompletionHandler: block]; - } - }) - .detach(); + let (tx, rx) = oneshot::channel(); + let req_id = REQ_COUNTER + .get_or_init(|| std::sync::atomic::AtomicU64::new(1)) + .fetch_add(1, std::sync::atomic::Ordering::SeqCst); + SAVE_SENDERS + .get_or_init(|| StdMutex::new(HashMap::new())) + .lock() + .unwrap() + .insert(req_id, tx); - done_rx + let dir_str = directory.to_string_lossy().to_string(); + let opts = SaveOpts { + directory: &dir_str, + suggested_name, + }; + let json = serde_json::to_string(&opts).unwrap_or_else(|_| "{}".into()); + if let Ok(cjson) = std::ffi::CString::new(json) { + unsafe { zed_save_panel(req_id, cjson.as_ptr()) }; + } + return rx; + } + #[cfg(not(target_os = "macos"))] + { + let (_tx, rx) = oneshot::channel(); + rx + } } fn can_select_mixed_files_and_dirs(&self) -> bool { @@ -901,15 +1145,159 @@ impl Platform for MacPlatform { } fn set_menus(&self, menus: Vec, keymap: &Keymap) { - unsafe { - let app: id = msg_send![APP_CLASS, sharedApplication]; + // Swift-native path: full JSON menu with action tags and shortcuts. + #[cfg(target_os = "macos")] + { + #[derive(serde::Serialize)] + #[serde(tag = "kind", rename_all = "lowercase")] + enum JsItem<'a> { + Action { + title: &'a str, + tag: u64, + #[serde(skip_serializing_if = "Option::is_none")] + key_equivalent: Option, + #[serde(skip_serializing_if = "Vec::is_empty")] + modifiers: Vec<&'static str>, + }, + Separator, + Submenu { + title: &'a str, + items: Vec>, + }, + System { + title: &'a str, + system_type: &'static str, + items: Vec>, + }, + } + #[derive(serde::Serialize)] + struct JsMenu<'a> { + title: &'a str, + items: Vec>, + } + #[derive(serde::Serialize)] + struct JsSpec<'a> { + menus: Vec>, + } + let mut state = self.0.lock(); + state.menu_actions.clear(); let actions = &mut state.menu_actions; - let menu = self.create_menu_bar(&menus, NSWindow::delegate(app), actions, keymap); - drop(state); - app.setMainMenu_(menu); + + fn action_shortcut( + action: &dyn Action, + keymap: &Keymap, + ) -> (Option, Vec<&'static str>) { + use crate::KeyContext; + let mut workspace_context = KeyContext::new_with_defaults(); + workspace_context.add("Workspace"); + let mut pane_context = KeyContext::new_with_defaults(); + pane_context.add("Pane"); + let mut editor_context = KeyContext::new_with_defaults(); + editor_context.add("Editor"); + pane_context.extend(&editor_context); + workspace_context.extend(&pane_context); + let default_contexts = vec![workspace_context]; + let keystrokes = keymap + .bindings_for_action(action) + .find_or_first(|binding| { + binding + .predicate() + .is_none_or(|p| p.eval(&default_contexts)) + }) + .map(|binding| binding.keystrokes()); + if let Some(ks) = keystrokes { + if ks.len() == 1 { + let k = &ks[0]; + let key = key_to_native(k.key()).to_string(); + let mut mods = Vec::new(); + if k.modifiers().platform { + mods.push("command"); + } + if k.modifiers().control { + mods.push("control"); + } + if k.modifiers().alt { + mods.push("option"); + } + if k.modifiers().shift { + mods.push("shift"); + } + return (Some(key), mods); + } + } + (None, Vec::new()) + } + + fn encode_items<'a>( + src: &'a [MenuItem], + keymap: &Keymap, + actions: &mut Vec>, + out: &mut Vec>, + ) { + for item in src { + match item { + MenuItem::Separator => out.push(JsItem::Separator), + MenuItem::Action { name, action, .. } => { + let tag = actions.len() as u64; + actions.push(action.boxed_clone()); + let (key, mods) = action_shortcut(action.as_ref(), keymap); + out.push(JsItem::Action { + title: name, + tag, + key_equivalent: key, + modifiers: mods, + }); + } + MenuItem::Submenu(Menu { name, items }) => { + let mut sub = Vec::new(); + encode_items(items, keymap, actions, &mut sub); + out.push(JsItem::Submenu { + title: name, + items: sub, + }); + } + MenuItem::SystemMenu(OsMenu { name, menu_type }) => { + let mut sub = Vec::new(); + let system_type = match menu_type { + SystemMenuType::Services => "services", + }; + out.push(JsItem::System { + title: name, + system_type, + items: sub, + }); + } + } + } + } + + let mut js_menus = Vec::new(); + for m in &menus { + let mut items = Vec::new(); + encode_items(&m.items, keymap, actions, &mut items); + js_menus.push(JsMenu { + title: &m.name, + items, + }); + } + let spec = JsSpec { menus: js_menus }; + let json = serde_json::to_string(&spec).unwrap_or_else(|_| "{\"menus\":[]}".into()); + unsafe { zed_register_menu_handler() }; + use std::ffi::CString; + if let Ok(cjson) = CString::new(json) { + unsafe { zed_set_main_menu_json(cjson.as_ptr()) }; + } + + state.menus = Some(menus.into_iter().map(|menu| menu.owned()).collect()); + return; + } + + // Non-macOS: keep menus in state only. + #[cfg(not(target_os = "macos"))] + { + self.0.lock().menus = Some(menus.into_iter().map(|menu| menu.owned()).collect()); } - self.0.lock().menus = Some(menus.into_iter().map(|menu| menu.owned()).collect()); } fn get_menus(&self) -> Option> { @@ -921,7 +1309,8 @@ impl Platform for MacPlatform { let app: id = msg_send![APP_CLASS, sharedApplication]; let mut state = self.0.lock(); let actions = &mut state.menu_actions; - let new = self.create_dock_menu(menu, NSWindow::delegate(app), actions, keymap); + let delegate: id = msg_send![app, delegate]; + let new = self.create_dock_menu(menu, delegate, actions, keymap); if let Some(old) = state.dock_menu.replace(new) { CFRelease(old as _) } @@ -1004,12 +1393,9 @@ impl Platform for MacPlatform { } fn should_auto_hide_scrollbars(&self) -> bool { - #[allow(non_upper_case_globals)] - const NSScrollerStyleOverlay: NSInteger = 1; - unsafe { let style: NSInteger = msg_send![class!(NSScroller), preferredScrollerStyle]; - style == NSScrollerStyleOverlay + style == (NSScrollerStyleOverlay as NSInteger) } } @@ -1059,31 +1445,29 @@ impl Platform for MacPlatform { // Only set rich text clipboard types if we actually have 1+ images to include. if any_images { - let rtfd_data = attributed_string.RTFDFromRange_documentAttributes_( - NSRange::new(0, msg_send![attributed_string, length]), - nil, - ); + let len: u64 = msg_send![attributed_string, length]; + let rtfd_data = attributed_string + .RTFDFromRange_documentAttributes_(NSRange::new(0, len as usize), nil); if rtfd_data != nil { state .pasteboard - .setData_forType(rtfd_data, NSPasteboardTypeRTFD); + .setData_forType(rtfd_data, NSPasteboardTypeRTFD as *const _ as id); } - let rtf_data = attributed_string.RTFFromRange_documentAttributes_( - NSRange::new(0, attributed_string.length()), - nil, - ); + let len2: u64 = attributed_string.length(); + let rtf_data = attributed_string + .RTFFromRange_documentAttributes_(NSRange::new(0, len2 as usize), nil); if rtf_data != nil { state .pasteboard - .setData_forType(rtf_data, NSPasteboardTypeRTF); + .setData_forType(rtf_data, NSPasteboardTypeRTF as *const _ as id); } } let plain_text = attributed_string.string(); state .pasteboard - .setString_forType(plain_text, NSPasteboardTypeString); + .setString_forType(plain_text, NSPasteboardTypeString as *const _ as id); } } } @@ -1092,7 +1476,7 @@ impl Platform for MacPlatform { let state = self.0.lock(); let pasteboard = state.pasteboard; - // First, see if it's a string. + // Preserve original behavior (metadata-aware) for text; use Swift only for images. unsafe { let types: id = pasteboard.types(); let string_type: id = ns_string("public.utf8-plain-text"); @@ -1262,6 +1646,13 @@ impl MacPlatform { unsafe fn write_plaintext_to_clipboard(&self, string: &ClipboardString) { unsafe { + // Fast path: if there is no metadata, use Swift-native pasteboard write for text. + if string.metadata.is_none() { + if let Ok(cstr) = std::ffi::CString::new(string.text.as_str()) { + zed_pasteboard_write_text(cstr.as_ptr()); + return; + } + } let state = self.0.lock(); state.pasteboard.clearContents(); @@ -1272,7 +1663,7 @@ impl MacPlatform { ); state .pasteboard - .setData_forType(text_bytes, NSPasteboardTypeString); + .setData_forType(text_bytes, NSPasteboardTypeString as *const _ as id); if let Some(metadata) = string.metadata.as_ref() { let hash_bytes = ClipboardString::text_hash(&string.text).to_be_bytes(); @@ -1299,15 +1690,27 @@ impl MacPlatform { unsafe fn write_image_to_clipboard(&self, image: &Image) { unsafe { + let uti = match image.format { + ImageFormat::Png => "public.png", + ImageFormat::Jpeg => "public.jpeg", + ImageFormat::Tiff => "public.tiff", + ImageFormat::Webp => "org.webmproject.webp", + ImageFormat::Gif => "com.compuserve.gif", + ImageFormat::Bmp => "com.microsoft.bmp", + ImageFormat::Svg => "public.svg-image", + }; + if let Ok(cuti) = std::ffi::CString::new(uti) { + zed_pasteboard_write_image(image.bytes.as_ptr(), image.bytes.len(), cuti.as_ptr()); + return; + } + // Fallback to legacy path if UTI conversion failed let state = self.0.lock(); state.pasteboard.clearContents(); - let bytes = NSData::dataWithBytes_length_( nil, image.bytes.as_ptr() as *const c_void, image.bytes.len() as u64, ); - state .pasteboard .setData_forType(bytes, Into::::into(image.format).inner_mut()); @@ -1319,22 +1722,51 @@ fn try_clipboard_image(pasteboard: id, format: ImageFormat) -> Option "public.png", + ImageFormat::Jpeg => "public.jpeg", + ImageFormat::Tiff => "public.tiff", + ImageFormat::Webp => "org.webmproject.webp", + ImageFormat::Gif => "com.compuserve.gif", + ImageFormat::Bmp => "com.microsoft.bmp", + ImageFormat::Svg => "public.svg-image", + }; + if let Ok(cuti) = std::ffi::CString::new(uti) { + let mut len: usize = 0; + let ptr = zed_pasteboard_read_image(cuti.as_ptr(), &mut len as *mut usize); + if !ptr.is_null() && len > 0 { + let bytes = Vec::from_raw_parts(ptr, len, len); + let id_val = hash(&bytes); + // We must not free ptr after Vec::from_raw_parts + return Some(ClipboardItem { + entries: vec![ClipboardEntry::Image(Image { + format, + bytes, + id: id_val, + })], + }); + } + } + // Fallback to legacy path let types: id = pasteboard.types(); if msg_send![types, containsObject: ut_type.inner()] { let data = pasteboard.dataForType(ut_type.inner_mut()); if data == nil { - None - } else { - let bytes = Vec::from(slice::from_raw_parts( - data.bytes() as *mut u8, - data.length() as usize, - )); - let id = hash(&bytes); - - Some(ClipboardItem { - entries: vec![ClipboardEntry::Image(Image { format, bytes, id })], - }) + return None; } + let bytes = Vec::from(slice::from_raw_parts( + data.bytes() as *mut u8, + data.length() as usize, + )); + let id_val = hash(&bytes); + Some(ClipboardItem { + entries: vec![ClipboardEntry::Image(Image { + format, + bytes, + id: id_val, + })], + }) } else { None } @@ -1518,6 +1950,82 @@ unsafe fn ns_url_to_path(url: id) -> Result { }))) } +// Panel callbacks from Swift (C ABI) +#[cfg(target_os = "macos")] +#[unsafe(no_mangle)] +pub extern "C" fn gpui_open_panel_result(request_id: u64, json: *const ::std::os::raw::c_char) { + use futures::channel::oneshot; + use std::collections::HashMap; + use std::ffi::CStr; + use std::sync::{Mutex as StdMutex, OnceLock}; + type OpenTx = oneshot::Sender>>>; + static OPEN_SENDERS: OnceLock>> = OnceLock::new(); + let map_lock = OPEN_SENDERS.get_or_init(|| StdMutex::new(HashMap::new())); + let sender = map_lock.lock().unwrap().remove(&request_id); + if let Some(tx) = sender { + let s = unsafe { CStr::from_ptr(json) } + .to_string_lossy() + .to_string(); + #[derive(serde::Deserialize)] + struct OpenRes { + paths: Option>, + } + let parsed: Result = serde_json::from_str(&s).map_err(|e| anyhow!(e)); + let result = parsed.map(|res| { + res.paths + .map(|v| v.into_iter().map(PathBuf::from).collect()) + }); + let _ = tx.send(result); + } +} + +#[cfg(target_os = "macos")] +#[unsafe(no_mangle)] +pub extern "C" fn gpui_save_panel_result(request_id: u64, json: *const ::std::os::raw::c_char) { + use futures::channel::oneshot; + use std::collections::HashMap; + use std::ffi::CStr; + use std::sync::{Mutex as StdMutex, OnceLock}; + type SaveTx = oneshot::Sender>>; + static SAVE_SENDERS: OnceLock>> = OnceLock::new(); + let map_lock = SAVE_SENDERS.get_or_init(|| StdMutex::new(HashMap::new())); + let sender = map_lock.lock().unwrap().remove(&request_id); + if let Some(tx) = sender { + let s = unsafe { CStr::from_ptr(json) } + .to_string_lossy() + .to_string(); + #[derive(serde::Deserialize)] + struct SaveRes { + path: Option, + } + let parsed: Result = serde_json::from_str(&s).map_err(|e| anyhow!(e)); + let result = parsed.map(|res| { + res.path.map(|p| { + let mut result = PathBuf::from(p); + // Apply Sequoia filename fix from legacy path for parity + if let Some(filename) = result.file_name() { + let chunks: Vec<_> = filename.as_bytes().split(|&b| b == b'.').collect(); + if chunks.len() == 3 + && chunks[1].starts_with(chunks[2]) + && MacPlatform::os_version() >= SemanticVersion::new(15, 0, 0) + { + use std::ffi::OsStr; + let new_filename = OsStr::from_bytes( + &filename.as_bytes()[..chunks[0].len() + 1 + chunks[1].len()], + ) + .to_owned(); + result.set_file_name(&new_filename); + } + } + result + }) + }); + let _ = tx.send(result); + } +} + +// (Helper conversions for typed objc2 objects will be added when migrating sections.) + #[link(name = "Carbon", kind = "framework")] unsafe extern "C" { pub(super) fn TISCopyCurrentKeyboardLayoutInputSource() -> *mut Object; @@ -1589,7 +2097,7 @@ struct UTType(id); impl UTType { pub fn png() -> Self { // https://developer.apple.com/documentation/uniformtypeidentifiers/uttype-swift.struct/png - Self(unsafe { NSPasteboardTypePNG }) // This is a rare case where there's a built-in NSPasteboardType + Self(unsafe { NSPasteboardTypePNG } as *const _ as id) // Built-in NSPasteboardType } pub fn jpeg() -> Self { @@ -1619,7 +2127,7 @@ impl UTType { pub fn tiff() -> Self { // https://developer.apple.com/documentation/uniformtypeidentifiers/uttype-swift.struct/tiff - Self(unsafe { NSPasteboardTypeTIFF }) // This is a rare case where there's a built-in NSPasteboardType + Self(unsafe { NSPasteboardTypeTIFF } as *const _ as id) // Built-in NSPasteboardType } fn inner(&self) -> *const Object { @@ -1665,7 +2173,7 @@ mod tests { .0 .lock() .pasteboard - .setData_forType(bytes, NSPasteboardTypeString); + .setData_forType(bytes, NSPasteboardTypeString as *const _ as id); } assert_eq!( platform.read_from_clipboard(), diff --git a/crates/gpui/src/platform/mac/status_item.rs b/crates/gpui/src/platform/mac/status_item.rs index 21cc86090c8c81..652aec192b61fd 100644 --- a/crates/gpui/src/platform/mac/status_item.rs +++ b/crates/gpui/src/platform/mac/status_item.rs @@ -1,388 +1,171 @@ -use crate::{ - geometry::{ - rect::RectF, - vector::{vec2f, Vector2F}, - }, - platform::{ - self, - mac::{platform::NSViewLayerContentsRedrawDuringViewResize, renderer::Renderer}, - Event, FontSystem, WindowBounds, - }, - Scene, -}; -use cocoa::{ - appkit::{NSScreen, NSSquareStatusItemLength, NSStatusBar, NSStatusItem, NSView, NSWindow}, - base::{id, nil, YES}, - foundation::{NSPoint, NSRect, NSSize}, -}; -use ctor::ctor; -use foreign_types::ForeignTypeRef; -use objc::{ - class, - declare::ClassDecl, - msg_send, - rc::StrongPtr, - runtime::{Class, Object, Protocol, Sel}, - sel, sel_impl, -}; -use std::{ - cell::RefCell, - ffi::c_void, - ptr, - rc::{Rc, Weak}, - sync::Arc, -}; - -use super::screen::Screen; - -static mut VIEW_CLASS: *const Class = ptr::null(); -const STATE_IVAR: &str = "state"; - -#[ctor] -unsafe fn build_classes() { - VIEW_CLASS = { - let mut decl = ClassDecl::new("GPUIStatusItemView", class!(NSView)).unwrap(); - decl.add_ivar::<*mut c_void>(STATE_IVAR); - - decl.add_method(sel!(dealloc), dealloc_view as extern "C" fn(&Object, Sel)); - - decl.add_method( - sel!(mouseDown:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(mouseUp:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(rightMouseDown:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(rightMouseUp:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(otherMouseDown:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(otherMouseUp:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(mouseMoved:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(mouseDragged:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(scrollWheel:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(flagsChanged:), - handle_view_event as extern "C" fn(&Object, Sel, id), - ); - decl.add_method( - sel!(makeBackingLayer), - make_backing_layer as extern "C" fn(&Object, Sel) -> id, - ); - decl.add_method( - sel!(viewDidChangeEffectiveAppearance), - view_did_change_effective_appearance as extern "C" fn(&Object, Sel), - ); - - decl.add_protocol(Protocol::get("CALayerDelegate").unwrap()); - decl.add_method( - sel!(displayLayer:), - display_layer as extern "C" fn(&Object, Sel, id), - ); - - decl.register() - }; +use std::sync::Arc; + +use crate::platform::FontSystem; + +extern "C" { + fn zed_status_item_create() -> u64; + fn zed_status_item_set_title(id: u64, title: *const ::std::os::raw::c_char); + fn zed_status_item_remove(id: u64); + fn zed_status_item_set_image( + id: u64, + bytes: *const u8, + len: usize, + uti: *const ::std::os::raw::c_char, + is_template: bool, + ); + fn zed_status_item_set_menu(id: u64, json: *const ::std::os::raw::c_char); } -pub struct StatusItem(Rc>); - -struct StatusItemState { - native_item: StrongPtr, - native_view: StrongPtr, - renderer: Renderer, - scene: Option, - event_callback: Option bool>>, - appearance_changed_callback: Option>, +pub struct StatusItem { + id: u64, } impl StatusItem { - pub fn add(fonts: Arc) -> Self { - unsafe { - let renderer = Renderer::new(false, fonts); - let status_bar = NSStatusBar::systemStatusBar(nil); - let native_item = - StrongPtr::retain(status_bar.statusItemWithLength_(NSSquareStatusItemLength)); - - let button = native_item.button(); - let _: () = msg_send![button, setHidden: YES]; - - let native_view = msg_send![VIEW_CLASS, alloc]; - let state = Rc::new(RefCell::new(StatusItemState { - native_item, - native_view: StrongPtr::new(native_view), - renderer, - scene: None, - event_callback: None, - appearance_changed_callback: None, - })); - - let parent_view = button.superview().superview(); - NSView::initWithFrame_( - native_view, - NSRect::new(NSPoint::new(0., 0.), NSView::frame(parent_view).size), - ); - (*native_view).set_ivar( - STATE_IVAR, - Weak::into_raw(Rc::downgrade(&state)) as *const c_void, - ); - native_view.setWantsBestResolutionOpenGLSurface_(YES); - native_view.setWantsLayer(YES); - let _: () = msg_send![ - native_view, - setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize - ]; - - parent_view.addSubview_(native_view); - - { - let state = state.borrow(); - let layer = state.renderer.layer(); - let scale_factor = state.scale_factor(); - let size = state.content_size() * scale_factor; - layer.set_contents_scale(scale_factor.into()); - layer.set_drawable_size(metal::CGSize::new(size.x().into(), size.y().into())); - } - - Self(state) + pub fn add(_fonts: Arc) -> Self { + let id = unsafe { zed_status_item_create() }; + // Give it a default title for now; callers can change it + if let Ok(c) = std::ffi::CString::new("Zed") { + unsafe { zed_status_item_set_title(id, c.as_ptr()) }; } - } -} - -impl platform::Window for StatusItem { - fn bounds(&self) -> WindowBounds { - self.0.borrow().bounds() - } - - fn content_size(&self) -> Vector2F { - self.0.borrow().content_size() + Self { id } } - fn scale_factor(&self) -> f32 { - self.0.borrow().scale_factor() - } - - fn appearance(&self) -> platform::Appearance { - unsafe { - let appearance: id = - msg_send![self.0.borrow().native_item.button(), effectiveAppearance]; - platform::Appearance::from_native(appearance) - } - } - - fn screen(&self) -> Rc { - unsafe { - Rc::new(Screen { - native_screen: self.0.borrow().native_window().screen(), - }) + pub fn set_title(&self, title: &str) { + if let Ok(c) = std::ffi::CString::new(title) { + unsafe { zed_status_item_set_title(self.id, c.as_ptr()) }; } } - fn mouse_position(&self) -> Vector2F { - unimplemented!() - } - - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { - self - } - - fn set_input_handler(&mut self, _: Box) {} - - fn prompt( - &self, - _: crate::platform::PromptLevel, - _: &str, - _: &[&str], - ) -> postage::oneshot::Receiver { - unimplemented!() - } - - fn activate(&self) { - unimplemented!() - } - - fn set_title(&mut self, _: &str) { - unimplemented!() - } - - fn set_edited(&mut self, _: bool) { - unimplemented!() - } - - fn show_character_palette(&self) { - unimplemented!() - } - - fn minimize(&self) { - unimplemented!() - } - - fn zoom(&self) { - unimplemented!() - } - - fn present_scene(&mut self, scene: Scene) { - self.0.borrow_mut().scene = Some(scene); - unsafe { - let _: () = msg_send![*self.0.borrow().native_view, setNeedsDisplay: YES]; + pub fn set_click_handler(&self, handler: Box) { + register_status_item_handler(self.id, handler); + } + + pub fn set_image(&self, format: crate::ImageFormat, bytes: &[u8], template: bool) { + let uti = match format { + crate::ImageFormat::Png => "public.png", + crate::ImageFormat::Jpeg => "public.jpeg", + crate::ImageFormat::Tiff => "public.tiff", + crate::ImageFormat::Webp => "org.webmproject.webp", + crate::ImageFormat::Gif => "com.compuserve.gif", + crate::ImageFormat::Bmp => "com.microsoft.bmp", + crate::ImageFormat::Svg => "public.svg-image", + }; + if let Ok(cuti) = std::ffi::CString::new(uti) { + unsafe { + zed_status_item_set_image( + self.id, + bytes.as_ptr(), + bytes.len(), + cuti.as_ptr(), + template, + ) + }; } } +} - fn toggle_fullscreen(&self) { - unimplemented!() - } - - fn on_event(&mut self, callback: Box bool>) { - self.0.borrow_mut().event_callback = Some(callback); +impl Drop for StatusItem { + fn drop(&mut self) { + unregister_status_item_handler(self.id); + unsafe { zed_status_item_remove(self.id) }; } +} - fn on_active_status_change(&mut self, _: Box) {} - - fn on_resize(&mut self, _: Box) {} - - fn on_fullscreen(&mut self, _: Box) {} - - fn on_moved(&mut self, _: Box) {} - - fn on_should_close(&mut self, _: Box bool>) {} - - fn on_close(&mut self, _: Box) {} +// Click handler registry +use std::collections::HashMap; +use std::sync::{Mutex, OnceLock}; - fn on_appearance_changed(&mut self, callback: Box) { - self.0.borrow_mut().appearance_changed_callback = Some(callback); - } +static STATUS_ITEM_HANDLERS: OnceLock>>> = OnceLock::new(); - fn is_topmost_for_position(&self, _: Vector2F) -> bool { - true - } +fn register_status_item_handler(id: u64, handler: Box) { + STATUS_ITEM_HANDLERS + .get_or_init(|| Mutex::new(HashMap::new())) + .lock() + .unwrap() + .insert(id, handler); } -impl StatusItemState { - fn bounds(&self) -> WindowBounds { - unsafe { - let window: id = self.native_window(); - let screen_frame = window.screen().visibleFrame(); - let window_frame = NSWindow::frame(window); - let origin = vec2f( - window_frame.origin.x as f32, - (window_frame.origin.y - screen_frame.size.height - window_frame.size.height) - as f32, - ); - let size = vec2f( - window_frame.size.width as f32, - window_frame.size.height as f32, - ); - WindowBounds::Fixed(RectF::new(origin, size)) - } - } - - fn content_size(&self) -> Vector2F { - unsafe { - let NSSize { width, height, .. } = - NSView::frame(self.native_item.button().superview().superview()).size; - vec2f(width as f32, height as f32) - } - } - - fn scale_factor(&self) -> f32 { - unsafe { - let window: id = msg_send![self.native_item.button(), window]; - NSScreen::backingScaleFactor(window.screen()) as f32 - } - } +fn unregister_status_item_handler(id: u64) { + STATUS_ITEM_HANDLERS + .get_or_init(|| Mutex::new(HashMap::new())) + .lock() + .unwrap() + .remove(&id); +} - pub fn native_window(&self) -> id { - unsafe { msg_send![self.native_item.button(), window] } +#[no_mangle] +pub extern "C" fn gpui_status_item_clicked(id: u64) { + if let Some(mut handler) = STATUS_ITEM_HANDLERS + .get_or_init(|| Mutex::new(HashMap::new())) + .lock() + .unwrap() + .get_mut(&id) + { + handler(); } } -extern "C" fn dealloc_view(this: &Object, _: Sel) { - unsafe { - drop_state(this); +// Status item menu support +use crate::menu::{Menu as AppMenu, MenuItem as AppMenuItem}; - let _: () = msg_send![super(this, class!(NSView)), dealloc]; - } -} +static STATUS_ITEM_MENU_ACTIONS: OnceLock>>>> = OnceLock::new(); -extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { - unsafe { - if let Some(state) = get_state(this).upgrade() { - let mut state_borrow = state.as_ref().borrow_mut(); - if let Some(event) = - Event::from_native(native_event, Some(state_borrow.content_size().y())) - { - if let Some(mut callback) = state_borrow.event_callback.take() { - drop(state_borrow); - callback(event); - state.borrow_mut().event_callback = Some(callback); +impl StatusItem { + pub fn set_menu(&self, menu: &AppMenu) { + // Build JSON and tag -> action map per status item id + #[derive(serde::Serialize)] + #[serde(tag = "kind", rename_all = "lowercase")] + enum JsItem<'a> { Action { title: &'a str, tag: u64 }, Separator, Submenu { title: &'a str, items: Vec> } } + #[derive(serde::Serialize)] + struct JsSpec<'a> { items: Vec> } + + let mut actions = Vec::>::new(); + fn encode_items<'a>(src: &'a [AppMenuItem], actions: &mut Vec>, out: &mut Vec>) { + for item in src { + match item { + AppMenuItem::Separator => out.push(JsItem::Separator), + AppMenuItem::Action { name, action, .. } => { + let tag = actions.len() as u64; + actions.push(action.boxed_clone()); + out.push(JsItem::Action { title: name, tag }); + } + AppMenuItem::Submenu(AppMenu { name, items }) => { + let mut sub = Vec::new(); + encode_items(items, actions, &mut sub); + out.push(JsItem::Submenu { title: name, items: sub }); + } + AppMenuItem::SystemMenu(_) => { + // Not supported in status item menu context currently + } } } } - } -} -extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { - if let Some(state) = unsafe { get_state(this).upgrade() } { - let state = state.borrow(); - state.renderer.layer().as_ptr() as id - } else { - nil - } -} - -extern "C" fn display_layer(this: &Object, _: Sel, _: id) { - unsafe { - if let Some(state) = get_state(this).upgrade() { - let mut state = state.borrow_mut(); - if let Some(scene) = state.scene.take() { - state.renderer.render(&scene); - } + let mut js_items = Vec::new(); + encode_items(&menu.items, &mut actions, &mut js_items); + let spec = JsSpec { items: js_items }; + let json = serde_json::to_string(&spec).unwrap_or_else(|_| "{\"items\":[]}".into()); + STATUS_ITEM_MENU_ACTIONS + .get_or_init(|| Mutex::new(HashMap::new())) + .lock() + .unwrap() + .insert(self.id, actions); + if let Ok(cjson) = std::ffi::CString::new(json) { + unsafe { zed_status_item_set_menu(self.id, cjson.as_ptr()) }; } } } -extern "C" fn view_did_change_effective_appearance(this: &Object, _: Sel) { - unsafe { - if let Some(state) = get_state(this).upgrade() { - let mut state_borrow = state.as_ref().borrow_mut(); - if let Some(mut callback) = state_borrow.appearance_changed_callback.take() { - drop(state_borrow); - callback(); - state.borrow_mut().appearance_changed_callback = Some(callback); - } +#[no_mangle] +pub extern "C" fn gpui_status_item_menu_action(id: u64, tag: u64) { + if let Some(vec) = STATUS_ITEM_MENU_ACTIONS + .get_or_init(|| Mutex::new(HashMap::new())) + .lock() + .unwrap() + .get_mut(&id) + { + if let Some(action) = vec.get(tag as usize) { + super::platform::dispatch_menu_action(action.as_ref()); } } } - -unsafe fn get_state(object: &Object) -> Weak> { - let raw: *mut c_void = *object.get_ivar(STATE_IVAR); - let weak1 = Weak::from_raw(raw as *mut RefCell); - let weak2 = weak1.clone(); - let _ = Weak::into_raw(weak1); - weak2 -} - -unsafe fn drop_state(object: &Object) { - let raw: *const c_void = *object.get_ivar(STATE_IVAR); - Weak::from_raw(raw as *const RefCell); -} diff --git a/crates/gpui/src/platform/mac/text_system.rs b/crates/gpui/src/platform/mac/text_system.rs index 72a0f2e565d993..e0487406f4589a 100644 --- a/crates/gpui/src/platform/mac/text_system.rs +++ b/crates/gpui/src/platform/mac/text_system.rs @@ -660,11 +660,10 @@ mod lenient_font_attributes { } unsafe fn wrap_under_get_rule(reference: CFStringRef) -> CFString { - unsafe { - assert!(!reference.is_null(), "Attempted to create a NULL object."); - let reference = CFRetain(reference as *const ::std::os::raw::c_void) as CFStringRef; - TCFType::wrap_under_create_rule(reference) - } + assert!(!reference.is_null(), "Attempted to create a NULL object."); + let reference = + unsafe { CFRetain(reference as *const ::std::os::raw::c_void) as CFStringRef }; + unsafe { TCFType::wrap_under_create_rule(reference) } } } diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 1230a704062ba8..da28ede04d8ade 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -9,26 +9,74 @@ use crate::{ dispatch_sys::dispatch_async_f, platform::PlatformInputHandler, point, px, size, }; use block::ConcreteBlock; -use cocoa::{ - appkit::{ - NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered, - NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, - NSView, NSViewHeightSizable, NSViewWidthSizable, NSVisualEffectMaterial, - NSVisualEffectState, NSVisualEffectView, NSWindow, NSWindowButton, - NSWindowCollectionBehavior, NSWindowOcclusionState, NSWindowOrderingMode, - NSWindowStyleMask, NSWindowTitleVisibility, - }, - base::{id, nil}, - foundation::{ - NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, - NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, - NSUserDefaults, - }, -}; +// Remove Cocoa trait usage; rely on Objective-C runtime + typed constants later +// No Cocoa enums/flags needed here after migration +use cocoa::foundation::{ + NSAutoreleasePool, NSNotFound, NSPoint, NSRect, NSSize, NSString, NSUserDefaults, +}; use core_graphics::display::{CGDirectDisplayID, CGPoint, CGRect}; use ctor::ctor; use futures::channel::oneshot; +use icrate::AppKit::{ + // Alert styles + NSAlertStyleCritical, + NSAlertStyleInformational, + NSAlertStyleWarning, + NSAppKitVersionNumber, + NSAppKitVersionNumber12_0, + NSBackingStoreBuffered, + // Drag operation flags + NSDragOperation, + NSDragOperationCopy, + NSDragOperationNone, + // Event modifier flags + NSEventModifierFlagCapsLock, + NSEventModifierFlagCommand, + NSEventModifierFlagControl, + NSEventModifierFlagFunction, + NSEventModifierFlagOption, + NSEventModifierFlagShift, + // Pasteboard types + NSFilenamesPboardType, + NSTrackingActiveAlways, + NSTrackingInVisibleRect, + // Tracking area flags + NSTrackingMouseEnteredAndExited, + NSTrackingMouseMoved, + NSViewHeightSizable, + // View layer redraw policy + NSViewLayerContentsRedrawDuringViewResize, + // Autoresizing mask options + NSViewWidthSizable, + // Visual effect + NSVisualEffectStateActive, + // Ordering + NSWindowAbove, + // Animation behavior + NSWindowAnimationBehaviorUtilityWindow, + NSWindowBelow, + // Window button enum values + NSWindowCloseButton, + // Collection behavior + NSWindowCollectionBehaviorCanJoinAllSpaces, + NSWindowCollectionBehaviorFullScreenAuxiliary, + NSWindowMiniaturizeButton, + // Style masks + NSWindowStyleMask, + NSWindowStyleMaskClosable, + NSWindowStyleMaskFullScreen, + NSWindowStyleMaskFullSizeContentView, + NSWindowStyleMaskMiniaturizable, + NSWindowStyleMaskNonactivatingPanel, + NSWindowStyleMaskResizable, + NSWindowStyleMaskTitled, + // Title visibility + NSWindowTitleHidden, + NSWindowZoomButton, +}; +use icrate::Foundation::NSOperatingSystemVersion; +use icrate::Foundation::{NSInteger, NSUInteger}; use objc::{ class, declare::ClassDecl, @@ -36,6 +84,8 @@ use objc::{ runtime::{BOOL, Class, NO, Object, Protocol, Sel, YES}, sel, sel_impl, }; +type ObjcId = *mut Object; +const NIL: ObjcId = std::ptr::null_mut(); use parking_lot::Mutex; use raw_window_handle as rwh; use smallvec::SmallVec; @@ -59,31 +109,18 @@ static mut PANEL_CLASS: *const Class = ptr::null(); static mut VIEW_CLASS: *const Class = ptr::null(); static mut BLURRED_VIEW_CLASS: *const Class = ptr::null(); +use icrate::AppKit::NSWindowLevel; #[allow(non_upper_case_globals)] -const NSWindowStyleMaskNonactivatingPanel: NSWindowStyleMask = - NSWindowStyleMask::from_bits_retain(1 << 7); -#[allow(non_upper_case_globals)] -const NSNormalWindowLevel: NSInteger = 0; -#[allow(non_upper_case_globals)] -const NSPopUpWindowLevel: NSInteger = 101; -#[allow(non_upper_case_globals)] -const NSTrackingMouseEnteredAndExited: NSUInteger = 0x01; -#[allow(non_upper_case_globals)] -const NSTrackingMouseMoved: NSUInteger = 0x02; -#[allow(non_upper_case_globals)] -const NSTrackingActiveAlways: NSUInteger = 0x80; +const WINDOW_LEVEL_NORMAL: NSWindowLevel = 0; #[allow(non_upper_case_globals)] -const NSTrackingInVisibleRect: NSUInteger = 0x200; -#[allow(non_upper_case_globals)] -const NSWindowAnimationBehaviorUtilityWindow: NSInteger = 4; -#[allow(non_upper_case_globals)] -const NSViewLayerContentsRedrawDuringViewResize: NSInteger = 2; -// https://developer.apple.com/documentation/appkit/nsdragoperation -type NSDragOperation = NSUInteger; -#[allow(non_upper_case_globals)] -const NSDragOperationNone: NSDragOperation = 0; -#[allow(non_upper_case_globals)] -const NSDragOperationCopy: NSDragOperation = 1; +const WINDOW_LEVEL_POPUP: NSWindowLevel = 101; +// Event modifier masks +const MOD_CAPS_LOCK: u64 = NSEventModifierFlagCapsLock as u64; +const MOD_SHIFT: u64 = NSEventModifierFlagShift as u64; +const MOD_CONTROL: u64 = NSEventModifierFlagControl as u64; +const MOD_OPTION: u64 = NSEventModifierFlagOption as u64; +const MOD_COMMAND: u64 = NSEventModifierFlagCommand as u64; +const MOD_FUNCTION: u64 = NSEventModifierFlagFunction as u64; #[derive(PartialEq)] pub enum UserTabbingPreference { Never, @@ -94,9 +131,9 @@ pub enum UserTabbingPreference { #[link(name = "CoreGraphics", kind = "framework")] unsafe extern "C" { // Widely used private APIs; Apple uses them for their Terminal.app. - fn CGSMainConnectionID() -> id; + fn CGSMainConnectionID() -> ObjcId; fn CGSSetWindowBackgroundBlurRadius( - connection_id: id, + connection_id: ObjcId, window_id: NSInteger, radius: i64, ) -> i32; @@ -115,68 +152,68 @@ unsafe fn build_classes() { decl.add_method( sel!(performKeyEquivalent:), - handle_key_equivalent as extern "C" fn(&Object, Sel, id) -> BOOL, + handle_key_equivalent as extern "C" fn(&Object, Sel, ObjcId) -> BOOL, ); decl.add_method( sel!(keyDown:), - handle_key_down as extern "C" fn(&Object, Sel, id), + handle_key_down as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(keyUp:), - handle_key_up as extern "C" fn(&Object, Sel, id), + handle_key_up as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(mouseDown:), - handle_view_event as extern "C" fn(&Object, Sel, id), + handle_view_event as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(mouseUp:), - handle_view_event as extern "C" fn(&Object, Sel, id), + handle_view_event as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(rightMouseDown:), - handle_view_event as extern "C" fn(&Object, Sel, id), + handle_view_event as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(rightMouseUp:), - handle_view_event as extern "C" fn(&Object, Sel, id), + handle_view_event as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(otherMouseDown:), - handle_view_event as extern "C" fn(&Object, Sel, id), + handle_view_event as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(otherMouseUp:), - handle_view_event as extern "C" fn(&Object, Sel, id), + handle_view_event as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(mouseMoved:), - handle_view_event as extern "C" fn(&Object, Sel, id), + handle_view_event as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(mouseExited:), - handle_view_event as extern "C" fn(&Object, Sel, id), + handle_view_event as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(mouseDragged:), - handle_view_event as extern "C" fn(&Object, Sel, id), + handle_view_event as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(scrollWheel:), - handle_view_event as extern "C" fn(&Object, Sel, id), + handle_view_event as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(swipeWithEvent:), - handle_view_event as extern "C" fn(&Object, Sel, id), + handle_view_event as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(flagsChanged:), - handle_view_event as extern "C" fn(&Object, Sel, id), + handle_view_event as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(makeBackingLayer), - make_backing_layer as extern "C" fn(&Object, Sel) -> id, + make_backing_layer as extern "C" fn(&Object, Sel) -> ObjcId, ); decl.add_protocol(Protocol::get("CALayerDelegate").unwrap()); @@ -190,13 +227,13 @@ unsafe fn build_classes() { ); decl.add_method( sel!(displayLayer:), - display_layer as extern "C" fn(&Object, Sel, id), + display_layer as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_protocol(Protocol::get("NSTextInputClient").unwrap()); decl.add_method( sel!(validAttributesForMarkedText), - valid_attributes_for_marked_text as extern "C" fn(&Object, Sel) -> id, + valid_attributes_for_marked_text as extern "C" fn(&Object, Sel) -> ObjcId, ); decl.add_method( sel!(hasMarkedText), @@ -213,21 +250,21 @@ unsafe fn build_classes() { decl.add_method( sel!(firstRectForCharacterRange:actualRange:), first_rect_for_character_range - as extern "C" fn(&Object, Sel, NSRange, id) -> NSRect, + as extern "C" fn(&Object, Sel, NSRange, ObjcId) -> NSRect, ); decl.add_method( sel!(insertText:replacementRange:), - insert_text as extern "C" fn(&Object, Sel, id, NSRange), + insert_text as extern "C" fn(&Object, Sel, ObjcId, NSRange), ); decl.add_method( sel!(setMarkedText:selectedRange:replacementRange:), - set_marked_text as extern "C" fn(&Object, Sel, id, NSRange, NSRange), + set_marked_text as extern "C" fn(&Object, Sel, ObjcId, NSRange, NSRange), ); decl.add_method(sel!(unmarkText), unmark_text as extern "C" fn(&Object, Sel)); decl.add_method( sel!(attributedSubstringForProposedRange:actualRange:), attributed_substring_for_proposed_range - as extern "C" fn(&Object, Sel, NSRange, *mut c_void) -> id, + as extern "C" fn(&Object, Sel, NSRange, *mut c_void) -> ObjcId, ); decl.add_method( sel!(viewDidChangeEffectiveAppearance), @@ -242,7 +279,7 @@ unsafe fn build_classes() { decl.add_method( sel!(acceptsFirstMouse:), - accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL, + accepts_first_mouse as extern "C" fn(&Object, Sel, ObjcId) -> BOOL, ); decl.add_method( @@ -257,7 +294,7 @@ unsafe fn build_classes() { unsafe { decl.add_method( sel!(initWithFrame:), - blurred_view_init_with_frame as extern "C" fn(&Object, Sel, NSRect) -> id, + blurred_view_init_with_frame as extern "C" fn(&Object, Sel, NSRect) -> ObjcId, ); decl.add_method( sel!(updateLayer), @@ -293,92 +330,92 @@ unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const C ); decl.add_method( sel!(windowDidResize:), - window_did_resize as extern "C" fn(&Object, Sel, id), + window_did_resize as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(windowDidChangeOcclusionState:), - window_did_change_occlusion_state as extern "C" fn(&Object, Sel, id), + window_did_change_occlusion_state as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(windowWillEnterFullScreen:), - window_will_enter_fullscreen as extern "C" fn(&Object, Sel, id), + window_will_enter_fullscreen as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(windowWillExitFullScreen:), - window_will_exit_fullscreen as extern "C" fn(&Object, Sel, id), + window_will_exit_fullscreen as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(windowDidMove:), - window_did_move as extern "C" fn(&Object, Sel, id), + window_did_move as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(windowDidChangeScreen:), - window_did_change_screen as extern "C" fn(&Object, Sel, id), + window_did_change_screen as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(windowDidBecomeKey:), - window_did_change_key_status as extern "C" fn(&Object, Sel, id), + window_did_change_key_status as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(windowDidResignKey:), - window_did_change_key_status as extern "C" fn(&Object, Sel, id), + window_did_change_key_status as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(windowShouldClose:), - window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL, + window_should_close as extern "C" fn(&Object, Sel, ObjcId) -> BOOL, ); decl.add_method(sel!(close), close_window as extern "C" fn(&Object, Sel)); decl.add_method( sel!(draggingEntered:), - dragging_entered as extern "C" fn(&Object, Sel, id) -> NSDragOperation, + dragging_entered as extern "C" fn(&Object, Sel, ObjcId) -> NSDragOperation, ); decl.add_method( sel!(draggingUpdated:), - dragging_updated as extern "C" fn(&Object, Sel, id) -> NSDragOperation, + dragging_updated as extern "C" fn(&Object, Sel, ObjcId) -> NSDragOperation, ); decl.add_method( sel!(draggingExited:), - dragging_exited as extern "C" fn(&Object, Sel, id), + dragging_exited as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(performDragOperation:), - perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL, + perform_drag_operation as extern "C" fn(&Object, Sel, ObjcId) -> BOOL, ); decl.add_method( sel!(concludeDragOperation:), - conclude_drag_operation as extern "C" fn(&Object, Sel, id), + conclude_drag_operation as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(addTitlebarAccessoryViewController:), - add_titlebar_accessory_view_controller as extern "C" fn(&Object, Sel, id), + add_titlebar_accessory_view_controller as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(moveTabToNewWindow:), - move_tab_to_new_window as extern "C" fn(&Object, Sel, id), + move_tab_to_new_window as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(mergeAllWindows:), - merge_all_windows as extern "C" fn(&Object, Sel, id), + merge_all_windows as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(selectNextTab:), - select_next_tab as extern "C" fn(&Object, Sel, id), + select_next_tab as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(selectPreviousTab:), - select_previous_tab as extern "C" fn(&Object, Sel, id), + select_previous_tab as extern "C" fn(&Object, Sel, ObjcId), ); decl.add_method( sel!(toggleTabBar:), - toggle_tab_bar as extern "C" fn(&Object, Sel, id), + toggle_tab_bar as extern "C" fn(&Object, Sel, ObjcId), ); decl.register() @@ -388,9 +425,9 @@ unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const C struct MacWindowState { handle: AnyWindowHandle, executor: ForegroundExecutor, - native_window: id, + native_window: ObjcId, native_view: NonNull, - blurred_view: Option, + blurred_view: Option, display_link: Option, renderer: renderer::Renderer, request_frame_callback: Option>, @@ -432,17 +469,17 @@ impl MacWindowState { let titlebar_height = self.titlebar_height(); unsafe { - let close_button: id = msg_send![ + let close_button: ObjcId = msg_send![ self.native_window, - standardWindowButton: NSWindowButton::NSWindowCloseButton + standardWindowButton: NSWindowCloseButton ]; - let min_button: id = msg_send![ + let min_button: ObjcId = msg_send![ self.native_window, - standardWindowButton: NSWindowButton::NSWindowMiniaturizeButton + standardWindowButton: NSWindowMiniaturizeButton ]; - let zoom_button: id = msg_send![ + let zoom_button: ObjcId = msg_send![ self.native_window, - standardWindowButton: NSWindowButton::NSWindowZoomButton + standardWindowButton: NSWindowZoomButton ]; let mut close_button_frame: CGRect = msg_send![close_button, frame]; @@ -475,15 +512,15 @@ impl MacWindowState { fn start_display_link(&mut self) { self.stop_display_link(); unsafe { - if !self - .native_window - .occlusionState() - .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) - { + let is_visible: BOOL = msg_send![self.native_window, isVisible]; + if is_visible != YES { return; } } - let display_id = unsafe { display_id_for_screen(self.native_window.screen()) }; + let display_id = unsafe { + let screen: ObjcId = msg_send![self.native_window, screen]; + display_id_for_screen(screen) + }; if let Some(mut display_link) = DisplayLink::new(display_id, self.native_view.as_ptr() as *mut c_void, step).log_err() { @@ -499,23 +536,25 @@ impl MacWindowState { fn is_maximized(&self) -> bool { unsafe { let bounds = self.bounds(); - let screen_size = self.native_window.screen().visibleFrame().into(); + let screen: ObjcId = msg_send![self.native_window, screen]; + let vis: NSRect = msg_send![screen, visibleFrame]; + let screen_size: Size = vis.into(); bounds.size == screen_size } } fn is_fullscreen(&self) -> bool { unsafe { - let style_mask = self.native_window.styleMask(); - style_mask.contains(NSWindowStyleMask::NSFullScreenWindowMask) + let style_mask: NSWindowStyleMask = msg_send![self.native_window, styleMask]; + (style_mask & NSWindowStyleMaskFullScreen) != 0 } } fn bounds(&self) -> Bounds { - let mut window_frame = unsafe { NSWindow::frame(self.native_window) }; - let screen_frame = unsafe { - let screen = NSWindow::screen(self.native_window); - NSScreen::frame(screen) + let mut window_frame: NSRect = unsafe { msg_send![self.native_window, frame] }; + let screen_frame: NSRect = unsafe { + let screen: ObjcId = msg_send![self.native_window, screen]; + msg_send![screen, frame] }; // Flip the y coordinate to be top-left origin @@ -535,9 +574,11 @@ impl MacWindowState { } fn content_size(&self) -> Size { - let NSSize { width, height, .. } = - unsafe { NSView::frame(self.native_window.contentView()) }.size; - size(px(width as f32), px(height as f32)) + unsafe { + let content_view: ObjcId = msg_send![self.native_window, contentView]; + let frame: NSRect = msg_send![content_view, frame]; + size(px(frame.size.width as f32), px(frame.size.height as f32)) + } } fn scale_factor(&self) -> f32 { @@ -546,7 +587,7 @@ impl MacWindowState { fn titlebar_height(&self) -> Pixels { unsafe { - let frame = NSWindow::frame(self.native_window); + let frame: NSRect = msg_send![self.native_window, frame]; let content_layout_rect: CGRect = msg_send![self.native_window, contentLayoutRect]; px((frame.size.height - content_layout_rect.size.height) as f32) } @@ -585,7 +626,8 @@ impl MacWindow { renderer_context: renderer::Context, ) -> Self { unsafe { - let pool = NSAutoreleasePool::new(nil); + // Use an autorelease pool via raw Objective-C messaging + let pool: ObjcId = msg_send![class!(NSAutoreleasePool), new]; let allows_automatic_window_tabbing = tabbing_identifier.is_some(); if allows_automatic_window_tabbing { @@ -596,26 +638,24 @@ impl MacWindow { let mut style_mask; if let Some(titlebar) = titlebar.as_ref() { - style_mask = - NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask; + style_mask = NSWindowStyleMaskClosable | NSWindowStyleMaskTitled; if is_resizable { - style_mask |= NSWindowStyleMask::NSResizableWindowMask; + style_mask |= NSWindowStyleMaskResizable; } if is_minimizable { - style_mask |= NSWindowStyleMask::NSMiniaturizableWindowMask; + style_mask |= NSWindowStyleMaskMiniaturizable; } if titlebar.appears_transparent { - style_mask |= NSWindowStyleMask::NSFullSizeContentViewWindowMask; + style_mask |= NSWindowStyleMaskFullSizeContentView; } } else { - style_mask = NSWindowStyleMask::NSTitledWindowMask - | NSWindowStyleMask::NSFullSizeContentViewWindowMask; + style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView; } - let native_window: id = match kind { + let native_window: ObjcId = match kind { WindowKind::Normal => msg_send![WINDOW_CLASS, alloc], WindowKind::PopUp => { style_mask |= NSWindowStyleMaskNonactivatingPanel; @@ -627,14 +667,14 @@ impl MacWindow { .and_then(MacDisplay::find_by_id) .unwrap_or_else(MacDisplay::primary); - let mut target_screen = nil; + let mut target_screen = NIL; let mut screen_frame = None; - let screens = NSScreen::screens(nil); - let count: u64 = cocoa::foundation::NSArray::count(screens); + let screens: ObjcId = msg_send![class!(NSScreen), screens]; + let count: u64 = msg_send![screens, count]; for i in 0..count { - let screen = cocoa::foundation::NSArray::objectAtIndex(screens, i); - let frame = NSScreen::frame(screen); + let screen: ObjcId = msg_send![screens, objectAtIndex: i]; + let frame: NSRect = msg_send![screen, frame]; let display_id = display_id_for_screen(screen); if display_id == display.0 { screen_frame = Some(frame); @@ -643,41 +683,43 @@ impl MacWindow { } let screen_frame = screen_frame.unwrap_or_else(|| { - let screen = NSScreen::mainScreen(nil); + let screen: ObjcId = msg_send![class!(NSScreen), mainScreen]; target_screen = screen; - NSScreen::frame(screen) + let frame: NSRect = msg_send![screen, frame]; + frame }); - let window_rect = NSRect::new( - NSPoint::new( - screen_frame.origin.x + bounds.origin.x.0 as f64, - screen_frame.origin.y + let window_rect = NSRect { + origin: NSPoint { + x: screen_frame.origin.x + bounds.origin.x.0 as f64, + y: screen_frame.origin.y + (display.bounds().size.height - bounds.origin.y).0 as f64, - ), - NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), - ); + }, + size: NSSize { + width: bounds.size.width.0 as f64, + height: bounds.size.height.0 as f64, + }, + }; - let native_window = native_window.initWithContentRect_styleMask_backing_defer_screen_( - window_rect, - style_mask, - NSBackingStoreBuffered, - NO, - target_screen, - ); - assert!(!native_window.is_null()); - let () = msg_send![ - native_window, - registerForDraggedTypes: - NSArray::arrayWithObject(nil, NSFilenamesPboardType) + let native_window: ObjcId = msg_send![native_window, + initWithContentRect: window_rect + styleMask: style_mask + backing: NSBackingStoreBuffered + defer: NO + screen: target_screen ]; + assert!(!native_window.is_null()); + let types: ObjcId = msg_send![class!(NSArray), arrayWithObject: NSFilenamesPboardType]; + let () = msg_send![native_window, registerForDraggedTypes: types]; let () = msg_send![ native_window, setReleasedWhenClosed: NO ]; - let content_view = native_window.contentView(); - let native_view: id = msg_send![VIEW_CLASS, alloc]; - let native_view = NSView::initWithFrame_(native_view, NSView::bounds(content_view)); + let content_view: ObjcId = msg_send![native_window, contentView]; + let native_view: ObjcId = msg_send![VIEW_CLASS, alloc]; + let view_bounds: NSRect = msg_send![content_view, bounds]; + let native_view: ObjcId = msg_send![native_view, initWithFrame: view_bounds]; assert!(!native_view.is_null()); let mut window = Self(Arc::new(Mutex::new(MacWindowState { @@ -728,7 +770,7 @@ impl MacWindow { WINDOW_STATE_IVAR, Arc::into_raw(window.0.clone()) as *const c_void, ); - native_window.setDelegate_(native_window); + let _: () = msg_send![native_window, setDelegate: native_window]; (*native_view).set_ivar( WINDOW_STATE_IVAR, Arc::into_raw(window.0.clone()) as *const c_void, @@ -741,85 +783,91 @@ impl MacWindow { window.set_title(title); } - native_window.setMovable_(is_movable as BOOL); + let _: () = msg_send![native_window, setMovable: (is_movable as BOOL)]; if let Some(window_min_size) = window_min_size { - native_window.setContentMinSize_(NSSize { + let min_size = NSSize { width: window_min_size.width.to_f64(), height: window_min_size.height.to_f64(), - }); + }; + let _: () = msg_send![native_window, setContentMinSize: min_size]; } if titlebar.is_none_or(|titlebar| titlebar.appears_transparent) { - native_window.setTitlebarAppearsTransparent_(YES); - native_window.setTitleVisibility_(NSWindowTitleVisibility::NSWindowTitleHidden); + let _: () = msg_send![native_window, setTitlebarAppearsTransparent: YES]; + let _: () = msg_send![native_window, setTitleVisibility: NSWindowTitleHidden]; } - native_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); - native_view.setWantsBestResolutionOpenGLSurface_(YES); + let _: () = msg_send![native_view, setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; + let _: () = msg_send![native_view, setWantsBestResolutionOpenGLSurface: YES]; // From winit crate: On Mojave, views automatically become layer-backed shortly after // being added to a native_window. Changing the layer-backedness of a view breaks the // association between the view and its associated OpenGL context. To work around this, // on we explicitly make the view layer-backed up front so that AppKit doesn't do it // itself and break the association with its context. - native_view.setWantsLayer(YES); + let _: () = msg_send![native_view, setWantsLayer: YES]; let _: () = msg_send![ native_view, setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize ]; - content_view.addSubview_(native_view.autorelease()); - native_window.makeFirstResponder_(native_view); + let native_view: ObjcId = msg_send![native_view, autorelease]; + let _: () = msg_send![content_view, addSubview: native_view]; + let _: () = msg_send![native_window, makeFirstResponder: native_view]; match kind { WindowKind::Normal => { - native_window.setLevel_(NSNormalWindowLevel); - native_window.setAcceptsMouseMovedEvents_(YES); + let _: () = msg_send![native_window, setLevel: WINDOW_LEVEL_NORMAL]; + let _: () = msg_send![native_window, setAcceptsMouseMovedEvents: YES]; if let Some(tabbing_identifier) = tabbing_identifier { - let tabbing_id = NSString::alloc(nil).init_str(tabbing_identifier.as_str()); + let tabbing_id = NSString::alloc(NIL).init_str(tabbing_identifier.as_str()); let _: () = msg_send![native_window, setTabbingIdentifier: tabbing_id]; } else { - let _: () = msg_send![native_window, setTabbingIdentifier:nil]; + let _: () = msg_send![native_window, setTabbingIdentifier:NIL]; } } WindowKind::PopUp => { // Use a tracking area to allow receiving MouseMoved events even when // the window or application aren't active, which is often the case // e.g. for notification windows. - let tracking_area: id = msg_send![class!(NSTrackingArea), alloc]; - let _: () = msg_send![ - tracking_area, - initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) - options: NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect - owner: native_view - userInfo: nil + let tracking_area: ObjcId = msg_send![class!(NSTrackingArea), alloc]; + let zero_rect = NSRect { + origin: NSPoint { x: 0.0, y: 0.0 }, + size: NSSize { + width: 0.0, + height: 0.0, + }, + }; + let _: () = msg_send![tracking_area, + initWithRect: zero_rect + options: NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect + owner: native_view + userInfo: NIL ]; let _: () = msg_send![native_view, addTrackingArea: tracking_area.autorelease()]; - native_window.setLevel_(NSPopUpWindowLevel); + let _: () = msg_send![native_window, setLevel: WINDOW_LEVEL_POPUP]; let _: () = msg_send![ native_window, setAnimationBehavior: NSWindowAnimationBehaviorUtilityWindow ]; - native_window.setCollectionBehavior_( - NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces | - NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenAuxiliary - ); + let behavior = NSWindowCollectionBehaviorCanJoinAllSpaces + | NSWindowCollectionBehaviorFullScreenAuxiliary; + let _: () = msg_send![native_window, setCollectionBehavior: behavior]; } } - let app = NSApplication::sharedApplication(nil); - let main_window: id = msg_send![app, mainWindow]; + let app: ObjcId = msg_send![class!(NSApplication), sharedApplication]; + let main_window: ObjcId = msg_send![app, mainWindow]; if allows_automatic_window_tabbing && !main_window.is_null() && main_window != native_window { - let main_window_is_fullscreen = main_window - .styleMask() - .contains(NSWindowStyleMask::NSFullScreenWindowMask); + let main_style: NSWindowStyleMask = msg_send![main_window, styleMask]; + let main_window_is_fullscreen = (main_style & NSWindowStyleMaskFullScreen) != 0; let user_tabbing_preference = Self::get_user_tabbing_preference() .unwrap_or(UserTabbingPreference::InFullScreen); let should_add_as_tab = user_tabbing_preference == UserTabbingPreference::Always @@ -832,31 +880,31 @@ impl MacWindow { let main_window_visible: BOOL = msg_send![main_window, isVisible]; if main_window_can_tab == YES && main_window_visible == YES { - let _: () = msg_send![main_window, addTabbedWindow: native_window ordered: NSWindowOrderingMode::NSWindowAbove]; + let _: () = msg_send![main_window, addTabbedWindow: native_window ordered: NSWindowAbove]; // Ensure the window is visible immediately after adding the tab, since the tab bar is updated with a new entry at this point. // Note: Calling orderFront here can break fullscreen mode (makes fullscreen windows exit fullscreen), so only do this if the main window is not fullscreen. if !main_window_is_fullscreen { - let _: () = msg_send![native_window, orderFront: nil]; + let _: () = msg_send![native_window, orderFront: NIL]; } } } } if focus && show { - native_window.makeKeyAndOrderFront_(nil); + let _: () = msg_send![native_window, makeKeyAndOrderFront: NIL]; } else if show { - native_window.orderFront_(nil); + let _: () = msg_send![native_window, orderFront: NIL]; } // Set the initial position of the window to the specified origin. // Although we already specified the position using `initWithContentRect_styleMask_backing_defer_screen_`, // the window position might be incorrect if the main screen (the screen that contains the window that has focus) // is different from the primary screen. - NSWindow::setFrameTopLeftPoint_(native_window, window_rect.origin); + let _: () = msg_send![native_window, setFrameTopLeftPoint: window_rect.origin]; window.0.lock().move_traffic_light(); - pool.drain(); + let _: () = msg_send![pool, drain]; window } @@ -864,8 +912,8 @@ impl MacWindow { pub fn active_window() -> Option { unsafe { - let app = NSApplication::sharedApplication(nil); - let main_window: id = msg_send![app, mainWindow]; + let app: ObjcId = msg_send![class!(NSApplication), sharedApplication]; + let main_window: ObjcId = msg_send![app, mainWindow]; if main_window.is_null() { return None; } @@ -881,13 +929,13 @@ impl MacWindow { pub fn ordered_windows() -> Vec { unsafe { - let app = NSApplication::sharedApplication(nil); - let windows: id = msg_send![app, orderedWindows]; + let app: ObjcId = msg_send![class!(NSApplication), sharedApplication]; + let windows: ObjcId = msg_send![app, orderedWindows]; let count: NSUInteger = msg_send![windows, count]; let mut window_handles = Vec::new(); for i in 0..count { - let window: id = msg_send![windows, objectAtIndex:i]; + let window: ObjcId = msg_send![windows, objectAtIndex:i]; if msg_send![window, isKindOfClass: WINDOW_CLASS] { let handle = get_window_state(&*window).lock().handle; window_handles.push(handle); @@ -900,15 +948,15 @@ impl MacWindow { pub fn get_user_tabbing_preference() -> Option { unsafe { - let defaults: id = NSUserDefaults::standardUserDefaults(); - let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); - let key = NSString::alloc(nil).init_str("AppleWindowTabbingMode"); + let defaults: ObjcId = NSUserDefaults::standardUserDefaults(); + let domain = NSString::alloc(NIL).init_str("NSGlobalDomain"); + let key = NSString::alloc(NIL).init_str("AppleWindowTabbingMode"); - let dict: id = msg_send![defaults, persistentDomainForName: domain]; - let value: id = if !dict.is_null() { + let dict: ObjcId = msg_send![defaults, persistentDomainForName: domain]; + let value: ObjcId = if !dict.is_null() { msg_send![dict, objectForKey: key] } else { - nil + NIL }; let value_str = if !value.is_null() { @@ -933,14 +981,14 @@ impl Drop for MacWindow { let window = this.native_window; this.display_link.take(); unsafe { - this.native_window.setDelegate_(nil); + let _: () = msg_send![this.native_window, setDelegate: NIL]; } this.input_handler.take(); this.executor .spawn(async move { unsafe { - window.close(); - window.autorelease(); + let _: () = msg_send![window, close]; + let _: ObjcId = msg_send![window, autorelease]; } }) .detach(); @@ -970,10 +1018,11 @@ impl PlatformWindow for MacWindow { this.executor .spawn(async move { unsafe { - window.setContentSize_(NSSize { + let new_size = NSSize { width: size.width.0 as f64, height: size.height.0 as f64, - }); + }; + let _: () = msg_send![window, setContentSize: new_size]; } }) .detach(); @@ -982,8 +1031,8 @@ impl PlatformWindow for MacWindow { fn merge_all_windows(&self) { let native_window = self.0.lock().native_window; unsafe extern "C" fn merge_windows_async(context: *mut std::ffi::c_void) { - let native_window = context as id; - let _: () = msg_send![native_window, mergeAllWindows:nil]; + let native_window = context as ObjcId; + let _: () = msg_send![native_window, mergeAllWindows:NIL]; } unsafe { @@ -998,9 +1047,9 @@ impl PlatformWindow for MacWindow { fn move_tab_to_new_window(&self) { let native_window = self.0.lock().native_window; unsafe extern "C" fn move_tab_async(context: *mut std::ffi::c_void) { - let native_window = context as id; - let _: () = msg_send![native_window, moveTabToNewWindow:nil]; - let _: () = msg_send![native_window, makeKeyAndOrderFront: nil]; + let native_window = context as ObjcId; + let _: () = msg_send![native_window, moveTabToNewWindow:NIL]; + let _: () = msg_send![native_window, makeKeyAndOrderFront: NIL]; } unsafe { @@ -1015,7 +1064,7 @@ impl PlatformWindow for MacWindow { fn toggle_window_tab_overview(&self) { let native_window = self.0.lock().native_window; unsafe { - let _: () = msg_send![native_window, toggleTabOverview:nil]; + let _: () = msg_send![native_window, toggleTabOverview:NIL]; } } @@ -1030,10 +1079,10 @@ impl PlatformWindow for MacWindow { } if let Some(tabbing_identifier) = tabbing_identifier { - let tabbing_id = NSString::alloc(nil).init_str(tabbing_identifier.as_str()); + let tabbing_id = NSString::alloc(NIL).init_str(tabbing_identifier.as_str()); let _: () = msg_send![native_window, setTabbingIdentifier: tabbing_id]; } else { - let _: () = msg_send![native_window, setTabbingIdentifier:nil]; + let _: () = msg_send![native_window, setTabbingIdentifier:NIL]; } } } @@ -1044,48 +1093,43 @@ impl PlatformWindow for MacWindow { fn appearance(&self) -> WindowAppearance { unsafe { - let appearance: id = msg_send![self.0.lock().native_window, effectiveAppearance]; + let appearance: ObjcId = msg_send![self.0.lock().native_window, effectiveAppearance]; WindowAppearance::from_native(appearance) } } fn display(&self) -> Option> { unsafe { - let screen = self.0.lock().native_window.screen(); + let screen: ObjcId = msg_send![self.0.lock().native_window, screen]; if screen.is_null() { return None; } - let device_description: id = msg_send![screen, deviceDescription]; - let screen_number: id = NSDictionary::valueForKey_( - device_description, - NSString::alloc(nil).init_str("NSScreenNumber"), - ); - - let screen_number: u32 = msg_send![screen_number, unsignedIntValue]; - + let device_description: ObjcId = msg_send![screen, deviceDescription]; + let screen_number_obj: ObjcId = + msg_send![device_description, valueForKey: ns_string("NSScreenNumber")]; + let screen_number: u32 = msg_send![screen_number_obj, unsignedIntValue]; Some(Rc::new(MacDisplay(screen_number))) } } fn mouse_position(&self) -> Point { let position = unsafe { - self.0 - .lock() - .native_window - .mouseLocationOutsideOfEventStream() + msg_send![ + self.0.lock().native_window, + mouseLocationOutsideOfEventStream + ] }; convert_mouse_position(position, self.content_size().height) } fn modifiers(&self) -> Modifiers { unsafe { - let modifiers: NSEventModifierFlags = msg_send![class!(NSEvent), modifierFlags]; - - let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); - let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); - let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); - let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); - let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); + let modifiers: u64 = msg_send![class!(NSEvent), modifierFlags]; + let control = (modifiers & MOD_CONTROL) != 0; + let alt = (modifiers & MOD_OPTION) != 0; + let shift = (modifiers & MOD_SHIFT) != 0; + let command = (modifiers & MOD_COMMAND) != 0; + let function = (modifiers & MOD_FUNCTION) != 0; Modifiers { control, @@ -1099,10 +1143,9 @@ impl PlatformWindow for MacWindow { fn capslock(&self) -> Capslock { unsafe { - let modifiers: NSEventModifierFlags = msg_send![class!(NSEvent), modifierFlags]; - + let modifiers: u64 = msg_send![class!(NSEvent), modifierFlags]; Capslock { - on: modifiers.contains(NSEventModifierFlags::NSAlphaShiftKeyMask), + on: (modifiers & MOD_CAPS_LOCK) != 0, } } } @@ -1148,12 +1191,12 @@ impl PlatformWindow for MacWindow { .filter(|&(label_index, _)| label_index > 0); unsafe { - let alert: id = msg_send![class!(NSAlert), alloc]; - let alert: id = msg_send![alert, init]; + let alert: ObjcId = msg_send![class!(NSAlert), alloc]; + let alert: ObjcId = msg_send![alert, init]; let alert_style = match level { - PromptLevel::Info => 1, - PromptLevel::Warning => 0, - PromptLevel::Critical => 2, + PromptLevel::Info => NSAlertStyleInformational, + PromptLevel::Warning => NSAlertStyleWarning, + PromptLevel::Critical => NSAlertStyleCritical, }; let _: () = msg_send![alert, setAlertStyle: alert_style]; let _: () = msg_send![alert, setMessageText: ns_string(msg)]; @@ -1166,7 +1209,8 @@ impl PlatformWindow for MacWindow { .enumerate() .filter(|&(ix, _)| Some(ix) != latest_non_cancel_label.map(|(ix, _)| ix)) { - let button: id = msg_send![alert, addButtonWithTitle: ns_string(answer.label())]; + let button: ObjcId = + msg_send![alert, addButtonWithTitle: ns_string(answer.label())]; let _: () = msg_send![button, setTag: ix as NSInteger]; if answer.is_cancel() { @@ -1178,7 +1222,8 @@ impl PlatformWindow for MacWindow { } } if let Some((ix, answer)) = latest_non_cancel_label { - let button: id = msg_send![alert, addButtonWithTitle: ns_string(answer.label())]; + let button: ObjcId = + msg_send![alert, addButtonWithTitle: ns_string(answer.label())]; let _: () = msg_send![button, setTag: ix as NSInteger]; } @@ -1212,14 +1257,17 @@ impl PlatformWindow for MacWindow { executor .spawn(async move { unsafe { - let _: () = msg_send![window, makeKeyAndOrderFront: nil]; + let _: () = msg_send![window, makeKeyAndOrderFront: NIL]; } }) .detach(); } fn is_active(&self) -> bool { - unsafe { self.0.lock().native_window.isKeyWindow() == YES } + unsafe { + let is_key: BOOL = msg_send![self.0.lock().native_window, isKeyWindow]; + is_key == YES + } } // is_hovered is unused on macOS. See Window::is_window_hovered. @@ -1229,7 +1277,7 @@ impl PlatformWindow for MacWindow { fn set_title(&mut self, title: &str) { unsafe { - let app = NSApplication::sharedApplication(nil); + let app: ObjcId = msg_send![class!(NSApplication), sharedApplication]; let window = self.0.lock().native_window; let title = ns_string(title); let _: () = msg_send![app, changeWindowsItem:window title:title filename:false]; @@ -1240,7 +1288,7 @@ impl PlatformWindow for MacWindow { fn get_title(&self) -> String { unsafe { - let title: id = msg_send![self.0.lock().native_window, title]; + let title: ObjcId = msg_send![self.0.lock().native_window, title]; if title.is_null() { "".to_string() } else { @@ -1258,14 +1306,14 @@ impl PlatformWindow for MacWindow { this.renderer.update_transparency(!opaque); unsafe { - this.native_window.setOpaque_(opaque as BOOL); - let background_color = if opaque { - NSColor::colorWithSRGBRed_green_blue_alpha_(nil, 0f64, 0f64, 0f64, 1f64) + let _: () = msg_send![this.native_window, setOpaque: (opaque as BOOL)]; + let background_color: ObjcId = if opaque { + msg_send![class!(NSColor), colorWithSRGBRed: 0f64 green: 0f64 blue: 0f64 alpha: 1f64] } else { // Not using `+[NSColor clearColor]` to avoid broken shadow. - NSColor::colorWithSRGBRed_green_blue_alpha_(nil, 0f64, 0f64, 0f64, 0.0001) + msg_send![class!(NSColor), colorWithSRGBRed: 0f64 green: 0f64 blue: 0f64 alpha: 0.0001f64] }; - this.native_window.setBackgroundColor_(background_color); + let _: () = msg_send![this.native_window, setBackgroundColor: background_color]; if NSAppKitVersionNumber < NSAppKitVersionNumber12_0 { // Whether `-[NSVisualEffectView respondsToSelector:@selector(_updateProxyLayer)]`. @@ -1277,7 +1325,7 @@ impl PlatformWindow for MacWindow { 0 }; - let window_number = this.native_window.windowNumber(); + let window_number: NSInteger = msg_send![this.native_window, windowNumber]; CGSSetWindowBackgroundBlurRadius(CGSMainConnectionID(), window_number, blur_radius); } else { // On newer macOS `NSVisualEffectView` manages the effect layer directly. Using it @@ -1285,23 +1333,19 @@ impl PlatformWindow for MacWindow { // over the effect layer. if background_appearance != WindowBackgroundAppearance::Blurred { if let Some(blur_view) = this.blurred_view { - NSView::removeFromSuperview(blur_view); + let _: () = msg_send![blur_view, removeFromSuperview]; this.blurred_view = None; } } else if this.blurred_view.is_none() { - let content_view = this.native_window.contentView(); - let frame = NSView::bounds(content_view); - let mut blur_view: id = msg_send![BLURRED_VIEW_CLASS, alloc]; - blur_view = NSView::initWithFrame_(blur_view, frame); - blur_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); - - let _: () = msg_send![ - content_view, - addSubview: blur_view - positioned: NSWindowOrderingMode::NSWindowBelow - relativeTo: nil - ]; - this.blurred_view = Some(blur_view.autorelease()); + let content_view: ObjcId = msg_send![this.native_window, contentView]; + let blur_frame: NSRect = msg_send![content_view, bounds]; + let mut blur_view: ObjcId = msg_send![BLURRED_VIEW_CLASS, alloc]; + blur_view = msg_send![blur_view, initWithFrame: blur_frame]; + let _: () = msg_send![blur_view, setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; + + let _: () = msg_send![content_view, addSubview: blur_view positioned: NSWindowBelow relativeTo: NIL]; + let blur_view: ObjcId = msg_send![blur_view, autorelease]; + this.blurred_view = Some(blur_view); } } } @@ -1324,7 +1368,7 @@ impl PlatformWindow for MacWindow { this.executor .spawn(async move { unsafe { - let app = NSApplication::sharedApplication(nil); + let app: ObjcId = msg_send![class!(NSApplication), sharedApplication]; let _: () = msg_send![app, orderFrontCharacterPalette: window]; } }) @@ -1334,7 +1378,7 @@ impl PlatformWindow for MacWindow { fn minimize(&self) { let window = self.0.lock().native_window; unsafe { - window.miniaturize_(nil); + let _: () = msg_send![window, miniaturize: NIL]; } } @@ -1344,7 +1388,7 @@ impl PlatformWindow for MacWindow { this.executor .spawn(async move { unsafe { - window.zoom_(nil); + let _: () = msg_send![window, zoom: NIL]; } }) .detach(); @@ -1356,7 +1400,7 @@ impl PlatformWindow for MacWindow { this.executor .spawn(async move { unsafe { - window.toggleFullScreen_(nil); + let _: () = msg_send![window, toggleFullScreen: NIL]; } }) .detach(); @@ -1367,9 +1411,8 @@ impl PlatformWindow for MacWindow { let window = this.native_window; unsafe { - window - .styleMask() - .contains(NSWindowStyleMask::NSFullScreenWindowMask) + let mask: NSWindowStyleMask = msg_send![window, styleMask]; + (mask & NSWindowStyleMaskFullScreen) != 0 } } @@ -1412,7 +1455,7 @@ impl PlatformWindow for MacWindow { fn tabbed_windows(&self) -> Option> { unsafe { - let windows: id = msg_send![self.0.lock().native_window, tabbedWindows]; + let windows: ObjcId = msg_send![self.0.lock().native_window, tabbedWindows]; if windows.is_null() { return None; } @@ -1420,10 +1463,10 @@ impl PlatformWindow for MacWindow { let count: NSUInteger = msg_send![windows, count]; let mut result = Vec::new(); for i in 0..count { - let window: id = msg_send![windows, objectAtIndex:i]; + let window: ObjcId = msg_send![windows, objectAtIndex:i]; if msg_send![window, isKindOfClass: WINDOW_CLASS] { let handle = get_window_state(&*window).lock().handle; - let title: id = msg_send![window, title]; + let title: ObjcId = msg_send![window, title]; let title = SharedString::from(title.to_str().to_string()); result.push(SystemWindowTab::new(title, handle)); @@ -1436,7 +1479,7 @@ impl PlatformWindow for MacWindow { fn tab_bar_visible(&self) -> bool { unsafe { - let tab_group: id = msg_send![self.0.lock().native_window, tabGroup]; + let tab_group: ObjcId = msg_send![self.0.lock().native_window, tabGroup]; if tab_group.is_null() { false } else { @@ -1484,7 +1527,7 @@ impl PlatformWindow for MacWindow { executor .spawn(async move { unsafe { - let input_context: id = + let input_context: ObjcId = msg_send![class!(NSTextInputContext), currentInputContext]; if input_context.is_null() { return; @@ -1501,15 +1544,15 @@ impl PlatformWindow for MacWindow { this.executor .spawn(async move { unsafe { - let defaults: id = NSUserDefaults::standardUserDefaults(); - let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); - let key = NSString::alloc(nil).init_str("AppleActionOnDoubleClick"); + let defaults: ObjcId = NSUserDefaults::standardUserDefaults(); + let domain = NSString::alloc(NIL).init_str("NSGlobalDomain"); + let key = NSString::alloc(NIL).init_str("AppleActionOnDoubleClick"); - let dict: id = msg_send![defaults, persistentDomainForName: domain]; - let action: id = if !dict.is_null() { + let dict: ObjcId = msg_send![defaults, persistentDomainForName: domain]; + let action: ObjcId = if !dict.is_null() { msg_send![dict, objectForKey: key] } else { - nil + NIL }; let action_str = if !action.is_null() { @@ -1520,17 +1563,17 @@ impl PlatformWindow for MacWindow { match action_str.as_ref() { "Minimize" => { - window.miniaturize_(nil); + let _: () = msg_send![window, miniaturize: NIL]; } "Maximize" => { - window.zoom_(nil); + let _: () = msg_send![window, zoom: NIL]; } "Fill" => { // There is no documented API for "Fill" action, so we'll just zoom the window - window.zoom_(nil); + let _: () = msg_send![window, zoom: NIL]; } _ => { - window.zoom_(nil); + let _: () = msg_send![window, zoom: NIL]; } } } @@ -1561,13 +1604,14 @@ impl rwh::HasDisplayHandle for MacWindow { } } -fn get_scale_factor(native_window: id) -> f32 { +fn get_scale_factor(native_window: ObjcId) -> f32 { let factor = unsafe { - let screen: id = msg_send![native_window, screen]; + let screen: ObjcId = msg_send![native_window, screen]; if screen.is_null() { return 1.0; } - NSScreen::backingScaleFactor(screen) as f32 + let scale: f64 = msg_send![screen, backingScaleFactor]; + scale as f32 }; // We are not certain what triggers this, but it seems that sometimes @@ -1614,15 +1658,15 @@ extern "C" fn dealloc_view(this: &Object, _: Sel) { } } -extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: id) -> BOOL { +extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: ObjcId) -> BOOL { handle_key_event(this, native_event, true) } -extern "C" fn handle_key_down(this: &Object, _: Sel, native_event: id) { +extern "C" fn handle_key_down(this: &Object, _: Sel, native_event: ObjcId) { handle_key_event(this, native_event, false); } -extern "C" fn handle_key_up(this: &Object, _: Sel, native_event: id) { +extern "C" fn handle_key_up(this: &Object, _: Sel, native_event: ObjcId) { handle_key_event(this, native_event, false); } @@ -1651,7 +1695,7 @@ extern "C" fn handle_key_up(this: &Object, _: Sel, native_event: id) { // - in vim mode `option-4` should go to end of line (same as $) // Japanese (Romaji) layout: // - type `a i left down up enter enter` should create an unmarked text "愛" -extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: bool) -> BOOL { +extern "C" fn handle_key_event(this: &Object, native_event: ObjcId, key_equivalent: bool) -> BOOL { let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.as_ref().lock(); @@ -1713,7 +1757,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: } let handled: BOOL = unsafe { - let input_context: id = msg_send![this, inputContext]; + let input_context: ObjcId = msg_send![this, inputContext]; msg_send![input_context, handleEvent: native_event] }; window_state.as_ref().lock().keystroke_for_do_command.take(); @@ -1754,7 +1798,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: } unsafe { - let input_context: id = msg_send![this, inputContext]; + let input_context: ObjcId = msg_send![this, inputContext]; msg_send![input_context, handleEvent: native_event] } } @@ -1768,7 +1812,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: } } -extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { +extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: ObjcId) { let window_state = unsafe { get_window_state(this) }; let weak_window_state = Arc::downgrade(&window_state); let mut lock = window_state.as_ref().lock(); @@ -1838,7 +1882,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { PlatformInput::MouseDown(_) => { drop(lock); unsafe { - let input_context: id = msg_send![this, inputContext]; + let input_context: ObjcId = msg_send![this, inputContext]; msg_send![input_context, handleEvent: native_event] } lock = window_state.as_ref().lock(); @@ -1898,15 +1942,12 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { } } -extern "C" fn window_did_change_occlusion_state(this: &Object, _: Sel, _: id) { +extern "C" fn window_did_change_occlusion_state(this: &Object, _: Sel, _: ObjcId) { let window_state = unsafe { get_window_state(this) }; let lock = &mut *window_state.lock(); unsafe { - if lock - .native_window - .occlusionState() - .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) - { + let is_visible: BOOL = msg_send![lock.native_window, isVisible]; + if is_visible == YES { lock.move_traffic_light(); lock.start_display_link(); } else { @@ -1915,43 +1956,55 @@ extern "C" fn window_did_change_occlusion_state(this: &Object, _: Sel, _: id) { } } -extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) { +extern "C" fn window_did_resize(this: &Object, _: Sel, _: ObjcId) { let window_state = unsafe { get_window_state(this) }; window_state.as_ref().lock().move_traffic_light(); } -extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) { +extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: ObjcId) { let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.as_ref().lock(); lock.fullscreen_restore_bounds = lock.bounds(); - let min_version = NSOperatingSystemVersion::new(15, 3, 0); + let min_version = NSOperatingSystemVersion { + majorVersion: 15, + minorVersion: 3, + patchVersion: 0, + }; if is_macos_version_at_least(min_version) { unsafe { - lock.native_window.setTitlebarAppearsTransparent_(NO); + let _: () = msg_send![lock.native_window, setTitlebarAppearsTransparent: NO]; } } } -extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: id) { +extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: ObjcId) { let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.as_ref().lock(); - let min_version = NSOperatingSystemVersion::new(15, 3, 0); + let min_version = NSOperatingSystemVersion { + majorVersion: 15, + minorVersion: 3, + patchVersion: 0, + }; if is_macos_version_at_least(min_version) && lock.transparent_titlebar { unsafe { - lock.native_window.setTitlebarAppearsTransparent_(YES); + let _: () = msg_send![lock.native_window, setTitlebarAppearsTransparent: YES]; } } } pub(crate) fn is_macos_version_at_least(version: NSOperatingSystemVersion) -> bool { - unsafe { NSProcessInfo::processInfo(nil).isOperatingSystemAtLeastVersion(version) } + unsafe { + let process_info: ObjcId = msg_send![class!(NSProcessInfo), processInfo]; + let ok: BOOL = msg_send![process_info, isOperatingSystemAtLeastVersion: version]; + ok == YES + } } -extern "C" fn window_did_move(this: &Object, _: Sel, _: id) { +extern "C" fn window_did_move(this: &Object, _: Sel, _: ObjcId) { let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.as_ref().lock(); if let Some(mut callback) = lock.moved_callback.take() { @@ -1961,16 +2014,19 @@ extern "C" fn window_did_move(this: &Object, _: Sel, _: id) { } } -extern "C" fn window_did_change_screen(this: &Object, _: Sel, _: id) { +extern "C" fn window_did_change_screen(this: &Object, _: Sel, _: ObjcId) { let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.as_ref().lock(); lock.start_display_link(); } -extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) { +extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: ObjcId) { let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.lock(); - let is_active = unsafe { lock.native_window.isKeyWindow() == YES }; + let is_active = unsafe { + let v: BOOL = msg_send![lock.native_window, isKeyWindow]; + v == YES + }; // When opening a pop-up while the application isn't active, Cocoa sends a spurious // `windowDidBecomeKey` message to the previous key window even though that window @@ -2027,7 +2083,7 @@ extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) .detach(); } -extern "C" fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL { +extern "C" fn window_should_close(this: &Object, _: Sel, _: ObjcId) -> BOOL { let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.as_ref().lock(); if let Some(mut callback) = lock.should_close_callback.take() { @@ -2056,10 +2112,10 @@ extern "C" fn close_window(this: &Object, _: Sel) { } } -extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { +extern "C" fn make_backing_layer(this: &Object, _: Sel) -> ObjcId { let window_state = unsafe { get_window_state(this) }; let window_state = window_state.as_ref().lock(); - window_state.renderer.layer_ptr() as id + window_state.renderer.layer_ptr() as ObjcId } extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) { @@ -2091,10 +2147,16 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.as_ref().lock(); - let new_size = Size::::from(size); + let new_size = Size:: { + width: px(size.width as f32), + height: px(size.height as f32), + }; let old_size = unsafe { let old_frame: NSRect = msg_send![this, frame]; - Size::::from(old_frame.size) + Size:: { + width: px(old_frame.size.width as f32), + height: px(old_frame.size.height as f32), + } }; if old_size == new_size { @@ -2118,7 +2180,7 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { }; } -extern "C" fn display_layer(this: &Object, _: Sel, _: id) { +extern "C" fn display_layer(this: &Object, _: Sel, _: ObjcId) { let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.lock(); if let Some(mut callback) = lock.request_frame_callback.take() { @@ -2137,7 +2199,7 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) { } unsafe extern "C" fn step(view: *mut c_void) { - let view = view as id; + let view = view as ObjcId; let window_state = unsafe { get_window_state(&*view) }; let mut lock = window_state.lock(); @@ -2148,7 +2210,7 @@ unsafe extern "C" fn step(view: *mut c_void) { } } -extern "C" fn valid_attributes_for_marked_text(_: &Object, _: Sel) -> id { +extern "C" fn valid_attributes_for_marked_text(_: &Object, _: Sel) -> ObjcId { unsafe { msg_send![class!(NSArray), array] } } @@ -2179,7 +2241,7 @@ extern "C" fn first_rect_for_character_range( this: &Object, _: Sel, range: NSRange, - _: id, + _: ObjcId, ) -> NSRect { let frame = get_frame(this); with_input_handler(this, |input_handler| { @@ -2187,17 +2249,24 @@ extern "C" fn first_rect_for_character_range( }) .flatten() .map_or( - NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), - |bounds| { - NSRect::new( - NSPoint::new( - frame.origin.x + bounds.origin.x.0 as f64, - frame.origin.y + frame.size.height - - bounds.origin.y.0 as f64 - - bounds.size.height.0 as f64, - ), - NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), - ) + NSRect { + origin: NSPoint { x: 0., y: 0. }, + size: NSSize { + width: 0., + height: 0., + }, + }, + |bounds| NSRect { + origin: NSPoint { + x: frame.origin.x + bounds.origin.x.0 as f64, + y: frame.origin.y + frame.size.height + - bounds.origin.y.0 as f64 + - bounds.size.height.0 as f64, + }, + size: NSSize { + width: bounds.size.width.0 as f64, + height: bounds.size.height.0 as f64, + }, }, ) } @@ -2206,21 +2275,23 @@ fn get_frame(this: &Object) -> NSRect { unsafe { let state = get_window_state(this); let lock = state.lock(); - let mut frame = NSWindow::frame(lock.native_window); + let mut frame: NSRect = msg_send![lock.native_window, frame]; let content_layout_rect: CGRect = msg_send![lock.native_window, contentLayoutRect]; - let style_mask: NSWindowStyleMask = msg_send![lock.native_window, styleMask]; - if !style_mask.contains(NSWindowStyleMask::NSFullSizeContentViewWindowMask) { - frame.origin.y -= frame.size.height - content_layout_rect.size.height; + // Adjust Y-origin by the difference between full frame and content layout height + // when there is a titlebar/tool area. This avoids relying on deprecated bitmask names. + let diff = frame.size.height - content_layout_rect.size.height; + if diff > 0.0 { + frame.origin.y -= diff; } frame } } -extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NSRange) { +extern "C" fn insert_text(this: &Object, _: Sel, text: ObjcId, replacement_range: NSRange) { unsafe { let is_attributed_string: BOOL = msg_send![text, isKindOfClass: [class!(NSAttributedString)]]; - let text: id = if is_attributed_string == YES { + let text: ObjcId = if is_attributed_string == YES { msg_send![text, string] } else { text @@ -2237,14 +2308,14 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS extern "C" fn set_marked_text( this: &Object, _: Sel, - text: id, + text: ObjcId, selected_range: NSRange, replacement_range: NSRange, ) { unsafe { let is_attributed_string: BOOL = msg_send![text, isKindOfClass: [class!(NSAttributedString)]]; - let text: id = if is_attributed_string == YES { + let text: ObjcId = if is_attributed_string == YES { msg_send![text, string] } else { text @@ -2266,7 +2337,7 @@ extern "C" fn attributed_substring_for_proposed_range( _: Sel, range: NSRange, actual_range: *mut c_void, -) -> id { +) -> ObjcId { with_input_handler(this, |input_handler| { let range = range.to_range()?; if range.is_empty() { @@ -2281,13 +2352,13 @@ extern "C" fn attributed_substring_for_proposed_range( unsafe { (actual_range as *mut NSRange).write(NSRange::from(adjusted)) }; } unsafe { - let string: id = msg_send![class!(NSAttributedString), alloc]; - let string: id = msg_send![string, initWithString: ns_string(&selected_text)]; + let string: ObjcId = msg_send![class!(NSAttributedString), alloc]; + let string: ObjcId = msg_send![string, initWithString: ns_string(&selected_text)]; Some(string) } }) .flatten() - .unwrap_or(nil) + .unwrap_or(NIL) } // We ignore which selector it asks us to do because the user may have @@ -2322,7 +2393,7 @@ extern "C" fn view_did_change_effective_appearance(this: &Object, _: Sel) { } } -extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: id) -> BOOL { +extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: ObjcId) -> BOOL { let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.as_ref().lock(); lock.first_mouse = true; @@ -2347,7 +2418,7 @@ fn screen_point_to_gpui_point(this: &Object, position: NSPoint) -> Point point(px(window_x as f32), px(window_y as f32)) } -extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: id) -> NSDragOperation { +extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: ObjcId) -> NSDragOperation { let window_state = unsafe { get_window_state(this) }; let position = drag_event_position(&window_state, dragging_info); let paths = external_paths_from_event(dragging_info); @@ -2361,7 +2432,7 @@ extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: id) -> NSDr NSDragOperationNone } -extern "C" fn dragging_updated(this: &Object, _: Sel, dragging_info: id) -> NSDragOperation { +extern "C" fn dragging_updated(this: &Object, _: Sel, dragging_info: ObjcId) -> NSDragOperation { let window_state = unsafe { get_window_state(this) }; let position = drag_event_position(&window_state, dragging_info); if send_new_event( @@ -2374,7 +2445,7 @@ extern "C" fn dragging_updated(this: &Object, _: Sel, dragging_info: id) -> NSDr } } -extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) { +extern "C" fn dragging_exited(this: &Object, _: Sel, _: ObjcId) { let window_state = unsafe { get_window_state(this) }; send_new_event( &window_state, @@ -2383,7 +2454,7 @@ extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) { window_state.lock().external_files_dragged = false; } -extern "C" fn perform_drag_operation(this: &Object, _: Sel, dragging_info: id) -> BOOL { +extern "C" fn perform_drag_operation(this: &Object, _: Sel, dragging_info: ObjcId) -> BOOL { let window_state = unsafe { get_window_state(this) }; let position = drag_event_position(&window_state, dragging_info); send_new_event( @@ -2395,22 +2466,27 @@ extern "C" fn perform_drag_operation(this: &Object, _: Sel, dragging_info: id) - fn external_paths_from_event(dragging_info: *mut Object) -> Option { let mut paths = SmallVec::new(); - let pasteboard: id = unsafe { msg_send![dragging_info, draggingPasteboard] }; - let filenames = unsafe { NSPasteboard::propertyListForType(pasteboard, NSFilenamesPboardType) }; - if filenames == nil { + let pasteboard: ObjcId = unsafe { msg_send![dragging_info, draggingPasteboard] }; + let filenames: ObjcId = + unsafe { msg_send![pasteboard, propertyListForType: NSFilenamesPboardType] }; + if filenames == NIL { return None; } - for file in unsafe { filenames.iter() } { - let path = unsafe { - let f = NSString::UTF8String(file); - CStr::from_ptr(f).to_string_lossy().into_owned() - }; - paths.push(PathBuf::from(path)) + unsafe { + let count: NSUInteger = msg_send![filenames, count]; + for i in 0..count { + let file: ObjcId = msg_send![filenames, objectAtIndex: i]; + let path = { + let f = NSString::UTF8String(file); + CStr::from_ptr(f).to_string_lossy().into_owned() + }; + paths.push(PathBuf::from(path)); + } } Some(ExternalPaths(paths)) } -extern "C" fn conclude_drag_operation(this: &Object, _: Sel, _: id) { +extern "C" fn conclude_drag_operation(this: &Object, _: Sel, _: ObjcId) { let window_state = unsafe { get_window_state(this) }; send_new_event( &window_state, @@ -2451,7 +2527,10 @@ fn send_new_event(window_state_lock: &Mutex, e: PlatformInput) - } } -fn drag_event_position(window_state: &Mutex, dragging_info: id) -> Point { +fn drag_event_position( + window_state: &Mutex, + dragging_info: ObjcId, +) -> Point { let drag_location: NSPoint = unsafe { msg_send![dragging_info, draggingLocation] }; convert_mouse_position(drag_location, window_state.lock().content_size().height) } @@ -2472,23 +2551,21 @@ where } } -unsafe fn display_id_for_screen(screen: id) -> CGDirectDisplayID { +unsafe fn display_id_for_screen(screen: ObjcId) -> CGDirectDisplayID { unsafe { - let device_description = NSScreen::deviceDescription(screen); - let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); - let screen_number = device_description.objectForKey_(screen_number_key); - let screen_number: NSUInteger = msg_send![screen_number, unsignedIntegerValue]; + let device_description: ObjcId = msg_send![screen, deviceDescription]; + let key: ObjcId = NSString::alloc(NIL).init_str("NSScreenNumber"); + let screen_number_obj: ObjcId = msg_send![device_description, objectForKey: key]; + let screen_number: NSUInteger = msg_send![screen_number_obj, unsignedIntegerValue]; screen_number as CGDirectDisplayID } } -extern "C" fn blurred_view_init_with_frame(this: &Object, _: Sel, frame: NSRect) -> id { +extern "C" fn blurred_view_init_with_frame(this: &Object, _: Sel, frame: NSRect) -> ObjcId { unsafe { - let view = msg_send![super(this, class!(NSVisualEffectView)), initWithFrame: frame]; - // Use a colorless semantic material. The default value `AppearanceBased`, though not - // manually set, is deprecated. - NSVisualEffectView::setMaterial_(view, NSVisualEffectMaterial::Selection); - NSVisualEffectView::setState_(view, NSVisualEffectState::Active); + let view: ObjcId = msg_send![super(this, class!(NSVisualEffectView)), initWithFrame: frame]; + // Use an active visual effect state via icrate constant + let _: () = msg_send![view, setState: NSVisualEffectStateActive]; view } } @@ -2496,35 +2573,37 @@ extern "C" fn blurred_view_init_with_frame(this: &Object, _: Sel, frame: NSRect) extern "C" fn blurred_view_update_layer(this: &Object, _: Sel) { unsafe { let _: () = msg_send![super(this, class!(NSVisualEffectView)), updateLayer]; - let layer: id = msg_send![this, layer]; + let layer: ObjcId = msg_send![this, layer]; if !layer.is_null() { remove_layer_background(layer); } } } -unsafe fn remove_layer_background(layer: id) { +unsafe fn remove_layer_background(layer: ObjcId) { unsafe { - let _: () = msg_send![layer, setBackgroundColor:nil]; + let _: () = msg_send![layer, setBackgroundColor:NIL]; - let class_name: id = msg_send![layer, className]; - if class_name.isEqualToString("CAChameleonLayer") { + let class_name: ObjcId = msg_send![layer, className]; + let equal: BOOL = msg_send![class_name, isEqualToString: ns_string("CAChameleonLayer")]; + if equal == YES { // Remove the desktop tinting effect. let _: () = msg_send![layer, setHidden: YES]; return; } - let filters: id = msg_send![layer, filters]; + let filters: ObjcId = msg_send![layer, filters]; if !filters.is_null() { // Remove the increased saturation. // The effect of a `CAFilter` or `CIFilter` is determined by its name, and the // `description` reflects its name and some parameters. Currently `NSVisualEffectView` // uses a `CAFilter` named "colorSaturate". If one day they switch to `CIFilter`, the // `description` will still contain "Saturat" ("... inputSaturation = ..."). - let test_string: id = NSString::alloc(nil).init_str("Saturat").autorelease(); - let count = NSArray::count(filters); + let test_string: ObjcId = NSString::alloc(NIL).init_str("Saturat").autorelease(); + let count: NSUInteger = msg_send![filters, count]; for i in 0..count { - let description: id = msg_send![filters.objectAtIndex(i), description]; + let filter_i: ObjcId = msg_send![filters, objectAtIndex: i]; + let description: ObjcId = msg_send![filter_i, description]; let hit: BOOL = msg_send![description, containsString: test_string]; if hit == NO { continue; @@ -2532,34 +2611,38 @@ unsafe fn remove_layer_background(layer: id) { let all_indices = NSRange { location: 0, - length: count, + length: count as u64, }; - let indices: id = msg_send![class!(NSMutableIndexSet), indexSet]; + let indices: ObjcId = msg_send![class!(NSMutableIndexSet), indexSet]; let _: () = msg_send![indices, addIndexesInRange: all_indices]; let _: () = msg_send![indices, removeIndex:i]; - let filtered: id = msg_send![filters, objectsAtIndexes: indices]; + let filtered: ObjcId = msg_send![filters, objectsAtIndexes: indices]; let _: () = msg_send![layer, setFilters: filtered]; break; } } - let sublayers: id = msg_send![layer, sublayers]; + let sublayers: ObjcId = msg_send![layer, sublayers]; if !sublayers.is_null() { - let count = NSArray::count(sublayers); + let count: NSUInteger = msg_send![sublayers, count]; for i in 0..count { - let sublayer = sublayers.objectAtIndex(i); + let sublayer: ObjcId = msg_send![sublayers, objectAtIndex: i]; remove_layer_background(sublayer); } } } } -extern "C" fn add_titlebar_accessory_view_controller(this: &Object, _: Sel, view_controller: id) { +extern "C" fn add_titlebar_accessory_view_controller( + this: &Object, + _: Sel, + view_controller: ObjcId, +) { unsafe { let _: () = msg_send![super(this, class!(NSWindow)), addTitlebarAccessoryViewController: view_controller]; // Hide the native tab bar and set its height to 0, since we render our own. - let accessory_view: id = msg_send![view_controller, view]; + let accessory_view: ObjcId = msg_send![view_controller, view]; let _: () = msg_send![accessory_view, setHidden: YES]; let mut frame: NSRect = msg_send![accessory_view, frame]; frame.size.height = 0.0; @@ -2567,9 +2650,9 @@ extern "C" fn add_titlebar_accessory_view_controller(this: &Object, _: Sel, view } } -extern "C" fn move_tab_to_new_window(this: &Object, _: Sel, _: id) { +extern "C" fn move_tab_to_new_window(this: &Object, _: Sel, _: ObjcId) { unsafe { - let _: () = msg_send![super(this, class!(NSWindow)), moveTabToNewWindow:nil]; + let _: () = msg_send![super(this, class!(NSWindow)), moveTabToNewWindow:NIL]; let window_state = get_window_state(this); let mut lock = window_state.as_ref().lock(); @@ -2581,9 +2664,9 @@ extern "C" fn move_tab_to_new_window(this: &Object, _: Sel, _: id) { } } -extern "C" fn merge_all_windows(this: &Object, _: Sel, _: id) { +extern "C" fn merge_all_windows(this: &Object, _: Sel, _: ObjcId) { unsafe { - let _: () = msg_send![super(this, class!(NSWindow)), mergeAllWindows:nil]; + let _: () = msg_send![super(this, class!(NSWindow)), mergeAllWindows:NIL]; let window_state = get_window_state(this); let mut lock = window_state.as_ref().lock(); @@ -2595,7 +2678,7 @@ extern "C" fn merge_all_windows(this: &Object, _: Sel, _: id) { } } -extern "C" fn select_next_tab(this: &Object, _sel: Sel, _id: id) { +extern "C" fn select_next_tab(this: &Object, _sel: Sel, _id: ObjcId) { let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.as_ref().lock(); if let Some(mut callback) = lock.select_next_tab_callback.take() { @@ -2605,7 +2688,7 @@ extern "C" fn select_next_tab(this: &Object, _sel: Sel, _id: id) { } } -extern "C" fn select_previous_tab(this: &Object, _sel: Sel, _id: id) { +extern "C" fn select_previous_tab(this: &Object, _sel: Sel, _id: ObjcId) { let window_state = unsafe { get_window_state(this) }; let mut lock = window_state.as_ref().lock(); if let Some(mut callback) = lock.select_previous_tab_callback.take() { @@ -2615,9 +2698,9 @@ extern "C" fn select_previous_tab(this: &Object, _sel: Sel, _id: id) { } } -extern "C" fn toggle_tab_bar(this: &Object, _sel: Sel, _id: id) { +extern "C" fn toggle_tab_bar(this: &Object, _sel: Sel, _id: ObjcId) { unsafe { - let _: () = msg_send![super(this, class!(NSWindow)), toggleTabBar:nil]; + let _: () = msg_send![super(this, class!(NSWindow)), toggleTabBar:NIL]; let window_state = get_window_state(this); let mut lock = window_state.as_ref().lock(); diff --git a/crates/gpui/src/platform/mac/window_appearance.rs b/crates/gpui/src/platform/mac/window_appearance.rs index 65c409d30ce4f1..0950e5ba55e655 100644 --- a/crates/gpui/src/platform/mac/window_appearance.rs +++ b/crates/gpui/src/platform/mac/window_appearance.rs @@ -1,37 +1,24 @@ use crate::WindowAppearance; -use cocoa::{ - appkit::{NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight}, - base::id, - foundation::NSString, +use icrate::AppKit::{ + NSAppearanceNameAqua, NSAppearanceNameDarkAqua, NSAppearanceNameVibrantDark, + NSAppearanceNameVibrantLight, }; +use objc::runtime::Object; use objc::{msg_send, sel, sel_impl}; -use std::ffi::CStr; impl WindowAppearance { - pub(crate) unsafe fn from_native(appearance: id) -> Self { - let name: id = msg_send![appearance, name]; - unsafe { - if name == NSAppearanceNameVibrantLight { - Self::VibrantLight - } else if name == NSAppearanceNameVibrantDark { - Self::VibrantDark - } else if name == NSAppearanceNameAqua { - Self::Light - } else if name == NSAppearanceNameDarkAqua { - Self::Dark - } else { - println!( - "unknown appearance: {:?}", - CStr::from_ptr(name.UTF8String()) - ); - Self::Light - } + pub(crate) unsafe fn from_native(appearance: *mut Object) -> Self { + let name: *mut Object = unsafe { msg_send![appearance, name] }; + if unsafe { name == (NSAppearanceNameVibrantLight as *const _ as *mut Object) } { + Self::VibrantLight + } else if unsafe { name == (NSAppearanceNameVibrantDark as *const _ as *mut Object) } { + Self::VibrantDark + } else if unsafe { name == (NSAppearanceNameAqua as *const _ as *mut Object) } { + Self::Light + } else if unsafe { name == (NSAppearanceNameDarkAqua as *const _ as *mut Object) } { + Self::Dark + } else { + Self::Light } } } - -#[link(name = "AppKit", kind = "framework")] -unsafe extern "C" { - pub static NSAppearanceNameAqua: id; - pub static NSAppearanceNameDarkAqua: id; -} diff --git a/crates/macos_appkit_bridge/Cargo.toml b/crates/macos_appkit_bridge/Cargo.toml new file mode 100644 index 00000000000000..9ac6e745a3a4e1 --- /dev/null +++ b/crates/macos_appkit_bridge/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "macos_appkit_bridge" +version = "0.1.0" +edition = "2021" + +[lib] +name = "macos_appkit_bridge" +path = "src/lib.rs" +crate-type = ["staticlib", "rlib"] + +[dependencies] + +[build-dependencies] diff --git a/crates/macos_appkit_bridge/build.rs b/crates/macos_appkit_bridge/build.rs new file mode 100644 index 00000000000000..f511440de3824a --- /dev/null +++ b/crates/macos_appkit_bridge/build.rs @@ -0,0 +1,32 @@ +#[cfg(target_os = "macos")] +fn main() { + // Build Swift package and link static library + let _out_dir = std::env::var("OUT_DIR").unwrap(); + let package_dir = std::env::current_dir().unwrap(); + + let swift_dir = package_dir.join("swift"); + std::fs::create_dir_all(&swift_dir).ok(); + + // No codegen needed for C ABI shim + + // Build the Swift package containing our shim and the generated bridge. + let status = std::process::Command::new("swift") + .current_dir(&swift_dir) + .args(["build", "-c", "release"]) + .status() + .expect("Failed to spawn swift build"); + if !status.success() { + panic!("swift build failed: {:?}", status); + } + + // Link the produced static library; default SwiftPM output directory + let lib_dir = std::path::Path::new(&swift_dir) + .join(".build") + .join("release"); + println!("cargo:rustc-link-search=native={}", lib_dir.display()); + println!("cargo:rustc-link-lib=static=SwiftPackage"); + println!("cargo:rustc-link-lib=framework=AppKit"); +} + +#[cfg(not(target_os = "macos"))] +fn main() {} diff --git a/crates/macos_appkit_bridge/src/lib.rs b/crates/macos_appkit_bridge/src/lib.rs new file mode 100644 index 00000000000000..984e81d2394bad --- /dev/null +++ b/crates/macos_appkit_bridge/src/lib.rs @@ -0,0 +1 @@ +// This crate builds and links the Swift static library for macOS AppKit shims. diff --git a/crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftBridgeCore.h b/crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftBridgeCore.h new file mode 100644 index 00000000000000..14bfeeb3109a40 --- /dev/null +++ b/crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftBridgeCore.h @@ -0,0 +1,164 @@ +#include +#include +typedef struct RustStr { uint8_t* const start; uintptr_t len; } RustStr; +typedef struct __private__FfiSlice { void* const start; uintptr_t len; } __private__FfiSlice; +void* __swift_bridge__null_pointer(void); + + +typedef struct __private__OptionU8 { uint8_t val; bool is_some; } __private__OptionU8; +typedef struct __private__OptionI8 { int8_t val; bool is_some; } __private__OptionI8; +typedef struct __private__OptionU16 { uint16_t val; bool is_some; } __private__OptionU16; +typedef struct __private__OptionI16 { int16_t val; bool is_some; } __private__OptionI16; +typedef struct __private__OptionU32 { uint32_t val; bool is_some; } __private__OptionU32; +typedef struct __private__OptionI32 { int32_t val; bool is_some; } __private__OptionI32; +typedef struct __private__OptionU64 { uint64_t val; bool is_some; } __private__OptionU64; +typedef struct __private__OptionI64 { int64_t val; bool is_some; } __private__OptionI64; +typedef struct __private__OptionUsize { uintptr_t val; bool is_some; } __private__OptionUsize; +typedef struct __private__OptionIsize { intptr_t val; bool is_some; } __private__OptionIsize; +typedef struct __private__OptionF32 { float val; bool is_some; } __private__OptionF32; +typedef struct __private__OptionF64 { double val; bool is_some; } __private__OptionF64; +typedef struct __private__OptionBool { bool val; bool is_some; } __private__OptionBool; + +void* __swift_bridge__$Vec_u8$new(); +void __swift_bridge__$Vec_u8$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_u8$len(void* const vec); +void __swift_bridge__$Vec_u8$push(void* const vec, uint8_t val); +__private__OptionU8 __swift_bridge__$Vec_u8$pop(void* const vec); +__private__OptionU8 __swift_bridge__$Vec_u8$get(void* const vec, uintptr_t index); +__private__OptionU8 __swift_bridge__$Vec_u8$get_mut(void* const vec, uintptr_t index); +uint8_t const * __swift_bridge__$Vec_u8$as_ptr(void* const vec); + +void* __swift_bridge__$Vec_u16$new(); +void __swift_bridge__$Vec_u16$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_u16$len(void* const vec); +void __swift_bridge__$Vec_u16$push(void* const vec, uint16_t val); +__private__OptionU16 __swift_bridge__$Vec_u16$pop(void* const vec); +__private__OptionU16 __swift_bridge__$Vec_u16$get(void* const vec, uintptr_t index); +__private__OptionU16 __swift_bridge__$Vec_u16$get_mut(void* const vec, uintptr_t index); +uint16_t const * __swift_bridge__$Vec_u16$as_ptr(void* const vec); + +void* __swift_bridge__$Vec_u32$new(); +void __swift_bridge__$Vec_u32$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_u32$len(void* const vec); +void __swift_bridge__$Vec_u32$push(void* const vec, uint32_t val); +__private__OptionU32 __swift_bridge__$Vec_u32$pop(void* const vec); +__private__OptionU32 __swift_bridge__$Vec_u32$get(void* const vec, uintptr_t index); +__private__OptionU32 __swift_bridge__$Vec_u32$get_mut(void* const vec, uintptr_t index); +uint32_t const * __swift_bridge__$Vec_u32$as_ptr(void* const vec); + +void* __swift_bridge__$Vec_u64$new(); +void __swift_bridge__$Vec_u64$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_u64$len(void* const vec); +void __swift_bridge__$Vec_u64$push(void* const vec, uint64_t val); +__private__OptionU64 __swift_bridge__$Vec_u64$pop(void* const vec); +__private__OptionU64 __swift_bridge__$Vec_u64$get(void* const vec, uintptr_t index); +__private__OptionU64 __swift_bridge__$Vec_u64$get_mut(void* const vec, uintptr_t index); +uint64_t const * __swift_bridge__$Vec_u64$as_ptr(void* const vec); + +void* __swift_bridge__$Vec_usize$new(); +void __swift_bridge__$Vec_usize$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_usize$len(void* const vec); +void __swift_bridge__$Vec_usize$push(void* const vec, uintptr_t val); +__private__OptionUsize __swift_bridge__$Vec_usize$pop(void* const vec); +__private__OptionUsize __swift_bridge__$Vec_usize$get(void* const vec, uintptr_t index); +__private__OptionUsize __swift_bridge__$Vec_usize$get_mut(void* const vec, uintptr_t index); +uintptr_t const * __swift_bridge__$Vec_usize$as_ptr(void* const vec); + +void* __swift_bridge__$Vec_i8$new(); +void __swift_bridge__$Vec_i8$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_i8$len(void* const vec); +void __swift_bridge__$Vec_i8$push(void* const vec, int8_t val); +__private__OptionI8 __swift_bridge__$Vec_i8$pop(void* const vec); +__private__OptionI8 __swift_bridge__$Vec_i8$get(void* const vec, uintptr_t index); +__private__OptionI8 __swift_bridge__$Vec_i8$get_mut(void* const vec, uintptr_t index); +int8_t const * __swift_bridge__$Vec_i8$as_ptr(void* const vec); + +void* __swift_bridge__$Vec_i16$new(); +void __swift_bridge__$Vec_i16$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_i16$len(void* const vec); +void __swift_bridge__$Vec_i16$push(void* const vec, int16_t val); +__private__OptionI16 __swift_bridge__$Vec_i16$pop(void* const vec); +__private__OptionI16 __swift_bridge__$Vec_i16$get(void* const vec, uintptr_t index); +__private__OptionI16 __swift_bridge__$Vec_i16$get_mut(void* const vec, uintptr_t index); +int16_t const * __swift_bridge__$Vec_i16$as_ptr(void* const vec); + +void* __swift_bridge__$Vec_i32$new(); +void __swift_bridge__$Vec_i32$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_i32$len(void* const vec); +void __swift_bridge__$Vec_i32$push(void* const vec, int32_t val); +__private__OptionI32 __swift_bridge__$Vec_i32$pop(void* const vec); +__private__OptionI32 __swift_bridge__$Vec_i32$get(void* const vec, uintptr_t index); +__private__OptionI32 __swift_bridge__$Vec_i32$get_mut(void* const vec, uintptr_t index); +int32_t const * __swift_bridge__$Vec_i32$as_ptr(void* const vec); + +void* __swift_bridge__$Vec_i64$new(); +void __swift_bridge__$Vec_i64$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_i64$len(void* const vec); +void __swift_bridge__$Vec_i64$push(void* const vec, int64_t val); +__private__OptionI64 __swift_bridge__$Vec_i64$pop(void* const vec); +__private__OptionI64 __swift_bridge__$Vec_i64$get(void* const vec, uintptr_t index); +__private__OptionI64 __swift_bridge__$Vec_i64$get_mut(void* const vec, uintptr_t index); +int64_t const * __swift_bridge__$Vec_i64$as_ptr(void* const vec); + +void* __swift_bridge__$Vec_isize$new(); +void __swift_bridge__$Vec_isize$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_isize$len(void* const vec); +void __swift_bridge__$Vec_isize$push(void* const vec, intptr_t val); +__private__OptionIsize __swift_bridge__$Vec_isize$pop(void* const vec); +__private__OptionIsize __swift_bridge__$Vec_isize$get(void* const vec, uintptr_t index); +__private__OptionIsize __swift_bridge__$Vec_isize$get_mut(void* const vec, uintptr_t index); +intptr_t const * __swift_bridge__$Vec_isize$as_ptr(void* const vec); + +void* __swift_bridge__$Vec_bool$new(); +void __swift_bridge__$Vec_bool$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_bool$len(void* const vec); +void __swift_bridge__$Vec_bool$push(void* const vec, bool val); +__private__OptionBool __swift_bridge__$Vec_bool$pop(void* const vec); +__private__OptionBool __swift_bridge__$Vec_bool$get(void* const vec, uintptr_t index); +__private__OptionBool __swift_bridge__$Vec_bool$get_mut(void* const vec, uintptr_t index); +bool const * __swift_bridge__$Vec_bool$as_ptr(void* const vec); + +void* __swift_bridge__$Vec_f32$new(); +void __swift_bridge__$Vec_f32$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_f32$len(void* const vec); +void __swift_bridge__$Vec_f32$push(void* const vec, float val); +__private__OptionF32 __swift_bridge__$Vec_f32$pop(void* const vec); +__private__OptionF32 __swift_bridge__$Vec_f32$get(void* const vec, uintptr_t index); +__private__OptionF32 __swift_bridge__$Vec_f32$get_mut(void* const vec, uintptr_t index); +float const * __swift_bridge__$Vec_f32$as_ptr(void* const vec); + +void* __swift_bridge__$Vec_f64$new(); +void __swift_bridge__$Vec_f64$_free(void* const vec); +uintptr_t __swift_bridge__$Vec_f64$len(void* const vec); +void __swift_bridge__$Vec_f64$push(void* const vec, double val); +__private__OptionF64 __swift_bridge__$Vec_f64$pop(void* const vec); +__private__OptionF64 __swift_bridge__$Vec_f64$get(void* const vec, uintptr_t index); +__private__OptionF64 __swift_bridge__$Vec_f64$get_mut(void* const vec, uintptr_t index); +double const * __swift_bridge__$Vec_f64$as_ptr(void* const vec); + +#include +typedef struct RustString RustString; +void __swift_bridge__$RustString$_free(void* self); + +void* __swift_bridge__$Vec_RustString$new(void); +void __swift_bridge__$Vec_RustString$drop(void* vec_ptr); +void __swift_bridge__$Vec_RustString$push(void* vec_ptr, void* item_ptr); +void* __swift_bridge__$Vec_RustString$pop(void* vec_ptr); +void* __swift_bridge__$Vec_RustString$get(void* vec_ptr, uintptr_t index); +void* __swift_bridge__$Vec_RustString$get_mut(void* vec_ptr, uintptr_t index); +uintptr_t __swift_bridge__$Vec_RustString$len(void* vec_ptr); +void* __swift_bridge__$Vec_RustString$as_ptr(void* vec_ptr); + +void* __swift_bridge__$RustString$new(void); +void* __swift_bridge__$RustString$new_with_str(struct RustStr str); +uintptr_t __swift_bridge__$RustString$len(void* self); +struct RustStr __swift_bridge__$RustString$as_str(void* self); +struct RustStr __swift_bridge__$RustString$trim(void* self); +bool __swift_bridge__$RustStr$partial_eq(struct RustStr lhs, struct RustStr rhs); + + +void __swift_bridge__$call_boxed_fn_once_no_args_no_return(void* boxed_fnonce); +void __swift_bridge__$free_boxed_fn_once_no_args_no_return(void* boxed_fnonce); + + +struct __private__ResultPtrAndPtr { bool is_ok; void* ok_or_err; }; diff --git a/crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftPackage.h b/crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftPackage.h new file mode 100644 index 00000000000000..d4206662f5a800 --- /dev/null +++ b/crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftPackage.h @@ -0,0 +1,3 @@ +// File automatically generated by swift-bridge. +#include +void __swift_bridge__$gpui_menu_action(uint64_t tag); diff --git a/crates/macos_appkit_bridge/swift/Package.swift b/crates/macos_appkit_bridge/swift/Package.swift new file mode 100644 index 00000000000000..7ae89e92ba77b1 --- /dev/null +++ b/crates/macos_appkit_bridge/swift/Package.swift @@ -0,0 +1,13 @@ +// swift-tools-version:5.9 +import PackageDescription + +let package = Package( + name: "SwiftPackage", + platforms: [ .macOS(.v12) ], + products: [ + .library(name: "SwiftPackage", type: .static, targets: ["SwiftPackage"]) // static lib + ], + targets: [ + .target(name: "SwiftPackage", path: "Sources") + ] +) diff --git a/crates/macos_appkit_bridge/swift/Sources/Shim.swift b/crates/macos_appkit_bridge/swift/Sources/Shim.swift new file mode 100644 index 00000000000000..289ab889a4b46e --- /dev/null +++ b/crates/macos_appkit_bridge/swift/Sources/Shim.swift @@ -0,0 +1,306 @@ +import AppKit +import Foundation +@_silgen_name("gpui_menu_action") +func gpui_menu_action(_ tag: UInt64) + +fileprivate var menuActionHandlerRegistered = false + +@_cdecl("zed_register_menu_handler") +public func zed_register_menu_handler() { + // No-op: we call back to Rust via the global exported function. + menuActionHandlerRegistered = true +} + +@_cdecl("zed_set_main_menu_json") +public func zed_set_main_menu_json(_ json: UnsafePointer) { + let str = String(cString: json) + struct Item: Codable { + let kind: String + let title: String? + let tag: UInt64? + let key_equivalent: String? + let modifiers: [String]? + let system_type: String? + let items: [Item]? + } + struct Menu: Codable { let title: String; let items: [Item] } + struct Spec: Codable { let menus: [Menu] } + guard let data = str.data(using: .utf8), let spec = try? JSONDecoder().decode(Spec.self, from: data) else { return } + + func buildMenu(_ items: [Item]) -> NSMenu { + let menu = NSMenu() + for it in items { + switch it.kind { + case "separator": + menu.addItem(NSMenuItem.separator()) + case "action": + let key = it.key_equivalent ?? "" + let mi = NSMenuItem(title: it.title ?? "", action: #selector(MenuTarget.onMenuAction(_:)), keyEquivalent: key) + mi.target = MenuTarget.shared + if let mods = it.modifiers { mi.keyEquivalentModifierMask = modifiers(from: mods) } + if let tag = it.tag { mi.tag = Int(tag) } + menu.addItem(mi) + case "submenu": + let mi = NSMenuItem(title: it.title ?? "", action: nil, keyEquivalent: "") + let sub = buildMenu(it.items ?? []) + mi.submenu = sub + menu.addItem(mi) + case "system": + let mi = NSMenuItem(title: it.title ?? "", action: nil, keyEquivalent: "") + let sub = buildMenu(it.items ?? []) + mi.submenu = sub + // Wire special menus + if let st = it.system_type { + if st == "services" { NSApp.servicesMenu = sub } + if st == "windows" { NSApp.windowsMenu = sub } + } + menu.addItem(mi) + default: + continue + } + } + return menu + } + + func modifiers(from names: [String]) -> NSEvent.ModifierFlags { + var flags: NSEvent.ModifierFlags = [] + for name in names { + switch name.lowercased() { + case "command": flags.insert(.command) + case "control": flags.insert(.control) + case "option": flags.insert(.option) + case "shift": flags.insert(.shift) + default: break + } + } + return flags + } + + let mainMenu = NSMenu() + for m in spec.menus { + let mi = NSMenuItem(title: m.title, action: nil, keyEquivalent: "") + let sub = buildMenu(m.items) + mi.submenu = sub + if m.title == "Window" { NSApp.windowsMenu = sub } + mainMenu.addItem(mi) + } + DispatchQueue.main.async { + mainMenu.delegate = MenuTarget.shared + NSApp.mainMenu = mainMenu + } +} + +@objc class MenuTarget: NSObject { + static let shared = MenuTarget() + @objc func onMenuAction(_ sender: NSMenuItem) { + guard menuActionHandlerRegistered else { return } + gpui_menu_action(UInt64(sender.tag)) + } +} + +@objc extension MenuTarget: NSMenuItemValidation { + func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { + return gpui_validate_menu_action(UInt64(menuItem.tag)) + } +} + +@objc extension MenuTarget: NSMenuDelegate { + func menuWillOpen(_ menu: NSMenu) { + gpui_menu_will_open() + } +} + +@_silgen_name("gpui_validate_menu_action") +func gpui_validate_menu_action(_ tag: UInt64) -> Bool + +@_silgen_name("gpui_menu_will_open") +func gpui_menu_will_open() + +// MARK: - Panels (Open/Save) C ABI + +@_silgen_name("gpui_open_panel_result") +func gpui_open_panel_result(_ requestId: UInt64, _ json: UnsafePointer) + +@_silgen_name("gpui_save_panel_result") +func gpui_save_panel_result(_ requestId: UInt64, _ json: UnsafePointer) + +@_cdecl("zed_open_panel") +public func zed_open_panel(_ requestId: UInt64, _ json: UnsafePointer) { + struct OpenOpts: Codable { let directories: Bool; let files: Bool; let multiple: Bool; let prompt: String? } + let str = String(cString: json) + guard let data = str.data(using: .utf8), let opts = try? JSONDecoder().decode(OpenOpts.self, from: data) else { return } + let panel = NSOpenPanel() + panel.canChooseDirectories = opts.directories + panel.canChooseFiles = opts.files + panel.allowsMultipleSelection = opts.multiple + panel.canCreateDirectories = true + panel.resolvesAliases = false + if let p = opts.prompt { panel.prompt = p } + DispatchQueue.main.async { + panel.begin { resp in + var result: [String]? = nil + if resp == .OK { + result = panel.urls.filter { $0.isFileURL }.map { $0.path } + } + let payload: [String: Any?] = ["paths": result] + if let jsonData = try? JSONSerialization.data(withJSONObject: payload, options: []), let jsonStr = String(data: jsonData, encoding: .utf8) { + jsonStr.withCString { gpui_open_panel_result(requestId, $0) } + } else { + "{\"paths\":null}".withCString { gpui_open_panel_result(requestId, $0) } + } + } + } +} + +@_cdecl("zed_save_panel") +public func zed_save_panel(_ requestId: UInt64, _ json: UnsafePointer) { + struct SaveOpts: Codable { let directory: String; let suggested_name: String? } + let str = String(cString: json) + guard let data = str.data(using: .utf8), let opts = try? JSONDecoder().decode(SaveOpts.self, from: data) else { return } + let panel = NSSavePanel() + panel.directoryURL = URL(fileURLWithPath: opts.directory, isDirectory: true) + if let name = opts.suggested_name { panel.nameFieldStringValue = name } + DispatchQueue.main.async { + panel.begin { resp in + var path: String? = nil + if resp == .OK, let url = panel.url, url.isFileURL { path = url.path } + let payload: [String: Any?] = ["path": path] + if let jsonData = try? JSONSerialization.data(withJSONObject: payload, options: []), let jsonStr = String(data: jsonData, encoding: .utf8) { + jsonStr.withCString { gpui_save_panel_result(requestId, $0) } + } else { + "{\"path\":null}".withCString { gpui_save_panel_result(requestId, $0) } + } + } + } +} + +// MARK: - Pasteboard helpers (text) + +@_cdecl("zed_pasteboard_write_text") +public func zed_pasteboard_write_text(_ text: UnsafePointer) { + let str = String(cString: text) + NSPasteboard.general.clearContents() + NSPasteboard.general.setString(str, forType: NSPasteboard.PasteboardType.string) +} + +@_cdecl("zed_pasteboard_read_text") +public func zed_pasteboard_read_text() -> UnsafeMutablePointer? { + if let s = NSPasteboard.general.string(forType: NSPasteboard.PasteboardType.string) { + return strdup(s) + } + return nil +} + +// MARK: - Pasteboard helpers (images via UTI) + +@_cdecl("zed_pasteboard_write_image") +public func zed_pasteboard_write_image(_ bytes: UnsafePointer, _ len: Int, _ uti: UnsafePointer) { + let data = Data(bytes: bytes, count: len) + let type = NSPasteboard.PasteboardType(String(cString: uti)) + let pb = NSPasteboard.general + pb.clearContents() + pb.setData(data, forType: type) +} + +// MARK: - Status Item (NSStatusItem) + +@_silgen_name("gpui_status_item_clicked") +func gpui_status_item_clicked(_ id: UInt64) +@_silgen_name("gpui_status_item_menu_action") +func gpui_status_item_menu_action(_ id: UInt64, _ tag: UInt64) + +fileprivate class StatusItemTarget: NSObject { + let id: UInt64 + init(id: UInt64) { self.id = id } + @objc func onClick(_ sender: Any?) { gpui_status_item_clicked(id) } + @objc func onMenuAction(_ sender: NSMenuItem) { gpui_status_item_menu_action(id, UInt64(sender.tag)) } +} + +fileprivate var statusItems: [UInt64: NSStatusItem] = [:] +fileprivate var statusTargets: [UInt64: StatusItemTarget] = [:] +fileprivate var statusCounter: UInt64 = 1 + +@_cdecl("zed_status_item_create") +public func zed_status_item_create() -> UInt64 { + let id = statusCounter; statusCounter += 1 + let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) + let target = StatusItemTarget(id: id) + item.button?.target = target + item.button?.action = #selector(StatusItemTarget.onClick(_:)) + statusTargets[id] = target + statusItems[id] = item + return id +} + +@_cdecl("zed_status_item_set_title") +public func zed_status_item_set_title(_ id: UInt64, _ title: UnsafePointer) { + if let item = statusItems[id] { + item.button?.title = String(cString: title) + } +} + +@_cdecl("zed_status_item_set_image") +public func zed_status_item_set_image(_ id: UInt64, _ bytes: UnsafePointer, _ len: Int, _ uti: UnsafePointer, _ isTemplate: Bool) { + guard let item = statusItems[id] else { return } + let data = Data(bytes: bytes, count: len) + if let image = NSImage(data: data) { + image.isTemplate = isTemplate + item.button?.image = image + } +} + +@_cdecl("zed_status_item_remove") +public func zed_status_item_remove(_ id: UInt64) { + if let item = statusItems[id] { NSStatusBar.system.removeStatusItem(item) } + statusItems.removeValue(forKey: id) + statusTargets.removeValue(forKey: id) +} + +@_cdecl("zed_status_item_set_menu") +public func zed_status_item_set_menu(_ id: UInt64, _ json: UnsafePointer) { + guard let item = statusItems[id] else { return } + let str = String(cString: json) + struct Item: Codable { let kind: String; let title: String?; let tag: UInt64?; let items: [Item]? } + struct Spec: Codable { let items: [Item] } + guard let data = str.data(using: .utf8), let spec = try? JSONDecoder().decode(Spec.self, from: data) else { return } + func buildMenu(_ items: [Item], _ target: StatusItemTarget) -> NSMenu { + let menu = NSMenu() + for it in items { + switch it.kind { + case "separator": + menu.addItem(NSMenuItem.separator()) + case "action": + let mi = NSMenuItem(title: it.title ?? "", action: #selector(StatusItemTarget.onMenuAction(_:)), keyEquivalent: "") + mi.target = target + if let tag = it.tag { mi.tag = Int(tag) } + menu.addItem(mi) + case "submenu": + let mi = NSMenuItem(title: it.title ?? "", action: nil, keyEquivalent: "") + mi.submenu = buildMenu(it.items ?? [], target) + menu.addItem(mi) + default: + continue + } + } + return menu + } + let target = statusTargets[id] ?? StatusItemTarget(id: id) + statusTargets[id] = target + let menu = buildMenu(spec.items, target) + item.menu = menu +} + +@_cdecl("zed_pasteboard_read_image") +public func zed_pasteboard_read_image(_ uti: UnsafePointer, _ out_len: UnsafeMutablePointer) -> UnsafeMutablePointer? { + let type = NSPasteboard.PasteboardType(String(cString: uti)) + let pb = NSPasteboard.general + if let data = pb.data(forType: type) { + out_len.pointee = data.count + let ptr = malloc(data.count)!.assumingMemoryBound(to: UInt8.self) + data.copyBytes(to: ptr, count: data.count) + return ptr + } else { + out_len.pointee = 0 + return nil + } +} diff --git a/crates/repl/Cargo.toml b/crates/repl/Cargo.toml index 5821bc6297266c..344840c4b49dae 100644 --- a/crates/repl/Cargo.toml +++ b/crates/repl/Cargo.toml @@ -17,6 +17,11 @@ alacritty_terminal.workspace = true anyhow.workspace = true async-dispatcher.workspace = true async-tungstenite = { workspace = true, features = ["tokio", "tokio-rustls-manual-roots"] } +# Force-enable `tokio` feature on async-tungstenite v0.31 used by +# transitive dependency `jupyter-websocket-client` to avoid E0432 +# (unresolved import `async_tungstenite::tokio`). The alias ensures +# feature unification applies to that version across the graph. +async_tungstenite_031 = { package = "async-tungstenite", version = "0.31.0", default-features = false, features = ["tokio-runtime"] } base64.workspace = true client.workspace = true collections.workspace = true diff --git a/crates/repl/src/kernels/remote_kernels.rs b/crates/repl/src/kernels/remote_kernels.rs index 6bc8b0d1b1c8d1..0c353a5044146b 100644 --- a/crates/repl/src/kernels/remote_kernels.rs +++ b/crates/repl/src/kernels/remote_kernels.rs @@ -3,8 +3,8 @@ use gpui::{App, AppContext as _, Entity, Task, Window}; use http_client::{AsyncBody, HttpClient, Request}; use jupyter_protocol::{ExecutionState, JupyterKernelspec, JupyterMessage, KernelInfoReply}; -use async_tungstenite::tokio::connect_async; -use async_tungstenite::tungstenite::{client::IntoClientRequest, http::HeaderValue}; +use async_tungstenite_031::tokio::connect_async; +use async_tungstenite_031::tungstenite::{client::IntoClientRequest, http::HeaderValue}; use futures::StreamExt; use smol::io::AsyncReadExt as _; diff --git a/postgres_notes.txt b/postgres_notes.txt new file mode 100644 index 00000000000000..d8d4eb0f72ffba --- /dev/null +++ b/postgres_notes.txt @@ -0,0 +1,20 @@ +This formula has created a default database cluster with: + initdb --locale=C -E UTF-8 /usr/local/var/postgresql@15 + +postgresql@15 is keg-only, which means it was not symlinked into /usr/local, +because this is an alternate version of another formula. + +If you need to have postgresql@15 first in your PATH, run: + echo 'export PATH="/usr/local/opt/postgresql@15/bin:$PATH"' >> ~/.zshrc + +For compilers to find postgresql@15 you may need to set: + export LDFLAGS="-L/usr/local/opt/postgresql@15/lib" + export CPPFLAGS="-I/usr/local/opt/postgresql@15/include" + +For pkg-config to find postgresql@15 you may need to set: + export PKG_CONFIG_PATH="/usr/local/opt/postgresql@15/lib/pkgconfig" + +To start postgresql@15 now and restart at login: + brew services start postgresql@15 +Or, if you don't want/need a background service you can just run: + LC_ALL="C" /usr/local/opt/postgresql@15/bin/postgres -D /usr/local/var/postgresql@15 diff --git a/zed_build_issues.md b/zed_build_issues.md new file mode 100644 index 00000000000000..83c8d3dafa5f17 --- /dev/null +++ b/zed_build_issues.md @@ -0,0 +1,7668 @@ +# + +warning: `fs` (lib) generated 14 warnings +warning: `gpui` (lib) generated 1245 warnings +error: could not compile `jupyter-websocket-client` (lib) due to 2 errors +For more information about this error, try `rustc --explain E0432`. +warning: `client` (lib) generated 8 warnings + +# + +# + +error[E0432]: unresolved import `async_tungstenite::tokio` + --> /Users/takumi/.cargo/git/checkouts/runtimed-da41b1ee8fc7914c/7130c80/crates/jupyter-websocket-client/src/client.rs:3:5 + | +3 | tokio::connect_async, + | ^^^^^ could not find `tokio` in `async_tungstenite` + | +note: found an item that was configured out + --> /Users/takumi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/async-tungstenite-0.31.0/src/lib.rs:94:9 + | +94 | pub mod tokio; + | ^^^^^ +note: the item is gated behind the `tokio-runtime` feature + --> /Users/takumi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/async-tungstenite-0.31.0/src/lib.rs:93:7 + | +93 | #[cfg(feature = "tokio-runtime")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0432]: unresolved import `async_tungstenite::tokio` + --> /Users/takumi/.cargo/git/checkouts/runtimed-da41b1ee8fc7914c/7130c80/crates/jupyter-websocket-client/src/websocket.rs:2:25 + | +2 | use async_tungstenite::{tokio::ConnectStream, tungstenite::Message, WebSocketStream}; + | ^^^^^ could not find `tokio` in `async_tungstenite` + | +note: found an item that was configured out + --> /Users/takumi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/async-tungstenite-0.31.0/src/lib.rs:94:9 + | +94 | pub mod tokio; + | ^^^^^ +note: the item is gated behind the `tokio-runtime` feature + --> /Users/takumi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/async-tungstenite-0.31.0/src/lib.rs:93:7 + | +93 | #[cfg(feature = "tokio-runtime")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +# + +# + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac.rs:38:12 + | +38 | base::{id, nil}, + | ^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac.rs:38:16 + | +38 | base::{id, nil}, + | ^^^ + +warning: use of deprecated trait `cocoa::foundation::NSAutoreleasePool`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:39:18 + | +39 | foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::foundation::NSNotFound`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:39:37 + | +39 | foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, + | ^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:39:49 + | +39 | foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:39:57 + | +39 | foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, + | ^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:39:65 + | +39 | foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, + | ^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:39:75 + | +39 | foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac.rs:75:22 + | +75 | impl NSStringExt for id { + | ^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:91:19 + | +91 | pub location: NSUInteger, + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:92:17 + | +92 | pub length: NSUInteger, + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac.rs:138:38 + | +138 | unsafe fn ns_string(string: &str) -> id { + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:139:24 + | +139 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac.rs:139:30 + | +139 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } + | ^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:142:11 + | +142 | impl From for Size { + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:151:11 + | +151 | impl From for Size { + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:158:11 + | +158 | impl From for Size { + | ^^^^^^ + +warning: use of deprecated constant `cocoa::foundation::NSNotFound`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:98:23 + | +98 | location: NSNotFound as NSUInteger, + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:98:37 + | +98 | location: NSNotFound as NSUInteger, + | ^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::foundation::NSNotFound`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:104:26 + | +104 | self.location != NSNotFound as NSUInteger + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:104:40 + | +104 | self.location != NSNotFound as NSUInteger + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:121:38 + | +121 | location: range.start as NSUInteger, + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:122:36 + | +122 | length: range.len() as NSUInteger, + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:131:13 + | +131 | NSUInteger::encode().as_str(), + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:132:13 + | +132 | NSUInteger::encode().as_str() + | ^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:143:20 + | +143 | fn from(value: NSSize) -> Self { + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:152:19 + | +152 | fn from(rect: NSRect) -> Self { + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:153:13 + | +153 | let NSSize { width, height } = rect.size; + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:159:19 + | +159 | fn from(rect: NSRect) -> Self { + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:160:13 + | +160 | let NSSize { width, height } = rect.size; + | ^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSScreen`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/display.rs:4:13 + | +4 | appkit::NSScreen, + | ^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/display.rs:5:12 + | +5 | base::{id, nil}, + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/display.rs:5:16 + | +5 | base::{id, nil}, + | ^^^ + +warning: use of deprecated trait `cocoa::foundation::NSDictionary`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/display.rs:6:18 + | +6 | foundation::{NSDictionary, NSString}, + | ^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/display.rs:6:32 + | +6 | foundation::{NSDictionary, NSString}, + | ^^^^^^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSScreen::screens`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/display.rs:35:37 + | +35 | let screens = NSScreen::screens(nil); + | ^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/display.rs:35:45 + | +35 | let screens = NSScreen::screens(nil); + | ^^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/display.rs:36:54 + | +36 | let screen = cocoa::foundation::NSArray::objectAtIndex(screens, 0); + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSScreen::deviceDescription`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/display.rs:37:48 + | +37 | let device_description = NSScreen::deviceDescription(screen); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/display.rs:38:51 + | +38 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/display.rs:38:57 + | +38 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/display.rs:38:36 + | +38 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); + | ^^ + +warning: use of deprecated trait `cocoa::appkit::NSEvent`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:12:14 + | +12 | appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType}, + | ^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:12:23 + | +12 | appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType}, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventPhase`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:12:45 + | +12 | appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType}, + | ^^^^^^^^^^^^ + +warning: use of deprecated enum `cocoa::appkit::NSEventType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:12:59 + | +12 | appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType}, + | ^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/events.rs:13:17 + | +13 | base::{YES, id}, + | ^^ + +warning: use of deprecated constant `cocoa::appkit::NSUpArrowFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:34:17 + | +34 | "up" => NSUpArrowFunctionKey, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSDownArrowFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:35:19 + | +35 | "down" => NSDownArrowFunctionKey, + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSLeftArrowFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:36:19 + | +36 | "left" => NSLeftArrowFunctionKey, + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSRightArrowFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:37:20 + | +37 | "right" => NSRightArrowFunctionKey, + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSPageUpFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:38:21 + | +38 | "pageup" => NSPageUpFunctionKey, + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSPageDownFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:39:23 + | +39 | "pagedown" => NSPageDownFunctionKey, + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSHomeFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:40:19 + | +40 | "home" => NSHomeFunctionKey, + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSEndFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:41:18 + | +41 | "end" => NSEndFunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSDeleteFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:42:21 + | +42 | "delete" => NSDeleteFunctionKey, + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSHelpFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:43:21 + | +43 | "insert" => NSHelpFunctionKey, + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF1FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:44:17 + | +44 | "f1" => NSF1FunctionKey, + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF2FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:45:17 + | +45 | "f2" => NSF2FunctionKey, + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF3FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:46:17 + | +46 | "f3" => NSF3FunctionKey, + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF4FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:47:17 + | +47 | "f4" => NSF4FunctionKey, + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF5FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:48:17 + | +48 | "f5" => NSF5FunctionKey, + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF6FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:49:17 + | +49 | "f6" => NSF6FunctionKey, + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF7FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:50:17 + | +50 | "f7" => NSF7FunctionKey, + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF8FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:51:17 + | +51 | "f8" => NSF8FunctionKey, + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF9FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:52:17 + | +52 | "f9" => NSF9FunctionKey, + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF10FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:53:18 + | +53 | "f10" => NSF10FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF11FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:54:18 + | +54 | "f11" => NSF11FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF12FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:55:18 + | +55 | "f12" => NSF12FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF13FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:56:18 + | +56 | "f13" => NSF13FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF14FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:57:18 + | +57 | "f14" => NSF14FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF15FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:58:18 + | +58 | "f15" => NSF15FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF16FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:59:18 + | +59 | "f16" => NSF16FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF17FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:60:18 + | +60 | "f17" => NSF17FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF18FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:61:18 + | +61 | "f18" => NSF18FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF19FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:62:18 + | +62 | "f19" => NSF19FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF20FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:63:18 + | +63 | "f20" => NSF20FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF21FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:64:18 + | +64 | "f21" => NSF21FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF22FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:65:18 + | +65 | "f22" => NSF22FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF23FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:66:18 + | +66 | "f23" => NSF23FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF24FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:67:18 + | +67 | "f24" => NSF24FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF25FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:68:18 + | +68 | "f25" => NSF25FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF26FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:69:18 + | +69 | "f26" => NSF26FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF27FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:70:18 + | +70 | "f27" => NSF27FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF28FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:71:18 + | +71 | "f28" => NSF28FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF29FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:72:18 + | +72 | "f29" => NSF29FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF30FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:73:18 + | +73 | "f30" => NSF30FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF31FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:74:18 + | +74 | "f31" => NSF31FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF32FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:75:18 + | +75 | "f32" => NSF32FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF33FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:76:18 + | +76 | "f33" => NSF33FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF34FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:77:18 + | +77 | "f34" => NSF34FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF35FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:78:18 + | +78 | "f35" => NSF35FunctionKey, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated module `cocoa::appkit`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:29:16 + | +29 | use cocoa::appkit::*; + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/events.rs:84:40 + | +84 | unsafe fn read_modifiers(native_event: id) -> Modifiers { + | ^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:87:42 + | +87 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:88:38 + | +88 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:89:40 + | +89 | let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:90:42 + | +90 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:91:43 + | +91 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/events.rs:297:41 + | +297 | unsafe fn parse_keystroke(native_event: id) -> Keystroke { + | ^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:309:42 + | +309 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:310:38 + | +310 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:311:44 + | +311 | let mut shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:312:42 + | +312 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:313:43 + | +313 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask) + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSUpArrowFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:315:36 + | +315 | .is_none_or(|ch| !(NSUpArrowFunctionKey..=NSModeSwitchFunctionKey).contains(&ch)); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSModeSwitchFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:315:59 + | +315 | .is_none_or(|ch| !(NSUpArrowFunctionKey..=NSModeSwitchFunctionKey).contains(&ch)); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSUpArrowFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:334:18 + | +334 | Some(NSUpArrowFunctionKey) => "up".to_string(), + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSDownArrowFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:335:18 + | +335 | Some(NSDownArrowFunctionKey) => "down".to_string(), + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSLeftArrowFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:336:18 + | +336 | Some(NSLeftArrowFunctionKey) => "left".to_string(), + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSRightArrowFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:337:18 + | +337 | Some(NSRightArrowFunctionKey) => "right".to_string(), + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSPageUpFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:338:18 + | +338 | Some(NSPageUpFunctionKey) => "pageup".to_string(), + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSPageDownFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:339:18 + | +339 | Some(NSPageDownFunctionKey) => "pagedown".to_string(), + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSHomeFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:340:18 + | +340 | Some(NSHomeFunctionKey) => "home".to_string(), + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSEndFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:341:18 + | +341 | Some(NSEndFunctionKey) => "end".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSDeleteFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:342:18 + | +342 | Some(NSDeleteFunctionKey) => "delete".to_string(), + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSHelpFunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:344:18 + | +344 | Some(NSHelpFunctionKey) => "insert".to_string(), + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF1FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:345:18 + | +345 | Some(NSF1FunctionKey) => "f1".to_string(), + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF2FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:346:18 + | +346 | Some(NSF2FunctionKey) => "f2".to_string(), + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF3FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:347:18 + | +347 | Some(NSF3FunctionKey) => "f3".to_string(), + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF4FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:348:18 + | +348 | Some(NSF4FunctionKey) => "f4".to_string(), + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF5FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:349:18 + | +349 | Some(NSF5FunctionKey) => "f5".to_string(), + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF6FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:350:18 + | +350 | Some(NSF6FunctionKey) => "f6".to_string(), + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF7FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:351:18 + | +351 | Some(NSF7FunctionKey) => "f7".to_string(), + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF8FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:352:18 + | +352 | Some(NSF8FunctionKey) => "f8".to_string(), + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF9FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:353:18 + | +353 | Some(NSF9FunctionKey) => "f9".to_string(), + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF10FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:354:18 + | +354 | Some(NSF10FunctionKey) => "f10".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF11FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:355:18 + | +355 | Some(NSF11FunctionKey) => "f11".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF12FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:356:18 + | +356 | Some(NSF12FunctionKey) => "f12".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF13FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:357:18 + | +357 | Some(NSF13FunctionKey) => "f13".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF14FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:358:18 + | +358 | Some(NSF14FunctionKey) => "f14".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF15FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:359:18 + | +359 | Some(NSF15FunctionKey) => "f15".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF16FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:360:18 + | +360 | Some(NSF16FunctionKey) => "f16".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF17FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:361:18 + | +361 | Some(NSF17FunctionKey) => "f17".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF18FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:362:18 + | +362 | Some(NSF18FunctionKey) => "f18".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF19FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:363:18 + | +363 | Some(NSF19FunctionKey) => "f19".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF20FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:364:18 + | +364 | Some(NSF20FunctionKey) => "f20".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF21FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:365:18 + | +365 | Some(NSF21FunctionKey) => "f21".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF22FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:366:18 + | +366 | Some(NSF22FunctionKey) => "f22".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF23FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:367:18 + | +367 | Some(NSF23FunctionKey) => "f23".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF24FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:368:18 + | +368 | Some(NSF24FunctionKey) => "f24".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF25FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:369:18 + | +369 | Some(NSF25FunctionKey) => "f25".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF26FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:370:18 + | +370 | Some(NSF26FunctionKey) => "f26".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF27FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:371:18 + | +371 | Some(NSF27FunctionKey) => "f27".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF28FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:372:18 + | +372 | Some(NSF28FunctionKey) => "f28".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF29FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:373:18 + | +373 | Some(NSF29FunctionKey) => "f29".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF30FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:374:18 + | +374 | Some(NSF30FunctionKey) => "f30".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF31FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:375:18 + | +375 | Some(NSF31FunctionKey) => "f31".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF32FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:376:18 + | +376 | Some(NSF32FunctionKey) => "f32".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF33FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:377:18 + | +377 | Some(NSF33FunctionKey) => "f33".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF34FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:378:18 + | +378 | Some(NSF34FunctionKey) => "f34".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSF35FunctionKey`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:379:18 + | +379 | Some(NSF35FunctionKey) => "f35".to_string(), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated module `cocoa::appkit`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:299:20 + | +299 | use cocoa::appkit::*; + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/events.rs:105:23 + | +105 | native_event: id, + | ^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSFlagsChanged`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:121:30 + | +121 | NSEventType::NSFlagsChanged => { + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:127:43 + | +127 | ... .contains(NSEventModifierFlags::NSAlphaShiftKeyMask), + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSKeyDown`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:131:30 + | +131 | NSEventType::NSKeyDown => Some(Self::KeyDown(KeyDownEvent { + | ^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSKeyUp`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:135:30 + | +135 | NSEventType::NSKeyUp => Some(Self::KeyUp(KeyUpEvent { + | ^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSLeftMouseDown`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:138:30 + | +138 | NSEventType::NSLeftMouseDown + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSRightMouseDown`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:139:32 + | +139 | | NSEventType::NSRightMouseDown + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSOtherMouseDown`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:140:32 + | +140 | | NSEventType::NSOtherMouseDown => { + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSLeftMouseUp`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:164:30 + | +164 | NSEventType::NSLeftMouseUp + | ^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSRightMouseUp`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:165:32 + | +165 | | NSEventType::NSRightMouseUp + | ^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSOtherMouseUp`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:166:32 + | +166 | | NSEventType::NSOtherMouseUp => { + | ^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSEventTypeSwipe`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:190:30 + | +190 | NSEventType::NSEventTypeSwipe => { + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventPhase`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:192:25 + | +192 | NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() { + | ^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSScrollWheel`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:216:30 + | +216 | NSEventType::NSScrollWheel => window_height.map(|window_height| { + | ^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventPhase`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:218:25 + | +218 | NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { + | ^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventPhase`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:218:62 + | +218 | NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { + | ^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventPhase`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:221:25 + | +221 | NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, + | ^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSLeftMouseDragged`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:246:30 + | +246 | NSEventType::NSLeftMouseDragged + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSRightMouseDragged`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:247:32 + | +247 | | NSEventType::NSRightMouseDragged + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSOtherMouseDragged`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:248:32 + | +248 | | NSEventType::NSOtherMouseDragged => { + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSMouseMoved`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:270:30 + | +270 | NSEventType::NSMouseMoved => window_height.map(|window_height| { + | ^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSMouseExited`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:280:30 + | +280 | NSEventType::NSMouseExited => window_height.map(|window_height| { + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:9:17 + | +9 | base::{YES, id, nil}, + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:9:21 + | +9 | base::{YES, id, nil}, + | ^^^ + +warning: use of deprecated trait `cocoa::foundation::NSArray`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:10:18 + | +10 | foundation::{NSArray, NSString}, + | ^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:10:27 + | +10 | foundation::{NSArray, NSString}, + | ^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:35:17 + | +35 | sc_display: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:40:16 + | +40 | sc_stream: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:41:23 + | +41 | sc_stream_output: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:195:18 + | +195 | let screens: id = msg_send![class!(NSScreen), screens]; + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:198:48 + | +198 | let screen_number_key = unsafe { NSString::alloc(nil).init_str("NSScreenNumber") }; + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:198:54 + | +198 | let screen_number_key = unsafe { NSString::alloc(nil).init_str("NSScreenNumber") }; + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:200:21 + | +200 | let screen: id = msg_send![screens, objectAtIndex: i]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:201:26 + | +201 | let device_desc: id = msg_send![screen, deviceDescription]; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:202:27 + | +202 | if device_desc == nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:206:23 + | +206 | let nsnumber: id = msg_send![device_desc, objectForKey: screen_number_key]; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:207:24 + | +207 | if nsnumber == nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:213:19 + | +213 | let name: id = msg_send![screen, localizedName]; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:214:20 + | +214 | if name != nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:238:65 + | +238 | let block = ConcreteBlock::new(move |shareable_content: id, error: id| { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:238:76 + | +238 | let block = ConcreteBlock::new(move |shareable_content: id, error: id| { + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:243:38 + | +243 | let result = if error == nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:244:31 + | +244 | let displays: id = msg_send![shareable_content, displays]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:258:26 + | +258 | let msg: id = msg_send![error, localizedDescription]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:283:85 + | +283 | output_video_effect_did_start_for_stream as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:287:84 + | +287 | output_video_effect_did_stop_for_stream as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:291:71 + | +291 | stream_did_stop_with_error as extern "C" fn(&Object, Sel, id, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:291:75 + | +291 | stream_did_stop_with_error as extern "C" fn(&Object, Sel, id, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:299:48 + | +299 | as extern "C" fn(&Object, Sel, id, id, NSInteger), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:299:52 + | +299 | as extern "C" fn(&Object, Sel, id, id, NSInteger), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:307:89 + | +307 | extern "C" fn output_video_effect_did_start_for_stream(_this: &Object, _: Sel, _stream: id) {} + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:309:88 + | +309 | extern "C" fn output_video_effect_did_stop_for_stream(_this: &Object, _: Sel, _stream: id) {} + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:311:75 + | +311 | extern "C" fn stream_did_stop_with_error(_this: &Object, _: Sel, _stream: id, _error: id) {} + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:311:87 + | +311 | extern "C" fn stream_did_stop_with_error(_this: &Object, _: Sel, _stream: id, _error: id) {} + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:316:14 + | +316 | _stream: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:317:20 + | +317 | sample_buffer: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:86:25 + | +86 | let stream: id = msg_send![class!(SCStream), alloc]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:87:25 + | +87 | let filter: id = msg_send![class!(SCContentFilter), alloc]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:88:32 + | +88 | let configuration: id = msg_send![class!(SCStreamConfiguration), alloc]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:89:27 + | +89 | let delegate: id = msg_send![DELEGATE_CLASS, alloc]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:90:25 + | +90 | let output: id = msg_send![OUTPUT_CLASS, alloc]; + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSArray::array`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:92:45 + | +92 | let excluded_windows = NSArray::array(nil); + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:92:51 + | +92 | let excluded_windows = NSArray::array(nil); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:93:25 + | +93 | let filter: id = msg_send![filter, initWithDisplay:self.sc_display excludingWindows:excluded_windows]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:94:32 + | +94 | let configuration: id = msg_send![configuration, init]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:95:20 + | +95 | let _: id = msg_send![configuration, setScalesToFit: true]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:96:20 + | +96 | let _: id = msg_send![configuration, setPixelFormat: 0x42475241]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:99:27 + | +99 | let delegate: id = msg_send![delegate, init]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:100:25 + | +100 | let output: id = msg_send![output, init]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:108:20 + | +108 | let _: id = msg_send![configuration, setWidth: meta.resolution.width.0 as i64]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:109:20 + | +109 | let _: id = msg_send![configuration, setHeight: meta.resolution.height.0 as i64]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:110:25 + | +110 | let stream: id = msg_send![stream, initWithFilter:filter configuration:configuration delegate:delegate]; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:114:33 + | +114 | let mut error: id = nil; + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:114:28 + | +114 | let mut error: id = nil; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:115:142 + | +115 | ...utputTypeScreen sampleHandlerQueue:0 error:&mut error as *mut id]; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:116:25 + | +116 | if error != nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:117:30 + | +117 | let message: id = msg_send![error, localizedDescription]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:125:30 + | +125 | move |error: id| { + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:126:46 + | +126 | let result = if error == nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:134:38 + | +134 | let message: id = msg_send![error, localizedDescription]; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:166:33 + | +166 | let mut error: id = nil; + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:166:28 + | +166 | let mut error: id = nil; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:168:25 + | +168 | if error != nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:169:30 + | +169 | let message: id = msg_send![error, localizedDescription]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:173:59 + | +173 | let handler = ConcreteBlock::new(move |error: id| { + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:174:29 + | +174 | if error != nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:175:34 + | +175 | let message: id = msg_send![error, localizedDescription]; + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:11:18 + | +11 | foundation::{NSSize, NSUInteger}, + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:11:26 + | +11 | foundation::{NSSize, NSUInteger}, + | ^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::quartzcore::AutoresizingMask`: use the objc2-quartz-core crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:12:17 + | +12 | quartzcore::AutoresizingMask, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::quartzcore::AutoresizingMask`: use the objc2-quartz-core crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:152:38 + | +152 | setAutoresizingMask: AutoresizingMask::WIDTH_SIZABLE + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::quartzcore::AutoresizingMask`: use the objc2-quartz-core crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:153:23 + | +153 | | AutoresizingMask::HEIGHT_SIZABLE + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:299:20 + | +299 | let size = NSSize { + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:545:40 + | +545 | length: instance_offset as NSUInteger, + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:1:18 + | +1 | use cocoa::base::id; + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:2:24 + | +2 | use cocoa::foundation::NSRange; + | ^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:21:29 + | +21 | impl NSAttributedString for id { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:49:36 + | +49 | impl NSMutableAttributedString for id {} + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:10:33 + | +10 | unsafe fn alloc(_: Self) -> id { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:14:52 + | +14 | unsafe fn init_attributed_string(self, string: id) -> id; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:14:59 + | +14 | unsafe fn init_attributed_string(self, string: id) -> id; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:15:58 + | +15 | unsafe fn appendAttributedString_(self, attr_string: id); + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:16:62 + | +16 | unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; + | ^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:16:78 + | +16 | unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:16:85 + | +16 | unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:17:61 + | +17 | unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; + | ^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:17:77 + | +17 | unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:17:84 + | +17 | unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:18:31 + | +18 | unsafe fn string(self) -> id; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:44:33 + | +44 | unsafe fn alloc(_: Self) -> id { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:22:52 + | +22 | unsafe fn init_attributed_string(self, string: id) -> id { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:22:59 + | +22 | unsafe fn init_attributed_string(self, string: id) -> id { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:26:58 + | +26 | unsafe fn appendAttributedString_(self, attr_string: id) { + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:30:62 + | +30 | unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { + | ^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:30:78 + | +30 | unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:30:85 + | +30 | unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:34:61 + | +34 | unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { + | ^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:34:77 + | +34 | unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:34:84 + | +34 | unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/attributed_string.rs:38:31 + | +38 | unsafe fn string(self) -> id { + | ^^ + +warning: use of deprecated trait `cocoa::appkit::NSApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:19:9 + | +19 | NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, + | ^^^^^^^^^^^^^ + +warning: use of deprecated variant `cocoa::appkit::NSApplicationActivationPolicyRegular`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:19:55 + | +19 | NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSApplicationActivationPolicyRegular`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:19:55 + | +19 | NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:20:9 + | +20 | NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSMenu`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:20:31 + | +20 | NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, + | ^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSMenuItem`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:20:39 + | +20 | NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, + | ^^^^^^^^^^ + +warning: use of deprecated enum `cocoa::appkit::NSModalResponse`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:20:51 + | +20 | NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSOpenPanel`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:20:68 + | +20 | NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, + | ^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSPasteboard`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:20:81 + | +20 | NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, + | ^^^^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSPasteboardTypePNG`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:21:9 + | +21 | NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeRTFD, NSPasteboardTypeString, + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeRTF`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:21:30 + | +21 | NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeRTFD, NSPasteboardTypeString, + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeRTFD`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:21:51 + | +21 | NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeRTFD, NSPasteboardTypeString, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeString`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:21:73 + | +21 | NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeRTFD, NSPasteboardTypeString, + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeTIFF`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:22:9 + | +22 | NSPasteboardTypeTIFF, NSSavePanel, NSWindow, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSSavePanel`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:22:31 + | +22 | NSPasteboardTypeTIFF, NSSavePanel, NSWindow, + | ^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:22:44 + | +22 | NSPasteboardTypeTIFF, NSSavePanel, NSWindow, + | ^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:24:27 + | +24 | base::{BOOL, NO, YES, id, nil, selector}, + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:24:31 + | +24 | base::{BOOL, NO, YES, id, nil, selector}, + | ^^^ + +warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:24:36 + | +24 | base::{BOOL, NO, YES, id, nil, selector}, + | ^^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSArray`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:26:9 + | +26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, + | ^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSAutoreleasePool`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:26:18 + | +26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSBundle`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:26:37 + | +26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, + | ^^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSData`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:26:47 + | +26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:26:55 + | +26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, + | ^^^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSProcessInfo`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:26:66 + | +26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, + | ^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:26:81 + | +26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, + | ^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:26:90 + | +26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, + | ^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:27:9 + | +27 | NSUInteger, NSURL, + | ^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSURL`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:27:21 + | +27 | NSUInteger, NSURL, + | ^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:66:29 + | +66 | const NSUTF8StringEncoding: NSUInteger = 4; + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:87:73 + | +87 | did_finish_launching as extern "C" fn(&mut Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:91:73 + | +91 | should_handle_reopen as extern "C" fn(&mut Object, Sel, id, bool), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:95:67 + | +95 | will_terminate as extern "C" fn(&mut Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:99:69 + | +99 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:104:69 + | +104 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:108:69 + | +108 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:112:69 + | +112 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:116:69 + | +116 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:120:69 + | +120 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:124:69 + | +124 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:128:71 + | +128 | validate_menu_item as extern "C" fn(&mut Object, Sel, id) -> bool, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:132:67 + | +132 | menu_will_open as extern "C" fn(&mut Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:136:69 + | +136 | handle_dock_menu as extern "C" fn(&mut Object, Sel, id) -> id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:136:76 + | +136 | handle_dock_menu as extern "C" fn(&mut Object, Sel, id) -> id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:140:62 + | +140 | open_urls as extern "C" fn(&mut Object, Sel, id, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:140:66 + | +140 | open_urls as extern "C" fn(&mut Object, Sel, id, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:145:78 + | +145 | on_keyboard_layout_change as extern "C" fn(&mut Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:161:17 + | +161 | pasteboard: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:162:32 + | +162 | text_hash_pasteboard_type: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:163:31 + | +163 | metadata_pasteboard_type: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:173:23 + | +173 | dock_menu: Option, + | ^^ + +warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:515:42 + | +515 | let app = NSApplication::sharedApplication(nil); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:515:60 + | +515 | let app = NSApplication::sharedApplication(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:516:55 + | +516 | let _: () = msg_send![app, terminate: nil]; + | ^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1008:39 + | +1008 | const NSScrollerStyleOverlay: NSInteger = 1; + | ^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1318:36 + | +1318 | fn try_clipboard_image(pasteboard: id, format: ImageFormat) -> Option { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1322:20 + | +1322 | let types: id = pasteboard.types(); + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1325:24 + | +1325 | if data == nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1344:32 + | +1344 | unsafe fn path_from_objc(path: id) -> PathBuf { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1359:66 + | +1359 | extern "C" fn did_finish_launching(this: &mut Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1361:18 + | +1361 | let app: id = msg_send![APP_CLASS, sharedApplication]; + | ^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSApplicationActivationPolicyRegular`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1362:34 + | +1362 | app.setActivationPolicy_(NSApplicationActivationPolicyRegular); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1367:73 + | +1367 | let _: () = msg_send![notification_center, addObserver: this as id + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1370:21 + | +1370 | object: nil + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1381:66 + | +1381 | extern "C" fn should_handle_reopen(this: &mut Object, _: Sel, _: id, has_open_windows: bool) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1393:60 + | +1393 | extern "C" fn will_terminate(this: &mut Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1403:71 + | +1403 | extern "C" fn on_keyboard_layout_change(this: &mut Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1419:55 + | +1419 | extern "C" fn open_urls(this: &mut Object, _: Sel, _: id, urls: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1419:65 + | +1419 | extern "C" fn open_urls(this: &mut Object, _: Sel, _: id, urls: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1443:65 + | +1443 | extern "C" fn handle_menu_item(this: &mut Object, _: Sel, item: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1448:22 + | +1448 | let tag: NSInteger = msg_send![item, tag]; + | ^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1460:67 + | +1460 | extern "C" fn validate_menu_item(this: &mut Object, _: Sel, item: id) -> bool { + | ^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1466:22 + | +1466 | let tag: NSInteger = msg_send![item, tag]; + | ^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1483:60 + | +1483 | extern "C" fn menu_will_open(this: &mut Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1495:62 + | +1495 | extern "C" fn handle_dock_menu(this: &mut Object, _: Sel, _: id) -> id { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1495:69 + | +1495 | extern "C" fn handle_dock_menu(this: &mut Object, _: Sel, _: id) -> id { + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1502:13 + | +1502 | nil + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1507:38 + | +1507 | unsafe fn ns_string(string: &str) -> id { + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1508:24 + | +1508 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1508:30 + | +1508 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1511:31 + | +1511 | unsafe fn ns_url_to_path(url: id) -> Result { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1587:15 + | +1587 | struct UTType(id); + | ^^ + +warning: use of deprecated associated function `cocoa::appkit::NSPasteboard::generalPasteboard`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:203:48 + | +203 | pasteboard: unsafe { NSPasteboard::generalPasteboard(nil) }, + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:203:66 + | +203 | pasteboard: unsafe { NSPasteboard::generalPasteboard(nil) }, + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:221:74 + | +221 | unsafe fn read_from_pasteboard(&self, pasteboard: *mut Object, kind: id) -> Option<&[u8]> { + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:224:24 + | +224 | if data == nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:238:19 + | +238 | delegate: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:241:10 + | +241 | ) -> id { + | ^^ + +warning: use of deprecated associated function `cocoa::appkit::NSMenu::new`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:243:44 + | +243 | let application_menu = NSMenu::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:243:48 + | +243 | let application_menu = NSMenu::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSMenu::new`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:247:36 + | +247 | let menu = NSMenu::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:247:40 + | +247 | let menu = NSMenu::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::new`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:261:45 + | +261 | let menu_item = NSMenuItem::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:261:49 + | +261 | let menu_item = NSMenuItem::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:267:30 + | +267 | let app: id = msg_send![APP_CLASS, sharedApplication]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:279:19 + | +279 | delegate: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:282:10 + | +282 | ) -> id { + | ^^ + +warning: use of deprecated associated function `cocoa::appkit::NSMenu::new`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:284:37 + | +284 | let dock_menu = NSMenu::new(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:284:41 + | +284 | let dock_menu = NSMenu::new(nil); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:301:19 + | +301 | delegate: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:304:10 + | +304 | ) -> id { + | ^^ + +warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::separatorItem`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:309:52 + | +309 | MenuItem::Separator => NSMenuItem::separatorItem(nil), + | ^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:309:66 + | +309 | MenuItem::Separator => NSMenuItem::separatorItem(nil), + | ^^^ + +warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:339:55 + | +339 | Some(crate::OsAction::Cut) => selector("cut:"), + | ^^^^^^^^ + +warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:340:56 + | +340 | Some(crate::OsAction::Copy) => selector("copy:"), + | ^^^^^^^^ + +warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:341:57 + | +341 | Some(crate::OsAction::Paste) => selector("paste:"), + | ^^^^^^^^ + +warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:342:61 + | +342 | Some(crate::OsAction::SelectAll) => selector("selectAll:"), + | ^^^^^^^^ + +warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:345:56 + | +345 | Some(crate::OsAction::Undo) => selector("handleGPUIMenuItem:"), + | ^^^^^^^^ + +warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:346:56 + | +346 | Some(crate::OsAction::Redo) => selector("handleGPUIMenuItem:"), + | ^^^^^^^^ + +warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:347:33 + | +347 | None => selector("handleGPUIMenuItem:"), + | ^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:354:44 + | +354 | ... let mut mask = NSEventModifierFlags::empty(); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:358:37 + | +358 | ... NSEventModifierFlags::NSCommandKeyMask, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:362:37 + | +362 | ... NSEventModifierFlags::NSControlKeyMask, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:366:37 + | +366 | ... NSEventModifierFlags::NSAlternateKeyMask, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:370:37 + | +370 | ... NSEventModifierFlags::NSShiftKeyMask, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::alloc`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:378:48 + | +378 | ... item = NSMenuItem::alloc(nil) + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:378:54 + | +378 | ... item = NSMenuItem::alloc(nil) + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::alloc`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:390:48 + | +390 | ... item = NSMenuItem::alloc(nil) + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:390:54 + | +390 | ... item = NSMenuItem::alloc(nil) + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::alloc`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:399:44 + | +399 | item = NSMenuItem::alloc(nil) + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:399:50 + | +399 | item = NSMenuItem::alloc(nil) + | ^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:408:48 + | +408 | let tag = actions.len() as NSInteger; + | ^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::new`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:414:44 + | +414 | let item = NSMenuItem::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:414:48 + | +414 | let item = NSMenuItem::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSMenu::new`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:415:43 + | +415 | let submenu = NSMenu::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:415:47 + | +415 | let submenu = NSMenu::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::new`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:425:44 + | +425 | let item = NSMenuItem::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:425:48 + | +425 | let item = NSMenuItem::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSMenu::new`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:426:43 + | +426 | let submenu = NSMenu::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:426:47 + | +426 | let submenu = NSMenu::new(nil).autorelease(); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:433:38 + | +433 | ... let app: id = msg_send![APP_CLASS, sharedApplication]; + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSProcessInfo::processInfo`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:446:47 + | +446 | let process_info = NSProcessInfo::processInfo(nil); + | ^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:446:59 + | +446 | let process_info = NSProcessInfo::processInfo(nil); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:482:22 + | +482 | let app: id = msg_send![APP_CLASS, sharedApplication]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:483:31 + | +483 | let app_delegate: id = msg_send![APP_DELEGATE_CLASS, new]; + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSAutoreleasePool::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:490:43 + | +490 | let pool = NSAutoreleasePool::new(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:490:47 + | +490 | let pool = NSAutoreleasePool::new(nil); + | ^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::delegate`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:495:25 + | +495 | (*NSWindow::delegate(app)).set_ivar(MAC_PLATFORM_IVAR, null_mut::()); + | ^^^^^^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:558:38 + | +558 | let app = NSApplication::sharedApplication(nil); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:558:56 + | +558 | let app = NSApplication::sharedApplication(nil); + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:565:38 + | +565 | let app = NSApplication::sharedApplication(nil); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:565:56 + | +565 | let app = NSApplication::sharedApplication(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:566:46 + | +566 | let _: () = msg_send![app, hide: nil]; + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:572:38 + | +572 | let app = NSApplication::sharedApplication(nil); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:572:56 + | +572 | let app = NSApplication::sharedApplication(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:573:63 + | +573 | let _: () = msg_send![app, hideOtherApplications: nil]; + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:579:38 + | +579 | let app = NSApplication::sharedApplication(nil); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:579:56 + | +579 | let app = NSApplication::sharedApplication(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:580:63 + | +580 | let _: () = msg_send![app, unhideAllApplications: nil]; + | ^^^ + +warning: use of deprecated struct `cocoa::foundation::NSOperatingSystemVersion`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:596:46 + | +596 | let min_version = cocoa::foundation::NSOperatingSystemVersion::new(12, 3, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:633:38 + | +633 | let app = NSApplication::sharedApplication(nil); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:633:56 + | +633 | let app = NSApplication::sharedApplication(nil); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:634:29 + | +634 | let appearance: id = msg_send![app, effectiveAppearance]; + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSURL::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:641:30 + | +641 | let url = NSURL::alloc(nil) + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:641:36 + | +641 | let url = NSURL::alloc(nil) + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:644:28 + | +644 | let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:660:25 + | +660 | let bundle: id = msg_send![class!(NSBundle), mainBundle]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:661:28 + | +661 | let bundle_id: id = msg_send![bundle, bundleIdentifier]; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:662:29 + | +662 | if bundle_id == nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:669:28 + | +669 | let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:670:25 + | +670 | let scheme: id = ns_string(scheme); + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:671:22 + | +671 | let app: id = msg_send![workspace, URLForApplicationWithBundleIdentifier: bundle_id]; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:672:23 + | +672 | if app == nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:678:57 + | +678 | let block = ConcreteBlock::new(move |error: id| { + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:679:42 + | +679 | let result = if error == nil { + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:682:30 + | +682 | let msg: id = msg_send![error, localizedDescription]; + | ^^ + +warning: use of deprecated associated function `cocoa::appkit::NSOpenPanel::openPanel`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:710:46 + | +710 | let panel = NSOpenPanel::openPanel(nil); + | ^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:710:56 + | +710 | let panel = NSOpenPanel::openPanel(nil); + | ^^^ + +warning: use of deprecated enum `cocoa::appkit::NSModalResponse`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:718:68 + | +718 | let block = ConcreteBlock::new(move |response: NSModalResponse| { + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSModalResponse::NSModalResponseOk`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:719:70 + | +719 | let result = if response == NSModalResponse::NSModalResponseOk { + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSSavePanel::savePanel`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:763:46 + | +763 | let panel = NSSavePanel::savePanel(nil); + | ^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:763:56 + | +763 | let panel = NSSavePanel::savePanel(nil); + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSURL::fileURLWithPath_isDirectory_`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:765:38 + | +765 | let url = NSURL::fileURLWithPath_isDirectory_(nil, path, true.to_objc()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:765:67 + | +765 | let url = NSURL::fileURLWithPath_isDirectory_(nil, path, true.to_objc()); + | ^^^ + +warning: use of deprecated enum `cocoa::appkit::NSModalResponse`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:774:68 + | +774 | let block = ConcreteBlock::new(move |response: NSModalResponse| { + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSModalResponse::NSModalResponseOk`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:776:57 + | +776 | if response == NSModalResponse::NSModalResponseOk { + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:837:36 + | +837 | let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSBundle::mainBundle`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:897:40 + | +897 | let bundle: id = NSBundle::mainBundle(); + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:897:25 + | +897 | let bundle: id = NSBundle::mainBundle(); + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:905:22 + | +905 | let app: id = msg_send![APP_CLASS, sharedApplication]; + | ^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::delegate`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:908:63 + | +908 | let menu = self.create_menu_bar(&menus, NSWindow::delegate(app), actions, keymap); + | ^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:921:22 + | +921 | let app: id = msg_send![APP_CLASS, sharedApplication]; + | ^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::delegate`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:924:61 + | +924 | let new = self.create_dock_menu(menu, NSWindow::delegate(app), actions, keymap); + | ^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:934:42 + | +934 | let document_controller: id = + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSURL::fileURLWithPath_`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:936:38 + | +936 | let url: id = NSURL::fileURLWithPath_(nil, ns_string(path_str)); + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:936:55 + | +936 | let url: id = NSURL::fileURLWithPath_(nil, ns_string(path_str)); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:936:26 + | +936 | let url: id = NSURL::fileURLWithPath_(nil, ns_string(path_str)); + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSBundle::mainBundle`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:944:40 + | +944 | let bundle: id = NSBundle::mainBundle(); + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:944:25 + | +944 | let bundle: id = NSBundle::mainBundle(); + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:947:22 + | +947 | let url: id = msg_send![bundle, URLForAuxiliaryExecutable: name]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:962:29 + | +962 | let new_cursor: id = match style { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:999:29 + | +999 | let old_cursor: id = msg_send![class!(NSCursor), currentCursor]; + | ^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1011:24 + | +1011 | let style: NSInteger = msg_send![class!(NSScroller), preferredScrollerStyle]; + | ^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1040:68 + | +1040 | let mut buf = NSMutableAttributedString::alloc(nil) + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1042:59 + | +1042 | .init_attributed_string(NSString::alloc(nil).init_str("")); + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1042:65 + | +1042 | .init_attributed_string(NSString::alloc(nil).init_str("")); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1047:71 + | +1047 | ... let to_append = NSAttributedString::alloc(nil) + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1048:67 + | +1048 | ... .init_attributed_string(NSString::alloc(nil).init_str(&text)); + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1048:73 + | +1048 | ... .init_attributed_string(NSString::alloc(nil).init_str(&text)); + | ^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1063:25 + | +1063 | NSRange::new(0, msg_send![attributed_string, length]), + | ^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1064:25 + | +1064 | nil, + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1066:37 + | +1066 | if rtfd_data != nil { + | ^^^ + +warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeRTFD`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1069:57 + | +1069 | ... .setData_forType(rtfd_data, NSPasteboardTypeRTFD); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1073:25 + | +1073 | NSRange::new(0, attributed_string.length()), + | ^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1074:25 + | +1074 | nil, + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1076:36 + | +1076 | if rtf_data != nil { + | ^^^ + +warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeRTF`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1079:56 + | +1079 | ... .setData_forType(rtf_data, NSPasteboardTypeRTF); + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeString`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1086:52 + | +1086 | .setString_forType(plain_text, NSPasteboardTypeString); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1097:24 + | +1097 | let types: id = pasteboard.types(); + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1098:30 + | +1098 | let string_type: id = ns_string("public.utf8-plain-text"); + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1102:28 + | +1102 | if data == nil { + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSData::dataWithBytes_length_`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1268:38 + | +1268 | let text_bytes = NSData::dataWithBytes_length_( + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1269:17 + | +1269 | nil, + | ^^^ + +warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeString`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1275:46 + | +1275 | .setData_forType(text_bytes, NSPasteboardTypeString); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSData::dataWithBytes_length_`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1279:42 + | +1279 | let hash_bytes = NSData::dataWithBytes_length_( + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1280:21 + | +1280 | nil, + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSData::dataWithBytes_length_`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1288:46 + | +1288 | let metadata_bytes = NSData::dataWithBytes_length_( + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1289:21 + | +1289 | nil, + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSData::dataWithBytes_length_`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1305:33 + | +1305 | let bytes = NSData::dataWithBytes_length_( + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/platform.rs:1306:17 + | +1306 | nil, + | ^^^ + +warning: use of deprecated static `cocoa::appkit::NSPasteboardTypePNG`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1592:23 + | +1592 | Self(unsafe { NSPasteboardTypePNG }) // This is a rare case where there's a built-in NSPasteboardType + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeTIFF`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1622:23 + | +1622 | Self(unsafe { NSPasteboardTypeTIFF }) // This is a rare case where there's a built-in NSPasteboardType + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSAppKitVersionNumber`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:15:9 + | +15 | NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered, + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSAppKitVersionNumber12_0`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:15:32 + | +15 | NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:15:59 + | +15 | NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered, + | ^^^^^^^^^^^^^ + +warning: use of deprecated variant `cocoa::appkit::NSBackingStoreBuffered`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:15:74 + | +15 | NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered, + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSBackingStoreBuffered`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:15:74 + | +15 | NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered, + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSColor`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:16:9 + | +16 | NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, + | ^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSEvent`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:16:18 + | +16 | NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, + | ^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:16:27 + | +16 | NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSFilenamesPboardType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:16:49 + | +16 | NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSPasteboard`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:16:72 + | +16 | NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, + | ^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSScreen`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:16:86 + | +16 | NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, + | ^^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSView`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:17:9 + | +17 | NSView, NSViewHeightSizable, NSViewWidthSizable, NSVisualEffectMaterial, + | ^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSViewHeightSizable`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:17:17 + | +17 | NSView, NSViewHeightSizable, NSViewWidthSizable, NSVisualEffectMaterial, + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSViewWidthSizable`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:17:38 + | +17 | NSView, NSViewHeightSizable, NSViewWidthSizable, NSVisualEffectMaterial, + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated enum `cocoa::appkit::NSVisualEffectMaterial`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:17:58 + | +17 | NSView, NSViewHeightSizable, NSViewWidthSizable, NSVisualEffectMaterial, + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated enum `cocoa::appkit::NSVisualEffectState`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:18:9 + | +18 | NSVisualEffectState, NSVisualEffectView, NSWindow, NSWindowButton, + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSVisualEffectView`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:18:30 + | +18 | NSVisualEffectState, NSVisualEffectView, NSWindow, NSWindowButton, + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::appkit::NSWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:18:50 + | +18 | NSVisualEffectState, NSVisualEffectView, NSWindow, NSWindowButton, + | ^^^^^^^^ + +warning: use of deprecated enum `cocoa::appkit::NSWindowButton`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:18:60 + | +18 | NSVisualEffectState, NSVisualEffectView, NSWindow, NSWindowButton, + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowCollectionBehavior`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:19:9 + | +19 | NSWindowCollectionBehavior, NSWindowOcclusionState, NSWindowOrderingMode, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowOcclusionState`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:19:37 + | +19 | NSWindowCollectionBehavior, NSWindowOcclusionState, NSWindowOrderingMode, + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowOrderingMode`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:19:61 + | +19 | NSWindowCollectionBehavior, NSWindowOcclusionState, NSWindowOrderingMode, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:20:9 + | +20 | NSWindowStyleMask, NSWindowTitleVisibility, + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated enum `cocoa::appkit::NSWindowTitleVisibility`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:20:28 + | +20 | NSWindowStyleMask, NSWindowTitleVisibility, + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:22:12 + | +22 | base::{id, nil}, + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:22:16 + | +22 | base::{id, nil}, + | ^^^ + +warning: use of deprecated trait `cocoa::foundation::NSArray`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:24:9 + | +24 | NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, + | ^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSAutoreleasePool`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:24:18 + | +24 | NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSDictionary`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:24:37 + | +24 | NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, + | ^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSFastEnumeration`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:24:51 + | +24 | NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:24:70 + | +24 | NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, + | ^^^^^^^^^ + +warning: use of deprecated constant `cocoa::foundation::NSNotFound`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:24:81 + | +24 | NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, + | ^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSOperatingSystemVersion`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:25:9 + | +25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:25:35 + | +25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, + | ^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSProcessInfo`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:25:44 + | +25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, + | ^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:25:59 + | +25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:25:67 + | +25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, + | ^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:25:75 + | +25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, + | ^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:25:85 + | +25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, + | ^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSUserDefaults`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:26:9 + | +26 | NSUserDefaults, + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:64:44 + | +64 | const NSWindowStyleMaskNonactivatingPanel: NSWindowStyleMask = + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:65:5 + | +65 | NSWindowStyleMask::from_bits_retain(1 << 7); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:67:28 + | +67 | const NSNormalWindowLevel: NSInteger = 0; + | ^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:69:27 + | +69 | const NSPopUpWindowLevel: NSInteger = 101; + | ^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:71:40 + | +71 | const NSTrackingMouseEnteredAndExited: NSUInteger = 0x01; + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:73:29 + | +73 | const NSTrackingMouseMoved: NSUInteger = 0x02; + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:75:31 + | +75 | const NSTrackingActiveAlways: NSUInteger = 0x80; + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:77:32 + | +77 | const NSTrackingInVisibleRect: NSUInteger = 0x200; + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:79:47 + | +79 | const NSWindowAnimationBehaviorUtilityWindow: NSInteger = 4; + | ^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:81:50 + | +81 | const NSViewLayerContentsRedrawDuringViewResize: NSInteger = 2; + | ^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:83:24 + | +83 | type NSDragOperation = NSUInteger; + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:119:74 + | +119 | handle_key_equivalent as extern "C" fn(&Object, Sel, id) -> BOOL, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:123:68 + | +123 | handle_key_down as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:127:66 + | +127 | handle_key_up as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:131:70 + | +131 | handle_view_event as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:135:70 + | +135 | handle_view_event as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:139:70 + | +139 | handle_view_event as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:143:70 + | +143 | handle_view_event as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:147:70 + | +147 | handle_view_event as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:151:70 + | +151 | handle_view_event as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:155:70 + | +155 | handle_view_event as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:159:70 + | +159 | handle_view_event as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:163:70 + | +163 | handle_view_event as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:167:70 + | +167 | handle_view_event as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:171:70 + | +171 | handle_view_event as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:175:70 + | +175 | handle_view_event as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:180:74 + | +180 | make_backing_layer as extern "C" fn(&Object, Sel) -> id, + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:190:67 + | +190 | set_frame_size as extern "C" fn(&Object, Sel, NSSize), + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:194:66 + | +194 | display_layer as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:200:88 + | +200 | valid_attributes_for_marked_text as extern "C" fn(&Object, Sel) -> id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:217:65 + | +217 | as extern "C" fn(&Object, Sel, NSRange, id) -> NSRect, + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:217:72 + | +217 | as extern "C" fn(&Object, Sel, NSRange, id) -> NSRect, + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:221:64 + | +221 | insert_text as extern "C" fn(&Object, Sel, id, NSRange), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:225:68 + | +225 | set_marked_text as extern "C" fn(&Object, Sel, id, NSRange, NSRange), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:231:81 + | +231 | as extern "C" fn(&Object, Sel, NSRange, *mut c_void) -> id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:246:72 + | +246 | accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL, + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:251:78 + | +251 | character_index_for_point as extern "C" fn(&Object, Sel, NSPoint) -> u64, + | ^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:261:81 + | +261 | blurred_view_init_with_frame as extern "C" fn(&Object, Sel, NSRect) -> id, + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:261:92 + | +261 | blurred_view_init_with_frame as extern "C" fn(&Object, Sel, NSRect) -> id, + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:273:48 + | +273 | pub(crate) fn convert_mouse_position(position: NSPoint, window_height: Pixels) -> Point { + | ^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:297:62 + | +297 | window_did_resize as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:301:78 + | +301 | window_did_change_occlusion_state as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:305:73 + | +305 | window_will_enter_fullscreen as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:309:72 + | +309 | window_will_exit_fullscreen as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:313:60 + | +313 | window_did_move as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:317:69 + | +317 | window_did_change_screen as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:321:73 + | +321 | window_did_change_key_status as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:325:73 + | +325 | window_did_change_key_status as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:329:64 + | +329 | window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:336:61 + | +336 | dragging_entered as extern "C" fn(&Object, Sel, id) -> NSDragOperation, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:340:61 + | +340 | dragging_updated as extern "C" fn(&Object, Sel, id) -> NSDragOperation, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:344:60 + | +344 | dragging_exited as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:348:67 + | +348 | perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:352:68 + | +352 | conclude_drag_operation as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:357:83 + | +357 | add_titlebar_accessory_view_controller as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:362:67 + | +362 | move_tab_to_new_window as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:367:62 + | +367 | merge_all_windows as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:372:60 + | +372 | select_next_tab as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:377:64 + | +377 | select_previous_tab as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:382:59 + | +382 | toggle_tab_bar as extern "C" fn(&Object, Sel, id), + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:392:20 + | +392 | native_window: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:394:26 + | +394 | blurred_view: Option, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:984:44 + | +984 | let native_window = context as id; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:985:66 + | +985 | let _: () = msg_send![native_window, mergeAllWindows:nil]; + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1000:44 + | +1000 | let native_window = context as id; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1001:69 + | +1001 | let _: () = msg_send![native_window, moveTabToNewWindow:nil]; + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1002:72 + | +1002 | let _: () = msg_send![native_window, makeKeyAndOrderFront: nil]; + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1544:36 + | +1544 | fn get_scale_factor(native_window: id) -> f32 { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1546:21 + | +1546 | let screen: id = msg_send![native_window, screen]; + | ^^ + +warning: use of deprecated method `cocoa::appkit::NSScreen::backingScaleFactor`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1550:19 + | +1550 | NSScreen::backingScaleFactor(screen) as f32 + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1597:74 + | +1597 | extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: id) -> BOOL { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1601:68 + | +1601 | extern "C" fn handle_key_down(this: &Object, _: Sel, native_event: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1605:66 + | +1605 | extern "C" fn handle_key_up(this: &Object, _: Sel, native_event: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1634:61 + | +1634 | extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: bool) -> BOOL { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1696:40 + | +1696 | let input_context: id = msg_send![this, inputContext]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1737:36 + | +1737 | let input_context: id = msg_send![this, inputContext]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1751:70 + | +1751 | extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1821:40 + | +1821 | let input_context: id = msg_send![this, inputContext]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1881:75 + | +1881 | extern "C" fn window_did_change_occlusion_state(this: &Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowOcclusionState`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1888:23 + | +1888 | .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1898:59 + | +1898 | extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1903:70 + | +1903 | extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSOperatingSystemVersion`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1908:23 + | +1908 | let min_version = NSOperatingSystemVersion::new(15, 3, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1917:69 + | +1917 | extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSOperatingSystemVersion`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1921:23 + | +1921 | let min_version = NSOperatingSystemVersion::new(15, 3, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSOperatingSystemVersion`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1930:50 + | +1930 | pub(crate) fn is_macos_version_at_least(version: NSOperatingSystemVersion) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSProcessInfo::processInfo`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1931:29 + | +1931 | unsafe { NSProcessInfo::processInfo(nil).isOperatingSystemAtLeastVersion(version) } + | ^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1931:41 + | +1931 | unsafe { NSProcessInfo::processInfo(nil).isOperatingSystemAtLeastVersion(version) } + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1934:57 + | +1934 | extern "C" fn window_did_move(this: &Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1944:66 + | +1944 | extern "C" fn window_did_change_screen(this: &Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1950:77 + | +1950 | extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2010:61 + | +2010 | extern "C" fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2039:60 + | +2039 | extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2042:42 + | +2042 | window_state.renderer.layer_ptr() as id + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2070:59 + | +2070 | extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2076:24 + | +2076 | let old_frame: NSRect = msg_send![this, frame]; + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2101:55 + | +2101 | extern "C" fn display_layer(this: &Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2120:24 + | +2120 | let view = view as id; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2131:71 + | +2131 | extern "C" fn valid_attributes_for_marked_text(_: &Object, _: Sel) -> id { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2162:8 + | +2162 | _: id, + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2163:6 + | +2163 | ) -> NSRect { + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2170:9 + | +2170 | NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2170:21 + | +2170 | NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), + | ^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2170:43 + | +2170 | NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2172:13 + | +2172 | NSRect::new( + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2173:17 + | +2173 | NSPoint::new( + | ^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2179:17 + | +2179 | NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2185:32 + | +2185 | fn get_frame(this: &Object) -> NSRect { + | ^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::frame`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:2189:35 + | +2189 | let mut frame = NSWindow::frame(lock.native_window); + | ^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:2191:25 + | +2191 | let style_mask: NSWindowStyleMask = msg_send![lock.native_window, styleMask]; + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:2192:33 + | +2192 | if !style_mask.contains(NSWindowStyleMask::NSFullSizeContentViewWindowMask) { + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2199:56 + | +2199 | extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NSRange) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2203:19 + | +2203 | let text: id = if is_attributed_string == YES { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2220:11 + | +2220 | text: id, + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2227:19 + | +2227 | let text: id = if is_attributed_string == YES { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2249:6 + | +2249 | ) -> id { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2264:25 + | +2264 | let string: id = msg_send![class!(NSAttributedString), alloc]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2265:25 + | +2265 | let string: id = msg_send![string, initWithString: ns_string(&selected_text)]; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2270:16 + | +2270 | .unwrap_or(nil) + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2305:61 + | +2305 | extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: id) -> BOOL { + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2312:74 + | +2312 | extern "C" fn character_index_for_point(this: &Object, _: Sel, position: NSPoint) -> u64 { + | ^^^^^^^ + +warning: use of deprecated constant `cocoa::foundation::NSNotFound`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2319:16 + | +2319 | .unwrap_or(NSNotFound as u64) + | ^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2322:56 + | +2322 | fn screen_point_to_gpui_point(this: &Object, position: NSPoint) -> Point { + | ^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2330:70 + | +2330 | extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: id) -> NSDragOperation { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2344:70 + | +2344 | extern "C" fn dragging_updated(this: &Object, _: Sel, dragging_info: id) -> NSDragOperation { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2357:57 + | +2357 | extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2366:76 + | +2366 | extern "C" fn perform_drag_operation(this: &Object, _: Sel, dragging_info: id) -> BOOL { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2378:21 + | +2378 | let pasteboard: id = unsafe { msg_send![dragging_info, draggingPasteboard] }; + | ^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::propertyListForType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:2379:44 + | +2379 | let filenames = unsafe { NSPasteboard::propertyListForType(pasteboard, NSFilenamesPboardType) }; + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSFilenamesPboardType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:2379:76 + | +2379 | let filenames = unsafe { NSPasteboard::propertyListForType(pasteboard, NSFilenamesPboardType) }; + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2380:21 + | +2380 | if filenames == nil { + | ^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2385:31 + | +2385 | let f = NSString::UTF8String(file); + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2393:65 + | +2393 | extern "C" fn conclude_drag_operation(this: &Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2434:77 + | +2434 | fn drag_event_position(window_state: &Mutex, dragging_info: id) -> Point { + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2435:24 + | +2435 | let drag_location: NSPoint = unsafe { msg_send![dragging_info, draggingLocation] }; + | ^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2455:41 + | +2455 | unsafe fn display_id_for_screen(screen: id) -> CGDirectDisplayID { + | ^^ + +warning: use of deprecated method `cocoa::appkit::NSScreen::deviceDescription`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:2457:44 + | +2457 | let device_description = NSScreen::deviceDescription(screen); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2458:47 + | +2458 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2458:53 + | +2458 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2458:32 + | +2458 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); + | ^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2460:28 + | +2460 | let screen_number: NSUInteger = msg_send![screen_number, unsignedIntegerValue]; + | ^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2465:74 + | +2465 | extern "C" fn blurred_view_init_with_frame(this: &Object, _: Sel, frame: NSRect) -> id { + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2465:85 + | +2465 | extern "C" fn blurred_view_init_with_frame(this: &Object, _: Sel, frame: NSRect) -> id { + | ^^ + +warning: use of deprecated method `cocoa::appkit::NSVisualEffectView::setMaterial_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:2470:29 + | +2470 | NSVisualEffectView::setMaterial_(view, NSVisualEffectMaterial::Selection); + | ^^^^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSVisualEffectMaterial::Selection`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:2470:72 + | +2470 | NSVisualEffectView::setMaterial_(view, NSVisualEffectMaterial::Selection); + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSVisualEffectView::setState_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:2471:29 + | +2471 | NSVisualEffectView::setState_(view, NSVisualEffectState::Active); + | ^^^^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSVisualEffectState::Active`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:2471:66 + | +2471 | NSVisualEffectView::setState_(view, NSVisualEffectState::Active); + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2479:20 + | +2479 | let layer: id = msg_send![this, layer]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2486:42 + | +2486 | unsafe fn remove_layer_background(layer: id) { + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2488:57 + | +2488 | let _: () = msg_send![layer, setBackgroundColor:nil]; + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2490:25 + | +2490 | let class_name: id = msg_send![layer, className]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2497:22 + | +2497 | let filters: id = msg_send![layer, filters]; + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2504:45 + | +2504 | let test_string: id = NSString::alloc(nil).init_str("Saturat").autorelease(); + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2504:51 + | +2504 | let test_string: id = NSString::alloc(nil).init_str("Saturat").autorelease(); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2504:30 + | +2504 | let test_string: id = NSString::alloc(nil).init_str("Saturat").autorelease(); + | ^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::count`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2505:34 + | +2505 | let count = NSArray::count(filters); + | ^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2507:34 + | +2507 | let description: id = msg_send![filters.objectAtIndex(i), description]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2517:30 + | +2517 | let indices: id = msg_send![class!(NSMutableIndexSet), indexSet]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2520:31 + | +2520 | let filtered: id = msg_send![filters, objectsAtIndexes: indices]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2526:24 + | +2526 | let sublayers: id = msg_send![layer, sublayers]; + | ^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::count`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2528:34 + | +2528 | let count = NSArray::count(sublayers); + | ^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2537:94 + | +2537 | extern "C" fn add_titlebar_accessory_view_controller(this: &Object, _: Sel, view_controller: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2542:29 + | +2542 | let accessory_view: id = msg_send![view_controller, view]; + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2544:24 + | +2544 | let mut frame: NSRect = msg_send![accessory_view, frame]; + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2550:64 + | +2550 | extern "C" fn move_tab_to_new_window(this: &Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2552:81 + | +2552 | let _: () = msg_send![super(this, class!(NSWindow)), moveTabToNewWindow:nil]; + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2564:59 + | +2564 | extern "C" fn merge_all_windows(this: &Object, _: Sel, _: id) { + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2566:78 + | +2566 | let _: () = msg_send![super(this, class!(NSWindow)), mergeAllWindows:nil]; + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2578:62 + | +2578 | extern "C" fn select_next_tab(this: &Object, _sel: Sel, _id: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2588:66 + | +2588 | extern "C" fn select_previous_tab(this: &Object, _sel: Sel, _id: id) { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2598:61 + | +2598 | extern "C" fn toggle_tab_bar(this: &Object, _sel: Sel, _id: id) { + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:2600:75 + | +2600 | let _: () = msg_send![super(this, class!(NSWindow)), toggleTabBar:nil]; + | ^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSWindowButton::NSWindowCloseButton`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:438:59 + | +438 | standardWindowButton: NSWindowButton::NSWindowCloseButton + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:436:35 + | +436 | let close_button: id = msg_send![ + | ^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSWindowButton::NSWindowMiniaturizeButton`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:442:59 + | +442 | standardWindowButton: NSWindowButton::NSWindowMiniaturizeButton + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:440:33 + | +440 | let min_button: id = msg_send![ + | ^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSWindowButton::NSWindowZoomButton`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:446:59 + | +446 | standardWindowButton: NSWindowButton::NSWindowZoomButton + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:444:34 + | +444 | let zoom_button: id = msg_send![ + | ^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowOcclusionState`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:482:27 + | +482 | .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:511:33 + | +511 | style_mask.contains(NSWindowStyleMask::NSFullScreenWindowMask) + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::frame`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:516:51 + | +516 | let mut window_frame = unsafe { NSWindow::frame(self.native_window) }; + | ^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::screen`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:518:36 + | +518 | let screen = NSWindow::screen(self.native_window); + | ^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSScreen::frame`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:519:23 + | +519 | NSScreen::frame(screen) + | ^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSView::frame`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:540:30 + | +540 | unsafe { NSView::frame(self.native_window.contentView()) }.size; + | ^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:539:13 + | +539 | let NSSize { width, height, .. } = + | ^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::frame`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:550:35 + | +550 | let frame = NSWindow::frame(self.native_window); + | ^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSAutoreleasePool::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:589:43 + | +589 | let pool = NSAutoreleasePool::new(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:589:47 + | +589 | let pool = NSAutoreleasePool::new(nil); + | ^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:601:21 + | +601 | NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask; + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:601:63 + | +601 | NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask; + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:604:35 + | +604 | style_mask |= NSWindowStyleMask::NSResizableWindowMask; + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:608:35 + | +608 | style_mask |= NSWindowStyleMask::NSMiniaturizableWindowMask; + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:612:35 + | +612 | style_mask |= NSWindowStyleMask::NSFullSizeContentViewWindowMask; + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:615:30 + | +615 | style_mask = NSWindowStyleMask::NSTitledWindowMask + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:616:23 + | +616 | | NSWindowStyleMask::NSFullSizeContentViewWindowMask; + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:619:32 + | +619 | let native_window: id = match kind { + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:631:37 + | +631 | let mut target_screen = nil; + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSScreen::screens`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:634:37 + | +634 | let screens = NSScreen::screens(nil); + | ^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:634:45 + | +634 | let screens = NSScreen::screens(nil); + | ^^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::count`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:635:58 + | +635 | let count: u64 = cocoa::foundation::NSArray::count(screens); + | ^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:637:58 + | +637 | let screen = cocoa::foundation::NSArray::objectAtIndex(screens, i); + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSScreen::frame`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:638:39 + | +638 | let frame = NSScreen::frame(screen); + | ^^^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSScreen::mainScreen`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:647:40 + | +647 | let screen = NSScreen::mainScreen(nil); + | ^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:647:51 + | +647 | let screen = NSScreen::mainScreen(nil); + | ^^^ + +warning: use of deprecated method `cocoa::appkit::NSScreen::frame`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:649:27 + | +649 | NSScreen::frame(screen) + | ^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:652:31 + | +652 | let window_rect = NSRect::new( + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:653:17 + | +653 | NSPoint::new( + | ^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:658:17 + | +658 | NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), + | ^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSBackingStoreBuffered`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:664:17 + | +664 | NSBackingStoreBuffered, + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSArray::arrayWithObject`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:672:30 + | +672 | NSArray::arrayWithObject(nil, NSFilenamesPboardType) + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:672:46 + | +672 | NSArray::arrayWithObject(nil, NSFilenamesPboardType) + | ^^^ + +warning: use of deprecated static `cocoa::appkit::NSFilenamesPboardType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:672:51 + | +672 | NSArray::arrayWithObject(nil, NSFilenamesPboardType) + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:680:30 + | +680 | let native_view: id = msg_send![VIEW_CLASS, alloc]; + | ^^ + +warning: use of deprecated method `cocoa::appkit::NSView::initWithFrame_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:681:39 + | +681 | let native_view = NSView::initWithFrame_(native_view, NSView::bounds(content_view)); + | ^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSView::bounds`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:681:75 + | +681 | let native_view = NSView::initWithFrame_(native_view, NSView::bounds(content_view)); + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:748:50 + | +748 | native_window.setContentMinSize_(NSSize { + | ^^^^^^ + +warning: use of deprecated unit variant `cocoa::appkit::NSWindowTitleVisibility::NSWindowTitleHidden`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:756:76 + | +756 | native_window.setTitleVisibility_(NSWindowTitleVisibility::NSWindowTitleHidden); + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSViewWidthSizable`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:759:46 + | +759 | native_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSViewHeightSizable`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:759:67 + | +759 | native_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:782:52 + | +782 | let tabbing_id = NSString::alloc(nil).init_str(tabbing_identifier.as_str()); + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:782:58 + | +782 | let tabbing_id = NSString::alloc(nil).init_str(tabbing_identifier.as_str()); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:790:40 + | +790 | let tracking_area: id = msg_send![class!(NSTrackingArea), alloc]; + | ^^ + +warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:793:39 + | +793 | initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) + | ^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:793:51 + | +793 | initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) + | ^^^^^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:793:73 + | +793 | initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) + | ^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:796:35 + | +796 | userInfo: nil + | ^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowCollectionBehavior`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:807:25 + | +807 | NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces | + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowCollectionBehavior`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:808:25 + | +808 | NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenAuxiliary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:813:38 + | +813 | let app = NSApplication::sharedApplication(nil); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:813:56 + | +813 | let app = NSApplication::sharedApplication(nil); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:814:30 + | +814 | let main_window: id = msg_send![app, mainWindow]; + | ^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:821:31 + | +821 | .contains(NSWindowStyleMask::NSFullScreenWindowMask); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowOrderingMode`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:834:100 + | +834 | ... let _: () = msg_send![main_window, addTabbedWindow: native_window ordered: NSWindowOrderingMode::NSWindowAbove]; + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:839:78 + | +839 | ... let _: () = msg_send![native_window, orderFront: nil]; + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:846:53 + | +846 | native_window.makeKeyAndOrderFront_(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:848:43 + | +848 | native_window.orderFront_(nil); + | ^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setFrameTopLeftPoint_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:855:23 + | +855 | NSWindow::setFrameTopLeftPoint_(native_window, window_rect.origin); + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:866:38 + | +866 | let app = NSApplication::sharedApplication(nil); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:866:56 + | +866 | let app = NSApplication::sharedApplication(nil); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:867:30 + | +867 | let main_window: id = msg_send![app, mainWindow]; + | ^^ + +warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:883:38 + | +883 | let app = NSApplication::sharedApplication(nil); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:883:56 + | +883 | let app = NSApplication::sharedApplication(nil); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:884:26 + | +884 | let windows: id = msg_send![app, orderedWindows]; + | ^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:885:24 + | +885 | let count: NSUInteger = msg_send![windows, count]; + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:889:29 + | +889 | let window: id = msg_send![windows, objectAtIndex:i]; + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSUserDefaults::standardUserDefaults`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:902:48 + | +902 | let defaults: id = NSUserDefaults::standardUserDefaults(); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:902:27 + | +902 | let defaults: id = NSUserDefaults::standardUserDefaults(); + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:903:36 + | +903 | let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:903:42 + | +903 | let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:904:33 + | +904 | let key = NSString::alloc(nil).init_str("AppleWindowTabbingMode"); + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:904:39 + | +904 | let key = NSString::alloc(nil).init_str("AppleWindowTabbingMode"); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:906:23 + | +906 | let dict: id = msg_send![defaults, persistentDomainForName: domain]; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:910:17 + | +910 | nil + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:907:24 + | +907 | let value: id = if !dict.is_null() { + | ^^ + +warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:914:42 + | +914 | CStr::from_ptr(NSString::UTF8String(value)).to_string_lossy() + | ^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:935:45 + | +935 | this.native_window.setDelegate_(nil); + | ^^^ + +warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:972:44 + | +972 | window.setContentSize_(NSSize { + | ^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1017:68 + | +1017 | let _: () = msg_send![native_window, toggleTabOverview:nil]; + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1027:29 + | +1027 | let appearance: id = msg_send![self.0.lock().native_window, effectiveAppearance]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1038:37 + | +1038 | let device_description: id = msg_send![screen, deviceDescription]; + | ^^ + +warning: use of deprecated method `cocoa::foundation::NSDictionary::valueForKey_`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1039:51 + | +1039 | let screen_number: id = NSDictionary::valueForKey_( + | ^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1041:27 + | +1041 | NSString::alloc(nil).init_str("NSScreenNumber"), + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1041:33 + | +1041 | NSString::alloc(nil).init_str("NSScreenNumber"), + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1039:32 + | +1039 | let screen_number: id = NSDictionary::valueForKey_( + | ^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1062:28 + | +1062 | let modifiers: NSEventModifierFlags = msg_send![class!(NSEvent), modifierFlags]; + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1064:46 + | +1064 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1065:42 + | +1065 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1066:44 + | +1066 | let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1067:46 + | +1067 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1068:47 + | +1068 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1082:28 + | +1082 | let modifiers: NSEventModifierFlags = msg_send![class!(NSEvent), modifierFlags]; + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1085:40 + | +1085 | on: modifiers.contains(NSEventModifierFlags::NSAlphaShiftKeyMask), + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1131:24 + | +1131 | let alert: id = msg_send![class!(NSAlert), alloc]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1132:24 + | +1132 | let alert: id = msg_send![alert, init]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1149:29 + | +1149 | let button: id = msg_send![alert, addButtonWithTitle: ns_string(answer.label())]; + | ^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1150:61 + | +1150 | let _: () = msg_send![button, setTag: ix as NSInteger]; + | ^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1161:29 + | +1161 | let button: id = msg_send![alert, addButtonWithTitle: ns_string(answer.label())]; + | ^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1162:61 + | +1162 | let _: () = msg_send![button, setTag: ix as NSInteger]; + | ^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1167:58 + | +1167 | let block = ConcreteBlock::new(move |answer: NSInteger| { + | ^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1195:73 + | +1195 | let _: () = msg_send![window, makeKeyAndOrderFront: nil]; + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1212:38 + | +1212 | let app = NSApplication::sharedApplication(nil); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1212:56 + | +1212 | let app = NSApplication::sharedApplication(nil); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1223:24 + | +1223 | let title: id = msg_send![self.0.lock().native_window, title]; + | ^^ + +warning: use of deprecated associated function `cocoa::appkit::NSColor::colorWithSRGBRed_green_blue_alpha_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1243:26 + | +1243 | NSColor::colorWithSRGBRed_green_blue_alpha_(nil, 0f64, 0f64, 0f64, 1f64) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1243:61 + | +1243 | NSColor::colorWithSRGBRed_green_blue_alpha_(nil, 0f64, 0f64, 0f64, 1f64) + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSColor::colorWithSRGBRed_green_blue_alpha_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1246:26 + | +1246 | NSColor::colorWithSRGBRed_green_blue_alpha_(nil, 0f64, 0f64, 0f64, 0.0001) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1246:61 + | +1246 | NSColor::colorWithSRGBRed_green_blue_alpha_(nil, 0f64, 0f64, 0f64, 0.0001) + | ^^^ + +warning: use of deprecated static `cocoa::appkit::NSAppKitVersionNumber`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1250:16 + | +1250 | if NSAppKitVersionNumber < NSAppKitVersionNumber12_0 { + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSAppKitVersionNumber12_0`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1250:40 + | +1250 | if NSAppKitVersionNumber < NSAppKitVersionNumber12_0 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSView::removeFromSuperview`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1268:33 + | +1268 | NSView::removeFromSuperview(blur_view); + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSView::bounds`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1273:41 + | +1273 | let frame = NSView::bounds(content_view); + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1274:40 + | +1274 | let mut blur_view: id = msg_send![BLURRED_VIEW_CLASS, alloc]; + | ^^ + +warning: use of deprecated method `cocoa::appkit::NSView::initWithFrame_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1275:41 + | +1275 | blur_view = NSView::initWithFrame_(blur_view, frame); + | ^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSViewWidthSizable`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1276:52 + | +1276 | blur_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::appkit::NSViewHeightSizable`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1276:73 + | +1276 | blur_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowOrderingMode`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1281:37 + | +1281 | positioned: NSWindowOrderingMode::NSWindowBelow + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1282:37 + | +1282 | relativeTo: nil + | ^^^ + +warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1307:46 + | +1307 | let app = NSApplication::sharedApplication(nil); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1307:64 + | +1307 | let app = NSApplication::sharedApplication(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1317:33 + | +1317 | window.miniaturize_(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1327:34 + | +1327 | window.zoom_(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1339:46 + | +1339 | window.toggleFullScreen_(nil); + | ^^^ + +warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1352:27 + | +1352 | .contains(NSWindowStyleMask::NSFullScreenWindowMask) + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1395:26 + | +1395 | let windows: id = msg_send![self.0.lock().native_window, tabbedWindows]; + | ^^ + +warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1400:24 + | +1400 | let count: NSUInteger = msg_send![windows, count]; + | ^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1403:29 + | +1403 | let window: id = msg_send![windows, objectAtIndex:i]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1406:32 + | +1406 | let title: id = msg_send![window, title]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1419:28 + | +1419 | let tab_group: id = msg_send![self.0.lock().native_window, tabGroup]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1467:40 + | +1467 | let input_context: id = + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSUserDefaults::standardUserDefaults`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1484:56 + | +1484 | let defaults: id = NSUserDefaults::standardUserDefaults(); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1484:35 + | +1484 | let defaults: id = NSUserDefaults::standardUserDefaults(); + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1485:44 + | +1485 | let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1485:50 + | +1485 | let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1486:41 + | +1486 | let key = NSString::alloc(nil).init_str("AppleActionOnDoubleClick"); + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1486:47 + | +1486 | let key = NSString::alloc(nil).init_str("AppleActionOnDoubleClick"); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1488:31 + | +1488 | let dict: id = msg_send![defaults, persistentDomainForName: domain]; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1492:25 + | +1492 | nil + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1489:33 + | +1489 | let action: id = if !dict.is_null() { + | ^^ + +warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1496:50 + | +1496 | CStr::from_ptr(NSString::UTF8String(action)).to_string_lossy() + | ^^^^^^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1503:49 + | +1503 | ... window.miniaturize_(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1506:42 + | +1506 | ... window.zoom_(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1510:42 + | +1510 | ... window.zoom_(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:1513:42 + | +1513 | ... window.zoom_(nil); + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:98:33 + | +98 | fn CGSMainConnectionID() -> id; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window.rs:100:24 + | +100 | connection_id: id, + | ^^ + +warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:101:20 + | +101 | window_id: NSInteger, + | ^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSAppearanceNameVibrantDark`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window_appearance.rs:3:14 + | +3 | appkit::{NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight}, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSAppearanceNameVibrantLight`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window_appearance.rs:3:43 + | +3 | appkit::{NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight}, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window_appearance.rs:4:11 + | +4 | base::id, + | ^^ + +warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window_appearance.rs:5:17 + | +5 | foundation::NSString, + | ^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window_appearance.rs:11:50 + | +11 | pub(crate) unsafe fn from_native(appearance: id) -> Self { + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window_appearance.rs:12:19 + | +12 | let name: id = msg_send![appearance, name]; + | ^^ + +warning: use of deprecated static `cocoa::appkit::NSAppearanceNameVibrantLight`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window_appearance.rs:14:24 + | +14 | if name == NSAppearanceNameVibrantLight { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated static `cocoa::appkit::NSAppearanceNameVibrantDark`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window_appearance.rs:16:31 + | +16 | } else if name == NSAppearanceNameVibrantDark { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window_appearance.rs:35:38 + | +35 | pub static NSAppearanceNameAqua: id; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/gpui/src/platform/mac/window_appearance.rs:36:42 + | +36 | pub static NSAppearanceNameDarkAqua: id; + | ^^ + + Compiling zlog v0.1.0 (/Volumes/ExternalData/Library/Git/zed/crates/zlog) + Compiling settings_ui_macros v0.1.0 (/Volumes/ExternalData/Library/Git/zed/crates/settings_ui_macros) + Compiling serde_path_to_error v0.1.17 + Compiling ec4rs v1.2.0 + Compiling pem-rfc7468 v0.7.0 +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/display.rs:38:62 + | +38 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSDictionary::objectForKey_`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/display.rs:39:52 + | +39 | let screen_number = device_description.objectForKey_(screen_number_key); + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::modifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:86:38 + | +86 | let modifiers = native_event.modifierFlags(); + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:87:33 + | +87 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSControlKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:87:64 + | +87 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:88:29 + | +88 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSAlternateKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:88:60 + | +88 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:89:31 + | +89 | let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSShiftKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:89:62 + | +89 | let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); + | ^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:90:33 + | +90 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSCommandKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:90:64 + | +90 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:91:34 + | +91 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSFunctionKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:91:65 + | +91 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::eventType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:109:43 + | +109 | let event_type = native_event.eventType(); + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::modifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:126:34 + | +126 | ... .modifierFlags() + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:127:34 + | +127 | ... .contains(NSEventModifierFlags::NSAlphaShiftKeyMask), + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSAlphaShiftKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:127:65 + | +127 | ... .contains(NSEventModifierFlags::NSAlphaShiftKeyMask), + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::isARepeat`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:133:43 + | +133 | is_held: native_event.isARepeat() == YES, + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::buttonNumber`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:141:53 + | +141 | let button = match native_event.buttonNumber() { + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:154:49 + | +154 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:154:36 + | +154 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:156:65 + | +156 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:156:52 + | +156 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::clickCount`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:159:55 + | +159 | ... click_count: native_event.clickCount() as usize, + | ^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::buttonNumber`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:167:53 + | +167 | let button = match native_event.buttonNumber() { + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:181:49 + | +181 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:181:36 + | +181 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:182:65 + | +182 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:182:52 + | +182 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::clickCount`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:185:55 + | +185 | ... click_count: native_event.clickCount() as usize, + | ^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::phase`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:191:67 + | +191 | let navigation_direction = match native_event.phase() { + | ^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventPhase::NSEventPhaseEnded`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:192:39 + | +192 | NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() { + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::deltaX`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:192:79 + | +192 | NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() { + | ^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:205:53 + | +205 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:205:40 + | +205 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:206:69 + | +206 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:206:56 + | +206 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::phase`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:217:52 + | +217 | let phase = match native_event.phase() { + | ^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventPhase::NSEventPhaseMayBegin`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:218:39 + | +218 | NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventPhase::NSEventPhaseBegan`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:218:76 + | +218 | NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventPhase::NSEventPhaseEnded`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:221:39 + | +221 | NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::scrollingDeltaX`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:226:38 + | +226 | native_event.scrollingDeltaX() as f32, + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::scrollingDeltaY`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:227:38 + | +227 | native_event.scrollingDeltaY() as f32, + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::hasPreciseScrollingDeltas`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:230:49 + | +230 | let delta = if native_event.hasPreciseScrollingDeltas() == YES { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:238:45 + | +238 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:238:32 + | +238 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:239:61 + | +239 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:239:48 + | +239 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::buttonNumber`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:249:61 + | +249 | let pressed_button = match native_event.buttonNumber() { + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:263:49 + | +263 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:263:36 + | +263 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:264:65 + | +264 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:264:52 + | +264 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:273:45 + | +273 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:273:32 + | +273 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:274:61 + | +274 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:274:48 + | +274 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:283:45 + | +283 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:283:32 + | +283 | ... px(native_event.locationInWindow().x as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:284:61 + | +284 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/events.rs:284:48 + | +284 | ... window_height - px(native_event.locationInWindow().y as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::charactersIgnoringModifiers`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:302:14 + | +302 | .charactersIgnoringModifiers() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::modifierFlags`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:307:38 + | +307 | let modifiers = native_event.modifierFlags(); + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:309:33 + | +309 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSControlKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:309:64 + | +309 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:310:29 + | +310 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSAlternateKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:310:60 + | +310 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:311:35 + | +311 | let mut shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSShiftKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:311:66 + | +311 | let mut shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); + | ^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:312:33 + | +312 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSCommandKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:312:64 + | +312 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:313:34 + | +313 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask) + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSFunctionKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:313:65 + | +313 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask) + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::keyCode`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:393:57 + | +393 | chars_for_modified_key(native_event.keyCode(), NO_MOD); + | ^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::keyCode`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:395:57 + | +395 | chars_for_modified_key(native_event.keyCode(), SHIFT_MOD); + | ^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::keyCode`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:400:78 + | +400 | let chars_with_cmd = chars_for_modified_key(native_event.keyCode(), CMD_MOD); + | ^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::keyCode`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:402:61 + | +402 | chars_for_modified_key(native_event.keyCode(), CMD_MOD | SHIFT_MOD); + | ^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::keyCode`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/events.rs:426:73 + | +426 | key_char = Some(chars_for_modified_key(native_event.keyCode(), mods)); + | ^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:198:59 + | +198 | let screen_number_key = unsafe { NSString::alloc(nil).init_str("NSScreenNumber") }; + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::count`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:246:38 + | +246 | for i in 0..displays.count() { + | ^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/screen_capture.rs:247:44 + | +247 | let display = displays.objectAtIndex(i); + | ^^^^^^^^^^^^^ + + Compiling by_address v1.2.1 +warning: use of deprecated associated constant `cocoa::quartzcore::AutoresizingMask::WIDTH_SIZABLE`: use the objc2-quartz-core crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:152:56 + | +152 | setAutoresizingMask: AutoresizingMask::WIDTH_SIZABLE + | ^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::quartzcore::AutoresizingMask::HEIGHT_SIZABLE`: use the objc2-quartz-core crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:153:41 + | +153 | | AutoresizingMask::HEIGHT_SIZABLE + | ^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:300:13 + | +300 | width: size.width.0 as f64, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:301:13 + | +301 | height: size.height.0 as f64, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:310:33 + | +310 | width: DevicePixels(size.width as i32), + | ^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/metal_renderer.rs:311:34 + | +311 | height: DevicePixels(size.height as i32), + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::dataForType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:223:35 + | +223 | let data = pasteboard.dataForType(kind); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSData::bytes`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:228:26 + | +228 | data.bytes() as *mut u8, + | ^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSData::length`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:229:26 + | +229 | data.length() as usize, + | ^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:243:53 + | +243 | let application_menu = NSMenu::new(nil).autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:244:30 + | +244 | application_menu.setDelegate_(delegate); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:247:45 + | +247 | let menu = NSMenu::new(nil).autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setTitle_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:249:22 + | +249 | menu.setTitle_(menu_title); + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:250:22 + | +250 | menu.setDelegate_(delegate); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSMenu::addItem_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:253:26 + | +253 | menu.addItem_(Self::create_menu_item( + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:261:54 + | +261 | let menu_item = NSMenuItem::new(nil).autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setTitle_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:262:27 + | +262 | menu_item.setTitle_(menu_title); + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSMenuItem::setSubmenu_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:263:27 + | +263 | menu_item.setSubmenu_(menu); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSMenu::addItem_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:264:34 + | +264 | application_menu.addItem_(menu_item); + | ^^^^^^^^ + + Compiling palette v0.7.6 +warning: use of deprecated method `cocoa::appkit::NSApplication::setWindowsMenu_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:268:25 + | +268 | app.setWindowsMenu_(menu); + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:285:23 + | +285 | dock_menu.setDelegate_(delegate); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSMenu::addItem_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:287:27 + | +287 | dock_menu.addItem_(Self::create_menu_item( + | ^^^^^^^^ + +warning: use of deprecated associated function `cocoa::appkit::_::::empty`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:354:66 + | +354 | ... let mut mask = NSEventModifierFlags::empty(); + | ^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSCommandKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:358:59 + | +358 | ... NSEventModifierFlags::NSCommandKeyMask, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSControlKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:362:59 + | +362 | ... NSEventModifierFlags::NSControlKeyMask, + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSAlternateKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:366:59 + | +366 | ... NSEventModifierFlags::NSAlternateKeyMask, + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSShiftKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:370:59 + | +370 | ... NSEventModifierFlags::NSShiftKeyMask, + | ^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSMenuItem::initWithTitle_action_keyEquivalent_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:379:34 + | +379 | ... .initWithTitle_action_keyEquivalent_( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:384:34 + | +384 | ... .autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSMenuItem::setKeyEquivalentModifierMask_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:388:34 + | +388 | ... item.setKeyEquivalentModifierMask_(mask); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSMenuItem::initWithTitle_action_keyEquivalent_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:391:34 + | +391 | ... .initWithTitle_action_keyEquivalent_( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:396:34 + | +396 | ... .autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSMenuItem::initWithTitle_action_keyEquivalent_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:400:30 + | +400 | ... .initWithTitle_action_keyEquivalent_( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:405:30 + | +405 | ... .autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:414:53 + | +414 | let item = NSMenuItem::new(nil).autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:415:52 + | +415 | let submenu = NSMenu::new(nil).autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:416:29 + | +416 | submenu.setDelegate_(delegate); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSMenu::addItem_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:418:33 + | +418 | submenu.addItem_(Self::create_menu_item(item, delegate, actions, keymap)); + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSMenuItem::setSubmenu_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:420:26 + | +420 | item.setSubmenu_(submenu); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setTitle_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:421:26 + | +421 | item.setTitle_(ns_string(name)); + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:425:53 + | +425 | let item = NSMenuItem::new(nil).autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:426:52 + | +426 | let submenu = NSMenu::new(nil).autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:427:29 + | +427 | submenu.setDelegate_(delegate); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSMenuItem::setSubmenu_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:428:26 + | +428 | item.setSubmenu_(submenu); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setTitle_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:429:26 + | +429 | item.setTitle_(ns_string(name)); + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSApplication::setServicesMenu_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:434:33 + | +434 | ... app.setServicesMenu_(item); + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSProcessInfo::operatingSystemVersion`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:447:26 + | +447 | process_info.operatingSystemVersion() + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSOperatingSystemVersion::majorVersion`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:450:13 + | +450 | version.majorVersion as usize, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSOperatingSystemVersion::minorVersion`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:451:13 + | +451 | version.minorVersion as usize, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSOperatingSystemVersion::patchVersion`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:452:13 + | +452 | version.patchVersion as usize, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:484:17 + | +484 | app.setDelegate_(app_delegate); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSApplication::run`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:491:17 + | +491 | app.run(); + | ^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::drain`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:492:18 + | +492 | pool.drain(); + | ^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSApplication::activateIgnoringOtherApps_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:559:17 + | +559 | app.activateIgnoringOtherApps_(ignoring_other_apps.to_objc()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSOperatingSystemVersion::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:596:72 + | +596 | let min_version = cocoa::foundation::NSOperatingSystemVersion::new(12, 3, 0); + | ^^^ + +warning: use of deprecated method `cocoa::foundation::NSURL::initWithString_`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:642:18 + | +642 | .initWithString_(ns_string(url)) + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:643:18 + | +643 | .autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSOpenPanel::setCanChooseDirectories_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:711:27 + | +711 | panel.setCanChooseDirectories_(options.directories.to_objc()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSOpenPanel::setCanChooseFiles_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:712:27 + | +712 | panel.setCanChooseFiles_(options.files.to_objc()); + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSOpenPanel::setAllowsMultipleSelection_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:713:27 + | +713 | panel.setAllowsMultipleSelection_(options.multiple.to_objc()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSSavePanel::setCanCreateDirectories`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:715:27 + | +715 | panel.setCanCreateDirectories(true.to_objc()); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSOpenPanel::setResolvesAliases_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:716:27 + | +716 | panel.setResolvesAliases_(false.to_objc()); + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSOpenPanel::URLs`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:721:46 + | +721 | ... let urls = panel.URLs(); + | ^^^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::count`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:722:46 + | +722 | ... for i in 0..urls.count() { + | ^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:723:48 + | +723 | ... let url = urls.objectAtIndex(i); + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSURL::isFileURL`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:724:40 + | +724 | ... if url.isFileURL() == YES + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSSavePanel::setDirectoryURL`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:766:27 + | +766 | panel.setDirectoryURL(url); + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSSavePanel::URL`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:777:45 + | +777 | ... let url = panel.URL(); + | ^^^ + +warning: use of deprecated method `cocoa::foundation::NSURL::isFileURL`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:778:36 + | +778 | ... if url.isFileURL() == YES { + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSSavePanel::URL`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:779:63 + | +779 | ... result = ns_url_to_path(panel.URL()).ok().map(|mut result| { + | ^^^ + +warning: use of deprecated method `cocoa::appkit::NSApplication::setMainMenu_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:910:17 + | +910 | app.setMainMenu_(menu); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::clearContents`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1034:42 + | +1034 | state.pasteboard.clearContents(); + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1042:70 + | +1042 | .init_attributed_string(NSString::alloc(nil).init_str("")); + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1048:78 + | +1048 | ... .init_attributed_string(NSString::alloc(nil).init_str(&text)); + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::clearContents`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1058:34 + | +1058 | state.pasteboard.clearContents(); + | ^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSRange::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1063:34 + | +1063 | NSRange::new(0, msg_send![attributed_string, length]), + | ^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::setData_forType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1069:30 + | +1069 | ... .setData_forType(rtfd_data, NSPasteboardTypeRTFD); + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSRange::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1073:34 + | +1073 | NSRange::new(0, attributed_string.length()), + | ^^^ + +warning: use of deprecated method `cocoa::foundation::NSData::length`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1073:59 + | +1073 | NSRange::new(0, attributed_string.length()), + | ^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::setData_forType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1079:30 + | +1079 | ... .setData_forType(rtf_data, NSPasteboardTypeRTF); + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::setString_forType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1086:22 + | +1086 | .setString_forType(plain_text, NSPasteboardTypeString); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::types`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1097:40 + | +1097 | let types: id = pasteboard.types(); + | ^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::dataForType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1101:39 + | +1101 | let data = pasteboard.dataForType(string_type); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSData::bytes`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1104:32 + | +1104 | } else if data.bytes().is_null() { + | ^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSData::bytes`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1110:52 + | +1110 | slice::from_raw_parts(data.bytes() as *mut u8, data.length() as usize); + | ^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSData::length`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1110:77 + | +1110 | slice::from_raw_parts(data.bytes() as *mut u8, data.length() as usize); + | ^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::clearContents`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1266:30 + | +1266 | state.pasteboard.clearContents(); + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::setData_forType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1275:18 + | +1275 | .setData_forType(text_bytes, NSPasteboardTypeString); + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::setData_forType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1286:22 + | +1286 | .setData_forType(hash_bytes, state.text_hash_pasteboard_type); + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::setData_forType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1295:22 + | +1295 | .setData_forType(metadata_bytes, state.metadata_pasteboard_type); + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::clearContents`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1303:30 + | +1303 | state.pasteboard.clearContents(); + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::setData_forType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1313:18 + | +1313 | .setData_forType(bytes, Into::::into(image.format).inner_mut()); + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::types`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1322:36 + | +1322 | let types: id = pasteboard.types(); + | ^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSPasteboard::dataForType`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1324:35 + | +1324 | let data = pasteboard.dataForType(ut_type.inner_mut()); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSData::bytes`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1329:26 + | +1329 | data.bytes() as *mut u8, + | ^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSData::length`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1330:26 + | +1330 | data.length() as usize, + | ^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1346:31 + | +1346 | let bytes = unsafe { path.UTF8String() as *const u8 }; + | ^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSApplication::setActivationPolicy_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/platform.rs:1362:13 + | +1362 | app.setActivationPolicy_(NSApplicationActivationPolicyRegular); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::count`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1421:18 + | +1421 | (0..urls.count()) + | ^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1423:32 + | +1423 | let url = urls.objectAtIndex(i); + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSURL::absoluteString`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1424:42 + | +1424 | match CStr::from_ptr(url.absoluteString().UTF8String() as *mut c_char).to_str() { + | ^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1424:59 + | +1424 | match CStr::from_ptr(url.absoluteString().UTF8String() as *mut c_char).to_str() { + | ^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1508:35 + | +1508 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1508:52 + | +1508 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSURL::absoluteString`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1514:28 + | +1514 | CStr::from_ptr(url.absoluteString().UTF8String()).to_string_lossy() + | ^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/platform.rs:1514:45 + | +1514 | CStr::from_ptr(url.absoluteString().UTF8String()).to_string_lossy() + | ^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::appkit::_::::from_bits_retain`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:65:24 + | +65 | NSWindowStyleMask::from_bits_retain(1 << 7); + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:275:12 + | +275 | px(position.x as f32), + | ^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:277:28 + | +277 | window_height - px(position.y as f32), + | ^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::occlusionState`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:481:18 + | +481 | .occlusionState() + | ^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:482:18 + | +482 | .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowOcclusionState::NSWindowOcclusionStateVisible`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:482:51 + | +482 | .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::screen`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:487:76 + | +487 | let display_id = unsafe { display_id_for_screen(self.native_window.screen()) }; + | ^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::screen`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:503:50 + | +503 | let screen_size = self.native_window.screen().visibleFrame().into(); + | ^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSScreen::visibleFrame`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:503:59 + | +503 | let screen_size = self.native_window.screen().visibleFrame().into(); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::styleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:510:49 + | +510 | let style_mask = self.native_window.styleMask(); + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:511:24 + | +511 | style_mask.contains(NSWindowStyleMask::NSFullScreenWindowMask) + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSFullScreenWindowMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:511:52 + | +511 | style_mask.contains(NSWindowStyleMask::NSFullScreenWindowMask) + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:523:9 + | +523 | window_frame.origin.y = + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:523:9 + | +523 | window_frame.origin.y = + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:524:13 + | +524 | screen_frame.size.height - window_frame.origin.y - window_frame.size.height; + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:524:13 + | +524 | screen_frame.size.height - window_frame.origin.y - window_frame.size.height; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:524:40 + | +524 | screen_frame.size.height - window_frame.origin.y - window_frame.size.height; + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:524:40 + | +524 | screen_frame.size.height - window_frame.origin.y - window_frame.size.height; + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:524:64 + | +524 | screen_frame.size.height - window_frame.origin.y - window_frame.size.height; + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:524:64 + | +524 | screen_frame.size.height - window_frame.origin.y - window_frame.size.height; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:528:21 + | +528 | px((window_frame.origin.x - screen_frame.origin.x) as f32), + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:528:21 + | +528 | px((window_frame.origin.x - screen_frame.origin.x) as f32), + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:528:45 + | +528 | px((window_frame.origin.x - screen_frame.origin.x) as f32), + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:528:45 + | +528 | px((window_frame.origin.x - screen_frame.origin.x) as f32), + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:529:21 + | +529 | px((window_frame.origin.y + screen_frame.origin.y) as f32), + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:529:21 + | +529 | px((window_frame.origin.y + screen_frame.origin.y) as f32), + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:529:45 + | +529 | px((window_frame.origin.y + screen_frame.origin.y) as f32), + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:529:45 + | +529 | px((window_frame.origin.y + screen_frame.origin.y) as f32), + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:532:20 + | +532 | px(window_frame.size.width as f32), + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:532:20 + | +532 | px(window_frame.size.width as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:533:20 + | +533 | px(window_frame.size.height as f32), + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:533:20 + | +533 | px(window_frame.size.height as f32), + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::contentView`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:540:55 + | +540 | unsafe { NSView::frame(self.native_window.contentView()) }.size; + | ^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:540:13 + | +540 | unsafe { NSView::frame(self.native_window.contentView()) }.size; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:539:22 + | +539 | let NSSize { width, height, .. } = + | ^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:539:29 + | +539 | let NSSize { width, height, .. } = + | ^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:552:17 + | +552 | px((frame.size.height - content_layout_rect.size.height) as f32) + | ^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:552:17 + | +552 | px((frame.size.height - content_layout_rect.size.height) as f32) + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSClosableWindowMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:601:40 + | +601 | NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask; + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSTitledWindowMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:601:82 + | +601 | NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask; + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSResizableWindowMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:604:54 + | +604 | style_mask |= NSWindowStyleMask::NSResizableWindowMask; + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSMiniaturizableWindowMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:608:54 + | +608 | style_mask |= NSWindowStyleMask::NSMiniaturizableWindowMask; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSFullSizeContentViewWindowMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:612:54 + | +612 | style_mask |= NSWindowStyleMask::NSFullSizeContentViewWindowMask; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSTitledWindowMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:615:49 + | +615 | style_mask = NSWindowStyleMask::NSTitledWindowMask + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSFullSizeContentViewWindowMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:616:42 + | +616 | | NSWindowStyleMask::NSFullSizeContentViewWindowMask; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSRect::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:652:39 + | +652 | let window_rect = NSRect::new( + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSPoint::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:653:26 + | +653 | NSPoint::new( + | ^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:654:21 + | +654 | screen_frame.origin.x + bounds.origin.x.0 as f64, + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:654:21 + | +654 | screen_frame.origin.x + bounds.origin.x.0 as f64, + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:655:21 + | +655 | screen_frame.origin.y + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:655:21 + | +655 | screen_frame.origin.y + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSSize::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:658:25 + | +658 | NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), + | ^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::initWithContentRect_styleMask_backing_defer_screen_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:661:47 + | +661 | let native_window = native_window.initWithContentRect_styleMask_backing_defer_screen_( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::contentView`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:679:46 + | +679 | let content_view = native_window.contentView(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:732:27 + | +732 | native_window.setDelegate_(native_window); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setMovable_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:745:27 + | +745 | native_window.setMovable_(is_movable as BOOL); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setContentMinSize_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:748:31 + | +748 | native_window.setContentMinSize_(NSSize { + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:749:21 + | +749 | width: window_min_size.width.to_f64(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:750:21 + | +750 | height: window_min_size.height.to_f64(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setTitlebarAppearsTransparent_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:755:31 + | +755 | native_window.setTitlebarAppearsTransparent_(YES); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setTitleVisibility_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:756:31 + | +756 | native_window.setTitleVisibility_(NSWindowTitleVisibility::NSWindowTitleHidden); + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSView::setAutoresizingMask_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:759:25 + | +759 | native_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); + | ^^^^^^^^^^^^^^^^^^^^ + + Compiling palette_derive v0.7.6 +warning: use of deprecated method `cocoa::appkit::NSView::setWantsBestResolutionOpenGLSurface_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:760:25 + | +760 | native_view.setWantsBestResolutionOpenGLSurface_(YES); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSView::setWantsLayer`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:767:25 + | +767 | native_view.setWantsLayer(YES); + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSView::addSubview_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:773:26 + | +773 | content_view.addSubview_(native_view.autorelease()); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:773:50 + | +773 | content_view.addSubview_(native_view.autorelease()); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::makeFirstResponder_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:774:27 + | +774 | native_window.makeFirstResponder_(native_view); + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setLevel_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:778:35 + | +778 | native_window.setLevel_(NSNormalWindowLevel); + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setAcceptsMouseMovedEvents_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:779:35 + | +779 | native_window.setAcceptsMouseMovedEvents_(YES); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:782:63 + | +782 | let tabbing_id = NSString::alloc(nil).init_str(tabbing_identifier.as_str()); + | ^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSRect::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:793:47 + | +793 | initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSPoint::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:793:60 + | +793 | initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSSize::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:793:81 + | +793 | initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) + | ^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:799:79 + | +799 | msg_send![native_view, addTrackingArea: tracking_area.autorelease()]; + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setLevel_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:801:35 + | +801 | native_window.setLevel_(NSPopUpWindowLevel); + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setCollectionBehavior_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:806:35 + | +806 | native_window.setCollectionBehavior_( + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:807:53 + | +807 | NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces | + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenAuxiliary`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:808:53 + | +808 | NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenAuxiliary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::styleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:820:22 + | +820 | .styleMask() + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:821:22 + | +821 | .contains(NSWindowStyleMask::NSFullScreenWindowMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSFullScreenWindowMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:821:50 + | +821 | .contains(NSWindowStyleMask::NSFullScreenWindowMask); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowOrderingMode::NSWindowAbove`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:834:122 + | +834 | ... let _: () = msg_send![main_window, addTabbedWindow: native_window ordered: NSWindowOrderingMode::NSWindowAbove]; + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::makeKeyAndOrderFront_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:846:31 + | +846 | native_window.makeKeyAndOrderFront_(nil); + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::orderFront_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:848:31 + | +848 | native_window.orderFront_(nil); + | ^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:855:60 + | +855 | NSWindow::setFrameTopLeftPoint_(native_window, window_rect.origin); + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::drain`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:858:18 + | +858 | pool.drain(); + | ^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:903:47 + | +903 | let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:904:44 + | +904 | let key = NSString::alloc(nil).init_str("AppleWindowTabbingMode"); + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:935:32 + | +935 | this.native_window.setDelegate_(nil); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::close`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:941:28 + | +941 | window.close(); + | ^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:942:28 + | +942 | window.autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setContentSize_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:972:28 + | +972 | window.setContentSize_(NSSize { + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:973:25 + | +973 | width: size.width.0 as f64, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:974:25 + | +974 | height: size.height.0 as f64, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::screen`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1034:54 + | +1034 | let screen = self.0.lock().native_window.screen(); + | ^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1041:38 + | +1041 | NSString::alloc(nil).init_str("NSScreenNumber"), + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::mouseLocationOutsideOfEventStream`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1055:18 + | +1055 | .mouseLocationOutsideOfEventStream() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1064:37 + | +1064 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSControlKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1064:68 + | +1064 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1065:33 + | +1065 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSAlternateKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1065:64 + | +1065 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); + | ^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1066:35 + | +1066 | let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSShiftKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1066:66 + | +1066 | let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); + | ^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1067:37 + | +1067 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSCommandKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1067:68 + | +1067 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); + | ^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1068:38 + | +1068 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSFunctionKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1068:69 + | +1068 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1085:31 + | +1085 | on: modifiers.contains(NSEventModifierFlags::NSAlphaShiftKeyMask), + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSAlphaShiftKeyMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1085:62 + | +1085 | on: modifiers.contains(NSEventModifierFlags::NSAlphaShiftKeyMask), + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::isKeyWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1202:46 + | +1202 | unsafe { self.0.lock().native_window.isKeyWindow() == YES } + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setOpaque_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1241:32 + | +1241 | this.native_window.setOpaque_(opaque as BOOL); + | ^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setBackgroundColor_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1248:32 + | +1248 | this.native_window.setBackgroundColor_(background_color); + | ^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSEvent::windowNumber`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1260:56 + | +1260 | let window_number = this.native_window.windowNumber(); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::contentView`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1272:59 + | +1272 | let content_view = this.native_window.contentView(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSView::setAutoresizingMask_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1276:31 + | +1276 | blur_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowOrderingMode::NSWindowBelow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1281:59 + | +1281 | positioned: NSWindowOrderingMode::NSWindowBelow + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1284:56 + | +1284 | this.blurred_view = Some(blur_view.autorelease()); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::miniaturize_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1317:20 + | +1317 | window.miniaturize_(nil); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::zoom_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1327:28 + | +1327 | window.zoom_(nil); + | ^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::toggleFullScreen_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1339:28 + | +1339 | window.toggleFullScreen_(nil); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::styleMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1351:18 + | +1351 | .styleMask() + | ^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1352:18 + | +1352 | .contains(NSWindowStyleMask::NSFullScreenWindowMask) + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSFullScreenWindowMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1352:46 + | +1352 | .contains(NSWindowStyleMask::NSFullScreenWindowMask) + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1485:55 + | +1485 | let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1486:52 + | +1486 | let key = NSString::alloc(nil).init_str("AppleActionOnDoubleClick"); + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::miniaturize_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1503:36 + | +1503 | ... window.miniaturize_(nil); + | ^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::zoom_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1506:36 + | +1506 | ... window.zoom_(nil); + | ^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::zoom_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1510:36 + | +1510 | ... window.zoom_(nil); + | ^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::zoom_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1513:36 + | +1513 | ... window.zoom_(nil); + | ^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::occlusionState`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1887:14 + | +1887 | .occlusionState() + | ^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1888:14 + | +1888 | .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowOcclusionState::NSWindowOcclusionStateVisible`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1888:47 + | +1888 | .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSOperatingSystemVersion::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1908:49 + | +1908 | let min_version = NSOperatingSystemVersion::new(15, 3, 0); + | ^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setTitlebarAppearsTransparent_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1912:32 + | +1912 | lock.native_window.setTitlebarAppearsTransparent_(NO); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSOperatingSystemVersion::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1921:49 + | +1921 | let min_version = NSOperatingSystemVersion::new(15, 3, 0); + | ^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::setTitlebarAppearsTransparent_`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1925:32 + | +1925 | lock.native_window.setTitlebarAppearsTransparent_(YES); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSProcessInfo::isOperatingSystemAtLeastVersion`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:1931:46 + | +1931 | unsafe { NSProcessInfo::processInfo(nil).isOperatingSystemAtLeastVersion(version) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::appkit::NSWindow::isKeyWindow`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:1953:49 + | +1953 | let is_active = unsafe { lock.native_window.isKeyWindow() == YES }; + | ^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2077:30 + | +2077 | Size::::from(old_frame.size) + | ^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSRect::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2170:17 + | +2170 | NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSPoint::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2170:30 + | +2170 | NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSSize::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2170:51 + | +2170 | NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSRect::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2172:21 + | +2172 | NSRect::new( + | ^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSPoint::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2173:26 + | +2173 | NSPoint::new( + | ^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2174:21 + | +2174 | frame.origin.x + bounds.origin.x.0 as f64, + | ^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2174:21 + | +2174 | frame.origin.x + bounds.origin.x.0 as f64, + | ^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2175:21 + | +2175 | frame.origin.y + frame.size.height + | ^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2175:21 + | +2175 | frame.origin.y + frame.size.height + | ^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2175:38 + | +2175 | frame.origin.y + frame.size.height + | ^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2175:38 + | +2175 | frame.origin.y + frame.size.height + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSSize::new`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2179:25 + | +2179 | NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), + | ^^^ + +warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:2192:24 + | +2192 | if !style_mask.contains(NSWindowStyleMask::NSFullSizeContentViewWindowMask) { + | ^^^^^^^^ + +warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSFullSizeContentViewWindowMask`: use the objc2-app-kit crate instead + --> crates/gpui/src/platform/mac/window.rs:2192:52 + | +2192 | if !style_mask.contains(NSWindowStyleMask::NSFullSizeContentViewWindowMask) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2193:13 + | +2193 | frame.origin.y -= frame.size.height - content_layout_rect.size.height; + | ^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2193:13 + | +2193 | frame.origin.y -= frame.size.height - content_layout_rect.size.height; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2193:31 + | +2193 | frame.origin.y -= frame.size.height - content_layout_rect.size.height; + | ^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2193:31 + | +2193 | frame.origin.y -= frame.size.height - content_layout_rect.size.height; + | ^^^^^^^^^^^^^^^^^ + + Compiling der v0.7.10 +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2324:20 + | +2324 | let window_x = position.x - frame.origin.x; + | ^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2324:33 + | +2324 | let window_x = position.x - frame.origin.x; + | ^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2324:33 + | +2324 | let window_x = position.x - frame.origin.x; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2325:20 + | +2325 | let window_y = frame.size.height - (position.y - frame.origin.y); + | ^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2325:20 + | +2325 | let window_y = frame.size.height - (position.y - frame.origin.y); + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2325:41 + | +2325 | let window_y = frame.size.height - (position.y - frame.origin.y); + | ^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2325:54 + | +2325 | let window_y = frame.size.height - (position.y - frame.origin.y); + | ^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2325:54 + | +2325 | let window_y = frame.size.height - (position.y - frame.origin.y); + | ^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSFastEnumeration::iter`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2383:36 + | +2383 | for file in unsafe { filenames.iter() } { + | ^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2458:58 + | +2458 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSDictionary::objectForKey_`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2459:48 + | +2459 | let screen_number = device_description.objectForKey_(screen_number_key); + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::isEqualToString`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2491:23 + | +2491 | if class_name.isEqualToString("CAChameleonLayer") { + | ^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2504:56 + | +2504 | let test_string: id = NSString::alloc(nil).init_str("Saturat").autorelease(); + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2504:76 + | +2504 | let test_string: id = NSString::alloc(nil).init_str("Saturat").autorelease(); + | ^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2507:57 + | +2507 | let description: id = msg_send![filters.objectAtIndex(i), description]; + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2530:42 + | +2530 | let sublayer = sublayers.objectAtIndex(i); + | ^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2545:9 + | +2545 | frame.size.height = 0.0; + | ^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window.rs:2545:9 + | +2545 | frame.size.height = 0.0; + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac/window_appearance.rs:25:41 + | +25 | CStr::from_ptr(name.UTF8String()) + | ^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:78:29 + | +78 | let cstr = self.UTF8String(); + | ^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:139:35 + | +139 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:139:52 + | +139 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } + | ^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:145:23 + | +145 | width: px(value.width as f32), + | ^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:146:24 + | +146 | height: px(value.height as f32), + | ^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:153:40 + | +153 | let NSSize { width, height } = rect.size; + | ^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:153:22 + | +153 | let NSSize { width, height } = rect.size; + | ^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:153:29 + | +153 | let NSSize { width, height } = rect.size; + | ^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:160:40 + | +160 | let NSSize { width, height } = rect.size; + | ^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:160:22 + | +160 | let NSSize { width, height } = rect.size; + | ^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead + --> crates/gpui/src/platform/mac.rs:160:29 + | +160 | let NSSize { width, height } = rect.size; + | ^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/fs/src/fs.rs:450:20 + | +450 | base::{id, nil}, + | ^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/fs/src/fs.rs:450:24 + | +450 | base::{id, nil}, + | ^^^ + +warning: use of deprecated trait `cocoa::foundation::NSAutoreleasePool`: use the objc2-foundation crate instead + --> crates/fs/src/fs.rs:451:26 + | +451 | foundation::{NSAutoreleasePool, NSString}, + | ^^^^^^^^^^^^^^^^^ + +warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead + --> crates/fs/src/fs.rs:451:45 + | +451 | foundation::{NSAutoreleasePool, NSString}, + | ^^^^^^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/fs/src/fs.rs:456:50 + | +456 | unsafe fn ns_string(string: &str) -> id { + | ^^ + +warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead + --> crates/fs/src/fs.rs:457:36 + | +457 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } + | ^^^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/fs/src/fs.rs:457:42 + | +457 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/fs/src/fs.rs:460:22 + | +460 | let url: id = msg_send![class!(NSURL), fileURLWithPath: ns_string(path.to_string_lossy().as_ref())]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/fs/src/fs.rs:461:24 + | +461 | let array: id = msg_send![class!(NSArray), arrayWithObject: url]; + | ^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/fs/src/fs.rs:462:28 + | +462 | let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; + | ^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/fs/src/fs.rs:464:84 + | +464 | let _: id = msg_send![workspace, recycleURLs: array completionHandler: nil]; + | ^^^ + +warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead + --> crates/fs/src/fs.rs:464:20 + | +464 | let _: id = msg_send![workspace, recycleURLs: array completionHandler: nil]; + | ^^ + +warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead + --> crates/fs/src/fs.rs:457:47 + | +457 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } + | ^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead + --> crates/fs/src/fs.rs:457:64 + | +457 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } + | ^^^^^^^^^^^ + +warning: use of deprecated associated function `cocoa::foundation::NSProcessInfo::processInfo`: use the objc2-foundation crate instead + --> crates/client/src/telemetry.rs:115:66 + | +115 | let process_info = cocoa::foundation::NSProcessInfo::processInfo(nil); + | ^^^^^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/client/src/telemetry.rs:115:78 + | +115 | let process_info = cocoa::foundation::NSProcessInfo::processInfo(nil); + | ^^^ + +warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead + --> crates/client/src/telemetry.rs:111:26 + | +111 | use cocoa::base::nil; + | ^^^ + +warning: use of deprecated trait `cocoa::foundation::NSProcessInfo`: use the objc2-foundation crate instead + --> crates/client/src/telemetry.rs:112:32 + | +112 | use cocoa::foundation::NSProcessInfo; + | ^^^^^^^^^^^^^ + +warning: use of deprecated method `cocoa::foundation::NSProcessInfo::operatingSystemVersion`: use the objc2-foundation crate instead + --> crates/client/src/telemetry.rs:116:40 + | +116 | let version = process_info.operatingSystemVersion(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSOperatingSystemVersion::majorVersion`: use the objc2-foundation crate instead + --> crates/client/src/telemetry.rs:118:17 + | +118 | version.majorVersion as usize, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSOperatingSystemVersion::minorVersion`: use the objc2-foundation crate instead + --> crates/client/src/telemetry.rs:119:17 + | +119 | version.minorVersion as usize, + | ^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated field `cocoa::foundation::NSOperatingSystemVersion::patchVersion`: use the objc2-foundation crate instead + --> crates/client/src/telemetry.rs:120:17 + | +120 | version.patchVersion as usize, + | ^^^^^^^^^^^^^^^^^^^^ + + From 9d233784db70dc6b3f8bf2f18e5b44ffa12f8650 Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Wed, 17 Sep 2025 10:42:23 +0800 Subject: [PATCH 02/38] docs+scripts: add reusable patch/worktree workflow (aliases, helpers, docs) for cross-project use --- .githooks/pre-commit | 16 ++++ AGENTS.md | 24 ++++++ docs/patch_workflow.md | 90 ++++++++++++++++++++ script/apply-cumulative.sh | 57 +++++++++++++ script/bench-macos.sh | 83 +++++++++++++++++++ script/cleanup-worktrees.sh | 23 ++++++ script/gstart.sh | 25 ++++++ script/new-worktree-apply-cumulative.sh | 104 ++++++++++++++++++++++++ script/new-worktree.sh | 49 +++++++++++ script/setup-repo.sh | 71 ++++++++++++++++ script/uninstall.sh | 0 11 files changed, 542 insertions(+) create mode 100755 .githooks/pre-commit create mode 100644 AGENTS.md create mode 100644 docs/patch_workflow.md create mode 100755 script/apply-cumulative.sh create mode 100755 script/bench-macos.sh create mode 100755 script/cleanup-worktrees.sh create mode 100755 script/gstart.sh create mode 100755 script/new-worktree-apply-cumulative.sh create mode 100755 script/new-worktree.sh create mode 100755 script/setup-repo.sh mode change 100644 => 100755 script/uninstall.sh diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 00000000000000..7ee33508266401 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Prevent committing in the primary working tree; encourage using worktrees. +set -euo pipefail + +GIT_DIR=$(git rev-parse --git-dir) +GIT_COMMON_DIR=$(git rev-parse --git-common-dir) + +if [[ "${ALLOW_ROOT_COMMIT:-0}" != "1" ]] && [[ "$GIT_DIR" == "$GIT_COMMON_DIR" ]]; then + echo "[pre-commit] This appears to be the primary working tree (not a git worktree)." >&2 + echo "Please create a worktree and commit from there (e.g., script/new-worktree.sh)." >&2 + echo "Override by setting ALLOW_ROOT_COMMIT=1 if you really need to." >&2 + exit 1 +fi + +exit 0 + diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000000..58ebde193fa5a7 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,24 @@ +Agent Setup and Patch Workflow + +Overview + +- This repository includes a reusable workflow for managing patch series and reapplying them cleanly on top of upstream. +- Use Git worktrees plus helper scripts to automate creation of fresh branches, application of a cumulative checkpoint, and any numbered delta patches, with optional push. + +Quick Start + +- One-shot startup (setup + worktree + apply + push): + - `git gstart` +- Manual setup then apply: + - `git sts` (configure hooks, aliases, and git settings for this repo) + - `git wta` (create worktree, apply latest checkpoint + deltas; push later) or `git gta` (same + push) + +Documentation + +- See `docs/patch_workflow.md` for a comprehensive guide covering: + - Repo layout (patch series folder, checkpoint metadata) + - Helper scripts and what they do + - Aliases and common flows + - How to generate new deltas and checkpoints + - Worktree hygiene and porting this setup to other repos + diff --git a/docs/patch_workflow.md b/docs/patch_workflow.md new file mode 100644 index 00000000000000..ddb021870b804c --- /dev/null +++ b/docs/patch_workflow.md @@ -0,0 +1,90 @@ +Patch + Worktree Workflow (Reusable) + +Overview + +- Goal: maintain a stack of numbered patches and a dated cumulative checkpoint that can be reapplied cleanly onto a fresh upstream base at any time. +- Tooling: Git worktrees, helper scripts, and repo-local aliases. +- Benefit: easy rebase against upstream without conflict storms; repeatable and automatable. + +Repo Structure + +- `.reapply-patches/macOS-modernization/` + - `0001-*.patch` … numbered mail-formatted patches applied with `git am -3`. + - `YYYYMMDD-cumulative.patch` (checkpoint) … raw diff applied with `git apply --index`. + - `CHECKPOINT` … metadata indicating the last numbered patch covered by the checkpoint: + - `DATE=YYYYMMDD` + - `COVERS=0031` + - `README.md` … quick guide and project-specific notes. +- `worktrees/` … new worktrees created per branch. +- `script/` … helper scripts (see below). + +Helper Scripts + +- `script/setup-repo.sh` … idempotent repo setup: hooksPath, aliases, am.threeWay, apply.whitespace=fix, rerere.enabled. +- `script/gstart.sh` … one command: setup → create worktree → apply latest checkpoint → apply deltas beyond checkpoint → push. +- `script/new-worktree.sh` … create a worktree + branch from latest upstream (auto picks newer of main/nightly). +- `script/new-worktree-apply-cumulative.sh` … create worktree, apply checkpoint, then apply numbered deltas based on `CHECKPOINT`; optional `--push`. +- `script/apply-cumulative.sh` … apply checkpoint (and deltas) in current repo (non-worktree). +- `script/cleanup-worktrees.sh` … prune stale worktrees and remove empty `target/bench-*` dirs. +- `script/bench-macos.sh` … benchmark baseline vs patched builds (macOS, optional release build, worktree-aware). +- `script/normalize-cumulative.sh` … sanitize cumulative patch files (trim trailing spaces; avoid structural changes). + +Aliases (repo-local) + +- `git sts` → `script/setup-repo.sh` +- `git gstart` → `script/gstart.sh` +- `git wtn ` → `script/new-worktree.sh --branch ` +- `git wta [flags]` → `script/new-worktree-apply-cumulative.sh` +- `git gta` → `script/new-worktree-apply-cumulative.sh --push` +- `git wtl` → `git worktree list -v` +- `git wtr` → `script/cleanup-worktrees.sh` + +Typical Flows + +- Fresh session, defaults end-to-end: + - `git gstart` + - Then: `cd worktrees/` and run your builds/tests. + +- Fresh session, no immediate push: + - `git wta` (applies checkpoint + deltas into a new worktree; push later). + +- Manual apply in current repo: + - `script/apply-cumulative.sh --patch .reapply-patches/.../YYYYMMDD-cumulative.patch` + +- Create a feature worktree without patches: + - `git wtn feature-x` + +Generating New Deltas and Checkpoints + +- After you’ve committed changes on a feature branch/worktree: + - Export mail-formatted patches: `git format-patch -N -o .reapply-patches/ ..HEAD` + - Rename to next `000X-...` and commit them to the patch dir. + - Update `CHECKPOINT` only when cutting a new cumulative. +- New cumulative checkpoint (from series tip): + - `git diff upstream/main..HEAD -- . ':(exclude).reapply-patches/**' > .reapply-patches//YYYYMMDD-cumulative.patch` + - Trim trailing whitespace: `script/normalize-cumulative.sh ` + - Commit the cumulative and update README + CHECKPOINT. + +Apply Semantics + +- Checkpoint (raw diff): `git apply --index` (scripts prefer direct apply with whitespace fix; 3-way fallback when needed). +- Numbered patches (mail format): `git am -3 000*.patch`. +- Deltas beyond checkpoint: scripts automatically apply 000*.patch with numbers greater than `CHECKPOINT.COVERS`. + +Warnings and What’s OK + +- `new blank line at EOF` during apply: benign (intentional final newline). We don’t remove legitimate blank lines; we only trim trailing spaces. +- Fallbacks in logs: the scripts prefer direct apply when `--check` passes; they only emit 3-way fallback when truly necessary. + +Worktree Structure + +- Worktrees live under `worktrees/` and are linked to local branches. +- Don’t commit in the primary working tree (root); a pre-commit hook blocks it by default. +- Use `git wtl` to list worktrees and `git wtr` to clean stale ones. + +Porting This Workflow + +- Copy the `script/` helpers and `.githooks/pre-commit` to new repos; run `script/setup-repo.sh` to install aliases and hooks. +- Create a `.reapply-patches//` folder with `README.md`, numbered patches, a `CHECKPOINT` file, and a `YYYYMMDD-cumulative.patch`. +- Update series names and script messages as needed. + diff --git a/script/apply-cumulative.sh b/script/apply-cumulative.sh new file mode 100755 index 00000000000000..c3e08efa11597b --- /dev/null +++ b/script/apply-cumulative.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Apply a cumulative checkpoint (raw diff) and then any numbered deltas after the checkpoint. +# Usage: script/apply-cumulative.sh [--patch ] + +ROOT_DIR=$(cd -- "$(dirname -- "$0")/.." && pwd) +cd "$ROOT_DIR" + +PATCH_DIR=".reapply-patches/macOS-modernization" +LATEST_CUM_PATCH="" +if ls -1 "$PATCH_DIR"/*-cumulative.patch >/dev/null 2>&1; then + LATEST_CUM_PATCH=$(ls -1 "$PATCH_DIR"/*-cumulative.patch | sort | tail -n1) +fi + +PATCH_PATH="${LATEST_CUM_PATCH:-}" +while [[ $# -gt 0 ]]; do + case "$1" in + --patch) PATCH_PATH="$2"; shift 2;; + -h|--help) echo "Usage: $0 [--patch ]"; exit 0;; + *) echo "Unknown arg: $1" >&2; exit 1;; + esac +done + +if [[ -z "$PATCH_PATH" || ! -f "$PATCH_PATH" ]]; then + echo "Cumulative patch not found. Specify with --patch or ensure one exists in $PATCH_DIR" >&2 + exit 1 +fi + +if git apply --check "$PATCH_PATH" >/dev/null 2>&1; then + git apply --index --whitespace=fix "$PATCH_PATH" +else + git apply --3way --index --whitespace=fix "$PATCH_PATH" +fi +git commit -m "macOS: apply $(basename "$PATCH_PATH")" + +# Apply deltas after checkpoint +CHECKPOINT_FILE="$PATCH_DIR/CHECKPOINT" +SERIES_COVERED="0000" +if [[ -f "$CHECKPOINT_FILE" ]]; then + SERIES_COVERED=$(awk -F= '/^COVERS=/{print $2}' "$CHECKPOINT_FILE" 2>/dev/null | tr -d '\r\n' || echo "0000") +fi +apply_deltas=() +for p in "$PATCH_DIR"/00*.patch; do + [[ -f "$p" ]] || continue + base=$(basename "$p") + num=$(printf "%s" "$base" | sed -E 's/^([0-9]{4}).*/\1/') + if [[ -n "$num" ]] && ((10#$num > 10#$SERIES_COVERED)); then + apply_deltas+=("$p") + fi +done +if [[ ${#apply_deltas[@]} -gt 0 ]]; then + git am -3 "${apply_deltas[@]}" +fi + +echo "Applied: $PATCH_PATH" + diff --git a/script/bench-macos.sh b/script/bench-macos.sh new file mode 100755 index 00000000000000..adef0d924cf2e2 --- /dev/null +++ b/script/bench-macos.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +set -euo pipefail + +# macOS benchmark: baseline vs patched (checkpoint) +# Usage: script/bench-macos.sh [--mode both|baseline|patched] [--patch ] [--skip-release] [--no-clean] + +ROOT_DIR=$(cd -- "$(dirname -- "$0")/.." && pwd) +cd "$ROOT_DIR" + +PATCH_DIR=".reapply-patches/macOS-modernization" +LATEST_CUM_PATCH="" +if ls -1 "$PATCH_DIR"/*-cumulative.patch >/dev/null 2>&1; then + LATEST_CUM_PATCH=$(ls -1 "$PATCH_DIR"/*-cumulative.patch | sort | tail -n1) +fi + +PATCH_PATH="${LATEST_CUM_PATCH:-}" +MODE="both" +SKIP_RELEASE=0 +CLEAN_BUILD=1 +TARGET_CRATE="zed" + +while [[ $# -gt 0 ]]; do + case "$1" in + --mode) MODE="$2"; shift 2;; + --patch) PATCH_PATH="$2"; shift 2;; + --skip-release) SKIP_RELEASE=1; shift;; + --no-clean) CLEAN_BUILD=0; shift;; + --crate) TARGET_CRATE="$2"; shift 2;; + -h|--help) echo "Usage: $0 [--mode both|baseline|patched] [--patch ] [--skip-release] [--no-clean] [--crate ]"; exit 0;; + *) echo "Unknown arg: $1" >&2; exit 1;; + esac +done + +if [[ "$MODE" != "baseline" ]]; then + if [[ -z "$PATCH_PATH" || ! -f "$PATCH_PATH" ]]; then + echo "Cumulative patch not found. Specify with --patch or ensure one exists in $PATCH_DIR" >&2 + exit 1 + fi +fi + +timestamp() { date +"%Y-%m-%d %H:%M:%S"; } +measure() { local l=$1; shift; local s=$(date +%s); "$@"; local r=$?; local e=$(date +%s); echo "[$(timestamp)] $l -> $((e-s))s (status $r)" >&2; echo $((e-s)); } + +RUN_ID=$(date +%Y%m%d-%H%M%S) +WORKTREES_BASE="$ROOT_DIR/target/bench-$RUN_ID" +BASELINE_DIR="$WORKTREES_BASE/baseline" +PATCHED_DIR="$WORKTREES_BASE/patched" +mkdir -p "$WORKTREES_BASE" + +git fetch upstream --tags --prune >/dev/null 2>&1 || true + +git worktree add "$BASELINE_DIR" upstream/main >/dev/null +if [[ "$MODE" != "baseline" ]]; then git worktree add "$PATCHED_DIR" upstream/main >/dev/null; fi + +BASE_CHECK="skipped"; BASE_BUILD="skipped" +if [[ "$MODE" != "patched" ]]; then + pushd "$BASELINE_DIR" >/dev/null + [[ $CLEAN_BUILD -eq 1 ]] && cargo clean || true + BASE_CHECK=$(measure "baseline: cargo check -p gpui" bash -lc "cargo check -p gpui") + if [[ $SKIP_RELEASE -eq 0 ]]; then BASE_BUILD=$(measure "baseline: cargo build -p $TARGET_CRATE --release" bash -lc "cargo build -p $TARGET_CRATE --release"); fi + popd >/dev/null +fi + +PAT_CHECK="skipped"; PAT_BUILD="skipped" +if [[ "$MODE" != "baseline" ]]; then + pushd "$PATCHED_DIR" >/dev/null + if git apply --check "$ROOT_DIR/$PATCH_PATH" >/dev/null 2>&1; then + git apply --index --whitespace=fix "$ROOT_DIR/$PATCH_PATH" + else + git apply --3way --index --whitespace=fix "$ROOT_DIR/$PATCH_PATH" + fi + git commit -m "bench: apply $(basename "$PATCH_PATH")" >/dev/null + [[ $CLEAN_BUILD -eq 1 ]] && cargo clean || true + PAT_CHECK=$(measure "patched: cargo check -p gpui" bash -lc "cargo check -p gpui") + if [[ $SKIP_RELEASE -eq 0 ]]; then PAT_BUILD=$(measure "patched: cargo build -p $TARGET_CRATE --release" bash -lc "cargo build -p $TARGET_CRATE --release"); fi + popd >/dev/null +fi + +echo "Baseline check: $BASE_CHECK s" +echo "Baseline build: $BASE_BUILD s" +echo "Patched check: $PAT_CHECK s" +echo "Patched build: $PAT_BUILD s" + diff --git a/script/cleanup-worktrees.sh b/script/cleanup-worktrees.sh new file mode 100755 index 00000000000000..8161b1ab160867 --- /dev/null +++ b/script/cleanup-worktrees.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Clean up stale/prunable worktrees and empty benchmark directories. + +ROOT_DIR=$(cd -- "$(dirname -- "$0")/.." && pwd) +cd "$ROOT_DIR" + +echo "=== git worktree prune -v ===" +git worktree prune -v || true + +echo "=== Removing empty target/bench-* directories ===" +shopt -s nullglob +for d in "$ROOT_DIR"/target/bench-*; do + if [[ -d "$d" && -z "$(ls -A "$d" 2>/dev/null || true)" ]]; then + rm -rf "$d" + echo "Removed empty: $d" + fi +done +shopt -u nullglob + +echo "Done." + diff --git a/script/gstart.sh b/script/gstart.sh new file mode 100755 index 00000000000000..7578fa7b4512cd --- /dev/null +++ b/script/gstart.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Idempotent one-shot: ensure repo is configured, then create a new worktree from +# latest upstream base and apply the current cumulative checkpoint, and push. + +ROOT_DIR=$(cd -- "$(dirname -- "$0")/.." && pwd) +cd "$ROOT_DIR" + +script/setup-repo.sh --no-fetch || true +OUT=$(script/new-worktree-apply-cumulative.sh --push "$@") +echo "$OUT" + +WT=$(echo "$OUT" | sed -n 's/^WORKTREE=\(.*\)$/\1/p' | tail -n1) +BR=$(echo "$OUT" | sed -n 's/^BRANCH=\(.*\)$/\1/p' | tail -n1) + +echo +echo "=== gstart complete ===" +echo "Branch: ${BR:-unknown}" +echo "Worktree: ${WT:-unknown}" +if [[ -n "${WT:-}" && -d "$WT" ]]; then + echo "Next: cd \"$WT\" && codex" + echo "Then ask the agent to read: README.md, AGENTS.md, and docs/patch_workflow.md" +fi + diff --git a/script/new-worktree-apply-cumulative.sh b/script/new-worktree-apply-cumulative.sh new file mode 100755 index 00000000000000..400dc0c9bf4a15 --- /dev/null +++ b/script/new-worktree-apply-cumulative.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Create a new worktree from latest upstream base and apply the cumulative checkpoint, then any deltas. +# Usage: script/new-worktree-apply-cumulative.sh [--patch ] [--branch ] [--base auto|main|nightly] [--push] + +ROOT_DIR=$(cd -- "$(dirname -- "$0")/.." && pwd) +cd "$ROOT_DIR" + +PATCH_DIR=".reapply-patches/macOS-modernization" +LATEST_CUM_PATCH="" +if ls -1 "$PATCH_DIR"/*-cumulative.patch >/dev/null 2>&1; then + LATEST_CUM_PATCH=$(ls -1 "$PATCH_DIR"/*-cumulative.patch | sort | tail -n1) +fi + +PATCH_PATH="${LATEST_CUM_PATCH:-}" +BRANCH_NAME="" +BASE_MODE="auto" +DO_PUSH=0 + +while [[ $# -gt 0 ]]; do + case "$1" in + --patch) PATCH_PATH="$2"; shift 2;; + --branch) BRANCH_NAME="$2"; shift 2;; + --base) BASE_MODE="$2"; shift 2;; + --push) DO_PUSH=1; shift;; + -h|--help) echo "Usage: $0 [--patch ] [--branch ] [--base auto|main|nightly] [--push]"; exit 0;; + *) echo "Unknown arg: $1" >&2; exit 1;; + esac +done + +if [[ -z "$PATCH_PATH" || ! -f "$PATCH_PATH" ]]; then + echo "Cumulative patch not found. Specify with --patch or ensure one exists in $PATCH_DIR" >&2 + exit 1 +fi + +if [[ "${PATCH_PATH:0:1}" == "/" ]]; then + PATCH_ABS="$PATCH_PATH" +else + PATCH_ABS="$ROOT_DIR/$PATCH_PATH" +fi + +pick_base() { + local mode="$1"; local main_ref="upstream/main"; local nightly_ref="upstream/nightly"; local nightly_tag="refs/tags/nightly" + if [[ "$mode" == "main" ]]; then echo "$main_ref"; return; fi + if [[ "$mode" == "nightly" ]]; then + git rev-parse -q --verify "$nightly_ref" >/dev/null && { echo "$nightly_ref"; return; } + git rev-parse -q --verify "$nightly_tag" >/dev/null && { echo "$nightly_tag"; return; } + echo "$main_ref"; return + fi + local main_ts=0 night_ts=0 night_ref="" + git rev-parse -q --verify "$main_ref" >/dev/null && main_ts=$(git log -1 --format=%ct "$main_ref" || echo 0) + if git rev-parse -q --verify "$nightly_ref" >/dev/null; then night_ref="$nightly_ref"; night_ts=$(git log -1 --format=%ct "$nightly_ref" || echo 0) + elif git rev-parse -q --verify "$nightly_tag" >/dev/null; then night_ref="$nightly_tag"; night_ts=$(git log -1 --format=%ct "$nightly_tag" || echo 0); fi + if [[ -n "$night_ref" && $night_ts -gt $main_ts ]]; then echo "$night_ref"; else echo "$main_ref"; fi +} + +git fetch upstream --tags --prune >/dev/null 2>&1 || true +BASE_REF=$(pick_base "$BASE_MODE") +BASE_SHORT=$(git rev-parse --short "$BASE_REF") + +if [[ -z "$BRANCH_NAME" ]]; then BRANCH_NAME="macOS-modernization-apply-$(date +%Y%m%d-%H%M%S)"; fi + +WT_DIR="$ROOT_DIR/worktrees/$BRANCH_NAME" +mkdir -p "$ROOT_DIR/worktrees" +echo "Creating worktree: $WT_DIR (branch $BRANCH_NAME) from $BASE_REF ($BASE_SHORT)" +GIT_DIR="$(git rev-parse --git-dir)" git worktree add "$WT_DIR" "$BASE_REF" -b "$BRANCH_NAME" >/dev/null + +pushd "$WT_DIR" >/dev/null +if git apply --check "$PATCH_ABS" >/dev/null 2>&1; then + git apply --index --whitespace=fix "$PATCH_ABS" +else + git apply --3way --index --whitespace=fix "$PATCH_ABS" +fi +git commit -m "macOS: apply $(basename "$PATCH_ABS")" + +# Apply deltas after checkpoint (use CHECKPOINT.COVERS to filter) +PATCH_DIR_ABS="$ROOT_DIR/.reapply-patches/macOS-modernization" +CHECKPOINT_FILE="$PATCH_DIR_ABS/CHECKPOINT" +SERIES_COVERED="0000" +if [[ -f "$CHECKPOINT_FILE" ]]; then + SERIES_COVERED=$(awk -F= '/^COVERS=/{print $2}' "$CHECKPOINT_FILE" 2>/dev/null | tr -d '\r\n' || echo "0000") +fi +apply_deltas=() +for p in "$PATCH_DIR_ABS"/00*.patch; do + [[ -f "$p" ]] || continue + base=$(basename "$p") + num=$(printf "%s" "$base" | sed -E 's/^([0-9]{4}).*/\1/') + if [[ -n "$num" ]] && ((10#$num > 10#$SERIES_COVERED)); then + apply_deltas+=("$p") + fi +done +if [[ ${#apply_deltas[@]} -gt 0 ]]; then + git am -3 "${apply_deltas[@]}" +fi + +if [[ $DO_PUSH -eq 1 ]]; then git push -u origin "$BRANCH_NAME"; fi +popd >/dev/null + +echo "WORKTREE=$WT_DIR" +echo "BRANCH=$BRANCH_NAME" + +exit 0 + diff --git a/script/new-worktree.sh b/script/new-worktree.sh new file mode 100755 index 00000000000000..9eef742984fc0f --- /dev/null +++ b/script/new-worktree.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Create a new worktree branch from latest upstream base. +# Usage: script/new-worktree.sh --branch [--base auto|main|nightly] + +ROOT_DIR=$(cd -- "$(dirname -- "$0")/.." && pwd) +cd "$ROOT_DIR" + +BRANCH_NAME="" +BASE_MODE="auto" + +while [[ $# -gt 0 ]]; do + case "$1" in + --branch) BRANCH_NAME="$2"; shift 2;; + --base) BASE_MODE="$2"; shift 2;; + -h|--help) echo "Usage: $0 --branch [--base auto|main|nightly]"; exit 0;; + *) echo "Unknown arg: $1" >&2; exit 1;; + esac +done + +pick_base() { + local mode="$1"; local main_ref="upstream/main"; local nightly_ref="upstream/nightly"; local nightly_tag="refs/tags/nightly" + if [[ "$mode" == "main" ]]; then echo "$main_ref"; return; fi + if [[ "$mode" == "nightly" ]]; then + git rev-parse -q --verify "$nightly_ref" >/dev/null && { echo "$nightly_ref"; return; } + git rev-parse -q --verify "$nightly_tag" >/dev/null && { echo "$nightly_tag"; return; } + echo "$main_ref"; return + fi + local main_ts=0 night_ts=0 night_ref="" + git rev-parse -q --verify "$main_ref" >/dev/null && main_ts=$(git log -1 --format=%ct "$main_ref" || echo 0) + if git rev-parse -q --verify "$nightly_ref" >/dev/null; then night_ref="$nightly_ref"; night_ts=$(git log -1 --format=%ct "$nightly_ref" || echo 0) + elif git rev-parse -q --verify "$nightly_tag" >/dev/null; then night_ref="$nightly_tag"; night_ts=$(git log -1 --format=%ct "$nightly_tag" || echo 0); fi + if [[ -n "$night_ref" && $night_ts -gt $main_ts ]]; then echo "$night_ref"; else echo "$main_ref"; fi +} + +git fetch upstream --tags --prune >/dev/null 2>&1 || true +BASE_REF=$(pick_base "$BASE_MODE") +BASE_SHORT=$(git rev-parse --short "$BASE_REF") + +if [[ -z "$BRANCH_NAME" ]]; then echo "--branch required" >&2; exit 1; fi + +WT_DIR="$ROOT_DIR/worktrees/$BRANCH_NAME" +mkdir -p "$ROOT_DIR/worktrees" + +echo "Creating worktree: $WT_DIR (branch $BRANCH_NAME) from $BASE_REF ($BASE_SHORT)" +GIT_DIR="$(git rev-parse --git-dir)" git worktree add "$WT_DIR" "$BASE_REF" -b "$BRANCH_NAME" >/dev/null +echo "Done: $WT_DIR" + diff --git a/script/setup-repo.sh b/script/setup-repo.sh new file mode 100755 index 00000000000000..ee33868a20f921 --- /dev/null +++ b/script/setup-repo.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +set -euo pipefail + +# One-time or per-session setup for this repo to enable a worktree-first workflow +# and patch management helpers. +# +# Usage: +# script/setup-repo.sh [--apply-checkpoint] [--push] [--branch ] [--base auto|main|nightly] +# [--no-fetch] + +ROOT_DIR=$(cd -- "$(dirname -- "$0")/.." && pwd) +cd "$ROOT_DIR" + +DO_APPLY=0 +DO_PUSH=0 +BRANCH_NAME="" +BASE_MODE="auto" +DO_FETCH=1 + +while [[ $# -gt 0 ]]; do + case "$1" in + --apply-checkpoint) DO_APPLY=1; shift;; + --push) DO_PUSH=1; shift;; + --branch) BRANCH_NAME="$2"; shift 2;; + --base) BASE_MODE="$2"; shift 2;; + --no-fetch) DO_FETCH=0; shift;; + -h|--help) echo "Usage: $0 [--apply-checkpoint] [--push] [--branch ] [--base auto|main|nightly] [--no-fetch]"; exit 0;; + *) echo "Unknown arg: $1" >&2; exit 1;; + esac +done + +# hooks +git config --local core.hooksPath .githooks || true + +# patch-friendly git config +git config --local am.threeWay true || true +git config --local apply.whitespace fix || true +git config --local rerere.enabled true || true + +# aliases +git config --local alias.wtn "!script/new-worktree.sh --branch" || true +git config --local alias.wta "!script/new-worktree-apply-cumulative.sh" || true +git config --local alias.gta "!script/new-worktree-apply-cumulative.sh --push" || true +git config --local alias.wtl "!git worktree list -v" || true +git config --local alias.wtr "!script/cleanup-worktrees.sh" || true +git config --local alias.sts "!script/setup-repo.sh" || true +git config --local alias.gstart "!script/gstart.sh" || true + +# ensure executables +chmod +x \ + script/new-worktree.sh \ + script/new-worktree-apply-cumulative.sh \ + script/apply-cumulative.sh \ + script/cleanup-worktrees.sh \ + script/bench-macos.sh \ + script/gstart.sh 2>/dev/null || true + +if [[ $DO_FETCH -eq 1 ]]; then + git fetch upstream --tags --prune >/dev/null 2>&1 || true + git fetch origin --tags --prune >/dev/null 2>&1 || true +fi + +if [[ $DO_APPLY -eq 1 ]]; then + cmd=( script/new-worktree-apply-cumulative.sh --base "$BASE_MODE" ) + [[ -n "$BRANCH_NAME" ]] && cmd+=( --branch "$BRANCH_NAME" ) + [[ $DO_PUSH -eq 1 ]] && cmd+=( --push ) + "${cmd[@]}" +fi + +echo "Setup complete." + diff --git a/script/uninstall.sh b/script/uninstall.sh old mode 100644 new mode 100755 From 52d6a0de8f3767f9204a23d3fdcc3929f6a02ef0 Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Wed, 17 Sep 2025 12:30:15 +0800 Subject: [PATCH 03/38] patches: re-add macOS modernization checkpoint (20250917) with CHECKPOINT; wire scripts to use it on main --- .../20250917-cumulative.patch | 14906 ++++++++++++++++ .../macOS-modernization/CHECKPOINT | 2 + .../macOS-modernization/README.md | 11 + 3 files changed, 14919 insertions(+) create mode 100644 .reapply-patches/macOS-modernization/20250917-cumulative.patch create mode 100644 .reapply-patches/macOS-modernization/CHECKPOINT create mode 100644 .reapply-patches/macOS-modernization/README.md diff --git a/.reapply-patches/macOS-modernization/20250917-cumulative.patch b/.reapply-patches/macOS-modernization/20250917-cumulative.patch new file mode 100644 index 00000000000000..8f607b5a2bed32 --- /dev/null +++ b/.reapply-patches/macOS-modernization/20250917-cumulative.patch @@ -0,0 +1,14906 @@ +diff --git a/.gitea/workflows/auto-open-prs.yml b/.gitea/workflows/auto-open-prs.yml +new file mode 100644 +index 0000000000..47fd60bfd5 +--- /dev/null ++++ b/.gitea/workflows/auto-open-prs.yml +@@ -0,0 +1,73 @@ ++# Auto-open a pull request into the default branch when a non-default branch is pushed. ++# ++# Requirements: ++# - Repository secret GITEA_TOKEN with API scope that can open PRs on this fork. ++# - Optional repository variable DEFAULT_BRANCH to override the default branch name (defaults to "main"). ++ ++name: Auto Open PRs ++ ++on: ++ push: ++ branches-ignore: ++ - main ++ - master ++ workflow_dispatch: {} ++ ++jobs: ++ open-pr: ++ runs-on: docker ++ env: ++ DEFAULT_BRANCH: ${{ vars.DEFAULT_BRANCH || 'main' }} ++ steps: ++ - name: Derive server, repo, and branch ++ id: drv ++ shell: bash ++ run: | ++ set -euo pipefail ++ SERVER_URL="${GITHUB_SERVER_URL:-${GITEA_SERVER_URL:-}}" ++ REPO_PATH="${GITHUB_REPOSITORY:-${GITEA_REPOSITORY:-}}" ++ # Branch name from ref variables ++ BR="${GITHUB_REF_NAME:-${GITEA_REF_NAME:-}}" ++ if [ -z "$BR" ]; then ++ REF="${GITHUB_REF:-${GITEA_REF:-}}" ++ BR="${REF##refs/heads/}" ++ fi ++ if [ -z "$SERVER_URL" ] || [ -z "$REPO_PATH" ] || [ -z "$BR" ]; then ++ echo "Missing SERVER_URL, REPO_PATH or branch name from env." >&2 ++ exit 1 ++ fi ++ echo "SERVER_URL=$SERVER_URL" >> "$GITHUB_OUTPUT" ++ echo "REPO_PATH=$REPO_PATH" >> "$GITHUB_OUTPUT" ++ echo "PUSH_BRANCH=$BR" >> "$GITHUB_OUTPUT" ++ echo "Default branch: $DEFAULT_BRANCH; Push branch: $BR" >&2 ++ ++ - name: Skip default branch ++ if: ${{ steps.drv.outputs.PUSH_BRANCH == env.DEFAULT_BRANCH }} ++ run: echo "Push to default branch; nothing to do." >&2 ++ ++ - name: Ensure PR exists or create ++ if: ${{ steps.drv.outputs.PUSH_BRANCH != env.DEFAULT_BRANCH }} ++ shell: bash ++ env: ++ GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} ++ run: | ++ set -euo pipefail ++ API_BASE="${{ steps.drv.outputs.SERVER_URL }}/api/v1" ++ REPO="${{ steps.drv.outputs.REPO_PATH }}" ++ BRANCH="${{ steps.drv.outputs.PUSH_BRANCH }}" ++ # Check existing open PRs for this head branch ++ PRS=$(curl -sfSL -H "Authorization: token ${GITEA_TOKEN}" "${API_BASE}/repos/${REPO}/pulls?state=open") ++ # Try to detect if a PR for this head exists (head_branch may be present; fallback to scanning title/body for branch string) ++ if echo "$PRS" | grep -q "\"head_branch\"\s*:\s*\"$BRANCH\""; then ++ echo "PR already open for $BRANCH; skipping." >&2 ++ exit 0 ++ fi ++ TITLE="Auto-PR: $BRANCH -> $DEFAULT_BRANCH" ++ BODY="Automatically opened pull request for branch $BRANCH into $DEFAULT_BRANCH." ++ JSON_PAYLOAD=$(printf '{"title":"%s","body":"%s","head":"%s","base":"%s"}' \ ++ "$TITLE" "$BODY" "$BRANCH" "$DEFAULT_BRANCH") ++ curl -sfSL -X POST \ ++ -H "Content-Type: application/json" \ ++ -H "Authorization: token ${GITEA_TOKEN}" \ ++ "${API_BASE}/repos/${REPO}/pulls" \ ++ -d "$JSON_PAYLOAD" +diff --git a/.gitea/workflows/auto-rebase-prs.yml b/.gitea/workflows/auto-rebase-prs.yml +new file mode 100644 +index 0000000000..dd8e548620 +--- /dev/null ++++ b/.gitea/workflows/auto-rebase-prs.yml +@@ -0,0 +1,149 @@ ++# Auto-rebase open PR branches against the default branch (main by default). ++# ++# Requirements: ++# - Repository secret GITEA_TOKEN with API scope that can read PRs and push to branches in this fork. ++# - Optional repository variable DEFAULT_BRANCH to override the default branch name (defaults to "main"). ++# ++# Behavior: ++# - Lists open PRs in this repo. For PRs whose head branch is in this repo, ++# rebases the branch onto the default branch and force-pushes with lease. ++# - On rebase conflict, aborts and posts a comment on the PR asking for manual resolution. ++ ++name: Auto Rebase PRs ++ ++on: ++ schedule: ++ - cron: "*/30 * * * *" # every 30 minutes ++ workflow_dispatch: {} ++ ++jobs: ++ rebase: ++ runs-on: docker ++ env: ++ DEFAULT_BRANCH: ${{ vars.DEFAULT_BRANCH || 'main' }} ++ steps: ++ - name: Derive server and repo ++ id: drv ++ shell: bash ++ run: | ++ set -euo pipefail ++ SERVER_URL="${GITHUB_SERVER_URL:-${GITEA_SERVER_URL:-}}" ++ REPO_PATH="${GITHUB_REPOSITORY:-${GITEA_REPOSITORY:-}}" ++ if [ -z "$SERVER_URL" ] || [ -z "$REPO_PATH" ]; then ++ echo "Missing SERVER_URL or REPO_PATH from env (GITHUB_* or GITEA_*)" >&2 ++ exit 1 ++ fi ++ echo "SERVER_URL=$SERVER_URL" >> "$GITHUB_OUTPUT" ++ echo "REPO_PATH=$REPO_PATH" >> "$GITHUB_OUTPUT" ++ ++ - name: Prepare repository clone ++ shell: bash ++ run: | ++ set -euo pipefail ++ git init work ++ cd work ++ git config user.name "gitea-actions" ++ git config user.email "actions@localhost" ++ ORIGIN_URL="${{ steps.drv.outputs.SERVER_URL }}/${{ steps.drv.outputs.REPO_PATH }}.git" ++ git remote add origin "$ORIGIN_URL" ++ git fetch --prune origin ++ git checkout -B "$DEFAULT_BRANCH" "origin/$DEFAULT_BRANCH" || git checkout -B "$DEFAULT_BRANCH" ++ ++ - name: List open PRs ++ id: list ++ shell: bash ++ env: ++ GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} ++ run: | ++ set -euo pipefail ++ API_BASE="${{ steps.drv.outputs.SERVER_URL }}/api/v1" ++ REPO="${{ steps.drv.outputs.REPO_PATH }}" ++ AUTH=(-H "Authorization: token ${GITEA_TOKEN}") ++ curl -sfSL "${API_BASE}/repos/${REPO}/pulls?state=open" "${AUTH[@]}" > prs.json ++ echo "Pulled PR list:" >&2; wc -c prs.json >&2 || true ++ # Extract: pr_number, head_branch, base_branch, head_repo_full_name ++ python3 - << 'PY' < prs.json > pr_list.txt ++import sys, json ++data=json.load(sys.stdin) ++def repo_name(r): ++ if not r: ++ return '' ++ # Try common fields ++ return r.get('full_name') or ( ++ (r.get('owner',{}).get('login','') + '/' + r.get('name','')).strip('/') ++ ) ++for pr in data: ++ num = pr.get('number') or pr.get('index') ++ head = pr.get('head') if isinstance(pr.get('head'), str) else pr.get('head_branch') ++ base = pr.get('base') if isinstance(pr.get('base'), str) else pr.get('base_branch') ++ head_repo = repo_name(pr.get('head_repo') or pr.get('head_repo')) ++ print(f"{num}\t{head or ''}\t{base or ''}\t{head_repo}") ++PY ++ echo "PR list:" >&2; cat pr_list.txt >&2 || true ++ ++ - name: Rebase each PR branch ++ shell: bash ++ env: ++ GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} ++ run: | ++ set -euo pipefail ++ cd work ++ API_BASE="${{ steps.drv.outputs.SERVER_URL }}/api/v1" ++ REPO="${{ steps.drv.outputs.REPO_PATH }}" ++ while IFS=$'\t' read -r PR_NUM HEAD_BRANCH BASE_BRANCH HEAD_REPO; do ++ [ -n "$PR_NUM" ] || continue ++ # Skip if head branch is empty ++ if [ -z "$HEAD_BRANCH" ]; then ++ echo "PR #$PR_NUM: no head branch reported; skipping" >&2 ++ continue ++ fi ++ # Only rebase branches that live in this repo ++ if [ -n "$HEAD_REPO" ] && [ "$HEAD_REPO" != "${REPO}" ]; then ++ echo "PR #$PR_NUM: head repo is external ($HEAD_REPO); skipping" >&2 ++ continue ++ fi ++ echo "Rebasing PR #$PR_NUM branch '$HEAD_BRANCH' onto '$DEFAULT_BRANCH'" >&2 ++ git fetch origin "$DEFAULT_BRANCH" "$HEAD_BRANCH" || true ++ if ! git show-ref --verify --quiet "refs/remotes/origin/$HEAD_BRANCH"; then ++ echo "PR #$PR_NUM: origin/$HEAD_BRANCH not found; skipping" >&2 ++ continue ++ fi ++ git checkout -B "$HEAD_BRANCH" "origin/$HEAD_BRANCH" ++ set +e ++ git rebase "origin/$DEFAULT_BRANCH" ++ REBASE_STATUS=$? ++ set -e ++ if [ $REBASE_STATUS -ne 0 ]; then ++ echo "PR #$PR_NUM: rebase conflict; aborting and commenting" >&2 ++ git rebase --abort || true ++ # Post a comment ++ if [ -n "$GITEA_TOKEN" ]; then ++ COMMENT_PAYLOAD=$(printf '{"body":"Auto-rebase failed due to conflicts. Please rebase onto %s and resolve conflicts."}' "$DEFAULT_BRANCH") ++ curl -sfSL -X POST \ ++ -H "Content-Type: application/json" \ ++ -H "Authorization: token ${GITEA_TOKEN}" \ ++ "${API_BASE}/repos/${REPO}/issues/${PR_NUM}/comments" \ ++ -d "$COMMENT_PAYLOAD" || true ++ # Ensure a 'needs-rebase' label exists ++ LABELS_JSON=$(curl -sfSL -H "Authorization: token ${GITEA_TOKEN}" "${API_BASE}/repos/${REPO}/labels" || echo '[]') ++ LABEL_EXISTS=$(echo "$LABELS_JSON" | grep -i '"name"\s*:\s*"needs-rebase"' || true) ++ if [ -z "$LABEL_EXISTS" ]; then ++ curl -sfSL -X POST \ ++ -H "Content-Type: application/json" \ ++ -H "Authorization: token ${GITEA_TOKEN}" \ ++ "${API_BASE}/repos/${REPO}/labels" \ ++ -d '{"name":"needs-rebase","color":"#b60205"}' || true ++ fi ++ # Add label to the PR ++ curl -sfSL -X POST \ ++ -H "Content-Type: application/json" \ ++ -H "Authorization: token ${GITEA_TOKEN}" \ ++ "${API_BASE}/repos/${REPO}/issues/${PR_NUM}/labels" \ ++ -d '["needs-rebase"]' || true ++ fi ++ # Do not push in conflict case ++ continue ++ fi ++ echo "PR #$PR_NUM: rebase succeeded; pushing with lease" >&2 ++ git push --force-with-lease origin "$HEAD_BRANCH" ++ done < ../pr_list.txt +diff --git a/.gitea/workflows/sync-upstream.yml b/.gitea/workflows/sync-upstream.yml +new file mode 100644 +index 0000000000..657cc05ae6 +--- /dev/null ++++ b/.gitea/workflows/sync-upstream.yml +@@ -0,0 +1,108 @@ ++# Sync upstream main from the mirror into this fork, and open a PR when a fast-forward is not possible. ++# ++# Requirements (set in your fork repository settings): ++# - Repository secret GITEA_TOKEN with API scope that can push and open PRs on this fork. ++# - Repository secret UPSTREAM_REPO set to the path of the upstream mirror inside this Gitea instance, ++# for example: "org/zed-mirror" (without .git). ++# - Optional repository variable DEFAULT_BRANCH to override the default branch name (defaults to "main"). ++# ++# This workflow assumes the mirror repository (UPSTREAM_REPO) is already auto-synced from the real upstream. ++ ++name: Sync Upstream ++ ++on: ++ schedule: ++ - cron: "*/30 * * * *" # every 30 minutes ++ workflow_dispatch: {} ++ ++jobs: ++ sync-upstream: ++ runs-on: docker ++ env: ++ DEFAULT_BRANCH: ${{ vars.DEFAULT_BRANCH || 'main' }} ++ steps: ++ - name: Derive server and repo ++ id: drv ++ shell: bash ++ run: | ++ set -euo pipefail ++ # Prefer GitHub-compatible vars provided by Gitea Actions, fallback to Gitea-specific ones ++ SERVER_URL="${GITHUB_SERVER_URL:-${GITEA_SERVER_URL:-}}" ++ REPO_PATH="${GITHUB_REPOSITORY:-${GITEA_REPOSITORY:-}}" ++ if [ -z "$SERVER_URL" ] || [ -z "$REPO_PATH" ]; then ++ echo "Missing SERVER_URL or REPO_PATH from env (GITHUB_* or GITEA_*)" >&2 ++ exit 1 ++ fi ++ echo "SERVER_URL=$SERVER_URL" >> "$GITHUB_OUTPUT" ++ echo "REPO_PATH=$REPO_PATH" >> "$GITHUB_OUTPUT" ++ ++ - name: Prepare repository ++ shell: bash ++ run: | ++ set -euo pipefail ++ git init sync-work ++ cd sync-work ++ git config user.name "gitea-actions" ++ git config user.email "actions@localhost" ++ ORIGIN_URL="${{ steps.drv.outputs.SERVER_URL }}/${{ steps.drv.outputs.REPO_PATH }}.git" ++ git remote add origin "$ORIGIN_URL" ++ git fetch --prune origin ++ git checkout -B "$DEFAULT_BRANCH" "origin/$DEFAULT_BRANCH" || git checkout -B "$DEFAULT_BRANCH" ++ ++ - name: Add upstream and fetch ++ shell: bash ++ env: ++ UPSTREAM_REPO: ${{ secrets.UPSTREAM_REPO }} ++ run: | ++ set -euo pipefail ++ if [ -z "${UPSTREAM_REPO:-}" ]; then ++ echo "Secret UPSTREAM_REPO not set (expected '/')" >&2 ++ exit 1 ++ fi ++ cd sync-work ++ UPSTREAM_URL="${{ steps.drv.outputs.SERVER_URL }}/$UPSTREAM_REPO.git" ++ if git remote get-url upstream >/dev/null 2>&1; then ++ git remote set-url upstream "$UPSTREAM_URL" ++ else ++ git remote add upstream "$UPSTREAM_URL" ++ fi ++ git fetch --prune upstream ++ ++ - name: Fast-forward or open PR ++ shell: bash ++ env: ++ GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} ++ run: | ++ set -euo pipefail ++ cd sync-work ++ if git merge --ff-only "upstream/$DEFAULT_BRANCH"; then ++ echo "Fast-forward merge succeeded. Pushing main." >&2 ++ git push origin "$DEFAULT_BRANCH" ++ exit 0 ++ fi ++ ++ # Create a sync branch with a regular merge (may leave conflicts to be resolved in PR) ++ BR="sync/upstream-$(date -u +%Y%m%d%H%M%S)" ++ git checkout -B "$BR" ++ set +e ++ git merge "upstream/$DEFAULT_BRANCH" ++ MERGE_STATUS=$? ++ set -e ++ git push -u origin "$BR" ++ ++ # Open a PR into main on this fork ++ if [ -z "${GITEA_TOKEN:-}" ]; then ++ echo "Secret GITEA_TOKEN not set; cannot open PR automatically." >&2 ++ exit 0 ++ fi ++ API_BASE="${{ steps.drv.outputs.SERVER_URL }}/api/v1" ++ REPO="${{ steps.drv.outputs.REPO_PATH }}" ++ TITLE="Sync upstream into $DEFAULT_BRANCH ($BR)" ++ BODY="Upstream: ${{ secrets.UPSTREAM_REPO }} | Branch: $BR | Merge status: $MERGE_STATUS" ++ JSON_PAYLOAD=$(printf '{"title":"%s","body":"%s","head":"%s","base":"%s"}' \ ++ "$TITLE" "$BODY" "$BR" "$DEFAULT_BRANCH") ++ curl -sfSL -X POST \ ++ -H "Content-Type: application/json" \ ++ -H "Authorization: token ${GITEA_TOKEN}" \ ++ "${API_BASE}/repos/${REPO}/pulls" \ ++ -d "$JSON_PAYLOAD" +diff --git a/AGENTS.md b/AGENTS.md +new file mode 100644 +index 0000000000..3818552dba +--- /dev/null ++++ b/AGENTS.md +@@ -0,0 +1,644 @@ ++# Zed Build Fixes and Agent Notes ++ ++This document tracks the work done by agents to get the Zed workspace building locally, plus the rationale, validation steps, and next actions. Error and warning outputs are kept separately (see `zed_build_issues.md`); this file focuses on what changed and why. ++ ++## Overview ++ ++- Target: Build the `zed` workspace locally without errors. ++- Primary blocker identified: `jupyter-websocket-client` failed to compile due to unresolved imports from `async-tungstenite` and a follow‑on type mismatch caused by two different `async-tungstenite` versions in the dependency graph. ++- Approach: Enable the correct feature on `async-tungstenite` v0.31.0 required by `jupyter-websocket-client`, and isolate type identity by importing that version via an alias in the `repl` crate where the websocket types are used. ++ ++## Current State (macOS platform + typed prep) ++ ++- Cocoa trait shims have been removed from mac menus. We now use raw Objective‑C (`msg_send`) consistently for `NSMenu`/`NSMenuItem` construction and wiring, with immediate item addition to ensure correct retention. ++- `objc2` is enabled unconditionally on macOS; we removed it from feature lists that implied optional use to avoid dependency/feature mismatches. We have not yet switched the macro family globally in platform.rs to `objc2::msg_send!`/`msg_send_id!` to keep changes safe and incremental. ++- icrate typed constants are in use across mac modules where they bring clarity and safety without heavy bridging (e.g., scroller style, event flags, pasteboard types, appearance names). ++- Workspace clippy is clean after targeted fixes in `collab`. ++ ++## Changes Since Last Update ++ ++- Menus (platform.rs): ++ - Replaced Cocoa shims with raw Objective‑C for `NSMenu`/`NSMenuItem` (create via `alloc/new/init` + `autorelease`). ++ - Added `add_menu_item(parent_menu, ...)` that creates separator/action/submenu/system items and immediately adds them to the parent (correct retention and simpler lifetimes). ++ - Replaced window/services menu wiring with `setWindowsMenu:` and `setServicesMenu:` (`msg_send!`). ++ - Removed the old `create_menu_item` helper; no callers remain. ++ ++- objc2 dependency (Cargo): ++ - Made `objc2` non‑optional on macOS and removed it from the `macos-blade` feature set. ++ - Enabled icrate features for NSMenu/NSMenuItem/NSStatusBar/NSScroller to support typed usage. ++ ++- Other mac modules: ++ - status_item.rs: using icrate `NSSquareStatusItemLength` and `NSViewLayerContentsRedrawDuringViewResize`. ++ - window_appearance.rs: switched to icrate `NSAppearanceName*` and localized unsafe. ++ - events.rs: localized unsafe blocks around typed getters; removed unnecessary casts. ++ ++- collab crate (clippy blockers): ++ - Removed conflicting manual `Nullable` impl in ids.rs; disambiguated `to_string` calls in queries and tests to avoid trait collisions with `sea_orm::Iden`. ++ ++## Swift AppKit Migration (C ABI) — macOS Native UI ++ ++Objective: Replace Cocoa/objc2/icrate-heavy call sites in gpui with Swift-native AppKit code accessed through a minimal, explicit C ABI. Keep Rust as the core controller (data models, logic, callbacks); Swift owns AppKit object lifetimes and main-thread UI. ++ ++Scope completed in this pass: ++- Menus (macOS): Build full NSMenu in Swift from a JSON spec; route actions/validation/will-open back to Rust. ++- Panels: Replace `NSOpenPanel`/`NSSavePanel` msg_send! flows with Swift-native presenters + JSON callbacks. ++- Pasteboard: Add Swift helpers for text and images (UTI-based) and prefer them from Rust; retain legacy fallback when metadata is present. ++- Status Item: Add Swift C-ABI for basic create/title/remove and hook a click callback into Rust (not yet routed to a consumer). ++ ++### Swift package and exported C ABI ++ ++- Location: `crates/macos_appkit_bridge/swift` (SwiftPM package) ++- Build: `crates/macos_appkit_bridge/build.rs` compiles the package (`swift build -c release`) and links static lib + `AppKit`. ++- Exported symbols (selected): ++ - Menus: `zed_register_menu_handler()`, `zed_set_main_menu_json(const char*)` ++ - Panels: `zed_open_panel(uint64_t req_id, const char* json)`, `zed_save_panel(uint64_t req_id, const char* json)` ++ - Pasteboard (text): `zed_pasteboard_write_text(const char*)`, `zed_pasteboard_read_text() -> char*` ++ - Pasteboard (image): `zed_pasteboard_write_image(const uint8_t*, size_t, const char* uti)`, `zed_pasteboard_read_image(const char* uti, size_t* out_len) -> uint8_t*` ++ - Status Item: `zed_status_item_create() -> uint64_t`, `zed_status_item_set_title(uint64_t, const char*)`, `zed_status_item_set_image(uint64_t, const uint8_t*, size_t, const char* uti, bool isTemplate)`, `zed_status_item_set_menu(uint64_t, const char* json)`, `zed_status_item_remove(uint64_t)` ++- Swift → Rust callbacks: ++ - Menus: `gpui_menu_action(uint64_t tag)`, `gpui_validate_menu_action(uint64_t tag) -> bool`, `gpui_menu_will_open()` ++ - Panels: `gpui_open_panel_result(uint64_t req_id, const char* json)`, `gpui_save_panel_result(uint64_t req_id, const char* json)` ++ - Status Item: `gpui_status_item_clicked(uint64_t id)`, `gpui_status_item_menu_action(uint64_t id, uint64_t tag)` ++ ++### Rust integration changes ++ ++- Menus (gpui/platform.rs): ++ - Serialize full menu tree with tags, key equivalents, and modifiers from Keymap. ++ - Send to Swift via `zed_set_main_menu_json`; store `menu_actions` in order so `tag == index`. ++ - Implement callbacks: ++ - `gpui_menu_action` looks up `menu_actions[tag]` and calls `menu_command`. ++ - `gpui_validate_menu_action` calls `validate_menu_command`. ++ - `gpui_menu_will_open` calls `will_open_menu`. ++ ++- Panels: ++ - `prompt_for_paths`/`prompt_for_new_path` now call `zed_open_panel`/`zed_save_panel`. ++ - Use `OnceLock + Mutex>` to await results; `gpui_open_panel_result`/`gpui_save_panel_result` parse JSON and fulfill. ++ - Removed `NSOpenPanel`/`NSSavePanel` legacy flows and imports. ++ ++- Pasteboard: ++ - Prefer Swift text read/write for simple strings; keep legacy path for metadata-backed writes and reads (to preserve existing behavior). ++ - Prefer Swift image read/write using UTIs; legacy fallback retained. ++ ++- Status Item: ++ - Thin Rust wrapper (`crates/gpui/src/platform/mac/status_item.rs`) now calls `zed_status_item_{create,set_title,remove}`. ++ - Exported `gpui_status_item_clicked(id)` in Rust (currently no-op); will be wired to a Rust handler map. ++ - Removed legacy Cocoa subclass/rendering code from status_item.rs. ++ ++### JSON contracts ++ ++- Menus: ++ - `{"menus":[{"title":"File","items":[{"kind":"action","title":"Open","tag":1,"key_equivalent":"o","modifiers":["command"]},{"kind":"separator"},{"kind":"submenu","title":"Recent","items":[...]},{"kind":"system","title":"Services","system_type":"services","items":[]}]}]}` ++ - Swift builds NSMenu/NSMenuItem tree; wires `services` to `NSApp.servicesMenu`, `Window` top-level title wires `NSApp.windowsMenu`. ++- Open Panel request: `{ "directories": bool, "files": bool, "multiple": bool, "prompt"?: string }` ++ - Response: `{ "paths": ["/path/one", ...] }` or `{ "paths": null }` ++- Save Panel request: `{ "directory": "/dir", "suggested_name"?: "name" }` ++ - Response: `{ "path": "/path" }` or `{ "path": null }` ++ - Parity: Sequoia filename fix applied on Rust side for OS ≥ 15. ++ ++- Status item menu: ++ - Request: `{ "items": [ {"kind":"action","title":"...","tag":1}, {"kind":"submenu","title":"...","items":[...]}, {"kind":"separator"} ] }` ++ - Clicks: `gpui_status_item_menu_action(id, tag)`; Rust dispatches to the same `menu_command` callback used by app menus. ++ ++### Validation ++ ++- macOS local: `cargo fmt`, `cargo check`, and `cargo clippy -p gpui --all-targets` pass after the changes. ++- Swift package builds via build.rs and links statically. ++- Functionality validated end-to-end for menu action routing and basic panel flows. ++ ++## Remaining Work / Plan (High-level) ++ ++1) Status item clicks ++ - Maintain a map `status_item_handlers: HashMap>` in Rust. ++ - Expose `set_click_handler(&self, handler: Box)` on the Rust `StatusItem` wrapper. ++ - Implement `gpui_status_item_clicked(id)` to dispatch into the registered handler. ++ ++2) Status item image support ++ - Swift: add `zed_status_item_set_image(id, bytes*, len, uti, isTemplate: bool)` that creates an `NSImage` from PNG/other data; set `isTemplate` for proper dark/light rendering. ++ - Rust: add `StatusItem::set_image(&self, format: ImageFormat, bytes: &[u8], template: bool)` with UTI mapping, call Swift. ++ ++3) Cocoa cleanup (next passes) ++ - `window_appearance.rs`: reduce direct `cocoa` usage by relying on typed constants and minimize NSString bridging where possible; consider a small Swift helper if it simplifies name matching. ++ - `screen_capture.rs`: larger module; propose a focused pass to either (a) keep current Objective‑C runtime path but reduce unsafe surface, or (b) explore a Swift wrapper for ScreenCapture APIs. ++ - `metal_renderer.rs`: isolate AppKit/Cocoa usage and consider if any calls benefit from small Swift helpers; keep most Metal logic in Rust. ++ ++4) Menu system menu parity ++ - Consider emitting an explicit windows system menu in the JSON (`system_type: "windows"`) if/when the Rust model adds it, though we already wire by top-level title. ++ ++5) Pasteboard consolidation ++ - Consider migrating metadata-backed clipboard into Swift to fully eliminate legacy pasteboard paths, preserving hash-matching semantics. ++ ++## Risks & Mitigations ++ ++- ABI boundary errors (symbols, alloc/free): ++ - Mitigation: C strings are owned/freed explicitly; image pointers are adopted via `Vec::from_raw_parts` on Rust side; Swift uses `malloc/strdup` and Rust frees or adopts accordingly. ++- Main-thread constraints: ++ - Panels and UI are dispatched to main in Swift; avoids cross-thread UI bugs. ++- Behavior parity: ++ - Kept legacy fallbacks for pasteboard metadata and image formats to avoid regressions; plan to consolidate entirely to Swift once parity is confirmed. ++ ++## Definition of Done (this migration) ++ ++- Menus, panels, pasteboard, and status items operate through Swift with no Cocoa usage in those Rust paths. ++- All callbacks from Swift route cleanly to Rust handlers. ++- Remaining legacy Cocoa usage is documented and planned for focused follow-ups. ++ ++--- ++ ++## Immediate TODOs ++ ++- Status Item click routing ++ - [ ] Add Rust handler map and `set_click_handler` API; implement `gpui_status_item_clicked` dispatch. ++- Status Item image support ++ - [ ] Add Swift `zed_status_item_set_image(id, bytes, len, uti, isTemplate)`; add Rust `set_image` with UTI mapping. ++- Cocoa cleanup ++ - [ ] Reduce `window_appearance.rs` cocoa usage; consider Swift helper if needed. ++ - [ ] Plan a dedicated pass for `screen_capture.rs` and `metal_renderer.rs`. ++ ++ ++## Validation ++ ++- gpui: `cargo check -p gpui` passes. ++- gpui clippy: runs clean (`cargo clippy -p gpui --all-targets`). On macOS, shader compilation requires elevated permissions due to cache writes. ++- Workspace clippy: runs clean after `collab` fixes (`cargo clippy --workspace --all-targets`). ++ ++## Next: Typed objc2 Migration (unconditional on macOS) ++ ++We will adopt objc2 typed APIs (Retained, typed `msg_send!`/`msg_send_id!`) end‑to‑end in platform.rs, then re‑scan window.rs. To avoid macro/type mismatches, we will convert whole sections instead of splicing typed calls into objc macro regions. ++ ++### Phase 1 — Typed Menus ++ ++- Replace `NSMenu`/`NSMenuItem` creation with objc2 `msg_send_id!` and typed `Retained`. ++- Use objc2 `msg_send!` on typed receivers for setters (`setTitle:`, `setDelegate:`, `setSubmenu:`, `addItem:`). ++- Switch `title`/`keyEquivalent` to typed `NSString` (icrate Foundation) and remove Cocoa `ns_string` in these paths. ++- Keep raw `id` interop points localized only where the callee still expects it. ++ ++### Phase 2 — Typed NSString and Selectors ++ ++- Introduce a typed `NSString` constructor helper for platform.rs and use it across menu code. ++- Replace remaining Cocoa `NSString` usage in platform.rs where practical; ensure selectors are used from typed contexts where provided by icrate. ++ ++### Phase 3 — Beyond Menus ++ ++- Gradually migrate services hooks, open/save panels, pasteboard, and common NSApplication calls to objc2 typed APIs where icrate provides them, keeping behavior identical. ++- Replace `objc::msg_send!` in the converted sections with `icrate::objc2::msg_send!` to avoid mixing macro families. ++ ++### Phase 4 — window.rs Sweep ++ ++- Re‑scan for newly trivial typed replacements; confirm no regressions introduced by typed menu adoption. ++ ++## Risks, Mitigations, Rollback ++ ++- Risk: mixing objc and objc2 macro families in a single section can cause type mismatches (`Class` vs `AnyClass`) and private pointer usage. ++ - Mitigation: convert entire sections to objc2 at once and keep interop to raw `id` localized and minimal. ++- Risk: subtle retention/lifetime issues when switching to typed `Retained`. ++ - Mitigation: retain via immediate parent addition; keep ownership clear; lean on typed ownership where available. ++- Rollback: the current raw Objective‑C (msg_send) path is stable and can serve as a rollback if needed. ++ ++## Checklist Before Each Phase ++ ++- [ ] cargo fmt ++- [ ] cargo check -p gpui ++- [ ] cargo clippy -p gpui --all-targets (elevated permissions on macOS) ++- [ ] cargo clippy --workspace --all-targets ++- [ ] Update AGENTS.md with scope, changes, and validation ++## Root Cause Analysis ++ ++1) Feature gating in `async-tungstenite` 0.31.0 ++ ++- `jupyter-websocket-client` imports `async_tungstenite::tokio`, which is conditionally compiled behind the `tokio-runtime` feature in `async-tungstenite` v0.31.0. ++- That feature was not enabled by default in our graph, causing unresolved imports during compilation. ++ ++2) Multiple `async-tungstenite` versions in the workspace ++ ++- The workspace depends on `async-tungstenite` v0.29.1 (via `workspace.dependencies`). ++- `jupyter-websocket-client` depends on `async-tungstenite` v0.31.0. ++- When `repl` used `connect_async` and also consumed types produced by `jupyter-websocket-client`, we ended up with two different `WebSocketStream` types — one from 0.29.1 and one from 0.31.0. Even if the generics look the same, they are distinct types when compiled from different crate versions, yielding a type mismatch. ++ ++## Changes Implemented ++ ++Minimal, targeted fixes to restore the build without rippling changes across the whole workspace. ++ ++1) Add an alias dependency for `async-tungstenite` v0.31.0 in `repl` ++ ++File: `crates/repl/Cargo.toml` ++ ++```toml ++[dependencies] ++# Existing workspace dependency on 0.29.x remains for other crates. ++ ++# Alias pointing specifically at 0.31.0 with the required feature gate. ++async_tungstenite_031 = { package = "async-tungstenite", version = "0.31.0", default-features = false, features = ["tokio-runtime"] } ++``` ++ ++Why: ++- Ensures `async_tungstenite::tokio` module is compiled in v0.31.0 by enabling `tokio-runtime`. ++- Keeps the change narrowly scoped (only `repl`), avoiding potential breakage elsewhere. ++ ++2) Import the aliased `async-tungstenite` in `repl` ++ ++File: `crates/repl/src/kernels/remote_kernels.rs` ++ ++```rust ++// Before: ++// use async_tungstenite::tokio::connect_async; ++// use async_tungstenite::tungstenite::{client::IntoClientRequest, http::HeaderValue}; ++ ++// After: ++use async_tungstenite_031::tokio::connect_async; ++use async_tungstenite_031::tungstenite::{client::IntoClientRequest, http::HeaderValue}; ++``` ++ ++Why: ++- Guarantees that the `WebSocketStream` type and related symbols used in `repl` come from the same crate version as `jupyter-websocket-client` (0.31.0), eliminating cross‑version type mismatches. ++ ++## Validation ++ ++Steps used to validate the fix locally: ++ ++- Build the `repl` crate in isolation (fastest loop): ++ - `cargo check -p repl` ++- Build the main application crate: ++ - `cargo check -p zed` ++ ++Both checks pass. Remaining output consists of warnings already tracked elsewhere. ++ ++Helpful diagnostics: ++ ++- Inspect the dependency graph and features for `async-tungstenite`: ++ - `cargo tree -p repl -i async-tungstenite` ++ - `cargo tree -e features -p repl -i async-tungstenite` ++- Confirm where `async_tungstenite::tokio` comes from and which features enable it. ++ ++## Design Notes and Trade‑offs ++ ++- Minimal blast radius: We avoided bumping the workspace’s `async-tungstenite` version globally, which could introduce new incompatibilities across many crates. ++- Type identity: Importing the aliased 0.31.0 directly in `repl` ensures all websocket types match those expected by `jupyter-websocket-client`. ++- Alternative options considered: ++ - Global upgrade to `async-tungstenite` v0.31.0 in `[workspace.dependencies]` and removing the alias. This would need careful testing across `client`, `rpc`, and other crates that currently use 0.29.x. ++ - Wrapper type or newtype around the websocket stream to bridge versions. More code and maintenance for little gain versus aligning versions where needed. ++ - Upstream: add/ensure `tokio-runtime` is enabled for `jupyter-websocket-client` if appropriate for its default use cases. ++ ++## Follow‑ups / Backlog ++ ++- Unify `async-tungstenite` versions: ++ - Evaluate moving the entire workspace to `async-tungstenite` 0.31.x and adjust features (`tokio-runtime`, TLS options) to match current usage. ++ - Pros: fewer duplicate crates, fewer cross‑version type pitfalls. ++ - Cons: risk of breakage; needs a sweep of crates that rely on older behavior. ++ ++- macOS deprecation warnings: ++ - Source: usage of `cocoa` APIs in `gpui`, and previously in `fs` and `client`. ++ - Status: `client` and `fs` migrated off `cocoa` to use the Objective‑C runtime directly (`objc`), eliminating deprecation warnings without allowances. ++ - Next: migrate `gpui` away from `cocoa` toward `objc2` typed APIs (see plan below). While migrating, we can keep warnings muted to preserve a clean build, and remove allowances as we complete each module. ++ ++## Cocoa → objc2 Migration Plan (macOS) ++ ++Objective: Replace uses of the deprecated `cocoa` crate with modern Objective‑C bindings based on `objc2` (and/or `icrate`), eliminating deprecation warnings and improving type safety. ++ ++Strategy: Migrate incrementally per module, starting with leaf features and utility types, then high‑churn subsystems. Maintain a clean build throughout by gating warnings only on modules pending migration. ++ ++Phases: ++ ++1) Preparation ++ - Add `objc2` and `icrate` (or `objc2-foundation`/`objc2-app-kit` as appropriate) as macOS dependencies in `gpui`. ++ - Establish utility shims in `gpui::platform::mac` for common conversions (Rust `&str` ↔️ `NSString`, range/geometry types), backed by `objc2`. ++ - Document memory rules (retain/release/autorelease) and preferred patterns (`objc2::rc::Retained`, `autoreleasepool`). ++ ++2) Utility Types and Core Glue ++ - Replace `id`, `nil`, `NSRange`, `NSRect`, `NSSize`, and string helpers with `objc2`/`icrate` equivalents exposed from a central module. ++ - Update internal helpers to avoid `cocoa` imports; ensure `Encode` impls still work where needed. ++ ++3) Low-Risk Modules ++ - Migrate `attributed_string.rs`, `display.rs`, `display_link.rs` to `objc2`/`icrate`. ++ - Validate via `cargo check -p gpui` and run related unit tests. ++ ++4) Eventing and Input ++ - Migrate `events.rs` and `keyboard.rs` from `cocoa::appkit` to `icrate::AppKit` constants/types. ++ - Pay special attention to enum/constant shape changes; adjust matches accordingly. ++ ++5) Windowing and Rendering Surfaces ++ - Migrate `window.rs`, `window_appearance.rs`, `metal_*` integration away from `cocoa`. ++ - Align with existing `objc2` usage in the Blade renderer; prefer `objc2-metal` for Metal interop. ++ ++6) Cleanup and Enforcement ++ - Remove temporary deprecation allowances from `gpui` modules. ++ - Drop `cocoa` from `gpui` dependencies. ++ - Add CI check ensuring no `cocoa::` imports remain under macOS. ++ ++Validation at Each Step: ++ - `cargo check -p gpui` and `cargo check -p zed`. ++ - If available, run macOS smoke tests (launch, window open, basic input) to verify behavior. ++ ++Status Snapshot: ++ - `client`: migrated off `cocoa` (uses `objc`). ++ - `fs`: migrated off `cocoa` (uses `objc`). ++ - `gpui/events.rs`: migrated off `cocoa` using Objective‑C runtime (`objc`); currently uses numeric AppKit constants (event types, phases, modifier masks) for parity. Follow‑up: replace numerics with typed constants from `objc2`/`icrate` after aligning versions. ++ - `gpui/display.rs`, `gpui/attributed_string.rs`, `gpui/open_type.rs`: migrated off `cocoa`. ++ - `gpui/keyboard.rs`: already uses `objc` directly; no `cocoa` imports to replace. ++ - Remaining: `gpui/window_appearance.rs`, and any other mac‑specific modules that still import `cocoa`. ++ ++### Update: mac/window.rs migration (continued) ++ ++Scope: replace deprecated Cocoa trait calls with raw Objective‑C messaging while keeping behavior and performance. Keep types/bitmasks from Cocoa where needed to satisfy `objc::Encode` and avoid `icrate` feature‑gating pitfalls; plan to move to `objc2/icrate` typed APIs after version alignment. ++ ++Key changes: ++- Imports: favor `cocoa` for `NSWindowStyleMask`, `NSWindowOrderingMode`, `NSWindowCollectionBehavior`, `NSWindowButton`, `NSWindowTitleVisibility`, `NSRect/NSPoint/NSSize` (ensures `objc::Encode` for method hooks). Keep a minimal set from `icrate::AppKit` (`NSAppKitVersionNumber(_12_0)`, `NSBackingStoreBuffered`) and `icrate::Foundation` (`NSOperatingSystemVersion`, `NSInteger`, `NSUInteger`). ++- Autorelease pool: replace `NSAutoreleasePool::new(nil)` + `drain()` trait calls with `msg_send![class!(NSAutoreleasePool), new]` and `msg_send![pool, drain]`. ++- Visibility/occlusion: replace `occlusionState.contains(...)` with `isVisible` checks to avoid typed‑bitflag gating. ++- Style mask checks: where we previously branched on `NSFullSizeContentViewWindowMask`, compute the offset using `frame.size.height - contentLayoutRect.size.height` and apply it only when positive. This avoids brittle bitmask checks and preserves correctness. ++- Titlebar/traffic lights: continue to position buttons via `standardWindowButton:` and set frame via `msg_send!`; constants come from Cocoa (`NSWindowButton` and `CGRect/CGPoint`). ++- Tab/window behavior: replace `setCollectionBehavior_` and other Cocoa trait invocations with `msg_send!`. ++- File drag pasteboard: replace `NSPasteboard::propertyListForType` trait call with `msg_send![pasteboard, propertyListForType: NSFilenamesPboardType]` and iterate via `count`/`objectAtIndex:`; use `NSString::UTF8String` to extract Rust paths. ++- Blur/visual effect: avoid deprecated `AppearanceBased`. Initialize a `NSVisualEffectView` and set its state to active via `msg_send![view, setState: 1]` (parity with `NSVisualEffectStateActive`). Defer material selection to defaults for now; see follow‑up below. ++- Window control calls: replace trait calls (`miniaturize_`, `zoom_`, `close`, `setDelegate_`, `removeFromSuperview`) with `msg_send!` equivalents. ++ ++Notes and rationale: ++- Mixing `icrate` typed constants with raw `id` pointers often requires enabling per‑type features (e.g., `Foundation_NSAutoreleasePool`, `Foundation_NSProcessInfo`). To keep build green without broad dependency churn, we prefer Cocoa for constants/types while using `objc` for all method dispatch. ++- We removed local `NSRect/NSPoint/NSSize` structs and switched to Cocoa’s definitions to satisfy `objc::Encode` for method hooks like `setFrameSize:` and `firstRectForCharacterRange:actualRange:`. ++- For `NSVisualEffectView`, we used `setState:` only; moving to fully typed `icrate` enums (e.g., `NSVisualEffectMaterial`) is planned once we align `objc2/icrate` versions and features. ++ ++Validation: ++- `cargo check -p gpui` passes after these changes. Behavior parity retained in core paths: window creation, focus/activation, moving/resizing, drag‑and‑drop, key and mouse input, IME composition, and titlebar behavior. ++ ++Follow‑ups: ++- Replace numeric `setState: 1` with a typed constant from `icrate` (`NSVisualEffectState::Active`) when `objc2/icrate` versions are aligned and features enabled. ++- Audit remaining uses of Cocoa value types/constants and migrate to `objc2/icrate` where practical. ++- Consider reintroducing a precise fullscreen check via a robust source (either `icrate` bitflags or a different API) if we need to distinguish between zoomed vs. fullscreen in more places. ++ ++### mac/window.rs — Cocoa → icrate inventory (current) ++ ++- Migrated to icrate: ++ - Window style flags: `NSWindowStyleMask*` (Closable, Titled, Resizable, Miniaturizable, FullSizeContentView, NonactivatingPanel, FullScreen) ++ - Ordering: `NSWindowAbove`, `NSWindowBelow` ++ - Collection behavior: `NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorFullScreenAuxiliary` ++ - Title visibility: `NSWindowTitleHidden` ++ - Visual effect state: `NSVisualEffectStateActive` ++ - Window buttons: `NSWindowCloseButton`, `NSWindowMiniaturizeButton`, `NSWindowZoomButton` ++ - Tracking flags: `NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect` ++ - View redraw policy: `NSViewLayerContentsRedrawDuringViewResize` ++ - Pasteboard type: `NSFilenamesPboardType` ++ - Autoresizing mask: `NSViewWidthSizable | NSViewHeightSizable` ++ ++- Still using local equivalents (no named constants in icrate): ++ - Window levels: wrappers `WINDOW_LEVEL_NORMAL` (=0), `WINDOW_LEVEL_POPUP` (=101) typed as `NSWindowLevel`. ++ - Rationale: icrate provides `NSWindowLevel` alias but not named levels; wrappers document intent while keeping behavior. ++ ++### Coordinated updates ++ ++- NSOperatingSystemVersion: ++ - Replaced Cocoa with `icrate::Foundation::NSOperatingSystemVersion` in both `window.rs` and `platform.rs`. ++ - Constructed via struct literal `{ majorVersion, minorVersion, patchVersion }` and continue using `isOperatingSystemAtLeastVersion:` via `NSProcessInfo` with `msg_send!`. ++ ++Notes: ++- No remaining Cocoa enums/bitflags in `window.rs` that have direct icrate equivalents. ++- The code relies on `msg_send!` for behavior while using typed constants from icrate where available. ++ ++Additional notes: ++- `client/telemetry.rs` keeps a local `NSOperatingSystemVersion` struct to avoid adding an icrate dependency just to read version fields on macOS. There is no Cocoa trait usage in that module, so it’s fine to leave as-is. ++- In `window.rs`, we now rely on icrate for nearly all constants. The remaining window level values are wrapped in typed constants (`NSWindowLevel`) for safety and clarity. ++ ++### Other mac modules — icrate typed constants ++ ++- `events.rs`: migrated numeric event values to icrate typed constants. ++ - Event types: `NSEventType*` (e.g., `NSEventTypeKeyDown`, `NSEventTypeScrollWheel`, `NSEventTypeSwipe`). ++ - Modifier flags: `NSEventModifierFlag*` (CapsLock, Shift, Control, Option, Command, Function). ++ - Phases: `NSEventPhase*` (Began, Ended, MayBegin). ++ - Implementation detail: constants are mapped to local `const` u64 values via `as u64` to minimize code churn while preserving typed sources. ++ ++- `display.rs`: no Cocoa enums/bitflags were present; left logic using `NSScreen` + `deviceDescription` lookups with `msg_send!`. ++- `attributed_string.rs`: wrappers around `NSAttributedString`/`NSMutableAttributedString`; no enums/bitflags to migrate. ++ ++--- ++ ++## Compact Status Summary (for quick reference) ++ ++- Build fixes ++ - Resolved `async-tungstenite` version/feature mismatch via alias in `repl` and imports in `remote_kernels.rs`. ++ - Workspace builds cleanly; clippy run and resolved issues in updated files. ++ ++- macOS objc2/icrate migrations (completed to date) ++ - `window.rs` (core): moved to `msg_send!` calls; adopted icrate typed flags for style masks, ordering, collection behavior, title visibility, visual effect state, tracking, redraw, pasteboard type, autoresize. Added typed wrappers for window levels. ++ - `events.rs`: replaced raw numeric event types/modifiers/phases with icrate constants; adopted typed `NSEvent` getters (type, modifierFlags, isARepeat, buttonNumber, clickCount, deltaX, momentumPhase, scrollingDeltaX/Y, keyCode, locationInWindow). Kept `charactersIgnoringModifiers` via `msg_send!` intentionally (see Trade-offs). ++ - `platform.rs`: switched pasteboard types to icrate; interop with Cocoa methods via `as *const _ as id` casts (within `unsafe` for extern statics). Migrated `NSOperatingSystemVersion` to icrate. ++ - `display.rs`, `attributed_string.rs`, `keyboard.rs`: no Cocoa enums/bitflags to migrate; left logic intact. ++ ++- Version checks ++ - `NSOperatingSystemVersion` now from icrate in `window.rs` and `platform.rs`; struct literal used with `NSProcessInfo` `isOperatingSystemAtLeastVersion:`. ++ - `client/telemetry.rs` keeps a small local struct for OS version to avoid a new dependency (no Cocoa traits used). ++ ++- Trade-offs and intentional non-changes ++ - `events.rs` `charactersIgnoringModifiers`: converting to icrate `Id` would require additional bridging code. Current `NSStringExt` path is stable; we’ve left it for now. ++ - Occlusion handling: continued using `isVisible` instead of typed occlusion state to avoid bitflag gating churn; behavior unchanged. ++ ++- Remaining backlog (ordered) ++ - `events.rs`: clean up inner `unsafe` blocks reported as unnecessary; consider adopting typed NSString conversions if/when it improves clarity. ++ - `platform.rs`: evaluate further icrate adoption in menu/pasteboard read paths only if it doesn’t complicate Cocoa `id` interop. ++ - `window.rs`: optionally replace visibility checks with typed occlusion flags if parity remains guaranteed. ++ - Broader sweep: continue replacing ad-hoc Cocoa constants across mac modules where icrate exports equivalents, and keep documenting any interop casts. ++ ++Notes on Typed Constants in `events.rs`: ++- We attempted to switch to `objc2`/`icrate` typed constants for `NSEventType`, `NSEventPhase`, and `NSEventModifierFlags` but observed API shape differences and version skew (`icrate 0.1.2` depends on `objc2 0.5.x`, workspace has `objc2 0.6`). ++- Decision: keep the parity‑preserving numeric constants for now to maintain a green build. Action item: align `objc2`/`icrate` versions and replace numeric masks and values with typed constants in a focused follow‑up. ++ ++## Tips for Future Changes ++ ++- When a crate imports types from a dependency that uses a newer version of a common library (like `async-tungstenite`), ensure imports in the current crate come from the same version to avoid type mismatches. ++- Use Cargo package aliasing to pull in a specific version alongside a workspace‑wide version when a global upgrade is too risky. ++- To debug feature‑gated modules, check the crate’s source (on crates.io or in `~/.cargo/registry`) for `#[cfg(feature = "...")]` around the modules you need. ++ ++## Quick Reference ++ ++- Files changed: ++ - `crates/repl/Cargo.toml` ++ - `crates/repl/src/kernels/remote_kernels.rs` ++ ++- Key dependencies: ++ - `async-tungstenite` v0.29.1 (workspace‑wide) ++ - `async-tungstenite` v0.31.0 with `tokio-runtime` (aliased as `async_tungstenite_031` in `repl`) ++ - `jupyter-websocket-client` (pulls in 0.31.0) ++ ++- Common commands: ++ - `cargo check -p repl` ++ - `cargo check -p zed` ++ - `cargo build -p zed --release` ++ - `cargo tree -p repl -i async-tungstenite` ++ ++--- ++ ++Maintainers: If you want me to attempt a workspace‑wide upgrade to `async-tungstenite` 0.31.x, I can prepare a branch and a checklist for verification across affected crates. ++ ++## Dependency Unification and Upgrade Plan ++ ++Goal: ensure there is exactly one version of every dependency across the workspace, keep crates up to date, and resolve any issues that arise from upgrades. ++ ++### Guiding Principles ++ ++- Prefer a single, centrally declared version for each dependency in `[workspace.dependencies]`. ++- Avoid cross‑version type identities (e.g., two `WebSocketStream` types from different `async-tungstenite` versions). ++- Align ecosystems: Tokio + Tungstenite + TLS, Serde stack, Proc‑macro stack, Wasmtime stack, etc. ++- Keep changes small and verifiable; roll forward with incremental PRs. ++ ++### Tools ++ ++- Inventory duplicates: `cargo tree -d` ++- Explore features: `cargo tree -e features -i ` ++- Outdated dependencies: `cargo outdated -R` (install via `cargo install cargo-outdated`) ++- Batch upgrades: `cargo upgrade` (from `cargo-edit`; install via `cargo install cargo-edit`) ++- Duplicate/version policy in CI: `cargo deny check` (install via `cargo install cargo-deny`) ++ ++### Phase 0 — Preparation ++ ++- Add `cargo-deny` config to enforce single versions: ++ - Create `deny.toml` with `bans` configured to fail on multiple versions except for known, documented exceptions (e.g., build‑time proc‑macro stacks if unavoidable during transition). ++ - Add a CI job to run `cargo deny check bans licenses sources`. ++- Ensure local devs have `cargo-outdated` and `cargo-edit` installed. ++ ++### Phase 1 — Inventory and Target Versions ++ ++- Run `cargo tree -d` to list all duplicate versions. ++- Group duplicates by ecosystem and criticality: ++ - Core async stack: `tokio`, `async-tungstenite`, `tokio-tungstenite`, `tungstenite`, `rustls`, `tokio-rustls`. ++ - Serialization: `serde`, `serde_json`, `schemars`. ++ - Proc-macro toolchain: `syn`, `proc-macro2`, `quote`. ++ - HTTP: `reqwest`, `hyper`, `http`, TLS deps. ++ - Wasm/WASI: `wasmtime`, `wasmtime-wasi`, `wit-component`. ++ - Logging/telemetry: `tracing`, `log`. ++- For each group, select target versions: ++ - Prefer the latest compatible stable versions across the group (consult release notes). ++ - For crates pinned to git revisions or vendor forks (e.g., `reqwest`, tree‑sitter grammars), confirm whether to keep pins or move to crates.io releases. ++ ++### Phase 2 — Centralize Versions ++ ++- Move chosen versions into `[workspace.dependencies]` in the root `Cargo.toml`. ++- Update member `Cargo.toml` files to use `*.workspace = true` where possible. ++- Remove ad‑hoc version pins in leaf crates unless strictly necessary. ++- Use `[patch.crates-io]` or `[patch.'https://…']` only when needed to force a transitive dependency version; document why in comments. ++ ++### Phase 3 — Ecosystem Alignment (High‑Risk Areas) ++ ++- Async/WebSocket/TLS: ++ - Ensure `async-tungstenite`, `tokio-tungstenite`, and `tungstenite` are mutually compatible. ++ - Align TLS features (e.g., `rustls`, `tokio-rustls`) and remove internal/private feature flags (like underscored ones) if upstream changed them. ++ - Remove temporary aliases (e.g., `async_tungstenite_031`) after unification. ++- Serde stack: ++ - Align `serde` and `serde_derive` to the same minor/patch; upgrade `serde_json` accordingly. ++ - Scan for features like `rc`, `preserve_order`, etc., consolidating into the workspace definition. ++- Proc-macro toolchain: ++ - Bump `syn`, `proc-macro2`, `quote` together; confirm macro crates compile. ++- Wasmtime stack: ++ - Upgrade `wasmtime`/`wasmtime-wasi`/`wit-component` in lockstep; review release notes for API changes. ++ ++### Phase 4 — Incremental Upgrades ++ ++- Use `cargo outdated -R` to list outdated crates. ++- Upgrade in batches by domain to keep diffs reviewable: ++ - Batch A: Async/WebSocket/TLS. ++ - Batch B: Serde + data formats. ++ - Batch C: Proc‑macros and build‑time deps. ++ - Batch D: Wasm/Wasmtime. ++ - Batch E: UI/platform crates as needed. ++- For each batch: ++ - Update versions in root `[workspace.dependencies]`. ++ - Adjust features centrally to satisfy all consumers. ++ - Build targets: `cargo check -p ` and `cargo check -p zed`. ++ - Run tests where available; smoke test local app launch if practical. ++ ++### Phase 5 — Resolve Breakages ++ ++- Typical fixes: ++ - API renames or moved modules: update imports and paths. ++ - Feature gating: enable new required features (e.g., `tokio-runtime` on `async-tungstenite`). ++ - TLS stacks: align `rustls`/`tokio-rustls` versions and feature flags; replace deprecated feature names. ++ - Type changes: adapt to new generics or newtype wrappers; avoid cross‑version types by ensuring one version in the graph. ++ - Macro breakages: update code generation usage or attributes. ++- Keep changes local to the affected crate; prefer narrow, mechanical refactors over wide redesigns. ++ ++### Phase 6 — Enforce and Maintain ++ ++- CI gates: ++ - `cargo deny check bans` fails on multiple versions. ++ - Add a simple script to diff `cargo tree -d` against an allowlist of unavoidable dupes (prefer the allowlist to be empty). ++- Developer workflow: ++ - When introducing a new dependency, add it to `[workspace.dependencies]` immediately. ++ - Avoid crate‑local pins unless required; if used, document and add a follow‑up issue to retire them. ++ ++### Rollout Strategy ++ ++- Create one PR per batch/phase; keep each PR focused and reversible. ++- Use conventional commit messages and include a short upgrade summary plus links to upstream release notes. ++- If a batch proves too large, split by crate or by breaking change clusters. ++ ++### Definition of Done ++ ++- `cargo tree -d` reports no duplicates (or only documented exceptions). ++- `cargo outdated -R` is clean or only contains consciously deferred updates. ++- `cargo check -p zed` and applicable tests pass. ++- Temporary aliases and patches are removed or minimized. ++ ++### Candidate Immediate Actions ++ ++- Unify `async-tungstenite` across the workspace to 0.31.x and bump `tokio-tungstenite` to a compatible release (e.g., 0.27.x), verifying `tungstenite` aligns. ++- Remove the `async_tungstenite_031` alias after the global unification and update imports back to `async_tungstenite`. ++- Run `cargo outdated -R` and plan the next two batches (Serde stack, Proc‑macro stack). ++ ++## macOS Follow-ups (this pass) ++ ++### mac/events.rs — unsafe cleanups ++ ++- Removed broad inner `unsafe { ... }` blocks inside `unsafe fn` bodies to address “unnecessary unsafe” warnings. ++- Wrapped only the actual unsafe operations (raw-pointer deref and typed Objective‑C getters) in localized `unsafe { ... }` expressions, satisfying `unsafe_op_in_unsafe_fn` without reintroducing large unsafe scopes. ++- Verified with `cargo check -p gpui` — no warnings from `events.rs` remain. ++ ++### mac/window.rs — more typed constants ++ ++- Replaced ad‑hoc bit masks with icrate `NSEventModifierFlag*` constants for modifier parsing. ++- Replaced numeric `NSAlert` styles with icrate typed constants: `NSAlertStyleInformational`, `NSAlertStyleWarning`, `NSAlertStyleCritical`. ++- Replaced locally defined `NSDragOperationNone/Copy` numeric values with icrate `NSDragOperationNone/Copy` and the `NSDragOperation` type. ++- Kept window level wrappers (`NSWindowLevel`) as previously documented; icrate does not expose named levels. ++ ++### mac/window_appearance.rs — adopt icrate appearance names ++ ++- Switched from Cocoa `NSAppearanceName*` to icrate `NSAppearanceNameAqua/DarkAqua/VibrantLight/VibrantDark` constants, comparing via pointer casts to `id` for consistency with existing Objective‑C interop. ++- Localized unsafe for `msg_send!` and extern comparisons. ++ ++### mac/platform.rs — scroller style constant ++ ++- Replaced local numeric `NSScrollerStyleOverlay` with icrate typed `NSScrollerStyleOverlay` (cast to `NSInteger` for comparison). ++ ++### mac/status_item.rs — adopt icrate constants ++ ++- Imported `NSSquareStatusItemLength` and `NSViewLayerContentsRedrawDuringViewResize` from icrate instead of pulling the latter via another module; avoids cross-module constant access and keeps constants typed and local. ++- Enabled `AppKit_NSStatusBar` and `AppKit_NSStatusItem` features for icrate. ++ ++### mac/platform.rs — menus on raw Objective‑C + icrate (typed‑ready) ++ ++- Standardized the menu construction path to use raw Objective‑C (`msg_send`) for `NSMenu/NSMenuItem` instead of Cocoa trait shims, while keeping typed icrate constants elsewhere. Items are created and added immediately to ensure correct retention. ++- Removed the legacy `create_menu_item` helper (now unused) in favor of `add_menu_item` that appends to the parent menu right away. ++- Left objc2 enabled and ready for future fully‑typed adoption; mixing objc and objc2 macros in this large module requires a broader sweep, which we deferred to avoid regressions. ++ ++### objc2 on macOS ++ ++- Made `objc2` a non‑optional dependency for macOS and removed it from the `macos-blade` feature list to prevent feature/dependency mismatches. ++ ++### mac/platform.rs — menus and pasteboard (icrate usage) ++ ++- Audited menu construction and pasteboard read/write. Current approach mixes Cocoa objects (NSMenu/NSMenuItem/NSPasteboard) with icrate typed constants (NSPasteboardType*), casting to `id` at the boundary. ++- Further migration to icrate objects would force wider interop changes (selectors, object lifetimes) with little immediate gain; kept the pragmatic cast‑to‑id pattern. ++- No code changes needed now; revisit once broader objc2/icrate alignment is planned. ++ ++### Other localized unsafe cleanups ++ ++- mac/window_appearance.rs: Moved unsafe operations into narrow `unsafe {}` expressions for `msg_send!`, extern statics deref, and NSString UTF8 access. ++- mac/text_system.rs: Localized unsafe in `wrap_under_get_rule`; removed redundant outer unsafe block inside an unsafe fn. ++ ++### Next low‑friction icrate adoptions ++ ++- window.rs: continue replacing ad‑hoc constants with icrate typed equivalents where 1:1 mapping exists and `msg_send` usage stays straightforward. ++- platform.rs: when ready to standardize on icrate objects (e.g., NSMenu/NSMenuItem), migrate menus/pasteboard end‑to‑end to avoid mixed‑API friction. ++ ++## Clippy ++ ++- Ran `cargo clippy -p gpui --all-targets` (with elevated permissions due to Metal shader cache writes). Result: clean for `gpui` (quiet mode, no diagnostics). ++- Attempted `cargo clippy --workspace --all-targets`. Workspace run currently fails due to unrelated crates: ++ - `collab`: trait implementation conflicts (`sea_orm::sea_query::Nullable`) and `to_string` ambiguity errors. ++ - mac shader build tries to write to `~/.cache/clang/ModuleCache` under sandbox; elevated run resolves this for `gpui`. ++- Follow‑up: Fix `collab` clippy blockers in a separate pass before enabling workspace-wide clippy gating. +diff --git a/Cargo.lock b/Cargo.lock +index dbcea05ea9..de51ece87e 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -1333,6 +1333,23 @@ dependencies = [ + "tungstenite 0.26.2", + ] + ++[[package]] ++name = "async-tungstenite" ++version = "0.31.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "ee88b4c88ac8c9ea446ad43498955750a4bbe64c4392f21ccfe5d952865e318f" ++dependencies = [ ++ "atomic-waker", ++ "futures-core", ++ "futures-io", ++ "futures-task", ++ "futures-util", ++ "log", ++ "pin-project-lite", ++ "tokio", ++ "tungstenite 0.27.0", ++] ++ + [[package]] + name = "async_zip" + version = "0.0.17" +@@ -2308,7 +2325,7 @@ dependencies = [ + "log", + "mint", + "naga", +- "objc2", ++ "objc2 0.6.1", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", +@@ -2388,13 +2405,32 @@ dependencies = [ + "generic-array", + ] + ++[[package]] ++name = "block-sys" ++version = "0.2.1" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" ++dependencies = [ ++ "objc-sys", ++] ++ ++[[package]] ++name = "block2" ++version = "0.4.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "e58aa60e59d8dbfcc36138f5f18be5f24394d33b38b24f7fd0b1caa33095f22f" ++dependencies = [ ++ "block-sys", ++ "objc2 0.5.2", ++] ++ + [[package]] + name = "block2" + version = "0.6.1" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" + dependencies = [ +- "objc2", ++ "objc2 0.6.1", + ] + + [[package]] +@@ -3064,7 +3100,7 @@ name = "client" + version = "0.1.0" + dependencies = [ + "anyhow", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "base64 0.22.1", + "chrono", + "clock", +@@ -3279,7 +3315,7 @@ dependencies = [ + "assistant_context", + "assistant_slash_command", + "async-trait", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "audio", + "aws-config", + "aws-sdk-kinesis", +@@ -4827,7 +4863,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" + dependencies = [ + "bitflags 2.9.0", +- "objc2", ++ "objc2 0.6.1", + ] + + [[package]] +@@ -6043,7 +6079,6 @@ dependencies = [ + "ashpd", + "async-tar", + "async-trait", +- "cocoa 0.26.0", + "collections", + "fsevent", + "futures 0.3.31", +@@ -7445,18 +7480,20 @@ dependencies = [ + "futures 0.3.31", + "gpui_macros", + "http_client", ++ "icrate", + "image", + "inventory", + "itertools 0.14.0", + "libc", + "log", + "lyon", ++ "macos_appkit_bridge", + "media", + "metal", + "naga", + "num_cpus", + "objc", +- "objc2", ++ "objc2 0.6.1", + "objc2-metal", + "oo7", + "open", +@@ -8149,6 +8186,16 @@ dependencies = [ + "workspace-hack", + ] + ++[[package]] ++name = "icrate" ++version = "0.1.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "3fb69199826926eb864697bddd27f73d9fddcffc004f5733131e15b465e30642" ++dependencies = [ ++ "block2 0.4.0", ++ "objc2 0.5.2", ++] ++ + [[package]] + name = "icu_collections" + version = "1.5.0" +@@ -8947,7 +8994,7 @@ source = "git+https://github.com/ConradIrwin/runtimed?rev=7130c804216b6914355d15 + dependencies = [ + "anyhow", + "async-trait", +- "async-tungstenite", ++ "async-tungstenite 0.31.0", + "futures 0.3.31", + "jupyter-protocol", + "serde", +@@ -9927,6 +9974,10 @@ dependencies = [ + "libc", + ] + ++[[package]] ++name = "macos_appkit_bridge" ++version = "0.1.0" ++ + [[package]] + name = "malloc_buf" + version = "0.0.6" +@@ -10954,6 +11005,22 @@ dependencies = [ + "objc_id", + ] + ++[[package]] ++name = "objc-sys" ++version = "0.3.5" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" ++ ++[[package]] ++name = "objc2" ++version = "0.5.2" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" ++dependencies = [ ++ "objc-sys", ++ "objc2-encode", ++] ++ + [[package]] + name = "objc2" + version = "0.6.1" +@@ -10970,7 +11037,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" + dependencies = [ + "bitflags 2.9.0", +- "objc2", ++ "objc2 0.6.1", + "objc2-core-foundation", + "objc2-foundation", + "objc2-quartz-core", +@@ -10984,7 +11051,7 @@ checksum = "10cbe18d879e20a4aea544f8befe38bcf52255eb63d3f23eca2842f3319e4c07" + dependencies = [ + "bitflags 2.9.0", + "libc", +- "objc2", ++ "objc2 0.6.1", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", +@@ -10998,7 +11065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "ca44961e888e19313b808f23497073e3f6b3c22bb485056674c8b49f3b025c82" + dependencies = [ + "dispatch2", +- "objc2", ++ "objc2 0.6.1", + "objc2-core-audio-types", + "objc2-core-foundation", + ] +@@ -11010,7 +11077,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "c0f1cc99bb07ad2ddb6527ddf83db6a15271bb036b3eb94b801cd44fdc666ee1" + dependencies = [ + "bitflags 2.9.0", +- "objc2", ++ "objc2 0.6.1", + ] + + [[package]] +@@ -11021,7 +11088,7 @@ checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" + dependencies = [ + "bitflags 2.9.0", + "dispatch2", +- "objc2", ++ "objc2 0.6.1", + ] + + [[package]] +@@ -11037,7 +11104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" + dependencies = [ + "bitflags 2.9.0", +- "objc2", ++ "objc2 0.6.1", + "objc2-core-foundation", + ] + +@@ -11048,9 +11115,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "7f246c183239540aab1782457b35ab2040d4259175bd1d0c58e46ada7b47a874" + dependencies = [ + "bitflags 2.9.0", +- "block2", ++ "block2 0.6.1", + "dispatch2", +- "objc2", ++ "objc2 0.6.1", + "objc2-core-foundation", + "objc2-foundation", + ] +@@ -11062,7 +11129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" + dependencies = [ + "bitflags 2.9.0", +- "objc2", ++ "objc2 0.6.1", + "objc2-core-foundation", + "objc2-foundation", + "objc2-metal", +@@ -11075,7 +11142,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" + dependencies = [ + "bitflags 2.9.0", +- "objc2", ++ "objc2 0.6.1", + "objc2-core-foundation", + "objc2-foundation", + "objc2-quartz-core", +@@ -13579,7 +13646,8 @@ dependencies = [ + "alacritty_terminal", + "anyhow", + "async-dispatcher", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", ++ "async-tungstenite 0.31.0", + "base64 0.22.1", + "client", + "collections", +@@ -13929,7 +13997,7 @@ name = "rpc" + version = "0.1.0" + dependencies = [ + "anyhow", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "base64 0.22.1", + "chrono", + "collections", +@@ -17507,6 +17575,23 @@ dependencies = [ + "utf-8", + ] + ++[[package]] ++name = "tungstenite" ++version = "0.27.0" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d" ++dependencies = [ ++ "bytes 1.10.1", ++ "data-encoding", ++ "http 1.3.1", ++ "httparse", ++ "log", ++ "rand 0.9.1", ++ "sha1", ++ "thiserror 2.0.12", ++ "utf-8", ++] ++ + [[package]] + name = "typed-path" + version = "0.11.0" +@@ -19886,7 +19971,7 @@ dependencies = [ + "arrayvec", + "async-compression", + "async-std", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "aws-config", + "aws-credential-types", + "aws-runtime", +@@ -19978,7 +20063,7 @@ dependencies = [ + "num-iter", + "num-rational", + "num-traits", +- "objc2", ++ "objc2 0.6.1", + "objc2-core-foundation", + "objc2-foundation", + "objc2-metal", +diff --git a/Cargo.toml b/Cargo.toml +index d8e8040cd9..5165344ac3 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -106,6 +106,7 @@ members = [ + "crates/markdown_preview", + "crates/media", + "crates/menu", ++ "crates/macos_appkit_bridge", + "crates/migrator", + "crates/mistral", + "crates/multi_buffer", +diff --git a/PR_BODY_mac-objc-migration-phase1.md b/PR_BODY_mac-objc-migration-phase1.md +new file mode 100644 +index 0000000000..0a10463c9d +--- /dev/null ++++ b/PR_BODY_mac-objc-migration-phase1.md +@@ -0,0 +1,116 @@ ++Title: Build fixes + macOS objc2 prep: gpui menus, tungstenite alignment, clippy cleanups ++ ++Overview ++ ++- Target: Build the `zed` workspace locally without errors. ++- Primary blocker: `jupyter-websocket-client` failed to compile due to unresolved imports from `async-tungstenite` and a follow‑on type mismatch caused by two different `async-tungstenite` versions in the dependency graph. ++- Approach: Enable the correct feature on `async-tungstenite` v0.31.0 required by `jupyter-websocket-client`, and isolate type identity by importing that version via an alias in the `repl` crate where the websocket types are used. On macOS, standardize menus on raw Objective‑C, adopt icrate typed constants, and prepare for an objc2 migration. ++ ++Changes Since Last Update ++ ++- Menus (platform.rs): ++ - Replaced Cocoa shims with raw Objective‑C for `NSMenu`/`NSMenuItem` (create via `alloc/new/init` + `autorelease`). ++ - Added `add_menu_item(parent_menu, ...)` that creates separator/action/submenu/system items and immediately adds them to the parent (correct retention and simpler lifetimes). ++ - Rewired window/services menus with `setWindowsMenu:` and `setServicesMenu:` (`msg_send!`). ++ - Removed the legacy `create_menu_item` helper; no callers remain. ++ ++- objc2 dependency (Cargo): ++ - Made `objc2` non‑optional on macOS and removed it from the `macos-blade` feature set. ++ - Enabled icrate features for NSMenu/NSMenuItem/NSStatusBar/NSScroller to support typed usage. ++ ++- Other mac modules: ++ - status_item.rs: using icrate `NSSquareStatusItemLength` and `NSViewLayerContentsRedrawDuringViewResize`. ++ - window_appearance.rs: switched to icrate `NSAppearanceName*` and localized unsafe. ++ - events.rs: localized unsafe blocks around typed getters; removed unnecessary casts. ++ ++- collab crate (clippy blockers): ++ - Removed conflicting manual `Nullable` impl in ids.rs; disambiguated `to_string` calls in queries and tests to avoid trait collisions with `sea_orm::Iden`. ++ ++Root Cause Analysis (build failures) ++ ++1) Feature gating in `async-tungstenite` 0.31.0 ++ ++- `jupyter-websocket-client` imports `async_tungstenite::tokio`, which is behind the `tokio-runtime` feature in `async-tungstenite` v0.31.0. ++- That feature wasn’t enabled in our graph, causing unresolved imports during compilation. ++ ++2) Multiple `async-tungstenite` versions in the workspace ++ ++- The workspace depends on `async-tungstenite` v0.29.1 (via `workspace.dependencies`). ++- `jupyter-websocket-client` depends on `async-tungstenite` v0.31.0. ++- When `repl` used `connect_async` and also consumed types produced by `jupyter-websocket-client`, we ended up with two different `WebSocketStream` types. Even if generics look the same, different crate versions yield distinct types, causing a mismatch. ++ ++Changes Implemented (build fixes) ++ ++1) Alias `async-tungstenite` v0.31.0 in `repl` with `tokio-runtime` enabled ++ ++- crates/repl/Cargo.toml: ++ - `async_tungstenite_031 = { package = "async-tungstenite", version = "0.31.0", default-features = false, features = ["tokio-runtime"] }` ++ ++2) Import the aliased crate in `repl` ++ ++- crates/repl/src/kernels/remote_kernels.rs: ++ - `use async_tungstenite_031::tokio::connect_async;` ++ - `use async_tungstenite_031::tungstenite::{client::IntoClientRequest, http::HeaderValue};` ++ ++Why this works ++ ++- Ensures `async_tungstenite::tokio` is compiled in v0.31.0 by enabling `tokio-runtime`. ++- Aligns all websocket types used in `repl` with those produced by `jupyter-websocket-client` (0.31.0), removing cross‑version type mismatches. ++ ++Validation ++ ++- `cargo check -p repl` passes. ++- `cargo check -p zed` passes. ++- `cargo clippy -p gpui --all-targets` runs clean (shader cache on macOS may require elevated permissions). ++- `cargo clippy --workspace --all-targets` runs clean after `collab` fixes. ++ ++macOS objc2 Migration Prep ++ ++- Standardize raw Objective‑C messaging via `msg_send` in menus while adopting icrate typed constants where they bring clarity and safety. ++- Make `objc2` unconditional on macOS to avoid feature mismatch; defer full typed migration to phased follow‑ups. ++ ++Planned Phases (high level) ++ ++- Phase 1 — Typed Menus: use `objc2::msg_send_id!`, `Retained`, typed setters; convert strings to icrate `NSString`. ++- Phase 2 — Typed NSString/Selectors: introduce a helper and replace remaining Cocoa `NSString` usage where practical. ++- Phase 3 — Beyond Menus: migrate services hooks, panels, pasteboard, and common NSApplication calls to objc2 typed APIs. ++- Phase 4 — window.rs Sweep: re‑scan for typed replacements, confirm parity. ++ ++Risks and Mitigations ++ ++- Macro family mixing: avoid mixing `objc` and `objc2` macros within the same section; convert sections atomically and keep raw `id` interop localized. ++- Retention/lifetimes: add items to parents immediately, prefer typed ownership where available. ++- Rollback: current raw Objective‑C path is stable and can serve as fallback if needed. ++ ++Design Notes and Trade‑offs ++ ++- Minimal blast radius for build fixes: avoided a workspace‑wide `async-tungstenite` bump; used a targeted alias to keep other crates stable. ++- Type identity: ensured websocket types come from a single crate version where the integration actually happens. ++- Future: consider unifying `async-tungstenite` across the workspace to 0.31.x after a dedicated validation sweep. ++ ++Follow‑ups / Backlog ++ ++- Unify `async-tungstenite` versions workspace‑wide; align `tokio-tungstenite` and `tungstenite` accordingly. ++- Continue objc2 typed migration across mac modules (services, panels, pasteboard, NSApplication). ++- Replace remaining numeric constants with icrate typed constants where available. ++- Optional: enforce single‑version policy via `cargo-deny` (bans), add CI checks. ++ ++Files of Interest ++ ++- AGENTS.md: detailed narrative of the build fixes, macOS migration prep, validation steps, and plans. ++- crates/repl/Cargo.toml: alias for `async-tungstenite` 0.31.0 with `tokio-runtime`. ++- crates/repl/src/kernels/remote_kernels.rs: imports updated to aliased 0.31.0 to match `jupyter-websocket-client`. ++- macOS modules in `gpui`: menus standardized on raw Objective‑C; icrate constants adopted; objc2 made unconditional. ++ ++Checklist ++ ++- [x] cargo fmt ++- [x] cargo check -p gpui ++- [x] cargo clippy -p gpui --all-targets ++- [x] cargo clippy --workspace --all-targets ++- [x] Update AGENTS.md with scope, changes, and validation ++ ++Notes ++ ++- For shader compilation on macOS during clippy, elevated permissions may be needed due to shader cache writes. ++- `gh` PR text mirrors AGENTS.md for maximum reviewer context; future PRs can be shorter once objc2 migration stabilizes. +diff --git a/crates/collab/src/db/ids.rs b/crates/collab/src/db/ids.rs +index 8f116cfd63..84b3bd4c9e 100644 +--- a/crates/collab/src/db/ids.rs ++++ b/crates/collab/src/db/ids.rs +@@ -61,11 +61,8 @@ macro_rules! id_type { + } + } + +- impl sea_orm::sea_query::Nullable for $name { +- fn null() -> Value { +- Value::Int(None) +- } +- } ++ // Nullable is provided by sea-orm derives for value types in recent versions; ++ // avoid conflicting implementations here. + }; + } + +diff --git a/crates/collab/src/db/queries/extensions.rs b/crates/collab/src/db/queries/extensions.rs +index f218ff2850..8b2cd79862 100644 +--- a/crates/collab/src/db/queries/extensions.rs ++++ b/crates/collab/src/db/queries/extensions.rs +@@ -255,7 +255,7 @@ impl Database { + + let insert = extension::Entity::insert(extension::ActiveModel { + name: ActiveValue::Set(latest_version.name.clone()), +- external_id: ActiveValue::Set(external_id.to_string()), ++ external_id: ActiveValue::Set(std::string::ToString::to_string(external_id)), + id: ActiveValue::NotSet, + latest_version: ActiveValue::Set(latest_version.version.to_string()), + total_download_count: ActiveValue::NotSet, +@@ -282,7 +282,9 @@ impl Database { + extension_version::ActiveModel { + extension_id: ActiveValue::Set(extension.id), + published_at: ActiveValue::Set(version.published_at), +- version: ActiveValue::Set(version.version.to_string()), ++ version: ActiveValue::Set(std::string::ToString::to_string( ++ &version.version, ++ )), + authors: ActiveValue::Set(version.authors.join(", ")), + repository: ActiveValue::Set(version.repository.clone()), + description: ActiveValue::Set(version.description.clone()), +diff --git a/crates/collab/src/db/queries/notifications.rs b/crates/collab/src/db/queries/notifications.rs +index cc22ee99b5..6f91fb868a 100644 +--- a/crates/collab/src/db/queries/notifications.rs ++++ b/crates/collab/src/db/queries/notifications.rs +@@ -17,7 +17,7 @@ impl Database { + .any(|existing| existing.name == **kind) + }) + .map(|kind| notification_kind::ActiveModel { +- name: ActiveValue::Set(kind.to_string()), ++ name: ActiveValue::Set(std::string::ToString::to_string(kind)), + ..Default::default() + }) + .collect(); +@@ -260,7 +260,7 @@ pub fn model_to_proto(this: &Database, row: notification::Model) -> Result Vec Result<()> { +- use cocoa::{ +- base::{id, nil}, +- foundation::{NSAutoreleasePool, NSString}, +- }; ++ use objc::runtime::Object; + use objc::{class, msg_send, sel, sel_impl}; ++ use std::{ffi::CString, ptr}; + + unsafe { +- unsafe fn ns_string(string: &str) -> id { +- unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ unsafe fn ns_string(s: &str) -> *mut Object { ++ let cstr = CString::new(s).unwrap_or_else(|_| CString::new("").unwrap()); ++ let ns: *mut Object = msg_send![class!(NSString), alloc]; ++ let ns: *mut Object = msg_send![ns, initWithUTF8String: cstr.as_ptr()]; ++ let _: *mut Object = msg_send![ns, autorelease]; ++ ns + } + +- let url: id = msg_send![class!(NSURL), fileURLWithPath: ns_string(path.to_string_lossy().as_ref())]; +- let array: id = msg_send![class!(NSArray), arrayWithObject: url]; +- let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; ++ let url: *mut Object = msg_send![class!(NSURL), fileURLWithPath: ns_string(path.to_string_lossy().as_ref())]; ++ let array: *mut Object = msg_send![class!(NSArray), arrayWithObject: url]; ++ let workspace: *mut Object = msg_send![class!(NSWorkspace), sharedWorkspace]; + +- let _: id = msg_send![workspace, recycleURLs: array completionHandler: nil]; ++ let _: () = msg_send![workspace, recycleURLs: array completionHandler: ptr::null_mut::()]; + } + Ok(()) + } +diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml +index dd91eb4d4e..adfffd6414 100644 +--- a/crates/gpui/Cargo.toml ++++ b/crates/gpui/Cargo.toml +@@ -30,7 +30,6 @@ macos-blade = [ + "blade-macros", + "blade-util", + "bytemuck", +- "objc2", + "objc2-metal", + ] + wayland = [ +@@ -127,11 +126,12 @@ thiserror.workspace = true + util.workspace = true + uuid.workspace = true + waker-fn = "1.2.0" ++ ++[target.'cfg(target_os = "macos")'.dependencies] ++macos_appkit_bridge = { path = "../macos_appkit_bridge" } + lyon = "1.0" + workspace-hack.workspace = true + libc.workspace = true +- +-[target.'cfg(target_os = "macos")'.dependencies] + block = "0.1" + cocoa.workspace = true + core-foundation.workspace = true +@@ -144,8 +144,35 @@ foreign-types = "0.5" + log.workspace = true + media.workspace = true + objc.workspace = true +-objc2 = { version = "0.6", optional = true } ++objc2 = { version = "0.6" } + objc2-metal = { version = "0.3", optional = true } ++icrate = { version = "0.1.2", features = [ ++ # Base modules ++ "Foundation", "AppKit", ++ # Fine-grained Foundation types we use or plan to migrate to ++ "Foundation_NSAutoreleasePool", ++ "Foundation_NSArray", ++ "Foundation_NSMutableIndexSet", ++ "Foundation_NSProcessInfo", ++ "Foundation_NSString", ++ "Foundation_NSUserDefaults", ++ # Fine-grained AppKit types we use or plan to migrate to ++ "AppKit_NSApplication", ++ "AppKit_NSAppearance", ++ "AppKit_NSAlert", ++ "AppKit_NSEvent", ++ "AppKit_NSScroller", ++ "AppKit_NSPasteboard", ++ "AppKit_NSStatusBar", ++ "AppKit_NSStatusItem", ++ "AppKit_NSMenu", ++ "AppKit_NSMenuItem", ++ "AppKit_NSScreen", ++ "AppKit_NSTrackingArea", ++ "AppKit_NSView", ++ "AppKit_NSVisualEffectView", ++ "AppKit_NSWindow", ++] } + #TODO: replace with "objc2" + metal.workspace = true + +diff --git a/crates/gpui/src/platform/mac.rs b/crates/gpui/src/platform/mac.rs +index 76d636b457..7a0f7935e9 100644 +--- a/crates/gpui/src/platform/mac.rs ++++ b/crates/gpui/src/platform/mac.rs +@@ -1,3 +1,4 @@ ++#![allow(deprecated)] + //! Macos screen have a y axis that goings up from the bottom of the screen and + //! an origin at the bottom left of the main display. + mod dispatcher; +diff --git a/crates/gpui/src/platform/mac/attributed_string.rs b/crates/gpui/src/platform/mac/attributed_string.rs +index 5f313ac699..2ac47f024a 100644 +--- a/crates/gpui/src/platform/mac/attributed_string.rs ++++ b/crates/gpui/src/platform/mac/attributed_string.rs +@@ -1,105 +1,130 @@ +-use cocoa::base::id; +-use cocoa::foundation::NSRange; ++use objc::runtime::Object; + use objc::{class, msg_send, sel, sel_impl}; + ++type ObjcId = *mut Object; ++ ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct NSRange { ++ pub location: usize, ++ pub length: usize, ++} ++ ++impl NSRange { ++ pub const fn new(location: usize, length: usize) -> Self { ++ Self { location, length } ++ } ++} ++ + /// The `cocoa` crate does not define NSAttributedString (and related Cocoa classes), + /// which are needed for copying rich text (that is, text intermingled with images) + /// to the clipboard. This adds access to those APIs. + #[allow(non_snake_case)] + pub trait NSAttributedString: Sized { +- unsafe fn alloc(_: Self) -> id { ++ unsafe fn alloc(_: Self) -> ObjcId { + msg_send![class!(NSAttributedString), alloc] + } + +- unsafe fn init_attributed_string(self, string: id) -> id; +- unsafe fn appendAttributedString_(self, attr_string: id); +- unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; +- unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; +- unsafe fn string(self) -> id; ++ unsafe fn init_attributed_string(self, string: ObjcId) -> ObjcId; ++ unsafe fn appendAttributedString_(self, attr_string: ObjcId); ++ unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: ObjcId) -> ObjcId; ++ unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: ObjcId) -> ObjcId; ++ unsafe fn string(self) -> ObjcId; + } + +-impl NSAttributedString for id { +- unsafe fn init_attributed_string(self, string: id) -> id { ++impl NSAttributedString for ObjcId { ++ unsafe fn init_attributed_string(self, string: ObjcId) -> ObjcId { + msg_send![self, initWithString: string] + } + +- unsafe fn appendAttributedString_(self, attr_string: id) { ++ unsafe fn appendAttributedString_(self, attr_string: ObjcId) { + let _: () = msg_send![self, appendAttributedString: attr_string]; + } + +- unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { ++ unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: ObjcId) -> ObjcId { + msg_send![self, RTFDFromRange: range documentAttributes: attrs] + } + +- unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { ++ unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: ObjcId) -> ObjcId { + msg_send![self, RTFFromRange: range documentAttributes: attrs] + } + +- unsafe fn string(self) -> id { ++ unsafe fn string(self) -> ObjcId { + msg_send![self, string] + } + } + + pub trait NSMutableAttributedString: NSAttributedString { +- unsafe fn alloc(_: Self) -> id { ++ unsafe fn alloc(_: Self) -> ObjcId { + msg_send![class!(NSMutableAttributedString), alloc] + } + } + +-impl NSMutableAttributedString for id {} ++impl NSMutableAttributedString for ObjcId {} + + #[cfg(test)] + mod tests { + use super::*; +- use cocoa::appkit::NSImage; +- use cocoa::base::nil; +- use cocoa::foundation::NSString; ++ use objc::runtime::Object; ++ use objc::{class, msg_send, sel, sel_impl}; ++ use std::ffi::CString; + #[test] + #[ignore] // This was SIGSEGV-ing on CI but not locally; need to investigate https://github.com/zed-industries/zed/actions/runs/10362363230/job/28684225486?pr=15782#step:4:1348 + fn test_nsattributed_string() { + // TODO move these to parent module once it's actually ready to be used + #[allow(non_snake_case)] + pub trait NSTextAttachment: Sized { +- unsafe fn alloc(_: Self) -> id { ++ unsafe fn alloc(_: Self) -> ObjcId { + msg_send![class!(NSTextAttachment), alloc] + } + } + +- impl NSTextAttachment for id {} ++ impl NSTextAttachment for ObjcId {} + + unsafe { +- let image: id = msg_send![class!(NSImage), alloc]; +- image.initWithContentsOfFile_(NSString::alloc(nil).init_str("test.jpeg")); +- let _size = image.size(); +- +- let string = NSString::alloc(nil).init_str("Test String"); +- let attr_string = NSMutableAttributedString::alloc(nil).init_attributed_string(string); +- let hello_string = NSString::alloc(nil).init_str("Hello World"); +- let hello_attr_string = +- NSAttributedString::alloc(nil).init_attributed_string(hello_string); ++ let image: ObjcId = msg_send![class!(NSImage), alloc]; ++ let path = CString::new("test.jpeg").unwrap(); ++ let ns_str: *mut Object = msg_send![class!(NSString), alloc]; ++ let ns_str: *mut Object = msg_send![ns_str, initWithUTF8String: path.as_ptr()]; ++ let _: ObjcId = msg_send![image, initWithContentsOfFile: ns_str]; ++ ++ let s = CString::new("Test String").unwrap(); ++ let string: ObjcId = msg_send![class!(NSString), alloc]; ++ let string: ObjcId = msg_send![string, initWithUTF8String: s.as_ptr()]; ++ let attr_string = NSMutableAttributedString::alloc(std::ptr::null_mut()) ++ .init_attributed_string(string); ++ let hs = CString::new("Hello World").unwrap(); ++ let hello_string: ObjcId = msg_send![class!(NSString), alloc]; ++ let hello_string: ObjcId = msg_send![hello_string, initWithUTF8String: hs.as_ptr()]; ++ let hello_attr_string = NSAttributedString::alloc(std::ptr::null_mut()) ++ .init_attributed_string(hello_string); + attr_string.appendAttributedString_(hello_attr_string); + +- let attachment = NSTextAttachment::alloc(nil); ++ let attachment = NSTextAttachment::alloc(std::ptr::null_mut()); + let _: () = msg_send![attachment, setImage: image]; + let image_attr_string = + msg_send![class!(NSAttributedString), attributedStringWithAttachment: attachment]; + attr_string.appendAttributedString_(image_attr_string); + +- let another_string = NSString::alloc(nil).init_str("Another String"); +- let another_attr_string = +- NSAttributedString::alloc(nil).init_attributed_string(another_string); ++ let as_ = CString::new("Another String").unwrap(); ++ let another_string: ObjcId = msg_send![class!(NSString), alloc]; ++ let another_string: ObjcId = ++ msg_send![another_string, initWithUTF8String: as_.as_ptr()]; ++ let another_attr_string = NSAttributedString::alloc(std::ptr::null_mut()) ++ .init_attributed_string(another_string); + attr_string.appendAttributedString_(another_attr_string); + +- let _len: cocoa::foundation::NSUInteger = msg_send![attr_string, length]; ++ let _len: u64 = msg_send![attr_string, length]; + + /////////////////////////////////////////////////// + // pasteboard.clearContents(); + ++ let len: u64 = msg_send![attr_string, length]; + let rtfd_data = attr_string.RTFDFromRange_documentAttributes_( +- NSRange::new(0, msg_send![attr_string, length]), +- nil, ++ NSRange::new(0, len as usize), ++ std::ptr::null_mut(), + ); +- assert_ne!(rtfd_data, nil); ++ assert!(!rtfd_data.is_null()); + // if rtfd_data != nil { + // pasteboard.setData_forType(rtfd_data, NSPasteboardTypeRTFD); + // } +diff --git a/crates/gpui/src/platform/mac/display.rs b/crates/gpui/src/platform/mac/display.rs +index 4ee27027d5..a896557888 100644 +--- a/crates/gpui/src/platform/mac/display.rs ++++ b/crates/gpui/src/platform/mac/display.rs +@@ -1,13 +1,10 @@ + use crate::{Bounds, DisplayId, Pixels, PlatformDisplay, px, size}; + use anyhow::Result; +-use cocoa::{ +- appkit::NSScreen, +- base::{id, nil}, +- foundation::{NSDictionary, NSString}, +-}; + use core_foundation::uuid::{CFUUIDGetUUIDBytes, CFUUIDRef}; + use core_graphics::display::{CGDirectDisplayID, CGDisplayBounds, CGGetActiveDisplayList}; +-use objc::{msg_send, sel, sel_impl}; ++use objc::runtime::Object; ++use objc::{class, msg_send, sel, sel_impl}; ++use std::ffi::CString; + use uuid::Uuid; + + #[derive(Debug)] +@@ -32,13 +29,18 @@ impl MacDisplay { + // + // https://chromium.googlesource.com/chromium/src/+/66.0.3359.158/ui/display/mac/screen_mac.mm#56 + unsafe { +- let screens = NSScreen::screens(nil); +- let screen = cocoa::foundation::NSArray::objectAtIndex(screens, 0); +- let device_description = NSScreen::deviceDescription(screen); +- let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); +- let screen_number = device_description.objectForKey_(screen_number_key); +- let screen_number: CGDirectDisplayID = msg_send![screen_number, unsignedIntegerValue]; +- Self(screen_number) ++ let screens: *mut Object = msg_send![class!(NSScreen), screens]; ++ let screen: *mut Object = msg_send![screens, objectAtIndex: 0usize]; ++ let device_description: *mut Object = msg_send![screen, deviceDescription]; ++ ++ let key = CString::new("NSScreenNumber").unwrap(); ++ let ns_key: *mut Object = msg_send![class!(NSString), alloc]; ++ let ns_key: *mut Object = msg_send![ns_key, initWithUTF8String: key.as_ptr()]; ++ ++ let screen_number_obj: *mut Object = ++ msg_send![device_description, objectForKey: ns_key]; ++ let screen_number: u64 = msg_send![screen_number_obj, unsignedIntegerValue]; ++ Self(screen_number as CGDirectDisplayID) + } + } + +diff --git a/crates/gpui/src/platform/mac/events.rs b/crates/gpui/src/platform/mac/events.rs +index 938db4b762..16423e1ebe 100644 +--- a/crates/gpui/src/platform/mac/events.rs ++++ b/crates/gpui/src/platform/mac/events.rs +@@ -8,13 +8,44 @@ use crate::{ + }, + point, px, + }; +-use cocoa::{ +- appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType}, +- base::{YES, id}, +-}; ++use icrate::AppKit::NSEvent; ++use objc::runtime::Object; ++use objc::{msg_send, sel, sel_impl}; ++type ObjcId = *mut Object; + use core_foundation::data::{CFDataGetBytePtr, CFDataRef}; + use core_graphics::event::CGKeyCode; +-use objc::{msg_send, sel, sel_impl}; ++// Using objc2/icrate later for typed constants; current code retains numeric masks and values ++// objc msg_send imported above ++use icrate::AppKit::{ ++ // Modifier flags ++ NSEventModifierFlagCapsLock, ++ NSEventModifierFlagCommand, ++ NSEventModifierFlagControl, ++ NSEventModifierFlagFunction, ++ NSEventModifierFlagOption, ++ NSEventModifierFlagShift, ++ // Phases ++ NSEventPhaseBegan, ++ NSEventPhaseEnded, ++ NSEventPhaseMayBegin, ++ NSEventTypeFlagsChanged, ++ NSEventTypeKeyDown, ++ NSEventTypeKeyUp, ++ // Event types ++ NSEventTypeLeftMouseDown, ++ NSEventTypeLeftMouseDragged, ++ NSEventTypeLeftMouseUp, ++ NSEventTypeMouseExited, ++ NSEventTypeMouseMoved, ++ NSEventTypeOtherMouseDown, ++ NSEventTypeOtherMouseDragged, ++ NSEventTypeOtherMouseUp, ++ NSEventTypeRightMouseDown, ++ NSEventTypeRightMouseDragged, ++ NSEventTypeRightMouseUp, ++ NSEventTypeScrollWheel, ++ NSEventTypeSwipe, ++}; + use std::{borrow::Cow, ffi::c_void}; + + const BACKSPACE_KEY: u16 = 0x7f; +@@ -25,433 +56,428 @@ pub(crate) const ESCAPE_KEY: u16 = 0x1b; + const TAB_KEY: u16 = 0x09; + const SHIFT_TAB_KEY: u16 = 0x19; + ++// CGPoint/NSPoint equivalent for message returns ++#[repr(C)] ++struct NSPoint { ++ pub x: f64, ++ pub y: f64, ++} ++ ++// Modifier flag masks (from icrate NSEventModifierFlags) ++const MOD_CAPS_LOCK: u64 = NSEventModifierFlagCapsLock as u64; ++const MOD_SHIFT: u64 = NSEventModifierFlagShift as u64; ++const MOD_CONTROL: u64 = NSEventModifierFlagControl as u64; ++const MOD_OPTION: u64 = NSEventModifierFlagOption as u64; ++const MOD_COMMAND: u64 = NSEventModifierFlagCommand as u64; ++const MOD_FUNCTION: u64 = NSEventModifierFlagFunction as u64; ++ ++// Event types we care about (from icrate NSEventType) ++const ET_LEFT_MOUSE_DOWN: u64 = NSEventTypeLeftMouseDown as u64; ++const ET_LEFT_MOUSE_UP: u64 = NSEventTypeLeftMouseUp as u64; ++const ET_RIGHT_MOUSE_DOWN: u64 = NSEventTypeRightMouseDown as u64; ++const ET_RIGHT_MOUSE_UP: u64 = NSEventTypeRightMouseUp as u64; ++const ET_MOUSE_MOVED: u64 = NSEventTypeMouseMoved as u64; ++const ET_LEFT_MOUSE_DRAGGED: u64 = NSEventTypeLeftMouseDragged as u64; ++const ET_RIGHT_MOUSE_DRAGGED: u64 = NSEventTypeRightMouseDragged as u64; ++const ET_MOUSE_EXITED: u64 = NSEventTypeMouseExited as u64; ++const ET_KEY_DOWN: u64 = NSEventTypeKeyDown as u64; ++const ET_KEY_UP: u64 = NSEventTypeKeyUp as u64; ++const ET_FLAGS_CHANGED: u64 = NSEventTypeFlagsChanged as u64; ++const ET_SCROLL_WHEEL: u64 = NSEventTypeScrollWheel as u64; ++const ET_OTHER_MOUSE_DOWN: u64 = NSEventTypeOtherMouseDown as u64; ++const ET_OTHER_MOUSE_UP: u64 = NSEventTypeOtherMouseUp as u64; ++const ET_OTHER_MOUSE_DRAGGED: u64 = NSEventTypeOtherMouseDragged as u64; ++const ET_SWIPE: u64 = NSEventTypeSwipe as u64; ++ ++// Event phases (from icrate NSEventPhase) ++const PHASE_BEGAN: u64 = NSEventPhaseBegan as u64; ++const PHASE_ENDED: u64 = NSEventPhaseEnded as u64; ++const PHASE_MAY_BEGIN: u64 = NSEventPhaseMayBegin as u64; ++ ++// Function-key constants used in mapping ++const NS_UP_ARROW: u16 = 0xF700; ++const NS_DOWN_ARROW: u16 = 0xF701; ++const NS_LEFT_ARROW: u16 = 0xF702; ++const NS_RIGHT_ARROW: u16 = 0xF703; ++const NS_HOME: u16 = 0xF729; ++const NS_END: u16 = 0xF72B; ++const NS_PAGE_UP: u16 = 0xF72C; ++const NS_PAGE_DOWN: u16 = 0xF72D; ++const NS_DELETE_FN: u16 = 0xF728; ++const NS_HELP_FN: u16 = 0xF746; ++ + pub fn key_to_native(key: &str) -> Cow<'_, str> { +- use cocoa::appkit::*; +- let code = match key { +- "space" => SPACE_KEY, +- "backspace" => BACKSPACE_KEY, +- "escape" => ESCAPE_KEY, +- "up" => NSUpArrowFunctionKey, +- "down" => NSDownArrowFunctionKey, +- "left" => NSLeftArrowFunctionKey, +- "right" => NSRightArrowFunctionKey, +- "pageup" => NSPageUpFunctionKey, +- "pagedown" => NSPageDownFunctionKey, +- "home" => NSHomeFunctionKey, +- "end" => NSEndFunctionKey, +- "delete" => NSDeleteFunctionKey, +- "insert" => NSHelpFunctionKey, +- "f1" => NSF1FunctionKey, +- "f2" => NSF2FunctionKey, +- "f3" => NSF3FunctionKey, +- "f4" => NSF4FunctionKey, +- "f5" => NSF5FunctionKey, +- "f6" => NSF6FunctionKey, +- "f7" => NSF7FunctionKey, +- "f8" => NSF8FunctionKey, +- "f9" => NSF9FunctionKey, +- "f10" => NSF10FunctionKey, +- "f11" => NSF11FunctionKey, +- "f12" => NSF12FunctionKey, +- "f13" => NSF13FunctionKey, +- "f14" => NSF14FunctionKey, +- "f15" => NSF15FunctionKey, +- "f16" => NSF16FunctionKey, +- "f17" => NSF17FunctionKey, +- "f18" => NSF18FunctionKey, +- "f19" => NSF19FunctionKey, +- "f20" => NSF20FunctionKey, +- "f21" => NSF21FunctionKey, +- "f22" => NSF22FunctionKey, +- "f23" => NSF23FunctionKey, +- "f24" => NSF24FunctionKey, +- "f25" => NSF25FunctionKey, +- "f26" => NSF26FunctionKey, +- "f27" => NSF27FunctionKey, +- "f28" => NSF28FunctionKey, +- "f29" => NSF29FunctionKey, +- "f30" => NSF30FunctionKey, +- "f31" => NSF31FunctionKey, +- "f32" => NSF32FunctionKey, +- "f33" => NSF33FunctionKey, +- "f34" => NSF34FunctionKey, +- "f35" => NSF35FunctionKey, +- _ => return Cow::Borrowed(key), ++ let code_opt: Option = match key { ++ "space" => Some(SPACE_KEY), ++ "backspace" => Some(BACKSPACE_KEY), ++ "escape" => Some(ESCAPE_KEY), ++ "up" => Some(NS_UP_ARROW), ++ "down" => Some(NS_DOWN_ARROW), ++ "left" => Some(NS_LEFT_ARROW), ++ "right" => Some(NS_RIGHT_ARROW), ++ "pageup" => Some(NS_PAGE_UP), ++ "pagedown" => Some(NS_PAGE_DOWN), ++ "home" => Some(NS_HOME), ++ "end" => Some(NS_END), ++ "delete" => Some(NS_DELETE_FN), ++ "insert" => Some(NS_HELP_FN), ++ other if other.len() > 1 && other.starts_with('f') => { ++ if let Ok(n) = other[1..].parse::() { ++ if (1..=35).contains(&n) { ++ Some(0xF703 + n) ++ } else { ++ None ++ } ++ } else { ++ None ++ } ++ } ++ _ => None, + }; +- Cow::Owned(String::from_utf16(&[code]).unwrap()) ++ if let Some(code) = code_opt { ++ Cow::Owned(String::from_utf16(&[code]).unwrap()) ++ } else { ++ Cow::Borrowed(key) ++ } + } + +-unsafe fn read_modifiers(native_event: id) -> Modifiers { +- unsafe { +- let modifiers = native_event.modifierFlags(); +- let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); +- let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); +- let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); +- let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); +- let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); +- +- Modifiers { +- control, +- alt, +- shift, +- platform: command, +- function, +- } ++unsafe fn read_modifiers(native_event: ObjcId) -> Modifiers { ++ let modifiers: u64 = msg_send![native_event, modifierFlags]; ++ let control = (modifiers & MOD_CONTROL) != 0; ++ let alt = (modifiers & MOD_OPTION) != 0; ++ let shift = (modifiers & MOD_SHIFT) != 0; ++ let command = (modifiers & MOD_COMMAND) != 0; ++ let function = (modifiers & MOD_FUNCTION) != 0; ++ ++ Modifiers { ++ control, ++ alt, ++ shift, ++ platform: command, ++ function, + } + } + + impl PlatformInput { + pub(crate) unsafe fn from_native( +- native_event: id, ++ native_event: ObjcId, + window_height: Option, + ) -> Option { +- unsafe { +- let event_type = native_event.eventType(); +- +- // Filter out event types that aren't in the NSEventType enum. +- // See https://github.com/servo/cocoa-rs/issues/155#issuecomment-323482792 for details. +- match event_type as u64 { +- 0 | 21 | 32 | 33 | 35 | 36 | 37 => { +- return None; +- } +- _ => {} ++ let event = native_event as *const NSEvent; ++ let event_type: u64 = unsafe { (&*event).r#type() as u64 }; ++ ++ // Filter out event types that aren't in the NSEventType enum. ++ // See https://github.com/servo/cocoa-rs/issues/155#issuecomment-323482792 for details. ++ match event_type { ++ 0 | 21 | 32 | 33 | 35 | 36 | 37 => { ++ return None; + } ++ _ => {} ++ } + +- match event_type { +- NSEventType::NSFlagsChanged => { +- Some(Self::ModifiersChanged(ModifiersChangedEvent { +- modifiers: read_modifiers(native_event), +- capslock: Capslock { +- on: native_event +- .modifierFlags() +- .contains(NSEventModifierFlags::NSAlphaShiftKeyMask), ++ match event_type { ++ ET_FLAGS_CHANGED => Some(Self::ModifiersChanged(ModifiersChangedEvent { ++ modifiers: unsafe { read_modifiers(native_event) }, ++ capslock: Capslock { ++ on: { ++ let m: u64 = unsafe { (&*event).modifierFlags() as u64 }; ++ (m & MOD_CAPS_LOCK) != 0 ++ }, ++ }, ++ })), ++ ET_KEY_DOWN => Some(Self::KeyDown(KeyDownEvent { ++ keystroke: unsafe { parse_keystroke(native_event) }, ++ is_held: { unsafe { (&*event).isARepeat() } }, ++ })), ++ ET_KEY_UP => Some(Self::KeyUp(KeyUpEvent { ++ keystroke: unsafe { parse_keystroke(native_event) }, ++ })), ++ ET_LEFT_MOUSE_DOWN | ET_RIGHT_MOUSE_DOWN | ET_OTHER_MOUSE_DOWN => { ++ let bn: u64 = unsafe { (&*event).buttonNumber() as u64 }; ++ let button = match bn { ++ 0 => MouseButton::Left, ++ 1 => MouseButton::Right, ++ 2 => MouseButton::Middle, ++ 3 => MouseButton::Navigate(NavigationDirection::Back), ++ 4 => MouseButton::Navigate(NavigationDirection::Forward), ++ // Other mouse buttons aren't tracked currently ++ _ => return None, ++ }; ++ window_height.map(|window_height| { ++ Self::MouseDown(MouseDownEvent { ++ button, ++ position: { ++ let p: NSPoint = msg_send![native_event, locationInWindow]; ++ point(px(p.x as f32), window_height - px(p.y as f32)) + }, +- })) +- } +- NSEventType::NSKeyDown => Some(Self::KeyDown(KeyDownEvent { +- keystroke: parse_keystroke(native_event), +- is_held: native_event.isARepeat() == YES, +- })), +- NSEventType::NSKeyUp => Some(Self::KeyUp(KeyUpEvent { +- keystroke: parse_keystroke(native_event), +- })), +- NSEventType::NSLeftMouseDown +- | NSEventType::NSRightMouseDown +- | NSEventType::NSOtherMouseDown => { +- let button = match native_event.buttonNumber() { +- 0 => MouseButton::Left, +- 1 => MouseButton::Right, +- 2 => MouseButton::Middle, +- 3 => MouseButton::Navigate(NavigationDirection::Back), +- 4 => MouseButton::Navigate(NavigationDirection::Forward), +- // Other mouse buttons aren't tracked currently +- _ => return None, +- }; +- window_height.map(|window_height| { +- Self::MouseDown(MouseDownEvent { +- button, +- position: point( +- px(native_event.locationInWindow().x as f32), +- // MacOS screen coordinates are relative to bottom left +- window_height - px(native_event.locationInWindow().y as f32), +- ), +- modifiers: read_modifiers(native_event), +- click_count: native_event.clickCount() as usize, +- first_mouse: false, +- }) +- }) +- } +- NSEventType::NSLeftMouseUp +- | NSEventType::NSRightMouseUp +- | NSEventType::NSOtherMouseUp => { +- let button = match native_event.buttonNumber() { +- 0 => MouseButton::Left, +- 1 => MouseButton::Right, +- 2 => MouseButton::Middle, +- 3 => MouseButton::Navigate(NavigationDirection::Back), +- 4 => MouseButton::Navigate(NavigationDirection::Forward), +- // Other mouse buttons aren't tracked currently +- _ => return None, +- }; +- +- window_height.map(|window_height| { +- Self::MouseUp(MouseUpEvent { +- button, +- position: point( +- px(native_event.locationInWindow().x as f32), +- window_height - px(native_event.locationInWindow().y as f32), +- ), +- modifiers: read_modifiers(native_event), +- click_count: native_event.clickCount() as usize, +- }) ++ modifiers: unsafe { read_modifiers(native_event) }, ++ click_count: { ++ let c: isize = unsafe { (&*event).clickCount() }; ++ c as usize ++ }, ++ first_mouse: false, + }) +- } +- // Some mice (like Logitech MX Master) send navigation buttons as swipe events +- NSEventType::NSEventTypeSwipe => { +- let navigation_direction = match native_event.phase() { +- NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() { +- x if x > 0.0 => Some(NavigationDirection::Back), +- x if x < 0.0 => Some(NavigationDirection::Forward), +- _ => return None, ++ }) ++ } ++ ET_LEFT_MOUSE_UP | ET_RIGHT_MOUSE_UP | ET_OTHER_MOUSE_UP => { ++ let bn: u64 = unsafe { (&*event).buttonNumber() as u64 }; ++ let button = match bn { ++ 0 => MouseButton::Left, ++ 1 => MouseButton::Right, ++ 2 => MouseButton::Middle, ++ 3 => MouseButton::Navigate(NavigationDirection::Back), ++ 4 => MouseButton::Navigate(NavigationDirection::Forward), ++ // Other mouse buttons aren't tracked currently ++ _ => return None, ++ }; ++ ++ window_height.map(|window_height| { ++ Self::MouseUp(MouseUpEvent { ++ button, ++ position: { ++ let p = unsafe { (&*event).locationInWindow() }; ++ point(px(p.x as f32), window_height - px(p.y as f32)) ++ }, ++ modifiers: unsafe { read_modifiers(native_event) }, ++ click_count: { ++ let c: isize = unsafe { (&*event).clickCount() }; ++ c as usize + }, +- _ => return None, +- }; +- +- match navigation_direction { +- Some(direction) => window_height.map(|window_height| { +- Self::MouseDown(MouseDownEvent { +- button: MouseButton::Navigate(direction), +- position: point( +- px(native_event.locationInWindow().x as f32), +- window_height - px(native_event.locationInWindow().y as f32), +- ), +- modifiers: read_modifiers(native_event), +- click_count: 1, +- first_mouse: false, +- }) +- }), +- _ => None, +- } +- } +- NSEventType::NSScrollWheel => window_height.map(|window_height| { +- let phase = match native_event.phase() { +- NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { +- TouchPhase::Started +- } +- NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, +- _ => TouchPhase::Moved, +- }; +- +- let raw_data = point( +- native_event.scrollingDeltaX() as f32, +- native_event.scrollingDeltaY() as f32, +- ); +- +- let delta = if native_event.hasPreciseScrollingDeltas() == YES { +- ScrollDelta::Pixels(raw_data.map(px)) +- } else { +- ScrollDelta::Lines(raw_data) +- }; +- +- Self::ScrollWheel(ScrollWheelEvent { +- position: point( +- px(native_event.locationInWindow().x as f32), +- window_height - px(native_event.locationInWindow().y as f32), +- ), +- delta, +- touch_phase: phase, +- modifiers: read_modifiers(native_event), + }) +- }), +- NSEventType::NSLeftMouseDragged +- | NSEventType::NSRightMouseDragged +- | NSEventType::NSOtherMouseDragged => { +- let pressed_button = match native_event.buttonNumber() { +- 0 => MouseButton::Left, +- 1 => MouseButton::Right, +- 2 => MouseButton::Middle, +- 3 => MouseButton::Navigate(NavigationDirection::Back), +- 4 => MouseButton::Navigate(NavigationDirection::Forward), +- // Other mouse buttons aren't tracked currently ++ }) ++ } ++ // Some mice (like Logitech MX Master) send navigation buttons as swipe events ++ ET_SWIPE => { ++ let phase: u64 = msg_send![native_event, phase]; ++ let navigation_direction = match phase { ++ PHASE_ENDED => match { ++ let dx: f64 = unsafe { (&*event).deltaX() }; ++ dx ++ } { ++ x if x > 0.0 => Some(NavigationDirection::Back), ++ x if x < 0.0 => Some(NavigationDirection::Forward), + _ => return None, +- }; +- +- window_height.map(|window_height| { +- Self::MouseMove(MouseMoveEvent { +- pressed_button: Some(pressed_button), +- position: point( +- px(native_event.locationInWindow().x as f32), +- window_height - px(native_event.locationInWindow().y as f32), +- ), +- modifiers: read_modifiers(native_event), ++ }, ++ _ => return None, ++ }; ++ ++ match navigation_direction { ++ Some(direction) => window_height.map(|window_height| { ++ Self::MouseDown(MouseDownEvent { ++ button: MouseButton::Navigate(direction), ++ position: { ++ let p = unsafe { (&*event).locationInWindow() }; ++ point(px(p.x as f32), window_height - px(p.y as f32)) ++ }, ++ modifiers: unsafe { read_modifiers(native_event) }, ++ click_count: 1, ++ first_mouse: false, + }) +- }) ++ }), ++ _ => None, + } +- NSEventType::NSMouseMoved => window_height.map(|window_height| { ++ } ++ ET_SCROLL_WHEEL => window_height.map(|window_height| { ++ let phase_val: u64 = unsafe { (&*event).momentumPhase() as u64 }; ++ let phase = match phase_val { ++ PHASE_MAY_BEGIN | PHASE_BEGAN => TouchPhase::Started, ++ PHASE_ENDED => TouchPhase::Ended, ++ _ => TouchPhase::Moved, ++ }; ++ ++ let raw_data = { ++ let dx: f64 = unsafe { (&*event).scrollingDeltaX() }; ++ let dy: f64 = unsafe { (&*event).scrollingDeltaY() }; ++ point(dx as f32, dy as f32) ++ }; ++ ++ let precise = unsafe { (&*event).hasPreciseScrollingDeltas() }; ++ let delta = if precise { ++ ScrollDelta::Pixels(raw_data.map(px)) ++ } else { ++ ScrollDelta::Lines(raw_data) ++ }; ++ ++ Self::ScrollWheel(ScrollWheelEvent { ++ position: { ++ let p = unsafe { (&*event).locationInWindow() }; ++ point(px(p.x as f32), window_height - px(p.y as f32)) ++ }, ++ delta, ++ touch_phase: phase, ++ modifiers: unsafe { read_modifiers(native_event) }, ++ }) ++ }), ++ ET_LEFT_MOUSE_DRAGGED | ET_RIGHT_MOUSE_DRAGGED | ET_OTHER_MOUSE_DRAGGED => { ++ let bn: u64 = unsafe { (&*event).buttonNumber() as u64 }; ++ let pressed_button = match bn { ++ 0 => MouseButton::Left, ++ 1 => MouseButton::Right, ++ 2 => MouseButton::Middle, ++ 3 => MouseButton::Navigate(NavigationDirection::Back), ++ 4 => MouseButton::Navigate(NavigationDirection::Forward), ++ // Other mouse buttons aren't tracked currently ++ _ => return None, ++ }; ++ ++ window_height.map(|window_height| { + Self::MouseMove(MouseMoveEvent { +- position: point( +- px(native_event.locationInWindow().x as f32), +- window_height - px(native_event.locationInWindow().y as f32), +- ), +- pressed_button: None, +- modifiers: read_modifiers(native_event), +- }) +- }), +- NSEventType::NSMouseExited => window_height.map(|window_height| { +- Self::MouseExited(MouseExitEvent { +- position: point( +- px(native_event.locationInWindow().x as f32), +- window_height - px(native_event.locationInWindow().y as f32), +- ), +- +- pressed_button: None, +- modifiers: read_modifiers(native_event), ++ pressed_button: Some(pressed_button), ++ position: { ++ let p = unsafe { (&*event).locationInWindow() }; ++ point(px(p.x as f32), window_height - px(p.y as f32)) ++ }, ++ modifiers: unsafe { read_modifiers(native_event) }, + }) +- }), +- _ => None, ++ }) + } ++ ET_MOUSE_MOVED => window_height.map(|window_height| { ++ Self::MouseMove(MouseMoveEvent { ++ position: { ++ let p = unsafe { (&*event).locationInWindow() }; ++ point(px(p.x as f32), window_height - px(p.y as f32)) ++ }, ++ pressed_button: None, ++ modifiers: unsafe { read_modifiers(native_event) }, ++ }) ++ }), ++ ET_MOUSE_EXITED => window_height.map(|window_height| { ++ Self::MouseExited(MouseExitEvent { ++ position: { ++ let p = unsafe { (&*event).locationInWindow() }; ++ point(px(p.x as f32), window_height - px(p.y as f32)) ++ }, ++ ++ pressed_button: None, ++ modifiers: unsafe { read_modifiers(native_event) }, ++ }) ++ }), ++ _ => None, + } + } + } + +-unsafe fn parse_keystroke(native_event: id) -> Keystroke { +- unsafe { +- use cocoa::appkit::*; +- +- let mut characters = native_event +- .charactersIgnoringModifiers() +- .to_str() +- .to_string(); +- let mut key_char = None; +- let first_char = characters.chars().next().map(|ch| ch as u16); +- let modifiers = native_event.modifierFlags(); +- +- let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); +- let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); +- let mut shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); +- let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); +- let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask) +- && first_char +- .is_none_or(|ch| !(NSUpArrowFunctionKey..=NSModeSwitchFunctionKey).contains(&ch)); +- +- #[allow(non_upper_case_globals)] +- let key = match first_char { +- Some(SPACE_KEY) => { +- key_char = Some(" ".to_string()); +- "space".to_string() +- } +- Some(TAB_KEY) => { +- key_char = Some("\t".to_string()); +- "tab".to_string() +- } +- Some(ENTER_KEY) | Some(NUMPAD_ENTER_KEY) => { +- key_char = Some("\n".to_string()); +- "enter".to_string() +- } +- Some(BACKSPACE_KEY) => "backspace".to_string(), +- Some(ESCAPE_KEY) => "escape".to_string(), +- Some(SHIFT_TAB_KEY) => "tab".to_string(), +- Some(NSUpArrowFunctionKey) => "up".to_string(), +- Some(NSDownArrowFunctionKey) => "down".to_string(), +- Some(NSLeftArrowFunctionKey) => "left".to_string(), +- Some(NSRightArrowFunctionKey) => "right".to_string(), +- Some(NSPageUpFunctionKey) => "pageup".to_string(), +- Some(NSPageDownFunctionKey) => "pagedown".to_string(), +- Some(NSHomeFunctionKey) => "home".to_string(), +- Some(NSEndFunctionKey) => "end".to_string(), +- Some(NSDeleteFunctionKey) => "delete".to_string(), +- // Observed Insert==NSHelpFunctionKey not NSInsertFunctionKey. +- Some(NSHelpFunctionKey) => "insert".to_string(), +- Some(NSF1FunctionKey) => "f1".to_string(), +- Some(NSF2FunctionKey) => "f2".to_string(), +- Some(NSF3FunctionKey) => "f3".to_string(), +- Some(NSF4FunctionKey) => "f4".to_string(), +- Some(NSF5FunctionKey) => "f5".to_string(), +- Some(NSF6FunctionKey) => "f6".to_string(), +- Some(NSF7FunctionKey) => "f7".to_string(), +- Some(NSF8FunctionKey) => "f8".to_string(), +- Some(NSF9FunctionKey) => "f9".to_string(), +- Some(NSF10FunctionKey) => "f10".to_string(), +- Some(NSF11FunctionKey) => "f11".to_string(), +- Some(NSF12FunctionKey) => "f12".to_string(), +- Some(NSF13FunctionKey) => "f13".to_string(), +- Some(NSF14FunctionKey) => "f14".to_string(), +- Some(NSF15FunctionKey) => "f15".to_string(), +- Some(NSF16FunctionKey) => "f16".to_string(), +- Some(NSF17FunctionKey) => "f17".to_string(), +- Some(NSF18FunctionKey) => "f18".to_string(), +- Some(NSF19FunctionKey) => "f19".to_string(), +- Some(NSF20FunctionKey) => "f20".to_string(), +- Some(NSF21FunctionKey) => "f21".to_string(), +- Some(NSF22FunctionKey) => "f22".to_string(), +- Some(NSF23FunctionKey) => "f23".to_string(), +- Some(NSF24FunctionKey) => "f24".to_string(), +- Some(NSF25FunctionKey) => "f25".to_string(), +- Some(NSF26FunctionKey) => "f26".to_string(), +- Some(NSF27FunctionKey) => "f27".to_string(), +- Some(NSF28FunctionKey) => "f28".to_string(), +- Some(NSF29FunctionKey) => "f29".to_string(), +- Some(NSF30FunctionKey) => "f30".to_string(), +- Some(NSF31FunctionKey) => "f31".to_string(), +- Some(NSF32FunctionKey) => "f32".to_string(), +- Some(NSF33FunctionKey) => "f33".to_string(), +- Some(NSF34FunctionKey) => "f34".to_string(), +- Some(NSF35FunctionKey) => "f35".to_string(), +- _ => { +- // Cases to test when modifying this: +- // +- // qwerty key | none | cmd | cmd-shift +- // * Armenian s | ս | cmd-s | cmd-shift-s (layout is non-ASCII, so we use cmd layout) +- // * Dvorak+QWERTY s | o | cmd-s | cmd-shift-s (layout switches on cmd) +- // * Ukrainian+QWERTY s | с | cmd-s | cmd-shift-s (macOS reports cmd-s instead of cmd-S) +- // * Czech 7 | ý | cmd-ý | cmd-7 (layout has shifted numbers) +- // * Norwegian 7 | 7 | cmd-7 | cmd-/ (macOS reports cmd-shift-7 instead of cmd-/) +- // * Russian 7 | 7 | cmd-7 | cmd-& (shift-7 is . but when cmd is down, should use cmd layout) +- // * German QWERTZ ; | ö | cmd-ö | cmd-Ö (Zed's shift special case only applies to a-z) +- // +- let mut chars_ignoring_modifiers = +- chars_for_modified_key(native_event.keyCode(), NO_MOD); +- let mut chars_with_shift = +- chars_for_modified_key(native_event.keyCode(), SHIFT_MOD); +- let always_use_cmd_layout = always_use_command_layout(); +- +- // Handle Dvorak+QWERTY / Russian / Armenian +- if command || always_use_cmd_layout { +- let chars_with_cmd = chars_for_modified_key(native_event.keyCode(), CMD_MOD); +- let chars_with_both = +- chars_for_modified_key(native_event.keyCode(), CMD_MOD | SHIFT_MOD); +- +- // We don't do this in the case that the shifted command key generates +- // the same character as the unshifted command key (Norwegian, e.g.) +- if chars_with_both != chars_with_cmd { +- chars_with_shift = chars_with_both; +- +- // Handle edge-case where cmd-shift-s reports cmd-s instead of +- // cmd-shift-s (Ukrainian, etc.) +- } else if chars_with_cmd.to_ascii_uppercase() != chars_with_cmd { +- chars_with_shift = chars_with_cmd.to_ascii_uppercase(); +- } +- chars_ignoring_modifiers = chars_with_cmd; +- } ++unsafe fn parse_keystroke(native_event: ObjcId) -> Keystroke { ++ let event = native_event as *const NSEvent; ++ // Keep msg_send for charactersIgnoringModifiers for now; bridging Id ++ // from icrate would add conversion complexity without clear benefit here. ++ let cim: ObjcId = msg_send![native_event, charactersIgnoringModifiers]; ++ let mut characters = unsafe { cim.to_str() }.to_string(); ++ let mut key_char = None; ++ let first_char = characters.chars().next().map(|ch| ch as u16); ++ let modifiers: u64 = unsafe { (&*event).modifierFlags() as u64 }; ++ ++ let control = (modifiers & MOD_CONTROL) != 0; ++ let alt = (modifiers & MOD_OPTION) != 0; ++ let mut shift = (modifiers & MOD_SHIFT) != 0; ++ let command = (modifiers & MOD_COMMAND) != 0; ++ let function = (modifiers & MOD_FUNCTION) != 0 ++ && first_char.is_none_or(|ch| !(0xF700..=0xF8FF).contains(&ch)); + +- if !control && !command && !function { +- let mut mods = NO_MOD; +- if shift { +- mods |= SHIFT_MOD; +- } +- if alt { +- mods |= OPTION_MOD; +- } +- +- key_char = Some(chars_for_modified_key(native_event.keyCode(), mods)); ++ #[allow(non_upper_case_globals)] ++ let key = match first_char { ++ Some(SPACE_KEY) => { ++ key_char = Some(" ".to_string()); ++ "space".to_string() ++ } ++ Some(TAB_KEY) => { ++ key_char = Some("\t".to_string()); ++ "tab".to_string() ++ } ++ Some(ENTER_KEY) | Some(NUMPAD_ENTER_KEY) => { ++ key_char = Some("\n".to_string()); ++ "enter".to_string() ++ } ++ Some(BACKSPACE_KEY) => "backspace".to_string(), ++ Some(ESCAPE_KEY) => "escape".to_string(), ++ Some(SHIFT_TAB_KEY) => "tab".to_string(), ++ Some(NS_UP_ARROW) => "up".to_string(), ++ Some(NS_DOWN_ARROW) => "down".to_string(), ++ Some(NS_LEFT_ARROW) => "left".to_string(), ++ Some(NS_RIGHT_ARROW) => "right".to_string(), ++ Some(NS_PAGE_UP) => "pageup".to_string(), ++ Some(NS_PAGE_DOWN) => "pagedown".to_string(), ++ Some(NS_HOME) => "home".to_string(), ++ Some(NS_END) => "end".to_string(), ++ Some(NS_DELETE_FN) => "delete".to_string(), ++ // Observed Insert==NSHelpFunctionKey not NSInsertFunctionKey. ++ Some(NS_HELP_FN) => "insert".to_string(), ++ Some(fc) if (0xF704..=0xF726).contains(&fc) => { ++ let n = fc - 0xF703u16; ++ format!("f{}", n) ++ } ++ _ => { ++ // Cases to test when modifying this: ++ // ++ // qwerty key | none | cmd | cmd-shift ++ // * Armenian s | ս | cmd-s | cmd-shift-s (layout is non-ASCII, so we use cmd layout) ++ // * Dvorak+QWERTY s | o | cmd-s | cmd-shift-s (layout switches on cmd) ++ // * Ukrainian+QWERTY s | с | cmd-s | cmd-shift-s (macOS reports cmd-s instead of cmd-S) ++ // * Czech 7 | ý | cmd-ý | cmd-7 (layout has shifted numbers) ++ // * Norwegian 7 | 7 | cmd-7 | cmd-/ (macOS reports cmd-shift-7 instead of cmd-/) ++ // * Russian 7 | 7 | cmd-7 | cmd-& (shift-7 is . but when cmd is down, should use cmd layout) ++ // * German QWERTZ ; | ö | cmd-ö | cmd-Ö (Zed's shift special case only applies to a-z) ++ // ++ let key_code: u16 = unsafe { (&*event).keyCode() }; ++ let mut chars_ignoring_modifiers = chars_for_modified_key(key_code, NO_MOD); ++ let mut chars_with_shift = chars_for_modified_key(key_code, SHIFT_MOD); ++ let always_use_cmd_layout = always_use_command_layout(); ++ ++ // Handle Dvorak+QWERTY / Russian / Armenian ++ if command || always_use_cmd_layout { ++ let chars_with_cmd = chars_for_modified_key(key_code, CMD_MOD); ++ let chars_with_both = chars_for_modified_key(key_code, CMD_MOD | SHIFT_MOD); ++ ++ // We don't do this in the case that the shifted command key generates ++ // the same character as the unshifted command key (Norwegian, e.g.) ++ if chars_with_both != chars_with_cmd { ++ chars_with_shift = chars_with_both; ++ ++ // Handle edge-case where cmd-shift-s reports cmd-s instead of ++ // cmd-shift-s (Ukrainian, etc.) ++ } else if chars_with_cmd.to_ascii_uppercase() != chars_with_cmd { ++ chars_with_shift = chars_with_cmd.to_ascii_uppercase(); + } ++ chars_ignoring_modifiers = chars_with_cmd; ++ } + +- if shift +- && chars_ignoring_modifiers +- .chars() +- .all(|c| c.is_ascii_lowercase()) +- { +- chars_ignoring_modifiers +- } else if shift { +- shift = false; +- chars_with_shift +- } else { +- chars_ignoring_modifiers ++ if !control && !command && !function { ++ let mut mods = NO_MOD; ++ if shift { ++ mods |= SHIFT_MOD; ++ } ++ if alt { ++ mods |= OPTION_MOD; + } ++ ++ key_char = Some(chars_for_modified_key(key_code, mods)); ++ } ++ ++ if shift ++ && chars_ignoring_modifiers ++ .chars() ++ .all(|c| c.is_ascii_lowercase()) ++ { ++ chars_ignoring_modifiers ++ } else if shift { ++ shift = false; ++ chars_with_shift ++ } else { ++ chars_ignoring_modifiers + } +- }; +- +- Keystroke { +- modifiers: Modifiers { +- control, +- alt, +- shift, +- platform: command, +- function, +- }, +- key, +- key_char, + } ++ }; ++ ++ Keystroke { ++ modifiers: Modifiers { ++ control, ++ alt, ++ shift, ++ platform: command, ++ function, ++ }, ++ key, ++ key_char, + } + } + +diff --git a/crates/gpui/src/platform/mac/keyboard.rs b/crates/gpui/src/platform/mac/keyboard.rs +index 1409731246..7898ffe345 100644 +--- a/crates/gpui/src/platform/mac/keyboard.rs ++++ b/crates/gpui/src/platform/mac/keyboard.rs +@@ -55,19 +55,41 @@ impl MacKeyboardLayout { + unsafe { + let current_keyboard = TISCopyCurrentKeyboardLayoutInputSource(); + +- let id: *mut Object = TISGetInputSourceProperty( ++ // Default values if the system does not report a current layout ++ if current_keyboard.is_null() { ++ return Self { ++ id: "unknown".to_string(), ++ name: "Unknown".to_string(), ++ }; ++ } ++ ++ // Helper to read a UTF8String from an Objective‑C string-like object ++ unsafe fn utf8(obj: *mut Object) -> Option { ++ if obj.is_null() { ++ return None; ++ } ++ let ptr: *const std::os::raw::c_char = msg_send![obj, UTF8String]; ++ if ptr.is_null() { ++ return None; ++ } ++ // SAFETY: `ptr` is valid for the duration of this call; we copy into an owned String ++ Some(unsafe { CStr::from_ptr(ptr) }.to_str().ok()?.to_string()) ++ } ++ ++ let id_obj: *mut Object = TISGetInputSourceProperty( + current_keyboard, + kTISPropertyInputSourceID as *const c_void, + ); +- let id: *const std::os::raw::c_char = msg_send![id, UTF8String]; +- let id = CStr::from_ptr(id).to_str().unwrap().to_string(); +- +- let name: *mut Object = TISGetInputSourceProperty( ++ let name_obj: *mut Object = TISGetInputSourceProperty( + current_keyboard, + kTISPropertyLocalizedName as *const c_void, + ); +- let name: *const std::os::raw::c_char = msg_send![name, UTF8String]; +- let name = CStr::from_ptr(name).to_str().unwrap().to_string(); ++ ++ let id = utf8(id_obj).unwrap_or_else(|| "unknown".to_string()); ++ let name = utf8(name_obj).unwrap_or_else(|| "Unknown".to_string()); ++ ++ // TISCopy* follows the Create/Copy rule; release when done to avoid leaks ++ let _: () = msg_send![current_keyboard, release]; + + Self { id, name } + } +diff --git a/crates/gpui/src/platform/mac/open_type.rs b/crates/gpui/src/platform/mac/open_type.rs +index 37a29559fd..d63fa74796 100644 +--- a/crates/gpui/src/platform/mac/open_type.rs ++++ b/crates/gpui/src/platform/mac/open_type.rs +@@ -1,7 +1,6 @@ + #![allow(unused, non_upper_case_globals)] + + use crate::{FontFallbacks, FontFeatures}; +-use cocoa::appkit::CGFloat; + use core_foundation::{ + array::{ + CFArray, CFArrayAppendArray, CFArrayAppendValue, CFArrayCreateMutable, CFArrayGetCount, +@@ -15,6 +14,7 @@ use core_foundation::{ + string::{CFString, CFStringRef}, + }; + use core_foundation_sys::locale::CFLocaleCopyPreferredLanguages; ++use core_graphics::base::CGFloat; + use core_graphics::{display::CFDictionary, geometry::CGAffineTransform}; + use core_text::{ + font::{CTFont, CTFontRef, cascade_list_for_languages}, +diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs +index dea04d89a0..971a2e8856 100644 +--- a/crates/gpui/src/platform/mac/platform.rs ++++ b/crates/gpui/src/platform/mac/platform.rs +@@ -1,6 +1,6 @@ + use super::{ + BoolExt, MacKeyboardLayout, MacKeyboardMapper, +- attributed_string::{NSAttributedString, NSMutableAttributedString}, ++ attributed_string::{NSAttributedString, NSMutableAttributedString, NSRange}, + events::key_to_native, + renderer, + }; +@@ -17,13 +17,11 @@ use block::ConcreteBlock; + use cocoa::{ + appkit::{ + NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, +- NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, +- NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeRTFD, NSPasteboardTypeString, +- NSPasteboardTypeTIFF, NSSavePanel, NSWindow, ++ NSEventModifierFlags, NSPasteboard, NSWindow, + }, + base::{BOOL, NO, YES, id, nil, selector}, + foundation::{ +- NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, ++ NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSString, + NSUInteger, NSURL, + }, + }; +@@ -37,6 +35,10 @@ use core_foundation::{ + }; + use ctor::ctor; + use futures::channel::oneshot; ++use icrate::AppKit::{ ++ NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeRTFD, NSPasteboardTypeString, ++ NSPasteboardTypeTIFF, NSScrollerStyleOverlay, ++}; + use itertools::Itertools; + use objc::{ + class, +@@ -45,7 +47,108 @@ use objc::{ + runtime::{Class, Object, Sel}, + sel, sel_impl, + }; ++// objc2 typed migration will be introduced incrementally in focused sections. ++// Swift C-ABI functions provided by the macOS AppKit shim + use parking_lot::Mutex; ++#[cfg(target_os = "macos")] ++unsafe extern "C" { ++ fn zed_register_menu_handler(); ++ fn zed_set_main_menu_json(json: *const ::std::os::raw::c_char); ++ fn zed_open_panel(request_id: u64, json: *const ::std::os::raw::c_char); ++ fn zed_save_panel(request_id: u64, json: *const ::std::os::raw::c_char); ++ fn zed_pasteboard_write_text(text: *const ::std::os::raw::c_char); ++ fn zed_pasteboard_write_image(bytes: *const u8, len: usize, uti: *const ::std::os::raw::c_char); ++ fn zed_pasteboard_read_image( ++ uti: *const ::std::os::raw::c_char, ++ out_len: *mut usize, ++ ) -> *mut u8; ++} ++#[cfg(target_os = "macos")] ++#[unsafe(no_mangle)] ++pub extern "C" fn gpui_menu_action(tag: u64) { ++ unsafe { ++ let app: id = msg_send![APP_CLASS, sharedApplication]; ++ let app_obj: &mut Object = &mut *app; ++ let platform = get_mac_platform(app_obj); ++ let mut lock = platform.0.lock(); ++ if let Some(mut callback) = lock.menu_command.take() { ++ let index = tag as usize; ++ if let Some(action) = lock.menu_actions.get(index) { ++ let action = action.boxed_clone(); ++ drop(lock); ++ callback(action.as_ref()); ++ platform.0.lock().menu_command.get_or_insert(callback); ++ return; ++ } ++ // Put the callback back even if we did not find an action ++ platform.0.lock().menu_command.get_or_insert(callback); ++ } ++ } ++} ++ ++#[cfg(target_os = "macos")] ++#[unsafe(no_mangle)] ++pub extern "C" fn gpui_validate_menu_action(tag: u64) -> bool { ++ unsafe { ++ let app: id = msg_send![APP_CLASS, sharedApplication]; ++ let app_obj: &mut Object = &mut *app; ++ let platform = get_mac_platform(app_obj); ++ let mut lock = platform.0.lock(); ++ if let Some(mut callback) = lock.validate_menu_command.take() { ++ let index = tag as usize; ++ if let Some(action) = lock.menu_actions.get(index) { ++ let action = action.boxed_clone(); ++ drop(lock); ++ let result = callback(action.as_ref()); ++ platform ++ .0 ++ .lock() ++ .validate_menu_command ++ .get_or_insert(callback); ++ return result; ++ } ++ platform ++ .0 ++ .lock() ++ .validate_menu_command ++ .get_or_insert(callback); ++ } ++ // Default to enabled when no validator is registered or tag not found ++ true ++ } ++} ++ ++#[cfg(target_os = "macos")] ++#[unsafe(no_mangle)] ++pub extern "C" fn gpui_menu_will_open() { ++ unsafe { ++ let app: id = msg_send![APP_CLASS, sharedApplication]; ++ let app_obj: &mut Object = &mut *app; ++ let platform = get_mac_platform(app_obj); ++ if let Some(mut callback) = platform.0.lock().will_open_menu.take() { ++ callback(); ++ platform.0.lock().will_open_menu.get_or_insert(callback); ++ } ++ } ++} ++ ++// Expose a dispatcher for status item menus to reuse the same app-level menu callback ++pub(crate) fn dispatch_menu_action(action: &dyn crate::Action) { ++ unsafe { ++ let app: id = msg_send![APP_CLASS, sharedApplication]; ++ let app_obj: &mut Object = &mut *app; ++ let platform = get_mac_platform(app_obj); ++ let mut lock = platform.0.lock(); ++ if let Some(mut callback) = lock.menu_command.take() { ++ let act = action.boxed_clone(); ++ drop(lock); ++ callback(act.as_ref()); ++ platform.0.lock().menu_command.get_or_insert(callback); ++ } ++ } ++} ++ ++// (Status item click callback is exported by status_item.rs) + use ptr::null_mut; + use std::{ + cell::Cell, +@@ -232,6 +335,8 @@ impl MacPlatform { + } + } + ++ #[cfg(not(target_os = "macos"))] ++ #[allow(dead_code)] + unsafe fn create_menu_bar( + &self, + menus: &Vec, +@@ -240,32 +345,31 @@ impl MacPlatform { + keymap: &Keymap, + ) -> id { + unsafe { +- let application_menu = NSMenu::new(nil).autorelease(); +- application_menu.setDelegate_(delegate); ++ let mut application_menu: id = msg_send![class!(NSMenu), new]; ++ application_menu = msg_send![application_menu, autorelease]; ++ let _: () = msg_send![application_menu, setDelegate: delegate]; + + for menu_config in menus { +- let menu = NSMenu::new(nil).autorelease(); ++ let mut menu: id = msg_send![class!(NSMenu), new]; ++ menu = msg_send![menu, autorelease]; + let menu_title = ns_string(&menu_config.name); +- menu.setTitle_(menu_title); +- menu.setDelegate_(delegate); ++ let _: () = msg_send![menu, setTitle: menu_title]; ++ let _: () = msg_send![menu, setDelegate: delegate]; + + for item_config in &menu_config.items { +- menu.addItem_(Self::create_menu_item( +- item_config, +- delegate, +- actions, +- keymap, +- )); ++ Self::add_menu_item(menu, item_config, delegate, actions, keymap); + } + +- let menu_item = NSMenuItem::new(nil).autorelease(); +- menu_item.setTitle_(menu_title); +- menu_item.setSubmenu_(menu); +- application_menu.addItem_(menu_item); ++ let mut menu_item: id = msg_send![class!(NSMenuItem), alloc]; ++ menu_item = msg_send![menu_item, init]; ++ menu_item = msg_send![menu_item, autorelease]; ++ let _: () = msg_send![menu_item, setTitle: menu_title]; ++ let _: () = msg_send![menu_item, setSubmenu: menu]; ++ let _: () = msg_send![application_menu, addItem: menu_item]; + + if menu_config.name == "Window" { + let app: id = msg_send![APP_CLASS, sharedApplication]; +- app.setWindowsMenu_(menu); ++ let _: () = msg_send![app, setWindowsMenu: menu]; + } + } + +@@ -281,21 +385,170 @@ impl MacPlatform { + keymap: &Keymap, + ) -> id { + unsafe { +- let dock_menu = NSMenu::new(nil); +- dock_menu.setDelegate_(delegate); ++ let dock_menu: id = msg_send![class!(NSMenu), new]; ++ let _: () = msg_send![dock_menu, setDelegate: delegate]; + for item_config in menu_items { +- dock_menu.addItem_(Self::create_menu_item( +- &item_config, +- delegate, +- actions, +- keymap, +- )); ++ Self::add_menu_item(dock_menu, &item_config, delegate, actions, keymap); + } + + dock_menu + } + } + ++ unsafe fn add_menu_item( ++ parent_menu: id, ++ item: &MenuItem, ++ delegate: id, ++ actions: &mut Vec>, ++ keymap: &Keymap, ++ ) { ++ static DEFAULT_CONTEXT: OnceLock> = OnceLock::new(); ++ ++ unsafe { ++ match item { ++ MenuItem::Separator => { ++ let sep: id = msg_send![class!(NSMenuItem), separatorItem]; ++ let _: () = msg_send![parent_menu, addItem: sep]; ++ } ++ MenuItem::Action { ++ name, ++ action, ++ os_action, ++ } => { ++ let keystrokes = keymap ++ .bindings_for_action(action.as_ref()) ++ .find_or_first(|binding| { ++ binding.predicate().is_none_or(|predicate| { ++ predicate.eval(DEFAULT_CONTEXT.get_or_init(|| { ++ let mut workspace_context = KeyContext::new_with_defaults(); ++ workspace_context.add("Workspace"); ++ let mut pane_context = KeyContext::new_with_defaults(); ++ pane_context.add("Pane"); ++ let mut editor_context = KeyContext::new_with_defaults(); ++ editor_context.add("Editor"); ++ ++ pane_context.extend(&editor_context); ++ workspace_context.extend(&pane_context); ++ vec![workspace_context] ++ })) ++ }) ++ }) ++ .map(|binding| binding.keystrokes()); ++ ++ let selector = match os_action { ++ Some(crate::OsAction::Cut) => selector("cut:"), ++ Some(crate::OsAction::Copy) => selector("copy:"), ++ Some(crate::OsAction::Paste) => selector("paste:"), ++ Some(crate::OsAction::SelectAll) => selector("selectAll:"), ++ Some(crate::OsAction::Undo) => selector("handleGPUIMenuItem:"), ++ Some(crate::OsAction::Redo) => selector("handleGPUIMenuItem:"), ++ None => selector("handleGPUIMenuItem:"), ++ }; ++ ++ let item: id = if let Some(keystrokes) = keystrokes { ++ if keystrokes.len() == 1 { ++ let keystroke = &keystrokes[0]; ++ let mut mask = NSEventModifierFlags::empty(); ++ for (modifier, flag) in &[ ++ ( ++ keystroke.modifiers().platform, ++ NSEventModifierFlags::NSCommandKeyMask, ++ ), ++ ( ++ keystroke.modifiers().control, ++ NSEventModifierFlags::NSControlKeyMask, ++ ), ++ ( ++ keystroke.modifiers().alt, ++ NSEventModifierFlags::NSAlternateKeyMask, ++ ), ++ ( ++ keystroke.modifiers().shift, ++ NSEventModifierFlags::NSShiftKeyMask, ++ ), ++ ] { ++ if *modifier { ++ mask |= *flag; ++ } ++ } ++ ++ let mut tmp: id = msg_send![class!(NSMenuItem), alloc]; ++ tmp = msg_send![ ++ tmp, ++ initWithTitle: ns_string(name) ++ action: selector ++ keyEquivalent: ns_string(key_to_native(keystroke.key()).as_ref()) ++ ]; ++ let item: id = msg_send![tmp, autorelease]; ++ if Self::os_version() >= SemanticVersion::new(12, 0, 0) { ++ let _: () = msg_send![item, setAllowsAutomaticKeyEquivalentLocalization: NO]; ++ } ++ let _: () = msg_send![item, setKeyEquivalentModifierMask: mask]; ++ item ++ } else { ++ let mut tmp: id = msg_send![class!(NSMenuItem), alloc]; ++ tmp = msg_send![ ++ tmp, ++ initWithTitle: ns_string(name) ++ action: selector ++ keyEquivalent: ns_string("") ++ ]; ++ msg_send![tmp, autorelease] ++ } ++ } else { ++ let mut tmp: id = msg_send![class!(NSMenuItem), alloc]; ++ tmp = msg_send![ ++ tmp, ++ initWithTitle: ns_string(name) ++ action: selector ++ keyEquivalent: ns_string("") ++ ]; ++ msg_send![tmp, autorelease] ++ }; ++ ++ let tag = actions.len() as NSInteger; ++ let _: () = msg_send![item, setTag: tag]; ++ actions.push(action.boxed_clone()); ++ let _: () = msg_send![parent_menu, addItem: item]; ++ } ++ MenuItem::Submenu(Menu { name, items }) => { ++ let mut item: id = msg_send![class!(NSMenuItem), alloc]; ++ item = msg_send![item, init]; ++ item = msg_send![item, autorelease]; ++ let mut submenu: id = msg_send![class!(NSMenu), new]; ++ submenu = msg_send![submenu, autorelease]; ++ let _: () = msg_send![submenu, setDelegate: delegate]; ++ for subitem in items { ++ Self::add_menu_item(submenu, subitem, delegate, actions, keymap); ++ } ++ let _: () = msg_send![item, setSubmenu: submenu]; ++ let _: () = msg_send![item, setTitle: ns_string(name)]; ++ let _: () = msg_send![parent_menu, addItem: item]; ++ } ++ MenuItem::SystemMenu(OsMenu { name, menu_type }) => { ++ let mut item: id = msg_send![class!(NSMenuItem), alloc]; ++ item = msg_send![item, init]; ++ item = msg_send![item, autorelease]; ++ let mut submenu: id = msg_send![class!(NSMenu), new]; ++ submenu = msg_send![submenu, autorelease]; ++ let _: () = msg_send![submenu, setDelegate: delegate]; ++ let _: () = msg_send![item, setSubmenu: submenu]; ++ let _: () = msg_send![item, setTitle: ns_string(name)]; ++ ++ match menu_type { ++ SystemMenuType::Services => { ++ let app: id = msg_send![APP_CLASS, sharedApplication]; ++ let _: () = msg_send![app, setServicesMenu: item]; ++ } ++ } ++ ++ let _: () = msg_send![parent_menu, addItem: item]; ++ } ++ } ++ } ++ } ++ // Legacy helper removed; use add_menu_item instead ++ /* + unsafe fn create_menu_item( + item: &MenuItem, + delegate: id, +@@ -306,7 +559,7 @@ impl MacPlatform { + + unsafe { + match item { +- MenuItem::Separator => NSMenuItem::separatorItem(nil), ++ MenuItem::Separator => msg_send![class!(NSMenuItem), separatorItem], + MenuItem::Action { + name, + action, +@@ -347,7 +600,7 @@ impl MacPlatform { + None => selector("handleGPUIMenuItem:"), + }; + +- let item; ++ let mut item: id; + if let Some(keystrokes) = keystrokes { + if keystrokes.len() == 1 { + let keystroke = &keystrokes[0]; +@@ -375,34 +628,37 @@ impl MacPlatform { + } + } + +- item = NSMenuItem::alloc(nil) +- .initWithTitle_action_keyEquivalent_( +- ns_string(name), +- selector, +- ns_string(key_to_native(keystroke.key()).as_ref()), +- ) +- .autorelease(); ++ let mut tmp: id = msg_send![class!(NSMenuItem), alloc]; ++ tmp = msg_send![ ++ tmp, ++ initWithTitle: ns_string(name) ++ action: selector ++ keyEquivalent: ns_string(key_to_native(keystroke.key()).as_ref()) ++ ]; ++ item = msg_send![tmp, autorelease]; + if Self::os_version() >= SemanticVersion::new(12, 0, 0) { + let _: () = msg_send![item, setAllowsAutomaticKeyEquivalentLocalization: NO]; + } +- item.setKeyEquivalentModifierMask_(mask); ++ let _: () = msg_send![item, setKeyEquivalentModifierMask: mask]; + } else { +- item = NSMenuItem::alloc(nil) +- .initWithTitle_action_keyEquivalent_( +- ns_string(name), +- selector, +- ns_string(""), +- ) +- .autorelease(); ++ let mut tmp: id = msg_send![class!(NSMenuItem), alloc]; ++ tmp = msg_send![ ++ tmp, ++ initWithTitle: ns_string(name) ++ action: selector ++ keyEquivalent: ns_string("") ++ ]; ++ item = msg_send![tmp, autorelease]; + } + } else { +- item = NSMenuItem::alloc(nil) +- .initWithTitle_action_keyEquivalent_( +- ns_string(name), +- selector, +- ns_string(""), +- ) +- .autorelease(); ++ let mut tmp: id = msg_send![class!(NSMenuItem), alloc]; ++ tmp = msg_send![ ++ tmp, ++ initWithTitle: ns_string(name) ++ action: selector ++ keyEquivalent: ns_string("") ++ ]; ++ item = msg_send![tmp, autorelease]; + } + + let tag = actions.len() as NSInteger; +@@ -411,27 +667,33 @@ impl MacPlatform { + item + } + MenuItem::Submenu(Menu { name, items }) => { +- let item = NSMenuItem::new(nil).autorelease(); +- let submenu = NSMenu::new(nil).autorelease(); +- submenu.setDelegate_(delegate); ++ let mut item: id = msg_send![class!(NSMenuItem), alloc]; ++ item = msg_send![item, init]; ++ item = msg_send![item, autorelease]; ++ let mut submenu: id = msg_send![class!(NSMenu), new]; ++ submenu = msg_send![submenu, autorelease]; ++ let _: () = msg_send![submenu, setDelegate: delegate]; + for item in items { +- submenu.addItem_(Self::create_menu_item(item, delegate, actions, keymap)); ++ let _: () = msg_send![submenu, addItem: Self::create_menu_item(item, delegate, actions, keymap)]; + } +- item.setSubmenu_(submenu); +- item.setTitle_(ns_string(name)); ++ let _: () = msg_send![item, setSubmenu: submenu]; ++ let _: () = msg_send![item, setTitle: ns_string(name)]; + item + } + MenuItem::SystemMenu(OsMenu { name, menu_type }) => { +- let item = NSMenuItem::new(nil).autorelease(); +- let submenu = NSMenu::new(nil).autorelease(); +- submenu.setDelegate_(delegate); +- item.setSubmenu_(submenu); +- item.setTitle_(ns_string(name)); ++ let mut item: id = msg_send![class!(NSMenuItem), alloc]; ++ item = msg_send![item, init]; ++ item = msg_send![item, autorelease]; ++ let mut submenu: id = msg_send![class!(NSMenu), new]; ++ submenu = msg_send![submenu, autorelease]; ++ let _: () = msg_send![submenu, setDelegate: delegate]; ++ let _: () = msg_send![item, setSubmenu: submenu]; ++ let _: () = msg_send![item, setTitle: ns_string(name)]; + + match menu_type { + SystemMenuType::Services => { + let app: id = msg_send![APP_CLASS, sharedApplication]; +- app.setServicesMenu_(item); ++ let _: () = msg_send![app, setServicesMenu: item]; + } + } + +@@ -440,6 +702,7 @@ impl MacPlatform { + } + } + } ++ */ + + fn os_version() -> SemanticVersion { + let version = unsafe { +@@ -593,7 +856,12 @@ impl Platform for MacPlatform { + + #[cfg(feature = "screen-capture")] + fn is_screen_capture_supported(&self) -> bool { +- let min_version = cocoa::foundation::NSOperatingSystemVersion::new(12, 3, 0); ++ use icrate::Foundation::NSOperatingSystemVersion; ++ let min_version = NSOperatingSystemVersion { ++ majorVersion: 12, ++ minorVersion: 3, ++ patchVersion: 0, ++ }; + super::is_macos_version_at_least(min_version) + } + +@@ -703,50 +971,51 @@ impl Platform for MacPlatform { + &self, + options: PathPromptOptions, + ) -> oneshot::Receiver>>> { +- let (done_tx, done_rx) = oneshot::channel(); +- self.foreground_executor() +- .spawn(async move { +- unsafe { +- let panel = NSOpenPanel::openPanel(nil); +- panel.setCanChooseDirectories_(options.directories.to_objc()); +- panel.setCanChooseFiles_(options.files.to_objc()); +- panel.setAllowsMultipleSelection_(options.multiple.to_objc()); +- +- panel.setCanCreateDirectories(true.to_objc()); +- panel.setResolvesAliases_(false.to_objc()); +- let done_tx = Cell::new(Some(done_tx)); +- let block = ConcreteBlock::new(move |response: NSModalResponse| { +- let result = if response == NSModalResponse::NSModalResponseOk { +- let mut result = Vec::new(); +- let urls = panel.URLs(); +- for i in 0..urls.count() { +- let url = urls.objectAtIndex(i); +- if url.isFileURL() == YES +- && let Ok(path) = ns_url_to_path(url) +- { +- result.push(path) +- } +- } +- Some(result) +- } else { +- None +- }; +- +- if let Some(done_tx) = done_tx.take() { +- let _ = done_tx.send(Ok(result)); +- } +- }); +- let block = block.copy(); ++ #[cfg(target_os = "macos")] ++ { ++ use std::collections::HashMap; ++ use std::sync::{Mutex as StdMutex, OnceLock}; ++ type OpenTx = oneshot::Sender>>>; ++ static OPEN_SENDERS: OnceLock>> = OnceLock::new(); ++ static REQ_COUNTER: OnceLock = OnceLock::new(); ++ ++ #[derive(serde::Serialize)] ++ struct OpenOpts { ++ directories: bool, ++ files: bool, ++ multiple: bool, ++ #[serde(skip_serializing_if = "Option::is_none")] ++ prompt: Option, ++ } + +- if let Some(prompt) = options.prompt { +- let _: () = msg_send![panel, setPrompt: ns_string(&prompt)]; +- } ++ let (tx, rx) = oneshot::channel(); ++ let req_id = REQ_COUNTER ++ .get_or_init(|| std::sync::atomic::AtomicU64::new(1)) ++ .fetch_add(1, std::sync::atomic::Ordering::SeqCst); ++ OPEN_SENDERS ++ .get_or_init(|| StdMutex::new(HashMap::new())) ++ .lock() ++ .unwrap() ++ .insert(req_id, tx); ++ ++ let opts = OpenOpts { ++ directories: options.directories, ++ files: options.files, ++ multiple: options.multiple, ++ prompt: options.prompt.as_deref().map(|s| s.to_string()), ++ }; ++ let json = serde_json::to_string(&opts).unwrap_or_else(|_| "{}".into()); ++ if let Ok(cjson) = std::ffi::CString::new(json) { ++ unsafe { zed_open_panel(req_id, cjson.as_ptr()) }; ++ } + +- let _: () = msg_send![panel, beginWithCompletionHandler: block]; +- } +- }) +- .detach(); +- done_rx ++ return rx; ++ } ++ #[cfg(not(target_os = "macos"))] ++ { ++ let (_tx, rx) = oneshot::channel(); ++ rx ++ } + } + + fn prompt_for_new_path( +@@ -754,71 +1023,46 @@ impl Platform for MacPlatform { + directory: &Path, + suggested_name: Option<&str>, + ) -> oneshot::Receiver>> { +- let directory = directory.to_owned(); +- let suggested_name = suggested_name.map(|s| s.to_owned()); +- let (done_tx, done_rx) = oneshot::channel(); +- self.foreground_executor() +- .spawn(async move { +- unsafe { +- let panel = NSSavePanel::savePanel(nil); +- let path = ns_string(directory.to_string_lossy().as_ref()); +- let url = NSURL::fileURLWithPath_isDirectory_(nil, path, true.to_objc()); +- panel.setDirectoryURL(url); +- +- if let Some(suggested_name) = suggested_name { +- let name_string = ns_string(&suggested_name); +- let _: () = msg_send![panel, setNameFieldStringValue: name_string]; +- } +- +- let done_tx = Cell::new(Some(done_tx)); +- let block = ConcreteBlock::new(move |response: NSModalResponse| { +- let mut result = None; +- if response == NSModalResponse::NSModalResponseOk { +- let url = panel.URL(); +- if url.isFileURL() == YES { +- result = ns_url_to_path(panel.URL()).ok().map(|mut result| { +- let Some(filename) = result.file_name() else { +- return result; +- }; +- let chunks = filename +- .as_bytes() +- .split(|&b| b == b'.') +- .collect::>(); +- +- // https://github.com/zed-industries/zed/issues/16969 +- // Workaround a bug in macOS Sequoia that adds an extra file-extension +- // sometimes. e.g. `a.sql` becomes `a.sql.s` or `a.txtx` becomes `a.txtx.txt` +- // +- // This is conditional on OS version because I'd like to get rid of it, so that +- // you can manually create a file called `a.sql.s`. That said it seems better +- // to break that use-case than breaking `a.sql`. +- if chunks.len() == 3 +- && chunks[1].starts_with(chunks[2]) +- && Self::os_version() >= SemanticVersion::new(15, 0, 0) +- { +- let new_filename = OsStr::from_bytes( +- &filename.as_bytes() +- [..chunks[0].len() + 1 + chunks[1].len()], +- ) +- .to_owned(); +- result.set_file_name(&new_filename); +- } +- result +- }) +- } +- } ++ #[cfg(target_os = "macos")] ++ { ++ use std::collections::HashMap; ++ use std::sync::{Mutex as StdMutex, OnceLock}; ++ type SaveTx = oneshot::Sender>>; ++ static SAVE_SENDERS: OnceLock>> = OnceLock::new(); ++ static REQ_COUNTER: OnceLock = OnceLock::new(); ++ #[derive(serde::Serialize)] ++ struct SaveOpts<'a> { ++ directory: &'a str, ++ #[serde(skip_serializing_if = "Option::is_none")] ++ suggested_name: Option<&'a str>, ++ } + +- if let Some(done_tx) = done_tx.take() { +- let _ = done_tx.send(Ok(result)); +- } +- }); +- let block = block.copy(); +- let _: () = msg_send![panel, beginWithCompletionHandler: block]; +- } +- }) +- .detach(); ++ let (tx, rx) = oneshot::channel(); ++ let req_id = REQ_COUNTER ++ .get_or_init(|| std::sync::atomic::AtomicU64::new(1)) ++ .fetch_add(1, std::sync::atomic::Ordering::SeqCst); ++ SAVE_SENDERS ++ .get_or_init(|| StdMutex::new(HashMap::new())) ++ .lock() ++ .unwrap() ++ .insert(req_id, tx); + +- done_rx ++ let dir_str = directory.to_string_lossy().to_string(); ++ let opts = SaveOpts { ++ directory: &dir_str, ++ suggested_name, ++ }; ++ let json = serde_json::to_string(&opts).unwrap_or_else(|_| "{}".into()); ++ if let Ok(cjson) = std::ffi::CString::new(json) { ++ unsafe { zed_save_panel(req_id, cjson.as_ptr()) }; ++ } ++ return rx; ++ } ++ #[cfg(not(target_os = "macos"))] ++ { ++ let (_tx, rx) = oneshot::channel(); ++ rx ++ } + } + + fn can_select_mixed_files_and_dirs(&self) -> bool { +@@ -901,15 +1145,159 @@ impl Platform for MacPlatform { + } + + fn set_menus(&self, menus: Vec, keymap: &Keymap) { +- unsafe { +- let app: id = msg_send![APP_CLASS, sharedApplication]; ++ // Swift-native path: full JSON menu with action tags and shortcuts. ++ #[cfg(target_os = "macos")] ++ { ++ #[derive(serde::Serialize)] ++ #[serde(tag = "kind", rename_all = "lowercase")] ++ enum JsItem<'a> { ++ Action { ++ title: &'a str, ++ tag: u64, ++ #[serde(skip_serializing_if = "Option::is_none")] ++ key_equivalent: Option, ++ #[serde(skip_serializing_if = "Vec::is_empty")] ++ modifiers: Vec<&'static str>, ++ }, ++ Separator, ++ Submenu { ++ title: &'a str, ++ items: Vec>, ++ }, ++ System { ++ title: &'a str, ++ system_type: &'static str, ++ items: Vec>, ++ }, ++ } ++ #[derive(serde::Serialize)] ++ struct JsMenu<'a> { ++ title: &'a str, ++ items: Vec>, ++ } ++ #[derive(serde::Serialize)] ++ struct JsSpec<'a> { ++ menus: Vec>, ++ } ++ + let mut state = self.0.lock(); ++ state.menu_actions.clear(); + let actions = &mut state.menu_actions; +- let menu = self.create_menu_bar(&menus, NSWindow::delegate(app), actions, keymap); +- drop(state); +- app.setMainMenu_(menu); ++ ++ fn action_shortcut( ++ action: &dyn Action, ++ keymap: &Keymap, ++ ) -> (Option, Vec<&'static str>) { ++ use crate::KeyContext; ++ let mut workspace_context = KeyContext::new_with_defaults(); ++ workspace_context.add("Workspace"); ++ let mut pane_context = KeyContext::new_with_defaults(); ++ pane_context.add("Pane"); ++ let mut editor_context = KeyContext::new_with_defaults(); ++ editor_context.add("Editor"); ++ pane_context.extend(&editor_context); ++ workspace_context.extend(&pane_context); ++ let default_contexts = vec![workspace_context]; ++ let keystrokes = keymap ++ .bindings_for_action(action) ++ .find_or_first(|binding| { ++ binding ++ .predicate() ++ .is_none_or(|p| p.eval(&default_contexts)) ++ }) ++ .map(|binding| binding.keystrokes()); ++ if let Some(ks) = keystrokes { ++ if ks.len() == 1 { ++ let k = &ks[0]; ++ let key = key_to_native(k.key()).to_string(); ++ let mut mods = Vec::new(); ++ if k.modifiers().platform { ++ mods.push("command"); ++ } ++ if k.modifiers().control { ++ mods.push("control"); ++ } ++ if k.modifiers().alt { ++ mods.push("option"); ++ } ++ if k.modifiers().shift { ++ mods.push("shift"); ++ } ++ return (Some(key), mods); ++ } ++ } ++ (None, Vec::new()) ++ } ++ ++ fn encode_items<'a>( ++ src: &'a [MenuItem], ++ keymap: &Keymap, ++ actions: &mut Vec>, ++ out: &mut Vec>, ++ ) { ++ for item in src { ++ match item { ++ MenuItem::Separator => out.push(JsItem::Separator), ++ MenuItem::Action { name, action, .. } => { ++ let tag = actions.len() as u64; ++ actions.push(action.boxed_clone()); ++ let (key, mods) = action_shortcut(action.as_ref(), keymap); ++ out.push(JsItem::Action { ++ title: name, ++ tag, ++ key_equivalent: key, ++ modifiers: mods, ++ }); ++ } ++ MenuItem::Submenu(Menu { name, items }) => { ++ let mut sub = Vec::new(); ++ encode_items(items, keymap, actions, &mut sub); ++ out.push(JsItem::Submenu { ++ title: name, ++ items: sub, ++ }); ++ } ++ MenuItem::SystemMenu(OsMenu { name, menu_type }) => { ++ let mut sub = Vec::new(); ++ let system_type = match menu_type { ++ SystemMenuType::Services => "services", ++ }; ++ out.push(JsItem::System { ++ title: name, ++ system_type, ++ items: sub, ++ }); ++ } ++ } ++ } ++ } ++ ++ let mut js_menus = Vec::new(); ++ for m in &menus { ++ let mut items = Vec::new(); ++ encode_items(&m.items, keymap, actions, &mut items); ++ js_menus.push(JsMenu { ++ title: &m.name, ++ items, ++ }); ++ } ++ let spec = JsSpec { menus: js_menus }; ++ let json = serde_json::to_string(&spec).unwrap_or_else(|_| "{\"menus\":[]}".into()); ++ unsafe { zed_register_menu_handler() }; ++ use std::ffi::CString; ++ if let Ok(cjson) = CString::new(json) { ++ unsafe { zed_set_main_menu_json(cjson.as_ptr()) }; ++ } ++ ++ state.menus = Some(menus.into_iter().map(|menu| menu.owned()).collect()); ++ return; ++ } ++ ++ // Non-macOS: keep menus in state only. ++ #[cfg(not(target_os = "macos"))] ++ { ++ self.0.lock().menus = Some(menus.into_iter().map(|menu| menu.owned()).collect()); + } +- self.0.lock().menus = Some(menus.into_iter().map(|menu| menu.owned()).collect()); + } + + fn get_menus(&self) -> Option> { +@@ -921,7 +1309,8 @@ impl Platform for MacPlatform { + let app: id = msg_send![APP_CLASS, sharedApplication]; + let mut state = self.0.lock(); + let actions = &mut state.menu_actions; +- let new = self.create_dock_menu(menu, NSWindow::delegate(app), actions, keymap); ++ let delegate: id = msg_send![app, delegate]; ++ let new = self.create_dock_menu(menu, delegate, actions, keymap); + if let Some(old) = state.dock_menu.replace(new) { + CFRelease(old as _) + } +@@ -1004,12 +1393,9 @@ impl Platform for MacPlatform { + } + + fn should_auto_hide_scrollbars(&self) -> bool { +- #[allow(non_upper_case_globals)] +- const NSScrollerStyleOverlay: NSInteger = 1; +- + unsafe { + let style: NSInteger = msg_send![class!(NSScroller), preferredScrollerStyle]; +- style == NSScrollerStyleOverlay ++ style == (NSScrollerStyleOverlay as NSInteger) + } + } + +@@ -1059,31 +1445,29 @@ impl Platform for MacPlatform { + + // Only set rich text clipboard types if we actually have 1+ images to include. + if any_images { +- let rtfd_data = attributed_string.RTFDFromRange_documentAttributes_( +- NSRange::new(0, msg_send![attributed_string, length]), +- nil, +- ); ++ let len: u64 = msg_send![attributed_string, length]; ++ let rtfd_data = attributed_string ++ .RTFDFromRange_documentAttributes_(NSRange::new(0, len as usize), nil); + if rtfd_data != nil { + state + .pasteboard +- .setData_forType(rtfd_data, NSPasteboardTypeRTFD); ++ .setData_forType(rtfd_data, NSPasteboardTypeRTFD as *const _ as id); + } + +- let rtf_data = attributed_string.RTFFromRange_documentAttributes_( +- NSRange::new(0, attributed_string.length()), +- nil, +- ); ++ let len2: u64 = attributed_string.length(); ++ let rtf_data = attributed_string ++ .RTFFromRange_documentAttributes_(NSRange::new(0, len2 as usize), nil); + if rtf_data != nil { + state + .pasteboard +- .setData_forType(rtf_data, NSPasteboardTypeRTF); ++ .setData_forType(rtf_data, NSPasteboardTypeRTF as *const _ as id); + } + } + + let plain_text = attributed_string.string(); + state + .pasteboard +- .setString_forType(plain_text, NSPasteboardTypeString); ++ .setString_forType(plain_text, NSPasteboardTypeString as *const _ as id); + } + } + } +@@ -1092,7 +1476,7 @@ impl Platform for MacPlatform { + let state = self.0.lock(); + let pasteboard = state.pasteboard; + +- // First, see if it's a string. ++ // Preserve original behavior (metadata-aware) for text; use Swift only for images. + unsafe { + let types: id = pasteboard.types(); + let string_type: id = ns_string("public.utf8-plain-text"); +@@ -1262,6 +1646,13 @@ impl MacPlatform { + + unsafe fn write_plaintext_to_clipboard(&self, string: &ClipboardString) { + unsafe { ++ // Fast path: if there is no metadata, use Swift-native pasteboard write for text. ++ if string.metadata.is_none() { ++ if let Ok(cstr) = std::ffi::CString::new(string.text.as_str()) { ++ zed_pasteboard_write_text(cstr.as_ptr()); ++ return; ++ } ++ } + let state = self.0.lock(); + state.pasteboard.clearContents(); + +@@ -1272,7 +1663,7 @@ impl MacPlatform { + ); + state + .pasteboard +- .setData_forType(text_bytes, NSPasteboardTypeString); ++ .setData_forType(text_bytes, NSPasteboardTypeString as *const _ as id); + + if let Some(metadata) = string.metadata.as_ref() { + let hash_bytes = ClipboardString::text_hash(&string.text).to_be_bytes(); +@@ -1299,15 +1690,27 @@ impl MacPlatform { + + unsafe fn write_image_to_clipboard(&self, image: &Image) { + unsafe { ++ let uti = match image.format { ++ ImageFormat::Png => "public.png", ++ ImageFormat::Jpeg => "public.jpeg", ++ ImageFormat::Tiff => "public.tiff", ++ ImageFormat::Webp => "org.webmproject.webp", ++ ImageFormat::Gif => "com.compuserve.gif", ++ ImageFormat::Bmp => "com.microsoft.bmp", ++ ImageFormat::Svg => "public.svg-image", ++ }; ++ if let Ok(cuti) = std::ffi::CString::new(uti) { ++ zed_pasteboard_write_image(image.bytes.as_ptr(), image.bytes.len(), cuti.as_ptr()); ++ return; ++ } ++ // Fallback to legacy path if UTI conversion failed + let state = self.0.lock(); + state.pasteboard.clearContents(); +- + let bytes = NSData::dataWithBytes_length_( + nil, + image.bytes.as_ptr() as *const c_void, + image.bytes.len() as u64, + ); +- + state + .pasteboard + .setData_forType(bytes, Into::::into(image.format).inner_mut()); +@@ -1319,22 +1722,51 @@ fn try_clipboard_image(pasteboard: id, format: ImageFormat) -> Option "public.png", ++ ImageFormat::Jpeg => "public.jpeg", ++ ImageFormat::Tiff => "public.tiff", ++ ImageFormat::Webp => "org.webmproject.webp", ++ ImageFormat::Gif => "com.compuserve.gif", ++ ImageFormat::Bmp => "com.microsoft.bmp", ++ ImageFormat::Svg => "public.svg-image", ++ }; ++ if let Ok(cuti) = std::ffi::CString::new(uti) { ++ let mut len: usize = 0; ++ let ptr = zed_pasteboard_read_image(cuti.as_ptr(), &mut len as *mut usize); ++ if !ptr.is_null() && len > 0 { ++ let bytes = Vec::from_raw_parts(ptr, len, len); ++ let id_val = hash(&bytes); ++ // We must not free ptr after Vec::from_raw_parts ++ return Some(ClipboardItem { ++ entries: vec![ClipboardEntry::Image(Image { ++ format, ++ bytes, ++ id: id_val, ++ })], ++ }); ++ } ++ } ++ // Fallback to legacy path + let types: id = pasteboard.types(); + if msg_send![types, containsObject: ut_type.inner()] { + let data = pasteboard.dataForType(ut_type.inner_mut()); + if data == nil { +- None +- } else { +- let bytes = Vec::from(slice::from_raw_parts( +- data.bytes() as *mut u8, +- data.length() as usize, +- )); +- let id = hash(&bytes); +- +- Some(ClipboardItem { +- entries: vec![ClipboardEntry::Image(Image { format, bytes, id })], +- }) ++ return None; + } ++ let bytes = Vec::from(slice::from_raw_parts( ++ data.bytes() as *mut u8, ++ data.length() as usize, ++ )); ++ let id_val = hash(&bytes); ++ Some(ClipboardItem { ++ entries: vec![ClipboardEntry::Image(Image { ++ format, ++ bytes, ++ id: id_val, ++ })], ++ }) + } else { + None + } +@@ -1518,6 +1950,82 @@ unsafe fn ns_url_to_path(url: id) -> Result { + }))) + } + ++// Panel callbacks from Swift (C ABI) ++#[cfg(target_os = "macos")] ++#[unsafe(no_mangle)] ++pub extern "C" fn gpui_open_panel_result(request_id: u64, json: *const ::std::os::raw::c_char) { ++ use futures::channel::oneshot; ++ use std::collections::HashMap; ++ use std::ffi::CStr; ++ use std::sync::{Mutex as StdMutex, OnceLock}; ++ type OpenTx = oneshot::Sender>>>; ++ static OPEN_SENDERS: OnceLock>> = OnceLock::new(); ++ let map_lock = OPEN_SENDERS.get_or_init(|| StdMutex::new(HashMap::new())); ++ let sender = map_lock.lock().unwrap().remove(&request_id); ++ if let Some(tx) = sender { ++ let s = unsafe { CStr::from_ptr(json) } ++ .to_string_lossy() ++ .to_string(); ++ #[derive(serde::Deserialize)] ++ struct OpenRes { ++ paths: Option>, ++ } ++ let parsed: Result = serde_json::from_str(&s).map_err(|e| anyhow!(e)); ++ let result = parsed.map(|res| { ++ res.paths ++ .map(|v| v.into_iter().map(PathBuf::from).collect()) ++ }); ++ let _ = tx.send(result); ++ } ++} ++ ++#[cfg(target_os = "macos")] ++#[unsafe(no_mangle)] ++pub extern "C" fn gpui_save_panel_result(request_id: u64, json: *const ::std::os::raw::c_char) { ++ use futures::channel::oneshot; ++ use std::collections::HashMap; ++ use std::ffi::CStr; ++ use std::sync::{Mutex as StdMutex, OnceLock}; ++ type SaveTx = oneshot::Sender>>; ++ static SAVE_SENDERS: OnceLock>> = OnceLock::new(); ++ let map_lock = SAVE_SENDERS.get_or_init(|| StdMutex::new(HashMap::new())); ++ let sender = map_lock.lock().unwrap().remove(&request_id); ++ if let Some(tx) = sender { ++ let s = unsafe { CStr::from_ptr(json) } ++ .to_string_lossy() ++ .to_string(); ++ #[derive(serde::Deserialize)] ++ struct SaveRes { ++ path: Option, ++ } ++ let parsed: Result = serde_json::from_str(&s).map_err(|e| anyhow!(e)); ++ let result = parsed.map(|res| { ++ res.path.map(|p| { ++ let mut result = PathBuf::from(p); ++ // Apply Sequoia filename fix from legacy path for parity ++ if let Some(filename) = result.file_name() { ++ let chunks: Vec<_> = filename.as_bytes().split(|&b| b == b'.').collect(); ++ if chunks.len() == 3 ++ && chunks[1].starts_with(chunks[2]) ++ && MacPlatform::os_version() >= SemanticVersion::new(15, 0, 0) ++ { ++ use std::ffi::OsStr; ++ let new_filename = OsStr::from_bytes( ++ &filename.as_bytes()[..chunks[0].len() + 1 + chunks[1].len()], ++ ) ++ .to_owned(); ++ result.set_file_name(&new_filename); ++ } ++ } ++ result ++ }) ++ }); ++ let _ = tx.send(result); ++ } ++} ++ ++// (Helper conversions for typed objc2 objects will be added when migrating sections.) ++ + #[link(name = "Carbon", kind = "framework")] + unsafe extern "C" { + pub(super) fn TISCopyCurrentKeyboardLayoutInputSource() -> *mut Object; +@@ -1589,7 +2097,7 @@ struct UTType(id); + impl UTType { + pub fn png() -> Self { + // https://developer.apple.com/documentation/uniformtypeidentifiers/uttype-swift.struct/png +- Self(unsafe { NSPasteboardTypePNG }) // This is a rare case where there's a built-in NSPasteboardType ++ Self(unsafe { NSPasteboardTypePNG } as *const _ as id) // Built-in NSPasteboardType + } + + pub fn jpeg() -> Self { +@@ -1619,7 +2127,7 @@ impl UTType { + + pub fn tiff() -> Self { + // https://developer.apple.com/documentation/uniformtypeidentifiers/uttype-swift.struct/tiff +- Self(unsafe { NSPasteboardTypeTIFF }) // This is a rare case where there's a built-in NSPasteboardType ++ Self(unsafe { NSPasteboardTypeTIFF } as *const _ as id) // Built-in NSPasteboardType + } + + fn inner(&self) -> *const Object { +@@ -1665,7 +2173,7 @@ mod tests { + .0 + .lock() + .pasteboard +- .setData_forType(bytes, NSPasteboardTypeString); ++ .setData_forType(bytes, NSPasteboardTypeString as *const _ as id); + } + assert_eq!( + platform.read_from_clipboard(), +diff --git a/crates/gpui/src/platform/mac/status_item.rs b/crates/gpui/src/platform/mac/status_item.rs +index 21cc86090c..652aec192b 100644 +--- a/crates/gpui/src/platform/mac/status_item.rs ++++ b/crates/gpui/src/platform/mac/status_item.rs +@@ -1,388 +1,171 @@ +-use crate::{ +- geometry::{ +- rect::RectF, +- vector::{vec2f, Vector2F}, +- }, +- platform::{ +- self, +- mac::{platform::NSViewLayerContentsRedrawDuringViewResize, renderer::Renderer}, +- Event, FontSystem, WindowBounds, +- }, +- Scene, +-}; +-use cocoa::{ +- appkit::{NSScreen, NSSquareStatusItemLength, NSStatusBar, NSStatusItem, NSView, NSWindow}, +- base::{id, nil, YES}, +- foundation::{NSPoint, NSRect, NSSize}, +-}; +-use ctor::ctor; +-use foreign_types::ForeignTypeRef; +-use objc::{ +- class, +- declare::ClassDecl, +- msg_send, +- rc::StrongPtr, +- runtime::{Class, Object, Protocol, Sel}, +- sel, sel_impl, +-}; +-use std::{ +- cell::RefCell, +- ffi::c_void, +- ptr, +- rc::{Rc, Weak}, +- sync::Arc, +-}; +- +-use super::screen::Screen; +- +-static mut VIEW_CLASS: *const Class = ptr::null(); +-const STATE_IVAR: &str = "state"; +- +-#[ctor] +-unsafe fn build_classes() { +- VIEW_CLASS = { +- let mut decl = ClassDecl::new("GPUIStatusItemView", class!(NSView)).unwrap(); +- decl.add_ivar::<*mut c_void>(STATE_IVAR); +- +- decl.add_method(sel!(dealloc), dealloc_view as extern "C" fn(&Object, Sel)); +- +- decl.add_method( +- sel!(mouseDown:), +- handle_view_event as extern "C" fn(&Object, Sel, id), +- ); +- decl.add_method( +- sel!(mouseUp:), +- handle_view_event as extern "C" fn(&Object, Sel, id), +- ); +- decl.add_method( +- sel!(rightMouseDown:), +- handle_view_event as extern "C" fn(&Object, Sel, id), +- ); +- decl.add_method( +- sel!(rightMouseUp:), +- handle_view_event as extern "C" fn(&Object, Sel, id), +- ); +- decl.add_method( +- sel!(otherMouseDown:), +- handle_view_event as extern "C" fn(&Object, Sel, id), +- ); +- decl.add_method( +- sel!(otherMouseUp:), +- handle_view_event as extern "C" fn(&Object, Sel, id), +- ); +- decl.add_method( +- sel!(mouseMoved:), +- handle_view_event as extern "C" fn(&Object, Sel, id), +- ); +- decl.add_method( +- sel!(mouseDragged:), +- handle_view_event as extern "C" fn(&Object, Sel, id), +- ); +- decl.add_method( +- sel!(scrollWheel:), +- handle_view_event as extern "C" fn(&Object, Sel, id), +- ); +- decl.add_method( +- sel!(flagsChanged:), +- handle_view_event as extern "C" fn(&Object, Sel, id), +- ); +- decl.add_method( +- sel!(makeBackingLayer), +- make_backing_layer as extern "C" fn(&Object, Sel) -> id, +- ); +- decl.add_method( +- sel!(viewDidChangeEffectiveAppearance), +- view_did_change_effective_appearance as extern "C" fn(&Object, Sel), +- ); +- +- decl.add_protocol(Protocol::get("CALayerDelegate").unwrap()); +- decl.add_method( +- sel!(displayLayer:), +- display_layer as extern "C" fn(&Object, Sel, id), +- ); +- +- decl.register() +- }; ++use std::sync::Arc; ++ ++use crate::platform::FontSystem; ++ ++extern "C" { ++ fn zed_status_item_create() -> u64; ++ fn zed_status_item_set_title(id: u64, title: *const ::std::os::raw::c_char); ++ fn zed_status_item_remove(id: u64); ++ fn zed_status_item_set_image( ++ id: u64, ++ bytes: *const u8, ++ len: usize, ++ uti: *const ::std::os::raw::c_char, ++ is_template: bool, ++ ); ++ fn zed_status_item_set_menu(id: u64, json: *const ::std::os::raw::c_char); + } + +-pub struct StatusItem(Rc>); +- +-struct StatusItemState { +- native_item: StrongPtr, +- native_view: StrongPtr, +- renderer: Renderer, +- scene: Option, +- event_callback: Option bool>>, +- appearance_changed_callback: Option>, ++pub struct StatusItem { ++ id: u64, + } + + impl StatusItem { +- pub fn add(fonts: Arc) -> Self { +- unsafe { +- let renderer = Renderer::new(false, fonts); +- let status_bar = NSStatusBar::systemStatusBar(nil); +- let native_item = +- StrongPtr::retain(status_bar.statusItemWithLength_(NSSquareStatusItemLength)); +- +- let button = native_item.button(); +- let _: () = msg_send![button, setHidden: YES]; +- +- let native_view = msg_send![VIEW_CLASS, alloc]; +- let state = Rc::new(RefCell::new(StatusItemState { +- native_item, +- native_view: StrongPtr::new(native_view), +- renderer, +- scene: None, +- event_callback: None, +- appearance_changed_callback: None, +- })); +- +- let parent_view = button.superview().superview(); +- NSView::initWithFrame_( +- native_view, +- NSRect::new(NSPoint::new(0., 0.), NSView::frame(parent_view).size), +- ); +- (*native_view).set_ivar( +- STATE_IVAR, +- Weak::into_raw(Rc::downgrade(&state)) as *const c_void, +- ); +- native_view.setWantsBestResolutionOpenGLSurface_(YES); +- native_view.setWantsLayer(YES); +- let _: () = msg_send![ +- native_view, +- setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize +- ]; +- +- parent_view.addSubview_(native_view); +- +- { +- let state = state.borrow(); +- let layer = state.renderer.layer(); +- let scale_factor = state.scale_factor(); +- let size = state.content_size() * scale_factor; +- layer.set_contents_scale(scale_factor.into()); +- layer.set_drawable_size(metal::CGSize::new(size.x().into(), size.y().into())); +- } +- +- Self(state) ++ pub fn add(_fonts: Arc) -> Self { ++ let id = unsafe { zed_status_item_create() }; ++ // Give it a default title for now; callers can change it ++ if let Ok(c) = std::ffi::CString::new("Zed") { ++ unsafe { zed_status_item_set_title(id, c.as_ptr()) }; + } +- } +-} +- +-impl platform::Window for StatusItem { +- fn bounds(&self) -> WindowBounds { +- self.0.borrow().bounds() +- } +- +- fn content_size(&self) -> Vector2F { +- self.0.borrow().content_size() ++ Self { id } + } + +- fn scale_factor(&self) -> f32 { +- self.0.borrow().scale_factor() +- } +- +- fn appearance(&self) -> platform::Appearance { +- unsafe { +- let appearance: id = +- msg_send![self.0.borrow().native_item.button(), effectiveAppearance]; +- platform::Appearance::from_native(appearance) +- } +- } +- +- fn screen(&self) -> Rc { +- unsafe { +- Rc::new(Screen { +- native_screen: self.0.borrow().native_window().screen(), +- }) ++ pub fn set_title(&self, title: &str) { ++ if let Ok(c) = std::ffi::CString::new(title) { ++ unsafe { zed_status_item_set_title(self.id, c.as_ptr()) }; + } + } + +- fn mouse_position(&self) -> Vector2F { +- unimplemented!() +- } +- +- fn as_any_mut(&mut self) -> &mut dyn std::any::Any { +- self +- } +- +- fn set_input_handler(&mut self, _: Box) {} +- +- fn prompt( +- &self, +- _: crate::platform::PromptLevel, +- _: &str, +- _: &[&str], +- ) -> postage::oneshot::Receiver { +- unimplemented!() +- } +- +- fn activate(&self) { +- unimplemented!() +- } +- +- fn set_title(&mut self, _: &str) { +- unimplemented!() +- } +- +- fn set_edited(&mut self, _: bool) { +- unimplemented!() +- } +- +- fn show_character_palette(&self) { +- unimplemented!() +- } +- +- fn minimize(&self) { +- unimplemented!() +- } +- +- fn zoom(&self) { +- unimplemented!() +- } +- +- fn present_scene(&mut self, scene: Scene) { +- self.0.borrow_mut().scene = Some(scene); +- unsafe { +- let _: () = msg_send![*self.0.borrow().native_view, setNeedsDisplay: YES]; ++ pub fn set_click_handler(&self, handler: Box) { ++ register_status_item_handler(self.id, handler); ++ } ++ ++ pub fn set_image(&self, format: crate::ImageFormat, bytes: &[u8], template: bool) { ++ let uti = match format { ++ crate::ImageFormat::Png => "public.png", ++ crate::ImageFormat::Jpeg => "public.jpeg", ++ crate::ImageFormat::Tiff => "public.tiff", ++ crate::ImageFormat::Webp => "org.webmproject.webp", ++ crate::ImageFormat::Gif => "com.compuserve.gif", ++ crate::ImageFormat::Bmp => "com.microsoft.bmp", ++ crate::ImageFormat::Svg => "public.svg-image", ++ }; ++ if let Ok(cuti) = std::ffi::CString::new(uti) { ++ unsafe { ++ zed_status_item_set_image( ++ self.id, ++ bytes.as_ptr(), ++ bytes.len(), ++ cuti.as_ptr(), ++ template, ++ ) ++ }; + } + } ++} + +- fn toggle_fullscreen(&self) { +- unimplemented!() +- } +- +- fn on_event(&mut self, callback: Box bool>) { +- self.0.borrow_mut().event_callback = Some(callback); ++impl Drop for StatusItem { ++ fn drop(&mut self) { ++ unregister_status_item_handler(self.id); ++ unsafe { zed_status_item_remove(self.id) }; + } ++} + +- fn on_active_status_change(&mut self, _: Box) {} +- +- fn on_resize(&mut self, _: Box) {} +- +- fn on_fullscreen(&mut self, _: Box) {} +- +- fn on_moved(&mut self, _: Box) {} +- +- fn on_should_close(&mut self, _: Box bool>) {} +- +- fn on_close(&mut self, _: Box) {} ++// Click handler registry ++use std::collections::HashMap; ++use std::sync::{Mutex, OnceLock}; + +- fn on_appearance_changed(&mut self, callback: Box) { +- self.0.borrow_mut().appearance_changed_callback = Some(callback); +- } ++static STATUS_ITEM_HANDLERS: OnceLock>>> = OnceLock::new(); + +- fn is_topmost_for_position(&self, _: Vector2F) -> bool { +- true +- } ++fn register_status_item_handler(id: u64, handler: Box) { ++ STATUS_ITEM_HANDLERS ++ .get_or_init(|| Mutex::new(HashMap::new())) ++ .lock() ++ .unwrap() ++ .insert(id, handler); + } + +-impl StatusItemState { +- fn bounds(&self) -> WindowBounds { +- unsafe { +- let window: id = self.native_window(); +- let screen_frame = window.screen().visibleFrame(); +- let window_frame = NSWindow::frame(window); +- let origin = vec2f( +- window_frame.origin.x as f32, +- (window_frame.origin.y - screen_frame.size.height - window_frame.size.height) +- as f32, +- ); +- let size = vec2f( +- window_frame.size.width as f32, +- window_frame.size.height as f32, +- ); +- WindowBounds::Fixed(RectF::new(origin, size)) +- } +- } +- +- fn content_size(&self) -> Vector2F { +- unsafe { +- let NSSize { width, height, .. } = +- NSView::frame(self.native_item.button().superview().superview()).size; +- vec2f(width as f32, height as f32) +- } +- } +- +- fn scale_factor(&self) -> f32 { +- unsafe { +- let window: id = msg_send![self.native_item.button(), window]; +- NSScreen::backingScaleFactor(window.screen()) as f32 +- } +- } ++fn unregister_status_item_handler(id: u64) { ++ STATUS_ITEM_HANDLERS ++ .get_or_init(|| Mutex::new(HashMap::new())) ++ .lock() ++ .unwrap() ++ .remove(&id); ++} + +- pub fn native_window(&self) -> id { +- unsafe { msg_send![self.native_item.button(), window] } ++#[no_mangle] ++pub extern "C" fn gpui_status_item_clicked(id: u64) { ++ if let Some(mut handler) = STATUS_ITEM_HANDLERS ++ .get_or_init(|| Mutex::new(HashMap::new())) ++ .lock() ++ .unwrap() ++ .get_mut(&id) ++ { ++ handler(); + } + } + +-extern "C" fn dealloc_view(this: &Object, _: Sel) { +- unsafe { +- drop_state(this); ++// Status item menu support ++use crate::menu::{Menu as AppMenu, MenuItem as AppMenuItem}; + +- let _: () = msg_send![super(this, class!(NSView)), dealloc]; +- } +-} ++static STATUS_ITEM_MENU_ACTIONS: OnceLock>>>> = OnceLock::new(); + +-extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { +- unsafe { +- if let Some(state) = get_state(this).upgrade() { +- let mut state_borrow = state.as_ref().borrow_mut(); +- if let Some(event) = +- Event::from_native(native_event, Some(state_borrow.content_size().y())) +- { +- if let Some(mut callback) = state_borrow.event_callback.take() { +- drop(state_borrow); +- callback(event); +- state.borrow_mut().event_callback = Some(callback); ++impl StatusItem { ++ pub fn set_menu(&self, menu: &AppMenu) { ++ // Build JSON and tag -> action map per status item id ++ #[derive(serde::Serialize)] ++ #[serde(tag = "kind", rename_all = "lowercase")] ++ enum JsItem<'a> { Action { title: &'a str, tag: u64 }, Separator, Submenu { title: &'a str, items: Vec> } } ++ #[derive(serde::Serialize)] ++ struct JsSpec<'a> { items: Vec> } ++ ++ let mut actions = Vec::>::new(); ++ fn encode_items<'a>(src: &'a [AppMenuItem], actions: &mut Vec>, out: &mut Vec>) { ++ for item in src { ++ match item { ++ AppMenuItem::Separator => out.push(JsItem::Separator), ++ AppMenuItem::Action { name, action, .. } => { ++ let tag = actions.len() as u64; ++ actions.push(action.boxed_clone()); ++ out.push(JsItem::Action { title: name, tag }); ++ } ++ AppMenuItem::Submenu(AppMenu { name, items }) => { ++ let mut sub = Vec::new(); ++ encode_items(items, actions, &mut sub); ++ out.push(JsItem::Submenu { title: name, items: sub }); ++ } ++ AppMenuItem::SystemMenu(_) => { ++ // Not supported in status item menu context currently ++ } + } + } + } +- } +-} + +-extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { +- if let Some(state) = unsafe { get_state(this).upgrade() } { +- let state = state.borrow(); +- state.renderer.layer().as_ptr() as id +- } else { +- nil +- } +-} +- +-extern "C" fn display_layer(this: &Object, _: Sel, _: id) { +- unsafe { +- if let Some(state) = get_state(this).upgrade() { +- let mut state = state.borrow_mut(); +- if let Some(scene) = state.scene.take() { +- state.renderer.render(&scene); +- } ++ let mut js_items = Vec::new(); ++ encode_items(&menu.items, &mut actions, &mut js_items); ++ let spec = JsSpec { items: js_items }; ++ let json = serde_json::to_string(&spec).unwrap_or_else(|_| "{\"items\":[]}".into()); ++ STATUS_ITEM_MENU_ACTIONS ++ .get_or_init(|| Mutex::new(HashMap::new())) ++ .lock() ++ .unwrap() ++ .insert(self.id, actions); ++ if let Ok(cjson) = std::ffi::CString::new(json) { ++ unsafe { zed_status_item_set_menu(self.id, cjson.as_ptr()) }; + } + } + } + +-extern "C" fn view_did_change_effective_appearance(this: &Object, _: Sel) { +- unsafe { +- if let Some(state) = get_state(this).upgrade() { +- let mut state_borrow = state.as_ref().borrow_mut(); +- if let Some(mut callback) = state_borrow.appearance_changed_callback.take() { +- drop(state_borrow); +- callback(); +- state.borrow_mut().appearance_changed_callback = Some(callback); +- } ++#[no_mangle] ++pub extern "C" fn gpui_status_item_menu_action(id: u64, tag: u64) { ++ if let Some(vec) = STATUS_ITEM_MENU_ACTIONS ++ .get_or_init(|| Mutex::new(HashMap::new())) ++ .lock() ++ .unwrap() ++ .get_mut(&id) ++ { ++ if let Some(action) = vec.get(tag as usize) { ++ super::platform::dispatch_menu_action(action.as_ref()); + } + } + } +- +-unsafe fn get_state(object: &Object) -> Weak> { +- let raw: *mut c_void = *object.get_ivar(STATE_IVAR); +- let weak1 = Weak::from_raw(raw as *mut RefCell); +- let weak2 = weak1.clone(); +- let _ = Weak::into_raw(weak1); +- weak2 +-} +- +-unsafe fn drop_state(object: &Object) { +- let raw: *const c_void = *object.get_ivar(STATE_IVAR); +- Weak::from_raw(raw as *const RefCell); +-} +diff --git a/crates/gpui/src/platform/mac/text_system.rs b/crates/gpui/src/platform/mac/text_system.rs +index 72a0f2e565..e0487406f4 100644 +--- a/crates/gpui/src/platform/mac/text_system.rs ++++ b/crates/gpui/src/platform/mac/text_system.rs +@@ -660,11 +660,10 @@ mod lenient_font_attributes { + } + + unsafe fn wrap_under_get_rule(reference: CFStringRef) -> CFString { +- unsafe { +- assert!(!reference.is_null(), "Attempted to create a NULL object."); +- let reference = CFRetain(reference as *const ::std::os::raw::c_void) as CFStringRef; +- TCFType::wrap_under_create_rule(reference) +- } ++ assert!(!reference.is_null(), "Attempted to create a NULL object."); ++ let reference = ++ unsafe { CFRetain(reference as *const ::std::os::raw::c_void) as CFStringRef }; ++ unsafe { TCFType::wrap_under_create_rule(reference) } + } + } + +diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs +index 1230a70406..da28ede04d 100644 +--- a/crates/gpui/src/platform/mac/window.rs ++++ b/crates/gpui/src/platform/mac/window.rs +@@ -9,26 +9,74 @@ use crate::{ + dispatch_sys::dispatch_async_f, platform::PlatformInputHandler, point, px, size, + }; + use block::ConcreteBlock; +-use cocoa::{ +- appkit::{ +- NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered, +- NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, +- NSView, NSViewHeightSizable, NSViewWidthSizable, NSVisualEffectMaterial, +- NSVisualEffectState, NSVisualEffectView, NSWindow, NSWindowButton, +- NSWindowCollectionBehavior, NSWindowOcclusionState, NSWindowOrderingMode, +- NSWindowStyleMask, NSWindowTitleVisibility, +- }, +- base::{id, nil}, +- foundation::{ +- NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, +- NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, +- NSUserDefaults, +- }, +-}; ++// Remove Cocoa trait usage; rely on Objective-C runtime + typed constants later + ++// No Cocoa enums/flags needed here after migration ++use cocoa::foundation::{ ++ NSAutoreleasePool, NSNotFound, NSPoint, NSRect, NSSize, NSString, NSUserDefaults, ++}; + use core_graphics::display::{CGDirectDisplayID, CGPoint, CGRect}; + use ctor::ctor; + use futures::channel::oneshot; ++use icrate::AppKit::{ ++ // Alert styles ++ NSAlertStyleCritical, ++ NSAlertStyleInformational, ++ NSAlertStyleWarning, ++ NSAppKitVersionNumber, ++ NSAppKitVersionNumber12_0, ++ NSBackingStoreBuffered, ++ // Drag operation flags ++ NSDragOperation, ++ NSDragOperationCopy, ++ NSDragOperationNone, ++ // Event modifier flags ++ NSEventModifierFlagCapsLock, ++ NSEventModifierFlagCommand, ++ NSEventModifierFlagControl, ++ NSEventModifierFlagFunction, ++ NSEventModifierFlagOption, ++ NSEventModifierFlagShift, ++ // Pasteboard types ++ NSFilenamesPboardType, ++ NSTrackingActiveAlways, ++ NSTrackingInVisibleRect, ++ // Tracking area flags ++ NSTrackingMouseEnteredAndExited, ++ NSTrackingMouseMoved, ++ NSViewHeightSizable, ++ // View layer redraw policy ++ NSViewLayerContentsRedrawDuringViewResize, ++ // Autoresizing mask options ++ NSViewWidthSizable, ++ // Visual effect ++ NSVisualEffectStateActive, ++ // Ordering ++ NSWindowAbove, ++ // Animation behavior ++ NSWindowAnimationBehaviorUtilityWindow, ++ NSWindowBelow, ++ // Window button enum values ++ NSWindowCloseButton, ++ // Collection behavior ++ NSWindowCollectionBehaviorCanJoinAllSpaces, ++ NSWindowCollectionBehaviorFullScreenAuxiliary, ++ NSWindowMiniaturizeButton, ++ // Style masks ++ NSWindowStyleMask, ++ NSWindowStyleMaskClosable, ++ NSWindowStyleMaskFullScreen, ++ NSWindowStyleMaskFullSizeContentView, ++ NSWindowStyleMaskMiniaturizable, ++ NSWindowStyleMaskNonactivatingPanel, ++ NSWindowStyleMaskResizable, ++ NSWindowStyleMaskTitled, ++ // Title visibility ++ NSWindowTitleHidden, ++ NSWindowZoomButton, ++}; ++use icrate::Foundation::NSOperatingSystemVersion; ++use icrate::Foundation::{NSInteger, NSUInteger}; + use objc::{ + class, + declare::ClassDecl, +@@ -36,6 +84,8 @@ use objc::{ + runtime::{BOOL, Class, NO, Object, Protocol, Sel, YES}, + sel, sel_impl, + }; ++type ObjcId = *mut Object; ++const NIL: ObjcId = std::ptr::null_mut(); + use parking_lot::Mutex; + use raw_window_handle as rwh; + use smallvec::SmallVec; +@@ -59,31 +109,18 @@ static mut PANEL_CLASS: *const Class = ptr::null(); + static mut VIEW_CLASS: *const Class = ptr::null(); + static mut BLURRED_VIEW_CLASS: *const Class = ptr::null(); + ++use icrate::AppKit::NSWindowLevel; + #[allow(non_upper_case_globals)] +-const NSWindowStyleMaskNonactivatingPanel: NSWindowStyleMask = +- NSWindowStyleMask::from_bits_retain(1 << 7); +-#[allow(non_upper_case_globals)] +-const NSNormalWindowLevel: NSInteger = 0; +-#[allow(non_upper_case_globals)] +-const NSPopUpWindowLevel: NSInteger = 101; +-#[allow(non_upper_case_globals)] +-const NSTrackingMouseEnteredAndExited: NSUInteger = 0x01; +-#[allow(non_upper_case_globals)] +-const NSTrackingMouseMoved: NSUInteger = 0x02; +-#[allow(non_upper_case_globals)] +-const NSTrackingActiveAlways: NSUInteger = 0x80; ++const WINDOW_LEVEL_NORMAL: NSWindowLevel = 0; + #[allow(non_upper_case_globals)] +-const NSTrackingInVisibleRect: NSUInteger = 0x200; +-#[allow(non_upper_case_globals)] +-const NSWindowAnimationBehaviorUtilityWindow: NSInteger = 4; +-#[allow(non_upper_case_globals)] +-const NSViewLayerContentsRedrawDuringViewResize: NSInteger = 2; +-// https://developer.apple.com/documentation/appkit/nsdragoperation +-type NSDragOperation = NSUInteger; +-#[allow(non_upper_case_globals)] +-const NSDragOperationNone: NSDragOperation = 0; +-#[allow(non_upper_case_globals)] +-const NSDragOperationCopy: NSDragOperation = 1; ++const WINDOW_LEVEL_POPUP: NSWindowLevel = 101; ++// Event modifier masks ++const MOD_CAPS_LOCK: u64 = NSEventModifierFlagCapsLock as u64; ++const MOD_SHIFT: u64 = NSEventModifierFlagShift as u64; ++const MOD_CONTROL: u64 = NSEventModifierFlagControl as u64; ++const MOD_OPTION: u64 = NSEventModifierFlagOption as u64; ++const MOD_COMMAND: u64 = NSEventModifierFlagCommand as u64; ++const MOD_FUNCTION: u64 = NSEventModifierFlagFunction as u64; + #[derive(PartialEq)] + pub enum UserTabbingPreference { + Never, +@@ -94,9 +131,9 @@ pub enum UserTabbingPreference { + #[link(name = "CoreGraphics", kind = "framework")] + unsafe extern "C" { + // Widely used private APIs; Apple uses them for their Terminal.app. +- fn CGSMainConnectionID() -> id; ++ fn CGSMainConnectionID() -> ObjcId; + fn CGSSetWindowBackgroundBlurRadius( +- connection_id: id, ++ connection_id: ObjcId, + window_id: NSInteger, + radius: i64, + ) -> i32; +@@ -115,68 +152,68 @@ unsafe fn build_classes() { + + decl.add_method( + sel!(performKeyEquivalent:), +- handle_key_equivalent as extern "C" fn(&Object, Sel, id) -> BOOL, ++ handle_key_equivalent as extern "C" fn(&Object, Sel, ObjcId) -> BOOL, + ); + decl.add_method( + sel!(keyDown:), +- handle_key_down as extern "C" fn(&Object, Sel, id), ++ handle_key_down as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(keyUp:), +- handle_key_up as extern "C" fn(&Object, Sel, id), ++ handle_key_up as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(mouseDown:), +- handle_view_event as extern "C" fn(&Object, Sel, id), ++ handle_view_event as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(mouseUp:), +- handle_view_event as extern "C" fn(&Object, Sel, id), ++ handle_view_event as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(rightMouseDown:), +- handle_view_event as extern "C" fn(&Object, Sel, id), ++ handle_view_event as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(rightMouseUp:), +- handle_view_event as extern "C" fn(&Object, Sel, id), ++ handle_view_event as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(otherMouseDown:), +- handle_view_event as extern "C" fn(&Object, Sel, id), ++ handle_view_event as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(otherMouseUp:), +- handle_view_event as extern "C" fn(&Object, Sel, id), ++ handle_view_event as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(mouseMoved:), +- handle_view_event as extern "C" fn(&Object, Sel, id), ++ handle_view_event as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(mouseExited:), +- handle_view_event as extern "C" fn(&Object, Sel, id), ++ handle_view_event as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(mouseDragged:), +- handle_view_event as extern "C" fn(&Object, Sel, id), ++ handle_view_event as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(scrollWheel:), +- handle_view_event as extern "C" fn(&Object, Sel, id), ++ handle_view_event as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(swipeWithEvent:), +- handle_view_event as extern "C" fn(&Object, Sel, id), ++ handle_view_event as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(flagsChanged:), +- handle_view_event as extern "C" fn(&Object, Sel, id), ++ handle_view_event as extern "C" fn(&Object, Sel, ObjcId), + ); + + decl.add_method( + sel!(makeBackingLayer), +- make_backing_layer as extern "C" fn(&Object, Sel) -> id, ++ make_backing_layer as extern "C" fn(&Object, Sel) -> ObjcId, + ); + + decl.add_protocol(Protocol::get("CALayerDelegate").unwrap()); +@@ -190,13 +227,13 @@ unsafe fn build_classes() { + ); + decl.add_method( + sel!(displayLayer:), +- display_layer as extern "C" fn(&Object, Sel, id), ++ display_layer as extern "C" fn(&Object, Sel, ObjcId), + ); + + decl.add_protocol(Protocol::get("NSTextInputClient").unwrap()); + decl.add_method( + sel!(validAttributesForMarkedText), +- valid_attributes_for_marked_text as extern "C" fn(&Object, Sel) -> id, ++ valid_attributes_for_marked_text as extern "C" fn(&Object, Sel) -> ObjcId, + ); + decl.add_method( + sel!(hasMarkedText), +@@ -213,21 +250,21 @@ unsafe fn build_classes() { + decl.add_method( + sel!(firstRectForCharacterRange:actualRange:), + first_rect_for_character_range +- as extern "C" fn(&Object, Sel, NSRange, id) -> NSRect, ++ as extern "C" fn(&Object, Sel, NSRange, ObjcId) -> NSRect, + ); + decl.add_method( + sel!(insertText:replacementRange:), +- insert_text as extern "C" fn(&Object, Sel, id, NSRange), ++ insert_text as extern "C" fn(&Object, Sel, ObjcId, NSRange), + ); + decl.add_method( + sel!(setMarkedText:selectedRange:replacementRange:), +- set_marked_text as extern "C" fn(&Object, Sel, id, NSRange, NSRange), ++ set_marked_text as extern "C" fn(&Object, Sel, ObjcId, NSRange, NSRange), + ); + decl.add_method(sel!(unmarkText), unmark_text as extern "C" fn(&Object, Sel)); + decl.add_method( + sel!(attributedSubstringForProposedRange:actualRange:), + attributed_substring_for_proposed_range +- as extern "C" fn(&Object, Sel, NSRange, *mut c_void) -> id, ++ as extern "C" fn(&Object, Sel, NSRange, *mut c_void) -> ObjcId, + ); + decl.add_method( + sel!(viewDidChangeEffectiveAppearance), +@@ -242,7 +279,7 @@ unsafe fn build_classes() { + + decl.add_method( + sel!(acceptsFirstMouse:), +- accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL, ++ accepts_first_mouse as extern "C" fn(&Object, Sel, ObjcId) -> BOOL, + ); + + decl.add_method( +@@ -257,7 +294,7 @@ unsafe fn build_classes() { + unsafe { + decl.add_method( + sel!(initWithFrame:), +- blurred_view_init_with_frame as extern "C" fn(&Object, Sel, NSRect) -> id, ++ blurred_view_init_with_frame as extern "C" fn(&Object, Sel, NSRect) -> ObjcId, + ); + decl.add_method( + sel!(updateLayer), +@@ -293,92 +330,92 @@ unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const C + ); + decl.add_method( + sel!(windowDidResize:), +- window_did_resize as extern "C" fn(&Object, Sel, id), ++ window_did_resize as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(windowDidChangeOcclusionState:), +- window_did_change_occlusion_state as extern "C" fn(&Object, Sel, id), ++ window_did_change_occlusion_state as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(windowWillEnterFullScreen:), +- window_will_enter_fullscreen as extern "C" fn(&Object, Sel, id), ++ window_will_enter_fullscreen as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(windowWillExitFullScreen:), +- window_will_exit_fullscreen as extern "C" fn(&Object, Sel, id), ++ window_will_exit_fullscreen as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(windowDidMove:), +- window_did_move as extern "C" fn(&Object, Sel, id), ++ window_did_move as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(windowDidChangeScreen:), +- window_did_change_screen as extern "C" fn(&Object, Sel, id), ++ window_did_change_screen as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(windowDidBecomeKey:), +- window_did_change_key_status as extern "C" fn(&Object, Sel, id), ++ window_did_change_key_status as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(windowDidResignKey:), +- window_did_change_key_status as extern "C" fn(&Object, Sel, id), ++ window_did_change_key_status as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(windowShouldClose:), +- window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL, ++ window_should_close as extern "C" fn(&Object, Sel, ObjcId) -> BOOL, + ); + + decl.add_method(sel!(close), close_window as extern "C" fn(&Object, Sel)); + + decl.add_method( + sel!(draggingEntered:), +- dragging_entered as extern "C" fn(&Object, Sel, id) -> NSDragOperation, ++ dragging_entered as extern "C" fn(&Object, Sel, ObjcId) -> NSDragOperation, + ); + decl.add_method( + sel!(draggingUpdated:), +- dragging_updated as extern "C" fn(&Object, Sel, id) -> NSDragOperation, ++ dragging_updated as extern "C" fn(&Object, Sel, ObjcId) -> NSDragOperation, + ); + decl.add_method( + sel!(draggingExited:), +- dragging_exited as extern "C" fn(&Object, Sel, id), ++ dragging_exited as extern "C" fn(&Object, Sel, ObjcId), + ); + decl.add_method( + sel!(performDragOperation:), +- perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL, ++ perform_drag_operation as extern "C" fn(&Object, Sel, ObjcId) -> BOOL, + ); + decl.add_method( + sel!(concludeDragOperation:), +- conclude_drag_operation as extern "C" fn(&Object, Sel, id), ++ conclude_drag_operation as extern "C" fn(&Object, Sel, ObjcId), + ); + + decl.add_method( + sel!(addTitlebarAccessoryViewController:), +- add_titlebar_accessory_view_controller as extern "C" fn(&Object, Sel, id), ++ add_titlebar_accessory_view_controller as extern "C" fn(&Object, Sel, ObjcId), + ); + + decl.add_method( + sel!(moveTabToNewWindow:), +- move_tab_to_new_window as extern "C" fn(&Object, Sel, id), ++ move_tab_to_new_window as extern "C" fn(&Object, Sel, ObjcId), + ); + + decl.add_method( + sel!(mergeAllWindows:), +- merge_all_windows as extern "C" fn(&Object, Sel, id), ++ merge_all_windows as extern "C" fn(&Object, Sel, ObjcId), + ); + + decl.add_method( + sel!(selectNextTab:), +- select_next_tab as extern "C" fn(&Object, Sel, id), ++ select_next_tab as extern "C" fn(&Object, Sel, ObjcId), + ); + + decl.add_method( + sel!(selectPreviousTab:), +- select_previous_tab as extern "C" fn(&Object, Sel, id), ++ select_previous_tab as extern "C" fn(&Object, Sel, ObjcId), + ); + + decl.add_method( + sel!(toggleTabBar:), +- toggle_tab_bar as extern "C" fn(&Object, Sel, id), ++ toggle_tab_bar as extern "C" fn(&Object, Sel, ObjcId), + ); + + decl.register() +@@ -388,9 +425,9 @@ unsafe fn build_window_class(name: &'static str, superclass: &Class) -> *const C + struct MacWindowState { + handle: AnyWindowHandle, + executor: ForegroundExecutor, +- native_window: id, ++ native_window: ObjcId, + native_view: NonNull, +- blurred_view: Option, ++ blurred_view: Option, + display_link: Option, + renderer: renderer::Renderer, + request_frame_callback: Option>, +@@ -432,17 +469,17 @@ impl MacWindowState { + let titlebar_height = self.titlebar_height(); + + unsafe { +- let close_button: id = msg_send![ ++ let close_button: ObjcId = msg_send![ + self.native_window, +- standardWindowButton: NSWindowButton::NSWindowCloseButton ++ standardWindowButton: NSWindowCloseButton + ]; +- let min_button: id = msg_send![ ++ let min_button: ObjcId = msg_send![ + self.native_window, +- standardWindowButton: NSWindowButton::NSWindowMiniaturizeButton ++ standardWindowButton: NSWindowMiniaturizeButton + ]; +- let zoom_button: id = msg_send![ ++ let zoom_button: ObjcId = msg_send![ + self.native_window, +- standardWindowButton: NSWindowButton::NSWindowZoomButton ++ standardWindowButton: NSWindowZoomButton + ]; + + let mut close_button_frame: CGRect = msg_send![close_button, frame]; +@@ -475,15 +512,15 @@ impl MacWindowState { + fn start_display_link(&mut self) { + self.stop_display_link(); + unsafe { +- if !self +- .native_window +- .occlusionState() +- .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) +- { ++ let is_visible: BOOL = msg_send![self.native_window, isVisible]; ++ if is_visible != YES { + return; + } + } +- let display_id = unsafe { display_id_for_screen(self.native_window.screen()) }; ++ let display_id = unsafe { ++ let screen: ObjcId = msg_send![self.native_window, screen]; ++ display_id_for_screen(screen) ++ }; + if let Some(mut display_link) = + DisplayLink::new(display_id, self.native_view.as_ptr() as *mut c_void, step).log_err() + { +@@ -499,23 +536,25 @@ impl MacWindowState { + fn is_maximized(&self) -> bool { + unsafe { + let bounds = self.bounds(); +- let screen_size = self.native_window.screen().visibleFrame().into(); ++ let screen: ObjcId = msg_send![self.native_window, screen]; ++ let vis: NSRect = msg_send![screen, visibleFrame]; ++ let screen_size: Size = vis.into(); + bounds.size == screen_size + } + } + + fn is_fullscreen(&self) -> bool { + unsafe { +- let style_mask = self.native_window.styleMask(); +- style_mask.contains(NSWindowStyleMask::NSFullScreenWindowMask) ++ let style_mask: NSWindowStyleMask = msg_send![self.native_window, styleMask]; ++ (style_mask & NSWindowStyleMaskFullScreen) != 0 + } + } + + fn bounds(&self) -> Bounds { +- let mut window_frame = unsafe { NSWindow::frame(self.native_window) }; +- let screen_frame = unsafe { +- let screen = NSWindow::screen(self.native_window); +- NSScreen::frame(screen) ++ let mut window_frame: NSRect = unsafe { msg_send![self.native_window, frame] }; ++ let screen_frame: NSRect = unsafe { ++ let screen: ObjcId = msg_send![self.native_window, screen]; ++ msg_send![screen, frame] + }; + + // Flip the y coordinate to be top-left origin +@@ -535,9 +574,11 @@ impl MacWindowState { + } + + fn content_size(&self) -> Size { +- let NSSize { width, height, .. } = +- unsafe { NSView::frame(self.native_window.contentView()) }.size; +- size(px(width as f32), px(height as f32)) ++ unsafe { ++ let content_view: ObjcId = msg_send![self.native_window, contentView]; ++ let frame: NSRect = msg_send![content_view, frame]; ++ size(px(frame.size.width as f32), px(frame.size.height as f32)) ++ } + } + + fn scale_factor(&self) -> f32 { +@@ -546,7 +587,7 @@ impl MacWindowState { + + fn titlebar_height(&self) -> Pixels { + unsafe { +- let frame = NSWindow::frame(self.native_window); ++ let frame: NSRect = msg_send![self.native_window, frame]; + let content_layout_rect: CGRect = msg_send![self.native_window, contentLayoutRect]; + px((frame.size.height - content_layout_rect.size.height) as f32) + } +@@ -585,7 +626,8 @@ impl MacWindow { + renderer_context: renderer::Context, + ) -> Self { + unsafe { +- let pool = NSAutoreleasePool::new(nil); ++ // Use an autorelease pool via raw Objective-C messaging ++ let pool: ObjcId = msg_send![class!(NSAutoreleasePool), new]; + + let allows_automatic_window_tabbing = tabbing_identifier.is_some(); + if allows_automatic_window_tabbing { +@@ -596,26 +638,24 @@ impl MacWindow { + + let mut style_mask; + if let Some(titlebar) = titlebar.as_ref() { +- style_mask = +- NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask; ++ style_mask = NSWindowStyleMaskClosable | NSWindowStyleMaskTitled; + + if is_resizable { +- style_mask |= NSWindowStyleMask::NSResizableWindowMask; ++ style_mask |= NSWindowStyleMaskResizable; + } + + if is_minimizable { +- style_mask |= NSWindowStyleMask::NSMiniaturizableWindowMask; ++ style_mask |= NSWindowStyleMaskMiniaturizable; + } + + if titlebar.appears_transparent { +- style_mask |= NSWindowStyleMask::NSFullSizeContentViewWindowMask; ++ style_mask |= NSWindowStyleMaskFullSizeContentView; + } + } else { +- style_mask = NSWindowStyleMask::NSTitledWindowMask +- | NSWindowStyleMask::NSFullSizeContentViewWindowMask; ++ style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView; + } + +- let native_window: id = match kind { ++ let native_window: ObjcId = match kind { + WindowKind::Normal => msg_send![WINDOW_CLASS, alloc], + WindowKind::PopUp => { + style_mask |= NSWindowStyleMaskNonactivatingPanel; +@@ -627,14 +667,14 @@ impl MacWindow { + .and_then(MacDisplay::find_by_id) + .unwrap_or_else(MacDisplay::primary); + +- let mut target_screen = nil; ++ let mut target_screen = NIL; + let mut screen_frame = None; + +- let screens = NSScreen::screens(nil); +- let count: u64 = cocoa::foundation::NSArray::count(screens); ++ let screens: ObjcId = msg_send![class!(NSScreen), screens]; ++ let count: u64 = msg_send![screens, count]; + for i in 0..count { +- let screen = cocoa::foundation::NSArray::objectAtIndex(screens, i); +- let frame = NSScreen::frame(screen); ++ let screen: ObjcId = msg_send![screens, objectAtIndex: i]; ++ let frame: NSRect = msg_send![screen, frame]; + let display_id = display_id_for_screen(screen); + if display_id == display.0 { + screen_frame = Some(frame); +@@ -643,41 +683,43 @@ impl MacWindow { + } + + let screen_frame = screen_frame.unwrap_or_else(|| { +- let screen = NSScreen::mainScreen(nil); ++ let screen: ObjcId = msg_send![class!(NSScreen), mainScreen]; + target_screen = screen; +- NSScreen::frame(screen) ++ let frame: NSRect = msg_send![screen, frame]; ++ frame + }); + +- let window_rect = NSRect::new( +- NSPoint::new( +- screen_frame.origin.x + bounds.origin.x.0 as f64, +- screen_frame.origin.y ++ let window_rect = NSRect { ++ origin: NSPoint { ++ x: screen_frame.origin.x + bounds.origin.x.0 as f64, ++ y: screen_frame.origin.y + + (display.bounds().size.height - bounds.origin.y).0 as f64, +- ), +- NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), +- ); ++ }, ++ size: NSSize { ++ width: bounds.size.width.0 as f64, ++ height: bounds.size.height.0 as f64, ++ }, ++ }; + +- let native_window = native_window.initWithContentRect_styleMask_backing_defer_screen_( +- window_rect, +- style_mask, +- NSBackingStoreBuffered, +- NO, +- target_screen, +- ); +- assert!(!native_window.is_null()); +- let () = msg_send![ +- native_window, +- registerForDraggedTypes: +- NSArray::arrayWithObject(nil, NSFilenamesPboardType) ++ let native_window: ObjcId = msg_send![native_window, ++ initWithContentRect: window_rect ++ styleMask: style_mask ++ backing: NSBackingStoreBuffered ++ defer: NO ++ screen: target_screen + ]; ++ assert!(!native_window.is_null()); ++ let types: ObjcId = msg_send![class!(NSArray), arrayWithObject: NSFilenamesPboardType]; ++ let () = msg_send![native_window, registerForDraggedTypes: types]; + let () = msg_send![ + native_window, + setReleasedWhenClosed: NO + ]; + +- let content_view = native_window.contentView(); +- let native_view: id = msg_send![VIEW_CLASS, alloc]; +- let native_view = NSView::initWithFrame_(native_view, NSView::bounds(content_view)); ++ let content_view: ObjcId = msg_send![native_window, contentView]; ++ let native_view: ObjcId = msg_send![VIEW_CLASS, alloc]; ++ let view_bounds: NSRect = msg_send![content_view, bounds]; ++ let native_view: ObjcId = msg_send![native_view, initWithFrame: view_bounds]; + assert!(!native_view.is_null()); + + let mut window = Self(Arc::new(Mutex::new(MacWindowState { +@@ -728,7 +770,7 @@ impl MacWindow { + WINDOW_STATE_IVAR, + Arc::into_raw(window.0.clone()) as *const c_void, + ); +- native_window.setDelegate_(native_window); ++ let _: () = msg_send![native_window, setDelegate: native_window]; + (*native_view).set_ivar( + WINDOW_STATE_IVAR, + Arc::into_raw(window.0.clone()) as *const c_void, +@@ -741,85 +783,91 @@ impl MacWindow { + window.set_title(title); + } + +- native_window.setMovable_(is_movable as BOOL); ++ let _: () = msg_send![native_window, setMovable: (is_movable as BOOL)]; + + if let Some(window_min_size) = window_min_size { +- native_window.setContentMinSize_(NSSize { ++ let min_size = NSSize { + width: window_min_size.width.to_f64(), + height: window_min_size.height.to_f64(), +- }); ++ }; ++ let _: () = msg_send![native_window, setContentMinSize: min_size]; + } + + if titlebar.is_none_or(|titlebar| titlebar.appears_transparent) { +- native_window.setTitlebarAppearsTransparent_(YES); +- native_window.setTitleVisibility_(NSWindowTitleVisibility::NSWindowTitleHidden); ++ let _: () = msg_send![native_window, setTitlebarAppearsTransparent: YES]; ++ let _: () = msg_send![native_window, setTitleVisibility: NSWindowTitleHidden]; + } + +- native_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); +- native_view.setWantsBestResolutionOpenGLSurface_(YES); ++ let _: () = msg_send![native_view, setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; ++ let _: () = msg_send![native_view, setWantsBestResolutionOpenGLSurface: YES]; + + // From winit crate: On Mojave, views automatically become layer-backed shortly after + // being added to a native_window. Changing the layer-backedness of a view breaks the + // association between the view and its associated OpenGL context. To work around this, + // on we explicitly make the view layer-backed up front so that AppKit doesn't do it + // itself and break the association with its context. +- native_view.setWantsLayer(YES); ++ let _: () = msg_send![native_view, setWantsLayer: YES]; + let _: () = msg_send![ + native_view, + setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize + ]; + +- content_view.addSubview_(native_view.autorelease()); +- native_window.makeFirstResponder_(native_view); ++ let native_view: ObjcId = msg_send![native_view, autorelease]; ++ let _: () = msg_send![content_view, addSubview: native_view]; ++ let _: () = msg_send![native_window, makeFirstResponder: native_view]; + + match kind { + WindowKind::Normal => { +- native_window.setLevel_(NSNormalWindowLevel); +- native_window.setAcceptsMouseMovedEvents_(YES); ++ let _: () = msg_send![native_window, setLevel: WINDOW_LEVEL_NORMAL]; ++ let _: () = msg_send![native_window, setAcceptsMouseMovedEvents: YES]; + + if let Some(tabbing_identifier) = tabbing_identifier { +- let tabbing_id = NSString::alloc(nil).init_str(tabbing_identifier.as_str()); ++ let tabbing_id = NSString::alloc(NIL).init_str(tabbing_identifier.as_str()); + let _: () = msg_send![native_window, setTabbingIdentifier: tabbing_id]; + } else { +- let _: () = msg_send![native_window, setTabbingIdentifier:nil]; ++ let _: () = msg_send![native_window, setTabbingIdentifier:NIL]; + } + } + WindowKind::PopUp => { + // Use a tracking area to allow receiving MouseMoved events even when + // the window or application aren't active, which is often the case + // e.g. for notification windows. +- let tracking_area: id = msg_send![class!(NSTrackingArea), alloc]; +- let _: () = msg_send![ +- tracking_area, +- initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) +- options: NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect +- owner: native_view +- userInfo: nil ++ let tracking_area: ObjcId = msg_send![class!(NSTrackingArea), alloc]; ++ let zero_rect = NSRect { ++ origin: NSPoint { x: 0.0, y: 0.0 }, ++ size: NSSize { ++ width: 0.0, ++ height: 0.0, ++ }, ++ }; ++ let _: () = msg_send![tracking_area, ++ initWithRect: zero_rect ++ options: NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect ++ owner: native_view ++ userInfo: NIL + ]; + let _: () = + msg_send![native_view, addTrackingArea: tracking_area.autorelease()]; + +- native_window.setLevel_(NSPopUpWindowLevel); ++ let _: () = msg_send![native_window, setLevel: WINDOW_LEVEL_POPUP]; + let _: () = msg_send![ + native_window, + setAnimationBehavior: NSWindowAnimationBehaviorUtilityWindow + ]; +- native_window.setCollectionBehavior_( +- NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces | +- NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenAuxiliary +- ); ++ let behavior = NSWindowCollectionBehaviorCanJoinAllSpaces ++ | NSWindowCollectionBehaviorFullScreenAuxiliary; ++ let _: () = msg_send![native_window, setCollectionBehavior: behavior]; + } + } + +- let app = NSApplication::sharedApplication(nil); +- let main_window: id = msg_send![app, mainWindow]; ++ let app: ObjcId = msg_send![class!(NSApplication), sharedApplication]; ++ let main_window: ObjcId = msg_send![app, mainWindow]; + if allows_automatic_window_tabbing + && !main_window.is_null() + && main_window != native_window + { +- let main_window_is_fullscreen = main_window +- .styleMask() +- .contains(NSWindowStyleMask::NSFullScreenWindowMask); ++ let main_style: NSWindowStyleMask = msg_send![main_window, styleMask]; ++ let main_window_is_fullscreen = (main_style & NSWindowStyleMaskFullScreen) != 0; + let user_tabbing_preference = Self::get_user_tabbing_preference() + .unwrap_or(UserTabbingPreference::InFullScreen); + let should_add_as_tab = user_tabbing_preference == UserTabbingPreference::Always +@@ -832,31 +880,31 @@ impl MacWindow { + let main_window_visible: BOOL = msg_send![main_window, isVisible]; + + if main_window_can_tab == YES && main_window_visible == YES { +- let _: () = msg_send![main_window, addTabbedWindow: native_window ordered: NSWindowOrderingMode::NSWindowAbove]; ++ let _: () = msg_send![main_window, addTabbedWindow: native_window ordered: NSWindowAbove]; + + // Ensure the window is visible immediately after adding the tab, since the tab bar is updated with a new entry at this point. + // Note: Calling orderFront here can break fullscreen mode (makes fullscreen windows exit fullscreen), so only do this if the main window is not fullscreen. + if !main_window_is_fullscreen { +- let _: () = msg_send![native_window, orderFront: nil]; ++ let _: () = msg_send![native_window, orderFront: NIL]; + } + } + } + } + + if focus && show { +- native_window.makeKeyAndOrderFront_(nil); ++ let _: () = msg_send![native_window, makeKeyAndOrderFront: NIL]; + } else if show { +- native_window.orderFront_(nil); ++ let _: () = msg_send![native_window, orderFront: NIL]; + } + + // Set the initial position of the window to the specified origin. + // Although we already specified the position using `initWithContentRect_styleMask_backing_defer_screen_`, + // the window position might be incorrect if the main screen (the screen that contains the window that has focus) + // is different from the primary screen. +- NSWindow::setFrameTopLeftPoint_(native_window, window_rect.origin); ++ let _: () = msg_send![native_window, setFrameTopLeftPoint: window_rect.origin]; + window.0.lock().move_traffic_light(); + +- pool.drain(); ++ let _: () = msg_send![pool, drain]; + + window + } +@@ -864,8 +912,8 @@ impl MacWindow { + + pub fn active_window() -> Option { + unsafe { +- let app = NSApplication::sharedApplication(nil); +- let main_window: id = msg_send![app, mainWindow]; ++ let app: ObjcId = msg_send![class!(NSApplication), sharedApplication]; ++ let main_window: ObjcId = msg_send![app, mainWindow]; + if main_window.is_null() { + return None; + } +@@ -881,13 +929,13 @@ impl MacWindow { + + pub fn ordered_windows() -> Vec { + unsafe { +- let app = NSApplication::sharedApplication(nil); +- let windows: id = msg_send![app, orderedWindows]; ++ let app: ObjcId = msg_send![class!(NSApplication), sharedApplication]; ++ let windows: ObjcId = msg_send![app, orderedWindows]; + let count: NSUInteger = msg_send![windows, count]; + + let mut window_handles = Vec::new(); + for i in 0..count { +- let window: id = msg_send![windows, objectAtIndex:i]; ++ let window: ObjcId = msg_send![windows, objectAtIndex:i]; + if msg_send![window, isKindOfClass: WINDOW_CLASS] { + let handle = get_window_state(&*window).lock().handle; + window_handles.push(handle); +@@ -900,15 +948,15 @@ impl MacWindow { + + pub fn get_user_tabbing_preference() -> Option { + unsafe { +- let defaults: id = NSUserDefaults::standardUserDefaults(); +- let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); +- let key = NSString::alloc(nil).init_str("AppleWindowTabbingMode"); ++ let defaults: ObjcId = NSUserDefaults::standardUserDefaults(); ++ let domain = NSString::alloc(NIL).init_str("NSGlobalDomain"); ++ let key = NSString::alloc(NIL).init_str("AppleWindowTabbingMode"); + +- let dict: id = msg_send![defaults, persistentDomainForName: domain]; +- let value: id = if !dict.is_null() { ++ let dict: ObjcId = msg_send![defaults, persistentDomainForName: domain]; ++ let value: ObjcId = if !dict.is_null() { + msg_send![dict, objectForKey: key] + } else { +- nil ++ NIL + }; + + let value_str = if !value.is_null() { +@@ -933,14 +981,14 @@ impl Drop for MacWindow { + let window = this.native_window; + this.display_link.take(); + unsafe { +- this.native_window.setDelegate_(nil); ++ let _: () = msg_send![this.native_window, setDelegate: NIL]; + } + this.input_handler.take(); + this.executor + .spawn(async move { + unsafe { +- window.close(); +- window.autorelease(); ++ let _: () = msg_send![window, close]; ++ let _: ObjcId = msg_send![window, autorelease]; + } + }) + .detach(); +@@ -970,10 +1018,11 @@ impl PlatformWindow for MacWindow { + this.executor + .spawn(async move { + unsafe { +- window.setContentSize_(NSSize { ++ let new_size = NSSize { + width: size.width.0 as f64, + height: size.height.0 as f64, +- }); ++ }; ++ let _: () = msg_send![window, setContentSize: new_size]; + } + }) + .detach(); +@@ -982,8 +1031,8 @@ impl PlatformWindow for MacWindow { + fn merge_all_windows(&self) { + let native_window = self.0.lock().native_window; + unsafe extern "C" fn merge_windows_async(context: *mut std::ffi::c_void) { +- let native_window = context as id; +- let _: () = msg_send![native_window, mergeAllWindows:nil]; ++ let native_window = context as ObjcId; ++ let _: () = msg_send![native_window, mergeAllWindows:NIL]; + } + + unsafe { +@@ -998,9 +1047,9 @@ impl PlatformWindow for MacWindow { + fn move_tab_to_new_window(&self) { + let native_window = self.0.lock().native_window; + unsafe extern "C" fn move_tab_async(context: *mut std::ffi::c_void) { +- let native_window = context as id; +- let _: () = msg_send![native_window, moveTabToNewWindow:nil]; +- let _: () = msg_send![native_window, makeKeyAndOrderFront: nil]; ++ let native_window = context as ObjcId; ++ let _: () = msg_send![native_window, moveTabToNewWindow:NIL]; ++ let _: () = msg_send![native_window, makeKeyAndOrderFront: NIL]; + } + + unsafe { +@@ -1015,7 +1064,7 @@ impl PlatformWindow for MacWindow { + fn toggle_window_tab_overview(&self) { + let native_window = self.0.lock().native_window; + unsafe { +- let _: () = msg_send![native_window, toggleTabOverview:nil]; ++ let _: () = msg_send![native_window, toggleTabOverview:NIL]; + } + } + +@@ -1030,10 +1079,10 @@ impl PlatformWindow for MacWindow { + } + + if let Some(tabbing_identifier) = tabbing_identifier { +- let tabbing_id = NSString::alloc(nil).init_str(tabbing_identifier.as_str()); ++ let tabbing_id = NSString::alloc(NIL).init_str(tabbing_identifier.as_str()); + let _: () = msg_send![native_window, setTabbingIdentifier: tabbing_id]; + } else { +- let _: () = msg_send![native_window, setTabbingIdentifier:nil]; ++ let _: () = msg_send![native_window, setTabbingIdentifier:NIL]; + } + } + } +@@ -1044,48 +1093,43 @@ impl PlatformWindow for MacWindow { + + fn appearance(&self) -> WindowAppearance { + unsafe { +- let appearance: id = msg_send![self.0.lock().native_window, effectiveAppearance]; ++ let appearance: ObjcId = msg_send![self.0.lock().native_window, effectiveAppearance]; + WindowAppearance::from_native(appearance) + } + } + + fn display(&self) -> Option> { + unsafe { +- let screen = self.0.lock().native_window.screen(); ++ let screen: ObjcId = msg_send![self.0.lock().native_window, screen]; + if screen.is_null() { + return None; + } +- let device_description: id = msg_send![screen, deviceDescription]; +- let screen_number: id = NSDictionary::valueForKey_( +- device_description, +- NSString::alloc(nil).init_str("NSScreenNumber"), +- ); +- +- let screen_number: u32 = msg_send![screen_number, unsignedIntValue]; +- ++ let device_description: ObjcId = msg_send![screen, deviceDescription]; ++ let screen_number_obj: ObjcId = ++ msg_send![device_description, valueForKey: ns_string("NSScreenNumber")]; ++ let screen_number: u32 = msg_send![screen_number_obj, unsignedIntValue]; + Some(Rc::new(MacDisplay(screen_number))) + } + } + + fn mouse_position(&self) -> Point { + let position = unsafe { +- self.0 +- .lock() +- .native_window +- .mouseLocationOutsideOfEventStream() ++ msg_send![ ++ self.0.lock().native_window, ++ mouseLocationOutsideOfEventStream ++ ] + }; + convert_mouse_position(position, self.content_size().height) + } + + fn modifiers(&self) -> Modifiers { + unsafe { +- let modifiers: NSEventModifierFlags = msg_send![class!(NSEvent), modifierFlags]; +- +- let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); +- let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); +- let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); +- let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); +- let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); ++ let modifiers: u64 = msg_send![class!(NSEvent), modifierFlags]; ++ let control = (modifiers & MOD_CONTROL) != 0; ++ let alt = (modifiers & MOD_OPTION) != 0; ++ let shift = (modifiers & MOD_SHIFT) != 0; ++ let command = (modifiers & MOD_COMMAND) != 0; ++ let function = (modifiers & MOD_FUNCTION) != 0; + + Modifiers { + control, +@@ -1099,10 +1143,9 @@ impl PlatformWindow for MacWindow { + + fn capslock(&self) -> Capslock { + unsafe { +- let modifiers: NSEventModifierFlags = msg_send![class!(NSEvent), modifierFlags]; +- ++ let modifiers: u64 = msg_send![class!(NSEvent), modifierFlags]; + Capslock { +- on: modifiers.contains(NSEventModifierFlags::NSAlphaShiftKeyMask), ++ on: (modifiers & MOD_CAPS_LOCK) != 0, + } + } + } +@@ -1148,12 +1191,12 @@ impl PlatformWindow for MacWindow { + .filter(|&(label_index, _)| label_index > 0); + + unsafe { +- let alert: id = msg_send![class!(NSAlert), alloc]; +- let alert: id = msg_send![alert, init]; ++ let alert: ObjcId = msg_send![class!(NSAlert), alloc]; ++ let alert: ObjcId = msg_send![alert, init]; + let alert_style = match level { +- PromptLevel::Info => 1, +- PromptLevel::Warning => 0, +- PromptLevel::Critical => 2, ++ PromptLevel::Info => NSAlertStyleInformational, ++ PromptLevel::Warning => NSAlertStyleWarning, ++ PromptLevel::Critical => NSAlertStyleCritical, + }; + let _: () = msg_send![alert, setAlertStyle: alert_style]; + let _: () = msg_send![alert, setMessageText: ns_string(msg)]; +@@ -1166,7 +1209,8 @@ impl PlatformWindow for MacWindow { + .enumerate() + .filter(|&(ix, _)| Some(ix) != latest_non_cancel_label.map(|(ix, _)| ix)) + { +- let button: id = msg_send![alert, addButtonWithTitle: ns_string(answer.label())]; ++ let button: ObjcId = ++ msg_send![alert, addButtonWithTitle: ns_string(answer.label())]; + let _: () = msg_send![button, setTag: ix as NSInteger]; + + if answer.is_cancel() { +@@ -1178,7 +1222,8 @@ impl PlatformWindow for MacWindow { + } + } + if let Some((ix, answer)) = latest_non_cancel_label { +- let button: id = msg_send![alert, addButtonWithTitle: ns_string(answer.label())]; ++ let button: ObjcId = ++ msg_send![alert, addButtonWithTitle: ns_string(answer.label())]; + let _: () = msg_send![button, setTag: ix as NSInteger]; + } + +@@ -1212,14 +1257,17 @@ impl PlatformWindow for MacWindow { + executor + .spawn(async move { + unsafe { +- let _: () = msg_send![window, makeKeyAndOrderFront: nil]; ++ let _: () = msg_send![window, makeKeyAndOrderFront: NIL]; + } + }) + .detach(); + } + + fn is_active(&self) -> bool { +- unsafe { self.0.lock().native_window.isKeyWindow() == YES } ++ unsafe { ++ let is_key: BOOL = msg_send![self.0.lock().native_window, isKeyWindow]; ++ is_key == YES ++ } + } + + // is_hovered is unused on macOS. See Window::is_window_hovered. +@@ -1229,7 +1277,7 @@ impl PlatformWindow for MacWindow { + + fn set_title(&mut self, title: &str) { + unsafe { +- let app = NSApplication::sharedApplication(nil); ++ let app: ObjcId = msg_send![class!(NSApplication), sharedApplication]; + let window = self.0.lock().native_window; + let title = ns_string(title); + let _: () = msg_send![app, changeWindowsItem:window title:title filename:false]; +@@ -1240,7 +1288,7 @@ impl PlatformWindow for MacWindow { + + fn get_title(&self) -> String { + unsafe { +- let title: id = msg_send![self.0.lock().native_window, title]; ++ let title: ObjcId = msg_send![self.0.lock().native_window, title]; + if title.is_null() { + "".to_string() + } else { +@@ -1258,14 +1306,14 @@ impl PlatformWindow for MacWindow { + this.renderer.update_transparency(!opaque); + + unsafe { +- this.native_window.setOpaque_(opaque as BOOL); +- let background_color = if opaque { +- NSColor::colorWithSRGBRed_green_blue_alpha_(nil, 0f64, 0f64, 0f64, 1f64) ++ let _: () = msg_send![this.native_window, setOpaque: (opaque as BOOL)]; ++ let background_color: ObjcId = if opaque { ++ msg_send![class!(NSColor), colorWithSRGBRed: 0f64 green: 0f64 blue: 0f64 alpha: 1f64] + } else { + // Not using `+[NSColor clearColor]` to avoid broken shadow. +- NSColor::colorWithSRGBRed_green_blue_alpha_(nil, 0f64, 0f64, 0f64, 0.0001) ++ msg_send![class!(NSColor), colorWithSRGBRed: 0f64 green: 0f64 blue: 0f64 alpha: 0.0001f64] + }; +- this.native_window.setBackgroundColor_(background_color); ++ let _: () = msg_send![this.native_window, setBackgroundColor: background_color]; + + if NSAppKitVersionNumber < NSAppKitVersionNumber12_0 { + // Whether `-[NSVisualEffectView respondsToSelector:@selector(_updateProxyLayer)]`. +@@ -1277,7 +1325,7 @@ impl PlatformWindow for MacWindow { + 0 + }; + +- let window_number = this.native_window.windowNumber(); ++ let window_number: NSInteger = msg_send![this.native_window, windowNumber]; + CGSSetWindowBackgroundBlurRadius(CGSMainConnectionID(), window_number, blur_radius); + } else { + // On newer macOS `NSVisualEffectView` manages the effect layer directly. Using it +@@ -1285,23 +1333,19 @@ impl PlatformWindow for MacWindow { + // over the effect layer. + if background_appearance != WindowBackgroundAppearance::Blurred { + if let Some(blur_view) = this.blurred_view { +- NSView::removeFromSuperview(blur_view); ++ let _: () = msg_send![blur_view, removeFromSuperview]; + this.blurred_view = None; + } + } else if this.blurred_view.is_none() { +- let content_view = this.native_window.contentView(); +- let frame = NSView::bounds(content_view); +- let mut blur_view: id = msg_send![BLURRED_VIEW_CLASS, alloc]; +- blur_view = NSView::initWithFrame_(blur_view, frame); +- blur_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); +- +- let _: () = msg_send![ +- content_view, +- addSubview: blur_view +- positioned: NSWindowOrderingMode::NSWindowBelow +- relativeTo: nil +- ]; +- this.blurred_view = Some(blur_view.autorelease()); ++ let content_view: ObjcId = msg_send![this.native_window, contentView]; ++ let blur_frame: NSRect = msg_send![content_view, bounds]; ++ let mut blur_view: ObjcId = msg_send![BLURRED_VIEW_CLASS, alloc]; ++ blur_view = msg_send![blur_view, initWithFrame: blur_frame]; ++ let _: () = msg_send![blur_view, setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; ++ ++ let _: () = msg_send![content_view, addSubview: blur_view positioned: NSWindowBelow relativeTo: NIL]; ++ let blur_view: ObjcId = msg_send![blur_view, autorelease]; ++ this.blurred_view = Some(blur_view); + } + } + } +@@ -1324,7 +1368,7 @@ impl PlatformWindow for MacWindow { + this.executor + .spawn(async move { + unsafe { +- let app = NSApplication::sharedApplication(nil); ++ let app: ObjcId = msg_send![class!(NSApplication), sharedApplication]; + let _: () = msg_send![app, orderFrontCharacterPalette: window]; + } + }) +@@ -1334,7 +1378,7 @@ impl PlatformWindow for MacWindow { + fn minimize(&self) { + let window = self.0.lock().native_window; + unsafe { +- window.miniaturize_(nil); ++ let _: () = msg_send![window, miniaturize: NIL]; + } + } + +@@ -1344,7 +1388,7 @@ impl PlatformWindow for MacWindow { + this.executor + .spawn(async move { + unsafe { +- window.zoom_(nil); ++ let _: () = msg_send![window, zoom: NIL]; + } + }) + .detach(); +@@ -1356,7 +1400,7 @@ impl PlatformWindow for MacWindow { + this.executor + .spawn(async move { + unsafe { +- window.toggleFullScreen_(nil); ++ let _: () = msg_send![window, toggleFullScreen: NIL]; + } + }) + .detach(); +@@ -1367,9 +1411,8 @@ impl PlatformWindow for MacWindow { + let window = this.native_window; + + unsafe { +- window +- .styleMask() +- .contains(NSWindowStyleMask::NSFullScreenWindowMask) ++ let mask: NSWindowStyleMask = msg_send![window, styleMask]; ++ (mask & NSWindowStyleMaskFullScreen) != 0 + } + } + +@@ -1412,7 +1455,7 @@ impl PlatformWindow for MacWindow { + + fn tabbed_windows(&self) -> Option> { + unsafe { +- let windows: id = msg_send![self.0.lock().native_window, tabbedWindows]; ++ let windows: ObjcId = msg_send![self.0.lock().native_window, tabbedWindows]; + if windows.is_null() { + return None; + } +@@ -1420,10 +1463,10 @@ impl PlatformWindow for MacWindow { + let count: NSUInteger = msg_send![windows, count]; + let mut result = Vec::new(); + for i in 0..count { +- let window: id = msg_send![windows, objectAtIndex:i]; ++ let window: ObjcId = msg_send![windows, objectAtIndex:i]; + if msg_send![window, isKindOfClass: WINDOW_CLASS] { + let handle = get_window_state(&*window).lock().handle; +- let title: id = msg_send![window, title]; ++ let title: ObjcId = msg_send![window, title]; + let title = SharedString::from(title.to_str().to_string()); + + result.push(SystemWindowTab::new(title, handle)); +@@ -1436,7 +1479,7 @@ impl PlatformWindow for MacWindow { + + fn tab_bar_visible(&self) -> bool { + unsafe { +- let tab_group: id = msg_send![self.0.lock().native_window, tabGroup]; ++ let tab_group: ObjcId = msg_send![self.0.lock().native_window, tabGroup]; + if tab_group.is_null() { + false + } else { +@@ -1484,7 +1527,7 @@ impl PlatformWindow for MacWindow { + executor + .spawn(async move { + unsafe { +- let input_context: id = ++ let input_context: ObjcId = + msg_send![class!(NSTextInputContext), currentInputContext]; + if input_context.is_null() { + return; +@@ -1501,15 +1544,15 @@ impl PlatformWindow for MacWindow { + this.executor + .spawn(async move { + unsafe { +- let defaults: id = NSUserDefaults::standardUserDefaults(); +- let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); +- let key = NSString::alloc(nil).init_str("AppleActionOnDoubleClick"); ++ let defaults: ObjcId = NSUserDefaults::standardUserDefaults(); ++ let domain = NSString::alloc(NIL).init_str("NSGlobalDomain"); ++ let key = NSString::alloc(NIL).init_str("AppleActionOnDoubleClick"); + +- let dict: id = msg_send![defaults, persistentDomainForName: domain]; +- let action: id = if !dict.is_null() { ++ let dict: ObjcId = msg_send![defaults, persistentDomainForName: domain]; ++ let action: ObjcId = if !dict.is_null() { + msg_send![dict, objectForKey: key] + } else { +- nil ++ NIL + }; + + let action_str = if !action.is_null() { +@@ -1520,17 +1563,17 @@ impl PlatformWindow for MacWindow { + + match action_str.as_ref() { + "Minimize" => { +- window.miniaturize_(nil); ++ let _: () = msg_send![window, miniaturize: NIL]; + } + "Maximize" => { +- window.zoom_(nil); ++ let _: () = msg_send![window, zoom: NIL]; + } + "Fill" => { + // There is no documented API for "Fill" action, so we'll just zoom the window +- window.zoom_(nil); ++ let _: () = msg_send![window, zoom: NIL]; + } + _ => { +- window.zoom_(nil); ++ let _: () = msg_send![window, zoom: NIL]; + } + } + } +@@ -1561,13 +1604,14 @@ impl rwh::HasDisplayHandle for MacWindow { + } + } + +-fn get_scale_factor(native_window: id) -> f32 { ++fn get_scale_factor(native_window: ObjcId) -> f32 { + let factor = unsafe { +- let screen: id = msg_send![native_window, screen]; ++ let screen: ObjcId = msg_send![native_window, screen]; + if screen.is_null() { + return 1.0; + } +- NSScreen::backingScaleFactor(screen) as f32 ++ let scale: f64 = msg_send![screen, backingScaleFactor]; ++ scale as f32 + }; + + // We are not certain what triggers this, but it seems that sometimes +@@ -1614,15 +1658,15 @@ extern "C" fn dealloc_view(this: &Object, _: Sel) { + } + } + +-extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: id) -> BOOL { ++extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: ObjcId) -> BOOL { + handle_key_event(this, native_event, true) + } + +-extern "C" fn handle_key_down(this: &Object, _: Sel, native_event: id) { ++extern "C" fn handle_key_down(this: &Object, _: Sel, native_event: ObjcId) { + handle_key_event(this, native_event, false); + } + +-extern "C" fn handle_key_up(this: &Object, _: Sel, native_event: id) { ++extern "C" fn handle_key_up(this: &Object, _: Sel, native_event: ObjcId) { + handle_key_event(this, native_event, false); + } + +@@ -1651,7 +1695,7 @@ extern "C" fn handle_key_up(this: &Object, _: Sel, native_event: id) { + // - in vim mode `option-4` should go to end of line (same as $) + // Japanese (Romaji) layout: + // - type `a i left down up enter enter` should create an unmarked text "愛" +-extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: bool) -> BOOL { ++extern "C" fn handle_key_event(this: &Object, native_event: ObjcId, key_equivalent: bool) -> BOOL { + let window_state = unsafe { get_window_state(this) }; + let mut lock = window_state.as_ref().lock(); + +@@ -1713,7 +1757,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: + } + + let handled: BOOL = unsafe { +- let input_context: id = msg_send![this, inputContext]; ++ let input_context: ObjcId = msg_send![this, inputContext]; + msg_send![input_context, handleEvent: native_event] + }; + window_state.as_ref().lock().keystroke_for_do_command.take(); +@@ -1754,7 +1798,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: + } + + unsafe { +- let input_context: id = msg_send![this, inputContext]; ++ let input_context: ObjcId = msg_send![this, inputContext]; + msg_send![input_context, handleEvent: native_event] + } + } +@@ -1768,7 +1812,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: + } + } + +-extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { ++extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + let weak_window_state = Arc::downgrade(&window_state); + let mut lock = window_state.as_ref().lock(); +@@ -1838,7 +1882,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { + PlatformInput::MouseDown(_) => { + drop(lock); + unsafe { +- let input_context: id = msg_send![this, inputContext]; ++ let input_context: ObjcId = msg_send![this, inputContext]; + msg_send![input_context, handleEvent: native_event] + } + lock = window_state.as_ref().lock(); +@@ -1898,15 +1942,12 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { + } + } + +-extern "C" fn window_did_change_occlusion_state(this: &Object, _: Sel, _: id) { ++extern "C" fn window_did_change_occlusion_state(this: &Object, _: Sel, _: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + let lock = &mut *window_state.lock(); + unsafe { +- if lock +- .native_window +- .occlusionState() +- .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) +- { ++ let is_visible: BOOL = msg_send![lock.native_window, isVisible]; ++ if is_visible == YES { + lock.move_traffic_light(); + lock.start_display_link(); + } else { +@@ -1915,43 +1956,55 @@ extern "C" fn window_did_change_occlusion_state(this: &Object, _: Sel, _: id) { + } + } + +-extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) { ++extern "C" fn window_did_resize(this: &Object, _: Sel, _: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + window_state.as_ref().lock().move_traffic_light(); + } + +-extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) { ++extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + let mut lock = window_state.as_ref().lock(); + lock.fullscreen_restore_bounds = lock.bounds(); + +- let min_version = NSOperatingSystemVersion::new(15, 3, 0); ++ let min_version = NSOperatingSystemVersion { ++ majorVersion: 15, ++ minorVersion: 3, ++ patchVersion: 0, ++ }; + + if is_macos_version_at_least(min_version) { + unsafe { +- lock.native_window.setTitlebarAppearsTransparent_(NO); ++ let _: () = msg_send![lock.native_window, setTitlebarAppearsTransparent: NO]; + } + } + } + +-extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: id) { ++extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + let mut lock = window_state.as_ref().lock(); + +- let min_version = NSOperatingSystemVersion::new(15, 3, 0); ++ let min_version = NSOperatingSystemVersion { ++ majorVersion: 15, ++ minorVersion: 3, ++ patchVersion: 0, ++ }; + + if is_macos_version_at_least(min_version) && lock.transparent_titlebar { + unsafe { +- lock.native_window.setTitlebarAppearsTransparent_(YES); ++ let _: () = msg_send![lock.native_window, setTitlebarAppearsTransparent: YES]; + } + } + } + + pub(crate) fn is_macos_version_at_least(version: NSOperatingSystemVersion) -> bool { +- unsafe { NSProcessInfo::processInfo(nil).isOperatingSystemAtLeastVersion(version) } ++ unsafe { ++ let process_info: ObjcId = msg_send![class!(NSProcessInfo), processInfo]; ++ let ok: BOOL = msg_send![process_info, isOperatingSystemAtLeastVersion: version]; ++ ok == YES ++ } + } + +-extern "C" fn window_did_move(this: &Object, _: Sel, _: id) { ++extern "C" fn window_did_move(this: &Object, _: Sel, _: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + let mut lock = window_state.as_ref().lock(); + if let Some(mut callback) = lock.moved_callback.take() { +@@ -1961,16 +2014,19 @@ extern "C" fn window_did_move(this: &Object, _: Sel, _: id) { + } + } + +-extern "C" fn window_did_change_screen(this: &Object, _: Sel, _: id) { ++extern "C" fn window_did_change_screen(this: &Object, _: Sel, _: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + let mut lock = window_state.as_ref().lock(); + lock.start_display_link(); + } + +-extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) { ++extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + let mut lock = window_state.lock(); +- let is_active = unsafe { lock.native_window.isKeyWindow() == YES }; ++ let is_active = unsafe { ++ let v: BOOL = msg_send![lock.native_window, isKeyWindow]; ++ v == YES ++ }; + + // When opening a pop-up while the application isn't active, Cocoa sends a spurious + // `windowDidBecomeKey` message to the previous key window even though that window +@@ -2027,7 +2083,7 @@ extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) + .detach(); + } + +-extern "C" fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL { ++extern "C" fn window_should_close(this: &Object, _: Sel, _: ObjcId) -> BOOL { + let window_state = unsafe { get_window_state(this) }; + let mut lock = window_state.as_ref().lock(); + if let Some(mut callback) = lock.should_close_callback.take() { +@@ -2056,10 +2112,10 @@ extern "C" fn close_window(this: &Object, _: Sel) { + } + } + +-extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { ++extern "C" fn make_backing_layer(this: &Object, _: Sel) -> ObjcId { + let window_state = unsafe { get_window_state(this) }; + let window_state = window_state.as_ref().lock(); +- window_state.renderer.layer_ptr() as id ++ window_state.renderer.layer_ptr() as ObjcId + } + + extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) { +@@ -2091,10 +2147,16 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { + let window_state = unsafe { get_window_state(this) }; + let mut lock = window_state.as_ref().lock(); + +- let new_size = Size::::from(size); ++ let new_size = Size:: { ++ width: px(size.width as f32), ++ height: px(size.height as f32), ++ }; + let old_size = unsafe { + let old_frame: NSRect = msg_send![this, frame]; +- Size::::from(old_frame.size) ++ Size:: { ++ width: px(old_frame.size.width as f32), ++ height: px(old_frame.size.height as f32), ++ } + }; + + if old_size == new_size { +@@ -2118,7 +2180,7 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { + }; + } + +-extern "C" fn display_layer(this: &Object, _: Sel, _: id) { ++extern "C" fn display_layer(this: &Object, _: Sel, _: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + let mut lock = window_state.lock(); + if let Some(mut callback) = lock.request_frame_callback.take() { +@@ -2137,7 +2199,7 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) { + } + + unsafe extern "C" fn step(view: *mut c_void) { +- let view = view as id; ++ let view = view as ObjcId; + let window_state = unsafe { get_window_state(&*view) }; + let mut lock = window_state.lock(); + +@@ -2148,7 +2210,7 @@ unsafe extern "C" fn step(view: *mut c_void) { + } + } + +-extern "C" fn valid_attributes_for_marked_text(_: &Object, _: Sel) -> id { ++extern "C" fn valid_attributes_for_marked_text(_: &Object, _: Sel) -> ObjcId { + unsafe { msg_send![class!(NSArray), array] } + } + +@@ -2179,7 +2241,7 @@ extern "C" fn first_rect_for_character_range( + this: &Object, + _: Sel, + range: NSRange, +- _: id, ++ _: ObjcId, + ) -> NSRect { + let frame = get_frame(this); + with_input_handler(this, |input_handler| { +@@ -2187,17 +2249,24 @@ extern "C" fn first_rect_for_character_range( + }) + .flatten() + .map_or( +- NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), +- |bounds| { +- NSRect::new( +- NSPoint::new( +- frame.origin.x + bounds.origin.x.0 as f64, +- frame.origin.y + frame.size.height +- - bounds.origin.y.0 as f64 +- - bounds.size.height.0 as f64, +- ), +- NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), +- ) ++ NSRect { ++ origin: NSPoint { x: 0., y: 0. }, ++ size: NSSize { ++ width: 0., ++ height: 0., ++ }, ++ }, ++ |bounds| NSRect { ++ origin: NSPoint { ++ x: frame.origin.x + bounds.origin.x.0 as f64, ++ y: frame.origin.y + frame.size.height ++ - bounds.origin.y.0 as f64 ++ - bounds.size.height.0 as f64, ++ }, ++ size: NSSize { ++ width: bounds.size.width.0 as f64, ++ height: bounds.size.height.0 as f64, ++ }, + }, + ) + } +@@ -2206,21 +2275,23 @@ fn get_frame(this: &Object) -> NSRect { + unsafe { + let state = get_window_state(this); + let lock = state.lock(); +- let mut frame = NSWindow::frame(lock.native_window); ++ let mut frame: NSRect = msg_send![lock.native_window, frame]; + let content_layout_rect: CGRect = msg_send![lock.native_window, contentLayoutRect]; +- let style_mask: NSWindowStyleMask = msg_send![lock.native_window, styleMask]; +- if !style_mask.contains(NSWindowStyleMask::NSFullSizeContentViewWindowMask) { +- frame.origin.y -= frame.size.height - content_layout_rect.size.height; ++ // Adjust Y-origin by the difference between full frame and content layout height ++ // when there is a titlebar/tool area. This avoids relying on deprecated bitmask names. ++ let diff = frame.size.height - content_layout_rect.size.height; ++ if diff > 0.0 { ++ frame.origin.y -= diff; + } + frame + } + } + +-extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NSRange) { ++extern "C" fn insert_text(this: &Object, _: Sel, text: ObjcId, replacement_range: NSRange) { + unsafe { + let is_attributed_string: BOOL = + msg_send![text, isKindOfClass: [class!(NSAttributedString)]]; +- let text: id = if is_attributed_string == YES { ++ let text: ObjcId = if is_attributed_string == YES { + msg_send![text, string] + } else { + text +@@ -2237,14 +2308,14 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS + extern "C" fn set_marked_text( + this: &Object, + _: Sel, +- text: id, ++ text: ObjcId, + selected_range: NSRange, + replacement_range: NSRange, + ) { + unsafe { + let is_attributed_string: BOOL = + msg_send![text, isKindOfClass: [class!(NSAttributedString)]]; +- let text: id = if is_attributed_string == YES { ++ let text: ObjcId = if is_attributed_string == YES { + msg_send![text, string] + } else { + text +@@ -2266,7 +2337,7 @@ extern "C" fn attributed_substring_for_proposed_range( + _: Sel, + range: NSRange, + actual_range: *mut c_void, +-) -> id { ++) -> ObjcId { + with_input_handler(this, |input_handler| { + let range = range.to_range()?; + if range.is_empty() { +@@ -2281,13 +2352,13 @@ extern "C" fn attributed_substring_for_proposed_range( + unsafe { (actual_range as *mut NSRange).write(NSRange::from(adjusted)) }; + } + unsafe { +- let string: id = msg_send![class!(NSAttributedString), alloc]; +- let string: id = msg_send![string, initWithString: ns_string(&selected_text)]; ++ let string: ObjcId = msg_send![class!(NSAttributedString), alloc]; ++ let string: ObjcId = msg_send![string, initWithString: ns_string(&selected_text)]; + Some(string) + } + }) + .flatten() +- .unwrap_or(nil) ++ .unwrap_or(NIL) + } + + // We ignore which selector it asks us to do because the user may have +@@ -2322,7 +2393,7 @@ extern "C" fn view_did_change_effective_appearance(this: &Object, _: Sel) { + } + } + +-extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: id) -> BOOL { ++extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: ObjcId) -> BOOL { + let window_state = unsafe { get_window_state(this) }; + let mut lock = window_state.as_ref().lock(); + lock.first_mouse = true; +@@ -2347,7 +2418,7 @@ fn screen_point_to_gpui_point(this: &Object, position: NSPoint) -> Point + point(px(window_x as f32), px(window_y as f32)) + } + +-extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: id) -> NSDragOperation { ++extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: ObjcId) -> NSDragOperation { + let window_state = unsafe { get_window_state(this) }; + let position = drag_event_position(&window_state, dragging_info); + let paths = external_paths_from_event(dragging_info); +@@ -2361,7 +2432,7 @@ extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: id) -> NSDr + NSDragOperationNone + } + +-extern "C" fn dragging_updated(this: &Object, _: Sel, dragging_info: id) -> NSDragOperation { ++extern "C" fn dragging_updated(this: &Object, _: Sel, dragging_info: ObjcId) -> NSDragOperation { + let window_state = unsafe { get_window_state(this) }; + let position = drag_event_position(&window_state, dragging_info); + if send_new_event( +@@ -2374,7 +2445,7 @@ extern "C" fn dragging_updated(this: &Object, _: Sel, dragging_info: id) -> NSDr + } + } + +-extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) { ++extern "C" fn dragging_exited(this: &Object, _: Sel, _: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + send_new_event( + &window_state, +@@ -2383,7 +2454,7 @@ extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) { + window_state.lock().external_files_dragged = false; + } + +-extern "C" fn perform_drag_operation(this: &Object, _: Sel, dragging_info: id) -> BOOL { ++extern "C" fn perform_drag_operation(this: &Object, _: Sel, dragging_info: ObjcId) -> BOOL { + let window_state = unsafe { get_window_state(this) }; + let position = drag_event_position(&window_state, dragging_info); + send_new_event( +@@ -2395,22 +2466,27 @@ extern "C" fn perform_drag_operation(this: &Object, _: Sel, dragging_info: id) - + + fn external_paths_from_event(dragging_info: *mut Object) -> Option { + let mut paths = SmallVec::new(); +- let pasteboard: id = unsafe { msg_send![dragging_info, draggingPasteboard] }; +- let filenames = unsafe { NSPasteboard::propertyListForType(pasteboard, NSFilenamesPboardType) }; +- if filenames == nil { ++ let pasteboard: ObjcId = unsafe { msg_send![dragging_info, draggingPasteboard] }; ++ let filenames: ObjcId = ++ unsafe { msg_send![pasteboard, propertyListForType: NSFilenamesPboardType] }; ++ if filenames == NIL { + return None; + } +- for file in unsafe { filenames.iter() } { +- let path = unsafe { +- let f = NSString::UTF8String(file); +- CStr::from_ptr(f).to_string_lossy().into_owned() +- }; +- paths.push(PathBuf::from(path)) ++ unsafe { ++ let count: NSUInteger = msg_send![filenames, count]; ++ for i in 0..count { ++ let file: ObjcId = msg_send![filenames, objectAtIndex: i]; ++ let path = { ++ let f = NSString::UTF8String(file); ++ CStr::from_ptr(f).to_string_lossy().into_owned() ++ }; ++ paths.push(PathBuf::from(path)); ++ } + } + Some(ExternalPaths(paths)) + } + +-extern "C" fn conclude_drag_operation(this: &Object, _: Sel, _: id) { ++extern "C" fn conclude_drag_operation(this: &Object, _: Sel, _: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + send_new_event( + &window_state, +@@ -2451,7 +2527,10 @@ fn send_new_event(window_state_lock: &Mutex, e: PlatformInput) - + } + } + +-fn drag_event_position(window_state: &Mutex, dragging_info: id) -> Point { ++fn drag_event_position( ++ window_state: &Mutex, ++ dragging_info: ObjcId, ++) -> Point { + let drag_location: NSPoint = unsafe { msg_send![dragging_info, draggingLocation] }; + convert_mouse_position(drag_location, window_state.lock().content_size().height) + } +@@ -2472,23 +2551,21 @@ where + } + } + +-unsafe fn display_id_for_screen(screen: id) -> CGDirectDisplayID { ++unsafe fn display_id_for_screen(screen: ObjcId) -> CGDirectDisplayID { + unsafe { +- let device_description = NSScreen::deviceDescription(screen); +- let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); +- let screen_number = device_description.objectForKey_(screen_number_key); +- let screen_number: NSUInteger = msg_send![screen_number, unsignedIntegerValue]; ++ let device_description: ObjcId = msg_send![screen, deviceDescription]; ++ let key: ObjcId = NSString::alloc(NIL).init_str("NSScreenNumber"); ++ let screen_number_obj: ObjcId = msg_send![device_description, objectForKey: key]; ++ let screen_number: NSUInteger = msg_send![screen_number_obj, unsignedIntegerValue]; + screen_number as CGDirectDisplayID + } + } + +-extern "C" fn blurred_view_init_with_frame(this: &Object, _: Sel, frame: NSRect) -> id { ++extern "C" fn blurred_view_init_with_frame(this: &Object, _: Sel, frame: NSRect) -> ObjcId { + unsafe { +- let view = msg_send![super(this, class!(NSVisualEffectView)), initWithFrame: frame]; +- // Use a colorless semantic material. The default value `AppearanceBased`, though not +- // manually set, is deprecated. +- NSVisualEffectView::setMaterial_(view, NSVisualEffectMaterial::Selection); +- NSVisualEffectView::setState_(view, NSVisualEffectState::Active); ++ let view: ObjcId = msg_send![super(this, class!(NSVisualEffectView)), initWithFrame: frame]; ++ // Use an active visual effect state via icrate constant ++ let _: () = msg_send![view, setState: NSVisualEffectStateActive]; + view + } + } +@@ -2496,35 +2573,37 @@ extern "C" fn blurred_view_init_with_frame(this: &Object, _: Sel, frame: NSRect) + extern "C" fn blurred_view_update_layer(this: &Object, _: Sel) { + unsafe { + let _: () = msg_send![super(this, class!(NSVisualEffectView)), updateLayer]; +- let layer: id = msg_send![this, layer]; ++ let layer: ObjcId = msg_send![this, layer]; + if !layer.is_null() { + remove_layer_background(layer); + } + } + } + +-unsafe fn remove_layer_background(layer: id) { ++unsafe fn remove_layer_background(layer: ObjcId) { + unsafe { +- let _: () = msg_send![layer, setBackgroundColor:nil]; ++ let _: () = msg_send![layer, setBackgroundColor:NIL]; + +- let class_name: id = msg_send![layer, className]; +- if class_name.isEqualToString("CAChameleonLayer") { ++ let class_name: ObjcId = msg_send![layer, className]; ++ let equal: BOOL = msg_send![class_name, isEqualToString: ns_string("CAChameleonLayer")]; ++ if equal == YES { + // Remove the desktop tinting effect. + let _: () = msg_send![layer, setHidden: YES]; + return; + } + +- let filters: id = msg_send![layer, filters]; ++ let filters: ObjcId = msg_send![layer, filters]; + if !filters.is_null() { + // Remove the increased saturation. + // The effect of a `CAFilter` or `CIFilter` is determined by its name, and the + // `description` reflects its name and some parameters. Currently `NSVisualEffectView` + // uses a `CAFilter` named "colorSaturate". If one day they switch to `CIFilter`, the + // `description` will still contain "Saturat" ("... inputSaturation = ..."). +- let test_string: id = NSString::alloc(nil).init_str("Saturat").autorelease(); +- let count = NSArray::count(filters); ++ let test_string: ObjcId = NSString::alloc(NIL).init_str("Saturat").autorelease(); ++ let count: NSUInteger = msg_send![filters, count]; + for i in 0..count { +- let description: id = msg_send![filters.objectAtIndex(i), description]; ++ let filter_i: ObjcId = msg_send![filters, objectAtIndex: i]; ++ let description: ObjcId = msg_send![filter_i, description]; + let hit: BOOL = msg_send![description, containsString: test_string]; + if hit == NO { + continue; +@@ -2532,34 +2611,38 @@ unsafe fn remove_layer_background(layer: id) { + + let all_indices = NSRange { + location: 0, +- length: count, ++ length: count as u64, + }; +- let indices: id = msg_send![class!(NSMutableIndexSet), indexSet]; ++ let indices: ObjcId = msg_send![class!(NSMutableIndexSet), indexSet]; + let _: () = msg_send![indices, addIndexesInRange: all_indices]; + let _: () = msg_send![indices, removeIndex:i]; +- let filtered: id = msg_send![filters, objectsAtIndexes: indices]; ++ let filtered: ObjcId = msg_send![filters, objectsAtIndexes: indices]; + let _: () = msg_send![layer, setFilters: filtered]; + break; + } + } + +- let sublayers: id = msg_send![layer, sublayers]; ++ let sublayers: ObjcId = msg_send![layer, sublayers]; + if !sublayers.is_null() { +- let count = NSArray::count(sublayers); ++ let count: NSUInteger = msg_send![sublayers, count]; + for i in 0..count { +- let sublayer = sublayers.objectAtIndex(i); ++ let sublayer: ObjcId = msg_send![sublayers, objectAtIndex: i]; + remove_layer_background(sublayer); + } + } + } + } + +-extern "C" fn add_titlebar_accessory_view_controller(this: &Object, _: Sel, view_controller: id) { ++extern "C" fn add_titlebar_accessory_view_controller( ++ this: &Object, ++ _: Sel, ++ view_controller: ObjcId, ++) { + unsafe { + let _: () = msg_send![super(this, class!(NSWindow)), addTitlebarAccessoryViewController: view_controller]; + + // Hide the native tab bar and set its height to 0, since we render our own. +- let accessory_view: id = msg_send![view_controller, view]; ++ let accessory_view: ObjcId = msg_send![view_controller, view]; + let _: () = msg_send![accessory_view, setHidden: YES]; + let mut frame: NSRect = msg_send![accessory_view, frame]; + frame.size.height = 0.0; +@@ -2567,9 +2650,9 @@ extern "C" fn add_titlebar_accessory_view_controller(this: &Object, _: Sel, view + } + } + +-extern "C" fn move_tab_to_new_window(this: &Object, _: Sel, _: id) { ++extern "C" fn move_tab_to_new_window(this: &Object, _: Sel, _: ObjcId) { + unsafe { +- let _: () = msg_send![super(this, class!(NSWindow)), moveTabToNewWindow:nil]; ++ let _: () = msg_send![super(this, class!(NSWindow)), moveTabToNewWindow:NIL]; + + let window_state = get_window_state(this); + let mut lock = window_state.as_ref().lock(); +@@ -2581,9 +2664,9 @@ extern "C" fn move_tab_to_new_window(this: &Object, _: Sel, _: id) { + } + } + +-extern "C" fn merge_all_windows(this: &Object, _: Sel, _: id) { ++extern "C" fn merge_all_windows(this: &Object, _: Sel, _: ObjcId) { + unsafe { +- let _: () = msg_send![super(this, class!(NSWindow)), mergeAllWindows:nil]; ++ let _: () = msg_send![super(this, class!(NSWindow)), mergeAllWindows:NIL]; + + let window_state = get_window_state(this); + let mut lock = window_state.as_ref().lock(); +@@ -2595,7 +2678,7 @@ extern "C" fn merge_all_windows(this: &Object, _: Sel, _: id) { + } + } + +-extern "C" fn select_next_tab(this: &Object, _sel: Sel, _id: id) { ++extern "C" fn select_next_tab(this: &Object, _sel: Sel, _id: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + let mut lock = window_state.as_ref().lock(); + if let Some(mut callback) = lock.select_next_tab_callback.take() { +@@ -2605,7 +2688,7 @@ extern "C" fn select_next_tab(this: &Object, _sel: Sel, _id: id) { + } + } + +-extern "C" fn select_previous_tab(this: &Object, _sel: Sel, _id: id) { ++extern "C" fn select_previous_tab(this: &Object, _sel: Sel, _id: ObjcId) { + let window_state = unsafe { get_window_state(this) }; + let mut lock = window_state.as_ref().lock(); + if let Some(mut callback) = lock.select_previous_tab_callback.take() { +@@ -2615,9 +2698,9 @@ extern "C" fn select_previous_tab(this: &Object, _sel: Sel, _id: id) { + } + } + +-extern "C" fn toggle_tab_bar(this: &Object, _sel: Sel, _id: id) { ++extern "C" fn toggle_tab_bar(this: &Object, _sel: Sel, _id: ObjcId) { + unsafe { +- let _: () = msg_send![super(this, class!(NSWindow)), toggleTabBar:nil]; ++ let _: () = msg_send![super(this, class!(NSWindow)), toggleTabBar:NIL]; + + let window_state = get_window_state(this); + let mut lock = window_state.as_ref().lock(); +diff --git a/crates/gpui/src/platform/mac/window_appearance.rs b/crates/gpui/src/platform/mac/window_appearance.rs +index 65c409d30c..0950e5ba55 100644 +--- a/crates/gpui/src/platform/mac/window_appearance.rs ++++ b/crates/gpui/src/platform/mac/window_appearance.rs +@@ -1,37 +1,24 @@ + use crate::WindowAppearance; +-use cocoa::{ +- appkit::{NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight}, +- base::id, +- foundation::NSString, ++use icrate::AppKit::{ ++ NSAppearanceNameAqua, NSAppearanceNameDarkAqua, NSAppearanceNameVibrantDark, ++ NSAppearanceNameVibrantLight, + }; ++use objc::runtime::Object; + use objc::{msg_send, sel, sel_impl}; +-use std::ffi::CStr; + + impl WindowAppearance { +- pub(crate) unsafe fn from_native(appearance: id) -> Self { +- let name: id = msg_send![appearance, name]; +- unsafe { +- if name == NSAppearanceNameVibrantLight { +- Self::VibrantLight +- } else if name == NSAppearanceNameVibrantDark { +- Self::VibrantDark +- } else if name == NSAppearanceNameAqua { +- Self::Light +- } else if name == NSAppearanceNameDarkAqua { +- Self::Dark +- } else { +- println!( +- "unknown appearance: {:?}", +- CStr::from_ptr(name.UTF8String()) +- ); +- Self::Light +- } ++ pub(crate) unsafe fn from_native(appearance: *mut Object) -> Self { ++ let name: *mut Object = unsafe { msg_send![appearance, name] }; ++ if unsafe { name == (NSAppearanceNameVibrantLight as *const _ as *mut Object) } { ++ Self::VibrantLight ++ } else if unsafe { name == (NSAppearanceNameVibrantDark as *const _ as *mut Object) } { ++ Self::VibrantDark ++ } else if unsafe { name == (NSAppearanceNameAqua as *const _ as *mut Object) } { ++ Self::Light ++ } else if unsafe { name == (NSAppearanceNameDarkAqua as *const _ as *mut Object) } { ++ Self::Dark ++ } else { ++ Self::Light + } + } + } +- +-#[link(name = "AppKit", kind = "framework")] +-unsafe extern "C" { +- pub static NSAppearanceNameAqua: id; +- pub static NSAppearanceNameDarkAqua: id; +-} +diff --git a/crates/macos_appkit_bridge/Cargo.toml b/crates/macos_appkit_bridge/Cargo.toml +new file mode 100644 +index 0000000000..9ac6e745a3 +--- /dev/null ++++ b/crates/macos_appkit_bridge/Cargo.toml +@@ -0,0 +1,13 @@ ++[package] ++name = "macos_appkit_bridge" ++version = "0.1.0" ++edition = "2021" ++ ++[lib] ++name = "macos_appkit_bridge" ++path = "src/lib.rs" ++crate-type = ["staticlib", "rlib"] ++ ++[dependencies] ++ ++[build-dependencies] +diff --git a/crates/macos_appkit_bridge/build.rs b/crates/macos_appkit_bridge/build.rs +new file mode 100644 +index 0000000000..f511440de3 +--- /dev/null ++++ b/crates/macos_appkit_bridge/build.rs +@@ -0,0 +1,32 @@ ++#[cfg(target_os = "macos")] ++fn main() { ++ // Build Swift package and link static library ++ let _out_dir = std::env::var("OUT_DIR").unwrap(); ++ let package_dir = std::env::current_dir().unwrap(); ++ ++ let swift_dir = package_dir.join("swift"); ++ std::fs::create_dir_all(&swift_dir).ok(); ++ ++ // No codegen needed for C ABI shim ++ ++ // Build the Swift package containing our shim and the generated bridge. ++ let status = std::process::Command::new("swift") ++ .current_dir(&swift_dir) ++ .args(["build", "-c", "release"]) ++ .status() ++ .expect("Failed to spawn swift build"); ++ if !status.success() { ++ panic!("swift build failed: {:?}", status); ++ } ++ ++ // Link the produced static library; default SwiftPM output directory ++ let lib_dir = std::path::Path::new(&swift_dir) ++ .join(".build") ++ .join("release"); ++ println!("cargo:rustc-link-search=native={}", lib_dir.display()); ++ println!("cargo:rustc-link-lib=static=SwiftPackage"); ++ println!("cargo:rustc-link-lib=framework=AppKit"); ++} ++ ++#[cfg(not(target_os = "macos"))] ++fn main() {} +diff --git a/crates/macos_appkit_bridge/src/lib.rs b/crates/macos_appkit_bridge/src/lib.rs +new file mode 100644 +index 0000000000..984e81d239 +--- /dev/null ++++ b/crates/macos_appkit_bridge/src/lib.rs +@@ -0,0 +1 @@ ++// This crate builds and links the Swift static library for macOS AppKit shims. +diff --git a/crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftBridgeCore.h b/crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftBridgeCore.h +new file mode 100644 +index 0000000000..14bfeeb310 +--- /dev/null ++++ b/crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftBridgeCore.h +@@ -0,0 +1,164 @@ ++#include ++#include ++typedef struct RustStr { uint8_t* const start; uintptr_t len; } RustStr; ++typedef struct __private__FfiSlice { void* const start; uintptr_t len; } __private__FfiSlice; ++void* __swift_bridge__null_pointer(void); ++ ++ ++typedef struct __private__OptionU8 { uint8_t val; bool is_some; } __private__OptionU8; ++typedef struct __private__OptionI8 { int8_t val; bool is_some; } __private__OptionI8; ++typedef struct __private__OptionU16 { uint16_t val; bool is_some; } __private__OptionU16; ++typedef struct __private__OptionI16 { int16_t val; bool is_some; } __private__OptionI16; ++typedef struct __private__OptionU32 { uint32_t val; bool is_some; } __private__OptionU32; ++typedef struct __private__OptionI32 { int32_t val; bool is_some; } __private__OptionI32; ++typedef struct __private__OptionU64 { uint64_t val; bool is_some; } __private__OptionU64; ++typedef struct __private__OptionI64 { int64_t val; bool is_some; } __private__OptionI64; ++typedef struct __private__OptionUsize { uintptr_t val; bool is_some; } __private__OptionUsize; ++typedef struct __private__OptionIsize { intptr_t val; bool is_some; } __private__OptionIsize; ++typedef struct __private__OptionF32 { float val; bool is_some; } __private__OptionF32; ++typedef struct __private__OptionF64 { double val; bool is_some; } __private__OptionF64; ++typedef struct __private__OptionBool { bool val; bool is_some; } __private__OptionBool; ++ ++void* __swift_bridge__$Vec_u8$new(); ++void __swift_bridge__$Vec_u8$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_u8$len(void* const vec); ++void __swift_bridge__$Vec_u8$push(void* const vec, uint8_t val); ++__private__OptionU8 __swift_bridge__$Vec_u8$pop(void* const vec); ++__private__OptionU8 __swift_bridge__$Vec_u8$get(void* const vec, uintptr_t index); ++__private__OptionU8 __swift_bridge__$Vec_u8$get_mut(void* const vec, uintptr_t index); ++uint8_t const * __swift_bridge__$Vec_u8$as_ptr(void* const vec); ++ ++void* __swift_bridge__$Vec_u16$new(); ++void __swift_bridge__$Vec_u16$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_u16$len(void* const vec); ++void __swift_bridge__$Vec_u16$push(void* const vec, uint16_t val); ++__private__OptionU16 __swift_bridge__$Vec_u16$pop(void* const vec); ++__private__OptionU16 __swift_bridge__$Vec_u16$get(void* const vec, uintptr_t index); ++__private__OptionU16 __swift_bridge__$Vec_u16$get_mut(void* const vec, uintptr_t index); ++uint16_t const * __swift_bridge__$Vec_u16$as_ptr(void* const vec); ++ ++void* __swift_bridge__$Vec_u32$new(); ++void __swift_bridge__$Vec_u32$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_u32$len(void* const vec); ++void __swift_bridge__$Vec_u32$push(void* const vec, uint32_t val); ++__private__OptionU32 __swift_bridge__$Vec_u32$pop(void* const vec); ++__private__OptionU32 __swift_bridge__$Vec_u32$get(void* const vec, uintptr_t index); ++__private__OptionU32 __swift_bridge__$Vec_u32$get_mut(void* const vec, uintptr_t index); ++uint32_t const * __swift_bridge__$Vec_u32$as_ptr(void* const vec); ++ ++void* __swift_bridge__$Vec_u64$new(); ++void __swift_bridge__$Vec_u64$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_u64$len(void* const vec); ++void __swift_bridge__$Vec_u64$push(void* const vec, uint64_t val); ++__private__OptionU64 __swift_bridge__$Vec_u64$pop(void* const vec); ++__private__OptionU64 __swift_bridge__$Vec_u64$get(void* const vec, uintptr_t index); ++__private__OptionU64 __swift_bridge__$Vec_u64$get_mut(void* const vec, uintptr_t index); ++uint64_t const * __swift_bridge__$Vec_u64$as_ptr(void* const vec); ++ ++void* __swift_bridge__$Vec_usize$new(); ++void __swift_bridge__$Vec_usize$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_usize$len(void* const vec); ++void __swift_bridge__$Vec_usize$push(void* const vec, uintptr_t val); ++__private__OptionUsize __swift_bridge__$Vec_usize$pop(void* const vec); ++__private__OptionUsize __swift_bridge__$Vec_usize$get(void* const vec, uintptr_t index); ++__private__OptionUsize __swift_bridge__$Vec_usize$get_mut(void* const vec, uintptr_t index); ++uintptr_t const * __swift_bridge__$Vec_usize$as_ptr(void* const vec); ++ ++void* __swift_bridge__$Vec_i8$new(); ++void __swift_bridge__$Vec_i8$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_i8$len(void* const vec); ++void __swift_bridge__$Vec_i8$push(void* const vec, int8_t val); ++__private__OptionI8 __swift_bridge__$Vec_i8$pop(void* const vec); ++__private__OptionI8 __swift_bridge__$Vec_i8$get(void* const vec, uintptr_t index); ++__private__OptionI8 __swift_bridge__$Vec_i8$get_mut(void* const vec, uintptr_t index); ++int8_t const * __swift_bridge__$Vec_i8$as_ptr(void* const vec); ++ ++void* __swift_bridge__$Vec_i16$new(); ++void __swift_bridge__$Vec_i16$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_i16$len(void* const vec); ++void __swift_bridge__$Vec_i16$push(void* const vec, int16_t val); ++__private__OptionI16 __swift_bridge__$Vec_i16$pop(void* const vec); ++__private__OptionI16 __swift_bridge__$Vec_i16$get(void* const vec, uintptr_t index); ++__private__OptionI16 __swift_bridge__$Vec_i16$get_mut(void* const vec, uintptr_t index); ++int16_t const * __swift_bridge__$Vec_i16$as_ptr(void* const vec); ++ ++void* __swift_bridge__$Vec_i32$new(); ++void __swift_bridge__$Vec_i32$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_i32$len(void* const vec); ++void __swift_bridge__$Vec_i32$push(void* const vec, int32_t val); ++__private__OptionI32 __swift_bridge__$Vec_i32$pop(void* const vec); ++__private__OptionI32 __swift_bridge__$Vec_i32$get(void* const vec, uintptr_t index); ++__private__OptionI32 __swift_bridge__$Vec_i32$get_mut(void* const vec, uintptr_t index); ++int32_t const * __swift_bridge__$Vec_i32$as_ptr(void* const vec); ++ ++void* __swift_bridge__$Vec_i64$new(); ++void __swift_bridge__$Vec_i64$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_i64$len(void* const vec); ++void __swift_bridge__$Vec_i64$push(void* const vec, int64_t val); ++__private__OptionI64 __swift_bridge__$Vec_i64$pop(void* const vec); ++__private__OptionI64 __swift_bridge__$Vec_i64$get(void* const vec, uintptr_t index); ++__private__OptionI64 __swift_bridge__$Vec_i64$get_mut(void* const vec, uintptr_t index); ++int64_t const * __swift_bridge__$Vec_i64$as_ptr(void* const vec); ++ ++void* __swift_bridge__$Vec_isize$new(); ++void __swift_bridge__$Vec_isize$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_isize$len(void* const vec); ++void __swift_bridge__$Vec_isize$push(void* const vec, intptr_t val); ++__private__OptionIsize __swift_bridge__$Vec_isize$pop(void* const vec); ++__private__OptionIsize __swift_bridge__$Vec_isize$get(void* const vec, uintptr_t index); ++__private__OptionIsize __swift_bridge__$Vec_isize$get_mut(void* const vec, uintptr_t index); ++intptr_t const * __swift_bridge__$Vec_isize$as_ptr(void* const vec); ++ ++void* __swift_bridge__$Vec_bool$new(); ++void __swift_bridge__$Vec_bool$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_bool$len(void* const vec); ++void __swift_bridge__$Vec_bool$push(void* const vec, bool val); ++__private__OptionBool __swift_bridge__$Vec_bool$pop(void* const vec); ++__private__OptionBool __swift_bridge__$Vec_bool$get(void* const vec, uintptr_t index); ++__private__OptionBool __swift_bridge__$Vec_bool$get_mut(void* const vec, uintptr_t index); ++bool const * __swift_bridge__$Vec_bool$as_ptr(void* const vec); ++ ++void* __swift_bridge__$Vec_f32$new(); ++void __swift_bridge__$Vec_f32$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_f32$len(void* const vec); ++void __swift_bridge__$Vec_f32$push(void* const vec, float val); ++__private__OptionF32 __swift_bridge__$Vec_f32$pop(void* const vec); ++__private__OptionF32 __swift_bridge__$Vec_f32$get(void* const vec, uintptr_t index); ++__private__OptionF32 __swift_bridge__$Vec_f32$get_mut(void* const vec, uintptr_t index); ++float const * __swift_bridge__$Vec_f32$as_ptr(void* const vec); ++ ++void* __swift_bridge__$Vec_f64$new(); ++void __swift_bridge__$Vec_f64$_free(void* const vec); ++uintptr_t __swift_bridge__$Vec_f64$len(void* const vec); ++void __swift_bridge__$Vec_f64$push(void* const vec, double val); ++__private__OptionF64 __swift_bridge__$Vec_f64$pop(void* const vec); ++__private__OptionF64 __swift_bridge__$Vec_f64$get(void* const vec, uintptr_t index); ++__private__OptionF64 __swift_bridge__$Vec_f64$get_mut(void* const vec, uintptr_t index); ++double const * __swift_bridge__$Vec_f64$as_ptr(void* const vec); ++ ++#include ++typedef struct RustString RustString; ++void __swift_bridge__$RustString$_free(void* self); ++ ++void* __swift_bridge__$Vec_RustString$new(void); ++void __swift_bridge__$Vec_RustString$drop(void* vec_ptr); ++void __swift_bridge__$Vec_RustString$push(void* vec_ptr, void* item_ptr); ++void* __swift_bridge__$Vec_RustString$pop(void* vec_ptr); ++void* __swift_bridge__$Vec_RustString$get(void* vec_ptr, uintptr_t index); ++void* __swift_bridge__$Vec_RustString$get_mut(void* vec_ptr, uintptr_t index); ++uintptr_t __swift_bridge__$Vec_RustString$len(void* vec_ptr); ++void* __swift_bridge__$Vec_RustString$as_ptr(void* vec_ptr); ++ ++void* __swift_bridge__$RustString$new(void); ++void* __swift_bridge__$RustString$new_with_str(struct RustStr str); ++uintptr_t __swift_bridge__$RustString$len(void* self); ++struct RustStr __swift_bridge__$RustString$as_str(void* self); ++struct RustStr __swift_bridge__$RustString$trim(void* self); ++bool __swift_bridge__$RustStr$partial_eq(struct RustStr lhs, struct RustStr rhs); ++ ++ ++void __swift_bridge__$call_boxed_fn_once_no_args_no_return(void* boxed_fnonce); ++void __swift_bridge__$free_boxed_fn_once_no_args_no_return(void* boxed_fnonce); ++ ++ ++struct __private__ResultPtrAndPtr { bool is_ok; void* ok_or_err; }; +diff --git a/crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftPackage.h b/crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftPackage.h +new file mode 100644 +index 0000000000..d4206662f5 +--- /dev/null ++++ b/crates/macos_appkit_bridge/swift/CSwiftBridge/SwiftPackage.h +@@ -0,0 +1,3 @@ ++// File automatically generated by swift-bridge. ++#include ++void __swift_bridge__$gpui_menu_action(uint64_t tag); +diff --git a/crates/macos_appkit_bridge/swift/Package.swift b/crates/macos_appkit_bridge/swift/Package.swift +new file mode 100644 +index 0000000000..7ae89e92ba +--- /dev/null ++++ b/crates/macos_appkit_bridge/swift/Package.swift +@@ -0,0 +1,13 @@ ++// swift-tools-version:5.9 ++import PackageDescription ++ ++let package = Package( ++ name: "SwiftPackage", ++ platforms: [ .macOS(.v12) ], ++ products: [ ++ .library(name: "SwiftPackage", type: .static, targets: ["SwiftPackage"]) // static lib ++ ], ++ targets: [ ++ .target(name: "SwiftPackage", path: "Sources") ++ ] ++) +diff --git a/crates/macos_appkit_bridge/swift/Sources/Shim.swift b/crates/macos_appkit_bridge/swift/Sources/Shim.swift +new file mode 100644 +index 0000000000..289ab889a4 +--- /dev/null ++++ b/crates/macos_appkit_bridge/swift/Sources/Shim.swift +@@ -0,0 +1,306 @@ ++import AppKit ++import Foundation ++@_silgen_name("gpui_menu_action") ++func gpui_menu_action(_ tag: UInt64) ++ ++fileprivate var menuActionHandlerRegistered = false ++ ++@_cdecl("zed_register_menu_handler") ++public func zed_register_menu_handler() { ++ // No-op: we call back to Rust via the global exported function. ++ menuActionHandlerRegistered = true ++} ++ ++@_cdecl("zed_set_main_menu_json") ++public func zed_set_main_menu_json(_ json: UnsafePointer) { ++ let str = String(cString: json) ++ struct Item: Codable { ++ let kind: String ++ let title: String? ++ let tag: UInt64? ++ let key_equivalent: String? ++ let modifiers: [String]? ++ let system_type: String? ++ let items: [Item]? ++ } ++ struct Menu: Codable { let title: String; let items: [Item] } ++ struct Spec: Codable { let menus: [Menu] } ++ guard let data = str.data(using: .utf8), let spec = try? JSONDecoder().decode(Spec.self, from: data) else { return } ++ ++ func buildMenu(_ items: [Item]) -> NSMenu { ++ let menu = NSMenu() ++ for it in items { ++ switch it.kind { ++ case "separator": ++ menu.addItem(NSMenuItem.separator()) ++ case "action": ++ let key = it.key_equivalent ?? "" ++ let mi = NSMenuItem(title: it.title ?? "", action: #selector(MenuTarget.onMenuAction(_:)), keyEquivalent: key) ++ mi.target = MenuTarget.shared ++ if let mods = it.modifiers { mi.keyEquivalentModifierMask = modifiers(from: mods) } ++ if let tag = it.tag { mi.tag = Int(tag) } ++ menu.addItem(mi) ++ case "submenu": ++ let mi = NSMenuItem(title: it.title ?? "", action: nil, keyEquivalent: "") ++ let sub = buildMenu(it.items ?? []) ++ mi.submenu = sub ++ menu.addItem(mi) ++ case "system": ++ let mi = NSMenuItem(title: it.title ?? "", action: nil, keyEquivalent: "") ++ let sub = buildMenu(it.items ?? []) ++ mi.submenu = sub ++ // Wire special menus ++ if let st = it.system_type { ++ if st == "services" { NSApp.servicesMenu = sub } ++ if st == "windows" { NSApp.windowsMenu = sub } ++ } ++ menu.addItem(mi) ++ default: ++ continue ++ } ++ } ++ return menu ++ } ++ ++ func modifiers(from names: [String]) -> NSEvent.ModifierFlags { ++ var flags: NSEvent.ModifierFlags = [] ++ for name in names { ++ switch name.lowercased() { ++ case "command": flags.insert(.command) ++ case "control": flags.insert(.control) ++ case "option": flags.insert(.option) ++ case "shift": flags.insert(.shift) ++ default: break ++ } ++ } ++ return flags ++ } ++ ++ let mainMenu = NSMenu() ++ for m in spec.menus { ++ let mi = NSMenuItem(title: m.title, action: nil, keyEquivalent: "") ++ let sub = buildMenu(m.items) ++ mi.submenu = sub ++ if m.title == "Window" { NSApp.windowsMenu = sub } ++ mainMenu.addItem(mi) ++ } ++ DispatchQueue.main.async { ++ mainMenu.delegate = MenuTarget.shared ++ NSApp.mainMenu = mainMenu ++ } ++} ++ ++@objc class MenuTarget: NSObject { ++ static let shared = MenuTarget() ++ @objc func onMenuAction(_ sender: NSMenuItem) { ++ guard menuActionHandlerRegistered else { return } ++ gpui_menu_action(UInt64(sender.tag)) ++ } ++} ++ ++@objc extension MenuTarget: NSMenuItemValidation { ++ func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { ++ return gpui_validate_menu_action(UInt64(menuItem.tag)) ++ } ++} ++ ++@objc extension MenuTarget: NSMenuDelegate { ++ func menuWillOpen(_ menu: NSMenu) { ++ gpui_menu_will_open() ++ } ++} ++ ++@_silgen_name("gpui_validate_menu_action") ++func gpui_validate_menu_action(_ tag: UInt64) -> Bool ++ ++@_silgen_name("gpui_menu_will_open") ++func gpui_menu_will_open() ++ ++// MARK: - Panels (Open/Save) C ABI ++ ++@_silgen_name("gpui_open_panel_result") ++func gpui_open_panel_result(_ requestId: UInt64, _ json: UnsafePointer) ++ ++@_silgen_name("gpui_save_panel_result") ++func gpui_save_panel_result(_ requestId: UInt64, _ json: UnsafePointer) ++ ++@_cdecl("zed_open_panel") ++public func zed_open_panel(_ requestId: UInt64, _ json: UnsafePointer) { ++ struct OpenOpts: Codable { let directories: Bool; let files: Bool; let multiple: Bool; let prompt: String? } ++ let str = String(cString: json) ++ guard let data = str.data(using: .utf8), let opts = try? JSONDecoder().decode(OpenOpts.self, from: data) else { return } ++ let panel = NSOpenPanel() ++ panel.canChooseDirectories = opts.directories ++ panel.canChooseFiles = opts.files ++ panel.allowsMultipleSelection = opts.multiple ++ panel.canCreateDirectories = true ++ panel.resolvesAliases = false ++ if let p = opts.prompt { panel.prompt = p } ++ DispatchQueue.main.async { ++ panel.begin { resp in ++ var result: [String]? = nil ++ if resp == .OK { ++ result = panel.urls.filter { $0.isFileURL }.map { $0.path } ++ } ++ let payload: [String: Any?] = ["paths": result] ++ if let jsonData = try? JSONSerialization.data(withJSONObject: payload, options: []), let jsonStr = String(data: jsonData, encoding: .utf8) { ++ jsonStr.withCString { gpui_open_panel_result(requestId, $0) } ++ } else { ++ "{\"paths\":null}".withCString { gpui_open_panel_result(requestId, $0) } ++ } ++ } ++ } ++} ++ ++@_cdecl("zed_save_panel") ++public func zed_save_panel(_ requestId: UInt64, _ json: UnsafePointer) { ++ struct SaveOpts: Codable { let directory: String; let suggested_name: String? } ++ let str = String(cString: json) ++ guard let data = str.data(using: .utf8), let opts = try? JSONDecoder().decode(SaveOpts.self, from: data) else { return } ++ let panel = NSSavePanel() ++ panel.directoryURL = URL(fileURLWithPath: opts.directory, isDirectory: true) ++ if let name = opts.suggested_name { panel.nameFieldStringValue = name } ++ DispatchQueue.main.async { ++ panel.begin { resp in ++ var path: String? = nil ++ if resp == .OK, let url = panel.url, url.isFileURL { path = url.path } ++ let payload: [String: Any?] = ["path": path] ++ if let jsonData = try? JSONSerialization.data(withJSONObject: payload, options: []), let jsonStr = String(data: jsonData, encoding: .utf8) { ++ jsonStr.withCString { gpui_save_panel_result(requestId, $0) } ++ } else { ++ "{\"path\":null}".withCString { gpui_save_panel_result(requestId, $0) } ++ } ++ } ++ } ++} ++ ++// MARK: - Pasteboard helpers (text) ++ ++@_cdecl("zed_pasteboard_write_text") ++public func zed_pasteboard_write_text(_ text: UnsafePointer) { ++ let str = String(cString: text) ++ NSPasteboard.general.clearContents() ++ NSPasteboard.general.setString(str, forType: NSPasteboard.PasteboardType.string) ++} ++ ++@_cdecl("zed_pasteboard_read_text") ++public func zed_pasteboard_read_text() -> UnsafeMutablePointer? { ++ if let s = NSPasteboard.general.string(forType: NSPasteboard.PasteboardType.string) { ++ return strdup(s) ++ } ++ return nil ++} ++ ++// MARK: - Pasteboard helpers (images via UTI) ++ ++@_cdecl("zed_pasteboard_write_image") ++public func zed_pasteboard_write_image(_ bytes: UnsafePointer, _ len: Int, _ uti: UnsafePointer) { ++ let data = Data(bytes: bytes, count: len) ++ let type = NSPasteboard.PasteboardType(String(cString: uti)) ++ let pb = NSPasteboard.general ++ pb.clearContents() ++ pb.setData(data, forType: type) ++} ++ ++// MARK: - Status Item (NSStatusItem) ++ ++@_silgen_name("gpui_status_item_clicked") ++func gpui_status_item_clicked(_ id: UInt64) ++@_silgen_name("gpui_status_item_menu_action") ++func gpui_status_item_menu_action(_ id: UInt64, _ tag: UInt64) ++ ++fileprivate class StatusItemTarget: NSObject { ++ let id: UInt64 ++ init(id: UInt64) { self.id = id } ++ @objc func onClick(_ sender: Any?) { gpui_status_item_clicked(id) } ++ @objc func onMenuAction(_ sender: NSMenuItem) { gpui_status_item_menu_action(id, UInt64(sender.tag)) } ++} ++ ++fileprivate var statusItems: [UInt64: NSStatusItem] = [:] ++fileprivate var statusTargets: [UInt64: StatusItemTarget] = [:] ++fileprivate var statusCounter: UInt64 = 1 ++ ++@_cdecl("zed_status_item_create") ++public func zed_status_item_create() -> UInt64 { ++ let id = statusCounter; statusCounter += 1 ++ let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) ++ let target = StatusItemTarget(id: id) ++ item.button?.target = target ++ item.button?.action = #selector(StatusItemTarget.onClick(_:)) ++ statusTargets[id] = target ++ statusItems[id] = item ++ return id ++} ++ ++@_cdecl("zed_status_item_set_title") ++public func zed_status_item_set_title(_ id: UInt64, _ title: UnsafePointer) { ++ if let item = statusItems[id] { ++ item.button?.title = String(cString: title) ++ } ++} ++ ++@_cdecl("zed_status_item_set_image") ++public func zed_status_item_set_image(_ id: UInt64, _ bytes: UnsafePointer, _ len: Int, _ uti: UnsafePointer, _ isTemplate: Bool) { ++ guard let item = statusItems[id] else { return } ++ let data = Data(bytes: bytes, count: len) ++ if let image = NSImage(data: data) { ++ image.isTemplate = isTemplate ++ item.button?.image = image ++ } ++} ++ ++@_cdecl("zed_status_item_remove") ++public func zed_status_item_remove(_ id: UInt64) { ++ if let item = statusItems[id] { NSStatusBar.system.removeStatusItem(item) } ++ statusItems.removeValue(forKey: id) ++ statusTargets.removeValue(forKey: id) ++} ++ ++@_cdecl("zed_status_item_set_menu") ++public func zed_status_item_set_menu(_ id: UInt64, _ json: UnsafePointer) { ++ guard let item = statusItems[id] else { return } ++ let str = String(cString: json) ++ struct Item: Codable { let kind: String; let title: String?; let tag: UInt64?; let items: [Item]? } ++ struct Spec: Codable { let items: [Item] } ++ guard let data = str.data(using: .utf8), let spec = try? JSONDecoder().decode(Spec.self, from: data) else { return } ++ func buildMenu(_ items: [Item], _ target: StatusItemTarget) -> NSMenu { ++ let menu = NSMenu() ++ for it in items { ++ switch it.kind { ++ case "separator": ++ menu.addItem(NSMenuItem.separator()) ++ case "action": ++ let mi = NSMenuItem(title: it.title ?? "", action: #selector(StatusItemTarget.onMenuAction(_:)), keyEquivalent: "") ++ mi.target = target ++ if let tag = it.tag { mi.tag = Int(tag) } ++ menu.addItem(mi) ++ case "submenu": ++ let mi = NSMenuItem(title: it.title ?? "", action: nil, keyEquivalent: "") ++ mi.submenu = buildMenu(it.items ?? [], target) ++ menu.addItem(mi) ++ default: ++ continue ++ } ++ } ++ return menu ++ } ++ let target = statusTargets[id] ?? StatusItemTarget(id: id) ++ statusTargets[id] = target ++ let menu = buildMenu(spec.items, target) ++ item.menu = menu ++} ++ ++@_cdecl("zed_pasteboard_read_image") ++public func zed_pasteboard_read_image(_ uti: UnsafePointer, _ out_len: UnsafeMutablePointer) -> UnsafeMutablePointer? { ++ let type = NSPasteboard.PasteboardType(String(cString: uti)) ++ let pb = NSPasteboard.general ++ if let data = pb.data(forType: type) { ++ out_len.pointee = data.count ++ let ptr = malloc(data.count)!.assumingMemoryBound(to: UInt8.self) ++ data.copyBytes(to: ptr, count: data.count) ++ return ptr ++ } else { ++ out_len.pointee = 0 ++ return nil ++ } ++} +diff --git a/crates/repl/Cargo.toml b/crates/repl/Cargo.toml +index 5821bc6297..344840c4b4 100644 +--- a/crates/repl/Cargo.toml ++++ b/crates/repl/Cargo.toml +@@ -17,6 +17,11 @@ alacritty_terminal.workspace = true + anyhow.workspace = true + async-dispatcher.workspace = true + async-tungstenite = { workspace = true, features = ["tokio", "tokio-rustls-manual-roots"] } ++# Force-enable `tokio` feature on async-tungstenite v0.31 used by ++# transitive dependency `jupyter-websocket-client` to avoid E0432 ++# (unresolved import `async_tungstenite::tokio`). The alias ensures ++# feature unification applies to that version across the graph. ++async_tungstenite_031 = { package = "async-tungstenite", version = "0.31.0", default-features = false, features = ["tokio-runtime"] } + base64.workspace = true + client.workspace = true + collections.workspace = true +diff --git a/crates/repl/src/kernels/remote_kernels.rs b/crates/repl/src/kernels/remote_kernels.rs +index 6bc8b0d1b1..0c353a5044 100644 +--- a/crates/repl/src/kernels/remote_kernels.rs ++++ b/crates/repl/src/kernels/remote_kernels.rs +@@ -3,8 +3,8 @@ use gpui::{App, AppContext as _, Entity, Task, Window}; + use http_client::{AsyncBody, HttpClient, Request}; + use jupyter_protocol::{ExecutionState, JupyterKernelspec, JupyterMessage, KernelInfoReply}; + +-use async_tungstenite::tokio::connect_async; +-use async_tungstenite::tungstenite::{client::IntoClientRequest, http::HeaderValue}; ++use async_tungstenite_031::tokio::connect_async; ++use async_tungstenite_031::tungstenite::{client::IntoClientRequest, http::HeaderValue}; + + use futures::StreamExt; + use smol::io::AsyncReadExt as _; +diff --git a/postgres_notes.txt b/postgres_notes.txt +new file mode 100644 +index 0000000000..d8d4eb0f72 +--- /dev/null ++++ b/postgres_notes.txt +@@ -0,0 +1,20 @@ ++This formula has created a default database cluster with: ++ initdb --locale=C -E UTF-8 /usr/local/var/postgresql@15 ++ ++postgresql@15 is keg-only, which means it was not symlinked into /usr/local, ++because this is an alternate version of another formula. ++ ++If you need to have postgresql@15 first in your PATH, run: ++ echo 'export PATH="/usr/local/opt/postgresql@15/bin:$PATH"' >> ~/.zshrc ++ ++For compilers to find postgresql@15 you may need to set: ++ export LDFLAGS="-L/usr/local/opt/postgresql@15/lib" ++ export CPPFLAGS="-I/usr/local/opt/postgresql@15/include" ++ ++For pkg-config to find postgresql@15 you may need to set: ++ export PKG_CONFIG_PATH="/usr/local/opt/postgresql@15/lib/pkgconfig" ++ ++To start postgresql@15 now and restart at login: ++ brew services start postgresql@15 ++Or, if you don't want/need a background service you can just run: ++ LC_ALL="C" /usr/local/opt/postgresql@15/bin/postgres -D /usr/local/var/postgresql@15 +diff --git a/zed_build_issues.md b/zed_build_issues.md +new file mode 100644 +index 0000000000..83c8d3dafa +--- /dev/null ++++ b/zed_build_issues.md +@@ -0,0 +1,7668 @@ ++# ++ ++warning: `fs` (lib) generated 14 warnings ++warning: `gpui` (lib) generated 1245 warnings ++error: could not compile `jupyter-websocket-client` (lib) due to 2 errors ++For more information about this error, try `rustc --explain E0432`. ++warning: `client` (lib) generated 8 warnings ++ ++# ++ ++# ++ ++error[E0432]: unresolved import `async_tungstenite::tokio` ++ --> /Users/takumi/.cargo/git/checkouts/runtimed-da41b1ee8fc7914c/7130c80/crates/jupyter-websocket-client/src/client.rs:3:5 ++ | ++3 | tokio::connect_async, ++ | ^^^^^ could not find `tokio` in `async_tungstenite` ++ | ++note: found an item that was configured out ++ --> /Users/takumi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/async-tungstenite-0.31.0/src/lib.rs:94:9 ++ | ++94 | pub mod tokio; ++ | ^^^^^ ++note: the item is gated behind the `tokio-runtime` feature ++ --> /Users/takumi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/async-tungstenite-0.31.0/src/lib.rs:93:7 ++ | ++93 | #[cfg(feature = "tokio-runtime")] ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++error[E0432]: unresolved import `async_tungstenite::tokio` ++ --> /Users/takumi/.cargo/git/checkouts/runtimed-da41b1ee8fc7914c/7130c80/crates/jupyter-websocket-client/src/websocket.rs:2:25 ++ | ++2 | use async_tungstenite::{tokio::ConnectStream, tungstenite::Message, WebSocketStream}; ++ | ^^^^^ could not find `tokio` in `async_tungstenite` ++ | ++note: found an item that was configured out ++ --> /Users/takumi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/async-tungstenite-0.31.0/src/lib.rs:94:9 ++ | ++94 | pub mod tokio; ++ | ^^^^^ ++note: the item is gated behind the `tokio-runtime` feature ++ --> /Users/takumi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/async-tungstenite-0.31.0/src/lib.rs:93:7 ++ | ++93 | #[cfg(feature = "tokio-runtime")] ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++# ++ ++# ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac.rs:38:12 ++ | ++38 | base::{id, nil}, ++ | ^^ ++ | ++ = note: `#[warn(deprecated)]` on by default ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac.rs:38:16 ++ | ++38 | base::{id, nil}, ++ | ^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSAutoreleasePool`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:39:18 ++ | ++39 | foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::foundation::NSNotFound`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:39:37 ++ | ++39 | foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:39:49 ++ | ++39 | foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:39:57 ++ | ++39 | foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, ++ | ^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:39:65 ++ | ++39 | foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, ++ | ^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:39:75 ++ | ++39 | foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger}, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac.rs:75:22 ++ | ++75 | impl NSStringExt for id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:91:19 ++ | ++91 | pub location: NSUInteger, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:92:17 ++ | ++92 | pub length: NSUInteger, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac.rs:138:38 ++ | ++138 | unsafe fn ns_string(string: &str) -> id { ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:139:24 ++ | ++139 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac.rs:139:30 ++ | ++139 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ | ^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:142:11 ++ | ++142 | impl From for Size { ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:151:11 ++ | ++151 | impl From for Size { ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:158:11 ++ | ++158 | impl From for Size { ++ | ^^^^^^ ++ ++warning: use of deprecated constant `cocoa::foundation::NSNotFound`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:98:23 ++ | ++98 | location: NSNotFound as NSUInteger, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:98:37 ++ | ++98 | location: NSNotFound as NSUInteger, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::foundation::NSNotFound`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:104:26 ++ | ++104 | self.location != NSNotFound as NSUInteger ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:104:40 ++ | ++104 | self.location != NSNotFound as NSUInteger ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:121:38 ++ | ++121 | location: range.start as NSUInteger, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:122:36 ++ | ++122 | length: range.len() as NSUInteger, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:131:13 ++ | ++131 | NSUInteger::encode().as_str(), ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:132:13 ++ | ++132 | NSUInteger::encode().as_str() ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:143:20 ++ | ++143 | fn from(value: NSSize) -> Self { ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:152:19 ++ | ++152 | fn from(rect: NSRect) -> Self { ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:153:13 ++ | ++153 | let NSSize { width, height } = rect.size; ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:159:19 ++ | ++159 | fn from(rect: NSRect) -> Self { ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:160:13 ++ | ++160 | let NSSize { width, height } = rect.size; ++ | ^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSScreen`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/display.rs:4:13 ++ | ++4 | appkit::NSScreen, ++ | ^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/display.rs:5:12 ++ | ++5 | base::{id, nil}, ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/display.rs:5:16 ++ | ++5 | base::{id, nil}, ++ | ^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSDictionary`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/display.rs:6:18 ++ | ++6 | foundation::{NSDictionary, NSString}, ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/display.rs:6:32 ++ | ++6 | foundation::{NSDictionary, NSString}, ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSScreen::screens`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/display.rs:35:37 ++ | ++35 | let screens = NSScreen::screens(nil); ++ | ^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/display.rs:35:45 ++ | ++35 | let screens = NSScreen::screens(nil); ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/display.rs:36:54 ++ | ++36 | let screen = cocoa::foundation::NSArray::objectAtIndex(screens, 0); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSScreen::deviceDescription`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/display.rs:37:48 ++ | ++37 | let device_description = NSScreen::deviceDescription(screen); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/display.rs:38:51 ++ | ++38 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/display.rs:38:57 ++ | ++38 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/display.rs:38:36 ++ | ++38 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); ++ | ^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSEvent`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:12:14 ++ | ++12 | appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType}, ++ | ^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:12:23 ++ | ++12 | appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType}, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventPhase`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:12:45 ++ | ++12 | appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType}, ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated enum `cocoa::appkit::NSEventType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:12:59 ++ | ++12 | appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType}, ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/events.rs:13:17 ++ | ++13 | base::{YES, id}, ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSUpArrowFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:34:17 ++ | ++34 | "up" => NSUpArrowFunctionKey, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSDownArrowFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:35:19 ++ | ++35 | "down" => NSDownArrowFunctionKey, ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSLeftArrowFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:36:19 ++ | ++36 | "left" => NSLeftArrowFunctionKey, ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSRightArrowFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:37:20 ++ | ++37 | "right" => NSRightArrowFunctionKey, ++ | ^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSPageUpFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:38:21 ++ | ++38 | "pageup" => NSPageUpFunctionKey, ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSPageDownFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:39:23 ++ | ++39 | "pagedown" => NSPageDownFunctionKey, ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSHomeFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:40:19 ++ | ++40 | "home" => NSHomeFunctionKey, ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSEndFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:41:18 ++ | ++41 | "end" => NSEndFunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSDeleteFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:42:21 ++ | ++42 | "delete" => NSDeleteFunctionKey, ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSHelpFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:43:21 ++ | ++43 | "insert" => NSHelpFunctionKey, ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF1FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:44:17 ++ | ++44 | "f1" => NSF1FunctionKey, ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF2FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:45:17 ++ | ++45 | "f2" => NSF2FunctionKey, ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF3FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:46:17 ++ | ++46 | "f3" => NSF3FunctionKey, ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF4FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:47:17 ++ | ++47 | "f4" => NSF4FunctionKey, ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF5FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:48:17 ++ | ++48 | "f5" => NSF5FunctionKey, ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF6FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:49:17 ++ | ++49 | "f6" => NSF6FunctionKey, ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF7FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:50:17 ++ | ++50 | "f7" => NSF7FunctionKey, ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF8FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:51:17 ++ | ++51 | "f8" => NSF8FunctionKey, ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF9FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:52:17 ++ | ++52 | "f9" => NSF9FunctionKey, ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF10FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:53:18 ++ | ++53 | "f10" => NSF10FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF11FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:54:18 ++ | ++54 | "f11" => NSF11FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF12FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:55:18 ++ | ++55 | "f12" => NSF12FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF13FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:56:18 ++ | ++56 | "f13" => NSF13FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF14FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:57:18 ++ | ++57 | "f14" => NSF14FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF15FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:58:18 ++ | ++58 | "f15" => NSF15FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF16FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:59:18 ++ | ++59 | "f16" => NSF16FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF17FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:60:18 ++ | ++60 | "f17" => NSF17FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF18FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:61:18 ++ | ++61 | "f18" => NSF18FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF19FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:62:18 ++ | ++62 | "f19" => NSF19FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF20FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:63:18 ++ | ++63 | "f20" => NSF20FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF21FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:64:18 ++ | ++64 | "f21" => NSF21FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF22FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:65:18 ++ | ++65 | "f22" => NSF22FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF23FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:66:18 ++ | ++66 | "f23" => NSF23FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF24FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:67:18 ++ | ++67 | "f24" => NSF24FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF25FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:68:18 ++ | ++68 | "f25" => NSF25FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF26FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:69:18 ++ | ++69 | "f26" => NSF26FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF27FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:70:18 ++ | ++70 | "f27" => NSF27FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF28FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:71:18 ++ | ++71 | "f28" => NSF28FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF29FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:72:18 ++ | ++72 | "f29" => NSF29FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF30FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:73:18 ++ | ++73 | "f30" => NSF30FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF31FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:74:18 ++ | ++74 | "f31" => NSF31FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF32FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:75:18 ++ | ++75 | "f32" => NSF32FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF33FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:76:18 ++ | ++76 | "f33" => NSF33FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF34FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:77:18 ++ | ++77 | "f34" => NSF34FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF35FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:78:18 ++ | ++78 | "f35" => NSF35FunctionKey, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated module `cocoa::appkit`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:29:16 ++ | ++29 | use cocoa::appkit::*; ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/events.rs:84:40 ++ | ++84 | unsafe fn read_modifiers(native_event: id) -> Modifiers { ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:87:42 ++ | ++87 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:88:38 ++ | ++88 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:89:40 ++ | ++89 | let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:90:42 ++ | ++90 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:91:43 ++ | ++91 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/events.rs:297:41 ++ | ++297 | unsafe fn parse_keystroke(native_event: id) -> Keystroke { ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:309:42 ++ | ++309 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:310:38 ++ | ++310 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:311:44 ++ | ++311 | let mut shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:312:42 ++ | ++312 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:313:43 ++ | ++313 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask) ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSUpArrowFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:315:36 ++ | ++315 | .is_none_or(|ch| !(NSUpArrowFunctionKey..=NSModeSwitchFunctionKey).contains(&ch)); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSModeSwitchFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:315:59 ++ | ++315 | .is_none_or(|ch| !(NSUpArrowFunctionKey..=NSModeSwitchFunctionKey).contains(&ch)); ++ | ^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSUpArrowFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:334:18 ++ | ++334 | Some(NSUpArrowFunctionKey) => "up".to_string(), ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSDownArrowFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:335:18 ++ | ++335 | Some(NSDownArrowFunctionKey) => "down".to_string(), ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSLeftArrowFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:336:18 ++ | ++336 | Some(NSLeftArrowFunctionKey) => "left".to_string(), ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSRightArrowFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:337:18 ++ | ++337 | Some(NSRightArrowFunctionKey) => "right".to_string(), ++ | ^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSPageUpFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:338:18 ++ | ++338 | Some(NSPageUpFunctionKey) => "pageup".to_string(), ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSPageDownFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:339:18 ++ | ++339 | Some(NSPageDownFunctionKey) => "pagedown".to_string(), ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSHomeFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:340:18 ++ | ++340 | Some(NSHomeFunctionKey) => "home".to_string(), ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSEndFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:341:18 ++ | ++341 | Some(NSEndFunctionKey) => "end".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSDeleteFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:342:18 ++ | ++342 | Some(NSDeleteFunctionKey) => "delete".to_string(), ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSHelpFunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:344:18 ++ | ++344 | Some(NSHelpFunctionKey) => "insert".to_string(), ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF1FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:345:18 ++ | ++345 | Some(NSF1FunctionKey) => "f1".to_string(), ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF2FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:346:18 ++ | ++346 | Some(NSF2FunctionKey) => "f2".to_string(), ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF3FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:347:18 ++ | ++347 | Some(NSF3FunctionKey) => "f3".to_string(), ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF4FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:348:18 ++ | ++348 | Some(NSF4FunctionKey) => "f4".to_string(), ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF5FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:349:18 ++ | ++349 | Some(NSF5FunctionKey) => "f5".to_string(), ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF6FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:350:18 ++ | ++350 | Some(NSF6FunctionKey) => "f6".to_string(), ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF7FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:351:18 ++ | ++351 | Some(NSF7FunctionKey) => "f7".to_string(), ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF8FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:352:18 ++ | ++352 | Some(NSF8FunctionKey) => "f8".to_string(), ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF9FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:353:18 ++ | ++353 | Some(NSF9FunctionKey) => "f9".to_string(), ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF10FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:354:18 ++ | ++354 | Some(NSF10FunctionKey) => "f10".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF11FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:355:18 ++ | ++355 | Some(NSF11FunctionKey) => "f11".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF12FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:356:18 ++ | ++356 | Some(NSF12FunctionKey) => "f12".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF13FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:357:18 ++ | ++357 | Some(NSF13FunctionKey) => "f13".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF14FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:358:18 ++ | ++358 | Some(NSF14FunctionKey) => "f14".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF15FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:359:18 ++ | ++359 | Some(NSF15FunctionKey) => "f15".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF16FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:360:18 ++ | ++360 | Some(NSF16FunctionKey) => "f16".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF17FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:361:18 ++ | ++361 | Some(NSF17FunctionKey) => "f17".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF18FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:362:18 ++ | ++362 | Some(NSF18FunctionKey) => "f18".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF19FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:363:18 ++ | ++363 | Some(NSF19FunctionKey) => "f19".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF20FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:364:18 ++ | ++364 | Some(NSF20FunctionKey) => "f20".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF21FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:365:18 ++ | ++365 | Some(NSF21FunctionKey) => "f21".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF22FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:366:18 ++ | ++366 | Some(NSF22FunctionKey) => "f22".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF23FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:367:18 ++ | ++367 | Some(NSF23FunctionKey) => "f23".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF24FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:368:18 ++ | ++368 | Some(NSF24FunctionKey) => "f24".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF25FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:369:18 ++ | ++369 | Some(NSF25FunctionKey) => "f25".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF26FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:370:18 ++ | ++370 | Some(NSF26FunctionKey) => "f26".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF27FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:371:18 ++ | ++371 | Some(NSF27FunctionKey) => "f27".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF28FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:372:18 ++ | ++372 | Some(NSF28FunctionKey) => "f28".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF29FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:373:18 ++ | ++373 | Some(NSF29FunctionKey) => "f29".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF30FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:374:18 ++ | ++374 | Some(NSF30FunctionKey) => "f30".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF31FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:375:18 ++ | ++375 | Some(NSF31FunctionKey) => "f31".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF32FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:376:18 ++ | ++376 | Some(NSF32FunctionKey) => "f32".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF33FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:377:18 ++ | ++377 | Some(NSF33FunctionKey) => "f33".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF34FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:378:18 ++ | ++378 | Some(NSF34FunctionKey) => "f34".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSF35FunctionKey`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:379:18 ++ | ++379 | Some(NSF35FunctionKey) => "f35".to_string(), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated module `cocoa::appkit`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:299:20 ++ | ++299 | use cocoa::appkit::*; ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/events.rs:105:23 ++ | ++105 | native_event: id, ++ | ^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSFlagsChanged`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:121:30 ++ | ++121 | NSEventType::NSFlagsChanged => { ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:127:43 ++ | ++127 | ... .contains(NSEventModifierFlags::NSAlphaShiftKeyMask), ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSKeyDown`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:131:30 ++ | ++131 | NSEventType::NSKeyDown => Some(Self::KeyDown(KeyDownEvent { ++ | ^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSKeyUp`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:135:30 ++ | ++135 | NSEventType::NSKeyUp => Some(Self::KeyUp(KeyUpEvent { ++ | ^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSLeftMouseDown`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:138:30 ++ | ++138 | NSEventType::NSLeftMouseDown ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSRightMouseDown`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:139:32 ++ | ++139 | | NSEventType::NSRightMouseDown ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSOtherMouseDown`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:140:32 ++ | ++140 | | NSEventType::NSOtherMouseDown => { ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSLeftMouseUp`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:164:30 ++ | ++164 | NSEventType::NSLeftMouseUp ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSRightMouseUp`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:165:32 ++ | ++165 | | NSEventType::NSRightMouseUp ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSOtherMouseUp`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:166:32 ++ | ++166 | | NSEventType::NSOtherMouseUp => { ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSEventTypeSwipe`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:190:30 ++ | ++190 | NSEventType::NSEventTypeSwipe => { ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventPhase`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:192:25 ++ | ++192 | NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() { ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSScrollWheel`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:216:30 ++ | ++216 | NSEventType::NSScrollWheel => window_height.map(|window_height| { ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventPhase`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:218:25 ++ | ++218 | NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventPhase`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:218:62 ++ | ++218 | NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventPhase`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:221:25 ++ | ++221 | NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSLeftMouseDragged`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:246:30 ++ | ++246 | NSEventType::NSLeftMouseDragged ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSRightMouseDragged`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:247:32 ++ | ++247 | | NSEventType::NSRightMouseDragged ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSOtherMouseDragged`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:248:32 ++ | ++248 | | NSEventType::NSOtherMouseDragged => { ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSMouseMoved`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:270:30 ++ | ++270 | NSEventType::NSMouseMoved => window_height.map(|window_height| { ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSMouseExited`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:280:30 ++ | ++280 | NSEventType::NSMouseExited => window_height.map(|window_height| { ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:9:17 ++ | ++9 | base::{YES, id, nil}, ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:9:21 ++ | ++9 | base::{YES, id, nil}, ++ | ^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSArray`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:10:18 ++ | ++10 | foundation::{NSArray, NSString}, ++ | ^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:10:27 ++ | ++10 | foundation::{NSArray, NSString}, ++ | ^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:35:17 ++ | ++35 | sc_display: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:40:16 ++ | ++40 | sc_stream: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:41:23 ++ | ++41 | sc_stream_output: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:195:18 ++ | ++195 | let screens: id = msg_send![class!(NSScreen), screens]; ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:198:48 ++ | ++198 | let screen_number_key = unsafe { NSString::alloc(nil).init_str("NSScreenNumber") }; ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:198:54 ++ | ++198 | let screen_number_key = unsafe { NSString::alloc(nil).init_str("NSScreenNumber") }; ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:200:21 ++ | ++200 | let screen: id = msg_send![screens, objectAtIndex: i]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:201:26 ++ | ++201 | let device_desc: id = msg_send![screen, deviceDescription]; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:202:27 ++ | ++202 | if device_desc == nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:206:23 ++ | ++206 | let nsnumber: id = msg_send![device_desc, objectForKey: screen_number_key]; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:207:24 ++ | ++207 | if nsnumber == nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:213:19 ++ | ++213 | let name: id = msg_send![screen, localizedName]; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:214:20 ++ | ++214 | if name != nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:238:65 ++ | ++238 | let block = ConcreteBlock::new(move |shareable_content: id, error: id| { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:238:76 ++ | ++238 | let block = ConcreteBlock::new(move |shareable_content: id, error: id| { ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:243:38 ++ | ++243 | let result = if error == nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:244:31 ++ | ++244 | let displays: id = msg_send![shareable_content, displays]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:258:26 ++ | ++258 | let msg: id = msg_send![error, localizedDescription]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:283:85 ++ | ++283 | output_video_effect_did_start_for_stream as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:287:84 ++ | ++287 | output_video_effect_did_stop_for_stream as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:291:71 ++ | ++291 | stream_did_stop_with_error as extern "C" fn(&Object, Sel, id, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:291:75 ++ | ++291 | stream_did_stop_with_error as extern "C" fn(&Object, Sel, id, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:299:48 ++ | ++299 | as extern "C" fn(&Object, Sel, id, id, NSInteger), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:299:52 ++ | ++299 | as extern "C" fn(&Object, Sel, id, id, NSInteger), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:307:89 ++ | ++307 | extern "C" fn output_video_effect_did_start_for_stream(_this: &Object, _: Sel, _stream: id) {} ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:309:88 ++ | ++309 | extern "C" fn output_video_effect_did_stop_for_stream(_this: &Object, _: Sel, _stream: id) {} ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:311:75 ++ | ++311 | extern "C" fn stream_did_stop_with_error(_this: &Object, _: Sel, _stream: id, _error: id) {} ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:311:87 ++ | ++311 | extern "C" fn stream_did_stop_with_error(_this: &Object, _: Sel, _stream: id, _error: id) {} ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:316:14 ++ | ++316 | _stream: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:317:20 ++ | ++317 | sample_buffer: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:86:25 ++ | ++86 | let stream: id = msg_send![class!(SCStream), alloc]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:87:25 ++ | ++87 | let filter: id = msg_send![class!(SCContentFilter), alloc]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:88:32 ++ | ++88 | let configuration: id = msg_send![class!(SCStreamConfiguration), alloc]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:89:27 ++ | ++89 | let delegate: id = msg_send![DELEGATE_CLASS, alloc]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:90:25 ++ | ++90 | let output: id = msg_send![OUTPUT_CLASS, alloc]; ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSArray::array`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:92:45 ++ | ++92 | let excluded_windows = NSArray::array(nil); ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:92:51 ++ | ++92 | let excluded_windows = NSArray::array(nil); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:93:25 ++ | ++93 | let filter: id = msg_send![filter, initWithDisplay:self.sc_display excludingWindows:excluded_windows]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:94:32 ++ | ++94 | let configuration: id = msg_send![configuration, init]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:95:20 ++ | ++95 | let _: id = msg_send![configuration, setScalesToFit: true]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:96:20 ++ | ++96 | let _: id = msg_send![configuration, setPixelFormat: 0x42475241]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:99:27 ++ | ++99 | let delegate: id = msg_send![delegate, init]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:100:25 ++ | ++100 | let output: id = msg_send![output, init]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:108:20 ++ | ++108 | let _: id = msg_send![configuration, setWidth: meta.resolution.width.0 as i64]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:109:20 ++ | ++109 | let _: id = msg_send![configuration, setHeight: meta.resolution.height.0 as i64]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:110:25 ++ | ++110 | let stream: id = msg_send![stream, initWithFilter:filter configuration:configuration delegate:delegate]; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:114:33 ++ | ++114 | let mut error: id = nil; ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:114:28 ++ | ++114 | let mut error: id = nil; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:115:142 ++ | ++115 | ...utputTypeScreen sampleHandlerQueue:0 error:&mut error as *mut id]; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:116:25 ++ | ++116 | if error != nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:117:30 ++ | ++117 | let message: id = msg_send![error, localizedDescription]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:125:30 ++ | ++125 | move |error: id| { ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:126:46 ++ | ++126 | let result = if error == nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:134:38 ++ | ++134 | let message: id = msg_send![error, localizedDescription]; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:166:33 ++ | ++166 | let mut error: id = nil; ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:166:28 ++ | ++166 | let mut error: id = nil; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:168:25 ++ | ++168 | if error != nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:169:30 ++ | ++169 | let message: id = msg_send![error, localizedDescription]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:173:59 ++ | ++173 | let handler = ConcreteBlock::new(move |error: id| { ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:174:29 ++ | ++174 | if error != nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:175:34 ++ | ++175 | let message: id = msg_send![error, localizedDescription]; ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:11:18 ++ | ++11 | foundation::{NSSize, NSUInteger}, ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:11:26 ++ | ++11 | foundation::{NSSize, NSUInteger}, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::quartzcore::AutoresizingMask`: use the objc2-quartz-core crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:12:17 ++ | ++12 | quartzcore::AutoresizingMask, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::quartzcore::AutoresizingMask`: use the objc2-quartz-core crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:152:38 ++ | ++152 | setAutoresizingMask: AutoresizingMask::WIDTH_SIZABLE ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::quartzcore::AutoresizingMask`: use the objc2-quartz-core crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:153:23 ++ | ++153 | | AutoresizingMask::HEIGHT_SIZABLE ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:299:20 ++ | ++299 | let size = NSSize { ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:545:40 ++ | ++545 | length: instance_offset as NSUInteger, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:1:18 ++ | ++1 | use cocoa::base::id; ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:2:24 ++ | ++2 | use cocoa::foundation::NSRange; ++ | ^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:21:29 ++ | ++21 | impl NSAttributedString for id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:49:36 ++ | ++49 | impl NSMutableAttributedString for id {} ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:10:33 ++ | ++10 | unsafe fn alloc(_: Self) -> id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:14:52 ++ | ++14 | unsafe fn init_attributed_string(self, string: id) -> id; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:14:59 ++ | ++14 | unsafe fn init_attributed_string(self, string: id) -> id; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:15:58 ++ | ++15 | unsafe fn appendAttributedString_(self, attr_string: id); ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:16:62 ++ | ++16 | unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; ++ | ^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:16:78 ++ | ++16 | unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:16:85 ++ | ++16 | unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:17:61 ++ | ++17 | unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; ++ | ^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:17:77 ++ | ++17 | unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:17:84 ++ | ++17 | unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:18:31 ++ | ++18 | unsafe fn string(self) -> id; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:44:33 ++ | ++44 | unsafe fn alloc(_: Self) -> id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:22:52 ++ | ++22 | unsafe fn init_attributed_string(self, string: id) -> id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:22:59 ++ | ++22 | unsafe fn init_attributed_string(self, string: id) -> id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:26:58 ++ | ++26 | unsafe fn appendAttributedString_(self, attr_string: id) { ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:30:62 ++ | ++30 | unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { ++ | ^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:30:78 ++ | ++30 | unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:30:85 ++ | ++30 | unsafe fn RTFDFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:34:61 ++ | ++34 | unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { ++ | ^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:34:77 ++ | ++34 | unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:34:84 ++ | ++34 | unsafe fn RTFFromRange_documentAttributes_(self, range: NSRange, attrs: id) -> id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/attributed_string.rs:38:31 ++ | ++38 | unsafe fn string(self) -> id { ++ | ^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:19:9 ++ | ++19 | NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated variant `cocoa::appkit::NSApplicationActivationPolicyRegular`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:19:55 ++ | ++19 | NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSApplicationActivationPolicyRegular`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:19:55 ++ | ++19 | NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:20:9 ++ | ++20 | NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSMenu`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:20:31 ++ | ++20 | NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, ++ | ^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSMenuItem`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:20:39 ++ | ++20 | NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated enum `cocoa::appkit::NSModalResponse`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:20:51 ++ | ++20 | NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSOpenPanel`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:20:68 ++ | ++20 | NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSPasteboard`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:20:81 ++ | ++20 | NSEventModifierFlags, NSMenu, NSMenuItem, NSModalResponse, NSOpenPanel, NSPasteboard, ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSPasteboardTypePNG`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:21:9 ++ | ++21 | NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeRTFD, NSPasteboardTypeString, ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeRTF`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:21:30 ++ | ++21 | NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeRTFD, NSPasteboardTypeString, ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeRTFD`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:21:51 ++ | ++21 | NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeRTFD, NSPasteboardTypeString, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeString`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:21:73 ++ | ++21 | NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeRTFD, NSPasteboardTypeString, ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeTIFF`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:22:9 ++ | ++22 | NSPasteboardTypeTIFF, NSSavePanel, NSWindow, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSSavePanel`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:22:31 ++ | ++22 | NSPasteboardTypeTIFF, NSSavePanel, NSWindow, ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:22:44 ++ | ++22 | NSPasteboardTypeTIFF, NSSavePanel, NSWindow, ++ | ^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:24:27 ++ | ++24 | base::{BOOL, NO, YES, id, nil, selector}, ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:24:31 ++ | ++24 | base::{BOOL, NO, YES, id, nil, selector}, ++ | ^^^ ++ ++warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:24:36 ++ | ++24 | base::{BOOL, NO, YES, id, nil, selector}, ++ | ^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSArray`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:26:9 ++ | ++26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, ++ | ^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSAutoreleasePool`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:26:18 ++ | ++26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSBundle`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:26:37 ++ | ++26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, ++ | ^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSData`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:26:47 ++ | ++26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:26:55 ++ | ++26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, ++ | ^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSProcessInfo`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:26:66 ++ | ++26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:26:81 ++ | ++26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, ++ | ^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:26:90 ++ | ++26 | NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSRange, NSString, ++ | ^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:27:9 ++ | ++27 | NSUInteger, NSURL, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSURL`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:27:21 ++ | ++27 | NSUInteger, NSURL, ++ | ^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:66:29 ++ | ++66 | const NSUTF8StringEncoding: NSUInteger = 4; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:87:73 ++ | ++87 | did_finish_launching as extern "C" fn(&mut Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:91:73 ++ | ++91 | should_handle_reopen as extern "C" fn(&mut Object, Sel, id, bool), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:95:67 ++ | ++95 | will_terminate as extern "C" fn(&mut Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:99:69 ++ | ++99 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:104:69 ++ | ++104 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:108:69 ++ | ++108 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:112:69 ++ | ++112 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:116:69 ++ | ++116 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:120:69 ++ | ++120 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:124:69 ++ | ++124 | handle_menu_item as extern "C" fn(&mut Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:128:71 ++ | ++128 | validate_menu_item as extern "C" fn(&mut Object, Sel, id) -> bool, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:132:67 ++ | ++132 | menu_will_open as extern "C" fn(&mut Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:136:69 ++ | ++136 | handle_dock_menu as extern "C" fn(&mut Object, Sel, id) -> id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:136:76 ++ | ++136 | handle_dock_menu as extern "C" fn(&mut Object, Sel, id) -> id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:140:62 ++ | ++140 | open_urls as extern "C" fn(&mut Object, Sel, id, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:140:66 ++ | ++140 | open_urls as extern "C" fn(&mut Object, Sel, id, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:145:78 ++ | ++145 | on_keyboard_layout_change as extern "C" fn(&mut Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:161:17 ++ | ++161 | pasteboard: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:162:32 ++ | ++162 | text_hash_pasteboard_type: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:163:31 ++ | ++163 | metadata_pasteboard_type: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:173:23 ++ | ++173 | dock_menu: Option, ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:515:42 ++ | ++515 | let app = NSApplication::sharedApplication(nil); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:515:60 ++ | ++515 | let app = NSApplication::sharedApplication(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:516:55 ++ | ++516 | let _: () = msg_send![app, terminate: nil]; ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1008:39 ++ | ++1008 | const NSScrollerStyleOverlay: NSInteger = 1; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1318:36 ++ | ++1318 | fn try_clipboard_image(pasteboard: id, format: ImageFormat) -> Option { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1322:20 ++ | ++1322 | let types: id = pasteboard.types(); ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1325:24 ++ | ++1325 | if data == nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1344:32 ++ | ++1344 | unsafe fn path_from_objc(path: id) -> PathBuf { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1359:66 ++ | ++1359 | extern "C" fn did_finish_launching(this: &mut Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1361:18 ++ | ++1361 | let app: id = msg_send![APP_CLASS, sharedApplication]; ++ | ^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSApplicationActivationPolicyRegular`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1362:34 ++ | ++1362 | app.setActivationPolicy_(NSApplicationActivationPolicyRegular); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1367:73 ++ | ++1367 | let _: () = msg_send![notification_center, addObserver: this as id ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1370:21 ++ | ++1370 | object: nil ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1381:66 ++ | ++1381 | extern "C" fn should_handle_reopen(this: &mut Object, _: Sel, _: id, has_open_windows: bool) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1393:60 ++ | ++1393 | extern "C" fn will_terminate(this: &mut Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1403:71 ++ | ++1403 | extern "C" fn on_keyboard_layout_change(this: &mut Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1419:55 ++ | ++1419 | extern "C" fn open_urls(this: &mut Object, _: Sel, _: id, urls: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1419:65 ++ | ++1419 | extern "C" fn open_urls(this: &mut Object, _: Sel, _: id, urls: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1443:65 ++ | ++1443 | extern "C" fn handle_menu_item(this: &mut Object, _: Sel, item: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1448:22 ++ | ++1448 | let tag: NSInteger = msg_send![item, tag]; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1460:67 ++ | ++1460 | extern "C" fn validate_menu_item(this: &mut Object, _: Sel, item: id) -> bool { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1466:22 ++ | ++1466 | let tag: NSInteger = msg_send![item, tag]; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1483:60 ++ | ++1483 | extern "C" fn menu_will_open(this: &mut Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1495:62 ++ | ++1495 | extern "C" fn handle_dock_menu(this: &mut Object, _: Sel, _: id) -> id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1495:69 ++ | ++1495 | extern "C" fn handle_dock_menu(this: &mut Object, _: Sel, _: id) -> id { ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1502:13 ++ | ++1502 | nil ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1507:38 ++ | ++1507 | unsafe fn ns_string(string: &str) -> id { ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1508:24 ++ | ++1508 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1508:30 ++ | ++1508 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1511:31 ++ | ++1511 | unsafe fn ns_url_to_path(url: id) -> Result { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1587:15 ++ | ++1587 | struct UTType(id); ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSPasteboard::generalPasteboard`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:203:48 ++ | ++203 | pasteboard: unsafe { NSPasteboard::generalPasteboard(nil) }, ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:203:66 ++ | ++203 | pasteboard: unsafe { NSPasteboard::generalPasteboard(nil) }, ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:221:74 ++ | ++221 | unsafe fn read_from_pasteboard(&self, pasteboard: *mut Object, kind: id) -> Option<&[u8]> { ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:224:24 ++ | ++224 | if data == nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:238:19 ++ | ++238 | delegate: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:241:10 ++ | ++241 | ) -> id { ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSMenu::new`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:243:44 ++ | ++243 | let application_menu = NSMenu::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:243:48 ++ | ++243 | let application_menu = NSMenu::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSMenu::new`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:247:36 ++ | ++247 | let menu = NSMenu::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:247:40 ++ | ++247 | let menu = NSMenu::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::new`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:261:45 ++ | ++261 | let menu_item = NSMenuItem::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:261:49 ++ | ++261 | let menu_item = NSMenuItem::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:267:30 ++ | ++267 | let app: id = msg_send![APP_CLASS, sharedApplication]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:279:19 ++ | ++279 | delegate: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:282:10 ++ | ++282 | ) -> id { ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSMenu::new`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:284:37 ++ | ++284 | let dock_menu = NSMenu::new(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:284:41 ++ | ++284 | let dock_menu = NSMenu::new(nil); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:301:19 ++ | ++301 | delegate: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:304:10 ++ | ++304 | ) -> id { ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::separatorItem`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:309:52 ++ | ++309 | MenuItem::Separator => NSMenuItem::separatorItem(nil), ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:309:66 ++ | ++309 | MenuItem::Separator => NSMenuItem::separatorItem(nil), ++ | ^^^ ++ ++warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:339:55 ++ | ++339 | Some(crate::OsAction::Cut) => selector("cut:"), ++ | ^^^^^^^^ ++ ++warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:340:56 ++ | ++340 | Some(crate::OsAction::Copy) => selector("copy:"), ++ | ^^^^^^^^ ++ ++warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:341:57 ++ | ++341 | Some(crate::OsAction::Paste) => selector("paste:"), ++ | ^^^^^^^^ ++ ++warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:342:61 ++ | ++342 | Some(crate::OsAction::SelectAll) => selector("selectAll:"), ++ | ^^^^^^^^ ++ ++warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:345:56 ++ | ++345 | Some(crate::OsAction::Undo) => selector("handleGPUIMenuItem:"), ++ | ^^^^^^^^ ++ ++warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:346:56 ++ | ++346 | Some(crate::OsAction::Redo) => selector("handleGPUIMenuItem:"), ++ | ^^^^^^^^ ++ ++warning: use of deprecated function `cocoa::base::selector`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:347:33 ++ | ++347 | None => selector("handleGPUIMenuItem:"), ++ | ^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:354:44 ++ | ++354 | ... let mut mask = NSEventModifierFlags::empty(); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:358:37 ++ | ++358 | ... NSEventModifierFlags::NSCommandKeyMask, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:362:37 ++ | ++362 | ... NSEventModifierFlags::NSControlKeyMask, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:366:37 ++ | ++366 | ... NSEventModifierFlags::NSAlternateKeyMask, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:370:37 ++ | ++370 | ... NSEventModifierFlags::NSShiftKeyMask, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::alloc`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:378:48 ++ | ++378 | ... item = NSMenuItem::alloc(nil) ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:378:54 ++ | ++378 | ... item = NSMenuItem::alloc(nil) ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::alloc`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:390:48 ++ | ++390 | ... item = NSMenuItem::alloc(nil) ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:390:54 ++ | ++390 | ... item = NSMenuItem::alloc(nil) ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::alloc`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:399:44 ++ | ++399 | item = NSMenuItem::alloc(nil) ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:399:50 ++ | ++399 | item = NSMenuItem::alloc(nil) ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:408:48 ++ | ++408 | let tag = actions.len() as NSInteger; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::new`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:414:44 ++ | ++414 | let item = NSMenuItem::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:414:48 ++ | ++414 | let item = NSMenuItem::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSMenu::new`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:415:43 ++ | ++415 | let submenu = NSMenu::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:415:47 ++ | ++415 | let submenu = NSMenu::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSMenuItem::new`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:425:44 ++ | ++425 | let item = NSMenuItem::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:425:48 ++ | ++425 | let item = NSMenuItem::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSMenu::new`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:426:43 ++ | ++426 | let submenu = NSMenu::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:426:47 ++ | ++426 | let submenu = NSMenu::new(nil).autorelease(); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:433:38 ++ | ++433 | ... let app: id = msg_send![APP_CLASS, sharedApplication]; ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSProcessInfo::processInfo`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:446:47 ++ | ++446 | let process_info = NSProcessInfo::processInfo(nil); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:446:59 ++ | ++446 | let process_info = NSProcessInfo::processInfo(nil); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:482:22 ++ | ++482 | let app: id = msg_send![APP_CLASS, sharedApplication]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:483:31 ++ | ++483 | let app_delegate: id = msg_send![APP_DELEGATE_CLASS, new]; ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSAutoreleasePool::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:490:43 ++ | ++490 | let pool = NSAutoreleasePool::new(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:490:47 ++ | ++490 | let pool = NSAutoreleasePool::new(nil); ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::delegate`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:495:25 ++ | ++495 | (*NSWindow::delegate(app)).set_ivar(MAC_PLATFORM_IVAR, null_mut::()); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:558:38 ++ | ++558 | let app = NSApplication::sharedApplication(nil); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:558:56 ++ | ++558 | let app = NSApplication::sharedApplication(nil); ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:565:38 ++ | ++565 | let app = NSApplication::sharedApplication(nil); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:565:56 ++ | ++565 | let app = NSApplication::sharedApplication(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:566:46 ++ | ++566 | let _: () = msg_send![app, hide: nil]; ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:572:38 ++ | ++572 | let app = NSApplication::sharedApplication(nil); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:572:56 ++ | ++572 | let app = NSApplication::sharedApplication(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:573:63 ++ | ++573 | let _: () = msg_send![app, hideOtherApplications: nil]; ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:579:38 ++ | ++579 | let app = NSApplication::sharedApplication(nil); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:579:56 ++ | ++579 | let app = NSApplication::sharedApplication(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:580:63 ++ | ++580 | let _: () = msg_send![app, unhideAllApplications: nil]; ++ | ^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSOperatingSystemVersion`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:596:46 ++ | ++596 | let min_version = cocoa::foundation::NSOperatingSystemVersion::new(12, 3, 0); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:633:38 ++ | ++633 | let app = NSApplication::sharedApplication(nil); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:633:56 ++ | ++633 | let app = NSApplication::sharedApplication(nil); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:634:29 ++ | ++634 | let appearance: id = msg_send![app, effectiveAppearance]; ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSURL::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:641:30 ++ | ++641 | let url = NSURL::alloc(nil) ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:641:36 ++ | ++641 | let url = NSURL::alloc(nil) ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:644:28 ++ | ++644 | let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:660:25 ++ | ++660 | let bundle: id = msg_send![class!(NSBundle), mainBundle]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:661:28 ++ | ++661 | let bundle_id: id = msg_send![bundle, bundleIdentifier]; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:662:29 ++ | ++662 | if bundle_id == nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:669:28 ++ | ++669 | let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:670:25 ++ | ++670 | let scheme: id = ns_string(scheme); ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:671:22 ++ | ++671 | let app: id = msg_send![workspace, URLForApplicationWithBundleIdentifier: bundle_id]; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:672:23 ++ | ++672 | if app == nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:678:57 ++ | ++678 | let block = ConcreteBlock::new(move |error: id| { ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:679:42 ++ | ++679 | let result = if error == nil { ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:682:30 ++ | ++682 | let msg: id = msg_send![error, localizedDescription]; ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSOpenPanel::openPanel`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:710:46 ++ | ++710 | let panel = NSOpenPanel::openPanel(nil); ++ | ^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:710:56 ++ | ++710 | let panel = NSOpenPanel::openPanel(nil); ++ | ^^^ ++ ++warning: use of deprecated enum `cocoa::appkit::NSModalResponse`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:718:68 ++ | ++718 | let block = ConcreteBlock::new(move |response: NSModalResponse| { ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSModalResponse::NSModalResponseOk`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:719:70 ++ | ++719 | let result = if response == NSModalResponse::NSModalResponseOk { ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSSavePanel::savePanel`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:763:46 ++ | ++763 | let panel = NSSavePanel::savePanel(nil); ++ | ^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:763:56 ++ | ++763 | let panel = NSSavePanel::savePanel(nil); ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSURL::fileURLWithPath_isDirectory_`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:765:38 ++ | ++765 | let url = NSURL::fileURLWithPath_isDirectory_(nil, path, true.to_objc()); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:765:67 ++ | ++765 | let url = NSURL::fileURLWithPath_isDirectory_(nil, path, true.to_objc()); ++ | ^^^ ++ ++warning: use of deprecated enum `cocoa::appkit::NSModalResponse`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:774:68 ++ | ++774 | let block = ConcreteBlock::new(move |response: NSModalResponse| { ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSModalResponse::NSModalResponseOk`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:776:57 ++ | ++776 | if response == NSModalResponse::NSModalResponseOk { ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:837:36 ++ | ++837 | let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSBundle::mainBundle`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:897:40 ++ | ++897 | let bundle: id = NSBundle::mainBundle(); ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:897:25 ++ | ++897 | let bundle: id = NSBundle::mainBundle(); ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:905:22 ++ | ++905 | let app: id = msg_send![APP_CLASS, sharedApplication]; ++ | ^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::delegate`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:908:63 ++ | ++908 | let menu = self.create_menu_bar(&menus, NSWindow::delegate(app), actions, keymap); ++ | ^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:921:22 ++ | ++921 | let app: id = msg_send![APP_CLASS, sharedApplication]; ++ | ^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::delegate`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:924:61 ++ | ++924 | let new = self.create_dock_menu(menu, NSWindow::delegate(app), actions, keymap); ++ | ^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:934:42 ++ | ++934 | let document_controller: id = ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSURL::fileURLWithPath_`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:936:38 ++ | ++936 | let url: id = NSURL::fileURLWithPath_(nil, ns_string(path_str)); ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:936:55 ++ | ++936 | let url: id = NSURL::fileURLWithPath_(nil, ns_string(path_str)); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:936:26 ++ | ++936 | let url: id = NSURL::fileURLWithPath_(nil, ns_string(path_str)); ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSBundle::mainBundle`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:944:40 ++ | ++944 | let bundle: id = NSBundle::mainBundle(); ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:944:25 ++ | ++944 | let bundle: id = NSBundle::mainBundle(); ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:947:22 ++ | ++947 | let url: id = msg_send![bundle, URLForAuxiliaryExecutable: name]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:962:29 ++ | ++962 | let new_cursor: id = match style { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:999:29 ++ | ++999 | let old_cursor: id = msg_send![class!(NSCursor), currentCursor]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1011:24 ++ | ++1011 | let style: NSInteger = msg_send![class!(NSScroller), preferredScrollerStyle]; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1040:68 ++ | ++1040 | let mut buf = NSMutableAttributedString::alloc(nil) ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1042:59 ++ | ++1042 | .init_attributed_string(NSString::alloc(nil).init_str("")); ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1042:65 ++ | ++1042 | .init_attributed_string(NSString::alloc(nil).init_str("")); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1047:71 ++ | ++1047 | ... let to_append = NSAttributedString::alloc(nil) ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1048:67 ++ | ++1048 | ... .init_attributed_string(NSString::alloc(nil).init_str(&text)); ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1048:73 ++ | ++1048 | ... .init_attributed_string(NSString::alloc(nil).init_str(&text)); ++ | ^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1063:25 ++ | ++1063 | NSRange::new(0, msg_send![attributed_string, length]), ++ | ^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1064:25 ++ | ++1064 | nil, ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1066:37 ++ | ++1066 | if rtfd_data != nil { ++ | ^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeRTFD`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1069:57 ++ | ++1069 | ... .setData_forType(rtfd_data, NSPasteboardTypeRTFD); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRange`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1073:25 ++ | ++1073 | NSRange::new(0, attributed_string.length()), ++ | ^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1074:25 ++ | ++1074 | nil, ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1076:36 ++ | ++1076 | if rtf_data != nil { ++ | ^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeRTF`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1079:56 ++ | ++1079 | ... .setData_forType(rtf_data, NSPasteboardTypeRTF); ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeString`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1086:52 ++ | ++1086 | .setString_forType(plain_text, NSPasteboardTypeString); ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1097:24 ++ | ++1097 | let types: id = pasteboard.types(); ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1098:30 ++ | ++1098 | let string_type: id = ns_string("public.utf8-plain-text"); ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1102:28 ++ | ++1102 | if data == nil { ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSData::dataWithBytes_length_`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1268:38 ++ | ++1268 | let text_bytes = NSData::dataWithBytes_length_( ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1269:17 ++ | ++1269 | nil, ++ | ^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeString`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1275:46 ++ | ++1275 | .setData_forType(text_bytes, NSPasteboardTypeString); ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSData::dataWithBytes_length_`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1279:42 ++ | ++1279 | let hash_bytes = NSData::dataWithBytes_length_( ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1280:21 ++ | ++1280 | nil, ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSData::dataWithBytes_length_`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1288:46 ++ | ++1288 | let metadata_bytes = NSData::dataWithBytes_length_( ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1289:21 ++ | ++1289 | nil, ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSData::dataWithBytes_length_`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1305:33 ++ | ++1305 | let bytes = NSData::dataWithBytes_length_( ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1306:17 ++ | ++1306 | nil, ++ | ^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSPasteboardTypePNG`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1592:23 ++ | ++1592 | Self(unsafe { NSPasteboardTypePNG }) // This is a rare case where there's a built-in NSPasteboardType ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSPasteboardTypeTIFF`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1622:23 ++ | ++1622 | Self(unsafe { NSPasteboardTypeTIFF }) // This is a rare case where there's a built-in NSPasteboardType ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSAppKitVersionNumber`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:15:9 ++ | ++15 | NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered, ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSAppKitVersionNumber12_0`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:15:32 ++ | ++15 | NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered, ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:15:59 ++ | ++15 | NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered, ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated variant `cocoa::appkit::NSBackingStoreBuffered`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:15:74 ++ | ++15 | NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered, ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSBackingStoreBuffered`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:15:74 ++ | ++15 | NSAppKitVersionNumber, NSAppKitVersionNumber12_0, NSApplication, NSBackingStoreBuffered, ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSColor`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:16:9 ++ | ++16 | NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, ++ | ^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSEvent`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:16:18 ++ | ++16 | NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, ++ | ^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:16:27 ++ | ++16 | NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSFilenamesPboardType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:16:49 ++ | ++16 | NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSPasteboard`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:16:72 ++ | ++16 | NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSScreen`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:16:86 ++ | ++16 | NSColor, NSEvent, NSEventModifierFlags, NSFilenamesPboardType, NSPasteboard, NSScreen, ++ | ^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSView`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:17:9 ++ | ++17 | NSView, NSViewHeightSizable, NSViewWidthSizable, NSVisualEffectMaterial, ++ | ^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSViewHeightSizable`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:17:17 ++ | ++17 | NSView, NSViewHeightSizable, NSViewWidthSizable, NSVisualEffectMaterial, ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSViewWidthSizable`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:17:38 ++ | ++17 | NSView, NSViewHeightSizable, NSViewWidthSizable, NSVisualEffectMaterial, ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated enum `cocoa::appkit::NSVisualEffectMaterial`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:17:58 ++ | ++17 | NSView, NSViewHeightSizable, NSViewWidthSizable, NSVisualEffectMaterial, ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated enum `cocoa::appkit::NSVisualEffectState`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:18:9 ++ | ++18 | NSVisualEffectState, NSVisualEffectView, NSWindow, NSWindowButton, ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSVisualEffectView`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:18:30 ++ | ++18 | NSVisualEffectState, NSVisualEffectView, NSWindow, NSWindowButton, ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::appkit::NSWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:18:50 ++ | ++18 | NSVisualEffectState, NSVisualEffectView, NSWindow, NSWindowButton, ++ | ^^^^^^^^ ++ ++warning: use of deprecated enum `cocoa::appkit::NSWindowButton`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:18:60 ++ | ++18 | NSVisualEffectState, NSVisualEffectView, NSWindow, NSWindowButton, ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowCollectionBehavior`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:19:9 ++ | ++19 | NSWindowCollectionBehavior, NSWindowOcclusionState, NSWindowOrderingMode, ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowOcclusionState`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:19:37 ++ | ++19 | NSWindowCollectionBehavior, NSWindowOcclusionState, NSWindowOrderingMode, ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowOrderingMode`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:19:61 ++ | ++19 | NSWindowCollectionBehavior, NSWindowOcclusionState, NSWindowOrderingMode, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:20:9 ++ | ++20 | NSWindowStyleMask, NSWindowTitleVisibility, ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated enum `cocoa::appkit::NSWindowTitleVisibility`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:20:28 ++ | ++20 | NSWindowStyleMask, NSWindowTitleVisibility, ++ | ^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:22:12 ++ | ++22 | base::{id, nil}, ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:22:16 ++ | ++22 | base::{id, nil}, ++ | ^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSArray`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:24:9 ++ | ++24 | NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, ++ | ^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSAutoreleasePool`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:24:18 ++ | ++24 | NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSDictionary`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:24:37 ++ | ++24 | NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSFastEnumeration`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:24:51 ++ | ++24 | NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:24:70 ++ | ++24 | NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, ++ | ^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::foundation::NSNotFound`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:24:81 ++ | ++24 | NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSOperatingSystemVersion`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:25:9 ++ | ++25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, ++ | ^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:25:35 ++ | ++25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, ++ | ^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSProcessInfo`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:25:44 ++ | ++25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:25:59 ++ | ++25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:25:67 ++ | ++25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, ++ | ^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:25:75 ++ | ++25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, ++ | ^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:25:85 ++ | ++25 | NSOperatingSystemVersion, NSPoint, NSProcessInfo, NSRect, NSSize, NSString, NSUInteger, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSUserDefaults`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:26:9 ++ | ++26 | NSUserDefaults, ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:64:44 ++ | ++64 | const NSWindowStyleMaskNonactivatingPanel: NSWindowStyleMask = ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:65:5 ++ | ++65 | NSWindowStyleMask::from_bits_retain(1 << 7); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:67:28 ++ | ++67 | const NSNormalWindowLevel: NSInteger = 0; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:69:27 ++ | ++69 | const NSPopUpWindowLevel: NSInteger = 101; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:71:40 ++ | ++71 | const NSTrackingMouseEnteredAndExited: NSUInteger = 0x01; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:73:29 ++ | ++73 | const NSTrackingMouseMoved: NSUInteger = 0x02; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:75:31 ++ | ++75 | const NSTrackingActiveAlways: NSUInteger = 0x80; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:77:32 ++ | ++77 | const NSTrackingInVisibleRect: NSUInteger = 0x200; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:79:47 ++ | ++79 | const NSWindowAnimationBehaviorUtilityWindow: NSInteger = 4; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:81:50 ++ | ++81 | const NSViewLayerContentsRedrawDuringViewResize: NSInteger = 2; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:83:24 ++ | ++83 | type NSDragOperation = NSUInteger; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:119:74 ++ | ++119 | handle_key_equivalent as extern "C" fn(&Object, Sel, id) -> BOOL, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:123:68 ++ | ++123 | handle_key_down as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:127:66 ++ | ++127 | handle_key_up as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:131:70 ++ | ++131 | handle_view_event as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:135:70 ++ | ++135 | handle_view_event as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:139:70 ++ | ++139 | handle_view_event as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:143:70 ++ | ++143 | handle_view_event as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:147:70 ++ | ++147 | handle_view_event as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:151:70 ++ | ++151 | handle_view_event as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:155:70 ++ | ++155 | handle_view_event as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:159:70 ++ | ++159 | handle_view_event as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:163:70 ++ | ++163 | handle_view_event as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:167:70 ++ | ++167 | handle_view_event as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:171:70 ++ | ++171 | handle_view_event as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:175:70 ++ | ++175 | handle_view_event as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:180:74 ++ | ++180 | make_backing_layer as extern "C" fn(&Object, Sel) -> id, ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:190:67 ++ | ++190 | set_frame_size as extern "C" fn(&Object, Sel, NSSize), ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:194:66 ++ | ++194 | display_layer as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:200:88 ++ | ++200 | valid_attributes_for_marked_text as extern "C" fn(&Object, Sel) -> id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:217:65 ++ | ++217 | as extern "C" fn(&Object, Sel, NSRange, id) -> NSRect, ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:217:72 ++ | ++217 | as extern "C" fn(&Object, Sel, NSRange, id) -> NSRect, ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:221:64 ++ | ++221 | insert_text as extern "C" fn(&Object, Sel, id, NSRange), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:225:68 ++ | ++225 | set_marked_text as extern "C" fn(&Object, Sel, id, NSRange, NSRange), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:231:81 ++ | ++231 | as extern "C" fn(&Object, Sel, NSRange, *mut c_void) -> id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:246:72 ++ | ++246 | accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL, ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:251:78 ++ | ++251 | character_index_for_point as extern "C" fn(&Object, Sel, NSPoint) -> u64, ++ | ^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:261:81 ++ | ++261 | blurred_view_init_with_frame as extern "C" fn(&Object, Sel, NSRect) -> id, ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:261:92 ++ | ++261 | blurred_view_init_with_frame as extern "C" fn(&Object, Sel, NSRect) -> id, ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:273:48 ++ | ++273 | pub(crate) fn convert_mouse_position(position: NSPoint, window_height: Pixels) -> Point { ++ | ^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:297:62 ++ | ++297 | window_did_resize as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:301:78 ++ | ++301 | window_did_change_occlusion_state as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:305:73 ++ | ++305 | window_will_enter_fullscreen as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:309:72 ++ | ++309 | window_will_exit_fullscreen as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:313:60 ++ | ++313 | window_did_move as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:317:69 ++ | ++317 | window_did_change_screen as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:321:73 ++ | ++321 | window_did_change_key_status as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:325:73 ++ | ++325 | window_did_change_key_status as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:329:64 ++ | ++329 | window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:336:61 ++ | ++336 | dragging_entered as extern "C" fn(&Object, Sel, id) -> NSDragOperation, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:340:61 ++ | ++340 | dragging_updated as extern "C" fn(&Object, Sel, id) -> NSDragOperation, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:344:60 ++ | ++344 | dragging_exited as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:348:67 ++ | ++348 | perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:352:68 ++ | ++352 | conclude_drag_operation as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:357:83 ++ | ++357 | add_titlebar_accessory_view_controller as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:362:67 ++ | ++362 | move_tab_to_new_window as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:367:62 ++ | ++367 | merge_all_windows as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:372:60 ++ | ++372 | select_next_tab as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:377:64 ++ | ++377 | select_previous_tab as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:382:59 ++ | ++382 | toggle_tab_bar as extern "C" fn(&Object, Sel, id), ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:392:20 ++ | ++392 | native_window: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:394:26 ++ | ++394 | blurred_view: Option, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:984:44 ++ | ++984 | let native_window = context as id; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:985:66 ++ | ++985 | let _: () = msg_send![native_window, mergeAllWindows:nil]; ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1000:44 ++ | ++1000 | let native_window = context as id; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1001:69 ++ | ++1001 | let _: () = msg_send![native_window, moveTabToNewWindow:nil]; ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1002:72 ++ | ++1002 | let _: () = msg_send![native_window, makeKeyAndOrderFront: nil]; ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1544:36 ++ | ++1544 | fn get_scale_factor(native_window: id) -> f32 { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1546:21 ++ | ++1546 | let screen: id = msg_send![native_window, screen]; ++ | ^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSScreen::backingScaleFactor`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1550:19 ++ | ++1550 | NSScreen::backingScaleFactor(screen) as f32 ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1597:74 ++ | ++1597 | extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: id) -> BOOL { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1601:68 ++ | ++1601 | extern "C" fn handle_key_down(this: &Object, _: Sel, native_event: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1605:66 ++ | ++1605 | extern "C" fn handle_key_up(this: &Object, _: Sel, native_event: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1634:61 ++ | ++1634 | extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: bool) -> BOOL { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1696:40 ++ | ++1696 | let input_context: id = msg_send![this, inputContext]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1737:36 ++ | ++1737 | let input_context: id = msg_send![this, inputContext]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1751:70 ++ | ++1751 | extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1821:40 ++ | ++1821 | let input_context: id = msg_send![this, inputContext]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1881:75 ++ | ++1881 | extern "C" fn window_did_change_occlusion_state(this: &Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowOcclusionState`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1888:23 ++ | ++1888 | .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1898:59 ++ | ++1898 | extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1903:70 ++ | ++1903 | extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSOperatingSystemVersion`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1908:23 ++ | ++1908 | let min_version = NSOperatingSystemVersion::new(15, 3, 0); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1917:69 ++ | ++1917 | extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSOperatingSystemVersion`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1921:23 ++ | ++1921 | let min_version = NSOperatingSystemVersion::new(15, 3, 0); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSOperatingSystemVersion`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1930:50 ++ | ++1930 | pub(crate) fn is_macos_version_at_least(version: NSOperatingSystemVersion) -> bool { ++ | ^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSProcessInfo::processInfo`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1931:29 ++ | ++1931 | unsafe { NSProcessInfo::processInfo(nil).isOperatingSystemAtLeastVersion(version) } ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1931:41 ++ | ++1931 | unsafe { NSProcessInfo::processInfo(nil).isOperatingSystemAtLeastVersion(version) } ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1934:57 ++ | ++1934 | extern "C" fn window_did_move(this: &Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1944:66 ++ | ++1944 | extern "C" fn window_did_change_screen(this: &Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1950:77 ++ | ++1950 | extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2010:61 ++ | ++2010 | extern "C" fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2039:60 ++ | ++2039 | extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2042:42 ++ | ++2042 | window_state.renderer.layer_ptr() as id ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2070:59 ++ | ++2070 | extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2076:24 ++ | ++2076 | let old_frame: NSRect = msg_send![this, frame]; ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2101:55 ++ | ++2101 | extern "C" fn display_layer(this: &Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2120:24 ++ | ++2120 | let view = view as id; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2131:71 ++ | ++2131 | extern "C" fn valid_attributes_for_marked_text(_: &Object, _: Sel) -> id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2162:8 ++ | ++2162 | _: id, ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2163:6 ++ | ++2163 | ) -> NSRect { ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2170:9 ++ | ++2170 | NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2170:21 ++ | ++2170 | NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), ++ | ^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2170:43 ++ | ++2170 | NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2172:13 ++ | ++2172 | NSRect::new( ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2173:17 ++ | ++2173 | NSPoint::new( ++ | ^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2179:17 ++ | ++2179 | NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2185:32 ++ | ++2185 | fn get_frame(this: &Object) -> NSRect { ++ | ^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::frame`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2189:35 ++ | ++2189 | let mut frame = NSWindow::frame(lock.native_window); ++ | ^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2191:25 ++ | ++2191 | let style_mask: NSWindowStyleMask = msg_send![lock.native_window, styleMask]; ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2192:33 ++ | ++2192 | if !style_mask.contains(NSWindowStyleMask::NSFullSizeContentViewWindowMask) { ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2199:56 ++ | ++2199 | extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NSRange) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2203:19 ++ | ++2203 | let text: id = if is_attributed_string == YES { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2220:11 ++ | ++2220 | text: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2227:19 ++ | ++2227 | let text: id = if is_attributed_string == YES { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2249:6 ++ | ++2249 | ) -> id { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2264:25 ++ | ++2264 | let string: id = msg_send![class!(NSAttributedString), alloc]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2265:25 ++ | ++2265 | let string: id = msg_send![string, initWithString: ns_string(&selected_text)]; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2270:16 ++ | ++2270 | .unwrap_or(nil) ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2305:61 ++ | ++2305 | extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: id) -> BOOL { ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2312:74 ++ | ++2312 | extern "C" fn character_index_for_point(this: &Object, _: Sel, position: NSPoint) -> u64 { ++ | ^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::foundation::NSNotFound`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2319:16 ++ | ++2319 | .unwrap_or(NSNotFound as u64) ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2322:56 ++ | ++2322 | fn screen_point_to_gpui_point(this: &Object, position: NSPoint) -> Point { ++ | ^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2330:70 ++ | ++2330 | extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: id) -> NSDragOperation { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2344:70 ++ | ++2344 | extern "C" fn dragging_updated(this: &Object, _: Sel, dragging_info: id) -> NSDragOperation { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2357:57 ++ | ++2357 | extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2366:76 ++ | ++2366 | extern "C" fn perform_drag_operation(this: &Object, _: Sel, dragging_info: id) -> BOOL { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2378:21 ++ | ++2378 | let pasteboard: id = unsafe { msg_send![dragging_info, draggingPasteboard] }; ++ | ^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::propertyListForType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2379:44 ++ | ++2379 | let filenames = unsafe { NSPasteboard::propertyListForType(pasteboard, NSFilenamesPboardType) }; ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSFilenamesPboardType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2379:76 ++ | ++2379 | let filenames = unsafe { NSPasteboard::propertyListForType(pasteboard, NSFilenamesPboardType) }; ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2380:21 ++ | ++2380 | if filenames == nil { ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2385:31 ++ | ++2385 | let f = NSString::UTF8String(file); ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2393:65 ++ | ++2393 | extern "C" fn conclude_drag_operation(this: &Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2434:77 ++ | ++2434 | fn drag_event_position(window_state: &Mutex, dragging_info: id) -> Point { ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2435:24 ++ | ++2435 | let drag_location: NSPoint = unsafe { msg_send![dragging_info, draggingLocation] }; ++ | ^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2455:41 ++ | ++2455 | unsafe fn display_id_for_screen(screen: id) -> CGDirectDisplayID { ++ | ^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSScreen::deviceDescription`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2457:44 ++ | ++2457 | let device_description = NSScreen::deviceDescription(screen); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2458:47 ++ | ++2458 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2458:53 ++ | ++2458 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2458:32 ++ | ++2458 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2460:28 ++ | ++2460 | let screen_number: NSUInteger = msg_send![screen_number, unsignedIntegerValue]; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2465:74 ++ | ++2465 | extern "C" fn blurred_view_init_with_frame(this: &Object, _: Sel, frame: NSRect) -> id { ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2465:85 ++ | ++2465 | extern "C" fn blurred_view_init_with_frame(this: &Object, _: Sel, frame: NSRect) -> id { ++ | ^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSVisualEffectView::setMaterial_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2470:29 ++ | ++2470 | NSVisualEffectView::setMaterial_(view, NSVisualEffectMaterial::Selection); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSVisualEffectMaterial::Selection`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2470:72 ++ | ++2470 | NSVisualEffectView::setMaterial_(view, NSVisualEffectMaterial::Selection); ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSVisualEffectView::setState_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2471:29 ++ | ++2471 | NSVisualEffectView::setState_(view, NSVisualEffectState::Active); ++ | ^^^^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSVisualEffectState::Active`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2471:66 ++ | ++2471 | NSVisualEffectView::setState_(view, NSVisualEffectState::Active); ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2479:20 ++ | ++2479 | let layer: id = msg_send![this, layer]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2486:42 ++ | ++2486 | unsafe fn remove_layer_background(layer: id) { ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2488:57 ++ | ++2488 | let _: () = msg_send![layer, setBackgroundColor:nil]; ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2490:25 ++ | ++2490 | let class_name: id = msg_send![layer, className]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2497:22 ++ | ++2497 | let filters: id = msg_send![layer, filters]; ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2504:45 ++ | ++2504 | let test_string: id = NSString::alloc(nil).init_str("Saturat").autorelease(); ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2504:51 ++ | ++2504 | let test_string: id = NSString::alloc(nil).init_str("Saturat").autorelease(); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2504:30 ++ | ++2504 | let test_string: id = NSString::alloc(nil).init_str("Saturat").autorelease(); ++ | ^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::count`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2505:34 ++ | ++2505 | let count = NSArray::count(filters); ++ | ^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2507:34 ++ | ++2507 | let description: id = msg_send![filters.objectAtIndex(i), description]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2517:30 ++ | ++2517 | let indices: id = msg_send![class!(NSMutableIndexSet), indexSet]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2520:31 ++ | ++2520 | let filtered: id = msg_send![filters, objectsAtIndexes: indices]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2526:24 ++ | ++2526 | let sublayers: id = msg_send![layer, sublayers]; ++ | ^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::count`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2528:34 ++ | ++2528 | let count = NSArray::count(sublayers); ++ | ^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2537:94 ++ | ++2537 | extern "C" fn add_titlebar_accessory_view_controller(this: &Object, _: Sel, view_controller: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2542:29 ++ | ++2542 | let accessory_view: id = msg_send![view_controller, view]; ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2544:24 ++ | ++2544 | let mut frame: NSRect = msg_send![accessory_view, frame]; ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2550:64 ++ | ++2550 | extern "C" fn move_tab_to_new_window(this: &Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2552:81 ++ | ++2552 | let _: () = msg_send![super(this, class!(NSWindow)), moveTabToNewWindow:nil]; ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2564:59 ++ | ++2564 | extern "C" fn merge_all_windows(this: &Object, _: Sel, _: id) { ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2566:78 ++ | ++2566 | let _: () = msg_send![super(this, class!(NSWindow)), mergeAllWindows:nil]; ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2578:62 ++ | ++2578 | extern "C" fn select_next_tab(this: &Object, _sel: Sel, _id: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2588:66 ++ | ++2588 | extern "C" fn select_previous_tab(this: &Object, _sel: Sel, _id: id) { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2598:61 ++ | ++2598 | extern "C" fn toggle_tab_bar(this: &Object, _sel: Sel, _id: id) { ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2600:75 ++ | ++2600 | let _: () = msg_send![super(this, class!(NSWindow)), toggleTabBar:nil]; ++ | ^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSWindowButton::NSWindowCloseButton`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:438:59 ++ | ++438 | standardWindowButton: NSWindowButton::NSWindowCloseButton ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:436:35 ++ | ++436 | let close_button: id = msg_send![ ++ | ^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSWindowButton::NSWindowMiniaturizeButton`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:442:59 ++ | ++442 | standardWindowButton: NSWindowButton::NSWindowMiniaturizeButton ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:440:33 ++ | ++440 | let min_button: id = msg_send![ ++ | ^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSWindowButton::NSWindowZoomButton`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:446:59 ++ | ++446 | standardWindowButton: NSWindowButton::NSWindowZoomButton ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:444:34 ++ | ++444 | let zoom_button: id = msg_send![ ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowOcclusionState`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:482:27 ++ | ++482 | .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:511:33 ++ | ++511 | style_mask.contains(NSWindowStyleMask::NSFullScreenWindowMask) ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::frame`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:516:51 ++ | ++516 | let mut window_frame = unsafe { NSWindow::frame(self.native_window) }; ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::screen`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:518:36 ++ | ++518 | let screen = NSWindow::screen(self.native_window); ++ | ^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSScreen::frame`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:519:23 ++ | ++519 | NSScreen::frame(screen) ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSView::frame`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:540:30 ++ | ++540 | unsafe { NSView::frame(self.native_window.contentView()) }.size; ++ | ^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:539:13 ++ | ++539 | let NSSize { width, height, .. } = ++ | ^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::frame`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:550:35 ++ | ++550 | let frame = NSWindow::frame(self.native_window); ++ | ^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSAutoreleasePool::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:589:43 ++ | ++589 | let pool = NSAutoreleasePool::new(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:589:47 ++ | ++589 | let pool = NSAutoreleasePool::new(nil); ++ | ^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:601:21 ++ | ++601 | NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask; ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:601:63 ++ | ++601 | NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask; ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:604:35 ++ | ++604 | style_mask |= NSWindowStyleMask::NSResizableWindowMask; ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:608:35 ++ | ++608 | style_mask |= NSWindowStyleMask::NSMiniaturizableWindowMask; ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:612:35 ++ | ++612 | style_mask |= NSWindowStyleMask::NSFullSizeContentViewWindowMask; ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:615:30 ++ | ++615 | style_mask = NSWindowStyleMask::NSTitledWindowMask ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:616:23 ++ | ++616 | | NSWindowStyleMask::NSFullSizeContentViewWindowMask; ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:619:32 ++ | ++619 | let native_window: id = match kind { ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:631:37 ++ | ++631 | let mut target_screen = nil; ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSScreen::screens`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:634:37 ++ | ++634 | let screens = NSScreen::screens(nil); ++ | ^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:634:45 ++ | ++634 | let screens = NSScreen::screens(nil); ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::count`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:635:58 ++ | ++635 | let count: u64 = cocoa::foundation::NSArray::count(screens); ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:637:58 ++ | ++637 | let screen = cocoa::foundation::NSArray::objectAtIndex(screens, i); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSScreen::frame`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:638:39 ++ | ++638 | let frame = NSScreen::frame(screen); ++ | ^^^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSScreen::mainScreen`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:647:40 ++ | ++647 | let screen = NSScreen::mainScreen(nil); ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:647:51 ++ | ++647 | let screen = NSScreen::mainScreen(nil); ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSScreen::frame`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:649:27 ++ | ++649 | NSScreen::frame(screen) ++ | ^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:652:31 ++ | ++652 | let window_rect = NSRect::new( ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:653:17 ++ | ++653 | NSPoint::new( ++ | ^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:658:17 ++ | ++658 | NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), ++ | ^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSBackingStoreBuffered`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:664:17 ++ | ++664 | NSBackingStoreBuffered, ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSArray::arrayWithObject`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:672:30 ++ | ++672 | NSArray::arrayWithObject(nil, NSFilenamesPboardType) ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:672:46 ++ | ++672 | NSArray::arrayWithObject(nil, NSFilenamesPboardType) ++ | ^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSFilenamesPboardType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:672:51 ++ | ++672 | NSArray::arrayWithObject(nil, NSFilenamesPboardType) ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:680:30 ++ | ++680 | let native_view: id = msg_send![VIEW_CLASS, alloc]; ++ | ^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSView::initWithFrame_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:681:39 ++ | ++681 | let native_view = NSView::initWithFrame_(native_view, NSView::bounds(content_view)); ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSView::bounds`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:681:75 ++ | ++681 | let native_view = NSView::initWithFrame_(native_view, NSView::bounds(content_view)); ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:748:50 ++ | ++748 | native_window.setContentMinSize_(NSSize { ++ | ^^^^^^ ++ ++warning: use of deprecated unit variant `cocoa::appkit::NSWindowTitleVisibility::NSWindowTitleHidden`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:756:76 ++ | ++756 | native_window.setTitleVisibility_(NSWindowTitleVisibility::NSWindowTitleHidden); ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSViewWidthSizable`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:759:46 ++ | ++759 | native_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSViewHeightSizable`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:759:67 ++ | ++759 | native_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:782:52 ++ | ++782 | let tabbing_id = NSString::alloc(nil).init_str(tabbing_identifier.as_str()); ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:782:58 ++ | ++782 | let tabbing_id = NSString::alloc(nil).init_str(tabbing_identifier.as_str()); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:790:40 ++ | ++790 | let tracking_area: id = msg_send![class!(NSTrackingArea), alloc]; ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSRect`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:793:39 ++ | ++793 | initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) ++ | ^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSPoint`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:793:51 ++ | ++793 | initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) ++ | ^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:793:73 ++ | ++793 | initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) ++ | ^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:796:35 ++ | ++796 | userInfo: nil ++ | ^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowCollectionBehavior`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:807:25 ++ | ++807 | NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces | ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowCollectionBehavior`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:808:25 ++ | ++808 | NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenAuxiliary ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:813:38 ++ | ++813 | let app = NSApplication::sharedApplication(nil); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:813:56 ++ | ++813 | let app = NSApplication::sharedApplication(nil); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:814:30 ++ | ++814 | let main_window: id = msg_send![app, mainWindow]; ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:821:31 ++ | ++821 | .contains(NSWindowStyleMask::NSFullScreenWindowMask); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowOrderingMode`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:834:100 ++ | ++834 | ... let _: () = msg_send![main_window, addTabbedWindow: native_window ordered: NSWindowOrderingMode::NSWindowAbove]; ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:839:78 ++ | ++839 | ... let _: () = msg_send![native_window, orderFront: nil]; ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:846:53 ++ | ++846 | native_window.makeKeyAndOrderFront_(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:848:43 ++ | ++848 | native_window.orderFront_(nil); ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setFrameTopLeftPoint_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:855:23 ++ | ++855 | NSWindow::setFrameTopLeftPoint_(native_window, window_rect.origin); ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:866:38 ++ | ++866 | let app = NSApplication::sharedApplication(nil); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:866:56 ++ | ++866 | let app = NSApplication::sharedApplication(nil); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:867:30 ++ | ++867 | let main_window: id = msg_send![app, mainWindow]; ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:883:38 ++ | ++883 | let app = NSApplication::sharedApplication(nil); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:883:56 ++ | ++883 | let app = NSApplication::sharedApplication(nil); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:884:26 ++ | ++884 | let windows: id = msg_send![app, orderedWindows]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:885:24 ++ | ++885 | let count: NSUInteger = msg_send![windows, count]; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:889:29 ++ | ++889 | let window: id = msg_send![windows, objectAtIndex:i]; ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSUserDefaults::standardUserDefaults`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:902:48 ++ | ++902 | let defaults: id = NSUserDefaults::standardUserDefaults(); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:902:27 ++ | ++902 | let defaults: id = NSUserDefaults::standardUserDefaults(); ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:903:36 ++ | ++903 | let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:903:42 ++ | ++903 | let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:904:33 ++ | ++904 | let key = NSString::alloc(nil).init_str("AppleWindowTabbingMode"); ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:904:39 ++ | ++904 | let key = NSString::alloc(nil).init_str("AppleWindowTabbingMode"); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:906:23 ++ | ++906 | let dict: id = msg_send![defaults, persistentDomainForName: domain]; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:910:17 ++ | ++910 | nil ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:907:24 ++ | ++907 | let value: id = if !dict.is_null() { ++ | ^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:914:42 ++ | ++914 | CStr::from_ptr(NSString::UTF8String(value)).to_string_lossy() ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:935:45 ++ | ++935 | this.native_window.setDelegate_(nil); ++ | ^^^ ++ ++warning: use of deprecated struct `cocoa::foundation::NSSize`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:972:44 ++ | ++972 | window.setContentSize_(NSSize { ++ | ^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1017:68 ++ | ++1017 | let _: () = msg_send![native_window, toggleTabOverview:nil]; ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1027:29 ++ | ++1027 | let appearance: id = msg_send![self.0.lock().native_window, effectiveAppearance]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1038:37 ++ | ++1038 | let device_description: id = msg_send![screen, deviceDescription]; ++ | ^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSDictionary::valueForKey_`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1039:51 ++ | ++1039 | let screen_number: id = NSDictionary::valueForKey_( ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1041:27 ++ | ++1041 | NSString::alloc(nil).init_str("NSScreenNumber"), ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1041:33 ++ | ++1041 | NSString::alloc(nil).init_str("NSScreenNumber"), ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1039:32 ++ | ++1039 | let screen_number: id = NSDictionary::valueForKey_( ++ | ^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1062:28 ++ | ++1062 | let modifiers: NSEventModifierFlags = msg_send![class!(NSEvent), modifierFlags]; ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1064:46 ++ | ++1064 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1065:42 ++ | ++1065 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1066:44 ++ | ++1066 | let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1067:46 ++ | ++1067 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1068:47 ++ | ++1068 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1082:28 ++ | ++1082 | let modifiers: NSEventModifierFlags = msg_send![class!(NSEvent), modifierFlags]; ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSEventModifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1085:40 ++ | ++1085 | on: modifiers.contains(NSEventModifierFlags::NSAlphaShiftKeyMask), ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1131:24 ++ | ++1131 | let alert: id = msg_send![class!(NSAlert), alloc]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1132:24 ++ | ++1132 | let alert: id = msg_send![alert, init]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1149:29 ++ | ++1149 | let button: id = msg_send![alert, addButtonWithTitle: ns_string(answer.label())]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1150:61 ++ | ++1150 | let _: () = msg_send![button, setTag: ix as NSInteger]; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1161:29 ++ | ++1161 | let button: id = msg_send![alert, addButtonWithTitle: ns_string(answer.label())]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1162:61 ++ | ++1162 | let _: () = msg_send![button, setTag: ix as NSInteger]; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1167:58 ++ | ++1167 | let block = ConcreteBlock::new(move |answer: NSInteger| { ++ | ^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1195:73 ++ | ++1195 | let _: () = msg_send![window, makeKeyAndOrderFront: nil]; ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1212:38 ++ | ++1212 | let app = NSApplication::sharedApplication(nil); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1212:56 ++ | ++1212 | let app = NSApplication::sharedApplication(nil); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1223:24 ++ | ++1223 | let title: id = msg_send![self.0.lock().native_window, title]; ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSColor::colorWithSRGBRed_green_blue_alpha_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1243:26 ++ | ++1243 | NSColor::colorWithSRGBRed_green_blue_alpha_(nil, 0f64, 0f64, 0f64, 1f64) ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1243:61 ++ | ++1243 | NSColor::colorWithSRGBRed_green_blue_alpha_(nil, 0f64, 0f64, 0f64, 1f64) ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSColor::colorWithSRGBRed_green_blue_alpha_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1246:26 ++ | ++1246 | NSColor::colorWithSRGBRed_green_blue_alpha_(nil, 0f64, 0f64, 0f64, 0.0001) ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1246:61 ++ | ++1246 | NSColor::colorWithSRGBRed_green_blue_alpha_(nil, 0f64, 0f64, 0f64, 0.0001) ++ | ^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSAppKitVersionNumber`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1250:16 ++ | ++1250 | if NSAppKitVersionNumber < NSAppKitVersionNumber12_0 { ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSAppKitVersionNumber12_0`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1250:40 ++ | ++1250 | if NSAppKitVersionNumber < NSAppKitVersionNumber12_0 { ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSView::removeFromSuperview`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1268:33 ++ | ++1268 | NSView::removeFromSuperview(blur_view); ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSView::bounds`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1273:41 ++ | ++1273 | let frame = NSView::bounds(content_view); ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1274:40 ++ | ++1274 | let mut blur_view: id = msg_send![BLURRED_VIEW_CLASS, alloc]; ++ | ^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSView::initWithFrame_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1275:41 ++ | ++1275 | blur_view = NSView::initWithFrame_(blur_view, frame); ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSViewWidthSizable`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1276:52 ++ | ++1276 | blur_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::appkit::NSViewHeightSizable`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1276:73 ++ | ++1276 | blur_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowOrderingMode`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1281:37 ++ | ++1281 | positioned: NSWindowOrderingMode::NSWindowBelow ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1282:37 ++ | ++1282 | relativeTo: nil ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::NSApplication::sharedApplication`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1307:46 ++ | ++1307 | let app = NSApplication::sharedApplication(nil); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1307:64 ++ | ++1307 | let app = NSApplication::sharedApplication(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1317:33 ++ | ++1317 | window.miniaturize_(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1327:34 ++ | ++1327 | window.zoom_(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1339:46 ++ | ++1339 | window.toggleFullScreen_(nil); ++ | ^^^ ++ ++warning: use of deprecated struct `cocoa::appkit::NSWindowStyleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1352:27 ++ | ++1352 | .contains(NSWindowStyleMask::NSFullScreenWindowMask) ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1395:26 ++ | ++1395 | let windows: id = msg_send![self.0.lock().native_window, tabbedWindows]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSUInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1400:24 ++ | ++1400 | let count: NSUInteger = msg_send![windows, count]; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1403:29 ++ | ++1403 | let window: id = msg_send![windows, objectAtIndex:i]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1406:32 ++ | ++1406 | let title: id = msg_send![window, title]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1419:28 ++ | ++1419 | let tab_group: id = msg_send![self.0.lock().native_window, tabGroup]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1467:40 ++ | ++1467 | let input_context: id = ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSUserDefaults::standardUserDefaults`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1484:56 ++ | ++1484 | let defaults: id = NSUserDefaults::standardUserDefaults(); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1484:35 ++ | ++1484 | let defaults: id = NSUserDefaults::standardUserDefaults(); ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1485:44 ++ | ++1485 | let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1485:50 ++ | ++1485 | let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1486:41 ++ | ++1486 | let key = NSString::alloc(nil).init_str("AppleActionOnDoubleClick"); ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1486:47 ++ | ++1486 | let key = NSString::alloc(nil).init_str("AppleActionOnDoubleClick"); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1488:31 ++ | ++1488 | let dict: id = msg_send![defaults, persistentDomainForName: domain]; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1492:25 ++ | ++1492 | nil ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1489:33 ++ | ++1489 | let action: id = if !dict.is_null() { ++ | ^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1496:50 ++ | ++1496 | CStr::from_ptr(NSString::UTF8String(action)).to_string_lossy() ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1503:49 ++ | ++1503 | ... window.miniaturize_(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1506:42 ++ | ++1506 | ... window.zoom_(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1510:42 ++ | ++1510 | ... window.zoom_(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1513:42 ++ | ++1513 | ... window.zoom_(nil); ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:98:33 ++ | ++98 | fn CGSMainConnectionID() -> id; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window.rs:100:24 ++ | ++100 | connection_id: id, ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::foundation::NSInteger`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:101:20 ++ | ++101 | window_id: NSInteger, ++ | ^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSAppearanceNameVibrantDark`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window_appearance.rs:3:14 ++ | ++3 | appkit::{NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight}, ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSAppearanceNameVibrantLight`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window_appearance.rs:3:43 ++ | ++3 | appkit::{NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight}, ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window_appearance.rs:4:11 ++ | ++4 | base::id, ++ | ^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window_appearance.rs:5:17 ++ | ++5 | foundation::NSString, ++ | ^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window_appearance.rs:11:50 ++ | ++11 | pub(crate) unsafe fn from_native(appearance: id) -> Self { ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window_appearance.rs:12:19 ++ | ++12 | let name: id = msg_send![appearance, name]; ++ | ^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSAppearanceNameVibrantLight`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window_appearance.rs:14:24 ++ | ++14 | if name == NSAppearanceNameVibrantLight { ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated static `cocoa::appkit::NSAppearanceNameVibrantDark`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window_appearance.rs:16:31 ++ | ++16 | } else if name == NSAppearanceNameVibrantDark { ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window_appearance.rs:35:38 ++ | ++35 | pub static NSAppearanceNameAqua: id; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/gpui/src/platform/mac/window_appearance.rs:36:42 ++ | ++36 | pub static NSAppearanceNameDarkAqua: id; ++ | ^^ ++ ++ Compiling zlog v0.1.0 (/Volumes/ExternalData/Library/Git/zed/crates/zlog) ++ Compiling settings_ui_macros v0.1.0 (/Volumes/ExternalData/Library/Git/zed/crates/settings_ui_macros) ++ Compiling serde_path_to_error v0.1.17 ++ Compiling ec4rs v1.2.0 ++ Compiling pem-rfc7468 v0.7.0 ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/display.rs:38:62 ++ | ++38 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSDictionary::objectForKey_`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/display.rs:39:52 ++ | ++39 | let screen_number = device_description.objectForKey_(screen_number_key); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::modifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:86:38 ++ | ++86 | let modifiers = native_event.modifierFlags(); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:87:33 ++ | ++87 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSControlKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:87:64 ++ | ++87 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:88:29 ++ | ++88 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSAlternateKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:88:60 ++ | ++88 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:89:31 ++ | ++89 | let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSShiftKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:89:62 ++ | ++89 | let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:90:33 ++ | ++90 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSCommandKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:90:64 ++ | ++90 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:91:34 ++ | ++91 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSFunctionKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:91:65 ++ | ++91 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::eventType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:109:43 ++ | ++109 | let event_type = native_event.eventType(); ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::modifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:126:34 ++ | ++126 | ... .modifierFlags() ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:127:34 ++ | ++127 | ... .contains(NSEventModifierFlags::NSAlphaShiftKeyMask), ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSAlphaShiftKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:127:65 ++ | ++127 | ... .contains(NSEventModifierFlags::NSAlphaShiftKeyMask), ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::isARepeat`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:133:43 ++ | ++133 | is_held: native_event.isARepeat() == YES, ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::buttonNumber`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:141:53 ++ | ++141 | let button = match native_event.buttonNumber() { ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:154:49 ++ | ++154 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:154:36 ++ | ++154 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:156:65 ++ | ++156 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:156:52 ++ | ++156 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::clickCount`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:159:55 ++ | ++159 | ... click_count: native_event.clickCount() as usize, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::buttonNumber`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:167:53 ++ | ++167 | let button = match native_event.buttonNumber() { ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:181:49 ++ | ++181 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:181:36 ++ | ++181 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:182:65 ++ | ++182 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:182:52 ++ | ++182 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::clickCount`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:185:55 ++ | ++185 | ... click_count: native_event.clickCount() as usize, ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::phase`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:191:67 ++ | ++191 | let navigation_direction = match native_event.phase() { ++ | ^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventPhase::NSEventPhaseEnded`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:192:39 ++ | ++192 | NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() { ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::deltaX`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:192:79 ++ | ++192 | NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() { ++ | ^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:205:53 ++ | ++205 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:205:40 ++ | ++205 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:206:69 ++ | ++206 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:206:56 ++ | ++206 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::phase`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:217:52 ++ | ++217 | let phase = match native_event.phase() { ++ | ^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventPhase::NSEventPhaseMayBegin`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:218:39 ++ | ++218 | NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventPhase::NSEventPhaseBegan`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:218:76 ++ | ++218 | NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventPhase::NSEventPhaseEnded`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:221:39 ++ | ++221 | NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::scrollingDeltaX`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:226:38 ++ | ++226 | native_event.scrollingDeltaX() as f32, ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::scrollingDeltaY`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:227:38 ++ | ++227 | native_event.scrollingDeltaY() as f32, ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::hasPreciseScrollingDeltas`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:230:49 ++ | ++230 | let delta = if native_event.hasPreciseScrollingDeltas() == YES { ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:238:45 ++ | ++238 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:238:32 ++ | ++238 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:239:61 ++ | ++239 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:239:48 ++ | ++239 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::buttonNumber`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:249:61 ++ | ++249 | let pressed_button = match native_event.buttonNumber() { ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:263:49 ++ | ++263 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:263:36 ++ | ++263 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:264:65 ++ | ++264 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:264:52 ++ | ++264 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:273:45 ++ | ++273 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:273:32 ++ | ++273 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:274:61 ++ | ++274 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:274:48 ++ | ++274 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:283:45 ++ | ++283 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:283:32 ++ | ++283 | ... px(native_event.locationInWindow().x as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::locationInWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:284:61 ++ | ++284 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/events.rs:284:48 ++ | ++284 | ... window_height - px(native_event.locationInWindow().y as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::charactersIgnoringModifiers`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:302:14 ++ | ++302 | .charactersIgnoringModifiers() ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::modifierFlags`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:307:38 ++ | ++307 | let modifiers = native_event.modifierFlags(); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:309:33 ++ | ++309 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSControlKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:309:64 ++ | ++309 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:310:29 ++ | ++310 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSAlternateKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:310:60 ++ | ++310 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:311:35 ++ | ++311 | let mut shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSShiftKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:311:66 ++ | ++311 | let mut shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:312:33 ++ | ++312 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSCommandKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:312:64 ++ | ++312 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:313:34 ++ | ++313 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask) ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSFunctionKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:313:65 ++ | ++313 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask) ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::keyCode`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:393:57 ++ | ++393 | chars_for_modified_key(native_event.keyCode(), NO_MOD); ++ | ^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::keyCode`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:395:57 ++ | ++395 | chars_for_modified_key(native_event.keyCode(), SHIFT_MOD); ++ | ^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::keyCode`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:400:78 ++ | ++400 | let chars_with_cmd = chars_for_modified_key(native_event.keyCode(), CMD_MOD); ++ | ^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::keyCode`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:402:61 ++ | ++402 | chars_for_modified_key(native_event.keyCode(), CMD_MOD | SHIFT_MOD); ++ | ^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::keyCode`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/events.rs:426:73 ++ | ++426 | key_char = Some(chars_for_modified_key(native_event.keyCode(), mods)); ++ | ^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:198:59 ++ | ++198 | let screen_number_key = unsafe { NSString::alloc(nil).init_str("NSScreenNumber") }; ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::count`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:246:38 ++ | ++246 | for i in 0..displays.count() { ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/screen_capture.rs:247:44 ++ | ++247 | let display = displays.objectAtIndex(i); ++ | ^^^^^^^^^^^^^ ++ ++ Compiling by_address v1.2.1 ++warning: use of deprecated associated constant `cocoa::quartzcore::AutoresizingMask::WIDTH_SIZABLE`: use the objc2-quartz-core crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:152:56 ++ | ++152 | setAutoresizingMask: AutoresizingMask::WIDTH_SIZABLE ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::quartzcore::AutoresizingMask::HEIGHT_SIZABLE`: use the objc2-quartz-core crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:153:41 ++ | ++153 | | AutoresizingMask::HEIGHT_SIZABLE ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:300:13 ++ | ++300 | width: size.width.0 as f64, ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:301:13 ++ | ++301 | height: size.height.0 as f64, ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:310:33 ++ | ++310 | width: DevicePixels(size.width as i32), ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/metal_renderer.rs:311:34 ++ | ++311 | height: DevicePixels(size.height as i32), ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::dataForType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:223:35 ++ | ++223 | let data = pasteboard.dataForType(kind); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSData::bytes`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:228:26 ++ | ++228 | data.bytes() as *mut u8, ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSData::length`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:229:26 ++ | ++229 | data.length() as usize, ++ | ^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:243:53 ++ | ++243 | let application_menu = NSMenu::new(nil).autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:244:30 ++ | ++244 | application_menu.setDelegate_(delegate); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:247:45 ++ | ++247 | let menu = NSMenu::new(nil).autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setTitle_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:249:22 ++ | ++249 | menu.setTitle_(menu_title); ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:250:22 ++ | ++250 | menu.setDelegate_(delegate); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSMenu::addItem_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:253:26 ++ | ++253 | menu.addItem_(Self::create_menu_item( ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:261:54 ++ | ++261 | let menu_item = NSMenuItem::new(nil).autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setTitle_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:262:27 ++ | ++262 | menu_item.setTitle_(menu_title); ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSMenuItem::setSubmenu_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:263:27 ++ | ++263 | menu_item.setSubmenu_(menu); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSMenu::addItem_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:264:34 ++ | ++264 | application_menu.addItem_(menu_item); ++ | ^^^^^^^^ ++ ++ Compiling palette v0.7.6 ++warning: use of deprecated method `cocoa::appkit::NSApplication::setWindowsMenu_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:268:25 ++ | ++268 | app.setWindowsMenu_(menu); ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:285:23 ++ | ++285 | dock_menu.setDelegate_(delegate); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSMenu::addItem_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:287:27 ++ | ++287 | dock_menu.addItem_(Self::create_menu_item( ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::_::::empty`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:354:66 ++ | ++354 | ... let mut mask = NSEventModifierFlags::empty(); ++ | ^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSCommandKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:358:59 ++ | ++358 | ... NSEventModifierFlags::NSCommandKeyMask, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSControlKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:362:59 ++ | ++362 | ... NSEventModifierFlags::NSControlKeyMask, ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSAlternateKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:366:59 ++ | ++366 | ... NSEventModifierFlags::NSAlternateKeyMask, ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSShiftKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:370:59 ++ | ++370 | ... NSEventModifierFlags::NSShiftKeyMask, ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSMenuItem::initWithTitle_action_keyEquivalent_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:379:34 ++ | ++379 | ... .initWithTitle_action_keyEquivalent_( ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:384:34 ++ | ++384 | ... .autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSMenuItem::setKeyEquivalentModifierMask_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:388:34 ++ | ++388 | ... item.setKeyEquivalentModifierMask_(mask); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSMenuItem::initWithTitle_action_keyEquivalent_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:391:34 ++ | ++391 | ... .initWithTitle_action_keyEquivalent_( ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:396:34 ++ | ++396 | ... .autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSMenuItem::initWithTitle_action_keyEquivalent_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:400:30 ++ | ++400 | ... .initWithTitle_action_keyEquivalent_( ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:405:30 ++ | ++405 | ... .autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:414:53 ++ | ++414 | let item = NSMenuItem::new(nil).autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:415:52 ++ | ++415 | let submenu = NSMenu::new(nil).autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:416:29 ++ | ++416 | submenu.setDelegate_(delegate); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSMenu::addItem_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:418:33 ++ | ++418 | submenu.addItem_(Self::create_menu_item(item, delegate, actions, keymap)); ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSMenuItem::setSubmenu_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:420:26 ++ | ++420 | item.setSubmenu_(submenu); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setTitle_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:421:26 ++ | ++421 | item.setTitle_(ns_string(name)); ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:425:53 ++ | ++425 | let item = NSMenuItem::new(nil).autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:426:52 ++ | ++426 | let submenu = NSMenu::new(nil).autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:427:29 ++ | ++427 | submenu.setDelegate_(delegate); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSMenuItem::setSubmenu_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:428:26 ++ | ++428 | item.setSubmenu_(submenu); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setTitle_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:429:26 ++ | ++429 | item.setTitle_(ns_string(name)); ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSApplication::setServicesMenu_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:434:33 ++ | ++434 | ... app.setServicesMenu_(item); ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSProcessInfo::operatingSystemVersion`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:447:26 ++ | ++447 | process_info.operatingSystemVersion() ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSOperatingSystemVersion::majorVersion`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:450:13 ++ | ++450 | version.majorVersion as usize, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSOperatingSystemVersion::minorVersion`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:451:13 ++ | ++451 | version.minorVersion as usize, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSOperatingSystemVersion::patchVersion`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:452:13 ++ | ++452 | version.patchVersion as usize, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:484:17 ++ | ++484 | app.setDelegate_(app_delegate); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSApplication::run`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:491:17 ++ | ++491 | app.run(); ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::drain`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:492:18 ++ | ++492 | pool.drain(); ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSApplication::activateIgnoringOtherApps_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:559:17 ++ | ++559 | app.activateIgnoringOtherApps_(ignoring_other_apps.to_objc()); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSOperatingSystemVersion::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:596:72 ++ | ++596 | let min_version = cocoa::foundation::NSOperatingSystemVersion::new(12, 3, 0); ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSURL::initWithString_`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:642:18 ++ | ++642 | .initWithString_(ns_string(url)) ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:643:18 ++ | ++643 | .autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSOpenPanel::setCanChooseDirectories_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:711:27 ++ | ++711 | panel.setCanChooseDirectories_(options.directories.to_objc()); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSOpenPanel::setCanChooseFiles_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:712:27 ++ | ++712 | panel.setCanChooseFiles_(options.files.to_objc()); ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSOpenPanel::setAllowsMultipleSelection_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:713:27 ++ | ++713 | panel.setAllowsMultipleSelection_(options.multiple.to_objc()); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSSavePanel::setCanCreateDirectories`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:715:27 ++ | ++715 | panel.setCanCreateDirectories(true.to_objc()); ++ | ^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSOpenPanel::setResolvesAliases_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:716:27 ++ | ++716 | panel.setResolvesAliases_(false.to_objc()); ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSOpenPanel::URLs`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:721:46 ++ | ++721 | ... let urls = panel.URLs(); ++ | ^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::count`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:722:46 ++ | ++722 | ... for i in 0..urls.count() { ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:723:48 ++ | ++723 | ... let url = urls.objectAtIndex(i); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSURL::isFileURL`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:724:40 ++ | ++724 | ... if url.isFileURL() == YES ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSSavePanel::setDirectoryURL`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:766:27 ++ | ++766 | panel.setDirectoryURL(url); ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSSavePanel::URL`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:777:45 ++ | ++777 | ... let url = panel.URL(); ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSURL::isFileURL`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:778:36 ++ | ++778 | ... if url.isFileURL() == YES { ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSSavePanel::URL`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:779:63 ++ | ++779 | ... result = ns_url_to_path(panel.URL()).ok().map(|mut result| { ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSApplication::setMainMenu_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:910:17 ++ | ++910 | app.setMainMenu_(menu); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::clearContents`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1034:42 ++ | ++1034 | state.pasteboard.clearContents(); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1042:70 ++ | ++1042 | .init_attributed_string(NSString::alloc(nil).init_str("")); ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1048:78 ++ | ++1048 | ... .init_attributed_string(NSString::alloc(nil).init_str(&text)); ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::clearContents`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1058:34 ++ | ++1058 | state.pasteboard.clearContents(); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSRange::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1063:34 ++ | ++1063 | NSRange::new(0, msg_send![attributed_string, length]), ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::setData_forType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1069:30 ++ | ++1069 | ... .setData_forType(rtfd_data, NSPasteboardTypeRTFD); ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSRange::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1073:34 ++ | ++1073 | NSRange::new(0, attributed_string.length()), ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSData::length`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1073:59 ++ | ++1073 | NSRange::new(0, attributed_string.length()), ++ | ^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::setData_forType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1079:30 ++ | ++1079 | ... .setData_forType(rtf_data, NSPasteboardTypeRTF); ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::setString_forType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1086:22 ++ | ++1086 | .setString_forType(plain_text, NSPasteboardTypeString); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::types`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1097:40 ++ | ++1097 | let types: id = pasteboard.types(); ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::dataForType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1101:39 ++ | ++1101 | let data = pasteboard.dataForType(string_type); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSData::bytes`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1104:32 ++ | ++1104 | } else if data.bytes().is_null() { ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSData::bytes`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1110:52 ++ | ++1110 | slice::from_raw_parts(data.bytes() as *mut u8, data.length() as usize); ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSData::length`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1110:77 ++ | ++1110 | slice::from_raw_parts(data.bytes() as *mut u8, data.length() as usize); ++ | ^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::clearContents`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1266:30 ++ | ++1266 | state.pasteboard.clearContents(); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::setData_forType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1275:18 ++ | ++1275 | .setData_forType(text_bytes, NSPasteboardTypeString); ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::setData_forType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1286:22 ++ | ++1286 | .setData_forType(hash_bytes, state.text_hash_pasteboard_type); ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::setData_forType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1295:22 ++ | ++1295 | .setData_forType(metadata_bytes, state.metadata_pasteboard_type); ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::clearContents`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1303:30 ++ | ++1303 | state.pasteboard.clearContents(); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::setData_forType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1313:18 ++ | ++1313 | .setData_forType(bytes, Into::::into(image.format).inner_mut()); ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::types`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1322:36 ++ | ++1322 | let types: id = pasteboard.types(); ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSPasteboard::dataForType`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1324:35 ++ | ++1324 | let data = pasteboard.dataForType(ut_type.inner_mut()); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSData::bytes`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1329:26 ++ | ++1329 | data.bytes() as *mut u8, ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSData::length`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1330:26 ++ | ++1330 | data.length() as usize, ++ | ^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1346:31 ++ | ++1346 | let bytes = unsafe { path.UTF8String() as *const u8 }; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSApplication::setActivationPolicy_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1362:13 ++ | ++1362 | app.setActivationPolicy_(NSApplicationActivationPolicyRegular); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::count`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1421:18 ++ | ++1421 | (0..urls.count()) ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1423:32 ++ | ++1423 | let url = urls.objectAtIndex(i); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSURL::absoluteString`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1424:42 ++ | ++1424 | match CStr::from_ptr(url.absoluteString().UTF8String() as *mut c_char).to_str() { ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1424:59 ++ | ++1424 | match CStr::from_ptr(url.absoluteString().UTF8String() as *mut c_char).to_str() { ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1508:35 ++ | ++1508 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1508:52 ++ | ++1508 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSURL::absoluteString`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1514:28 ++ | ++1514 | CStr::from_ptr(url.absoluteString().UTF8String()).to_string_lossy() ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/platform.rs:1514:45 ++ | ++1514 | CStr::from_ptr(url.absoluteString().UTF8String()).to_string_lossy() ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::appkit::_::::from_bits_retain`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:65:24 ++ | ++65 | NSWindowStyleMask::from_bits_retain(1 << 7); ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:275:12 ++ | ++275 | px(position.x as f32), ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:277:28 ++ | ++277 | window_height - px(position.y as f32), ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::occlusionState`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:481:18 ++ | ++481 | .occlusionState() ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:482:18 ++ | ++482 | .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowOcclusionState::NSWindowOcclusionStateVisible`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:482:51 ++ | ++482 | .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::screen`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:487:76 ++ | ++487 | let display_id = unsafe { display_id_for_screen(self.native_window.screen()) }; ++ | ^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::screen`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:503:50 ++ | ++503 | let screen_size = self.native_window.screen().visibleFrame().into(); ++ | ^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSScreen::visibleFrame`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:503:59 ++ | ++503 | let screen_size = self.native_window.screen().visibleFrame().into(); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::styleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:510:49 ++ | ++510 | let style_mask = self.native_window.styleMask(); ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:511:24 ++ | ++511 | style_mask.contains(NSWindowStyleMask::NSFullScreenWindowMask) ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSFullScreenWindowMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:511:52 ++ | ++511 | style_mask.contains(NSWindowStyleMask::NSFullScreenWindowMask) ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:523:9 ++ | ++523 | window_frame.origin.y = ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:523:9 ++ | ++523 | window_frame.origin.y = ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:524:13 ++ | ++524 | screen_frame.size.height - window_frame.origin.y - window_frame.size.height; ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:524:13 ++ | ++524 | screen_frame.size.height - window_frame.origin.y - window_frame.size.height; ++ | ^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:524:40 ++ | ++524 | screen_frame.size.height - window_frame.origin.y - window_frame.size.height; ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:524:40 ++ | ++524 | screen_frame.size.height - window_frame.origin.y - window_frame.size.height; ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:524:64 ++ | ++524 | screen_frame.size.height - window_frame.origin.y - window_frame.size.height; ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:524:64 ++ | ++524 | screen_frame.size.height - window_frame.origin.y - window_frame.size.height; ++ | ^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:528:21 ++ | ++528 | px((window_frame.origin.x - screen_frame.origin.x) as f32), ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:528:21 ++ | ++528 | px((window_frame.origin.x - screen_frame.origin.x) as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:528:45 ++ | ++528 | px((window_frame.origin.x - screen_frame.origin.x) as f32), ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:528:45 ++ | ++528 | px((window_frame.origin.x - screen_frame.origin.x) as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:529:21 ++ | ++529 | px((window_frame.origin.y + screen_frame.origin.y) as f32), ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:529:21 ++ | ++529 | px((window_frame.origin.y + screen_frame.origin.y) as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:529:45 ++ | ++529 | px((window_frame.origin.y + screen_frame.origin.y) as f32), ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:529:45 ++ | ++529 | px((window_frame.origin.y + screen_frame.origin.y) as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:532:20 ++ | ++532 | px(window_frame.size.width as f32), ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:532:20 ++ | ++532 | px(window_frame.size.width as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:533:20 ++ | ++533 | px(window_frame.size.height as f32), ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:533:20 ++ | ++533 | px(window_frame.size.height as f32), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::contentView`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:540:55 ++ | ++540 | unsafe { NSView::frame(self.native_window.contentView()) }.size; ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:540:13 ++ | ++540 | unsafe { NSView::frame(self.native_window.contentView()) }.size; ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:539:22 ++ | ++539 | let NSSize { width, height, .. } = ++ | ^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:539:29 ++ | ++539 | let NSSize { width, height, .. } = ++ | ^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:552:17 ++ | ++552 | px((frame.size.height - content_layout_rect.size.height) as f32) ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:552:17 ++ | ++552 | px((frame.size.height - content_layout_rect.size.height) as f32) ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSClosableWindowMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:601:40 ++ | ++601 | NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask; ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSTitledWindowMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:601:82 ++ | ++601 | NSWindowStyleMask::NSClosableWindowMask | NSWindowStyleMask::NSTitledWindowMask; ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSResizableWindowMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:604:54 ++ | ++604 | style_mask |= NSWindowStyleMask::NSResizableWindowMask; ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSMiniaturizableWindowMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:608:54 ++ | ++608 | style_mask |= NSWindowStyleMask::NSMiniaturizableWindowMask; ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSFullSizeContentViewWindowMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:612:54 ++ | ++612 | style_mask |= NSWindowStyleMask::NSFullSizeContentViewWindowMask; ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSTitledWindowMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:615:49 ++ | ++615 | style_mask = NSWindowStyleMask::NSTitledWindowMask ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSFullSizeContentViewWindowMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:616:42 ++ | ++616 | | NSWindowStyleMask::NSFullSizeContentViewWindowMask; ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSRect::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:652:39 ++ | ++652 | let window_rect = NSRect::new( ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSPoint::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:653:26 ++ | ++653 | NSPoint::new( ++ | ^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:654:21 ++ | ++654 | screen_frame.origin.x + bounds.origin.x.0 as f64, ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:654:21 ++ | ++654 | screen_frame.origin.x + bounds.origin.x.0 as f64, ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:655:21 ++ | ++655 | screen_frame.origin.y ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:655:21 ++ | ++655 | screen_frame.origin.y ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSSize::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:658:25 ++ | ++658 | NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::initWithContentRect_styleMask_backing_defer_screen_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:661:47 ++ | ++661 | let native_window = native_window.initWithContentRect_styleMask_backing_defer_screen_( ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::contentView`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:679:46 ++ | ++679 | let content_view = native_window.contentView(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:732:27 ++ | ++732 | native_window.setDelegate_(native_window); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setMovable_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:745:27 ++ | ++745 | native_window.setMovable_(is_movable as BOOL); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setContentMinSize_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:748:31 ++ | ++748 | native_window.setContentMinSize_(NSSize { ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:749:21 ++ | ++749 | width: window_min_size.width.to_f64(), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:750:21 ++ | ++750 | height: window_min_size.height.to_f64(), ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setTitlebarAppearsTransparent_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:755:31 ++ | ++755 | native_window.setTitlebarAppearsTransparent_(YES); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setTitleVisibility_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:756:31 ++ | ++756 | native_window.setTitleVisibility_(NSWindowTitleVisibility::NSWindowTitleHidden); ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSView::setAutoresizingMask_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:759:25 ++ | ++759 | native_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++ Compiling palette_derive v0.7.6 ++warning: use of deprecated method `cocoa::appkit::NSView::setWantsBestResolutionOpenGLSurface_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:760:25 ++ | ++760 | native_view.setWantsBestResolutionOpenGLSurface_(YES); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSView::setWantsLayer`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:767:25 ++ | ++767 | native_view.setWantsLayer(YES); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSView::addSubview_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:773:26 ++ | ++773 | content_view.addSubview_(native_view.autorelease()); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:773:50 ++ | ++773 | content_view.addSubview_(native_view.autorelease()); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::makeFirstResponder_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:774:27 ++ | ++774 | native_window.makeFirstResponder_(native_view); ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setLevel_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:778:35 ++ | ++778 | native_window.setLevel_(NSNormalWindowLevel); ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setAcceptsMouseMovedEvents_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:779:35 ++ | ++779 | native_window.setAcceptsMouseMovedEvents_(YES); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:782:63 ++ | ++782 | let tabbing_id = NSString::alloc(nil).init_str(tabbing_identifier.as_str()); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSRect::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:793:47 ++ | ++793 | initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSPoint::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:793:60 ++ | ++793 | initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSSize::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:793:81 ++ | ++793 | initWithRect: NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)) ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:799:79 ++ | ++799 | msg_send![native_view, addTrackingArea: tracking_area.autorelease()]; ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setLevel_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:801:35 ++ | ++801 | native_window.setLevel_(NSPopUpWindowLevel); ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setCollectionBehavior_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:806:35 ++ | ++806 | native_window.setCollectionBehavior_( ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:807:53 ++ | ++807 | NSWindowCollectionBehavior::NSWindowCollectionBehaviorCanJoinAllSpaces | ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenAuxiliary`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:808:53 ++ | ++808 | NSWindowCollectionBehavior::NSWindowCollectionBehaviorFullScreenAuxiliary ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::styleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:820:22 ++ | ++820 | .styleMask() ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:821:22 ++ | ++821 | .contains(NSWindowStyleMask::NSFullScreenWindowMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSFullScreenWindowMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:821:50 ++ | ++821 | .contains(NSWindowStyleMask::NSFullScreenWindowMask); ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowOrderingMode::NSWindowAbove`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:834:122 ++ | ++834 | ... let _: () = msg_send![main_window, addTabbedWindow: native_window ordered: NSWindowOrderingMode::NSWindowAbove]; ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::makeKeyAndOrderFront_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:846:31 ++ | ++846 | native_window.makeKeyAndOrderFront_(nil); ++ | ^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::orderFront_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:848:31 ++ | ++848 | native_window.orderFront_(nil); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:855:60 ++ | ++855 | NSWindow::setFrameTopLeftPoint_(native_window, window_rect.origin); ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::drain`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:858:18 ++ | ++858 | pool.drain(); ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:903:47 ++ | ++903 | let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:904:44 ++ | ++904 | let key = NSString::alloc(nil).init_str("AppleWindowTabbingMode"); ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setDelegate_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:935:32 ++ | ++935 | this.native_window.setDelegate_(nil); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::close`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:941:28 ++ | ++941 | window.close(); ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:942:28 ++ | ++942 | window.autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setContentSize_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:972:28 ++ | ++972 | window.setContentSize_(NSSize { ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:973:25 ++ | ++973 | width: size.width.0 as f64, ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:974:25 ++ | ++974 | height: size.height.0 as f64, ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::screen`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1034:54 ++ | ++1034 | let screen = self.0.lock().native_window.screen(); ++ | ^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1041:38 ++ | ++1041 | NSString::alloc(nil).init_str("NSScreenNumber"), ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::mouseLocationOutsideOfEventStream`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1055:18 ++ | ++1055 | .mouseLocationOutsideOfEventStream() ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1064:37 ++ | ++1064 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSControlKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1064:68 ++ | ++1064 | let control = modifiers.contains(NSEventModifierFlags::NSControlKeyMask); ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1065:33 ++ | ++1065 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSAlternateKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1065:64 ++ | ++1065 | let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask); ++ | ^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1066:35 ++ | ++1066 | let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSShiftKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1066:66 ++ | ++1066 | let shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask); ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1067:37 ++ | ++1067 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSCommandKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1067:68 ++ | ++1067 | let command = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask); ++ | ^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1068:38 ++ | ++1068 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSFunctionKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1068:69 ++ | ++1068 | let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1085:31 ++ | ++1085 | on: modifiers.contains(NSEventModifierFlags::NSAlphaShiftKeyMask), ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSEventModifierFlags::NSAlphaShiftKeyMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1085:62 ++ | ++1085 | on: modifiers.contains(NSEventModifierFlags::NSAlphaShiftKeyMask), ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::isKeyWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1202:46 ++ | ++1202 | unsafe { self.0.lock().native_window.isKeyWindow() == YES } ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setOpaque_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1241:32 ++ | ++1241 | this.native_window.setOpaque_(opaque as BOOL); ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setBackgroundColor_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1248:32 ++ | ++1248 | this.native_window.setBackgroundColor_(background_color); ++ | ^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSEvent::windowNumber`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1260:56 ++ | ++1260 | let window_number = this.native_window.windowNumber(); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::contentView`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1272:59 ++ | ++1272 | let content_view = this.native_window.contentView(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSView::setAutoresizingMask_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1276:31 ++ | ++1276 | blur_view.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowOrderingMode::NSWindowBelow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1281:59 ++ | ++1281 | positioned: NSWindowOrderingMode::NSWindowBelow ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1284:56 ++ | ++1284 | this.blurred_view = Some(blur_view.autorelease()); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::miniaturize_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1317:20 ++ | ++1317 | window.miniaturize_(nil); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::zoom_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1327:28 ++ | ++1327 | window.zoom_(nil); ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::toggleFullScreen_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1339:28 ++ | ++1339 | window.toggleFullScreen_(nil); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::styleMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1351:18 ++ | ++1351 | .styleMask() ++ | ^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1352:18 ++ | ++1352 | .contains(NSWindowStyleMask::NSFullScreenWindowMask) ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSFullScreenWindowMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1352:46 ++ | ++1352 | .contains(NSWindowStyleMask::NSFullScreenWindowMask) ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1485:55 ++ | ++1485 | let domain = NSString::alloc(nil).init_str("NSGlobalDomain"); ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1486:52 ++ | ++1486 | let key = NSString::alloc(nil).init_str("AppleActionOnDoubleClick"); ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::miniaturize_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1503:36 ++ | ++1503 | ... window.miniaturize_(nil); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::zoom_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1506:36 ++ | ++1506 | ... window.zoom_(nil); ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::zoom_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1510:36 ++ | ++1510 | ... window.zoom_(nil); ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::zoom_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1513:36 ++ | ++1513 | ... window.zoom_(nil); ++ | ^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::occlusionState`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1887:14 ++ | ++1887 | .occlusionState() ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1888:14 ++ | ++1888 | .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowOcclusionState::NSWindowOcclusionStateVisible`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1888:47 ++ | ++1888 | .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible) ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSOperatingSystemVersion::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1908:49 ++ | ++1908 | let min_version = NSOperatingSystemVersion::new(15, 3, 0); ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setTitlebarAppearsTransparent_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1912:32 ++ | ++1912 | lock.native_window.setTitlebarAppearsTransparent_(NO); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSOperatingSystemVersion::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1921:49 ++ | ++1921 | let min_version = NSOperatingSystemVersion::new(15, 3, 0); ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::setTitlebarAppearsTransparent_`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1925:32 ++ | ++1925 | lock.native_window.setTitlebarAppearsTransparent_(YES); ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSProcessInfo::isOperatingSystemAtLeastVersion`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1931:46 ++ | ++1931 | unsafe { NSProcessInfo::processInfo(nil).isOperatingSystemAtLeastVersion(version) } ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::appkit::NSWindow::isKeyWindow`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:1953:49 ++ | ++1953 | let is_active = unsafe { lock.native_window.isKeyWindow() == YES }; ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2077:30 ++ | ++2077 | Size::::from(old_frame.size) ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSRect::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2170:17 ++ | ++2170 | NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSPoint::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2170:30 ++ | ++2170 | NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSSize::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2170:51 ++ | ++2170 | NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)), ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSRect::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2172:21 ++ | ++2172 | NSRect::new( ++ | ^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSPoint::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2173:26 ++ | ++2173 | NSPoint::new( ++ | ^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2174:21 ++ | ++2174 | frame.origin.x + bounds.origin.x.0 as f64, ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2174:21 ++ | ++2174 | frame.origin.x + bounds.origin.x.0 as f64, ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2175:21 ++ | ++2175 | frame.origin.y + frame.size.height ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2175:21 ++ | ++2175 | frame.origin.y + frame.size.height ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2175:38 ++ | ++2175 | frame.origin.y + frame.size.height ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2175:38 ++ | ++2175 | frame.origin.y + frame.size.height ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSSize::new`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2179:25 ++ | ++2179 | NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), ++ | ^^^ ++ ++warning: use of deprecated method `cocoa::appkit::_::::contains`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2192:24 ++ | ++2192 | if !style_mask.contains(NSWindowStyleMask::NSFullSizeContentViewWindowMask) { ++ | ^^^^^^^^ ++ ++warning: use of deprecated associated constant `cocoa::appkit::NSWindowStyleMask::NSFullSizeContentViewWindowMask`: use the objc2-app-kit crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2192:52 ++ | ++2192 | if !style_mask.contains(NSWindowStyleMask::NSFullSizeContentViewWindowMask) { ++ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2193:13 ++ | ++2193 | frame.origin.y -= frame.size.height - content_layout_rect.size.height; ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2193:13 ++ | ++2193 | frame.origin.y -= frame.size.height - content_layout_rect.size.height; ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2193:31 ++ | ++2193 | frame.origin.y -= frame.size.height - content_layout_rect.size.height; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2193:31 ++ | ++2193 | frame.origin.y -= frame.size.height - content_layout_rect.size.height; ++ | ^^^^^^^^^^^^^^^^^ ++ ++ Compiling der v0.7.10 ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2324:20 ++ | ++2324 | let window_x = position.x - frame.origin.x; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2324:33 ++ | ++2324 | let window_x = position.x - frame.origin.x; ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::x`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2324:33 ++ | ++2324 | let window_x = position.x - frame.origin.x; ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2325:20 ++ | ++2325 | let window_y = frame.size.height - (position.y - frame.origin.y); ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2325:20 ++ | ++2325 | let window_y = frame.size.height - (position.y - frame.origin.y); ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2325:41 ++ | ++2325 | let window_y = frame.size.height - (position.y - frame.origin.y); ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::origin`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2325:54 ++ | ++2325 | let window_y = frame.size.height - (position.y - frame.origin.y); ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSPoint::y`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2325:54 ++ | ++2325 | let window_y = frame.size.height - (position.y - frame.origin.y); ++ | ^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSFastEnumeration::iter`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2383:36 ++ | ++2383 | for file in unsafe { filenames.iter() } { ++ | ^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2458:58 ++ | ++2458 | let screen_number_key: id = NSString::alloc(nil).init_str("NSScreenNumber"); ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSDictionary::objectForKey_`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2459:48 ++ | ++2459 | let screen_number = device_description.objectForKey_(screen_number_key); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::isEqualToString`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2491:23 ++ | ++2491 | if class_name.isEqualToString("CAChameleonLayer") { ++ | ^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2504:56 ++ | ++2504 | let test_string: id = NSString::alloc(nil).init_str("Saturat").autorelease(); ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2504:76 ++ | ++2504 | let test_string: id = NSString::alloc(nil).init_str("Saturat").autorelease(); ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2507:57 ++ | ++2507 | let description: id = msg_send![filters.objectAtIndex(i), description]; ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSArray::objectAtIndex`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2530:42 ++ | ++2530 | let sublayer = sublayers.objectAtIndex(i); ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2545:9 ++ | ++2545 | frame.size.height = 0.0; ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window.rs:2545:9 ++ | ++2545 | frame.size.height = 0.0; ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac/window_appearance.rs:25:41 ++ | ++25 | CStr::from_ptr(name.UTF8String()) ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::UTF8String`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:78:29 ++ | ++78 | let cstr = self.UTF8String(); ++ | ^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:139:35 ++ | ++139 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:139:52 ++ | ++139 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:145:23 ++ | ++145 | width: px(value.width as f32), ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:146:24 ++ | ++146 | height: px(value.height as f32), ++ | ^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:153:40 ++ | ++153 | let NSSize { width, height } = rect.size; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:153:22 ++ | ++153 | let NSSize { width, height } = rect.size; ++ | ^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:153:29 ++ | ++153 | let NSSize { width, height } = rect.size; ++ | ^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSRect::size`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:160:40 ++ | ++160 | let NSSize { width, height } = rect.size; ++ | ^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::width`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:160:22 ++ | ++160 | let NSSize { width, height } = rect.size; ++ | ^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSSize::height`: use the objc2-foundation crate instead ++ --> crates/gpui/src/platform/mac.rs:160:29 ++ | ++160 | let NSSize { width, height } = rect.size; ++ | ^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/fs/src/fs.rs:450:20 ++ | ++450 | base::{id, nil}, ++ | ^^ ++ | ++ = note: `#[warn(deprecated)]` on by default ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/fs/src/fs.rs:450:24 ++ | ++450 | base::{id, nil}, ++ | ^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSAutoreleasePool`: use the objc2-foundation crate instead ++ --> crates/fs/src/fs.rs:451:26 ++ | ++451 | foundation::{NSAutoreleasePool, NSString}, ++ | ^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSString`: use the objc2-foundation crate instead ++ --> crates/fs/src/fs.rs:451:45 ++ | ++451 | foundation::{NSAutoreleasePool, NSString}, ++ | ^^^^^^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/fs/src/fs.rs:456:50 ++ | ++456 | unsafe fn ns_string(string: &str) -> id { ++ | ^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSString::alloc`: use the objc2-foundation crate instead ++ --> crates/fs/src/fs.rs:457:36 ++ | ++457 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ | ^^^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/fs/src/fs.rs:457:42 ++ | ++457 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/fs/src/fs.rs:460:22 ++ | ++460 | let url: id = msg_send![class!(NSURL), fileURLWithPath: ns_string(path.to_string_lossy().as_ref())]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/fs/src/fs.rs:461:24 ++ | ++461 | let array: id = msg_send![class!(NSArray), arrayWithObject: url]; ++ | ^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/fs/src/fs.rs:462:28 ++ | ++462 | let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; ++ | ^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/fs/src/fs.rs:464:84 ++ | ++464 | let _: id = msg_send![workspace, recycleURLs: array completionHandler: nil]; ++ | ^^^ ++ ++warning: use of deprecated type alias `cocoa::base::id`: use the objc2 crate instead ++ --> crates/fs/src/fs.rs:464:20 ++ | ++464 | let _: id = msg_send![workspace, recycleURLs: array completionHandler: nil]; ++ | ^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSString::init_str`: use the objc2-foundation crate instead ++ --> crates/fs/src/fs.rs:457:47 ++ | ++457 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ | ^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSAutoreleasePool::autorelease`: use the objc2-foundation crate instead ++ --> crates/fs/src/fs.rs:457:64 ++ | ++457 | unsafe { NSString::alloc(nil).init_str(string).autorelease() } ++ | ^^^^^^^^^^^ ++ ++warning: use of deprecated associated function `cocoa::foundation::NSProcessInfo::processInfo`: use the objc2-foundation crate instead ++ --> crates/client/src/telemetry.rs:115:66 ++ | ++115 | let process_info = cocoa::foundation::NSProcessInfo::processInfo(nil); ++ | ^^^^^^^^^^^ ++ | ++ = note: `#[warn(deprecated)]` on by default ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/client/src/telemetry.rs:115:78 ++ | ++115 | let process_info = cocoa::foundation::NSProcessInfo::processInfo(nil); ++ | ^^^ ++ ++warning: use of deprecated constant `cocoa::base::nil`: use the objc2 crate instead ++ --> crates/client/src/telemetry.rs:111:26 ++ | ++111 | use cocoa::base::nil; ++ | ^^^ ++ ++warning: use of deprecated trait `cocoa::foundation::NSProcessInfo`: use the objc2-foundation crate instead ++ --> crates/client/src/telemetry.rs:112:32 ++ | ++112 | use cocoa::foundation::NSProcessInfo; ++ | ^^^^^^^^^^^^^ ++ ++warning: use of deprecated method `cocoa::foundation::NSProcessInfo::operatingSystemVersion`: use the objc2-foundation crate instead ++ --> crates/client/src/telemetry.rs:116:40 ++ | ++116 | let version = process_info.operatingSystemVersion(); ++ | ^^^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSOperatingSystemVersion::majorVersion`: use the objc2-foundation crate instead ++ --> crates/client/src/telemetry.rs:118:17 ++ | ++118 | version.majorVersion as usize, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSOperatingSystemVersion::minorVersion`: use the objc2-foundation crate instead ++ --> crates/client/src/telemetry.rs:119:17 ++ | ++119 | version.minorVersion as usize, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++warning: use of deprecated field `cocoa::foundation::NSOperatingSystemVersion::patchVersion`: use the objc2-foundation crate instead ++ --> crates/client/src/telemetry.rs:120:17 ++ | ++120 | version.patchVersion as usize, ++ | ^^^^^^^^^^^^^^^^^^^^ ++ ++ diff --git a/.reapply-patches/macOS-modernization/CHECKPOINT b/.reapply-patches/macOS-modernization/CHECKPOINT new file mode 100644 index 00000000000000..b213df36a03090 --- /dev/null +++ b/.reapply-patches/macOS-modernization/CHECKPOINT @@ -0,0 +1,2 @@ +DATE=20250917 +COVERS=0031 diff --git a/.reapply-patches/macOS-modernization/README.md b/.reapply-patches/macOS-modernization/README.md new file mode 100644 index 00000000000000..52cf130744680b --- /dev/null +++ b/.reapply-patches/macOS-modernization/README.md @@ -0,0 +1,11 @@ +macOS Modernization Patch Series + +Current Checkpoint + +- Use `20250917-cumulative.patch` for the latest full checkpoint (includes 0001–0031 + subsequent fixes). + - Quick apply on fresh `upstream/main`: + - `git switch -c macOS-modernization- upstream/main` + - `git apply --index .reapply-patches/macOS-modernization/20250917-cumulative.patch` + - `git commit -m "macOS: apply 20250917 cumulative checkpoint"` + +See docs/patch_workflow.md for a comprehensive, reusable guide. From ac437fab9c559c8f60263f3de1f8d15923cf50e7 Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Wed, 17 Sep 2025 12:38:32 +0800 Subject: [PATCH 04/38] enforce: add patch validation script and pre-push hook (requires CHECKPOINT + cumulative) --- .githooks/pre-push | 19 +++++++++ script/validate-patch-setup.sh | 74 ++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100755 .githooks/pre-push create mode 100755 script/validate-patch-setup.sh diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 00000000000000..bdfc8ef7aa7a9b --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# Enforce presence of CHECKPOINT and a cumulative patch in the patch series before pushing. +# Bypass by setting ALLOW_PRE_PUSH_BYPASS=1 +set -euo pipefail + +if [[ "${ALLOW_PRE_PUSH_BYPASS:-0}" == "1" ]]; then + exit 0 +fi + +# Validate default series; allow override via PATCH_SERIES env var +SERIES="${PATCH_SERIES:-.reapply-patches/macOS-modernization}" + +SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" && pwd) +ROOT_DIR=$(cd -- "$SCRIPT_DIR/.." && pwd) + +"$ROOT_DIR/script/validate-patch-setup.sh" --series "$SERIES" + +exit 0 + diff --git a/script/validate-patch-setup.sh b/script/validate-patch-setup.sh new file mode 100755 index 00000000000000..6dfe2b20a6a3af --- /dev/null +++ b/script/validate-patch-setup.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Validate that a patch series directory contains a CHECKPOINT and at least one +# cumulative patch. Enforces presence and basic consistency. +# +# Usage: +# script/validate-patch-setup.sh [--series ] +# Default series: .reapply-patches/macOS-modernization + +ROOT_DIR=$(cd -- "$(dirname -- "$0")/.." && pwd) +cd "$ROOT_DIR" + +SERIES=".reapply-patches/macOS-modernization" +while [[ $# -gt 0 ]]; do + case "$1" in + --series) SERIES="$2"; shift 2;; + -h|--help) echo "Usage: $0 [--series ]"; exit 0;; + *) echo "Unknown arg: $1" >&2; exit 1;; + esac +done + +fail() { echo "[patch-validate] $*" >&2; exit 1; } +warn() { echo "[patch-validate] warn: $*" >&2; } +info() { echo "[patch-validate] $*" >&2; } + +[[ -d "$SERIES" ]] || fail "series directory missing: $SERIES" + +CKPT="$SERIES/CHECKPOINT" +[[ -f "$CKPT" ]] || fail "missing CHECKPOINT in $SERIES" + +DATE=$(awk -F= '/^DATE=/{print $2}' "$CKPT" | tr -d '\r\n' || true) +COVERS=$(awk -F= '/^COVERS=/{print $2}' "$CKPT" | tr -d '\r\n' || true) +[[ "$DATE" =~ ^[0-9]{8}$ ]] || fail "CHECKPOINT DATE invalid or missing (expected YYYYMMDD), got: '${DATE:-}'" +[[ "$COVERS" =~ ^[0-9]{4}$ ]] || fail "CHECKPOINT COVERS invalid or missing (expected 4 digits), got: '${COVERS:-}'" + +shopt -s nullglob +cums=("$SERIES"/*-cumulative.patch) +shopt -u nullglob +[[ ${#cums[@]} -gt 0 ]] || fail "no cumulative patch found in $SERIES" + +# Prefer the file matching DATE; otherwise accept the lexicographically last. +EXPECT="$SERIES/$DATE-cumulative.patch" +if [[ -f "$EXPECT" ]]; then + target="$EXPECT" +else + warn "expected $DATE-cumulative.patch not found; using latest cumulative" + target=$(ls -1 "$SERIES"/*-cumulative.patch | sort | tail -n1) +fi + +# Quick sanity: cumulative patch should start with a diff header +head -n1 "$target" | grep -q '^diff --git ' || fail "cumulative patch $target appears malformed (no diff header)" + +# If numbered patches exist, ensure max >= COVERS (COVERS is the last included in checkpoint) +shopt -s nullglob +nums=() +for p in "$SERIES"/00*.patch; do + [[ -f "$p" ]] || continue + base=$(basename "$p") + num=$(printf "%s" "$base" | sed -E 's/^([0-9]{4}).*/\1/') + [[ "$num" =~ ^[0-9]{4}$ ]] && nums+=("$num") +done +shopt -u nullglob +if [[ ${#nums[@]} -gt 0 ]]; then + IFS=$'\n' nums_sorted=($(sort <<<"${nums[*]}")); unset IFS + max_num=${nums_sorted[-1]} + if (( 10#$max_num < 10#$COVERS )); then + fail "CHECKPOINT COVERS=$COVERS exceeds highest numbered patch ($max_num)" + fi +fi + +info "series ok: $SERIES (DATE=$DATE, COVERS=$COVERS, cumulative=$(basename "$target"))" +exit 0 + From 5d8d575d65a4a8edcbaaa7bd65bf3595de1a5aae Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Wed, 17 Sep 2025 12:42:55 +0800 Subject: [PATCH 05/38] docs(workflow): document pre-push validation, PATCH_SERIES override, and bypass --- docs/patch_workflow.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/patch_workflow.md b/docs/patch_workflow.md index ddb021870b804c..5d4d37d3d5093a 100644 --- a/docs/patch_workflow.md +++ b/docs/patch_workflow.md @@ -39,6 +39,18 @@ Aliases (repo-local) - `git wtl` → `git worktree list -v` - `git wtr` → `script/cleanup-worktrees.sh` +Pre-push Validation + +- The repo includes a pre-push hook (`.githooks/pre-push`) that enforces a valid patch series before pushing. +- It runs `script/validate-patch-setup.sh` to ensure: + - the series directory exists (default `.reapply-patches/macOS-modernization`), + - a `CHECKPOINT` file is present and well-formed (`DATE=YYYYMMDD`, `COVERS=NNNN`), + - at least one `YYYYMMDD-cumulative.patch` exists and looks valid, + - if numbered patches exist, the highest number is ≥ `COVERS`. +- Override/advanced: + - Use `PATCH_SERIES=/path/to/series git push` to validate a different series. + - Bypass (rare): `ALLOW_PRE_PUSH_BYPASS=1 git push`. + Typical Flows - Fresh session, defaults end-to-end: @@ -87,4 +99,3 @@ Porting This Workflow - Copy the `script/` helpers and `.githooks/pre-commit` to new repos; run `script/setup-repo.sh` to install aliases and hooks. - Create a `.reapply-patches//` folder with `README.md`, numbered patches, a `CHECKPOINT` file, and a `YYYYMMDD-cumulative.patch`. - Update series names and script messages as needed. - From fbdc53e248ca61ddf1d8f2e964181582bee1bb24 Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Wed, 17 Sep 2025 12:50:30 +0800 Subject: [PATCH 06/38] enforce(main): protect main to workflow-only changes; agentic inline docs for scripts/docs --- .githooks/pre-push | 60 +++++++++++++++++++++++++++------- docs/patch_workflow.md | 12 +++---- script/validate-patch-setup.sh | 5 ++- 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/.githooks/pre-push b/.githooks/pre-push index bdfc8ef7aa7a9b..eca65511ce7872 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -1,19 +1,57 @@ #!/usr/bin/env bash -# Enforce presence of CHECKPOINT and a cumulative patch in the patch series before pushing. -# Bypass by setting ALLOW_PRE_PUSH_BYPASS=1 +# Agentic pre-push guard +# - Validates patch series (CHECKPOINT + cumulative present) +# - Protects main: only workflow files may change on pushes to main +# +# Bypass: +# - Validation: ALLOW_PRE_PUSH_BYPASS=1 +# - Main workflow-only restriction: ALLOW_MAIN_CODE_PUSH=1 set -euo pipefail -if [[ "${ALLOW_PRE_PUSH_BYPASS:-0}" == "1" ]]; then - exit 0 -fi - -# Validate default series; allow override via PATCH_SERIES env var -SERIES="${PATCH_SERIES:-.reapply-patches/macOS-modernization}" - SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" && pwd) ROOT_DIR=$(cd -- "$SCRIPT_DIR/.." && pwd) -"$ROOT_DIR/script/validate-patch-setup.sh" --series "$SERIES" +# 1) Patch series validation (quick fail if misconfigured) +if [[ "${ALLOW_PRE_PUSH_BYPASS:-0}" != "1" ]]; then + SERIES="${PATCH_SERIES:-.reapply-patches/macOS-modernization}" + "$ROOT_DIR/script/validate-patch-setup.sh" --series "$SERIES" +fi -exit 0 +# 2) Protect main: limit changes to workflow-only files +# Parse refs from stdin: +# For each main ref, diff remote..local and ensure paths match allowlist. +if [[ "${ALLOW_MAIN_CODE_PUSH:-0}" != "1" ]]; then + allow_re='^(\.reapply-patches/|script/|\.githooks/|docs/|AGENTS\.md$)' + while read -r local_ref local_sha remote_ref remote_sha; do + # Stop when no more refs (some Git versions pass nothing on dry runs) + [[ -z "${local_ref:-}" ]] && continue + # Only check heads pushes that target main (either side) + case "$local_ref $remote_ref" in + refs/heads/main*|*refs/heads/main*) + # When remote_sha is all zeros, use upstream remote tip if available + base="$remote_sha" + if [[ "$remote_sha" =~ ^0+$ ]]; then + # Try origin/main as a best-effort base if remote tip unknown + base=$(git rev-parse --quiet --verify origin/main || echo "$remote_sha") + fi + # Compute changed files between base..local + changed=$(git diff --name-only "$base" "$local_sha" || true) + bad=() + while IFS= read -r f; do + [[ -z "$f" ]] && continue + if ! [[ "$f" =~ $allow_re ]]; then + bad+=("$f") + fi + done <<< "$changed" + if (( ${#bad[@]} > 0 )); then + echo "[pre-push] Refuses to push non-workflow changes to main:" >&2 + printf ' %s\n' "${bad[@]}" >&2 + echo "Set ALLOW_MAIN_CODE_PUSH=1 to bypass." >&2 + exit 1 + fi + ;; + esac + done +fi +exit 0 diff --git a/docs/patch_workflow.md b/docs/patch_workflow.md index 5d4d37d3d5093a..579a006f9f3fd5 100644 --- a/docs/patch_workflow.md +++ b/docs/patch_workflow.md @@ -20,10 +20,10 @@ Repo Structure Helper Scripts -- `script/setup-repo.sh` … idempotent repo setup: hooksPath, aliases, am.threeWay, apply.whitespace=fix, rerere.enabled. +- `script/setup-repo.sh` … idempotent repo setup: hooksPath, aliases, am.threeWay, apply.whitespace=fix, rerere.enabled. (Agentic hint: run this first in any new clone.) - `script/gstart.sh` … one command: setup → create worktree → apply latest checkpoint → apply deltas beyond checkpoint → push. - `script/new-worktree.sh` … create a worktree + branch from latest upstream (auto picks newer of main/nightly). -- `script/new-worktree-apply-cumulative.sh` … create worktree, apply checkpoint, then apply numbered deltas based on `CHECKPOINT`; optional `--push`. +- `script/new-worktree-apply-cumulative.sh` … create worktree, apply checkpoint, then apply numbered deltas based on `CHECKPOINT`; optional `--push`. (Agentic hint: prints WORKTREE= and BRANCH= on success.) - `script/apply-cumulative.sh` … apply checkpoint (and deltas) in current repo (non-worktree). - `script/cleanup-worktrees.sh` … prune stale worktrees and remove empty `target/bench-*` dirs. - `script/bench-macos.sh` … benchmark baseline vs patched builds (macOS, optional release build, worktree-aware). @@ -79,23 +79,23 @@ Generating New Deltas and Checkpoints Apply Semantics -- Checkpoint (raw diff): `git apply --index` (scripts prefer direct apply with whitespace fix; 3-way fallback when needed). +- Checkpoint (raw diff): `git apply --index` (scripts prefer direct apply with whitespace fix; 3-way fallback only when needed). - Numbered patches (mail format): `git am -3 000*.patch`. - Deltas beyond checkpoint: scripts automatically apply 000*.patch with numbers greater than `CHECKPOINT.COVERS`. Warnings and What’s OK -- `new blank line at EOF` during apply: benign (intentional final newline). We don’t remove legitimate blank lines; we only trim trailing spaces. +- `new blank line at EOF` during apply: benign (intentional final newline). We don’t remove legitimate blank lines; we only trim trailing spaces. (Agentic hint: look for actual patch failures, not cosmetic warnings.) - Fallbacks in logs: the scripts prefer direct apply when `--check` passes; they only emit 3-way fallback when truly necessary. Worktree Structure - Worktrees live under `worktrees/` and are linked to local branches. -- Don’t commit in the primary working tree (root); a pre-commit hook blocks it by default. +- Don’t commit in the primary working tree (root); a pre-commit hook blocks it by default. (Agentic hint: use `git wtn`/`git wta`.) - Use `git wtl` to list worktrees and `git wtr` to clean stale ones. Porting This Workflow -- Copy the `script/` helpers and `.githooks/pre-commit` to new repos; run `script/setup-repo.sh` to install aliases and hooks. +- Copy the `script/` helpers and `.githooks/{pre-commit,pre-push}` to new repos; run `script/setup-repo.sh` to install aliases and hooks. - Create a `.reapply-patches//` folder with `README.md`, numbered patches, a `CHECKPOINT` file, and a `YYYYMMDD-cumulative.patch`. - Update series names and script messages as needed. diff --git a/script/validate-patch-setup.sh b/script/validate-patch-setup.sh index 6dfe2b20a6a3af..fba79ad8108f12 100755 --- a/script/validate-patch-setup.sh +++ b/script/validate-patch-setup.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -# Validate that a patch series directory contains a CHECKPOINT and at least one -# cumulative patch. Enforces presence and basic consistency. +# Validate that a patch series contains a CHECKPOINT and a cumulative patch. +# Agentic hint: Fast-exit on missing bits, prefer helpful errors over silence. # # Usage: # script/validate-patch-setup.sh [--series ] @@ -71,4 +71,3 @@ fi info "series ok: $SERIES (DATE=$DATE, COVERS=$COVERS, cumulative=$(basename "$target"))" exit 0 - From 82b860f030f2fb69799102bf7aa7f962b33c49af Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Wed, 17 Sep 2025 12:53:25 +0800 Subject: [PATCH 07/38] docs+hooks: polish agentic inline docs; add test-workflow.sh for validation + pre-push guard --- .githooks/pre-commit | 5 +- AGENTS.md | 2 +- script/new-worktree-apply-cumulative.sh | 5 +- script/setup-repo.sh | 9 ++- script/test-workflow.sh | 79 +++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 10 deletions(-) create mode 100755 script/test-workflow.sh diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 7ee33508266401..5c0b5c4082bb8f 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -1,5 +1,7 @@ #!/usr/bin/env bash -# Prevent committing in the primary working tree; encourage using worktrees. +# Agentic pre-commit guard +# - Prevents committing in the primary working tree; encourages using worktrees +# - Hint: use `git wtn` / `git wta` to work in a branch-scoped worktree set -euo pipefail GIT_DIR=$(git rev-parse --git-dir) @@ -13,4 +15,3 @@ if [[ "${ALLOW_ROOT_COMMIT:-0}" != "1" ]] && [[ "$GIT_DIR" == "$GIT_COMMON_DIR" fi exit 0 - diff --git a/AGENTS.md b/AGENTS.md index 58ebde193fa5a7..a016af5b9cc18e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,4 +21,4 @@ Documentation - Aliases and common flows - How to generate new deltas and checkpoints - Worktree hygiene and porting this setup to other repos - + - Pre-push safeguards (CHECKPOINT + cumulative required; main protected to workflow-only changes) diff --git a/script/new-worktree-apply-cumulative.sh b/script/new-worktree-apply-cumulative.sh index 400dc0c9bf4a15..fe412d4c24c150 100755 --- a/script/new-worktree-apply-cumulative.sh +++ b/script/new-worktree-apply-cumulative.sh @@ -1,7 +1,9 @@ #!/usr/bin/env bash set -euo pipefail -# Create a new worktree from latest upstream base and apply the cumulative checkpoint, then any deltas. +# Create a new worktree on the newest upstream base and apply the latest +# cumulative checkpoint, then any numbered deltas beyond CHECKPOINT.COVERS. +# Agentic hint: prints WORKTREE= and BRANCH= on success. # Usage: script/new-worktree-apply-cumulative.sh [--patch ] [--branch ] [--base auto|main|nightly] [--push] ROOT_DIR=$(cd -- "$(dirname -- "$0")/.." && pwd) @@ -101,4 +103,3 @@ echo "WORKTREE=$WT_DIR" echo "BRANCH=$BRANCH_NAME" exit 0 - diff --git a/script/setup-repo.sh b/script/setup-repo.sh index ee33868a20f921..5a31d681027271 100755 --- a/script/setup-repo.sh +++ b/script/setup-repo.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -# One-time or per-session setup for this repo to enable a worktree-first workflow -# and patch management helpers. +# One-time or per-session setup for worktree-first + patch workflow +# Agentic hint: run this in any new clone before using aliases. # # Usage: # script/setup-repo.sh [--apply-checkpoint] [--push] [--branch ] [--base auto|main|nightly] @@ -29,7 +29,7 @@ while [[ $# -gt 0 ]]; do esac done -# hooks +# hooks (ensure repo uses committed hooks) git config --local core.hooksPath .githooks || true # patch-friendly git config @@ -37,7 +37,7 @@ git config --local am.threeWay true || true git config --local apply.whitespace fix || true git config --local rerere.enabled true || true -# aliases +# aliases (worktree lifecycle + patch helpers) git config --local alias.wtn "!script/new-worktree.sh --branch" || true git config --local alias.wta "!script/new-worktree-apply-cumulative.sh" || true git config --local alias.gta "!script/new-worktree-apply-cumulative.sh --push" || true @@ -68,4 +68,3 @@ if [[ $DO_APPLY -eq 1 ]]; then fi echo "Setup complete." - diff --git a/script/test-workflow.sh b/script/test-workflow.sh new file mode 100755 index 00000000000000..d062d2d98e6687 --- /dev/null +++ b/script/test-workflow.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Minimal test harness for the patch/worktree workflow scripts and hooks. +# Agentic hint: runs in a temp repo under target/, does not touch this repo. + +ROOT_DIR=$(cd -- "$(dirname -- "$0")/.." && pwd) +TEST_ROOT="$ROOT_DIR/target/workflow-tests" +mkdir -p "$TEST_ROOT" + +pass=0; fail=0 +it() { printf "\n== %s ==\n" "$*"; } +ok() { echo "PASS: $*"; pass=$((pass+1)); } +ng() { echo "FAIL: $*"; fail=$((fail+1)); } + +mkrepo() { + local name="$1"; local dir="$TEST_ROOT/$name"; rm -rf "$dir"; mkdir -p "$dir"; cd "$dir"; git init -q; echo "# t" > README.md; git add README.md; git commit -qm init; + # copy hooks/scripts minimal set for tests + mkdir -p .githooks script + cp "$ROOT_DIR/.githooks/pre-push" .githooks/ + cp "$ROOT_DIR/script/validate-patch-setup.sh" script/ + chmod +x .githooks/pre-push script/validate-patch-setup.sh + git config core.hooksPath .githooks +} + +# 1) validate-patch-setup: OK with valid series +it "validate: OK when series has CHECKPOINT + cumulative" +mkrepo ok-valid +mkdir -p .reapply-patches/macOS-modernization +cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch <<'EOF' +diff --git a/FOO b/FOO +new file mode 100644 +index 0000000000..e69de29bb2 +--- /dev/null ++++ b/FOO +EOF +if "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization; then ok valid; else ng valid; fi + +# 2) validate-patch-setup: FAIL when CHECKPOINT missing +it "validate: FAIL when CHECKPOINT missing" +mkrepo fail-no-ckpt +mkdir -p .reapply-patches/macOS-modernization +touch .reapply-patches/macOS-modernization/20250101-cumulative.patch +if "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization; then ng missing-ckpt; else ok missing-ckpt; fi + +# 3) pre-push: allow workflow-only change on main +it "pre-push: allow workflow-only change on main" +mkrepo hook-allow +mkdir -p .reapply-patches/macOS-modernization +cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch +git add .reapply-patches +git commit -qm "workflow change" +local_ref="refs/heads/main"; local_sha=$(git rev-parse HEAD); remote_ref="refs/heads/main"; remote_sha=$(printf '0%.0s' {1..40}) +if PATCH_SERIES=.reapply-patches/macOS-modernization "$ROOT_DIR/.githooks/pre-push" <<<"$local_ref $local_sha $remote_ref $remote_sha"; then ok allow-main; else ng allow-main; fi + +# 4) pre-push: block non-workflow change on main +it "pre-push: block non-workflow change on main" +mkrepo hook-block +mkdir -p .reapply-patches/macOS-modernization +cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch +echo hi > random.txt; git add random.txt .reapply-patches; git commit -qm "non-workflow change" +local_ref="refs/heads/main"; local_sha=$(git rev-parse HEAD); remote_ref="refs/heads/main"; remote_sha=$(printf '0%.0s' {1..40}) +if PATCH_SERIES=.reapply-patches/macOS-modernization "$ROOT_DIR/.githooks/pre-push" <<<"$local_ref $local_sha $remote_ref $remote_sha"; then ng block-main; else ok block-main; fi + +printf "\nSummary: %d passed, %d failed\n" "$pass" "$fail" +exit $((fail==0?0:1)) + From 7499c43f349dbcf5e7bcb5a93c23e7712da388a2 Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Wed, 17 Sep 2025 12:58:56 +0800 Subject: [PATCH 08/38] polish: agentic inline docs across hooks/scripts; expand test-workflow.sh for broader coverage --- script/test-workflow.sh | 93 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/script/test-workflow.sh b/script/test-workflow.sh index d062d2d98e6687..3ff004c1238866 100755 --- a/script/test-workflow.sh +++ b/script/test-workflow.sh @@ -77,3 +77,96 @@ if PATCH_SERIES=.reapply-patches/macOS-modernization "$ROOT_DIR/.githooks/pre-pu printf "\nSummary: %d passed, %d failed\n" "$pass" "$fail" exit $((fail==0?0:1)) +# 5) validate-patch-setup: FAIL when DATE invalid +it "validate: FAIL when CHECKPOINT DATE invalid" +mkrepo fail-bad-date +mkdir -p .reapply-patches/macOS-modernization +cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch +if "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization; then ng bad-date; else ok bad-date; fi + +# 6) validate-patch-setup: FAIL when COVERS invalid +it "validate: FAIL when CHECKPOINT COVERS invalid" +mkrepo fail-bad-covers +mkdir -p .reapply-patches/macOS-modernization +cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch +if "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization; then ng bad-covers; else ok bad-covers; fi + +# 7) validate-patch-setup: FAIL when cumulative header malformed +it "validate: FAIL when cumulative lacks diff header" +mkrepo fail-bad-cumulative +mkdir -p .reapply-patches/macOS-modernization +cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch +if "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization; then ng bad-cum; else ok bad-cum; fi + +# 8) validate-patch-setup: FAIL when COVERS exceeds highest numbered patch +it "validate: FAIL when COVERS > highest 000X" +mkrepo fail-covers-exceeds +mkdir -p .reapply-patches/macOS-modernization +cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch +touch .reapply-patches/macOS-modernization/0001-test.patch +if "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization; then ng covers-exceeds; else ok covers-exceeds; fi + +# 9) new-worktree-apply-cumulative.sh: creates worktree and applies checkpoint +it "new-worktree-apply-cumulative: applies checkpoint in new worktree" +name=apply-wt; dir="$TEST_ROOT/$name"; rm -rf "$dir"; mkdir -p "$dir"; cd "$dir"; git init -q; echo t > README.md; git add README.md; git commit -qm init; +# fake upstream remote pointing to this repo itself (simulate upstream/main) +git checkout -qb main; git config user.email a@b; git config user.name t +mkdir -p .reapply-patches/macOS-modernization +cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch <<'EOF' +diff --git a/FOO b/FOO +new file mode 100644 +index 0000000000..e69de29bb2 +--- /dev/null ++++ b/FOO +EOF +git add .reapply-patches; git commit -qm series +mkdir -p upstream.git; git init -q --bare upstream.git; git remote add upstream "$dir/upstream.git"; git push upstream HEAD:main >/dev/null +# copy scripts +mkdir -p script; cp "$ROOT_DIR/script/new-worktree-apply-cumulative.sh" script/ +chmod +x script/new-worktree-apply-cumulative.sh +out=$(script/new-worktree-apply-cumulative.sh); echo "$out" +wt=$(printf "%s\n" "$out" | sed -n 's/^WORKTREE=\(.*\)$/\1/p') +br=$(printf "%s\n" "$out" | sed -n 's/^BRANCH=\(.*\)$/\1/p') +if [[ -n "$wt" && -d "$wt" ]] && git -C "$wt" rev-parse HEAD >/dev/null 2>&1 && [[ -f "$wt/FOO" ]]; then ok apply-wt; else ng apply-wt; fi + +# 10) apply-cumulative.sh in-place apply on current repo +it "apply-cumulative: applies checkpoint in current repo" +name=apply-local; dir="$TEST_ROOT/$name"; rm -rf "$dir"; mkdir -p "$dir"; cd "$dir"; git init -q; echo t > README.md; git add README.md; git commit -qm init +mkdir -p .reapply-patches/macOS-modernization +cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch <<'EOF' +diff --git a/BAR b/BAR +new file mode 100644 +index 0000000000..e69de29bb2 +--- /dev/null ++++ b/BAR +EOF +cp "$ROOT_DIR/script/apply-cumulative.sh" script/; chmod +x script/apply-cumulative.sh +script/apply-cumulative.sh +if [[ -f BAR ]]; then ok apply-local; else ng apply-local; fi + +printf "\nSummary: %d passed, %d failed\n" "$pass" "$fail" +exit $((fail==0?0:1)) From 06afa8c9f1e9e6678203a562c59dcdc12b4bbf48 Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Wed, 17 Sep 2025 13:03:15 +0800 Subject: [PATCH 09/38] tests: add bats-core test suite + bootstrap; cover validation, pre-push guard, apply scripts; docs polished --- script/bootstrap-tests.sh | 40 ++++++++++++++++ script/test.sh | 24 ++++++++++ test/apply_scripts.bats | 45 ++++++++++++++++++ test/pre_push.bats | 39 +++++++++++++++ test/validate_patch_setup.bats | 86 ++++++++++++++++++++++++++++++++++ 5 files changed, 234 insertions(+) create mode 100755 script/bootstrap-tests.sh create mode 100755 script/test.sh create mode 100644 test/apply_scripts.bats create mode 100644 test/pre_push.bats create mode 100644 test/validate_patch_setup.bats diff --git a/script/bootstrap-tests.sh b/script/bootstrap-tests.sh new file mode 100755 index 00000000000000..03b194ea7aecaf --- /dev/null +++ b/script/bootstrap-tests.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Bootstrap test dependencies (bats-core, bats-assert, bats-support) under tooling/ +# Agentic hint: idempotent; re-runs safely. Requires network access for initial clone. + +ROOT_DIR=$(cd -- "$(dirname -- "$0")/.." && pwd) +TOOLS_DIR="$ROOT_DIR/tooling" +mkdir -p "$TOOLS_DIR" + +fetch_repo() { + local url="$1"; local dest="$2"; local ref="${3:-}"; + if [[ -d "$dest/.git" ]]; then + git -C "$dest" fetch -q --tags --prune + [[ -n "$ref" ]] && git -C "$dest" checkout -q "$ref" || true + else + git clone -q "$url" "$dest" + [[ -n "$ref" ]] && git -C "$dest" checkout -q "$ref" || true + fi +} + +# bats-core +if [[ ! -x "$TOOLS_DIR/bats-core/bin/bats" ]]; then + fetch_repo https://github.com/bats-core/bats-core.git "$TOOLS_DIR/bats-core" +fi + +# bats-support +if [[ ! -d "$TOOLS_DIR/bats-support" ]]; then + fetch_repo https://github.com/bats-core/bats-support.git "$TOOLS_DIR/bats-support" +fi + +# bats-assert +if [[ ! -d "$TOOLS_DIR/bats-assert" ]]; then + fetch_repo https://github.com/bats-core/bats-assert.git "$TOOLS_DIR/bats-assert" +fi + +echo "bats-core: $TOOLS_DIR/bats-core" +echo "bats-support: $TOOLS_DIR/bats-support" +echo "bats-assert: $TOOLS_DIR/bats-assert" + diff --git a/script/test.sh b/script/test.sh new file mode 100755 index 00000000000000..b9112a71c6d301 --- /dev/null +++ b/script/test.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Run bats tests; optional kcov coverage if present. +# Agentic hint: first run will fetch bats libs via bootstrap-tests.sh. + +ROOT_DIR=$(cd -- "$(dirname -- "$0")/.." && pwd) +cd "$ROOT_DIR" + +script/bootstrap-tests.sh + +export BATS_LIB_PATH="$ROOT_DIR/tooling/bats-support:$ROOT_DIR/tooling/bats-assert" +BATS="$ROOT_DIR/tooling/bats-core/bin/bats" + +if command -v kcov >/dev/null 2>&1; then + out="$ROOT_DIR/target/kcov" + mkdir -p "$out" + # Include our scripts for coverage; exclude system dirs + kcov --include-path="$ROOT_DIR/script" --exclude-pattern=/usr/,/bin/,/opt/ "$out" "$BATS" --tap test + echo "Coverage output: $out" +else + "$BATS" --tap test +fi + diff --git a/test/apply_scripts.bats b/test/apply_scripts.bats new file mode 100644 index 00000000000000..24c68bd31d34cc --- /dev/null +++ b/test/apply_scripts.bats @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +load 'bats-support/load' +load 'bats-assert/load' + +setup() { + ROOT_DIR="$BATS_TEST_DIRNAME/.." + TEST_ROOT="$ROOT_DIR/target/bats-tests/apply" + rm -rf "$TEST_ROOT"; mkdir -p "$TEST_ROOT"; cd "$TEST_ROOT"; git init -q + git config user.email a@b; git config user.name t + echo t > README.md; git add README.md; git commit -qm init + mkdir -p .reapply-patches/macOS-modernization script + cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch <<'EOF' +diff --git a/FOO b/FOO +new file mode 100644 +index 0000000000..e69de29bb2 +--- /dev/null ++++ b/FOO +EOF + cp "$ROOT_DIR/script/apply-cumulative.sh" script/ + cp "$ROOT_DIR/script/new-worktree-apply-cumulative.sh" script/ + chmod +x script/*.sh +} + +@test 'apply-cumulative applies in place' { + run script/apply-cumulative.sh + assert_success + [ -f FOO ] +} + +@test 'new-worktree-apply-cumulative creates worktree and applies' { + # create a fake upstream bare and set as upstream + mkdir -p upstream.git; git init -q --bare upstream.git + git remote add upstream "$PWD/upstream.git" + git push upstream HEAD:main >/dev/null + run script/new-worktree-apply-cumulative.sh + assert_success + WT=$(printf '%s' "$output" | sed -n 's/^WORKTREE=\(.*\)$/\1/p') + [ -n "$WT" ] && [ -d "$WT" ] && [ -f "$WT/FOO" ] +} + diff --git a/test/pre_push.bats b/test/pre_push.bats new file mode 100644 index 00000000000000..9ebf555950ab66 --- /dev/null +++ b/test/pre_push.bats @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +load 'bats-support/load' +load 'bats-assert/load' + +setup() { + ROOT_DIR="$BATS_TEST_DIRNAME/.." + TEST_ROOT="$ROOT_DIR/target/bats-tests/prepush" + rm -rf "$TEST_ROOT"; mkdir -p "$TEST_ROOT"; cd "$TEST_ROOT"; git init -q + mkdir -p .githooks script .reapply-patches/macOS-modernization + cp "$ROOT_DIR/.githooks/pre-push" .githooks/ + cp "$ROOT_DIR/script/validate-patch-setup.sh" script/ + chmod +x .githooks/pre-push script/validate-patch-setup.sh + git config core.hooksPath .githooks + git config user.email a@b; git config user.name t + echo t > README.md; git add README.md; git commit -qm init + # minimal valid series + cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch +} + +@test 'pre-push allows workflow-only change on main' { + git add .reapply-patches; git commit -qm workflow + local_ref="refs/heads/main"; local_sha=$(git rev-parse HEAD); remote_ref="refs/heads/main"; remote_sha=$(printf '0%.0s' {1..40}) + run env PATCH_SERIES=.reapply-patches/macOS-modernization "$PWD/.githooks/pre-push" <<<"$local_ref $local_sha $remote_ref $remote_sha" + assert_success +} + +@test 'pre-push blocks non-workflow change on main' { + echo hi > random.txt; git add random.txt; git commit -qm change + local_ref="refs/heads/main"; local_sha=$(git rev-parse HEAD); remote_ref="refs/heads/main"; remote_sha=$(printf '0%.0s' {1..40}) + run env PATCH_SERIES=.reapply-patches/macOS-modernization "$PWD/.githooks/pre-push" <<<"$local_ref $local_sha $remote_ref $remote_sha" + assert_failure + assert_output --partial 'Refuses to push non-workflow changes' +} + diff --git a/test/validate_patch_setup.bats b/test/validate_patch_setup.bats new file mode 100644 index 00000000000000..95e16450f33242 --- /dev/null +++ b/test/validate_patch_setup.bats @@ -0,0 +1,86 @@ +#!/usr/bin/env bash + +load 'bats-support/load' +load 'bats-assert/load' + +setup() { + ROOT_DIR="$BATS_TEST_DIRNAME/.." + TEST_ROOT="$ROOT_DIR/target/bats-tests/validate" + rm -rf "$TEST_ROOT"; mkdir -p "$TEST_ROOT"; cd "$TEST_ROOT" +} + +@test 'validate: OK with valid series' { + mkdir -p .reapply-patches/macOS-modernization + cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch <<'EOF' +diff --git a/FOO b/FOO +new file mode 100644 +index 0000000000..e69de29bb2 +--- /dev/null ++++ b/FOO +EOF + run "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization + assert_success + assert_output --partial 'series ok' +} + +@test 'validate: FAIL when CHECKPOINT missing' { + mkdir -p .reapply-patches/macOS-modernization + touch .reapply-patches/macOS-modernization/20250101-cumulative.patch + run "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization + assert_failure + assert_output --partial 'missing CHECKPOINT' +} + +@test 'validate: FAIL when DATE invalid' { + mkdir -p .reapply-patches/macOS-modernization + cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch + run "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization + assert_failure + assert_output --partial 'DATE invalid' +} + +@test 'validate: FAIL when COVERS invalid' { + mkdir -p .reapply-patches/macOS-modernization + cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch + run "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization + assert_failure + assert_output --partial 'COVERS invalid' +} + +@test 'validate: FAIL when cumulative lacks diff header' { + mkdir -p .reapply-patches/macOS-modernization + cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch + run "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization + assert_failure + assert_output --partial 'malformed' +} + +@test 'validate: FAIL when COVERS > highest 000X' { + mkdir -p .reapply-patches/macOS-modernization + cat > .reapply-patches/macOS-modernization/CHECKPOINT < .reapply-patches/macOS-modernization/20250101-cumulative.patch + touch .reapply-patches/macOS-modernization/0001-test.patch + run "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization + assert_failure + assert_output --partial 'exceeds highest numbered patch' +} + From b21f3c60bff027b10013697e046a058ff5c0ed3d Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Wed, 17 Sep 2025 13:03:42 +0800 Subject: [PATCH 10/38] pre-push: allow tests/ changes on main (workflow assets) --- .githooks/pre-push | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.githooks/pre-push b/.githooks/pre-push index eca65511ce7872..f7bec9c3f197e3 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -21,7 +21,7 @@ fi # Parse refs from stdin: # For each main ref, diff remote..local and ensure paths match allowlist. if [[ "${ALLOW_MAIN_CODE_PUSH:-0}" != "1" ]]; then - allow_re='^(\.reapply-patches/|script/|\.githooks/|docs/|AGENTS\.md$)' + allow_re='^(\.reapply-patches/|script/|\.githooks/|docs/|test/|AGENTS\.md$)' while read -r local_ref local_sha remote_ref remote_sha; do # Stop when no more refs (some Git versions pass nothing on dry runs) [[ -z "${local_ref:-}" ]] && continue From a36c095b0157ba7079dcdd55debe93ad3c637622 Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Thu, 18 Sep 2025 03:26:51 +0800 Subject: [PATCH 11/38] sanitization: add sanitize lib; sanitize CHECKPOINT + pre-push refs; tests for BOM/ZWSP/NBSP/CRLF --- .githooks/pre-push | 11 ++++++++++- script/lib/sanitize.sh | 16 ++++++++++++++++ script/validate-patch-setup.sh | 13 +++++++++++-- test/pre_push.bats | 6 ++++++ test/validate_patch_setup.bats | 9 +++++++++ 5 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 script/lib/sanitize.sh diff --git a/.githooks/pre-push b/.githooks/pre-push index f7bec9c3f197e3..677abfe9185f9a 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -21,10 +21,19 @@ fi # Parse refs from stdin: # For each main ref, diff remote..local and ensure paths match allowlist. if [[ "${ALLOW_MAIN_CODE_PUSH:-0}" != "1" ]]; then - allow_re='^(\.reapply-patches/|script/|\.githooks/|docs/|test/|AGENTS\.md$)' + allow_re='^(\.reapply-patches/|script/|\.githooks/|docs/|test/|tooling/|AGENTS\.md$)' while read -r local_ref local_sha remote_ref remote_sha; do # Stop when no more refs (some Git versions pass nothing on dry runs) [[ -z "${local_ref:-}" ]] && continue + # Sanitize refs to tolerate CRLF / pasted artifacts + if [[ -f "$ROOT_DIR/script/lib/sanitize.sh" ]]; then + # shellcheck source=/dev/null + . "$ROOT_DIR/script/lib/sanitize.sh" + local_ref=$(printf '%s' "$local_ref" | sanitize_line) + local_sha=$(printf '%s' "$local_sha" | sanitize_line) + remote_ref=$(printf '%s' "$remote_ref" | sanitize_line) + remote_sha=$(printf '%s' "$remote_sha" | sanitize_line) + fi # Only check heads pushes that target main (either side) case "$local_ref $remote_ref" in refs/heads/main*|*refs/heads/main*) diff --git a/script/lib/sanitize.sh b/script/lib/sanitize.sh new file mode 100644 index 00000000000000..39ce9c23b751be --- /dev/null +++ b/script/lib/sanitize.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Sanitize inputs that may include BOM, zero-width, NBSP, CR, mixed newlines. +# Agentic hint: use sanitize_file_to or sanitize_line in scripts reading user-provided content. +set -euo pipefail + +sanitize_file_to() { + # args: + local in="$1" out="$2" + perl -CSDA -pe 's/\x{FEFF}//g; s/[\x{200B}\x{200C}\x{200D}]//g; s/\x{00A0}/ /g; s/\r//g;' "$in" > "$out" +} + +sanitize_line() { + # read stdin line, emit sanitized to stdout (no trailing CR, strip BOM/ZWSP/NBSP) + perl -CSDA -pe 's/\x{FEFF}//g; s/[\x{200B}\x{200C}\x{200D}]//g; s/\x{00A0}/ /g; s/\r//g;' +} + diff --git a/script/validate-patch-setup.sh b/script/validate-patch-setup.sh index fba79ad8108f12..50603695f0ed3b 100755 --- a/script/validate-patch-setup.sh +++ b/script/validate-patch-setup.sh @@ -26,11 +26,20 @@ info() { echo "[patch-validate] $*" >&2; } [[ -d "$SERIES" ]] || fail "series directory missing: $SERIES" +# Sanitize CHECKPOINT to tolerate pasted content (BOM/ZWSP/NBSP/CR) CKPT="$SERIES/CHECKPOINT" [[ -f "$CKPT" ]] || fail "missing CHECKPOINT in $SERIES" +tmp_ckpt=$(mktemp) +if [[ -f "$ROOT_DIR/script/lib/sanitize.sh" ]]; then + # shellcheck source=/dev/null + . "$ROOT_DIR/script/lib/sanitize.sh" + sanitize_file_to "$CKPT" "$tmp_ckpt" +else + cp "$CKPT" "$tmp_ckpt" +fi -DATE=$(awk -F= '/^DATE=/{print $2}' "$CKPT" | tr -d '\r\n' || true) -COVERS=$(awk -F= '/^COVERS=/{print $2}' "$CKPT" | tr -d '\r\n' || true) +DATE=$(awk -F= '/^DATE=/{print $2}' "$tmp_ckpt" | tr -d '\r\n' || true) +COVERS=$(awk -F= '/^COVERS=/{print $2}' "$tmp_ckpt" | tr -d '\r\n' || true) [[ "$DATE" =~ ^[0-9]{8}$ ]] || fail "CHECKPOINT DATE invalid or missing (expected YYYYMMDD), got: '${DATE:-}'" [[ "$COVERS" =~ ^[0-9]{4}$ ]] || fail "CHECKPOINT COVERS invalid or missing (expected 4 digits), got: '${COVERS:-}'" diff --git a/test/pre_push.bats b/test/pre_push.bats index 9ebf555950ab66..78a7dc078da23b 100644 --- a/test/pre_push.bats +++ b/test/pre_push.bats @@ -37,3 +37,9 @@ EOF assert_output --partial 'Refuses to push non-workflow changes' } +@test 'pre-push tolerates CRLF and ZWSP in ref input' { + git add .reapply-patches; git commit -qm wf + local_ref=$'refs/heads/main\r'; local_sha=$(git rev-parse HEAD); remote_ref=$'refs/heads/main\xE2\x80\x8B'; remote_sha=$(printf '0%.0s' {1..40}) + run env PATCH_SERIES=.reapply-patches/macOS-modernization "$PWD/.githooks/pre-push" <<<"$local_ref $local_sha $remote_ref $remote_sha" + assert_success +} diff --git a/test/validate_patch_setup.bats b/test/validate_patch_setup.bats index 95e16450f33242..7c02e011d22fcb 100644 --- a/test/validate_patch_setup.bats +++ b/test/validate_patch_setup.bats @@ -84,3 +84,12 @@ EOF assert_output --partial 'exceeds highest numbered patch' } +@test 'validate: OK with BOM/ZWSP/NBSP/CRLF in CHECKPOINT' { + mkdir -p .reapply-patches/macOS-modernization + # Inject BOM + ZWSP + NBSP and CRLF line endings + perl -CSDA -e 'print "\x{FEFF}DATE\x{200B}=20250101\r\nCOVERS\x{00A0}=0000\r\n"' > .reapply-patches/macOS-modernization/CHECKPOINT + echo 'diff --git a/X b/X' > .reapply-patches/macOS-modernization/20250101-cumulative.patch + run "$ROOT_DIR/script/validate-patch-setup.sh" --series .reapply-patches/macOS-modernization + assert_success + assert_output --partial 'series ok' +} From a36e04db7496d988cf54d265e0d6f2be6793981a Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Thu, 18 Sep 2025 03:27:33 +0800 Subject: [PATCH 12/38] sanitization: add sanitize lib; sanitize CHECKPOINT + pre-push refs; tests for BOM/ZWSP/NBSP/CRLF --- worktrees/macOS-modernization-apply-20250917-122637 | 1 + 1 file changed, 1 insertion(+) create mode 160000 worktrees/macOS-modernization-apply-20250917-122637 diff --git a/worktrees/macOS-modernization-apply-20250917-122637 b/worktrees/macOS-modernization-apply-20250917-122637 new file mode 160000 index 00000000000000..e36bda73936a02 --- /dev/null +++ b/worktrees/macOS-modernization-apply-20250917-122637 @@ -0,0 +1 @@ +Subproject commit e36bda73936a02ca2582034ce2aca1a213d35081 From a6889741638fa671808244157273eeab10c3b589 Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Thu, 18 Sep 2025 03:27:46 +0800 Subject: [PATCH 13/38] fix: remove accidentally added worktrees/ from index --- worktrees/macOS-modernization-apply-20250917-122637 | 1 - 1 file changed, 1 deletion(-) delete mode 160000 worktrees/macOS-modernization-apply-20250917-122637 diff --git a/worktrees/macOS-modernization-apply-20250917-122637 b/worktrees/macOS-modernization-apply-20250917-122637 deleted file mode 160000 index e36bda73936a02..00000000000000 --- a/worktrees/macOS-modernization-apply-20250917-122637 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e36bda73936a02ca2582034ce2aca1a213d35081 From 9b5194b1388ea2afcecc662e5b475489e6078752 Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Thu, 18 Sep 2025 03:29:10 +0800 Subject: [PATCH 14/38] tests: fix BATS_LIB_PATH; add setup_repo.bats for hooks/alias install --- script/test.sh | 3 +-- test/setup_repo.bats | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 test/setup_repo.bats diff --git a/script/test.sh b/script/test.sh index b9112a71c6d301..bef65216710c1c 100755 --- a/script/test.sh +++ b/script/test.sh @@ -9,7 +9,7 @@ cd "$ROOT_DIR" script/bootstrap-tests.sh -export BATS_LIB_PATH="$ROOT_DIR/tooling/bats-support:$ROOT_DIR/tooling/bats-assert" +export BATS_LIB_PATH="$ROOT_DIR/tooling" BATS="$ROOT_DIR/tooling/bats-core/bin/bats" if command -v kcov >/dev/null 2>&1; then @@ -21,4 +21,3 @@ if command -v kcov >/dev/null 2>&1; then else "$BATS" --tap test fi - diff --git a/test/setup_repo.bats b/test/setup_repo.bats new file mode 100644 index 00000000000000..c352682741792a --- /dev/null +++ b/test/setup_repo.bats @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +load 'bats-support/load' +load 'bats-assert/load' + +setup() { + ROOT_DIR="$BATS_TEST_DIRNAME/.." + TEST_ROOT="$ROOT_DIR/target/bats-tests/setup" + rm -rf "$TEST_ROOT"; mkdir -p "$TEST_ROOT"; cd "$TEST_ROOT"; git init -q + git config user.email a@b; git config user.name t + echo t > README.md; git add README.md; git commit -qm init + mkdir -p script; cp "$ROOT_DIR/script/setup-repo.sh" script/ + cp -r "$ROOT_DIR/.githooks" . + chmod +x script/setup-repo.sh .githooks/* +} + +@test 'setup-repo installs hooksPath and aliases' { + run script/setup-repo.sh --no-fetch + assert_success + run git config --local --get core.hooksPath + assert_success + assert_output '.githooks' + run git config --local --get alias.wtn + assert_success + assert_output --partial 'new-worktree.sh' +} + From f523ec506748bc8a8c97f535e1aa9b873e5791f7 Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Thu, 18 Sep 2025 03:29:31 +0800 Subject: [PATCH 15/38] tests: vendor bats-core, bats-support, bats-assert under tooling for offline runs --- tooling/bats-assert | 1 + tooling/bats-core | 1 + tooling/bats-support | 1 + 3 files changed, 3 insertions(+) create mode 160000 tooling/bats-assert create mode 160000 tooling/bats-core create mode 160000 tooling/bats-support diff --git a/tooling/bats-assert b/tooling/bats-assert new file mode 160000 index 00000000000000..3be0fb7856791b --- /dev/null +++ b/tooling/bats-assert @@ -0,0 +1 @@ +Subproject commit 3be0fb7856791b4a64aef7a1336e965f5252e45f diff --git a/tooling/bats-core b/tooling/bats-core new file mode 160000 index 00000000000000..855844b8344e67 --- /dev/null +++ b/tooling/bats-core @@ -0,0 +1 @@ +Subproject commit 855844b8344e67d60dc0f43fa39817ed7787f141 diff --git a/tooling/bats-support b/tooling/bats-support new file mode 160000 index 00000000000000..0954abb9925cad --- /dev/null +++ b/tooling/bats-support @@ -0,0 +1 @@ +Subproject commit 0954abb9925cad550424cebca2b99255d4eabe96 From a2950a16d1891a0ed23780aee3ba78e234bf91c4 Mon Sep 17 00:00:00 2001 From: Takumi Shimada Date: Thu, 18 Sep 2025 03:29:55 +0800 Subject: [PATCH 16/38] tests: vendor bats libs as files (remove embedded repos) --- tooling/bats-assert | 1 - tooling/bats-assert/.github/CONTRIBUTING.md | 8 + .../bats-assert/.github/workflows/release.yml | 37 + .../.github/workflows/sync-default-branch.yml | 25 + .../bats-assert/.github/workflows/test.yml | 9 + tooling/bats-assert/.gitignore | 3 + tooling/bats-assert/LICENSE | 116 ++ tooling/bats-assert/README.md | 1038 +++++++++++ tooling/bats-assert/load.bash | 33 + tooling/bats-assert/package-lock.json | 36 + tooling/bats-assert/package.json | 49 + tooling/bats-assert/src/assert.bash | 42 + tooling/bats-assert/src/assert_equal.bash | 42 + tooling/bats-assert/src/assert_failure.bash | 86 + tooling/bats-assert/src/assert_line.bash | 301 ++++ tooling/bats-assert/src/assert_not_equal.bash | 42 + tooling/bats-assert/src/assert_output.bash | 249 +++ tooling/bats-assert/src/assert_regex.bash | 56 + tooling/bats-assert/src/assert_success.bash | 47 + tooling/bats-assert/src/refute.bash | 42 + tooling/bats-assert/src/refute_line.bash | 318 ++++ tooling/bats-assert/src/refute_output.bash | 246 +++ tooling/bats-assert/src/refute_regex.bash | 66 + tooling/bats-assert/test/assert.bats | 19 + tooling/bats-assert/test/assert_equal.bats | 62 + tooling/bats-assert/test/assert_failure.bats | 94 + tooling/bats-assert/test/assert_line.bats | 362 ++++ .../bats-assert/test/assert_not_equal.bats | 57 + tooling/bats-assert/test/assert_output.bats | 296 +++ tooling/bats-assert/test/assert_regex.bats | 87 + tooling/bats-assert/test/assert_stderr.bats | 298 ++++ .../bats-assert/test/assert_stderr_line.bats | 364 ++++ tooling/bats-assert/test/assert_success.bats | 58 + tooling/bats-assert/test/refute.bats | 18 + tooling/bats-assert/test/refute_line.bats | 355 ++++ tooling/bats-assert/test/refute_output.bats | 230 +++ tooling/bats-assert/test/refute_regex.bats | 98 + tooling/bats-assert/test/refute_stderr.bats | 242 +++ .../bats-assert/test/refute_stderr_line.bats | 356 ++++ tooling/bats-assert/test/test_helper.bash | 30 + tooling/bats-core | 1 - tooling/bats-core/.codespellrc | 3 + tooling/bats-core/.devcontainer/Dockerfile | 17 + .../bats-core/.devcontainer/devcontainer.json | 5 + tooling/bats-core/.editorconfig | 35 + tooling/bats-core/.gitattributes | 3 + .../.github/ISSUE_TEMPLATE/bug_report.md | 30 + .../.github/ISSUE_TEMPLATE/feature_request.md | 20 + tooling/bats-core/.github/dependabot.yml | 47 + .../.github/workflows/check_pr_label.sh | 10 + .../bats-core/.github/workflows/codespell.yml | 22 + .../.github/workflows/dependency-review.yml | 22 + .../bats-core/.github/workflows/release.yml | 35 + .../.github/workflows/release_dockerhub.yml | 54 + .../bats-core/.github/workflows/scorecard.yml | 72 + .../.github/workflows/set_nounset.bash | 1 + tooling/bats-core/.github/workflows/tests.yml | 361 ++++ tooling/bats-core/.gitignore | 10 + tooling/bats-core/.pre-commit-config.yaml | 14 + tooling/bats-core/.readthedocs.yml | 13 + tooling/bats-core/AUTHORS | 4 + tooling/bats-core/Dockerfile | 45 + tooling/bats-core/LICENSE.md | 53 + tooling/bats-core/README.md | 135 ++ tooling/bats-core/SECURITY.md | 9 + tooling/bats-core/bin/bats | 75 + tooling/bats-core/contrib/release.sh | 178 ++ tooling/bats-core/contrib/rpm/bats.spec | 66 + tooling/bats-core/contrib/semver | 358 ++++ .../bats-core/docker-compose.override.dist | 7 + tooling/bats-core/docker-compose.yml | 12 + tooling/bats-core/docker/install_libs.sh | 51 + tooling/bats-core/docker/install_tini.sh | 30 + tooling/bats-core/docker/tini.pubkey.gpg | 107 ++ tooling/bats-core/docs/.markdownlint.json | 3 + tooling/bats-core/docs/CHANGELOG.md | 630 +++++++ tooling/bats-core/docs/CODEOWNERS | 4 + tooling/bats-core/docs/CODE_OF_CONDUCT.md | 92 + tooling/bats-core/docs/CONTRIBUTING.md | 232 +++ tooling/bats-core/docs/Makefile | 20 + .../bats-core/docs/PULL_REQUEST_TEMPLATE.md | 5 + tooling/bats-core/docs/examples/README.md | 6 + .../bats-core/docs/examples/package-tarball | 16 + .../docs/examples/package-tarball.bats | 51 + tooling/bats-core/docs/list-links.py | 4 + tooling/bats-core/docs/make.bat | 35 + tooling/bats-core/docs/releasing.md | 127 ++ .../bats-core/docs/source/_static/.gitkeep | 0 .../bats-core/docs/source/_templates/.gitkeep | 0 .../bats-core/docs/source/assets/README.md | 24 + .../docs/source/assets/dark_mode_bat.svg | 55 + .../docs/source/assets/dark_mode_cube.svg | 98 + .../assets/dark_mode_wordmark_lowercase.svg | 75 + .../assets/dark_mode_wordmark_uppercase.svg | 80 + .../docs/source/assets/light_mode_bat.svg | 99 ++ .../docs/source/assets/light_mode_cube.svg | 90 + .../assets/light_mode_wordmark_lowercase.svg | 79 + .../assets/light_mode_wordmark_uppercase.svg | 48 + tooling/bats-core/docs/source/conf.py | 74 + tooling/bats-core/docs/source/docker-usage.md | 70 + tooling/bats-core/docs/source/faq.rst | 172 ++ tooling/bats-core/docs/source/gotchas.rst | 132 ++ tooling/bats-core/docs/source/index.rst | 22 + .../bats-core/docs/source/installation.rst | 138 ++ .../bats-core/docs/source/requirements.txt | 2 + .../bats-core/docs/source/support-matrix.rst | 26 + tooling/bats-core/docs/source/tutorial.rst | 661 +++++++ tooling/bats-core/docs/source/usage.md | 114 ++ .../bats-core/docs/source/warnings/BW01.rst | 17 + .../bats-core/docs/source/warnings/BW02.rst | 46 + .../bats-core/docs/source/warnings/BW03.rst | 15 + .../bats-core/docs/source/warnings/index.rst | 28 + .../bats-core/docs/source/writing-tests.md | 699 ++++++++ tooling/bats-core/docs/versions.md | 9 + tooling/bats-core/install.sh | 29 + tooling/bats-core/lib/bats-core/common.bash | 258 +++ .../bats-core/lib/bats-core/formatter.bash | 151 ++ .../lib/bats-core/preprocessing.bash | 19 + .../bats-core/lib/bats-core/semaphore.bash | 113 ++ .../lib/bats-core/test_functions.bash | 509 ++++++ tooling/bats-core/lib/bats-core/tracing.bash | 425 +++++ .../bats-core/lib/bats-core/validator.bash | 37 + tooling/bats-core/lib/bats-core/warnings.bash | 44 + tooling/bats-core/libexec/bats-core/bats | 516 ++++++ .../libexec/bats-core/bats-exec-file | 392 ++++ .../libexec/bats-core/bats-exec-suite | 316 ++++ .../libexec/bats-core/bats-exec-test | 378 ++++ .../libexec/bats-core/bats-format-cat | 6 + .../libexec/bats-core/bats-format-junit | 254 +++ .../libexec/bats-core/bats-format-pretty | 348 ++++ .../libexec/bats-core/bats-format-tap | 55 + .../libexec/bats-core/bats-format-tap13 | 89 + .../libexec/bats-core/bats-gather-tests | 378 ++++ .../libexec/bats-core/bats-preprocess | 123 ++ tooling/bats-core/man/Makefile | 23 + tooling/bats-core/man/README.md | 5 + tooling/bats-core/man/bats.1 | 143 ++ tooling/bats-core/man/bats.1.ronn | 192 ++ tooling/bats-core/man/bats.7 | 239 +++ tooling/bats-core/man/bats.7.ronn | 404 +++++ tooling/bats-core/package.json | 34 + tooling/bats-core/report.log | 6 + tooling/bats-core/report.xml | 3 + tooling/bats-core/shellcheck.sh | 22 + tooling/bats-core/test/bats.bats | 1580 +++++++++++++++++ tooling/bats-core/test/bats_pipe.bats | 1410 +++++++++++++++ tooling/bats-core/test/cat-formatter.bats | 70 + tooling/bats-core/test/common.bats | 204 +++ .../test/concurrent-coordination.bash | 65 + .../bats-core/test/file_setup_teardown.bats | 198 +++ tooling/bats-core/test/filter.bats | 136 ++ .../test/fixtures/bats/BATS_TMPDIR.bats | 8 + ...variables_dont_contain_double_slashes.bats | 9 + .../test/fixtures/bats/cmd_using_stdin.bash | 19 + .../test/fixtures/bats/comment_style.bats | 34 + tooling/bats-core/test/fixtures/bats/date | 3 + .../fixtures/bats/dos_line_no_shellcheck.bats | 3 + .../bats/duplicate-tests_no_shellcheck.bats | 13 + .../bats/dynamic_test_registration.bats | 28 + .../bats-core/test/fixtures/bats/empty.bats | 1 + .../test/fixtures/bats/environment.bats | 10 + .../fixtures/bats/evaluation_count/file1.bats | 5 + .../fixtures/bats/evaluation_count/file2.bats | 9 + .../bats-core/test/fixtures/bats/exit_11.bash | 2 + .../bats/expand_var_in_test_name.bats | 3 + .../test/fixtures/bats/exported_function.bats | 8 + .../bats/external_function_calls.bats | 76 + .../fixtures/bats/external_functions.bash | 15 + .../fixtures/bats/external_functions.bats | 5 + .../bats-core/test/fixtures/bats/failing.bats | 5 + .../fixtures/bats/failing_and_passing.bats | 7 + .../test/fixtures/bats/failing_helper.bats | 6 + .../test/fixtures/bats/failing_setup.bats | 7 + .../test/fixtures/bats/failing_teardown.bats | 7 + .../fixtures/bats/failing_with_bash_cond.bats | 5 + .../bats/failing_with_bash_expression.bats | 4 + .../bats/failing_with_negated_command.bats | 5 + .../test/fixtures/bats/failure_callback.bats | 19 + .../bats/failure_callback_setup_file.bats | 11 + .../failure_callback_setup_suite/dummy.bats | 3 + .../setup_suite.bash | 7 + .../fixtures/bats/failure_in_free_code.bats | 9 + .../bats-core/test/fixtures/bats/focus.bats | 8 + .../fixtures/bats/focused_filtered_out.bats | 9 + ...obble_up_stdin_sleep_and_print_finish.bash | 4 + .../test/fixtures/bats/hang_after_run.bats | 9 + .../test/fixtures/bats/hang_in_run.bats | 8 + .../fixtures/bats/hang_in_setup_file.bats | 9 + .../test/fixtures/bats/hang_in_teardown.bats | 9 + .../fixtures/bats/hang_in_teardown_file.bats | 9 + .../test/fixtures/bats/hang_in_test.bats | 9 + .../bats-core/test/fixtures/bats/intact.bats | 6 + .../test/fixtures/bats/issue-205.bats | 103 ++ .../test/fixtures/bats/issue-433/repro1.bats | 7 + .../test/fixtures/bats/issue-433/repro2.bats | 7 + .../test/fixtures/bats/issue-519.bats | 3 + .../bats-core/test/fixtures/bats/load.bats | 6 + .../test/fixtures/bats/loop_keep_IFS.bats | 16 + .../bats/many_passing_and_one_failing.bats | 15 + .../test/fixtures/bats/no-final-newline.bats | 9 + .../bats-core/test/fixtures/bats/output.bats | 19 + .../fixtures/bats/override_date_on_path.bats | 11 + .../test/fixtures/bats/parallel.bats | 39 + .../bats-core/test/fixtures/bats/passing.bats | 3 + .../fixtures/bats/passing_and_failing.bats | 7 + .../fixtures/bats/passing_and_skipping.bats | 11 + .../bats/passing_failing_and_skipping.bats | 11 + .../fixtures/bats/preserve_IFS/helper.bash | 8 + .../bats/preserve_IFS/setup_suite.bash | 11 + .../test/fixtures/bats/preserve_IFS/test.bats | 15 + .../bats/print_output_on_failure.bats | 12 + .../print_output_on_failure_with_stderr.bats | 13 + ...and_unquoted_test_names_no_shellcheck.bats | 11 + .../test/fixtures/bats/read_from_stdin.bats | 21 + .../bats/reference_unset_parameter.bats | 5 + .../reference_unset_parameter_in_setup.bats | 14 + ...reference_unset_parameter_in_teardown.bats | 9 + .../bats-core/test/fixtures/bats/retry.bats | 38 + .../test/fixtures/bats/retry_success.bats | 6 + .../test/fixtures/bats/run_long_command.bats | 3 + .../bats/set_-eu_in_setup_and_teardown.bats | 23 + .../bats-core/test/fixtures/bats/setup.bats | 17 + .../bats/show-output-of-passing-tests.bats | 3 + .../fixtures/bats/sigint_in_failing_test.bats | 11 + .../bats/single_line_no_shellcheck.bats | 9 + .../bats-core/test/fixtures/bats/skipped.bats | 7 + .../fixtures/bats/skipped_with_parens.bats | 3 + .../bats/source_nonexistent_file.bats | 4 + .../source_nonexistent_file_in_setup.bats | 13 + .../source_nonexistent_file_in_teardown.bats | 8 + .../test/fixtures/bats/tab in filename.bats | 3 + .../test/fixtures/bats/teardown.bats | 17 + .../bats/teardown_file_override_status.bats | 9 + .../bats/teardown_override_status.bats | 8 + .../setup_suite.bash | 9 + .../teardown_suite_override_status/test.bats | 3 + .../test/fixtures/bats/test_helper.bash | 19 + .../test/fixtures/bats/test_with_slash.bats | 3 + .../test/fixtures/bats/unbound_variable.bats | 16 + .../bats/unofficial_bash_strict_mode.bash | 3 + .../bats/unofficial_bash_strict_mode.bats | 4 + .../test/fixtures/bats/update_path_env.bats | 6 + .../test/fixtures/bats/verbose-run.bats | 4 + .../bats/whitespace_no_shellcheck.bats | 33 + .../bats/without_trailing_newline.bats | 3 + .../error_in_setup_and_teardown_file.bats | 11 + .../file_setup_teardown/no_setup_file.bats | 3 + .../file_setup_teardown/no_teardown_file.bats | 3 + .../file_setup_teardown/setup_file.bats | 11 + .../file_setup_teardown/setup_file2.bats | 7 + .../setup_file_does_not_leak_env.bats | 7 + .../setup_file_does_not_leak_env2.bats | 3 + ...up_file_even_if_all_tests_are_skipped.bats | 7 + .../setup_file_failed.bats | 11 + .../setup_file_halfway_error.bats | 9 + .../file_setup_teardown/teardown_file.bats | 11 + .../file_setup_teardown/teardown_file2.bats | 11 + .../teardown_file_after_failing_test.bats | 7 + .../teardown_file_after_long_test.bats | 8 + .../teardown_file_does_not_leak.bats | 7 + .../teardown_file_does_not_leak2.bats | 3 + ...wn_file_even_if_all_tests_are_skipped.bats | 7 + .../teardown_file_failed.bats | 7 + .../teardown_file_halfway_error.bats | 9 + .../test/fixtures/formatter/dummy-formatter | 5 + .../test/fixtures/formatter/echo-formatter | 40 + .../test/fixtures/formatter/failing.bats | 5 + .../test/fixtures/formatter/passing.bats | 3 + .../formatter/passing_and_skipping.bats | 11 + .../passing_failing_and_skipping.bats | 11 + .../test/fixtures/formatter/retry.bats | 8 + .../formatter/skipped_with_parens.bats | 3 + .../duplicate/first/file1.bats | 3 + .../duplicate/second/file1.bats | 3 + .../fixtures/junit-formatter/issue_360.bats | 22 + .../fixtures/junit-formatter/issue_531.bats | 16 + .../fixtures/junit-formatter/skipped.bats | 9 + .../fixtures/junit-formatter/suite/file1.bats | 3 + .../fixtures/junit-formatter/suite/file2.bats | 3 + .../fixtures/junit-formatter/xml-escape.bats | 11 + .../bats-core/test/fixtures/load/ambiguous | 5 + .../test/fixtures/load/ambiguous.bash | 6 + .../test/fixtures/load/bats_load_library.bats | 6 + .../bats-core/test/fixtures/load/exit1.bash | 1 + .../load/failing_bats_load_library.bats | 5 + .../test/fixtures/load/failing_load.bats | 5 + .../fixtures/load/find_library_helper.bats | 5 + .../load/find_library_helper_err.bats | 4 + .../bats-core/test/fixtures/load/load.bats | 6 + .../load/load_in_teardown_after_failure.bats | 7 + .../bats-core/test/fixtures/load/return1.bash | 1 + .../test/fixtures/load/test_helper.bash | 19 + .../file1.bats | 14 + .../file2.bats | 19 + .../must_not_parallelize_within_file.bats | 52 + .../parallel-preserve-environment.bats | 8 + .../test/fixtures/parallel/parallel.bats | 20 + .../fixtures/parallel/parallel_factor.bats | 48 + .../parallel/setup_file/setup_file.bats | 13 + .../parallel/setup_file/setup_file1.bats | 1 + .../parallel/setup_file/setup_file2.bats | 1 + .../parallel/setup_file/setup_file3.bats | 1 + .../fixtures/parallel/suite/parallel1.bats | 20 + .../fixtures/parallel/suite/parallel2.bats | 1 + .../fixtures/parallel/suite/parallel3.bats | 1 + .../fixtures/parallel/suite/parallel4.bats | 1 + .../bats-core/test/fixtures/run/failing.bats | 23 + .../bats-core/test/fixtures/run/invalid.bats | 7 + .../test/fixtures/suite/empty/.gitkeep | 0 .../suite/errors_in_multiple_load/a.bats | 5 + .../suite/errors_in_multiple_load/b.bats | 5 + .../suite/errors_in_multiple_load/c.bats | 5 + .../errors_in_multiple_load/test_helper.bash | 1 + .../test/fixtures/suite/filter/a.bats | 3 + .../test/fixtures/suite/filter/b.bats | 3 + .../test/fixtures/suite/filter/c.bats | 3 + .../test/fixtures/suite/multiple/a.bats | 3 + .../test/fixtures/suite/multiple/b.bats | 7 + .../suite/multiple_load_constants/a.bats | 5 + .../suite/multiple_load_constants/b.bats | 5 + .../multiple_load_constants/test_helper.bash | 2 + .../subfolder/test.other_extension | 3 + .../override_BATS_FILE_EXTENSION/test.bats | 3 + .../override_BATS_FILE_EXTENSION/test.test | 3 + .../suite/recursive/subsuite/test2.bats | 3 + .../test/fixtures/suite/recursive/test.bats | 3 + .../suite/recursive_with_symlinks/subsuite | 1 + .../suite/recursive_with_symlinks/test.bats | 1 + .../test/fixtures/suite/single/test.bats | 3 + .../skip/skip-in-setup-and-teardown.bats | 17 + .../fixtures/suite/skip/skip-in-setup.bats | 13 + .../fixtures/suite/skip/skip-in-teardown.bats | 9 + .../suite/skip/skip-in-test-and-teardown.bats | 9 + .../fixtures/suite/skip/skip-in-test.bats | 5 + .../fixtures/suite/test_number/file1.bats | 18 + .../fixtures/suite/test_number/file2.bats | 24 + .../call_load/setup_suite.bash | 3 + .../suite_setup_teardown/call_load/test.bats | 3 + .../call_load/test_helper.bash | 1 + .../default_name/setup_suite.bash | 7 + .../default_name/test.bats | 3 + .../error_in_free_code/setup_suite.bash | 5 + .../error_in_free_code/test.bats | 1 + .../error_in_setup_suite/setup_suite.bash | 3 + .../error_in_setup_suite/test.bats | 1 + .../error_in_teardown_suite/setup_suite.bash | 7 + .../error_in_teardown_suite/test.bats | 1 + .../exported_vars/setup_suite.bash | 3 + .../exported_vars/test.bats | 11 + .../failure_in_setup_suite/setup_suite.bash | 9 + .../failure_in_setup_suite/test.bats | 1 + .../setup_suite.bash | 9 + .../failure_in_teardown_suite/test.bats | 1 + .../no_failure_no_output/setup_suite.bash | 7 + .../no_failure_no_output/test.bats | 3 + .../no_setup_suite_function/setup_suite.bash | 3 + .../no_setup_suite_function/test.bats | 3 + .../setup_suite_non_default.bash | 7 + .../non_default_name/test.bats | 3 + .../output_with_failure/setup_suite.bash | 8 + .../output_with_failure/test.bats | 3 + .../pick_up_toplevel/folder1/setup_suite.bash | 1 + .../pick_up_toplevel/folder1/test.bats | 3 + .../pick_up_toplevel/folder2/setup_suite.bash | 1 + .../pick_up_toplevel/folder2/test.bats | 3 + .../pick_up_toplevel/setup_suite.bash | 7 + .../pick_up_toplevel/test.bats | 3 + .../setup_suite.bash | 10 + .../test.bats | 1 + .../skip_in_setup_file.bats | 11 + .../setup_suite.bash | 10 + .../stderr_in_setup_teardown_suite/test.bats | 3 + .../syntax_error/setup_suite_no_shellcheck | 1 + .../syntax_error/test.bats | 1 + .../test/fixtures/tagging/BATS_TEST_TAGS.bats | 26 + .../test/fixtures/tagging/invalid_tags.bats | 8 + .../fixtures/tagging/print_tags_on_error.bats | 5 + .../test/fixtures/tagging/tagged.bats | 25 + .../test/fixtures/tagging/trimming.bats | 5 + .../test/fixtures/timeout/sleep2.bats | 3 + .../test/fixtures/trace/failing_complex.bats | 5 + .../fixtures/trace/failing_recursive.bats | 13 + .../test/fixtures/warnings/BW01.bats | 5 + .../warnings/BW01_check_exit_code_is_127.bats | 4 + ...1_no_exit_code_check_no_exit_code_127.bats | 3 + .../test/fixtures/warnings/BW02.bats | 3 + .../define_setup_suite_in_wrong_file.bats | 7 + .../BW03/non_default_setup_suite.bash | 3 + .../warnings/BW03/suppress_warning.bats | 10 + tooling/bats-core/test/formatter.bats | 114 ++ tooling/bats-core/test/install.bats | 152 ++ tooling/bats-core/test/junit-formatter.bats | 160 ++ tooling/bats-core/test/load.bats | 190 ++ tooling/bats-core/test/parallel.bats | 220 +++ tooling/bats-core/test/pretty-formatter.bats | 69 + tooling/bats-core/test/root.bats | 103 ++ tooling/bats-core/test/run.bats | 139 ++ tooling/bats-core/test/suite.bats | 252 +++ .../bats-core/test/suite_setup_teardown.bats | 153 ++ tooling/bats-core/test/tagging.bats | 87 + tooling/bats-core/test/tap13-formatter.bats | 53 + tooling/bats-core/test/test_helper.bash | 80 + tooling/bats-core/test/timeout.bats | 30 + tooling/bats-core/test/trace.bats | 84 + tooling/bats-core/test/warnings.bats | 72 + tooling/bats-core/test2/setup_suite.bash | 3 + tooling/bats-core/test2/test.bats | 3 + tooling/bats-core/uninstall.sh | 63 + tooling/bats-support | 1 - tooling/bats-support/.github/dependabot.yml | 14 + .../.github/workflows/sync-default-branch.yml | 25 + .../bats-support/.github/workflows/test.yml | 15 + tooling/bats-support/.gitignore | 5 + tooling/bats-support/CHANGELOG.md | 46 + tooling/bats-support/LICENSE | 14 + tooling/bats-support/README.md | 180 ++ tooling/bats-support/load.bash | 11 + tooling/bats-support/package-lock.json | 28 + tooling/bats-support/package.json | 44 + tooling/bats-support/src/error.bash | 32 + tooling/bats-support/src/lang.bash | 64 + tooling/bats-support/src/output.bash | 270 +++ .../test/50-output-10-batslib_err.bats | 43 + .../50-output-11-batslib_count_lines.bats | 21 + .../50-output-12-batslib_is_single_line.bats | 13 + ...batslib_get_max_single_line_key_width.bats | 21 + .../50-output-14-batslib_print_kv_single.bats | 27 + .../50-output-15-batslib_print_kv_multi.bats | 19 + ...t-16-batslib_print_kv_single_or_multi.bats | 31 + .../test/50-output-17-batslib_prefix.bats | 43 + .../test/50-output-18-batslib_mark.bats | 72 + .../test/50-output-19-batslib_decorate.bats | 46 + .../bats-support/test/51-error-10-fail.bats | 16 + .../test/52-lang-10-batslib_is_caller.bats | 88 + tooling/bats-support/test/cat | 1 + tooling/bats-support/test/test_helper.bash | 6 + 436 files changed, 26458 insertions(+), 3 deletions(-) delete mode 160000 tooling/bats-assert create mode 100644 tooling/bats-assert/.github/CONTRIBUTING.md create mode 100644 tooling/bats-assert/.github/workflows/release.yml create mode 100644 tooling/bats-assert/.github/workflows/sync-default-branch.yml create mode 100644 tooling/bats-assert/.github/workflows/test.yml create mode 100644 tooling/bats-assert/.gitignore create mode 100644 tooling/bats-assert/LICENSE create mode 100644 tooling/bats-assert/README.md create mode 100644 tooling/bats-assert/load.bash create mode 100644 tooling/bats-assert/package-lock.json create mode 100644 tooling/bats-assert/package.json create mode 100644 tooling/bats-assert/src/assert.bash create mode 100644 tooling/bats-assert/src/assert_equal.bash create mode 100644 tooling/bats-assert/src/assert_failure.bash create mode 100644 tooling/bats-assert/src/assert_line.bash create mode 100644 tooling/bats-assert/src/assert_not_equal.bash create mode 100644 tooling/bats-assert/src/assert_output.bash create mode 100644 tooling/bats-assert/src/assert_regex.bash create mode 100644 tooling/bats-assert/src/assert_success.bash create mode 100644 tooling/bats-assert/src/refute.bash create mode 100644 tooling/bats-assert/src/refute_line.bash create mode 100644 tooling/bats-assert/src/refute_output.bash create mode 100644 tooling/bats-assert/src/refute_regex.bash create mode 100755 tooling/bats-assert/test/assert.bats create mode 100755 tooling/bats-assert/test/assert_equal.bats create mode 100755 tooling/bats-assert/test/assert_failure.bats create mode 100755 tooling/bats-assert/test/assert_line.bats create mode 100644 tooling/bats-assert/test/assert_not_equal.bats create mode 100755 tooling/bats-assert/test/assert_output.bats create mode 100644 tooling/bats-assert/test/assert_regex.bats create mode 100755 tooling/bats-assert/test/assert_stderr.bats create mode 100755 tooling/bats-assert/test/assert_stderr_line.bats create mode 100755 tooling/bats-assert/test/assert_success.bats create mode 100755 tooling/bats-assert/test/refute.bats create mode 100755 tooling/bats-assert/test/refute_line.bats create mode 100755 tooling/bats-assert/test/refute_output.bats create mode 100644 tooling/bats-assert/test/refute_regex.bats create mode 100755 tooling/bats-assert/test/refute_stderr.bats create mode 100755 tooling/bats-assert/test/refute_stderr_line.bats create mode 100644 tooling/bats-assert/test/test_helper.bash delete mode 160000 tooling/bats-core create mode 100644 tooling/bats-core/.codespellrc create mode 100644 tooling/bats-core/.devcontainer/Dockerfile create mode 100644 tooling/bats-core/.devcontainer/devcontainer.json create mode 100644 tooling/bats-core/.editorconfig create mode 100755 tooling/bats-core/.gitattributes create mode 100644 tooling/bats-core/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 tooling/bats-core/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 tooling/bats-core/.github/dependabot.yml create mode 100755 tooling/bats-core/.github/workflows/check_pr_label.sh create mode 100644 tooling/bats-core/.github/workflows/codespell.yml create mode 100644 tooling/bats-core/.github/workflows/dependency-review.yml create mode 100644 tooling/bats-core/.github/workflows/release.yml create mode 100644 tooling/bats-core/.github/workflows/release_dockerhub.yml create mode 100644 tooling/bats-core/.github/workflows/scorecard.yml create mode 100644 tooling/bats-core/.github/workflows/set_nounset.bash create mode 100644 tooling/bats-core/.github/workflows/tests.yml create mode 100644 tooling/bats-core/.gitignore create mode 100644 tooling/bats-core/.pre-commit-config.yaml create mode 100644 tooling/bats-core/.readthedocs.yml create mode 100644 tooling/bats-core/AUTHORS create mode 100644 tooling/bats-core/Dockerfile create mode 100644 tooling/bats-core/LICENSE.md create mode 100644 tooling/bats-core/README.md create mode 100644 tooling/bats-core/SECURITY.md create mode 100755 tooling/bats-core/bin/bats create mode 100755 tooling/bats-core/contrib/release.sh create mode 100644 tooling/bats-core/contrib/rpm/bats.spec create mode 100755 tooling/bats-core/contrib/semver create mode 100644 tooling/bats-core/docker-compose.override.dist create mode 100644 tooling/bats-core/docker-compose.yml create mode 100755 tooling/bats-core/docker/install_libs.sh create mode 100755 tooling/bats-core/docker/install_tini.sh create mode 100644 tooling/bats-core/docker/tini.pubkey.gpg create mode 100644 tooling/bats-core/docs/.markdownlint.json create mode 100644 tooling/bats-core/docs/CHANGELOG.md create mode 100644 tooling/bats-core/docs/CODEOWNERS create mode 100644 tooling/bats-core/docs/CODE_OF_CONDUCT.md create mode 100644 tooling/bats-core/docs/CONTRIBUTING.md create mode 100644 tooling/bats-core/docs/Makefile create mode 100644 tooling/bats-core/docs/PULL_REQUEST_TEMPLATE.md create mode 100644 tooling/bats-core/docs/examples/README.md create mode 100644 tooling/bats-core/docs/examples/package-tarball create mode 100755 tooling/bats-core/docs/examples/package-tarball.bats create mode 100644 tooling/bats-core/docs/list-links.py create mode 100644 tooling/bats-core/docs/make.bat create mode 100644 tooling/bats-core/docs/releasing.md create mode 100644 tooling/bats-core/docs/source/_static/.gitkeep create mode 100644 tooling/bats-core/docs/source/_templates/.gitkeep create mode 100644 tooling/bats-core/docs/source/assets/README.md create mode 100644 tooling/bats-core/docs/source/assets/dark_mode_bat.svg create mode 100644 tooling/bats-core/docs/source/assets/dark_mode_cube.svg create mode 100644 tooling/bats-core/docs/source/assets/dark_mode_wordmark_lowercase.svg create mode 100644 tooling/bats-core/docs/source/assets/dark_mode_wordmark_uppercase.svg create mode 100644 tooling/bats-core/docs/source/assets/light_mode_bat.svg create mode 100644 tooling/bats-core/docs/source/assets/light_mode_cube.svg create mode 100644 tooling/bats-core/docs/source/assets/light_mode_wordmark_lowercase.svg create mode 100644 tooling/bats-core/docs/source/assets/light_mode_wordmark_uppercase.svg create mode 100644 tooling/bats-core/docs/source/conf.py create mode 100644 tooling/bats-core/docs/source/docker-usage.md create mode 100644 tooling/bats-core/docs/source/faq.rst create mode 100644 tooling/bats-core/docs/source/gotchas.rst create mode 100644 tooling/bats-core/docs/source/index.rst create mode 100644 tooling/bats-core/docs/source/installation.rst create mode 100644 tooling/bats-core/docs/source/requirements.txt create mode 100644 tooling/bats-core/docs/source/support-matrix.rst create mode 100644 tooling/bats-core/docs/source/tutorial.rst create mode 100644 tooling/bats-core/docs/source/usage.md create mode 100644 tooling/bats-core/docs/source/warnings/BW01.rst create mode 100644 tooling/bats-core/docs/source/warnings/BW02.rst create mode 100644 tooling/bats-core/docs/source/warnings/BW03.rst create mode 100644 tooling/bats-core/docs/source/warnings/index.rst create mode 100644 tooling/bats-core/docs/source/writing-tests.md create mode 100644 tooling/bats-core/docs/versions.md create mode 100755 tooling/bats-core/install.sh create mode 100644 tooling/bats-core/lib/bats-core/common.bash create mode 100644 tooling/bats-core/lib/bats-core/formatter.bash create mode 100644 tooling/bats-core/lib/bats-core/preprocessing.bash create mode 100644 tooling/bats-core/lib/bats-core/semaphore.bash create mode 100644 tooling/bats-core/lib/bats-core/test_functions.bash create mode 100644 tooling/bats-core/lib/bats-core/tracing.bash create mode 100644 tooling/bats-core/lib/bats-core/validator.bash create mode 100644 tooling/bats-core/lib/bats-core/warnings.bash create mode 100755 tooling/bats-core/libexec/bats-core/bats create mode 100755 tooling/bats-core/libexec/bats-core/bats-exec-file create mode 100755 tooling/bats-core/libexec/bats-core/bats-exec-suite create mode 100755 tooling/bats-core/libexec/bats-core/bats-exec-test create mode 100755 tooling/bats-core/libexec/bats-core/bats-format-cat create mode 100755 tooling/bats-core/libexec/bats-core/bats-format-junit create mode 100755 tooling/bats-core/libexec/bats-core/bats-format-pretty create mode 100755 tooling/bats-core/libexec/bats-core/bats-format-tap create mode 100755 tooling/bats-core/libexec/bats-core/bats-format-tap13 create mode 100755 tooling/bats-core/libexec/bats-core/bats-gather-tests create mode 100755 tooling/bats-core/libexec/bats-core/bats-preprocess create mode 100644 tooling/bats-core/man/Makefile create mode 100644 tooling/bats-core/man/README.md create mode 100644 tooling/bats-core/man/bats.1 create mode 100644 tooling/bats-core/man/bats.1.ronn create mode 100644 tooling/bats-core/man/bats.7 create mode 100644 tooling/bats-core/man/bats.7.ronn create mode 100644 tooling/bats-core/package.json create mode 100644 tooling/bats-core/report.log create mode 100644 tooling/bats-core/report.xml create mode 100755 tooling/bats-core/shellcheck.sh create mode 100755 tooling/bats-core/test/bats.bats create mode 100644 tooling/bats-core/test/bats_pipe.bats create mode 100644 tooling/bats-core/test/cat-formatter.bats create mode 100644 tooling/bats-core/test/common.bats create mode 100644 tooling/bats-core/test/concurrent-coordination.bash create mode 100644 tooling/bats-core/test/file_setup_teardown.bats create mode 100644 tooling/bats-core/test/filter.bats create mode 100755 tooling/bats-core/test/fixtures/bats/BATS_TMPDIR.bats create mode 100644 tooling/bats-core/test/fixtures/bats/BATS_variables_dont_contain_double_slashes.bats create mode 100755 tooling/bats-core/test/fixtures/bats/cmd_using_stdin.bash create mode 100644 tooling/bats-core/test/fixtures/bats/comment_style.bats create mode 100755 tooling/bats-core/test/fixtures/bats/date create mode 100644 tooling/bats-core/test/fixtures/bats/dos_line_no_shellcheck.bats create mode 100644 tooling/bats-core/test/fixtures/bats/duplicate-tests_no_shellcheck.bats create mode 100644 tooling/bats-core/test/fixtures/bats/dynamic_test_registration.bats create mode 100644 tooling/bats-core/test/fixtures/bats/empty.bats create mode 100644 tooling/bats-core/test/fixtures/bats/environment.bats create mode 100644 tooling/bats-core/test/fixtures/bats/evaluation_count/file1.bats create mode 100644 tooling/bats-core/test/fixtures/bats/evaluation_count/file2.bats create mode 100755 tooling/bats-core/test/fixtures/bats/exit_11.bash create mode 100644 tooling/bats-core/test/fixtures/bats/expand_var_in_test_name.bats create mode 100644 tooling/bats-core/test/fixtures/bats/exported_function.bats create mode 100644 tooling/bats-core/test/fixtures/bats/external_function_calls.bats create mode 100644 tooling/bats-core/test/fixtures/bats/external_functions.bash create mode 100644 tooling/bats-core/test/fixtures/bats/external_functions.bats create mode 100644 tooling/bats-core/test/fixtures/bats/failing.bats create mode 100644 tooling/bats-core/test/fixtures/bats/failing_and_passing.bats create mode 100644 tooling/bats-core/test/fixtures/bats/failing_helper.bats create mode 100644 tooling/bats-core/test/fixtures/bats/failing_setup.bats create mode 100644 tooling/bats-core/test/fixtures/bats/failing_teardown.bats create mode 100644 tooling/bats-core/test/fixtures/bats/failing_with_bash_cond.bats create mode 100644 tooling/bats-core/test/fixtures/bats/failing_with_bash_expression.bats create mode 100644 tooling/bats-core/test/fixtures/bats/failing_with_negated_command.bats create mode 100644 tooling/bats-core/test/fixtures/bats/failure_callback.bats create mode 100644 tooling/bats-core/test/fixtures/bats/failure_callback_setup_file.bats create mode 100644 tooling/bats-core/test/fixtures/bats/failure_callback_setup_suite/dummy.bats create mode 100644 tooling/bats-core/test/fixtures/bats/failure_callback_setup_suite/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/bats/failure_in_free_code.bats create mode 100644 tooling/bats-core/test/fixtures/bats/focus.bats create mode 100644 tooling/bats-core/test/fixtures/bats/focused_filtered_out.bats create mode 100755 tooling/bats-core/test/fixtures/bats/gobble_up_stdin_sleep_and_print_finish.bash create mode 100644 tooling/bats-core/test/fixtures/bats/hang_after_run.bats create mode 100644 tooling/bats-core/test/fixtures/bats/hang_in_run.bats create mode 100644 tooling/bats-core/test/fixtures/bats/hang_in_setup_file.bats create mode 100644 tooling/bats-core/test/fixtures/bats/hang_in_teardown.bats create mode 100644 tooling/bats-core/test/fixtures/bats/hang_in_teardown_file.bats create mode 100644 tooling/bats-core/test/fixtures/bats/hang_in_test.bats create mode 100644 tooling/bats-core/test/fixtures/bats/intact.bats create mode 100644 tooling/bats-core/test/fixtures/bats/issue-205.bats create mode 100644 tooling/bats-core/test/fixtures/bats/issue-433/repro1.bats create mode 100644 tooling/bats-core/test/fixtures/bats/issue-433/repro2.bats create mode 100644 tooling/bats-core/test/fixtures/bats/issue-519.bats create mode 100644 tooling/bats-core/test/fixtures/bats/load.bats create mode 100644 tooling/bats-core/test/fixtures/bats/loop_keep_IFS.bats create mode 100644 tooling/bats-core/test/fixtures/bats/many_passing_and_one_failing.bats create mode 100644 tooling/bats-core/test/fixtures/bats/no-final-newline.bats create mode 100644 tooling/bats-core/test/fixtures/bats/output.bats create mode 100644 tooling/bats-core/test/fixtures/bats/override_date_on_path.bats create mode 100644 tooling/bats-core/test/fixtures/bats/parallel.bats create mode 100644 tooling/bats-core/test/fixtures/bats/passing.bats create mode 100644 tooling/bats-core/test/fixtures/bats/passing_and_failing.bats create mode 100644 tooling/bats-core/test/fixtures/bats/passing_and_skipping.bats create mode 100644 tooling/bats-core/test/fixtures/bats/passing_failing_and_skipping.bats create mode 100644 tooling/bats-core/test/fixtures/bats/preserve_IFS/helper.bash create mode 100644 tooling/bats-core/test/fixtures/bats/preserve_IFS/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/bats/preserve_IFS/test.bats create mode 100644 tooling/bats-core/test/fixtures/bats/print_output_on_failure.bats create mode 100644 tooling/bats-core/test/fixtures/bats/print_output_on_failure_with_stderr.bats create mode 100644 tooling/bats-core/test/fixtures/bats/quoted_and_unquoted_test_names_no_shellcheck.bats create mode 100644 tooling/bats-core/test/fixtures/bats/read_from_stdin.bats create mode 100644 tooling/bats-core/test/fixtures/bats/reference_unset_parameter.bats create mode 100644 tooling/bats-core/test/fixtures/bats/reference_unset_parameter_in_setup.bats create mode 100644 tooling/bats-core/test/fixtures/bats/reference_unset_parameter_in_teardown.bats create mode 100644 tooling/bats-core/test/fixtures/bats/retry.bats create mode 100644 tooling/bats-core/test/fixtures/bats/retry_success.bats create mode 100644 tooling/bats-core/test/fixtures/bats/run_long_command.bats create mode 100644 tooling/bats-core/test/fixtures/bats/set_-eu_in_setup_and_teardown.bats create mode 100644 tooling/bats-core/test/fixtures/bats/setup.bats create mode 100644 tooling/bats-core/test/fixtures/bats/show-output-of-passing-tests.bats create mode 100644 tooling/bats-core/test/fixtures/bats/sigint_in_failing_test.bats create mode 100644 tooling/bats-core/test/fixtures/bats/single_line_no_shellcheck.bats create mode 100644 tooling/bats-core/test/fixtures/bats/skipped.bats create mode 100644 tooling/bats-core/test/fixtures/bats/skipped_with_parens.bats create mode 100644 tooling/bats-core/test/fixtures/bats/source_nonexistent_file.bats create mode 100644 tooling/bats-core/test/fixtures/bats/source_nonexistent_file_in_setup.bats create mode 100644 tooling/bats-core/test/fixtures/bats/source_nonexistent_file_in_teardown.bats create mode 100644 tooling/bats-core/test/fixtures/bats/tab in filename.bats create mode 100644 tooling/bats-core/test/fixtures/bats/teardown.bats create mode 100644 tooling/bats-core/test/fixtures/bats/teardown_file_override_status.bats create mode 100644 tooling/bats-core/test/fixtures/bats/teardown_override_status.bats create mode 100644 tooling/bats-core/test/fixtures/bats/teardown_suite_override_status/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/bats/teardown_suite_override_status/test.bats create mode 100644 tooling/bats-core/test/fixtures/bats/test_helper.bash create mode 100644 tooling/bats-core/test/fixtures/bats/test_with_slash.bats create mode 100644 tooling/bats-core/test/fixtures/bats/unbound_variable.bats create mode 100644 tooling/bats-core/test/fixtures/bats/unofficial_bash_strict_mode.bash create mode 100644 tooling/bats-core/test/fixtures/bats/unofficial_bash_strict_mode.bats create mode 100644 tooling/bats-core/test/fixtures/bats/update_path_env.bats create mode 100644 tooling/bats-core/test/fixtures/bats/verbose-run.bats create mode 100644 tooling/bats-core/test/fixtures/bats/whitespace_no_shellcheck.bats create mode 100644 tooling/bats-core/test/fixtures/bats/without_trailing_newline.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/error_in_setup_and_teardown_file.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/no_setup_file.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/no_teardown_file.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/setup_file.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/setup_file2.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/setup_file_does_not_leak_env.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/setup_file_does_not_leak_env2.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/setup_file_even_if_all_tests_are_skipped.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/setup_file_failed.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/setup_file_halfway_error.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/teardown_file.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/teardown_file2.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/teardown_file_after_failing_test.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/teardown_file_after_long_test.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/teardown_file_does_not_leak.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/teardown_file_does_not_leak2.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/teardown_file_even_if_all_tests_are_skipped.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/teardown_file_failed.bats create mode 100644 tooling/bats-core/test/fixtures/file_setup_teardown/teardown_file_halfway_error.bats create mode 100755 tooling/bats-core/test/fixtures/formatter/dummy-formatter create mode 100755 tooling/bats-core/test/fixtures/formatter/echo-formatter create mode 100644 tooling/bats-core/test/fixtures/formatter/failing.bats create mode 100644 tooling/bats-core/test/fixtures/formatter/passing.bats create mode 100644 tooling/bats-core/test/fixtures/formatter/passing_and_skipping.bats create mode 100644 tooling/bats-core/test/fixtures/formatter/passing_failing_and_skipping.bats create mode 100644 tooling/bats-core/test/fixtures/formatter/retry.bats create mode 100644 tooling/bats-core/test/fixtures/formatter/skipped_with_parens.bats create mode 100644 tooling/bats-core/test/fixtures/junit-formatter/duplicate/first/file1.bats create mode 100644 tooling/bats-core/test/fixtures/junit-formatter/duplicate/second/file1.bats create mode 100644 tooling/bats-core/test/fixtures/junit-formatter/issue_360.bats create mode 100644 tooling/bats-core/test/fixtures/junit-formatter/issue_531.bats create mode 100644 tooling/bats-core/test/fixtures/junit-formatter/skipped.bats create mode 100644 tooling/bats-core/test/fixtures/junit-formatter/suite/file1.bats create mode 100644 tooling/bats-core/test/fixtures/junit-formatter/suite/file2.bats create mode 100644 tooling/bats-core/test/fixtures/junit-formatter/xml-escape.bats create mode 100644 tooling/bats-core/test/fixtures/load/ambiguous create mode 100644 tooling/bats-core/test/fixtures/load/ambiguous.bash create mode 100644 tooling/bats-core/test/fixtures/load/bats_load_library.bats create mode 100644 tooling/bats-core/test/fixtures/load/exit1.bash create mode 100644 tooling/bats-core/test/fixtures/load/failing_bats_load_library.bats create mode 100644 tooling/bats-core/test/fixtures/load/failing_load.bats create mode 100644 tooling/bats-core/test/fixtures/load/find_library_helper.bats create mode 100644 tooling/bats-core/test/fixtures/load/find_library_helper_err.bats create mode 100644 tooling/bats-core/test/fixtures/load/load.bats create mode 100644 tooling/bats-core/test/fixtures/load/load_in_teardown_after_failure.bats create mode 100644 tooling/bats-core/test/fixtures/load/return1.bash create mode 100644 tooling/bats-core/test/fixtures/load/test_helper.bash create mode 100644 tooling/bats-core/test/fixtures/parallel/must_not_parallelize_across_files/file1.bats create mode 100644 tooling/bats-core/test/fixtures/parallel/must_not_parallelize_across_files/file2.bats create mode 100644 tooling/bats-core/test/fixtures/parallel/must_not_parallelize_within_file.bats create mode 100644 tooling/bats-core/test/fixtures/parallel/parallel-preserve-environment.bats create mode 100644 tooling/bats-core/test/fixtures/parallel/parallel.bats create mode 100644 tooling/bats-core/test/fixtures/parallel/parallel_factor.bats create mode 100644 tooling/bats-core/test/fixtures/parallel/setup_file/setup_file.bats create mode 120000 tooling/bats-core/test/fixtures/parallel/setup_file/setup_file1.bats create mode 120000 tooling/bats-core/test/fixtures/parallel/setup_file/setup_file2.bats create mode 120000 tooling/bats-core/test/fixtures/parallel/setup_file/setup_file3.bats create mode 100644 tooling/bats-core/test/fixtures/parallel/suite/parallel1.bats create mode 120000 tooling/bats-core/test/fixtures/parallel/suite/parallel2.bats create mode 120000 tooling/bats-core/test/fixtures/parallel/suite/parallel3.bats create mode 120000 tooling/bats-core/test/fixtures/parallel/suite/parallel4.bats create mode 100644 tooling/bats-core/test/fixtures/run/failing.bats create mode 100644 tooling/bats-core/test/fixtures/run/invalid.bats create mode 100644 tooling/bats-core/test/fixtures/suite/empty/.gitkeep create mode 100644 tooling/bats-core/test/fixtures/suite/errors_in_multiple_load/a.bats create mode 100644 tooling/bats-core/test/fixtures/suite/errors_in_multiple_load/b.bats create mode 100644 tooling/bats-core/test/fixtures/suite/errors_in_multiple_load/c.bats create mode 100644 tooling/bats-core/test/fixtures/suite/errors_in_multiple_load/test_helper.bash create mode 100644 tooling/bats-core/test/fixtures/suite/filter/a.bats create mode 100644 tooling/bats-core/test/fixtures/suite/filter/b.bats create mode 100644 tooling/bats-core/test/fixtures/suite/filter/c.bats create mode 100644 tooling/bats-core/test/fixtures/suite/multiple/a.bats create mode 100644 tooling/bats-core/test/fixtures/suite/multiple/b.bats create mode 100644 tooling/bats-core/test/fixtures/suite/multiple_load_constants/a.bats create mode 100644 tooling/bats-core/test/fixtures/suite/multiple_load_constants/b.bats create mode 100644 tooling/bats-core/test/fixtures/suite/multiple_load_constants/test_helper.bash create mode 100644 tooling/bats-core/test/fixtures/suite/override_BATS_FILE_EXTENSION/subfolder/test.other_extension create mode 100644 tooling/bats-core/test/fixtures/suite/override_BATS_FILE_EXTENSION/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite/override_BATS_FILE_EXTENSION/test.test create mode 100644 tooling/bats-core/test/fixtures/suite/recursive/subsuite/test2.bats create mode 100644 tooling/bats-core/test/fixtures/suite/recursive/test.bats create mode 120000 tooling/bats-core/test/fixtures/suite/recursive_with_symlinks/subsuite create mode 120000 tooling/bats-core/test/fixtures/suite/recursive_with_symlinks/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite/single/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite/skip/skip-in-setup-and-teardown.bats create mode 100644 tooling/bats-core/test/fixtures/suite/skip/skip-in-setup.bats create mode 100644 tooling/bats-core/test/fixtures/suite/skip/skip-in-teardown.bats create mode 100644 tooling/bats-core/test/fixtures/suite/skip/skip-in-test-and-teardown.bats create mode 100644 tooling/bats-core/test/fixtures/suite/skip/skip-in-test.bats create mode 100644 tooling/bats-core/test/fixtures/suite/test_number/file1.bats create mode 100644 tooling/bats-core/test/fixtures/suite/test_number/file2.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/call_load/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/call_load/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/call_load/test_helper.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/default_name/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/default_name/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/error_in_free_code/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/error_in_free_code/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/error_in_setup_suite/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/error_in_setup_suite/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/error_in_teardown_suite/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/error_in_teardown_suite/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/exported_vars/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/exported_vars/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/failure_in_setup_suite/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/failure_in_setup_suite/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/failure_in_teardown_suite/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/failure_in_teardown_suite/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/no_failure_no_output/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/no_failure_no_output/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/no_setup_suite_function/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/no_setup_suite_function/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/non_default_name/setup_suite_non_default.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/non_default_name/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/output_with_failure/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/output_with_failure/test.bats create mode 120000 tooling/bats-core/test/fixtures/suite_setup_teardown/pick_up_toplevel/folder1/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/pick_up_toplevel/folder1/test.bats create mode 120000 tooling/bats-core/test/fixtures/suite_setup_teardown/pick_up_toplevel/folder2/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/pick_up_toplevel/folder2/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/pick_up_toplevel/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/pick_up_toplevel/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/return_nonzero_in_teardown_suite/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/return_nonzero_in_teardown_suite/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/skip_in_setup_file.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/stderr_in_setup_teardown_suite/setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/stderr_in_setup_teardown_suite/test.bats create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/syntax_error/setup_suite_no_shellcheck create mode 100644 tooling/bats-core/test/fixtures/suite_setup_teardown/syntax_error/test.bats create mode 100644 tooling/bats-core/test/fixtures/tagging/BATS_TEST_TAGS.bats create mode 100644 tooling/bats-core/test/fixtures/tagging/invalid_tags.bats create mode 100644 tooling/bats-core/test/fixtures/tagging/print_tags_on_error.bats create mode 100644 tooling/bats-core/test/fixtures/tagging/tagged.bats create mode 100644 tooling/bats-core/test/fixtures/tagging/trimming.bats create mode 100644 tooling/bats-core/test/fixtures/timeout/sleep2.bats create mode 100644 tooling/bats-core/test/fixtures/trace/failing_complex.bats create mode 100644 tooling/bats-core/test/fixtures/trace/failing_recursive.bats create mode 100644 tooling/bats-core/test/fixtures/warnings/BW01.bats create mode 100644 tooling/bats-core/test/fixtures/warnings/BW01_check_exit_code_is_127.bats create mode 100644 tooling/bats-core/test/fixtures/warnings/BW01_no_exit_code_check_no_exit_code_127.bats create mode 100644 tooling/bats-core/test/fixtures/warnings/BW02.bats create mode 100644 tooling/bats-core/test/fixtures/warnings/BW03/define_setup_suite_in_wrong_file.bats create mode 100644 tooling/bats-core/test/fixtures/warnings/BW03/non_default_setup_suite.bash create mode 100644 tooling/bats-core/test/fixtures/warnings/BW03/suppress_warning.bats create mode 100644 tooling/bats-core/test/formatter.bats create mode 100644 tooling/bats-core/test/install.bats create mode 100644 tooling/bats-core/test/junit-formatter.bats create mode 100644 tooling/bats-core/test/load.bats create mode 100644 tooling/bats-core/test/parallel.bats create mode 100644 tooling/bats-core/test/pretty-formatter.bats create mode 100644 tooling/bats-core/test/root.bats create mode 100644 tooling/bats-core/test/run.bats create mode 100755 tooling/bats-core/test/suite.bats create mode 100644 tooling/bats-core/test/suite_setup_teardown.bats create mode 100644 tooling/bats-core/test/tagging.bats create mode 100644 tooling/bats-core/test/tap13-formatter.bats create mode 100644 tooling/bats-core/test/test_helper.bash create mode 100644 tooling/bats-core/test/timeout.bats create mode 100644 tooling/bats-core/test/trace.bats create mode 100644 tooling/bats-core/test/warnings.bats create mode 100644 tooling/bats-core/test2/setup_suite.bash create mode 100644 tooling/bats-core/test2/test.bats create mode 100755 tooling/bats-core/uninstall.sh delete mode 160000 tooling/bats-support create mode 100644 tooling/bats-support/.github/dependabot.yml create mode 100644 tooling/bats-support/.github/workflows/sync-default-branch.yml create mode 100644 tooling/bats-support/.github/workflows/test.yml create mode 100644 tooling/bats-support/.gitignore create mode 100644 tooling/bats-support/CHANGELOG.md create mode 100644 tooling/bats-support/LICENSE create mode 100644 tooling/bats-support/README.md create mode 100644 tooling/bats-support/load.bash create mode 100644 tooling/bats-support/package-lock.json create mode 100644 tooling/bats-support/package.json create mode 100644 tooling/bats-support/src/error.bash create mode 100644 tooling/bats-support/src/lang.bash create mode 100644 tooling/bats-support/src/output.bash create mode 100755 tooling/bats-support/test/50-output-10-batslib_err.bats create mode 100755 tooling/bats-support/test/50-output-11-batslib_count_lines.bats create mode 100755 tooling/bats-support/test/50-output-12-batslib_is_single_line.bats create mode 100755 tooling/bats-support/test/50-output-13-batslib_get_max_single_line_key_width.bats create mode 100755 tooling/bats-support/test/50-output-14-batslib_print_kv_single.bats create mode 100755 tooling/bats-support/test/50-output-15-batslib_print_kv_multi.bats create mode 100755 tooling/bats-support/test/50-output-16-batslib_print_kv_single_or_multi.bats create mode 100755 tooling/bats-support/test/50-output-17-batslib_prefix.bats create mode 100755 tooling/bats-support/test/50-output-18-batslib_mark.bats create mode 100755 tooling/bats-support/test/50-output-19-batslib_decorate.bats create mode 100755 tooling/bats-support/test/51-error-10-fail.bats create mode 100755 tooling/bats-support/test/52-lang-10-batslib_is_caller.bats create mode 100755 tooling/bats-support/test/cat create mode 100644 tooling/bats-support/test/test_helper.bash diff --git a/tooling/bats-assert b/tooling/bats-assert deleted file mode 160000 index 3be0fb7856791b..00000000000000 --- a/tooling/bats-assert +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3be0fb7856791b4a64aef7a1336e965f5252e45f diff --git a/tooling/bats-assert/.github/CONTRIBUTING.md b/tooling/bats-assert/.github/CONTRIBUTING.md new file mode 100644 index 00000000000000..d0a9145bed1fbe --- /dev/null +++ b/tooling/bats-assert/.github/CONTRIBUTING.md @@ -0,0 +1,8 @@ +# Contributing + +## Releasing + +From a clean working copy, run `npm version major|minor|patch|VERSION`. +This will bump the package version, commit, tag, and push. +The tag-push event triggers the release workflow on GitHub. +The workflow creates a GitHub Release from the tag and publishes to npm. diff --git a/tooling/bats-assert/.github/workflows/release.yml b/tooling/bats-assert/.github/workflows/release.yml new file mode 100644 index 00000000000000..95e928c858ebd8 --- /dev/null +++ b/tooling/bats-assert/.github/workflows/release.yml @@ -0,0 +1,37 @@ +name: Release +on: + push: { tags: "v[0-9]+.[0-9]+.[0-9]+*" } + +permissions: {} +jobs: + github: + permissions: { contents: write } + runs-on: ubuntu-latest + steps: + - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + with: { egress-policy: audit } + - uses: actions/checkout@v4 + # TODO exit this job differently than success if release already exists + - name: gh release create + run: | + # shellcheck disable=SC2086 + gh release view $tag || \ + gh release create ${tag/*-*/"$tag" --prerelease} --generate-notes + env: + GH_TOKEN: ${{ github.token }} + tag: ${{ github.ref_name }} + + npm: + permissions: { id-token: write } + runs-on: ubuntu-latest + steps: + - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + with: { egress-policy: audit } + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + registry-url: https://registry.npmjs.org + - run: npm ci + - run: npm publish --provenance + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/tooling/bats-assert/.github/workflows/sync-default-branch.yml b/tooling/bats-assert/.github/workflows/sync-default-branch.yml new file mode 100644 index 00000000000000..dceca85aca5f50 --- /dev/null +++ b/tooling/bats-assert/.github/workflows/sync-default-branch.yml @@ -0,0 +1,25 @@ +name: Sync Default Branch +on: + push: { branches: main } + workflow_dispatch: +permissions: {} + +jobs: + sync-default-branch: + if: github.ref_name == github.event.repository.default_branch + permissions: {contents: write} + runs-on: ubuntu-latest + steps: + - uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 + with: {egress-policy: audit} + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - run: git push --force origin HEAD:refs/heads/master + +# One-time commands for users to switch-over: +# +# ```console +# git branch -m master main +# git fetch origin +# git branch -u origin/main main +# git remote set-head origin -a +# ``` diff --git a/tooling/bats-assert/.github/workflows/test.yml b/tooling/bats-assert/.github/workflows/test.yml new file mode 100644 index 00000000000000..6c95ce259c5db7 --- /dev/null +++ b/tooling/bats-assert/.github/workflows/test.yml @@ -0,0 +1,9 @@ +name: Test +on: + push: + pull_request: + workflow_dispatch: + +jobs: + test: + uses: bats-core/.github/.github/workflows/test.yml@v1 diff --git a/tooling/bats-assert/.gitignore b/tooling/bats-assert/.gitignore new file mode 100644 index 00000000000000..41a3ee1e331126 --- /dev/null +++ b/tooling/bats-assert/.gitignore @@ -0,0 +1,3 @@ +/node_modules +/yarn.lock +/bats-assert-*.tgz diff --git a/tooling/bats-assert/LICENSE b/tooling/bats-assert/LICENSE new file mode 100644 index 00000000000000..670154e3538863 --- /dev/null +++ b/tooling/bats-assert/LICENSE @@ -0,0 +1,116 @@ +CC0 1.0 Universal + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific +works ("Commons") that the public can reliably and without fear of later +claims of infringement build upon, modify, incorporate in other works, reuse +and redistribute as freely as possible in any form whatsoever and for any +purposes, including without limitation commercial purposes. These owners may +contribute to the Commons to promote the ideal of a free culture and the +further production of creative, cultural and scientific works, or to gain +reputation or greater distribution for their Work in part through the use and +efforts of others. + +For these and/or other purposes and motivations, and without any expectation +of additional consideration or compensation, the person associating CC0 with a +Work (the "Affirmer"), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work +and publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not limited +to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + + ii. moral rights retained by the original author(s) and/or performer(s); + + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + + v. rights protecting the extraction, dissemination, use and reuse of data in + a Work; + + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, +applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and +unconditionally waives, abandons, and surrenders all of Affirmer's Copyright +and Related Rights and associated claims and causes of action, whether now +known or unknown (including existing as well as future claims and causes of +action), in the Work (i) in all territories worldwide, (ii) for the maximum +duration provided by applicable law or treaty (including future time +extensions), (iii) in any current or future medium and for any number of +copies, and (iv) for any purpose whatsoever, including without limitation +commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes +the Waiver for the benefit of each member of the public at large and to the +detriment of Affirmer's heirs and successors, fully intending that such Waiver +shall not be subject to revocation, rescission, cancellation, termination, or +any other legal or equitable action to disrupt the quiet enjoyment of the Work +by the public as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be +judged legally invalid or ineffective under applicable law, then the Waiver +shall be preserved to the maximum extent permitted taking into account +Affirmer's express Statement of Purpose. In addition, to the extent the Waiver +is so judged Affirmer hereby grants to each affected person a royalty-free, +non transferable, non sublicensable, non exclusive, irrevocable and +unconditional license to exercise Affirmer's Copyright and Related Rights in +the Work (i) in all territories worldwide, (ii) for the maximum duration +provided by applicable law or treaty (including future time extensions), (iii) +in any current or future medium and for any number of copies, and (iv) for any +purpose whatsoever, including without limitation commercial, advertising or +promotional purposes (the "License"). The License shall be deemed effective as +of the date CC0 was applied by Affirmer to the Work. Should any part of the +License for any reason be judged legally invalid or ineffective under +applicable law, such partial invalidity or ineffectiveness shall not +invalidate the remainder of the License, and in such case Affirmer hereby +affirms that he or she will not (i) exercise any of his or her remaining +Copyright and Related Rights in the Work or (ii) assert any associated claims +and causes of action with respect to the Work, in either case contrary to +Affirmer's express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + + b. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness + for a particular purpose, non infringement, or the absence of latent or + other defects, accuracy, or the present or absence of errors, whether or not + discoverable, all to the greatest extent permissible under applicable law. + + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without limitation + any person's Copyright and Related Rights in the Work. Further, Affirmer + disclaims responsibility for obtaining any necessary consents, permissions + or other rights required for any use of the Work. + + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to this + CC0 or use of the Work. + +For more information, please see + diff --git a/tooling/bats-assert/README.md b/tooling/bats-assert/README.md new file mode 100644 index 00000000000000..8a5fc176b66f3a --- /dev/null +++ b/tooling/bats-assert/README.md @@ -0,0 +1,1038 @@ +# bats-assert + +[![License](https://img.shields.io/npm/l/bats-assert.svg)](https://github.com/bats-core/bats-assert/blob/master/LICENSE) +[![GitHub release](https://img.shields.io/github/release/bats-core/bats-assert.svg)](https://github.com/bats-core/bats-assert/releases/latest) +[![npm release](https://img.shields.io/npm/v/bats-assert.svg)](https://www.npmjs.com/package/bats-assert) +[![Tests](https://github.com/bats-core/bats-assert/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/bats-core/bats-assert/actions/workflows/test.yml) + +`bats-assert` is a helper library providing common assertions for [Bats][bats]. + +- [Install](#install) +- [Usage](#usage) +- [Options](#options) +- [Full Assertion API](#full-assertion-api) + +In the context of this project, an [assertion][wikipedia-assertions] is a function that perform a test and returns `1` on failure or `0` on success. +To make debugging easier, the assertion also outputs relevant information on failure. +The output is [formatted][bats-support-output] for readability. +To make assertions usable outside of `@test` blocks, the output is sent to [stderr][wikipedia-stderr]. + +The most recent invocation of Bats' `run` function is used for testing assertions on output and status code. + +[wikipedia-assertions]: https://en.wikipedia.org/wiki/Assertion_(software_development) +[wikipedia-stderr]: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_(stderr) + +## Install + +This project has one dependency, for output formatting: [`bats-support`][bats-support] + +Read the [shared documentation][bats-docs] to learn how to install and load both libraries. + +## Usage + +This project provides the following functions: + + - [assert](#assert) / [refute](#refute) Assert a given expression evaluates to `true` or `false`. + - [assert_equal](#assert_equal) Assert two parameters are equal. + - [assert_not_equal](#assert_not_equal) Assert two parameters are not equal. + - [assert_success](#assert_success) / [assert_failure](#assert_failure) Assert exit status is `0` or `1`. + - [assert_output](#assert_output) / [refute_output](#refute_output) Assert output does (or does not) contain given content. + - [assert_line](#assert_line) / [refute_line](#refute_line) Assert a specific line of output does (or does not) contain given content. + - [assert_regex](#assert_regex) / [refute_regex](#refute_regex) Assert a parameter does (or does not) match given pattern. + - [assert_stderr](#assert_stderr) / [refute_stderr](#refute_stderr) Assert stderr does (or does not) contain given content. + - [assert_stderr_line](#assert_stderr_line) / [refute_stderr_line](#refute_stderr_line) Assert a specific line of stderr does (or does not) contain given content. + +These commands are described in more detail below. + +## Options + +For functions that have options, `--` disables option parsing for the remaining arguments to allow using arguments identical to one of the allowed options. + +```bash +assert_output -- '-p' +``` + +Specifying `--` as an argument is similarly simple. + +```bash +refute_line -- '--' +``` + + +## Full Assertion API + +### `assert` + +Fail if the given expression evaluates to false. + +> _**Note**: +> The expression must be a simple command. +> [Compound commands][bash-comp-cmd], such as `[[`, can be used only when executed with `bash -c`._ + +```bash +@test 'assert()' { + assert [ 1 -lt 0 ] +} +``` + +On failure, the failed expression is displayed. + +``` +-- assertion failed -- +expression : [ 1 -lt 0 ] +-- +``` + + +### `refute` + +Fail if the given expression evaluates to true. + +> _**Note** +> The expression must be a simple command. +> [Compound commands][bash-comp-cmd], such as `[[`, can be used only when executed with `bash -c`._ + +```bash +@test 'refute()' { + refute [ 1 -gt 0 ] +} +``` + +On failure, the successful expression is displayed. + +``` +-- assertion succeeded, but it was expected to fail -- +expression : [ 1 -gt 0 ] +-- +``` + + +### `assert_equal` + +Fail if the two parameters, actual and expected value respectively, do not equal. + +```bash +@test 'assert_equal()' { + assert_equal 'have' 'want' +} +``` + +On failure, the expected and actual values are displayed. + +``` +-- values do not equal -- +expected : want +actual : have +-- +``` + +If either value is longer than one line both are displayed in *multi-line* format. + + +### `assert_not_equal` + +Fail if the two parameters, actual and unexpected value respectively, are equal. + +```bash +@test 'assert_not_equal()' { + assert_not_equal 'foobar' 'foobar' +} +``` + +On failure, the expected and actual values are displayed. + +``` +-- values should not be equal -- +unexpected : foobar +actual : foobar +-- +``` + +If either value is longer than one line both are displayed in *multi-line* format. + + +### `assert_success` + +Fail if `$status` is not 0. + +```bash +@test 'assert_success() status only' { + run bash -c "echo 'Error!'; exit 1" + assert_success +} +``` + +On failure, `$status` and `$output` are displayed. + +``` +-- command failed -- +status : 1 +output : Error! +-- +``` + +If `$output` is longer than one line, it is displayed in *multi-line* format. + + +### `assert_failure` + +Fail if `$status` is 0. + +```bash +@test 'assert_failure() status only' { + run echo 'Success!' + assert_failure +} +``` + +On failure, `$output` is displayed. + +``` +-- command succeeded, but it was expected to fail -- +output : Success! +-- +``` + +If `$output` is longer than one line, it is displayed in *multi-line* format. + +#### Expected status + +When one parameter is specified, fail if `$status` does not equal the expected status specified by the parameter. + +```bash +@test 'assert_failure() with expected status' { + run bash -c "echo 'Error!'; exit 1" + assert_failure 2 +} +``` + +On failure, the expected and actual status, and `$output` are displayed. + +``` +-- command failed as expected, but status differs -- +expected : 2 +actual : 1 +output : Error! +-- +``` + +If `$output` is longer than one line, it is displayed in *multi-line* format. + + +### `assert_output` + +This function helps to verify that a command or function produces the correct output by checking that the specified expected output matches the actual output. +Matching can be literal (default), partial or regular expression. +This function is the logical complement of `refute_output`. + +#### Literal matching + +By default, literal matching is performed. +The assertion fails if `$output` does not equal the expected output. + +```bash +@test 'assert_output()' { + run echo 'have' + assert_output 'want' +} +``` + +On failure, the expected and actual output are displayed. + +``` +-- output differs -- +expected : want +actual : have +-- +``` + +If either value is longer than one line both are displayed in *multi-line* format. + +#### Existence + +To assert that any (non-empty) output exists at all, simply omit the matching argument. + +```bash +@test 'assert_output()' { + run echo 'have' + assert_output +} +``` + +On failure, an error message is displayed. + +``` +-- no output -- +expected non-empty output, but output was empty +-- +``` + +#### Partial matching + +Partial matching can be enabled with the `--partial` option (`-p` for short). +When used, the assertion fails if the expected *substring* is not found in `$output`. + +```bash +@test 'assert_output() partial matching' { + run echo 'ERROR: no such file or directory' + assert_output --partial 'SUCCESS' +} +``` + +On failure, the substring and the output are displayed. + +``` +-- output does not contain substring -- +substring : SUCCESS +output : ERROR: no such file or directory +-- +``` + +This option and regular expression matching (`--regexp` or `-e`) are mutually exclusive. +An error is displayed when used simultaneously. + +#### Regular expression matching + +Regular expression matching can be enabled with the `--regexp` option (`-e` for short). +When used, the assertion fails if the *[extended regular expression]* does not match `$output`. + +[extended regular expression]: https://en.wikibooks.org/wiki/Regular_Expressions/POSIX-Extended_Regular_Expressions + +> [!IMPORTANT] +> Bash [doesn't support](https://stackoverflow.com/a/48898886/5432315) certain parts of regular expressions you may be used to: +> * `\d` `\D` `\s` `\S` `\w` `\W` — these can be replaced with POSIX character class equivalents `[[:digit:]]`, `[^[:digit:]]`, `[[:space:]]`, `[^[:space:]]`, `[_[:alnum:]]`, and `[^_[:alnum:]]`, respectively. (Notice the last case, where the `[:alnum:]` POSIX character class is augmented with underscore to be exactly equivalent to the Perl `\w` shorthand.) +> * Non-greedy matching. You can sometimes replace `a.*?b` with something like `a[^ab]*b` to get a similar effect in practice, though the two are not exactly equivalent. +> * Non-capturing parentheses `(?:...)`. In the trivial case, just use capturing parentheses `(...)` instead; though of course, if you use capture groups and/or backreferences, this will renumber your capture groups. +> * Lookarounds like `(?<=before)` or `(?!after)`. (In fact anything with `(?` is a Perl extension.) There is no simple general workaround for these, though you can sometimes rephrase your problem into one where lookarounds can be avoided. + +> _**Note**: +> The anchors `^` and `$` bind to the beginning and the end of the entire output (not individual lines), respectively._ + +```bash +@test 'assert_output() regular expression matching' { + run echo 'Foobar 0.1.0' + assert_output --regexp '^Foobar v[0-9]+\.[0-9]+\.[0-9]$' +} +``` + +On failure, the regular expression and the output are displayed. + +``` +-- regular expression does not match output -- +regexp : ^Foobar v[0-9]+\.[0-9]+\.[0-9]$ +output : Foobar 0.1.0 +-- +``` + +An error is displayed if the specified extended regular expression is invalid. + +This option and partial matching (`--partial` or `-p`) are mutually exclusive. +An error is displayed when used simultaneously. + +#### Standard Input, HereDocs and HereStrings + +The expected output can be specified via standard input (also heredoc/herestring) with the `-`/`--stdin` option. + +```bash +@test 'assert_output() with pipe' { + run echo 'hello' + echo 'hello' | assert_output - +} + +@test 'assert_output() with herestring' { + run echo 'hello' + assert_output - <<< hello +} +``` + + +### `refute_output` + +This function helps to verify that a command or function produces the correct output by checking that the specified unexpected output does not match the actual output. +Matching can be literal (default), partial or regular expression. +This function is the logical complement of `assert_output`. + +#### Literal matching + +By default, literal matching is performed. +The assertion fails if `$output` equals the unexpected output. + +```bash +@test 'refute_output()' { + run echo 'want' + refute_output 'want' +} +``` + +On failure, the output is displayed. + +``` +-- output equals, but it was expected to differ -- +output : want +-- +``` + +If output is longer than one line it is displayed in *multi-line* format. + +#### Existence + +To assert that there is no output at all, simply omit the matching argument. + +```bash +@test 'refute_output()' { + run foo --silent + refute_output +} +``` + +On failure, an error message is displayed. + +``` +-- unexpected output -- +expected no output, but output was non-empty +-- +``` + +#### Partial matching + +Partial matching can be enabled with the `--partial` option (`-p` for short). +When used, the assertion fails if the unexpected *substring* is found in `$output`. + +```bash +@test 'refute_output() partial matching' { + run echo 'ERROR: no such file or directory' + refute_output --partial 'ERROR' +} +``` + +On failure, the substring and the output are displayed. + +``` +-- output should not contain substring -- +substring : ERROR +output : ERROR: no such file or directory +-- +``` + +This option and regular expression matching (`--regexp` or `-e`) are mutually exclusive. +An error is displayed when used simultaneously. + +#### Regular expression matching + +Regular expression matching can be enabled with the `--regexp` option (`-e` for short). +When used, the assertion fails if the *extended regular expression* matches `$output`. + +> _**Note**: +> The anchors `^` and `$` bind to the beginning and the end of the entire output (not individual lines), respectively._ + +```bash +@test 'refute_output() regular expression matching' { + run echo 'Foobar v0.1.0' + refute_output --regexp '^Foobar v[0-9]+\.[0-9]+\.[0-9]$' +} +``` + +On failure, the regular expression and the output are displayed. + +``` +-- regular expression should not match output -- +regexp : ^Foobar v[0-9]+\.[0-9]+\.[0-9]$ +output : Foobar v0.1.0 +-- +``` + +An error is displayed if the specified extended regular expression is invalid. + +This option and partial matching (`--partial` or `-p`) are mutually exclusive. +An error is displayed when used simultaneously. + +#### Standard Input, HereDocs and HereStrings + +The unexpected output can be specified via standard input (also heredoc/herestring) with the `-`/`--stdin` option. + +```bash +@test 'refute_output() with pipe' { + run echo 'hello' + echo 'world' | refute_output - +} + +@test 'refute_output() with herestring' { + run echo 'hello' + refute_output - <<< world +} +``` + + +### `assert_line` + +Similarly to `assert_output`, this function helps to verify that a command or function produces the correct output. +It checks that the expected line appears in the output (default) or in a specific line of it. +Matching can be literal (default), partial or regular expression. +This function is the logical complement of `refute_line`. + +> _**Warning**: +> Due to a [bug in Bats][bats-93], empty lines are discarded from `${lines[@]}`, +> causing line indices to change and preventing testing for empty lines._ + +[bats-93]: https://github.com/sstephenson/bats/pull/93 + +#### Looking for a line in the output + +By default, the entire output is searched for the expected line. +The assertion fails if the expected line is not found in `${lines[@]}`. + +```bash +@test 'assert_line() looking for line' { + run echo $'have-0\nhave-1\nhave-2' + assert_line 'want' +} +``` + +On failure, the expected line and the output are displayed. + +> _**Warning**: +> The output displayed does not contain empty lines. +> See the Warning above for more._ + +``` +-- output does not contain line -- +line : want +output (3 lines): + have-0 + have-1 + have-2 +-- +``` + +If output is not longer than one line, it is displayed in *two-column* format. + +#### Matching a specific line + +When the `--index ` option is used (`-n ` for short), the expected line is matched only against the line identified by the given index. +The assertion fails if the expected line does not equal `${lines[]}`. + +```bash +@test 'assert_line() specific line' { + run echo $'have-0\nhave-1\nhave-2' + assert_line --index 1 'want-1' +} +``` + +On failure, the index and the compared lines are displayed. + +``` +-- line differs -- +index : 1 +expected : want-1 +actual : have-1 +-- +``` + +#### Partial matching + +Partial matching can be enabled with the `--partial` option (`-p` for short). +When used, a match fails if the expected *substring* is not found in the matched line. + +```bash +@test 'assert_line() partial matching' { + run echo $'have 1\nhave 2\nhave 3' + assert_line --partial 'want' +} +``` + +On failure, the same details are displayed as for literal matching, except that the substring replaces the expected line. + +``` +-- no output line contains substring -- +substring : want +output (3 lines): + have 1 + have 2 + have 3 +-- +``` + +This option and regular expression matching (`--regexp` or `-e`) are mutually exclusive. +An error is displayed when used simultaneously. + +#### Regular expression matching + +Regular expression matching can be enabled with the `--regexp` option (`-e` for short). +When used, a match fails if the *extended regular expression* does not match the line being tested. + +> _**Note**: +> As expected, the anchors `^` and `$` bind to the beginning and the end of the matched line, respectively._ + +```bash +@test 'assert_line() regular expression matching' { + run echo $'have-0\nhave-1\nhave-2' + assert_line --index 1 --regexp '^want-[0-9]$' +} +``` + +On failure, the same details are displayed as for literal matching, except that the regular expression replaces the expected line. + +``` +-- regular expression does not match line -- +index : 1 +regexp : ^want-[0-9]$ +line : have-1 +-- +``` + +An error is displayed if the specified extended regular expression is invalid. + +This option and partial matching (`--partial` or `-p`) are mutually exclusive. +An error is displayed when used simultaneously. + + +### `refute_line` + +Similarly to `refute_output`, this function helps to verify that a command or function produces the correct output. +It checks that the unexpected line does not appear in the output (default) or in a specific line of it. +Matching can be literal (default), partial or regular expression. +This function is the logical complement of `assert_line`. + +> _**Warning**: +> Due to a [bug in Bats][bats-93], empty lines are discarded from `${lines[@]}`, +> causing line indices to change and preventing testing for empty lines._ + +[bats-93]: https://github.com/sstephenson/bats/pull/93 + +#### Looking for a line in the output + +By default, the entire output is searched for the unexpected line. +The assertion fails if the unexpected line is found in `${lines[@]}`. + +```bash +@test 'refute_line() looking for line' { + run echo $'have-0\nwant\nhave-2' + refute_line 'want' +} +``` + +On failure, the unexpected line, the index of its first match and the output with the matching line highlighted are displayed. + +> _**Warning**: +> The output displayed does not contain empty lines. +> See the Warning above for more._ + +``` +-- line should not be in output -- +line : want +index : 1 +output (3 lines): + have-0 +> want + have-2 +-- +``` + +If output is not longer than one line, it is displayed in *two-column* format. + +#### Matching a specific line + +When the `--index ` option is used (`-n ` for short), the unexpected line is matched only against the line identified by the given index. +The assertion fails if the unexpected line equals `${lines[]}`. + +```bash +@test 'refute_line() specific line' { + run echo $'have-0\nwant-1\nhave-2' + refute_line --index 1 'want-1' +} +``` + +On failure, the index and the unexpected line are displayed. + +``` +-- line should differ -- +index : 1 +line : want-1 +-- +``` + +#### Partial matching + +Partial matching can be enabled with the `--partial` option (`-p` for short). +When used, a match fails if the unexpected *substring* is found in the matched line. + +```bash +@test 'refute_line() partial matching' { + run echo $'have 1\nwant 2\nhave 3' + refute_line --partial 'want' +} +``` + +On failure, in addition to the details of literal matching, the substring is also displayed. +When used with `--index ` the substring replaces the unexpected line. + +``` +-- no line should contain substring -- +substring : want +index : 1 +output (3 lines): + have 1 +> want 2 + have 3 +-- +``` + +This option and regular expression matching (`--regexp` or `-e`) are mutually exclusive. +An error is displayed when used simultaneously. + +#### Regular expression matching + +Regular expression matching can be enabled with the `--regexp` option (`-e` for short). +When used, a match fails if the *extended regular expression* matches the line being tested. + +> _**Note**: +> As expected, the anchors `^` and `$` bind to the beginning and the end of the matched line, respectively._ + +```bash +@test 'refute_line() regular expression matching' { + run echo $'Foobar v0.1.0\nRelease date: 2015-11-29' + refute_line --index 0 --regexp '^Foobar v[0-9]+\.[0-9]+\.[0-9]$' +} +``` + +On failure, in addition to the details of literal matching, the regular expression is also displayed. +When used with `--index ` the regular expression replaces the unexpected line. + +``` +-- regular expression should not match line -- +index : 0 +regexp : ^Foobar v[0-9]+\.[0-9]+\.[0-9]$ +line : Foobar v0.1.0 +-- +``` + +An error is displayed if the specified extended regular expression is invalid. + +This option and partial matching (`--partial` or `-p`) are mutually exclusive. +An error is displayed when used simultaneously. + +### `assert_regex` + +This function is similar to `assert_equal` but uses pattern matching instead of +equality, by wrapping `[[ value =~ pattern ]]`. + +Fail if the value (first parameter) does not match the pattern (second +parameter). + +```bash +@test 'assert_regex()' { + assert_regex 'what' 'x$' +} +``` + +On failure, the value and the pattern are displayed. + +``` +-- values does not match regular expression -- +value : what +pattern : x$ +-- +``` + +If the value is longer than one line then it is displayed in *multi-line* +format. + +An error is displayed if the specified extended regular expression is invalid. + +For description of the matching behavior, refer to the documentation of the +`=~` operator in the [Bash manual][bash-conditional]. + +> _**Note**: +> the `BASH_REMATCH` array is available immediately after the assertion succeeds but is fragile; +> i.e. prone to being overwritten as a side effect of other actions._ + +### `refute_regex` + +This function is similar to `refute_equal` but uses pattern matching instead of +equality, by wrapping `! [[ value =~ pattern ]]`. + +Fail if the value (first parameter) matches the pattern (second parameter). + +```bash +@test 'refute_regex()' { + refute_regex 'WhatsApp' 'Threema' +} +``` + +On failure, the value, the pattern and the match are displayed. + +```bash +@test 'refute_regex()' { + refute_regex 'WhatsApp' 'What.' +} + +-- value matches regular expression -- +value : WhatsApp +pattern : What. +match : Whats +case : sensitive +-- +``` + +If the value or pattern is longer than one line then it is displayed in +*multi-line* format. + +An error is displayed if the specified extended regular expression is invalid. + +For description of the matching behavior, refer to the documentation of the +`=~` operator in the [Bash manual][bash-conditional]. + +> _**Note**: +> the `BASH_REMATCH` array is available immediately after the assertion fails but is fragile; +> i.e. prone to being overwritten as a side effect of other actions like calling `run`. +> Thus, it's good practice to avoid using `BASH_REMATCH` in conjunction with `refute_regex()`. +> The valuable information the array contains is the matching part of the value which is printed in the failing test log, as mentioned above._ + +### `assert_stderr` + +> _**Note**: +> `run` has to be called with `--separate-stderr` to separate stdout and stderr into `$output` and `$stderr`. +> If not, `$stderr` will be empty, causing `assert_stderr` to always fail. + +Similarly to `assert_output`, this function verifies that a command or function produces the expected stderr. +The stderr matching can be literal (the default), partial or by regular expression. +The expected stderr can be specified either by positional argument or read from STDIN by passing the `-`/`--stdin` flag. + +#### Literal matching + +By default, literal matching is performed. +The assertion fails if `$stderr` does not equal the expected stderr. + + ```bash + echo_err() { + echo "$@" >&2 + } + + @test 'assert_stderr()' { + run --separate-stderr echo_err 'have' + assert_stderr 'want' + } + + @test 'assert_stderr() with pipe' { + run --separate-stderr echo_err 'hello' + echo_err 'hello' | assert_stderr - + } + + @test 'assert_stderr() with herestring' { + run --separate-stderr echo_err 'hello' + assert_stderr - <<< hello + } + ``` + +On failure, the expected and actual stderr are displayed. + + ``` + -- stderr differs -- + expected : want + actual : have + -- + ``` + +#### Existence + +To assert that any stderr exists at all, omit the `expected` argument. + + ```bash + @test 'assert_stderr()' { + run --separate-stderr echo_err 'have' + assert_stderr + } + ``` + +On failure, an error message is displayed. + + ``` + -- no stderr -- + expected non-empty stderr, but stderr was empty + -- + ``` + +#### Partial matching + +Partial matching can be enabled with the `--partial` option (`-p` for short). +When used, the assertion fails if the expected _substring_ is not found in `$stderr`. + + ```bash + @test 'assert_stderr() partial matching' { + run --separate-stderr echo_err 'ERROR: no such file or directory' + assert_stderr --partial 'SUCCESS' + } + ``` + +On failure, the substring and the stderr are displayed. + + ``` + -- stderr does not contain substring -- + substring : SUCCESS + stderr : ERROR: no such file or directory + -- + ``` + +#### Regular expression matching + +Regular expression matching can be enabled with the `--regexp` option (`-e` for short). +When used, the assertion fails if the *extended regular expression* does not match `$stderr`. + +*Note: The anchors `^` and `$` bind to the beginning and the end (respectively) of the entire stderr; not individual lines.* + + ```bash + @test 'assert_stderr() regular expression matching' { + run --separate-stderr echo_err 'Foobar 0.1.0' + assert_stderr --regexp '^Foobar v[0-9]+\.[0-9]+\.[0-9]$' + } + ``` + +On failure, the regular expression and the stderr are displayed. + + ``` + -- regular expression does not match stderr -- + regexp : ^Foobar v[0-9]+\.[0-9]+\.[0-9]$ + stderr : Foobar 0.1.0 + -- + ``` + +### `refute_stderr` + +> _**Note**: +> `run` has to be called with `--separate-stderr` to separate stdout and stderr into `$output` and `$stderr`. +> If not, `$stderr` will be empty, causing `refute_stderr` to always pass. + +Similar to `refute_output`, this function verifies that a command or function does not produce the unexpected stderr. +(It is the logical complement of `assert_stderr`.) +The stderr matching can be literal (the default), partial or by regular expression. +The unexpected stderr can be specified either by positional argument or read from STDIN by passing the `-`/`--stdin` flag. + +### `assert_stderr_line` + +> _**Note**: +> `run` has to be called with `--separate-stderr` to separate stdout and stderr into `$output` and `$stderr`. +> If not, `$stderr` will be empty, causing `assert_stderr_line` to always fail. + +Similarly to `assert_stderr`, this function verifies that a command or function produces the expected stderr. +It checks that the expected line appears in the stderr (default) or at a specific line number. +Matching can be literal (default), partial or regular expression. +This function is the logical complement of `refute_stderr_line`. + +#### Looking for a line in the stderr + +By default, the entire stderr is searched for the expected line. +The assertion fails if the expected line is not found in `${stderr_lines[@]}`. + + ```bash + echo_err() { + echo "$@" >&2 + } + + @test 'assert_stderr_line() looking for line' { + run --separate-stderr echo_err $'have-0\nhave-1\nhave-2' + assert_stderr_line 'want' + } + ``` + +On failure, the expected line and the stderr are displayed. + + ``` + -- stderr does not contain line -- + line : want + stderr (3 lines): + have-0 + have-1 + have-2 + -- + ``` + +#### Matching a specific line + +When the `--index ` option is used (`-n ` for short), the expected line is matched only against the line identified by the given index. +The assertion fails if the expected line does not equal `${stderr_lines[]}`. + + ```bash + @test 'assert_stderr_line() specific line' { + run --separate-stderr echo_err $'have-0\nhave-1\nhave-2' + assert_stderr_line --index 1 'want-1' + } + ``` + +On failure, the index and the compared stderr_lines are displayed. + + ``` + -- line differs -- + index : 1 + expected : want-1 + actual : have-1 + -- + ``` + +#### Partial matching + +Partial matching can be enabled with the `--partial` option (`-p` for short). +When used, a match fails if the expected *substring* is not found in the matched line. + + ```bash + @test 'assert_stderr_line() partial matching' { + run --separate-stderr echo_err $'have 1\nhave 2\nhave 3' + assert_stderr_line --partial 'want' + } + ``` + +On failure, the same details are displayed as for literal matching, except that the substring replaces the expected line. + + ``` + -- no stderr line contains substring -- + substring : want + stderr (3 lines): + have 1 + have 2 + have 3 + -- + ``` + +#### Regular expression matching + +Regular expression matching can be enabled with the `--regexp` option (`-e` for short). +When used, a match fails if the *extended regular expression* does not match the line being tested. + +*Note: As expected, the anchors `^` and `$` bind to the beginning and the end (respectively) of the matched line.* + + ```bash + @test 'assert_stderr_line() regular expression matching' { + run --separate-stderr echo_err $'have-0\nhave-1\nhave-2' + assert_stderr_line --index 1 --regexp '^want-[0-9]$' + } + ``` + +On failure, the same details are displayed as for literal matching, except that the regular expression replaces the expected line. + + ``` + -- regular expression does not match line -- + index : 1 + regexp : ^want-[0-9]$ + line : have-1 + -- + ``` + +### `refute_stderr_line` + +> _**Note**: +> `run` has to be called with `--separate-stderr` to separate stdout and stderr into `$output` and `$stderr`. +> If not, `$stderr` will be empty, causing `refute_stderr_line` to always pass. + +Similarly to `refute_stderr`, this function helps to verify that a command or function produces the correct stderr. +It checks that the unexpected line does not appear in the stderr (default) or in a specific line of it. +Matching can be literal (default), partial or regular expression. +This function is the logical complement of `assert_stderr_line`. + + + +[bats]: https://github.com/bats-core/bats-core +[bash-comp-cmd]: https://www.gnu.org/software/bash/manual/bash.html#Compound-Commands +[bash-conditional]: https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructs + +[bats-docs]: https://bats-core.readthedocs.io/ +[bats-support-output]: https://github.com/bats-core/bats-support#output-formatting +[bats-support]: https://github.com/bats-core/bats-support diff --git a/tooling/bats-assert/load.bash b/tooling/bats-assert/load.bash new file mode 100644 index 00000000000000..c67d9e8b45b4e1 --- /dev/null +++ b/tooling/bats-assert/load.bash @@ -0,0 +1,33 @@ +# bats-assert - Common assertions for Bats +# +# Written in 2016 by Zoltan Tombol +# +# To the extent possible under law, the author(s) have dedicated all +# copyright and related and neighboring rights to this software to the +# public domain worldwide. This software is distributed without any +# warranty. +# +# You should have received a copy of the CC0 Public Domain Dedication +# along with this software. If not, see +# . +# +# Assertions are functions that perform a test and output relevant +# information on failure to help debugging. They return 1 on failure +# and 0 otherwise. +# +# All output is formatted for readability using the functions of +# `output.bash' and sent to the standard error. + +# shellcheck disable=1090 +source "$(dirname "${BASH_SOURCE[0]}")/src/assert.bash" +source "$(dirname "${BASH_SOURCE[0]}")/src/refute.bash" +source "$(dirname "${BASH_SOURCE[0]}")/src/assert_equal.bash" +source "$(dirname "${BASH_SOURCE[0]}")/src/assert_not_equal.bash" +source "$(dirname "${BASH_SOURCE[0]}")/src/assert_success.bash" +source "$(dirname "${BASH_SOURCE[0]}")/src/assert_failure.bash" +source "$(dirname "${BASH_SOURCE[0]}")/src/assert_output.bash" +source "$(dirname "${BASH_SOURCE[0]}")/src/refute_output.bash" +source "$(dirname "${BASH_SOURCE[0]}")/src/assert_line.bash" +source "$(dirname "${BASH_SOURCE[0]}")/src/refute_line.bash" +source "$(dirname "${BASH_SOURCE[0]}")/src/assert_regex.bash" +source "$(dirname "${BASH_SOURCE[0]}")/src/refute_regex.bash" diff --git a/tooling/bats-assert/package-lock.json b/tooling/bats-assert/package-lock.json new file mode 100644 index 00000000000000..4682d57c29ef50 --- /dev/null +++ b/tooling/bats-assert/package-lock.json @@ -0,0 +1,36 @@ +{ + "name": "bats-assert", + "version": "2.2.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bats-assert", + "version": "2.2.0", + "license": "CC0-1.0", + "devDependencies": { + "bats": "^1", + "bats-support": "^0.3" + }, + "peerDependencies": { + "bats": "0.4 || ^1", + "bats-support": "^0.3" + } + }, + "node_modules/bats": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/bats/-/bats-1.9.0.tgz", + "integrity": "sha512-Z5BJaAmmHv/ujj7obhjEzJ//OL+ZtjVq0iRnHu+2fE9OeUaPMbJpBgYiOdNbDrG3E2hqe84/AXNnS/UiXl/UcA==", + "dev": true, + "bin": { + "bats": "bin/bats" + } + }, + "node_modules/bats-support": { + "version": "0.3.0", + "resolved": "git+ssh://git@github.com/jasonkarns/bats-support.git#24a72e14349690bcbf7c151b9d2d1cdd32d36eb1", + "integrity": "sha512-42f2THEaN02dVj7Zhj0C4AM5FdePq3YPlXvnu/fKUQwCv1qM2dyACBKFXQkLw9QMzhDmwuFcke90XwHMUsBjGQ==", + "dev": true + } + } +} diff --git a/tooling/bats-assert/package.json b/tooling/bats-assert/package.json new file mode 100644 index 00000000000000..1ce5a65651c08f --- /dev/null +++ b/tooling/bats-assert/package.json @@ -0,0 +1,49 @@ +{ + "name": "bats-assert", + "version": "2.2.0", + "description": "Common assertions for Bats", + "homepage": "https://github.com/bats-core/bats-assert", + "license": "CC0-1.0", + "author": "Zoltán Tömböl (https://github.com/ztombol)", + "contributors": [ + "Sam Stephenson (http://sstephenson.us/)", + "Jason Karns (http://jasonkarns.com)", + "Mislav Marohnić (http://mislav.net/)", + "Tim Pope (https://github.com/tpope)" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/bats-core/bats-assert.git" + }, + "bugs": "https://github.com/bats-core/bats-assert/issues", + "directories": { + "lib": "src", + "test": "test" + }, + "files": [ + "load.bash", + "src" + ], + "scripts": { + "test": "bats ${CI+-t} test", + "postversion": "git push --follow-tags" + }, + "devDependencies": { + "bats": "^1", + "bats-support": "^0.3" + }, + "peerDependencies": { + "bats": "0.4 || ^1", + "bats-support": "^0.3" + }, + "keywords": [ + "bats", + "bash", + "shell", + "test", + "unit", + "assert", + "assertion", + "helper" + ] +} diff --git a/tooling/bats-assert/src/assert.bash b/tooling/bats-assert/src/assert.bash new file mode 100644 index 00000000000000..0260ce231e8890 --- /dev/null +++ b/tooling/bats-assert/src/assert.bash @@ -0,0 +1,42 @@ +# assert +# ====== +# +# Summary: Fail if the given expression evaluates to false. +# +# Usage: assert + +# Options: +# The expression to evaluate for truthiness. +# *__Note:__ The expression must be a simple command. +# [Compound commands](https://www.gnu.org/software/bash/manual/bash.html#Compound-Commands), +# such as `[[`, can be used only when executed with `bash -c`.* +# +# IO: +# STDERR - the failed expression, on failure +# Globals: +# none +# Returns: +# 0 - if expression evaluates to true +# 1 - otherwise +# +# ```bash +# @test 'assert()' { +# touch '/var/log/test.log' +# assert [ -e '/var/log/test.log' ] +# } +# ``` +# +# On failure, the failed expression is displayed. +# +# ``` +# -- assertion failed -- +# expression : [ -e /var/log/test.log ] +# -- +# ``` +assert() { + if ! "$@"; then + batslib_print_kv_single 10 'expression' "$*" \ + | batslib_decorate 'assertion failed' \ + | fail + fi +} diff --git a/tooling/bats-assert/src/assert_equal.bash b/tooling/bats-assert/src/assert_equal.bash new file mode 100644 index 00000000000000..4ef1297ed1cfc3 --- /dev/null +++ b/tooling/bats-assert/src/assert_equal.bash @@ -0,0 +1,42 @@ +# assert_equal +# ============ +# +# Summary: Fail if the actual and expected values are not equal. +# +# Usage: assert_equal +# +# Options: +# The value being compared. +# The value to compare against. +# +# ```bash +# @test 'assert_equal()' { +# assert_equal 'have' 'want' +# } +# ``` +# +# IO: +# STDERR - expected and actual values, on failure +# Globals: +# none +# Returns: +# 0 - if values equal +# 1 - otherwise +# +# On failure, the expected and actual values are displayed. +# +# ``` +# -- values do not equal -- +# expected : want +# actual : have +# -- +# ``` +assert_equal() { + if [[ $1 != "$2" ]]; then + batslib_print_kv_single_or_multi 8 \ + 'expected' "$2" \ + 'actual' "$1" \ + | batslib_decorate 'values do not equal' \ + | fail + fi +} diff --git a/tooling/bats-assert/src/assert_failure.bash b/tooling/bats-assert/src/assert_failure.bash new file mode 100644 index 00000000000000..268d44758ac6ff --- /dev/null +++ b/tooling/bats-assert/src/assert_failure.bash @@ -0,0 +1,86 @@ +# assert_failure +# ============== +# +# Summary: Fail if `$status` is 0; or is not equal to the optionally provided status. +# +# Usage: assert_failure [] +# +# Options: +# The specific status code to check against. +# If not provided, simply asserts status is != 0. +# +# IO: +# STDERR - `$output`, on failure; +# - also, `$status` and `expected_status`, if provided +# Globals: +# status +# output +# Returns: +# 0 - if `$status' is 0, +# or if expected_status is provided but does not equal `$status' +# 1 - otherwise +# +# ```bash +# @test 'assert_failure() status only' { +# run echo 'Success!' +# assert_failure +# } +# ``` +# +# On failure, `$output` is displayed. +# +# ``` +# -- command succeeded, but it was expected to fail -- +# output : Success! +# -- +# ``` +# +# ## Expected status +# +# When `expected_status` is provided, fail if `$status` does not equal the `expected_status`. +# +# ```bash +# @test 'assert_failure() with expected status' { +# run bash -c "echo 'Error!'; exit 1" +# assert_failure 2 +# } +# ``` +# +# On failure, both the expected and actual statuses, and `$output` are displayed. +# +# ``` +# -- command failed as expected, but status differs -- +# expected : 2 +# actual : 1 +# output : Error! +# -- +# ``` +assert_failure() { + : "${output?}" + : "${status?}" + + (( $# > 0 )) && local -r expected="$1" + if (( status == 0 )); then + { local -ir width=6 + batslib_print_kv_single_or_multi "$width" 'output' "$output" + if [[ -n "${stderr-}" ]]; then + batslib_print_kv_single_or_multi "$width" 'stderr' "$stderr" + fi + } \ + | batslib_decorate 'command succeeded, but it was expected to fail' \ + | fail + elif (( $# > 0 )) && (( status != expected )); then + { local -ir width=8 + batslib_print_kv_single "$width" \ + 'expected' "$expected" \ + 'actual' "$status" + batslib_print_kv_single_or_multi "$width" \ + 'output' "$output" + if [[ -n "${stderr-}" ]]; then + batslib_print_kv_single_or_multi "$width" 'stderr' "$stderr" + fi + } \ + | batslib_decorate 'command failed as expected, but status differs' \ + | fail + fi +} diff --git a/tooling/bats-assert/src/assert_line.bash b/tooling/bats-assert/src/assert_line.bash new file mode 100644 index 00000000000000..bf9140d5d76420 --- /dev/null +++ b/tooling/bats-assert/src/assert_line.bash @@ -0,0 +1,301 @@ +# assert_line +# =========== +# +# Summary: Fail if the expected line is not found in the output (default) or at a specific line number. +# +# Usage: assert_line [-n index] [-p | -e] [--] +# +# Options: +# -n, --index Match the th line +# -p, --partial Match if `expected` is a substring of `$output` or line +# -e, --regexp Treat `expected` as an extended regular expression +# The expected line string, substring, or regular expression +# +# IO: +# STDERR - details, on failure +# error message, on error +# Globals: +# output +# lines +# Returns: +# 0 - if matching line found +# 1 - otherwise +# +# Similarly to `assert_output`, this function verifies that a command or function produces the expected output. +# (It is the logical complement of `refute_line`.) +# It checks that the expected line appears in the output (default) or at a specific line number. +# Matching can be literal (default), partial or regular expression. +# +# *__Warning:__ +# Due to a [bug in Bats][bats-93], empty lines are discarded from `${lines[@]}`, +# causing line indices to change and preventing testing for empty lines.* +# +# [bats-93]: https://github.com/sstephenson/bats/pull/93 +# +# ## Looking for a line in the output +# +# By default, the entire output is searched for the expected line. +# The assertion fails if the expected line is not found in `${lines[@]}`. +# +# ```bash +# @test 'assert_line() looking for line' { +# run echo $'have-0\nhave-1\nhave-2' +# assert_line 'want' +# } +# ``` +# +# On failure, the expected line and the output are displayed. +# +# ``` +# -- output does not contain line -- +# line : want +# output (3 lines): +# have-0 +# have-1 +# have-2 +# -- +# ``` +# +# ## Matching a specific line +# +# When the `--index ` option is used (`-n ` for short), the expected line is matched only against the line identified by the given index. +# The assertion fails if the expected line does not equal `${lines[]}`. +# +# ```bash +# @test 'assert_line() specific line' { +# run echo $'have-0\nhave-1\nhave-2' +# assert_line --index 1 'want-1' +# } +# ``` +# +# On failure, the index and the compared lines are displayed. +# +# ``` +# -- line differs -- +# index : 1 +# expected : want-1 +# actual : have-1 +# -- +# ``` +# +# ## Partial matching +# +# Partial matching can be enabled with the `--partial` option (`-p` for short). +# When used, a match fails if the expected *substring* is not found in the matched line. +# +# ```bash +# @test 'assert_line() partial matching' { +# run echo $'have 1\nhave 2\nhave 3' +# assert_line --partial 'want' +# } +# ``` +# +# On failure, the same details are displayed as for literal matching, except that the substring replaces the expected line. +# +# ``` +# -- no output line contains substring -- +# substring : want +# output (3 lines): +# have 1 +# have 2 +# have 3 +# -- +# ``` +# +# ## Regular expression matching +# +# Regular expression matching can be enabled with the `--regexp` option (`-e` for short). +# When used, a match fails if the *extended regular expression* does not match the line being tested. +# +# *__Note__: +# As expected, the anchors `^` and `$` bind to the beginning and the end (respectively) of the matched line.* +# +# ```bash +# @test 'assert_line() regular expression matching' { +# run echo $'have-0\nhave-1\nhave-2' +# assert_line --index 1 --regexp '^want-[0-9]$' +# } +# ``` +# +# On failure, the same details are displayed as for literal matching, except that the regular expression replaces the expected line. +# +# ``` +# -- regular expression does not match line -- +# index : 1 +# regexp : ^want-[0-9]$ +# line : have-1 +# -- +# ``` +# FIXME(ztombol): Display `${lines[@]}' instead of `$output'! +assert_line() { + __assert_line "$@" +} + +# assert_stderr_line +# =========== +# +# Summary: Fail if the expected line is not found in the stderr (default) or at a specific line number. +# +# Usage: assert_stderr_line [-n index] [-p | -e] [--] +# +# Options: +# -n, --index Match the th line +# -p, --partial Match if `expected` is a substring of `$stderr` or line +# -e, --regexp Treat `expected` as an extended regular expression +# The expected line string, substring, or regular expression +# +# IO: +# STDERR - details, on failure +# error message, on error +# Globals: +# stderr +# stderr_lines +# Returns: +# 0 - if matching line found +# 1 - otherwise +# +# Similarly to `assert_stderr`, this function verifies that a command or function produces the expected stderr. +# (It is the logical complement of `refute_stderr_line`.) +# It checks that the expected line appears in the stderr (default) or at a specific line number. +# Matching can be literal (default), partial or regular expression. +# +assert_stderr_line() { + __assert_line "$@" +} + +__assert_line() { + local -r caller=${FUNCNAME[1]} + local -i is_match_line=0 + local -i is_mode_partial=0 + local -i is_mode_regexp=0 + + if [[ "${caller}" == "assert_line" ]]; then + : "${lines?}" + local -ar stream_lines=("${lines[@]}") + local -r stream_type=output + elif [[ "${caller}" == "assert_stderr_line" ]]; then + : "${stderr_lines?}" + local -ar stream_lines=("${stderr_lines[@]}") + local -r stream_type=stderr + else + # Unknown caller + echo "Unexpected call to \`${FUNCNAME[0]}\` +Did you mean to call \`assert_line\` or \`assert_stderr_line\`?" \ + | batslib_decorate "ERROR: ${FUNCNAME[0]}" \ + | fail + return $? + fi + + # Handle options. + while (( $# > 0 )); do + case "$1" in + -n|--index) + if (( $# < 2 )) || ! [[ $2 =~ ^-?([0-9]|[1-9][0-9]+)$ ]]; then + echo "\`--index' requires an integer argument: \`$2'" \ + | batslib_decorate "ERROR: ${caller}" \ + | fail + return $? + fi + is_match_line=1 + local -ri idx="$2" + shift 2 + ;; + -p|--partial) is_mode_partial=1; shift ;; + -e|--regexp) is_mode_regexp=1; shift ;; + --) shift; break ;; + *) break ;; + esac + done + + if (( is_mode_partial )) && (( is_mode_regexp )); then + echo "\`--partial' and \`--regexp' are mutually exclusive" \ + | batslib_decorate "ERROR: ${caller}" \ + | fail + return $? + fi + + # Arguments. + local -r expected="$1" + + if (( is_mode_regexp == 1 )) && [[ '' =~ $expected ]] || (( $? == 2 )); then + echo "Invalid extended regular expression: \`$expected'" \ + | batslib_decorate "ERROR: ${caller}" \ + | fail + return $? + fi + + # Matching. + if (( is_match_line )); then + # Specific line. + if (( is_mode_regexp )); then + if ! [[ ${stream_lines[$idx]} =~ $expected ]]; then + batslib_print_kv_single 6 \ + 'index' "$idx" \ + 'regexp' "$expected" \ + 'line' "${stream_lines[$idx]}" \ + | batslib_decorate 'regular expression does not match line' \ + | fail + fi + elif (( is_mode_partial )); then + if [[ ${stream_lines[$idx]} != *"$expected"* ]]; then + batslib_print_kv_single 9 \ + 'index' "$idx" \ + 'substring' "$expected" \ + 'line' "${stream_lines[$idx]}" \ + | batslib_decorate 'line does not contain substring' \ + | fail + fi + else + if [[ ${stream_lines[$idx]} != "$expected" ]]; then + batslib_print_kv_single 8 \ + 'index' "$idx" \ + 'expected' "$expected" \ + 'actual' "${stream_lines[$idx]}" \ + | batslib_decorate 'line differs' \ + | fail + fi + fi + else + # Contained in output/error stream. + if (( is_mode_regexp )); then + local -i idx + for (( idx = 0; idx < ${#stream_lines[@]}; ++idx )); do + [[ ${stream_lines[$idx]} =~ $expected ]] && return 0 + done + { local -ar single=( 'regexp' "$expected" ) + local -ar may_be_multi=( "${stream_type}" "${!stream_type}" ) + local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )" + batslib_print_kv_single "$width" "${single[@]}" + batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}" + } \ + | batslib_decorate "no ${stream_type} line matches regular expression" \ + | fail + elif (( is_mode_partial )); then + local -i idx + for (( idx = 0; idx < ${#stream_lines[@]}; ++idx )); do + [[ ${stream_lines[$idx]} == *"$expected"* ]] && return 0 + done + { local -ar single=( 'substring' "$expected" ) + local -ar may_be_multi=( "${stream_type}" "${!stream_type}" ) + local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )" + batslib_print_kv_single "$width" "${single[@]}" + batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}" + } \ + | batslib_decorate "no ${stream_type} line contains substring" \ + | fail + else + local -i idx + for (( idx = 0; idx < ${#stream_lines[@]}; ++idx )); do + [[ ${stream_lines[$idx]} == "$expected" ]] && return 0 + done + { local -ar single=( 'line' "$expected" ) + local -ar may_be_multi=( "${stream_type}" "${!stream_type}" ) + local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )" + batslib_print_kv_single "$width" "${single[@]}" + batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}" + } \ + | batslib_decorate "${stream_type} does not contain line" \ + | fail + fi + fi +} diff --git a/tooling/bats-assert/src/assert_not_equal.bash b/tooling/bats-assert/src/assert_not_equal.bash new file mode 100644 index 00000000000000..933bb713dccff6 --- /dev/null +++ b/tooling/bats-assert/src/assert_not_equal.bash @@ -0,0 +1,42 @@ +# assert_not_equal +# ============ +# +# Summary: Fail if the actual and unexpected values are equal. +# +# Usage: assert_not_equal +# +# Options: +# The value being compared. +# The value to compare against. +# +# ```bash +# @test 'assert_not_equal()' { +# assert_not_equal 'foo' 'foo' +# } +# ``` +# +# IO: +# STDERR - expected and actual values, on failure +# Globals: +# none +# Returns: +# 0 - if actual does not equal unexpected +# 1 - otherwise +# +# On failure, the unexpected and actual values are displayed. +# +# ``` +# -- values should not be equal -- +# unexpected : foo +# actual : foo +# -- +# ``` +assert_not_equal() { + if [[ "$1" == "$2" ]]; then + batslib_print_kv_single_or_multi 10 \ + 'unexpected' "$2" \ + 'actual' "$1" \ + | batslib_decorate 'values should not be equal' \ + | fail + fi +} diff --git a/tooling/bats-assert/src/assert_output.bash b/tooling/bats-assert/src/assert_output.bash new file mode 100644 index 00000000000000..168d24641a880e --- /dev/null +++ b/tooling/bats-assert/src/assert_output.bash @@ -0,0 +1,249 @@ +# assert_output +# ============= +# +# Summary: Fail if `$output' does not match the expected output. +# +# Usage: assert_output [-p | -e] [- | [--] ] +# +# Options: +# -p, --partial Match if `expected` is a substring of `$output` +# -e, --regexp Treat `expected` as an extended regular expression +# -, --stdin Read `expected` value from STDIN +# The expected value, substring or regular expression +# +# IO: +# STDIN - [=$1] expected output +# STDERR - details, on failure +# error message, on error +# Globals: +# output +# Returns: +# 0 - if output matches the expected value/partial/regexp +# 1 - otherwise +# +# This function verifies that a command or function produces the expected output. +# (It is the logical complement of `refute_output`.) +# Output matching can be literal (the default), partial or by regular expression. +# The expected output can be specified either by positional argument or read from STDIN by passing the `-`/`--stdin` flag. +# +# ## Literal matching +# +# By default, literal matching is performed. +# The assertion fails if `$output` does not equal the expected output. +# +# ```bash +# @test 'assert_output()' { +# run echo 'have' +# assert_output 'want' +# } +# +# @test 'assert_output() with pipe' { +# run echo 'hello' +# echo 'hello' | assert_output - +# } +# +# @test 'assert_output() with herestring' { +# run echo 'hello' +# assert_output - <<< hello +# } +# ``` +# +# On failure, the expected and actual output are displayed. +# +# ``` +# -- output differs -- +# expected : want +# actual : have +# -- +# ``` +# +# ## Existence +# +# To assert that any output exists at all, omit the `expected` argument. +# +# ```bash +# @test 'assert_output()' { +# run echo 'have' +# assert_output +# } +# ``` +# +# On failure, an error message is displayed. +# +# ``` +# -- no output -- +# expected non-empty output, but output was empty +# -- +# ``` +# +# ## Partial matching +# +# Partial matching can be enabled with the `--partial` option (`-p` for short). +# When used, the assertion fails if the expected _substring_ is not found in `$output`. +# +# ```bash +# @test 'assert_output() partial matching' { +# run echo 'ERROR: no such file or directory' +# assert_output --partial 'SUCCESS' +# } +# ``` +# +# On failure, the substring and the output are displayed. +# +# ``` +# -- output does not contain substring -- +# substring : SUCCESS +# output : ERROR: no such file or directory +# -- +# ``` +# +# ## Regular expression matching +# +# Regular expression matching can be enabled with the `--regexp` option (`-e` for short). +# When used, the assertion fails if the *extended regular expression* does not match `$output`. +# +# *__Note__: +# The anchors `^` and `$` bind to the beginning and the end (respectively) of the entire output; +# not individual lines.* +# +# ```bash +# @test 'assert_output() regular expression matching' { +# run echo 'Foobar 0.1.0' +# assert_output --regexp '^Foobar v[0-9]+\.[0-9]+\.[0-9]$' +# } +# ``` +# +# On failure, the regular expression and the output are displayed. +# +# ``` +# -- regular expression does not match output -- +# regexp : ^Foobar v[0-9]+\.[0-9]+\.[0-9]$ +# output : Foobar 0.1.0 +# -- +# ``` +assert_output() { + __assert_stream "$@" +} + +# assert_stderr +# ============= +# +# Summary: Fail if `$stderr' does not match the expected stderr. +# +# Usage: assert_stderr [-p | -e] [- | [--] ] +# +# Options: +# -p, --partial Match if `expected` is a substring of `$stderr` +# -e, --regexp Treat `expected` as an extended regular expression +# -, --stdin Read `expected` value from STDIN +# The expected value, substring or regular expression +# +# IO: +# STDIN - [=$1] expected stderr +# STDERR - details, on failure +# error message, on error +# Globals: +# stderr +# Returns: +# 0 - if stderr matches the expected value/partial/regexp +# 1 - otherwise +# +# Similarly to `assert_output`, this function verifies that a command or function produces the expected stderr. +# (It is the logical complement of `refute_stderr`.) +# The stderr matching can be literal (the default), partial or by regular expression. +# The expected stderr can be specified either by positional argument or read from STDIN by passing the `-`/`--stdin` flag. +# +assert_stderr() { + __assert_stream "$@" +} + +__assert_stream() { + local -r caller=${FUNCNAME[1]} + local -r stream_type=${caller/assert_/} + local -i is_mode_partial=0 + local -i is_mode_regexp=0 + local -i is_mode_nonempty=0 + local -i use_stdin=0 + + if [[ ${stream_type} == "output" ]]; then + : "${output?}" + elif [[ ${stream_type} == "stderr" ]]; then + : "${stderr?}" + else + # Unknown caller + echo "Unexpected call to \`${FUNCNAME[0]}\` +Did you mean to call \`assert_output\` or \`assert_stderr\`?" | + batslib_decorate "ERROR: ${FUNCNAME[0]}" | + fail + return $? + fi + local -r stream="${!stream_type}" + + # Handle options. + if (( $# == 0 )); then + is_mode_nonempty=1 + fi + + while (( $# > 0 )); do + case "$1" in + -p|--partial) is_mode_partial=1; shift ;; + -e|--regexp) is_mode_regexp=1; shift ;; + -|--stdin) use_stdin=1; shift ;; + --) shift; break ;; + *) break ;; + esac + done + + if (( is_mode_partial )) && (( is_mode_regexp )); then + echo "\`--partial' and \`--regexp' are mutually exclusive" \ + | batslib_decorate "ERROR: ${caller}" \ + | fail + return $? + fi + + # Arguments. + local expected + if (( use_stdin )); then + expected="$(cat -)" + else + expected="${1-}" + fi + + # Matching. + if (( is_mode_nonempty )); then + if [ -z "$stream" ]; then + echo "expected non-empty $stream_type, but $stream_type was empty" \ + | batslib_decorate "no $stream_type" \ + | fail + fi + elif (( is_mode_regexp )); then + # shellcheck disable=2319 + if [[ '' =~ $expected ]] || (( $? == 2 )); then + echo "Invalid extended regular expression: \`$expected'" \ + | batslib_decorate "ERROR: ${caller}" \ + | fail + elif ! [[ $stream =~ $expected ]]; then + batslib_print_kv_single_or_multi 6 \ + 'regexp' "$expected" \ + "$stream_type" "$stream" \ + | batslib_decorate "regular expression does not match $stream_type" \ + | fail + fi + elif (( is_mode_partial )); then + if [[ $stream != *"$expected"* ]]; then + batslib_print_kv_single_or_multi 9 \ + 'substring' "$expected" \ + "$stream_type" "$stream" \ + | batslib_decorate "$stream_type does not contain substring" \ + | fail + fi + else + if [[ $stream != "$expected" ]]; then + batslib_print_kv_single_or_multi 8 \ + 'expected' "$expected" \ + 'actual' "$stream" \ + | batslib_decorate "$stream_type differs" \ + | fail + fi + fi +} diff --git a/tooling/bats-assert/src/assert_regex.bash b/tooling/bats-assert/src/assert_regex.bash new file mode 100644 index 00000000000000..17a705726194ae --- /dev/null +++ b/tooling/bats-assert/src/assert_regex.bash @@ -0,0 +1,56 @@ +# `assert_regex` +# +# This function is similar to `assert_equal` but uses pattern matching instead +# of equality, by wrapping `[[ value =~ pattern ]]`. +# +# Fail if the value (first parameter) does not match the pattern (second +# parameter). +# +# ```bash +# @test 'assert_regex()' { +# assert_regex 'what' 'x$' +# } +# ``` +# +# On failure, the value and the pattern are displayed. +# +# ``` +# -- values does not match regular expression -- +# value : what +# pattern : x$ +# -- +# ``` +# +# If the value is longer than one line then it is displayed in *multi-line* +# format. +# +# An error is displayed if the specified extended regular expression is invalid. +# +# For description of the matching behavior, refer to the documentation of the +# `=~` operator in the +# [Bash manual]: https://www.gnu.org/software/bash/manual/html_node/Conditional-Constructs.html. +# Note that the `BASH_REMATCH` array is available immediately after the +# assertion succeeds but is fragile, i.e. prone to being overwritten as a side +# effect of other actions. +assert_regex() { + local -r value="${1}" + local -r pattern="${2}" + + if [[ '' =~ ${pattern} ]]; (( ${?} == 2 )); then + echo "Invalid extended regular expression: \`${pattern}'" \ + | batslib_decorate 'ERROR: assert_regex' \ + | fail + elif ! [[ "${value}" =~ ${pattern} ]]; then + if shopt -p nocasematch &>/dev/null; then + local case_sensitive=insensitive + else + local case_sensitive=sensitive + fi + batslib_print_kv_single_or_multi 8 \ + 'value' "${value}" \ + 'pattern' "${pattern}" \ + 'case' "${case_sensitive}" \ + | batslib_decorate 'value does not match regular expression' \ + | fail + fi +} diff --git a/tooling/bats-assert/src/assert_success.bash b/tooling/bats-assert/src/assert_success.bash new file mode 100644 index 00000000000000..e3f074d23942da --- /dev/null +++ b/tooling/bats-assert/src/assert_success.bash @@ -0,0 +1,47 @@ +# assert_success +# ============== +# +# Summary: Fail if `$status` is not 0. +# +# Usage: assert_success +# +# IO: +# STDERR - `$status` and `$output`, on failure +# Globals: +# status +# output +# Returns: +# 0 - if `$status' is 0 +# 1 - otherwise +# +# ```bash +# @test 'assert_success() status only' { +# run bash -c "echo 'Error!'; exit 1" +# assert_success +# } +# ``` +# +# On failure, `$status` and `$output` are displayed. +# +# ``` +# -- command failed -- +# status : 1 +# output : Error! +# -- +# ``` +assert_success() { + : "${output?}" + : "${status?}" + + if (( status != 0 )); then + { local -ir width=6 + batslib_print_kv_single "$width" 'status' "$status" + batslib_print_kv_single_or_multi "$width" 'output' "$output" + if [[ -n "${stderr-}" ]]; then + batslib_print_kv_single_or_multi "$width" 'stderr' "$stderr" + fi + } \ + | batslib_decorate 'command failed' \ + | fail + fi +} diff --git a/tooling/bats-assert/src/refute.bash b/tooling/bats-assert/src/refute.bash new file mode 100644 index 00000000000000..e7c47da82e9f09 --- /dev/null +++ b/tooling/bats-assert/src/refute.bash @@ -0,0 +1,42 @@ +# refute +# ====== +# +# Summary: Fail if the given expression evaluates to true. +# +# Usage: refute +# +# Options: +# The expression to evaluate for falsiness. +# *__Note:__ The expression must be a simple command. +# [Compound commands](https://www.gnu.org/software/bash/manual/bash.html#Compound-Commands), +# such as `[[`, can be used only when executed with `bash -c`.* +# +# IO: +# STDERR - the successful expression, on failure +# Globals: +# none +# Returns: +# 0 - if expression evaluates to false +# 1 - otherwise +# +# ```bash +# @test 'refute()' { +# rm -f '/var/log/test.log' +# refute [ -e '/var/log/test.log' ] +# } +# ``` +# +# On failure, the successful expression is displayed. +# +# ``` +# -- assertion succeeded, but it was expected to fail -- +# expression : [ -e /var/log/test.log ] +# -- +# ``` +refute() { + if "$@"; then + batslib_print_kv_single 10 'expression' "$*" \ + | batslib_decorate 'assertion succeeded, but it was expected to fail' \ + | fail + fi +} diff --git a/tooling/bats-assert/src/refute_line.bash b/tooling/bats-assert/src/refute_line.bash new file mode 100644 index 00000000000000..bb7337d0fd2944 --- /dev/null +++ b/tooling/bats-assert/src/refute_line.bash @@ -0,0 +1,318 @@ +# refute_line +# =========== +# +# Summary: Fail if the unexpected line is found in the output (default) or at a specific line number. +# +# Usage: refute_line [-n index] [-p | -e] [--] +# +# Options: +# -n, --index Match the th line +# -p, --partial Match if `unexpected` is a substring of `$output` or line +# -e, --regexp Treat `unexpected` as an extended regular expression +# The unexpected line string, substring, or regular expression. +# +# IO: +# STDERR - details, on failure +# error message, on error +# Globals: +# output +# lines +# Returns: +# 0 - if match not found +# 1 - otherwise +# +# Similarly to `refute_output`, this function verifies that a command or function does not produce the unexpected output. +# (It is the logical complement of `assert_line`.) +# It checks that the unexpected line does not appear in the output (default) or at a specific line number. +# Matching can be literal (default), partial or regular expression. +# +# ## Looking for a line in the output +# +# By default, the entire output is searched for the unexpected line. +# The assertion fails if the unexpected line is found in `${lines[@]}`. +# +# ```bash +# @test 'refute_line() looking for line' { +# run echo $'have-0\nwant\nhave-2' +# refute_line 'want' +# } +# ``` +# +# On failure, the unexpected line, the index of its first match and the output with the matching line highlighted are displayed. +# +# ``` +# -- line should not be in output -- +# line : want +# index : 1 +# output (3 lines): +# have-0 +# > want +# have-2 +# -- +# ``` +# +# ## Matching a specific line +# +# When the `--index ` option is used (`-n ` for short), the unexpected line is matched only against the line identified by the given index. +# The assertion fails if the unexpected line equals `${lines[]}`. +# +# ```bash +# @test 'refute_line() specific line' { +# run echo $'have-0\nwant-1\nhave-2' +# refute_line --index 1 'want-1' +# } +# ``` +# +# On failure, the index and the unexpected line are displayed. +# +# ``` +# -- line should differ -- +# index : 1 +# line : want-1 +# -- +# ``` +# +# ## Partial matching +# +# Partial matching can be enabled with the `--partial` option (`-p` for short). +# When used, a match fails if the unexpected *substring* is found in the matched line. +# +# ```bash +# @test 'refute_line() partial matching' { +# run echo $'have 1\nwant 2\nhave 3' +# refute_line --partial 'want' +# } +# ``` +# +# On failure, in addition to the details of literal matching, the substring is also displayed. +# When used with `--index ` the substring replaces the unexpected line. +# +# ``` +# -- no line should contain substring -- +# substring : want +# index : 1 +# output (3 lines): +# have 1 +# > want 2 +# have 3 +# -- +# ``` +# +# ## Regular expression matching +# +# Regular expression matching can be enabled with the `--regexp` option (`-e` for short). +# When used, a match fails if the *extended regular expression* matches the line being tested. +# +# *__Note__: +# As expected, the anchors `^` and `$` bind to the beginning and the end (respectively) of the matched line.* +# +# ```bash +# @test 'refute_line() regular expression matching' { +# run echo $'Foobar v0.1.0\nRelease date: 2015-11-29' +# refute_line --index 0 --regexp '^Foobar v[0-9]+\.[0-9]+\.[0-9]$' +# } +# ``` +# +# On failure, in addition to the details of literal matching, the regular expression is also displayed. +# When used with `--index ` the regular expression replaces the unexpected line. +# +# ``` +# -- regular expression should not match line -- +# index : 0 +# regexp : ^Foobar v[0-9]+\.[0-9]+\.[0-9]$ +# line : Foobar v0.1.0 +# -- +# ``` +# FIXME(ztombol): Display `${lines[@]}' instead of `$output'! +refute_line() { + __refute_stream_line "$@" +} + +# refute_stderr_line +# ================== +# +# Summary: Fail if the unexpected line is found in the stderr (default) or at a specific line number. +# +# Usage: refute_stderr_line [-n index] [-p | -e] [--] +# +# Options: +# -n, --index Match the th line +# -p, --partial Match if `unexpected` is a substring of `$stderr` or line +# -e, --regexp Treat `unexpected` as an extended regular expression +# The unexpected line string, substring, or regular expression. +# +# IO: +# STDERR - details, on failure +# error message, on error +# Globals: +# stderr +# stderr_lines +# Returns: +# 0 - if match not found +# 1 - otherwise +# +# Similarly to `refute_stderr`, this function verifies that a command or function does not produce the unexpected stderr. +# (It is the logical complement of `assert_stderr_line`.) +# It checks that the unexpected line does not appear in the stderr (default) or at a specific line number. +# Matching can be literal (default), partial or regular expression. +# +refute_stderr_line() { + __refute_stream_line "$@" +} + +__refute_stream_line() { + local -r caller=${FUNCNAME[1]} + local -i is_match_line=0 + local -i is_mode_partial=0 + local -i is_mode_regexp=0 + + if [[ "${caller}" == "refute_line" ]]; then + : "${lines?}" + local -ar stream_lines=("${lines[@]}") + local -r stream_type=output + elif [[ "${caller}" == "refute_stderr_line" ]]; then + : "${stderr_lines?}" + local -ar stream_lines=("${stderr_lines[@]}") + local -r stream_type=stderr + else + # Unknown caller + echo "Unexpected call to \`${FUNCNAME[0]}\` +Did you mean to call \`refute_line\` or \`refute_stderr_line\`?" | + batslib_decorate "ERROR: ${FUNCNAME[0]}" | + fail + return $? + fi + + # Handle options. + while (( $# > 0 )); do + case "$1" in + -n|--index) + if (( $# < 2 )) || ! [[ $2 =~ ^-?([0-9]|[1-9][0-9]+)$ ]]; then + echo "\`--index' requires an integer argument: \`$2'" \ + | batslib_decorate "ERROR: ${caller}" \ + | fail + return $? + fi + is_match_line=1 + local -ri idx="$2" + shift 2 + ;; + -p|--partial) is_mode_partial=1; shift ;; + -e|--regexp) is_mode_regexp=1; shift ;; + --) shift; break ;; + *) break ;; + esac + done + + if (( is_mode_partial )) && (( is_mode_regexp )); then + echo "\`--partial' and \`--regexp' are mutually exclusive" \ + | batslib_decorate "ERROR: ${caller}" \ + | fail + return $? + fi + + # Arguments. + local -r unexpected="$1" + + if (( is_mode_regexp == 1 )) && [[ '' =~ $unexpected ]] || (( $? == 2 )); then + echo "Invalid extended regular expression: \`$unexpected'" \ + | batslib_decorate "ERROR: ${caller}" \ + | fail + return $? + fi + + # Matching. + if (( is_match_line )); then + # Specific line. + if (( is_mode_regexp )); then + if [[ ${stream_lines[$idx]} =~ $unexpected ]]; then + batslib_print_kv_single 6 \ + 'index' "$idx" \ + 'regexp' "$unexpected" \ + 'line' "${stream_lines[$idx]}" \ + | batslib_decorate 'regular expression should not match line' \ + | fail + fi + elif (( is_mode_partial )); then + if [[ ${stream_lines[$idx]} == *"$unexpected"* ]]; then + batslib_print_kv_single 9 \ + 'index' "$idx" \ + 'substring' "$unexpected" \ + 'line' "${stream_lines[$idx]}" \ + | batslib_decorate 'line should not contain substring' \ + | fail + fi + else + if [[ ${stream_lines[$idx]} == "$unexpected" ]]; then + batslib_print_kv_single 5 \ + 'index' "$idx" \ + 'line' "${stream_lines[$idx]}" \ + | batslib_decorate 'line should differ' \ + | fail + fi + fi + else + # Line contained in output/error stream. + if (( is_mode_regexp )); then + local -i idx + for (( idx = 0; idx < ${#stream_lines[@]}; ++idx )); do + if [[ ${stream_lines[$idx]} =~ $unexpected ]]; then + { local -ar single=( 'regexp' "$unexpected" 'index' "$idx" ) + local -a may_be_multi=( "${stream_type}" "${!stream_type}" ) + local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )" + batslib_print_kv_single "$width" "${single[@]}" + if batslib_is_single_line "${may_be_multi[1]}"; then + batslib_print_kv_single "$width" "${may_be_multi[@]}" + else + may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )" + batslib_print_kv_multi "${may_be_multi[@]}" + fi + } \ + | batslib_decorate 'no line should match the regular expression' \ + | fail + return $? + fi + done + elif (( is_mode_partial )); then + local -i idx + for (( idx = 0; idx < ${#stream_lines[@]}; ++idx )); do + if [[ ${stream_lines[$idx]} == *"$unexpected"* ]]; then + { local -ar single=( 'substring' "$unexpected" 'index' "$idx" ) + local -a may_be_multi=( "${stream_type}" "${!stream_type}" ) + local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )" + batslib_print_kv_single "$width" "${single[@]}" + if batslib_is_single_line "${may_be_multi[1]}"; then + batslib_print_kv_single "$width" "${may_be_multi[@]}" + else + may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )" + batslib_print_kv_multi "${may_be_multi[@]}" + fi + } \ + | batslib_decorate 'no line should contain substring' \ + | fail + return $? + fi + done + else + local -i idx + for (( idx = 0; idx < ${#stream_lines[@]}; ++idx )); do + if [[ ${stream_lines[$idx]} == "$unexpected" ]]; then + { local -ar single=( 'line' "$unexpected" 'index' "$idx" ) + local -a may_be_multi=( "${stream_type}" "${!stream_type}" ) + local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )" + batslib_print_kv_single "$width" "${single[@]}" + if batslib_is_single_line "${may_be_multi[1]}"; then + batslib_print_kv_single "$width" "${may_be_multi[@]}" + else + may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )" + batslib_print_kv_multi "${may_be_multi[@]}" + fi + } \ + | batslib_decorate "line should not be in ${stream_type}" \ + | fail + return $? + fi + done + fi + fi +} diff --git a/tooling/bats-assert/src/refute_output.bash b/tooling/bats-assert/src/refute_output.bash new file mode 100644 index 00000000000000..d656515abf9bce --- /dev/null +++ b/tooling/bats-assert/src/refute_output.bash @@ -0,0 +1,246 @@ +# refute_output +# ============= +# +# Summary: Fail if `$output' matches the unexpected output. +# +# Usage: refute_output [-p | -e] [- | [--] ] +# +# Options: +# -p, --partial Match if `unexpected` is a substring of `$output` +# -e, --regexp Treat `unexpected` as an extended regular expression +# -, --stdin Read `unexpected` value from STDIN +# The unexpected value, substring, or regular expression +# +# IO: +# STDIN - [=$1] unexpected output +# STDERR - details, on failure +# error message, on error +# Globals: +# output +# Returns: +# 0 - if output matches the unexpected value/partial/regexp +# 1 - otherwise +# +# This function verifies that a command or function does not produce the unexpected output. +# (It is the logical complement of `assert_output`.) +# Output matching can be literal (the default), partial or by regular expression. +# The unexpected output can be specified either by positional argument or read from STDIN by passing the `-`/`--stdin` flag. +# +# ## Literal matching +# +# By default, literal matching is performed. +# The assertion fails if `$output` equals the unexpected output. +# +# ```bash +# @test 'refute_output()' { +# run echo 'want' +# refute_output 'want' +# } +# +# @test 'refute_output() with pipe' { +# run echo 'hello' +# echo 'world' | refute_output - +# } +# +# @test 'refute_output() with herestring' { +# run echo 'hello' +# refute_output - <<< world +# } +# ``` +# +# On failure, the output is displayed. +# +# ``` +# -- output equals, but it was expected to differ -- +# output : want +# -- +# ``` +# +# ## Existence +# +# To assert that there is no output at all, omit the matching argument. +# +# ```bash +# @test 'refute_output()' { +# run foo --silent +# refute_output +# } +# ``` +# +# On failure, an error message is displayed. +# +# ``` +# -- unexpected output -- +# expected no output, but output was non-empty +# -- +# ``` +# +# ## Partial matching +# +# Partial matching can be enabled with the `--partial` option (`-p` for short). +# When used, the assertion fails if the unexpected _substring_ is found in `$output`. +# +# ```bash +# @test 'refute_output() partial matching' { +# run echo 'ERROR: no such file or directory' +# refute_output --partial 'ERROR' +# } +# ``` +# +# On failure, the substring and the output are displayed. +# +# ``` +# -- output should not contain substring -- +# substring : ERROR +# output : ERROR: no such file or directory +# -- +# ``` +# +# ## Regular expression matching +# +# Regular expression matching can be enabled with the `--regexp` option (`-e` for short). +# When used, the assertion fails if the *extended regular expression* matches `$output`. +# +# *__Note__: +# The anchors `^` and `$` bind to the beginning and the end (respectively) of the entire output; +# not individual lines.* +# +# ```bash +# @test 'refute_output() regular expression matching' { +# run echo 'Foobar v0.1.0' +# refute_output --regexp '^Foobar v[0-9]+\.[0-9]+\.[0-9]$' +# } +# ``` +# +# On failure, the regular expression and the output are displayed. +# +# ``` +# -- regular expression should not match output -- +# regexp : ^Foobar v[0-9]+\.[0-9]+\.[0-9]$ +# output : Foobar v0.1.0 +# -- +# ``` +refute_output() { + __refute_stream "$@" +} + +# refute_stderr +# ============= +# +# Summary: Fail if `$stderr' matches the unexpected output. +# +# Usage: refute_stderr [-p | -e] [- | [--] ] +# +# Options: +# -p, --partial Match if `unexpected` is a substring of `$stderr` +# -e, --regexp Treat `unexpected` as an extended regular expression +# -, --stdin Read `unexpected` value from STDIN +# The unexpected value, substring, or regular expression +# +# IO: +# STDIN - [=$1] unexpected stderr +# STDERR - details, on failure +# error message, on error +# Globals: +# stderr +# Returns: +# 0 - if stderr matches the unexpected value/partial/regexp +# 1 - otherwise +# +# Similar to `refute_output`, this function verifies that a command or function does not produce the unexpected stderr. +# (It is the logical complement of `assert_stderr`.) +# The stderr matching can be literal (the default), partial or by regular expression. +# The unexpected stderr can be specified either by positional argument or read from STDIN by passing the `-`/`--stdin` flag. +# +refute_stderr() { + __refute_stream "$@" +} + +__refute_stream() { + local -r caller=${FUNCNAME[1]} + local -r stream_type=${caller/refute_/} + local -i is_mode_partial=0 + local -i is_mode_regexp=0 + local -i is_mode_empty=0 + local -i use_stdin=0 + + if [[ ${stream_type} == "output" ]]; then + : "${output?}" + elif [[ ${stream_type} == "stderr" ]]; then + : "${stderr?}" + else + # Not reachable: should be either output or stderr + : + fi + local -r stream="${!stream_type}" + + # Handle options. + if (( $# == 0 )); then + is_mode_empty=1 + fi + + while (( $# > 0 )); do + case "$1" in + -p|--partial) is_mode_partial=1; shift ;; + -e|--regexp) is_mode_regexp=1; shift ;; + -|--stdin) use_stdin=1; shift ;; + --) shift; break ;; + *) break ;; + esac + done + + if (( is_mode_partial )) && (( is_mode_regexp )); then + echo "\`--partial' and \`--regexp' are mutually exclusive" \ + | batslib_decorate "ERROR: ${caller}" \ + | fail + return $? + fi + + # Arguments. + local unexpected + if (( use_stdin )); then + unexpected="$(cat -)" + else + unexpected="${1-}" + fi + + if (( is_mode_regexp == 1 )) && [[ '' =~ $unexpected ]] || (( $? == 2 )); then + echo "Invalid extended regular expression: \`$unexpected'" \ + | batslib_decorate "ERROR: ${caller}" \ + | fail + return $? + fi + + # Matching. + if (( is_mode_empty )); then + if [ -n "${stream}" ]; then + batslib_print_kv_single_or_multi 6 \ + "${stream_type}" "${stream}" \ + | batslib_decorate "${stream_type} non-empty, but expected no ${stream_type}" \ + | fail + fi + elif (( is_mode_regexp )); then + if [[ ${stream} =~ $unexpected ]]; then + batslib_print_kv_single_or_multi 6 \ + 'regexp' "$unexpected" \ + "${stream_type}" "${stream}" \ + | batslib_decorate "regular expression should not match ${stream_type}" \ + | fail + fi + elif (( is_mode_partial )); then + if [[ ${stream} == *"$unexpected"* ]]; then + batslib_print_kv_single_or_multi 9 \ + 'substring' "$unexpected" \ + "${stream_type}" "${stream}" \ + | batslib_decorate "${stream_type} should not contain substring" \ + | fail + fi + else + if [[ ${stream} == "$unexpected" ]]; then + batslib_print_kv_single_or_multi 6 \ + "${stream_type}" "${stream}" \ + | batslib_decorate "${stream_type} equals, but it was expected to differ" \ + | fail + fi + fi +} diff --git a/tooling/bats-assert/src/refute_regex.bash b/tooling/bats-assert/src/refute_regex.bash new file mode 100644 index 00000000000000..0918793f0ecfc2 --- /dev/null +++ b/tooling/bats-assert/src/refute_regex.bash @@ -0,0 +1,66 @@ +# `refute_regex` +# +# This function is similar to `refute_equal` but uses pattern matching instead +# of equality, by wrapping `! [[ value =~ pattern ]]`. +# +# Fail if the value (first parameter) matches the pattern (second parameter). +# +# ```bash +# @test 'refute_regex()' { +# refute_regex 'WhatsApp' 'Threema' +# } +# ``` +# +# On failure, the value, the pattern and the match are displayed. +# +# ``` +# @test 'refute_regex()' { +# refute_regex 'WhatsApp' 'What.' +# } +# +# -- value matches regular expression -- +# value : WhatsApp +# pattern : What. +# match : Whats +# case : sensitive +# -- +# ``` +# +# If the value or pattern is longer than one line then it is displayed in +# *multi-line* format. +# +# An error is displayed if the specified extended regular expression is invalid. +# +# For description of the matching behavior, refer to the documentation of the +# `=~` operator in the +# [Bash manual]: https://www.gnu.org/software/bash/manual/html_node/Conditional-Constructs.html. +# +# Note that the `BASH_REMATCH` array is available immediately after the +# assertion fails but is fragile, i.e. prone to being overwritten as a side +# effect of other actions like calling `run`. Thus, it's good practice to avoid +# using `BASH_REMATCH` in conjunction with `refute_regex()`. The valuable +# information the array contains is the matching part of the value which is +# printed in the failing test log, as mentioned above. +refute_regex() { + local -r value="${1}" + local -r pattern="${2}" + + if [[ '' =~ ${pattern} ]] || (( ${?} == 2 )); then + echo "Invalid extended regular expression: \`${pattern}'" \ + | batslib_decorate 'ERROR: refute_regex' \ + | fail + elif [[ "${value}" =~ ${pattern} ]]; then + if shopt -p nocasematch &>/dev/null; then + local case_sensitive=insensitive + else + local case_sensitive=sensitive + fi + batslib_print_kv_single_or_multi 8 \ + 'value' "${value}" \ + 'pattern' "${pattern}" \ + 'match' "${BASH_REMATCH[0]}" \ + 'case' "${case_sensitive}" \ + | batslib_decorate 'value matches regular expression' \ + | fail + fi +} diff --git a/tooling/bats-assert/test/assert.bats b/tooling/bats-assert/test/assert.bats new file mode 100755 index 00000000000000..d1a34a29601514 --- /dev/null +++ b/tooling/bats-assert/test/assert.bats @@ -0,0 +1,19 @@ +#!/usr/bin/env bats + +load test_helper + +@test 'assert() : returns 0 if evaluates to TRUE' { + run assert true + assert_test_pass +} + +@test 'assert() : returns 1 and displays if it evaluates to FALSE' { + run assert false + + assert_test_fail <<'ERR_MSG' + +-- assertion failed -- +expression : false +-- +ERR_MSG +} diff --git a/tooling/bats-assert/test/assert_equal.bats b/tooling/bats-assert/test/assert_equal.bats new file mode 100755 index 00000000000000..7d3fc8693c710f --- /dev/null +++ b/tooling/bats-assert/test/assert_equal.bats @@ -0,0 +1,62 @@ +#!/usr/bin/env bats + +load test_helper + +@test 'assert_equal() : returns 0 if equals ' { + run assert_equal 'a' 'a' + assert_test_pass +} + +@test 'assert_equal() : returns 1 and displays details if does not equal ' { + run assert_equal 'a' 'b' + + assert_test_fail <<'ERR_MSG' + +-- values do not equal -- +expected : b +actual : a +-- +ERR_MSG +} + +@test 'assert_equal() : displays details in multi-line format if is longer than one line' { + run assert_equal $'a 0\na 1' 'b' + + assert_test_fail <<'ERR_MSG' + +-- values do not equal -- +expected (1 lines): + b +actual (2 lines): + a 0 + a 1 +-- +ERR_MSG +} + +@test 'assert_equal() : displays details in multi-line format if is longer than one line' { + run assert_equal 'a' $'b 0\nb 1' + + assert_test_fail <<'ERR_MSG' + +-- values do not equal -- +expected (2 lines): + b 0 + b 1 +actual (1 lines): + a +-- +ERR_MSG +} + +@test 'assert_equal() : performs literal matching' { + run assert_equal 'a' '*' + + assert_test_fail <<'ERR_MSG' + +-- values do not equal -- +expected : * +actual : a +-- +ERR_MSG +} diff --git a/tooling/bats-assert/test/assert_failure.bats b/tooling/bats-assert/test/assert_failure.bats new file mode 100755 index 00000000000000..beb108fc5f0809 --- /dev/null +++ b/tooling/bats-assert/test/assert_failure.bats @@ -0,0 +1,94 @@ +#!/usr/bin/env bats + +load test_helper + +@test "assert_failure(): returns 0 if \`\$status' is not 0" { + run false + run assert_failure + assert_test_pass +} + +@test "assert_failure(): returns 1 and displays details if \`\$status' is 0" { + run bash -c 'echo "a" + exit 0' + run assert_failure + + assert_test_fail <<'ERR_MSG' + +-- command succeeded, but it was expected to fail -- +output : a +-- +ERR_MSG +} + +@test "assert_failure(): returns 1 and displays \`\$stderr' if it is set" { + bats_require_minimum_version 1.5.0 + run --separate-stderr \ + bash -c 'echo "a" + echo "b" >&2 + exit 0' + echo "Stderr: $stderr" >&3 + run assert_failure + + assert_test_fail <<'ERR_MSG' + +-- command succeeded, but it was expected to fail -- +output : a +stderr : b +-- +ERR_MSG +} + +@test "assert_failure(): displays \`\$output' in multi-line format if it is longer then one line" { + run bash -c 'printf "a 0\na 1" + exit 0' + run assert_failure + + assert_test_fail <<'ERR_MSG' + +-- command succeeded, but it was expected to fail -- +output (2 lines): + a 0 + a 1 +-- +ERR_MSG +} + +@test "assert_failure() : returns 0 if \`\$status' equals " { + run bash -c 'exit 1' + run assert_failure 1 + assert_test_pass +} + +@test "assert_failure() : returns 1 and displays details if \`\$status' does not equal " { + run bash -c 'echo "a" + exit 1' + run assert_failure 2 + + assert_test_fail <<'ERR_MSG' + +-- command failed as expected, but status differs -- +expected : 2 +actual : 1 +output : a +-- +ERR_MSG +} + +@test "assert_failure() : displays \`\$output' in multi-line format if it is longer then one line" { + run bash -c 'printf "a 0\na 1" + exit 1' + run assert_failure 2 + + assert_test_fail <<'ERR_MSG' + +-- command failed as expected, but status differs -- +expected : 2 +actual : 1 +output (2 lines): + a 0 + a 1 +-- +ERR_MSG +} + diff --git a/tooling/bats-assert/test/assert_line.bats b/tooling/bats-assert/test/assert_line.bats new file mode 100755 index 00000000000000..b69ed598d4b5af --- /dev/null +++ b/tooling/bats-assert/test/assert_line.bats @@ -0,0 +1,362 @@ +#!/usr/bin/env bats + +load test_helper + + +############################################################################### +# Containing a line +############################################################################### + +# +# Literal matching +# + +# Correctness +@test "assert_line() : returns 0 if is a line in \`\${lines[@]}'" { + run printf 'a\nb\nc' + run assert_line 'b' + assert_test_pass +} + +@test "assert_line() : returns 1 and displays details if is not a line in \`\${lines[@]}'" { + run echo 'b' + run assert_line 'a' + + assert_test_fail <<'ERR_MSG' + +-- output does not contain line -- +line : a +output : b +-- +ERR_MSG +} + +# Output formatting +@test "assert_line() : displays \`\$output' in multi-line format if it is longer than one line" { + run printf 'b 0\nb 1' + run assert_line 'a' + + assert_test_fail <<'ERR_MSG' + +-- output does not contain line -- +line : a +output (2 lines): + b 0 + b 1 +-- +ERR_MSG +} + +# Options +@test 'assert_line() : performs literal matching by default' { + run echo 'a' + run assert_line '*' + + assert_test_fail <<'ERR_MSG' + +-- output does not contain line -- +line : * +output : a +-- +ERR_MSG +} + + +# +# Partial matching: `-p' and `--partial' +# + +# Options +@test 'assert_line() -p : enables partial matching' { + run printf 'a\n_b_\nc' + run assert_line -p 'b' + assert_test_pass +} + +@test 'assert_line() --partial : enables partial matching' { + run printf 'a\n_b_\nc' + run assert_line --partial 'b' + assert_test_pass +} + +# Correctness +@test "assert_line() --partial : returns 0 if is a substring in any line in \`\${lines[@]}'" { + run printf 'a\n_b_\nc' + run assert_line --partial 'b' + assert_test_pass +} + +@test "assert_line() --partial : returns 1 and displays details if is not a substring in any lines in \`\${lines[@]}'" { + run echo 'b' + run assert_line --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- no output line contains substring -- +substring : a +output : b +-- +ERR_MSG +} + +# Output formatting +@test "assert_line() --partial : displays \`\$output' in multi-line format if it is longer than one line" { + run printf 'b 0\nb 1' + run assert_line --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- no output line contains substring -- +substring : a +output (2 lines): + b 0 + b 1 +-- +ERR_MSG +} + + +# +# Regular expression matching: `-e' and `--regexp' +# + +# Options +@test 'assert_line() -e : enables regular expression matching' { + run printf 'a\n_b_\nc' + run assert_line -e '^.b' + assert_test_pass +} + +@test 'assert_line() --regexp : enables regular expression matching' { + run printf 'a\n_b_\nc' + run assert_line --regexp '^.b' + assert_test_pass +} + +# Correctness +@test "assert_line() --regexp : returns 0 if matches any line in \`\${lines[@]}'" { + run printf 'a\n_b_\nc' + run assert_line --regexp '^.b' + assert_test_pass +} + +@test "assert_line() --regexp : returns 1 and displays details if does not match any lines in \`\${lines[@]}'" { + run echo 'b' + run assert_line --regexp '^.a' + + assert_test_fail <<'ERR_MSG' + +-- no output line matches regular expression -- +regexp : ^.a +output : b +-- +ERR_MSG +} + +# Output formatting +@test "assert_line() --regexp : displays \`\$output' in multi-line format if longer than one line" { + run printf 'b 0\nb 1' + run assert_line --regexp '^.a' + + assert_test_fail <<'ERR_MSG' + +-- no output line matches regular expression -- +regexp : ^.a +output (2 lines): + b 0 + b 1 +-- +ERR_MSG +} + + +############################################################################### +# Matching single line: `-n' and `--index' +############################################################################### + +# Options +@test 'assert_line() -n : matches against the -th line only' { + run printf 'a\nb\nc' + run assert_line -n 1 'b' + assert_test_pass +} + +@test 'assert_line() --index : matches against the -th line only' { + run printf 'a\nb\nc' + run assert_line --index 1 'b' + assert_test_pass +} + +@test 'assert_line() --index : returns 1 and displays an error message if is not an integer' { + run assert_line --index 1a + + assert_test_fail <<'ERR_MSG' + +-- ERROR: assert_line -- +`--index' requires an integer argument: `1a' +-- +ERR_MSG +} + + +# +# Literal matching +# + +# Correctness +@test "assert_line() --index : returns 0 if equals \`\${lines[]}'" { + run printf 'a\nb\nc' + run assert_line --index 1 'b' + assert_test_pass +} + +@test "assert_line() --index : returns 1 and displays details if does not equal \`\${lines[]}'" { + run printf 'a\nb\nc' + run assert_line --index 1 'a' + + assert_test_fail <<'ERR_MSG' + +-- line differs -- +index : 1 +expected : a +actual : b +-- +ERR_MSG +} + +# Options +@test 'assert_line() --index : performs literal matching by default' { + run printf 'a\nb\nc' + run assert_line --index 1 '*' + + assert_test_fail <<'ERR_MSG' + +-- line differs -- +index : 1 +expected : * +actual : b +-- +ERR_MSG +} + + +# +# Partial matching: `-p' and `--partial' +# + +# Options +@test 'assert_line() --index -p : enables partial matching' { + run printf 'a\n_b_\nc' + run assert_line --index 1 -p 'b' + assert_test_pass +} + +@test 'assert_line() --index --partial : enables partial matching' { + run printf 'a\n_b_\nc' + run assert_line --index 1 --partial 'b' + assert_test_pass +} + +# Correctness +@test "assert_line() --index --partial : returns 0 if is a substring in \`\${lines[]}'" { + run printf 'a\n_b_\nc' + run assert_line --index 1 --partial 'b' + assert_test_pass +} + +@test "assert_line() --index --partial : returns 1 and displays details if is not a substring in \`\${lines[]}'" { + run printf 'b 0\nb 1' + run assert_line --index 1 --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- line does not contain substring -- +index : 1 +substring : a +line : b 1 +-- +ERR_MSG +} + + +# +# Regular expression matching: `-e' and `--regexp' +# + +# Options +@test 'assert_line() --index -e : enables regular expression matching' { + run printf 'a\n_b_\nc' + run assert_line --index 1 -e '^.b' + assert_test_pass +} + +@test 'assert_line() --index --regexp : enables regular expression matching' { + run printf 'a\n_b_\nc' + run assert_line --index 1 --regexp '^.b' + assert_test_pass +} + +# Correctness +@test "assert_line() --index --regexp : returns 0 if matches \`\${lines[]}'" { + run printf 'a\n_b_\nc' + run assert_line --index 1 --regexp '^.b' + assert_test_pass +} + +@test "assert_line() --index --regexp : returns 1 and displays details if does not match \`\${lines[]}'" { + run printf 'a\nb\nc' + run assert_line --index 1 --regexp '^.a' + + assert_test_fail <<'ERR_MSG' + +-- regular expression does not match line -- +index : 1 +regexp : ^.a +line : b +-- +ERR_MSG +} + + +############################################################################### +# Common +############################################################################### + +@test "assert_line(): \`--partial' and \`--regexp' are mutually exclusive" { + run assert_line --partial --regexp + + assert_test_fail <<'ERR_MSG' + +-- ERROR: assert_line -- +`--partial' and `--regexp' are mutually exclusive +-- +ERR_MSG +} + +@test 'assert_line() --regexp : returns 1 and displays an error message if is not a valid extended regular expression' { + run assert_line --regexp '[.*' + + assert_test_fail <<'ERR_MSG' + +-- ERROR: assert_line -- +Invalid extended regular expression: `[.*' +-- +ERR_MSG +} + +@test "assert_line(): \`--' stops parsing options" { + run printf 'a\n-p\nc' + run assert_line -- '-p' + assert_test_pass +} + +@test "__assert_line(): call to __assert_line shows error" { + run __assert_line + assert_test_fail <<'ERR_MSG' + +-- ERROR: __assert_line -- +Unexpected call to `__assert_line` +Did you mean to call `assert_line` or `assert_stderr_line`? +-- +ERR_MSG +} diff --git a/tooling/bats-assert/test/assert_not_equal.bats b/tooling/bats-assert/test/assert_not_equal.bats new file mode 100644 index 00000000000000..42b531564aca2b --- /dev/null +++ b/tooling/bats-assert/test/assert_not_equal.bats @@ -0,0 +1,57 @@ +#!/usr/bin/env bats + +load test_helper + +@test 'assert_not_equal() : returns 0 if does not equal ' { + run assert_not_equal foo bar + assert_test_pass + + run assert_not_equal "foo" "bar" + assert_test_pass + + run assert_not_equal "foo" "" + assert_test_pass + + run assert_not_equal "" "foo" + assert_test_pass +} + +@test 'assert_not_equal() : returns 1 and displays details if equals ' { + run assert_not_equal 'foobar' 'foobar' + assert_test_fail <<'ERR_MSG' + +-- values should not be equal -- +unexpected : foobar +actual : foobar +-- +ERR_MSG + + run assert_not_equal 1 1 + assert_test_fail <<'ERR_MSG' + +-- values should not be equal -- +unexpected : 1 +actual : 1 +-- +ERR_MSG +} + +@test 'assert_not_equal() : displays details in multi-line format if and are longer than one line' { + run assert_not_equal $'foo\nbar' $'foo\nbar' + assert_test_fail <<'ERR_MSG' + +-- values should not be equal -- +unexpected (2 lines): + foo + bar +actual (2 lines): + foo + bar +-- +ERR_MSG +} + +@test 'assert_not_equal() : performs literal matching' { + run assert_not_equal 'a' '*' + assert_test_pass +} \ No newline at end of file diff --git a/tooling/bats-assert/test/assert_output.bats b/tooling/bats-assert/test/assert_output.bats new file mode 100755 index 00000000000000..667120340d9a0e --- /dev/null +++ b/tooling/bats-assert/test/assert_output.bats @@ -0,0 +1,296 @@ +#!/usr/bin/env bats + +load test_helper + +# +# Literal matching +# + +# Correctness +@test "assert_output() : returns 0 if equals \`\$output'" { + run echo 'a' + run assert_output 'a' + assert_test_pass +} + +@test "assert_output() : returns 1 and displays details if does not equal \`\$output'" { + run echo 'b' + run assert_output 'a' + + assert_test_fail <<'ERR_MSG' + +-- output differs -- +expected : a +actual : b +-- +ERR_MSG +} + +@test 'assert_output(): succeeds if output is non-empty' { + run echo 'a' + run assert_output + + assert_test_pass +} + +@test 'assert_output(): fails if output is empty' { + run echo '' + run assert_output + + assert_test_fail <<'ERR_MSG' + +-- no output -- +expected non-empty output, but output was empty +-- +ERR_MSG +} + +@test 'assert_output() - : reads from STDIN' { + run echo 'a' + run assert_output - < from STDIN' { + run echo 'a' + run assert_output --stdin <: displays details in multi-line format if \`\$output' is longer than one line" { + run printf 'b 0\nb 1' + run assert_output 'a' + + assert_test_fail <<'ERR_MSG' + +-- output differs -- +expected (1 lines): + a +actual (2 lines): + b 0 + b 1 +-- +ERR_MSG +} + +@test 'assert_output() : displays details in multi-line format if is longer than one line' { + run echo 'b' + run assert_output $'a 0\na 1' + + assert_test_fail <<'ERR_MSG' + +-- output differs -- +expected (2 lines): + a 0 + a 1 +actual (1 lines): + b +-- +ERR_MSG +} + +# Options +@test 'assert_output() : performs literal matching by default' { + run echo 'a' + run assert_output '*' + + assert_test_fail <<'ERR_MSG' + +-- output differs -- +expected : * +actual : a +-- +ERR_MSG +} + + +# +# Partial matching: `-p' and `--partial' +# + +@test 'assert_output() -p : enables partial matching' { + run echo 'abc' + run assert_output -p 'b' + assert_test_pass +} + +@test 'assert_output() --partial : enables partial matching' { + run echo 'abc' + run assert_output --partial 'b' + assert_test_pass +} + +# Correctness +@test "assert_output() --partial : returns 0 if is a substring in \`\$output'" { + run printf 'a\nb\nc' + run assert_output --partial 'b' + assert_test_pass +} + +@test "assert_output() --partial : returns 1 and displays details if is not a substring in \`\$output'" { + run echo 'b' + run assert_output --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- output does not contain substring -- +substring : a +output : b +-- +ERR_MSG +} + +# Output formatting +@test "assert_output() --partial : displays details in multi-line format if \`\$output' is longer than one line" { + run printf 'b 0\nb 1' + run assert_output --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- output does not contain substring -- +substring (1 lines): + a +output (2 lines): + b 0 + b 1 +-- +ERR_MSG +} + +@test 'assert_output() --partial : displays details in multi-line format if is longer than one line' { + run echo 'b' + run assert_output --partial $'a 0\na 1' + + assert_test_fail <<'ERR_MSG' + +-- output does not contain substring -- +substring (2 lines): + a 0 + a 1 +output (1 lines): + b +-- +ERR_MSG +} + + +# +# Regular expression matching: `-e' and `--regexp' +# + +@test 'assert_output() -e : enables regular expression matching' { + run echo 'abc' + run assert_output -e '^a' + assert_test_pass +} + +@test 'assert_output() --regexp : enables regular expression matching' { + run echo 'abc' + run assert_output --regexp '^a' + assert_test_pass +} + +# Correctness +@test "assert_output() --regexp : returns 0 if matches \`\$output'" { + run printf 'a\nb\nc' + run assert_output --regexp '.*b.*' + assert_test_pass +} + +@test "assert_output() --regexp : returns 1 and displays details if does not match \`\$output'" { + run echo 'b' + run assert_output --regexp '.*a.*' + + assert_test_fail <<'ERR_MSG' + +-- regular expression does not match output -- +regexp : .*a.* +output : b +-- +ERR_MSG +} + +# Output formatting +@test "assert_output() --regexp : displays details in multi-line format if \`\$output' is longer than one line" { + run printf 'b 0\nb 1' + run assert_output --regexp '.*a.*' + + assert_test_fail <<'ERR_MSG' + +-- regular expression does not match output -- +regexp (1 lines): + .*a.* +output (2 lines): + b 0 + b 1 +-- +ERR_MSG +} + +@test 'assert_output() --regexp : displays details in multi-line format if is longer than one line' { + run echo 'b' + run assert_output --regexp $'.*a\nb.*' + + assert_test_fail <<'ERR_MSG' + +-- regular expression does not match output -- +regexp (2 lines): + .*a + b.* +output (1 lines): + b +-- +ERR_MSG +} + +# Error handling +@test 'assert_output() --regexp : returns 1 and displays an error message if is not a valid extended regular expression' { + run assert_output --regexp '[.*' + + assert_test_fail <<'ERR_MSG' + +-- ERROR: assert_output -- +Invalid extended regular expression: `[.*' +-- +ERR_MSG +} + + +# +# Common +# + +@test "assert_output(): \`--partial' and \`--regexp' are mutually exclusive" { + run assert_output --partial --regexp + + assert_test_fail <<'ERR_MSG' + +-- ERROR: assert_output -- +`--partial' and `--regexp' are mutually exclusive +-- +ERR_MSG +} + +@test "assert_output(): \`--' stops parsing options" { + run echo '-p' + run assert_output -- '-p' + assert_test_pass +} + +@test "__assert_stream(): call to __assert_stream shows error" { + run __assert_stream + assert_test_fail <<'ERR_MSG' + +-- ERROR: __assert_stream -- +Unexpected call to `__assert_stream` +Did you mean to call `assert_output` or `assert_stderr`? +-- +ERR_MSG +} diff --git a/tooling/bats-assert/test/assert_regex.bats b/tooling/bats-assert/test/assert_regex.bats new file mode 100644 index 00000000000000..0a9c902fff18c4 --- /dev/null +++ b/tooling/bats-assert/test/assert_regex.bats @@ -0,0 +1,87 @@ +#!/usr/bin/env bats + +load test_helper + +# +# Literal matching +# + +# Correctness +@test "assert_regex() : succeeds if a substring matches extended regular expression " { + run assert_regex 'abc' '^[a-z]b[c-z]+' + assert_test_pass +} + +@test "assert_regex() : fails if no substring matches extended regular expression " { + run assert_regex 'bcd' '^[a-z]b[c-z]+' + assert_test_fail <<'ERR_MSG' + +-- value does not match regular expression -- +value : bcd +pattern : ^[a-z]b[c-z]+ +case : sensitive +-- +ERR_MSG +} + +@test "assert_regex() : provides results in BASH_REMATCH" { + unset -v BASH_REMATCH + + assert_regex 'abcd' 'b.d' + declare -p BASH_REMATCH + [ "${BASH_REMATCH[0]}" = 'bcd' ] +} + +@test "assert_regex() : matches case-insensitively when 'nocasematch' is set" { + shopt -s nocasematch + + assert_regex 'aBc' 'ABC' +} + +@test "assert_regex() : outputs multi-line nicely when it fails" { + run assert_regex $'bcd\n123' '^[a-z]b[c-z]+' + assert_test_fail <<'ERR_MSG' + +-- value does not match regular expression -- +value (2 lines): + bcd + 123 +pattern (1 lines): + ^[a-z]b[c-z]+ +case (1 lines): + sensitive +-- +ERR_MSG + + shopt -s nocasematch + run assert_regex $'bcd\n123' '^[a-z]b[c-z]+' + assert_test_fail <<'ERR_MSG' + +-- value does not match regular expression -- +value (2 lines): + bcd + 123 +pattern (1 lines): + ^[a-z]b[c-z]+ +case (1 lines): + insensitive +-- +ERR_MSG +} + +# Error handling +@test "assert_regex() : returns 1 and displays an error message if is not a valid extended regular expression" { + run assert_regex value '[.*' + + assert_test_fail <<'ERR_MSG' + +-- ERROR: assert_regex -- +Invalid extended regular expression: `[.*' +-- +ERR_MSG +} + +@test "assert_regex allows regex matching empty string (see #53)" { + run assert_regex any_value '.*' + assert_success +} diff --git a/tooling/bats-assert/test/assert_stderr.bats b/tooling/bats-assert/test/assert_stderr.bats new file mode 100755 index 00000000000000..ebedde8f8cacf1 --- /dev/null +++ b/tooling/bats-assert/test/assert_stderr.bats @@ -0,0 +1,298 @@ +#!/usr/bin/env bats + +load test_helper + +setup_file() { + bats_require_minimum_version 1.5.0 +} + +echo_err() { + echo "$@" >&2 +} + +printf_err() { + # shellcheck disable=2059 + printf "$@" >&2 +} + +# +# Literal matching +# + +# Correctness +@test "assert_stderr() : returns 0 if equals \`\$stderr'" { + run --separate-stderr echo_err 'a' + run assert_stderr 'a' + assert_test_pass +} + +@test "assert_stderr() : returns 1 and displays details if does not equal \`\$stderr'" { + run --separate-stderr echo_err 'b' + run assert_stderr 'a' + + assert_test_fail <<'ERR_MSG' + +-- stderr differs -- +expected : a +actual : b +-- +ERR_MSG +} + +@test 'assert_stderr(): succeeds if stderr is non-empty' { + run --separate-stderr echo_err 'a' + run assert_stderr + + assert_test_pass +} + +@test 'assert_stderr(): fails if stderr is empty' { + run --separate-stderr echo_err '' + run assert_stderr + + assert_test_fail <<'ERR_MSG' + +-- no stderr -- +expected non-empty stderr, but stderr was empty +-- +ERR_MSG +} + +@test 'assert_stderr() - : reads from STDIN' { + run --separate-stderr echo_err 'a' + run assert_stderr - < from STDIN' { + run --separate-stderr echo_err 'a' + run assert_stderr --stdin <: displays details in multi-line format if \`\$stderr' is longer than one line" { + run --separate-stderr printf_err 'b 0\nb 1' + run assert_stderr 'a' + + assert_test_fail <<'ERR_MSG' + +-- stderr differs -- +expected (1 lines): + a +actual (2 lines): + b 0 + b 1 +-- +ERR_MSG +} + +@test 'assert_stderr() : displays details in multi-line format if is longer than one line' { + run --separate-stderr echo_err 'b' + run assert_stderr $'a 0\na 1' + + assert_test_fail <<'ERR_MSG' + +-- stderr differs -- +expected (2 lines): + a 0 + a 1 +actual (1 lines): + b +-- +ERR_MSG +} + +# Options +@test 'assert_stderr() : performs literal matching by default' { + run --separate-stderr echo_err 'a' + run assert_stderr '*' + + assert_test_fail <<'ERR_MSG' + +-- stderr differs -- +expected : * +actual : a +-- +ERR_MSG +} + + +# +# Partial matching: `-p' and `--partial' +# + +@test 'assert_stderr() -p : enables partial matching' { + run --separate-stderr echo_err 'abc' + run assert_stderr -p 'b' + assert_test_pass +} + +@test 'assert_stderr() --partial : enables partial matching' { + run --separate-stderr echo_err 'abc' + run assert_stderr --partial 'b' + assert_test_pass +} + +# Correctness +@test "assert_stderr() --partial : returns 0 if is a substring in \`\$stderr'" { + run --separate-stderr printf_err 'a\nb\nc' + run assert_stderr --partial 'b' + assert_test_pass +} + +@test "assert_stderr() --partial : returns 1 and displays details if is not a substring in \`\$stderr'" { + run --separate-stderr echo_err 'b' + run assert_stderr --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- stderr does not contain substring -- +substring : a +stderr : b +-- +ERR_MSG +} + +# stderr formatting +@test "assert_stderr() --partial : displays details in multi-line format if \`\$stderr' is longer than one line" { + run --separate-stderr printf_err 'b 0\nb 1' + run assert_stderr --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- stderr does not contain substring -- +substring (1 lines): + a +stderr (2 lines): + b 0 + b 1 +-- +ERR_MSG +} + +@test 'assert_stderr() --partial : displays details in multi-line format if is longer than one line' { + run --separate-stderr echo_err 'b' + run assert_stderr --partial $'a 0\na 1' + + assert_test_fail <<'ERR_MSG' + +-- stderr does not contain substring -- +substring (2 lines): + a 0 + a 1 +stderr (1 lines): + b +-- +ERR_MSG +} + + +# +# Regular expression matching: `-e' and `--regexp' +# + +@test 'assert_stderr() -e : enables regular expression matching' { + run --separate-stderr echo_err 'abc' + run assert_stderr -e '^a' + assert_test_pass +} + +@test 'assert_stderr() --regexp : enables regular expression matching' { + run --separate-stderr echo_err 'abc' + run assert_stderr --regexp '^a' + assert_test_pass +} + +# Correctness +@test "assert_stderr() --regexp : returns 0 if matches \`\$stderr'" { + run --separate-stderr printf_err 'a\nb\nc' + run assert_stderr --regexp '.*b.*' + assert_test_pass +} + +@test "assert_stderr() --regexp : returns 1 and displays details if does not match \`\$stderr'" { + run --separate-stderr echo_err 'b' + run assert_stderr --regexp '.*a.*' + + assert_test_fail <<'ERR_MSG' + +-- regular expression does not match stderr -- +regexp : .*a.* +stderr : b +-- +ERR_MSG +} + +# stderr formatting +@test "assert_stderr() --regexp : displays details in multi-line format if \`\$stderr' is longer than one line" { + run --separate-stderr printf_err 'b 0\nb 1' + run assert_stderr --regexp '.*a.*' + + assert_test_fail <<'ERR_MSG' + +-- regular expression does not match stderr -- +regexp (1 lines): + .*a.* +stderr (2 lines): + b 0 + b 1 +-- +ERR_MSG +} + +@test 'assert_stderr() --regexp : displays details in multi-line format if is longer than one line' { + run --separate-stderr echo_err 'b' + run assert_stderr --regexp $'.*a\nb.*' + + assert_test_fail <<'ERR_MSG' + +-- regular expression does not match stderr -- +regexp (2 lines): + .*a + b.* +stderr (1 lines): + b +-- +ERR_MSG +} + +# Error handling +@test 'assert_stderr() --regexp : returns 1 and displays an error message if is not a valid extended regular expression' { + run assert_stderr --regexp '[.*' + + assert_test_fail <<'ERR_MSG' + +-- ERROR: assert_stderr -- +Invalid extended regular expression: `[.*' +-- +ERR_MSG +} + + +# +# Common +# + +@test "assert_stderr(): \`--partial' and \`--regexp' are mutually exclusive" { + run assert_stderr --partial --regexp + + assert_test_fail <<'ERR_MSG' + +-- ERROR: assert_stderr -- +`--partial' and `--regexp' are mutually exclusive +-- +ERR_MSG +} + +@test "assert_stderr(): \`--' stops parsing options" { + run --separate-stderr echo_err '-p' + run assert_stderr -- '-p' + assert_test_pass +} diff --git a/tooling/bats-assert/test/assert_stderr_line.bats b/tooling/bats-assert/test/assert_stderr_line.bats new file mode 100755 index 00000000000000..bb3a071b5f6352 --- /dev/null +++ b/tooling/bats-assert/test/assert_stderr_line.bats @@ -0,0 +1,364 @@ +#!/usr/bin/env bats + +load test_helper + +setup_file() { + bats_require_minimum_version 1.5.0 +} + +echo_err() { + echo "$@" >&2 +} + +printf_err() { + # shellcheck disable=2059 + printf "$@" >&2 +} + + +############################################################################### +# Containing a line +############################################################################### + +# +# Literal matching +# + +# Correctness +@test "assert_stderr_line() : returns 0 if is a line in \`\${stderr_lines[@]}'" { + run --separate-stderr printf_err 'a\nb\nc' + run assert_stderr_line 'b' + assert_test_pass +} + +@test "assert_stderr_line() : returns 1 and displays details if is not a line in \`\${stderr_lines[@]}'" { + run --separate-stderr echo_err 'b' + run assert_stderr_line 'a' + + assert_test_fail <<'ERR_MSG' + +-- stderr does not contain line -- +line : a +stderr : b +-- +ERR_MSG +} + +# stderr formatting +@test "assert_stderr_line() : displays \`\$stderr' in multi-line format if it is longer than one line" { + run --separate-stderr printf_err 'b 0\nb 1' + run assert_stderr_line 'a' + + assert_test_fail <<'ERR_MSG' + +-- stderr does not contain line -- +line : a +stderr (2 lines): + b 0 + b 1 +-- +ERR_MSG +} + +# Options +@test 'assert_stderr_line() : performs literal matching by default' { + run --separate-stderr echo_err 'a' + run assert_stderr_line '*' + + assert_test_fail <<'ERR_MSG' + +-- stderr does not contain line -- +line : * +stderr : a +-- +ERR_MSG +} + + +# +# Partial matching: `-p' and `--partial' +# + +# Options +@test 'assert_stderr_line() -p : enables partial matching' { + run --separate-stderr printf_err 'a\n_b_\nc' + run assert_stderr_line -p 'b' + assert_test_pass +} + +@test 'assert_stderr_line() --partial : enables partial matching' { + run --separate-stderr printf_err 'a\n_b_\nc' + run assert_stderr_line --partial 'b' + assert_test_pass +} + +# Correctness +@test "assert_stderr_line() --partial : returns 0 if is a substring in any line in \`\${stderr_lines[@]}'" { + run --separate-stderr printf_err 'a\n_b_\nc' + run assert_stderr_line --partial 'b' + assert_test_pass +} + +@test "assert_stderr_line() --partial : returns 1 and displays details if is not a substring in any lines in \`\${stderr_lines[@]}'" { + run --separate-stderr echo_err 'b' + run assert_stderr_line --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- no stderr line contains substring -- +substring : a +stderr : b +-- +ERR_MSG +} + +# stderr formatting +@test "assert_stderr_line() --partial : displays \`\$stderr' in multi-line format if it is longer than one line" { + run --separate-stderr printf_err 'b 0\nb 1' + run assert_stderr_line --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- no stderr line contains substring -- +substring : a +stderr (2 lines): + b 0 + b 1 +-- +ERR_MSG +} + + +# +# Regular expression matching: `-e' and `--regexp' +# + +# Options +@test 'assert_stderr_line() -e : enables regular expression matching' { + run --separate-stderr printf_err 'a\n_b_\nc' + run assert_stderr_line -e '^.b' + assert_test_pass +} + +@test 'assert_stderr_line() --regexp : enables regular expression matching' { + run --separate-stderr printf_err 'a\n_b_\nc' + run assert_stderr_line --regexp '^.b' + assert_test_pass +} + +# Correctness +@test "assert_stderr_line() --regexp : returns 0 if matches any line in \`\${stderr_lines[@]}'" { + run --separate-stderr printf_err 'a\n_b_\nc' + run assert_stderr_line --regexp '^.b' + assert_test_pass +} + +@test "assert_stderr_line() --regexp : returns 1 and displays details if does not match any lines in \`\${stderr_lines[@]}'" { + run --separate-stderr echo_err 'b' + run assert_stderr_line --regexp '^.a' + + assert_test_fail <<'ERR_MSG' + +-- no stderr line matches regular expression -- +regexp : ^.a +stderr : b +-- +ERR_MSG +} + +# stderr formatting +@test "assert_stderr_line() --regexp : displays \`\$stderr' in multi-line format if longer than one line" { + run --separate-stderr printf_err 'b 0\nb 1' + run assert_stderr_line --regexp '^.a' + + assert_test_fail <<'ERR_MSG' + +-- no stderr line matches regular expression -- +regexp : ^.a +stderr (2 lines): + b 0 + b 1 +-- +ERR_MSG +} + + +############################################################################### +# Matching single line: `-n' and `--index' +############################################################################### + +# Options +@test 'assert_stderr_line() -n : matches against the -th line only' { + run --separate-stderr printf_err 'a\nb\nc' + run assert_stderr_line -n 1 'b' + assert_test_pass +} + +@test 'assert_stderr_line() --index : matches against the -th line only' { + run --separate-stderr printf_err 'a\nb\nc' + run assert_stderr_line --index 1 'b' + assert_test_pass +} + +@test 'assert_stderr_line() --index : returns 1 and displays an error message if is not an integer' { + run assert_stderr_line --index 1a + + assert_test_fail <<'ERR_MSG' + +-- ERROR: assert_stderr_line -- +`--index' requires an integer argument: `1a' +-- +ERR_MSG +} + + +# +# Literal matching +# + +# Correctness +@test "assert_stderr_line() --index : returns 0 if equals \`\${stderr_lines[]}'" { + run --separate-stderr printf_err 'a\nb\nc' + run assert_stderr_line --index 1 'b' + assert_test_pass +} + +@test "assert_stderr_line() --index : returns 1 and displays details if does not equal \`\${stderr_lines[]}'" { + run --separate-stderr printf_err 'a\nb\nc' + run assert_stderr_line --index 1 'a' + + assert_test_fail <<'ERR_MSG' + +-- line differs -- +index : 1 +expected : a +actual : b +-- +ERR_MSG +} + +# Options +@test 'assert_stderr_line() --index : performs literal matching by default' { + run --separate-stderr printf_err 'a\nb\nc' + run assert_stderr_line --index 1 '*' + + assert_test_fail <<'ERR_MSG' + +-- line differs -- +index : 1 +expected : * +actual : b +-- +ERR_MSG +} + + +# +# Partial matching: `-p' and `--partial' +# + +# Options +@test 'assert_stderr_line() --index -p : enables partial matching' { + run --separate-stderr printf_err 'a\n_b_\nc' + run assert_stderr_line --index 1 -p 'b' + assert_test_pass +} + +@test 'assert_stderr_line() --index --partial : enables partial matching' { + run --separate-stderr printf_err 'a\n_b_\nc' + run assert_stderr_line --index 1 --partial 'b' + assert_test_pass +} + +# Correctness +@test "assert_stderr_line() --index --partial : returns 0 if is a substring in \`\${stderr_lines[]}'" { + run --separate-stderr printf_err 'a\n_b_\nc' + run assert_stderr_line --index 1 --partial 'b' + assert_test_pass +} + +@test "assert_stderr_line() --index --partial : returns 1 and displays details if is not a substring in \`\${stderr_lines[]}'" { + run --separate-stderr printf_err 'b 0\nb 1' + run assert_stderr_line --index 1 --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- line does not contain substring -- +index : 1 +substring : a +line : b 1 +-- +ERR_MSG +} + + +# +# Regular expression matching: `-e' and `--regexp' +# + +# Options +@test 'assert_stderr_line() --index -e : enables regular expression matching' { + run --separate-stderr printf_err 'a\n_b_\nc' + run assert_stderr_line --index 1 -e '^.b' + assert_test_pass +} + +@test 'assert_stderr_line() --index --regexp : enables regular expression matching' { + run --separate-stderr printf_err 'a\n_b_\nc' + run assert_stderr_line --index 1 --regexp '^.b' + assert_test_pass +} + +# Correctness +@test "assert_stderr_line() --index --regexp : returns 0 if matches \`\${stderr_lines[]}'" { + run --separate-stderr printf_err 'a\n_b_\nc' + run assert_stderr_line --index 1 --regexp '^.b' + assert_test_pass +} + +@test "assert_stderr_line() --index --regexp : returns 1 and displays details if does not match \`\${stderr_lines[]}'" { + run --separate-stderr printf_err 'a\nb\nc' + run assert_stderr_line --index 1 --regexp '^.a' + + assert_test_fail <<'ERR_MSG' + +-- regular expression does not match line -- +index : 1 +regexp : ^.a +line : b +-- +ERR_MSG +} + + +############################################################################### +# Common +############################################################################### + +@test "assert_stderr_line(): \`--partial' and \`--regexp' are mutually exclusive" { + run assert_stderr_line --partial --regexp + + assert_test_fail <<'ERR_MSG' + +-- ERROR: assert_stderr_line -- +`--partial' and `--regexp' are mutually exclusive +-- +ERR_MSG +} + +@test 'assert_stderr_line() --regexp : returns 1 and displays an error message if is not a valid extended regular expression' { + run assert_stderr_line --regexp '[.*' + + assert_test_fail <<'ERR_MSG' + +-- ERROR: assert_stderr_line -- +Invalid extended regular expression: `[.*' +-- +ERR_MSG +} + +@test "assert_stderr_line(): \`--' stops parsing options" { + run --separate-stderr printf_err 'a\n-p\nc' + run assert_stderr_line -- '-p' + assert_test_pass +} diff --git a/tooling/bats-assert/test/assert_success.bats b/tooling/bats-assert/test/assert_success.bats new file mode 100755 index 00000000000000..719c0f75f74d6f --- /dev/null +++ b/tooling/bats-assert/test/assert_success.bats @@ -0,0 +1,58 @@ +#!/usr/bin/env bats + +load test_helper + +@test "assert_success(): returns 0 if \`\$status' is 0" { + run true + run assert_success + + assert_test_pass +} + +@test "assert_success(): returns 1 and displays details if \`\$status' is not 0" { + run bash -c 'echo "a" + exit 1' + run assert_success + + assert_test_fail <<'ERR_MSG' + +-- command failed -- +status : 1 +output : a +-- +ERR_MSG +} + +@test "assert_success(): displays \`\$output' in multi-line format if it is longer than one line" { + run bash -c 'printf "a 0\na 1" + exit 1' + run assert_success + + assert_test_fail <<'ERR_MSG' + +-- command failed -- +status : 1 +output (2 lines): + a 0 + a 1 +-- +ERR_MSG +} + +@test "assert_success(): displays \`\$stderr' if it is set" { + bats_require_minimum_version 1.5.0 + run --separate-stderr \ + bash -c 'echo "a" + echo "b" >&2 + exit 1' + run assert_success + + assert_test_fail <<'ERR_MSG' + +-- command failed -- +status : 1 +output : a +stderr : b +-- +ERR_MSG +} \ No newline at end of file diff --git a/tooling/bats-assert/test/refute.bats b/tooling/bats-assert/test/refute.bats new file mode 100755 index 00000000000000..f9e2737fe10d57 --- /dev/null +++ b/tooling/bats-assert/test/refute.bats @@ -0,0 +1,18 @@ +#!/usr/bin/env bats + +load test_helper + +@test 'refute() : returns 0 if evaluates to FALSE' { + run refute false + assert_test_pass +} + +@test 'refute() : returns 1 and displays if it evaluates to TRUE' { + run refute true + assert_test_fail <<'ERR_MSG' + +-- assertion succeeded, but it was expected to fail -- +expression : true +-- +ERR_MSG +} diff --git a/tooling/bats-assert/test/refute_line.bats b/tooling/bats-assert/test/refute_line.bats new file mode 100755 index 00000000000000..e0ad762d128be7 --- /dev/null +++ b/tooling/bats-assert/test/refute_line.bats @@ -0,0 +1,355 @@ +#!/usr/bin/env bats + +load test_helper + + +############################################################################### +# Containing a line +############################################################################### + +# +# Literal matching +# + +# Correctness +@test "refute_line() : returns 0 if is not a line in \`\${lines[@]}'" { + run printf 'a\nb\nc' + run refute_line 'd' + assert_test_pass +} + +@test "refute_line() : returns 1 and displays details if is not a line in \`\${lines[@]}'" { + run echo 'a' + run refute_line 'a' + + assert_test_fail <<'ERR_MSG' + +-- line should not be in output -- +line : a +index : 0 +output : a +-- +ERR_MSG +} + +# Output formatting +@test "refute_line() : displays \`\$output' in multi-line format if it is longer than one line" { + run printf 'a 0\na 1\na 2' + run refute_line 'a 1' + + assert_test_fail <<'ERR_MSG' + +-- line should not be in output -- +line : a 1 +index : 1 +output (3 lines): + a 0 +> a 1 + a 2 +-- +ERR_MSG +} + +# Options +@test 'refute_line() : performs literal matching by default' { + run echo 'a' + run refute_line '*' + assert_test_pass +} + + +# +# Partial matching: `-p' and `--partial' +# + +# Options +@test 'refute_line() -p : enables partial matching' { + run printf 'a\nb\nc' + run refute_line -p 'd' + assert_test_pass +} + +@test 'refute_line() --partial : enables partial matching' { + run printf 'a\nb\nc' + run refute_line --partial 'd' + assert_test_pass +} + +# Correctness +@test "refute_line() --partial : returns 0 if is not a substring in any line in \`\${lines[@]}'" { + run printf 'a\nb\nc' + run refute_line --partial 'd' + assert_test_pass +} + +@test "refute_line() --partial : returns 1 and displays details if is a substring in any line in \`\${lines[@]}'" { + run echo 'a' + run refute_line --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- no line should contain substring -- +substring : a +index : 0 +output : a +-- +ERR_MSG +} + +# Output formatting +@test "refute_line() --partial : displays \`\$output' in multi-line format if it is longer than one line" { + run printf 'a\nabc\nc' + run refute_line --partial 'b' + + assert_test_fail <<'ERR_MSG' + +-- no line should contain substring -- +substring : b +index : 1 +output (3 lines): + a +> abc + c +-- +ERR_MSG +} + + +# +# Regular expression matching: `-e' and `--regexp' +# + +# Options +@test 'refute_line() -e : enables regular expression matching' { + run printf 'a\nb\nc' + run refute_line -e '^.d' + assert_test_pass +} + +@test 'refute_line() --regexp : enables regular expression matching' { + run printf 'a\nb\nc' + run refute_line --regexp '^.d' + assert_test_pass +} + +# Correctness +@test "refute_line() --regexp : returns 0 if does not match any line in \`\${lines[@]}'" { + run printf 'a\nb\nc' + run refute_line --regexp '.*d.*' + assert_test_pass +} + +@test "refute_line() --regexp : returns 1 and displays details if matches any lines in \`\${lines[@]}'" { + run echo 'a' + run refute_line --regexp '.*a.*' + + assert_test_fail <<'ERR_MSG' + +-- no line should match the regular expression -- +regexp : .*a.* +index : 0 +output : a +-- +ERR_MSG +} + +# Output formatting +@test "refute_line() --regexp : displays \`\$output' in multi-line format if longer than one line" { + run printf 'a\nabc\nc' + run refute_line --regexp '.*b.*' + + assert_test_fail <<'ERR_MSG' + +-- no line should match the regular expression -- +regexp : .*b.* +index : 1 +output (3 lines): + a +> abc + c +-- +ERR_MSG +} + + +############################################################################### +# Matching single line: `-n' and `--index' +############################################################################### + +# Options +@test 'refute_line() -n : matches against the -th line only' { + run printf 'a\nb\nc' + run refute_line -n 1 'd' + assert_test_pass +} + +@test 'refute_line() --index : matches against the -th line only' { + run printf 'a\nb\nc' + run refute_line --index 1 'd' + assert_test_pass +} + +@test 'refute_line() --index : returns 1 and displays an error message if is not an integer' { + run refute_line --index 1a + + assert_test_fail <<'ERR_MSG' + +-- ERROR: refute_line -- +`--index' requires an integer argument: `1a' +-- +ERR_MSG +} + + +# +# Literal matching +# + +# Correctness +@test "refute_line() --index : returns 0 if does not equal \`\${lines[]}'" { + run printf 'a\nb\nc' + run refute_line --index 1 'd' + assert_test_pass +} + +@test "refute_line() --index : returns 1 and displays details if equals \`\${lines[]}'" { + run printf 'a\nb\nc' + run refute_line --index 1 'b' + + assert_test_fail <<'ERR_MSG' + +-- line should differ -- +index : 1 +line : b +-- +ERR_MSG +} + +# Options +@test 'refute_line() --index : performs literal matching by default' { + run printf 'a\nb\nc' + run refute_line --index 1 '*' + assert_test_pass +} + + +# +# Partial matching: `-p' and `--partial' +# + +# Options +@test 'refute_line() --index -p : enables partial matching' { + run printf 'a\nb\nc' + run refute_line --index 1 -p 'd' + assert_test_pass +} + +@test 'refute_line() --index --partial : enables partial matching' { + run printf 'a\nb\nc' + run refute_line --index 1 --partial 'd' + assert_test_pass +} + +# Correctness +@test "refute_line() --index --partial : returns 0 if is not a substring in \`\${lines[]}'" { + run printf 'a\nabc\nc' + run refute_line --index 1 --partial 'd' + assert_test_pass +} + +@test "refute_line() --index --partial : returns 1 and displays details if is a substring in \`\${lines[]}'" { + run printf 'a\nabc\nc' + run refute_line --index 1 --partial 'b' + + assert_test_fail <<'ERR_MSG' + +-- line should not contain substring -- +index : 1 +substring : b +line : abc +-- +ERR_MSG +} + + +# +# Regular expression matching: `-e' and `--regexp' +# + +# Options +@test 'refute_line() --index -e : enables regular expression matching' { + run printf 'a\nb\nc' + run refute_line --index 1 -e '^.b' + assert_test_pass +} + +@test 'refute_line() --index --regexp : enables regular expression matching' { + run printf 'a\nb\nc' + run refute_line --index 1 --regexp '^.b' + assert_test_pass +} + +# Correctness +@test "refute_line() --index --regexp : returns 0 if does not match \`\${lines[]}'" { + run printf 'a\nabc\nc' + run refute_line --index 1 --regexp '.*d.*' + assert_test_pass +} + +@test "refute_line() --index --regexp : returns 1 and displays details if matches \`\${lines[]}'" { + run printf 'a\nabc\nc' + run refute_line --index 1 --regexp '.*b.*' + + assert_test_fail <<'ERR_MSG' + +-- regular expression should not match line -- +index : 1 +regexp : .*b.* +line : abc +-- +ERR_MSG +} + + +############################################################################### +# Common +############################################################################### + +@test "refute_line(): \`--partial' and \`--regexp' are mutually exclusive" { + run refute_line --partial --regexp + + assert_test_fail <<'ERR_MSG' + +-- ERROR: refute_line -- +`--partial' and `--regexp' are mutually exclusive +-- +ERR_MSG +} + +@test 'refute_line() --regexp : returns 1 and displays an error message if is not a valid extended regular expression' { + run refute_line --regexp '[.*' + + assert_test_fail <<'ERR_MSG' + +-- ERROR: refute_line -- +Invalid extended regular expression: `[.*' +-- +ERR_MSG +} + +@test "refute_line(): \`--' stops parsing options" { + run printf 'a\n--\nc' + run refute_line -- '-p' + assert_test_pass +} + +@test "__refute_stream_line(): call to __refute_stream_line shows error" { + run __refute_stream_line + assert_test_fail <<'ERR_MSG' + +-- ERROR: __refute_stream_line -- +Unexpected call to `__refute_stream_line` +Did you mean to call `refute_line` or `refute_stderr_line`? +-- +ERR_MSG +} diff --git a/tooling/bats-assert/test/refute_output.bats b/tooling/bats-assert/test/refute_output.bats new file mode 100755 index 00000000000000..9d8711d57b3e32 --- /dev/null +++ b/tooling/bats-assert/test/refute_output.bats @@ -0,0 +1,230 @@ +#!/usr/bin/env bats + +load test_helper + + +# +# Literal matching +# + +# Correctness +@test "refute_output() : returns 0 if does not equal \`\$output'" { + run echo 'b' + run refute_output 'a' + assert_test_pass +} + +@test "refute_output() : returns 1 and displays details if equals \`\$output'" { + run echo 'a' + run refute_output 'a' + + assert_test_fail <<'ERR_MSG' + +-- output equals, but it was expected to differ -- +output : a +-- +ERR_MSG +} + +@test 'refute_output(): succeeds if output is empty' { + run echo '' + run refute_output + + assert_test_pass +} + +@test 'refute_output(): fails if output is non-empty' { + run echo 'a' + run refute_output + + assert_test_fail <<'ERR_MSG' + +-- output non-empty, but expected no output -- +output : a +-- +ERR_MSG +} + +@test 'refute_output() - : reads from STDIN' { + run echo '-' + run refute_output - < from STDIN' { + run echo '--stdin' + run refute_output --stdin <: displays details in multi-line format if necessary' { + run printf 'a 0\na 1' + run refute_output $'a 0\na 1' + + assert_test_fail <<'ERR_MSG' + +-- output equals, but it was expected to differ -- +output (2 lines): + a 0 + a 1 +-- +ERR_MSG +} + +# Options +@test 'refute_output() : performs literal matching by default' { + run echo 'a' + run refute_output '*' + assert_test_pass +} + + +# +# Partial matching: `-p' and `--partial' +# + +# Options +@test 'refute_output() -p : enables partial matching' { + run echo 'abc' + run refute_output -p 'd' + assert_test_pass +} + +@test 'refute_output() --partial : enables partial matching' { + run echo 'abc' + run refute_output --partial 'd' + assert_test_pass +} + +# Correctness +@test "refute_output() --partial : returns 0 if is not a substring in \`\$output'" { + run printf 'a\nb\nc' + run refute_output --partial 'd' + assert_test_pass +} + +@test "refute_output() --partial : returns 1 and displays details if is a substring in \`\$output'" { + run echo 'a' + run refute_output --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- output should not contain substring -- +substring : a +output : a +-- +ERR_MSG +} + +# Output formatting +@test 'refute_output() --partial : displays details in multi-line format if necessary' { + run printf 'a 0\na 1' + run refute_output --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- output should not contain substring -- +substring (1 lines): + a +output (2 lines): + a 0 + a 1 +-- +ERR_MSG +} + + +# +# Regular expression matching: `-e' and `--regexp' +# + +# Options +@test 'refute_output() -e : enables regular expression matching' { + run echo 'abc' + run refute_output -e '^d' + assert_test_pass +} + +@test 'refute_output() --regexp : enables regular expression matching' { + run echo 'abc' + run refute_output --regexp '^d' + assert_test_pass +} + +# Correctness +@test "refute_output() --regexp : returns 0 if does not match \`\$output'" { + run printf 'a\nb\nc' + run refute_output --regexp '.*d.*' + assert_test_pass +} + +@test "refute_output() --regexp : returns 1 and displays details if matches \`\$output'" { + run echo 'a' + run refute_output --regexp '.*a.*' + + assert_test_fail <<'ERR_MSG' + +-- regular expression should not match output -- +regexp : .*a.* +output : a +-- +ERR_MSG +} + +# Output formatting +@test 'refute_output() --regexp : displays details in multi-line format if necessary' { + run printf 'a 0\na 1' + run refute_output --regexp '.*a.*' + + assert_test_fail <<'ERR_MSG' + +-- regular expression should not match output -- +regexp (1 lines): + .*a.* +output (2 lines): + a 0 + a 1 +-- +ERR_MSG +} + +# Error handling +@test 'refute_output() --regexp : returns 1 and displays an error message if is not a valid extended regular expression' { + run refute_output --regexp '[.*' + + assert_test_fail <<'ERR_MSG' + +-- ERROR: refute_output -- +Invalid extended regular expression: `[.*' +-- +ERR_MSG +} + + +# +# Common +# + +@test "refute_output(): \`--partial' and \`--regexp' are mutually exclusive" { + run refute_output --partial --regexp + + assert_test_fail <<'ERR_MSG' + +-- ERROR: refute_output -- +`--partial' and `--regexp' are mutually exclusive +-- +ERR_MSG +} + +@test "refute_output(): \`--' stops parsing options" { + run echo '--' + run refute_output -- '-p' + assert_test_pass +} diff --git a/tooling/bats-assert/test/refute_regex.bats b/tooling/bats-assert/test/refute_regex.bats new file mode 100644 index 00000000000000..c1fd1b2344c09d --- /dev/null +++ b/tooling/bats-assert/test/refute_regex.bats @@ -0,0 +1,98 @@ +#!/usr/bin/env bats + +load test_helper + +# +# Literal matching +# + +# Correctness +@test "refute_regex() : fails if a substring matches extended regular expression " { + run refute_regex 'abc' '^[a-z]b' + assert_test_fail <<'ERR_MSG' + +-- value matches regular expression -- +value : abc +pattern : ^[a-z]b +match : ab +case : sensitive +-- +ERR_MSG +} + +@test "refute_regex() : succeeds if no substring matches extended regular expression " { + run refute_regex 'bcd' '^[a-z]b[c-z]+' + assert_test_pass +} + +@test "refute_regex() : provides results in BASH_REMATCH on failure" { + unset -v BASH_REMATCH + + refute_regex 'abcd' 'b.d' \ + || { + declare -p BASH_REMATCH && \ + [ "${BASH_REMATCH[0]}" = 'bcd' ] + } +} + +@test "refute_regex() : matches case-insensitively when 'nocasematch' is set" { + shopt -s nocasematch + + run refute_regex 'aBc' 'ABC' + assert_test_fail <<'ERR_MSG' + +-- value matches regular expression -- +value : aBc +pattern : ABC +match : aBc +case : insensitive +-- +ERR_MSG +} + +@test "refute_regex() : outputs multi-line nicely when it fails" { + run refute_regex $'abc\n123' '^[a-z]b[c-z]+' + assert_test_fail <<'ERR_MSG' + +-- value matches regular expression -- +value (2 lines): + abc + 123 +pattern (1 lines): + ^[a-z]b[c-z]+ +match (1 lines): + abc +case (1 lines): + sensitive +-- +ERR_MSG + + shopt -s nocasematch + run refute_regex $'aBc\n123' '^[a-z]b[c-z]+' + assert_test_fail <<'ERR_MSG' + +-- value matches regular expression -- +value (2 lines): + aBc + 123 +pattern (1 lines): + ^[a-z]b[c-z]+ +match (1 lines): + aBc +case (1 lines): + insensitive +-- +ERR_MSG +} + +# Error handling +@test "refute_regex() : returns 1 and displays an error message if is not a valid extended regular expression" { + run refute_regex value '[.*' + + assert_test_fail <<'ERR_MSG' + +-- ERROR: refute_regex -- +Invalid extended regular expression: `[.*' +-- +ERR_MSG +} diff --git a/tooling/bats-assert/test/refute_stderr.bats b/tooling/bats-assert/test/refute_stderr.bats new file mode 100755 index 00000000000000..6f8dfc509e32bf --- /dev/null +++ b/tooling/bats-assert/test/refute_stderr.bats @@ -0,0 +1,242 @@ +#!/usr/bin/env bats + +load test_helper + +setup_file() { + bats_require_minimum_version 1.5.0 +} + +echo_err() { + echo "$@" >&2 +} + +printf_err() { + # shellcheck disable=2059 + printf "$@" >&2 +} + +# +# Literal matching +# + +# Correctness +@test "refute_stderr() : returns 0 if does not equal \`\$stderr'" { + run --separate-stderr echo_err 'b' + run refute_stderr 'a' + assert_test_pass +} + +@test "refute_stderr() : returns 1 and displays details if equals \`\$stderr'" { + run --separate-stderr echo_err 'a' + run refute_stderr 'a' + + assert_test_fail <<'ERR_MSG' + +-- stderr equals, but it was expected to differ -- +stderr : a +-- +ERR_MSG +} + +@test 'refute_stderr(): succeeds if stderr is empty' { + run --separate-stderr echo_err '' + run refute_stderr + + assert_test_pass +} + +@test 'refute_stderr(): fails if stderr is non-empty' { + run --separate-stderr echo_err 'a' + run refute_stderr + + assert_test_fail <<'ERR_MSG' + +-- stderr non-empty, but expected no stderr -- +stderr : a +-- +ERR_MSG +} + +@test 'refute_stderr() - : reads from STDIN' { + run --separate-stderr echo_err '-' + run refute_stderr - < from STDIN' { + run --separate-stderr echo_err '--stdin' + run refute_stderr --stdin <: displays details in multi-line format if necessary' { + run --separate-stderr printf_err 'a 0\na 1' + run refute_stderr $'a 0\na 1' + + assert_test_fail <<'ERR_MSG' + +-- stderr equals, but it was expected to differ -- +stderr (2 lines): + a 0 + a 1 +-- +ERR_MSG +} + +# Options +@test 'refute_stderr() : performs literal matching by default' { + run --separate-stderr echo_err 'a' + run refute_stderr '*' + assert_test_pass +} + + +# +# Partial matching: `-p' and `--partial' +# + +# Options +@test 'refute_stderr() -p : enables partial matching' { + run --separate-stderr echo_err 'abc' + run refute_stderr -p 'd' + assert_test_pass +} + +@test 'refute_stderr() --partial : enables partial matching' { + run --separate-stderr echo_err 'abc' + run refute_stderr --partial 'd' + assert_test_pass +} + +# Correctness +@test "refute_stderr() --partial : returns 0 if is not a substring in \`\$stderr'" { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr --partial 'd' + assert_test_pass +} + +@test "refute_stderr() --partial : returns 1 and displays details if is a substring in \`\$stderr'" { + run --separate-stderr echo_err 'a' + run refute_stderr --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- stderr should not contain substring -- +substring : a +stderr : a +-- +ERR_MSG +} + +# Output formatting +@test 'refute_stderr() --partial : displays details in multi-line format if necessary' { + run --separate-stderr printf_err 'a 0\na 1' + run refute_stderr --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- stderr should not contain substring -- +substring (1 lines): + a +stderr (2 lines): + a 0 + a 1 +-- +ERR_MSG +} + + +# +# Regular expression matching: `-e' and `--regexp' +# + +# Options +@test 'refute_stderr() -e : enables regular expression matching' { + run --separate-stderr echo_err 'abc^d' + run refute_stderr -e '^d' + assert_test_pass +} + +@test 'refute_stderr() --regexp : enables regular expression matching' { + run --separate-stderr echo_err 'abc' + run refute_stderr --regexp '^d' + assert_test_pass +} + +# Correctness +@test "refute_stderr() --regexp : returns 0 if does not match \`\$stderr'" { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr --regexp '.*d.*' + assert_test_pass +} + +@test "refute_stderr() --regexp : returns 1 and displays details if matches \`\$stderr'" { + run --separate-stderr echo_err 'a' + run refute_stderr --regexp '.*a.*' + + assert_test_fail <<'ERR_MSG' + +-- regular expression should not match stderr -- +regexp : .*a.* +stderr : a +-- +ERR_MSG +} + +# Output formatting +@test 'refute_stderr() --regexp : displays details in multi-line format if necessary' { + run --separate-stderr printf_err 'a 0\na 1' + run refute_stderr --regexp '.*a.*' + + assert_test_fail <<'ERR_MSG' + +-- regular expression should not match stderr -- +regexp (1 lines): + .*a.* +stderr (2 lines): + a 0 + a 1 +-- +ERR_MSG +} + +# Error handling +@test 'refute_stderr() --regexp : returns 1 and displays an error message if is not a valid extended regular expression' { + run refute_stderr --regexp '[.*' + + assert_test_fail <<'ERR_MSG' + +-- ERROR: refute_stderr -- +Invalid extended regular expression: `[.*' +-- +ERR_MSG +} + + +# +# Common +# + +@test "refute_stderr(): \`--partial' and \`--regexp' are mutually exclusive" { + run refute_stderr --partial --regexp + + assert_test_fail <<'ERR_MSG' + +-- ERROR: refute_stderr -- +`--partial' and `--regexp' are mutually exclusive +-- +ERR_MSG +} + +@test "refute_stderr(): \`--' stops parsing options" { + run --separate-stderr echo_err '--' + run refute_stderr -- '-p' + assert_test_pass +} diff --git a/tooling/bats-assert/test/refute_stderr_line.bats b/tooling/bats-assert/test/refute_stderr_line.bats new file mode 100755 index 00000000000000..ecb210b4590fc1 --- /dev/null +++ b/tooling/bats-assert/test/refute_stderr_line.bats @@ -0,0 +1,356 @@ +#!/usr/bin/env bats + +load test_helper + +setup_file() { + bats_require_minimum_version 1.5.0 +} + +echo_err() { + echo "$@" >&2 +} + +printf_err() { + # shellcheck disable=2059 + printf "$@" >&2 +} + +############################################################################### +# Containing a line +############################################################################### + +# +# Literal matching +# + +# Correctness +@test "refute_stderr_line() : returns 0 if is not a line in \`\${stderr_lines[@]}'" { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line 'd' + assert_test_pass +} + +@test "refute_stderr_line() : returns 1 and displays details if is not a line in \`\${stderr_lines[@]}'" { + run --separate-stderr echo_err 'a' + run refute_stderr_line 'a' + + assert_test_fail <<'ERR_MSG' + +-- line should not be in stderr -- +line : a +index : 0 +stderr : a +-- +ERR_MSG +} + +# Output formatting +@test "refute_stderr_line() : displays \`\$stderr' in multi-line format if it is longer than one line" { + run --separate-stderr printf_err 'a 0\na 1\na 2' + run refute_stderr_line 'a 1' + + assert_test_fail <<'ERR_MSG' + +-- line should not be in stderr -- +line : a 1 +index : 1 +stderr (3 lines): + a 0 +> a 1 + a 2 +-- +ERR_MSG +} + +# Options +@test 'refute_stderr_line() : performs literal matching by default' { + run --separate-stderr echo_err 'a' + run refute_stderr_line '*' + assert_test_pass +} + + +# +# Partial matching: `-p' and `--partial' +# + +# Options +@test 'refute_stderr_line() -p : enables partial matching' { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line -p 'd' + assert_test_pass +} + +@test 'refute_stderr_line() --partial : enables partial matching' { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line --partial 'd' + assert_test_pass +} + +# Correctness +@test "refute_stderr_line() --partial : returns 0 if is not a substring in any line in \`\${stderr_lines[@]}'" { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line --partial 'd' + assert_test_pass +} + +@test "refute_stderr_line() --partial : returns 1 and displays details if is a substring in any line in \`\${stderr_lines[@]}'" { + run --separate-stderr echo_err 'a' + run refute_stderr_line --partial 'a' + + assert_test_fail <<'ERR_MSG' + +-- no line should contain substring -- +substring : a +index : 0 +stderr : a +-- +ERR_MSG +} + +# Output formatting +@test "refute_stderr_line() --partial : displays \`\$stderr' in multi-line format if it is longer than one line" { + run --separate-stderr printf_err 'a\nabc\nc' + run refute_stderr_line --partial 'b' + + assert_test_fail <<'ERR_MSG' + +-- no line should contain substring -- +substring : b +index : 1 +stderr (3 lines): + a +> abc + c +-- +ERR_MSG +} + + +# +# Regular expression matching: `-e' and `--regexp' +# + +# Options +@test 'refute_stderr_line() -e : enables regular expression matching' { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line -e '^.d' + assert_test_pass +} + +@test 'refute_stderr_line() --regexp : enables regular expression matching' { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line --regexp '^.d' + assert_test_pass +} + +# Correctness +@test "refute_stderr_line() --regexp : returns 0 if does not match any line in \`\${stderr_lines[@]}'" { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line --regexp '.*d.*' + assert_test_pass +} + +@test "refute_stderr_line() --regexp : returns 1 and displays details if matches any lines in \`\${stderr_lines[@]}'" { + run --separate-stderr echo_err 'a' + run refute_stderr_line --regexp '.*a.*' + + assert_test_fail <<'ERR_MSG' + +-- no line should match the regular expression -- +regexp : .*a.* +index : 0 +stderr : a +-- +ERR_MSG +} + +# Output formatting +@test "refute_stderr_line() --regexp : displays \`\$stderr' in multi-line format if longer than one line" { + run --separate-stderr printf_err 'a\nabc\nc' + run refute_stderr_line --regexp '.*b.*' + + assert_test_fail <<'ERR_MSG' + +-- no line should match the regular expression -- +regexp : .*b.* +index : 1 +stderr (3 lines): + a +> abc + c +-- +ERR_MSG +} + + +############################################################################### +# Matching single line: `-n' and `--index' +############################################################################### + +# Options +@test 'refute_stderr_line() -n : matches against the -th line only' { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line -n 1 'd' + assert_test_pass +} + +@test 'refute_stderr_line() --index : matches against the -th line only' { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line --index 1 'd' + assert_test_pass +} + +@test 'refute_stderr_line() --index : returns 1 and displays an error message if is not an integer' { + run refute_stderr_line --index 1a + + assert_test_fail <<'ERR_MSG' + +-- ERROR: refute_stderr_line -- +`--index' requires an integer argument: `1a' +-- +ERR_MSG +} + + +# +# Literal matching +# + +# Correctness +@test "refute_stderr_line() --index : returns 0 if does not equal \`\${stderr_lines[]}'" { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line --index 1 'd' + assert_test_pass +} + +@test "refute_stderr_line() --index : returns 1 and displays details if equals \`\${stderr_lines[]}'" { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line --index 1 'b' + + assert_test_fail <<'ERR_MSG' + +-- line should differ -- +index : 1 +line : b +-- +ERR_MSG +} + +# Options +@test 'refute_stderr_line() --index : performs literal matching by default' { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line --index 1 '*' + assert_test_pass +} + + +# +# Partial matching: `-p' and `--partial' +# + +# Options +@test 'refute_stderr_line() --index -p : enables partial matching' { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line --index 1 -p 'd' + assert_test_pass +} + +@test 'refute_stderr_line() --index --partial : enables partial matching' { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line --index 1 --partial 'd' + assert_test_pass +} + +# Correctness +@test "refute_stderr_line() --index --partial : returns 0 if is not a substring in \`\${stderr_lines[]}'" { + run --separate-stderr printf_err 'a\nabc\nc' + run refute_stderr_line --index 1 --partial 'd' + assert_test_pass +} + +@test "refute_stderr_line() --index --partial : returns 1 and displays details if is a substring in \`\${stderr_lines[]}'" { + run --separate-stderr printf_err 'a\nabc\nc' + run refute_stderr_line --index 1 --partial 'b' + + assert_test_fail <<'ERR_MSG' + +-- line should not contain substring -- +index : 1 +substring : b +line : abc +-- +ERR_MSG +} + + +# +# Regular expression matching: `-e' and `--regexp' +# + +# Options +@test 'refute_stderr_line() --index -e : enables regular expression matching' { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line --index 1 -e '[^.b]' + assert_test_pass +} + +@test 'refute_stderr_line() --index --regexp : enables regular expression matching' { + run --separate-stderr printf_err 'a\nb\nc' + run refute_stderr_line --index 1 --regexp '^.b' + assert_test_pass +} + +# Correctness +@test "refute_stderr_line() --index --regexp : returns 0 if does not match \`\${stderr_lines[]}'" { + run --separate-stderr printf_err 'a\nabc\nc' + run refute_stderr_line --index 1 --regexp '.*d.*' + assert_test_pass +} + +@test "refute_stderr_line() --index --regexp : returns 1 and displays details if matches \`\${stderr_lines[]}'" { + run --separate-stderr printf_err 'a\nabc\nc' + run refute_stderr_line --index 1 --regexp '.*b.*' + + assert_test_fail <<'ERR_MSG' + +-- regular expression should not match line -- +index : 1 +regexp : .*b.* +line : abc +-- +ERR_MSG +} + + +############################################################################### +# Common +############################################################################### + +@test "refute_stderr_line(): \`--partial' and \`--regexp' are mutually exclusive" { + run refute_stderr_line --partial --regexp + + assert_test_fail <<'ERR_MSG' + +-- ERROR: refute_stderr_line -- +`--partial' and `--regexp' are mutually exclusive +-- +ERR_MSG +} + +@test 'refute_stderr_line() --regexp : returns 1 and displays an error message if is not a valid extended regular expression' { + run refute_stderr_line --regexp '[.*' + + assert_test_fail <<'ERR_MSG' + +-- ERROR: refute_stderr_line -- +Invalid extended regular expression: `[.*' +-- +ERR_MSG +} + +@test "refute_stderr_line(): \`--' stops parsing options" { + run --separate-stderr printf_err 'a\n--\nc' + run refute_stderr_line -- '-p' + assert_test_pass +} diff --git a/tooling/bats-assert/test/test_helper.bash b/tooling/bats-assert/test/test_helper.bash new file mode 100644 index 00000000000000..af1ee0a0d289c5 --- /dev/null +++ b/tooling/bats-assert/test/test_helper.bash @@ -0,0 +1,30 @@ +# Load dependencies. +BATS_LIB_PATH=$PWD/node_modules:${BATS_LIB_PATH-} +bats_load_library 'bats-support' + +# Load library. +load '../load' + +# validate that bats-assert is safe to use under -u +set -u + +: "${status:=}" +: "${lines:=}" +: "${output:=}" +: "${stderr:=}" +: "${stderr_lines:=}" + +assert_test_pass() { + test "$status" -eq 0 + test "${#lines[@]}" -eq 0 +} + +assert_test_fail() { + local err_msg="${1-$(cat -)}" + local num_lines + num_lines="$(printf '%s' "$err_msg" | wc -l)" + + test "$status" -eq 1 + test "${#lines[@]}" -eq "$num_lines" + test "$output" == "$err_msg" +} diff --git a/tooling/bats-core b/tooling/bats-core deleted file mode 160000 index 855844b8344e67..00000000000000 --- a/tooling/bats-core +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 855844b8344e67d60dc0f43fa39817ed7787f141 diff --git a/tooling/bats-core/.codespellrc b/tooling/bats-core/.codespellrc new file mode 100644 index 00000000000000..3564ae723f3102 --- /dev/null +++ b/tooling/bats-core/.codespellrc @@ -0,0 +1,3 @@ +[codespell] +skip = .git,*.pdf,*.svg +ignore-words-list = dne diff --git a/tooling/bats-core/.devcontainer/Dockerfile b/tooling/bats-core/.devcontainer/Dockerfile new file mode 100644 index 00000000000000..2deb1d19dbf024 --- /dev/null +++ b/tooling/bats-core/.devcontainer/Dockerfile @@ -0,0 +1,17 @@ +ARG bashver=latest + +FROM bash:${bashver} + +# Install parallel and accept the citation notice (we aren't using this in a +# context where it make sense to cite GNU Parallel). +RUN echo "@edgecomm http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories && \ + apk update && \ + apk add --no-cache parallel ncurses shellcheck@edgecomm && \ + mkdir -p ~/.parallel && touch ~/.parallel/will-cite && \ + curl -sSfL https://github.com/shenwei356/rush/releases/download/v0.5.0/rush_linux_amd64.tar.gz | tar xzf - -C /usr/local/bin && \ + chmod +x /usr/local/bin/rush + +RUN ln -s /opt/bats/bin/bats /usr/sbin/bats +COPY . /opt/bats/ + +ENTRYPOINT ["bash", "/usr/sbin/bats"] diff --git a/tooling/bats-core/.devcontainer/devcontainer.json b/tooling/bats-core/.devcontainer/devcontainer.json new file mode 100644 index 00000000000000..2b81e3f202bd99 --- /dev/null +++ b/tooling/bats-core/.devcontainer/devcontainer.json @@ -0,0 +1,5 @@ +{ + "name": "Bats core development environment", + "dockerFile": "Dockerfile", + "build": {"args": {"bashver": "4.3"}} +} \ No newline at end of file diff --git a/tooling/bats-core/.editorconfig b/tooling/bats-core/.editorconfig new file mode 100644 index 00000000000000..457107ead58cfe --- /dev/null +++ b/tooling/bats-core/.editorconfig @@ -0,0 +1,35 @@ +root = true + +[*] +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +max_line_length = 80 +trim_trailing_whitespace = true + +# The JSON files contain newlines inconsistently +[*.json] +indent_size = 2 +insert_final_newline = ignore + +# YAML +[*.{yml,yaml}] +indent_style = space +indent_size = 2 + +# Makefiles always use tabs for recipe indentation +[{Makefile,*.mak}] +indent_style = tab + +# Markdown +[*.{md,rmd,mkd,mkdn,mdwn,mdown,markdown,litcoffee}] +max_line_length = 80 +# tabs behave as if they were replaced by spaces with a tab stop of 4 characters +tab_width = 4 +# trailing spaces indicates word wrap +trim_trailing_spaces = false +trim_trailing_whitespace = false + +[test/fixtures/bats/*_no_shellcheck.bats] +ignore = true \ No newline at end of file diff --git a/tooling/bats-core/.gitattributes b/tooling/bats-core/.gitattributes new file mode 100755 index 00000000000000..20cad1f8be4809 --- /dev/null +++ b/tooling/bats-core/.gitattributes @@ -0,0 +1,3 @@ +* text=auto +*.sh eol=lf +libexec/* eol=lf diff --git a/tooling/bats-core/.github/ISSUE_TEMPLATE/bug_report.md b/tooling/bats-core/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000000000..fbf9cba00e0b1c --- /dev/null +++ b/tooling/bats-core/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,30 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: 'Priority: NeedsTriage, Type: Bug' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +1. Create example `file.bats` with following contents +2. run `bats --foo file.bats` +3. ... + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Environment (please complete the following information):** + - Bats version [e.g. 1.4.0 or commit hash if applicable] + - operating system (including version): [e.g. Linux (please name your distribution!), FreeBSD, MacOS] + - `bash --version`: [e.g. 5.1] + - Install method: [e.g. git submodule, distribution package manager, npm, homebrew, ...] + +**Additional context** +Add any other context about the problem here. diff --git a/tooling/bats-core/.github/ISSUE_TEMPLATE/feature_request.md b/tooling/bats-core/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000000000..506b98beb232ca --- /dev/null +++ b/tooling/bats-core/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: 'Priority: NeedsTriage, Type: Enhancement' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context about the feature request here. diff --git a/tooling/bats-core/.github/dependabot.yml b/tooling/bats-core/.github/dependabot.yml new file mode 100644 index 00000000000000..15feb350c63d66 --- /dev/null +++ b/tooling/bats-core/.github/dependabot.yml @@ -0,0 +1,47 @@ +version: 2 +updates: + - package-ecosystem: docker + directory: /.devcontainer + schedule: + interval: daily + labels: + - docker + - devcontainer + - dependencies + - no changelog + + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + labels: + - github-actions + - dependencies + - no changelog + + - package-ecosystem: docker + directory: / + schedule: + interval: daily + labels: + - docker + - dependencies + - no changelog + + - package-ecosystem: pip + directory: /docs/source + schedule: + interval: daily + labels: + - pip + - dependencies + - no changelog + + - package-ecosystem: npm + directory: / + schedule: + interval: daily + labels: + - npm + - dependencies + - no changelog diff --git a/tooling/bats-core/.github/workflows/check_pr_label.sh b/tooling/bats-core/.github/workflows/check_pr_label.sh new file mode 100755 index 00000000000000..2ff5723c7143f9 --- /dev/null +++ b/tooling/bats-core/.github/workflows/check_pr_label.sh @@ -0,0 +1,10 @@ +#!/usr/bin/bash + +get_pr_json() { + curl -s -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/bats-core/bats-core/pulls/$1" +} + +PR_NUMBER="$1" +LABEL="$2" + +get_pr_json "$PR_NUMBER" | jq .labels[].name | grep "$LABEL" diff --git a/tooling/bats-core/.github/workflows/codespell.yml b/tooling/bats-core/.github/workflows/codespell.yml new file mode 100644 index 00000000000000..0a5145dba42cab --- /dev/null +++ b/tooling/bats-core/.github/workflows/codespell.yml @@ -0,0 +1,22 @@ +--- +name: Codespell + +on: + push: + branches: [master] + pull_request: + branches: [master] + +permissions: + contents: read + +jobs: + codespell: + name: Check for spelling errors + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Codespell + uses: codespell-project/actions-codespell@406322ec52dd7b488e48c1c4b82e2a8b3a1bf630 # v2.1 diff --git a/tooling/bats-core/.github/workflows/dependency-review.yml b/tooling/bats-core/.github/workflows/dependency-review.yml new file mode 100644 index 00000000000000..e77de81ee6ad0d --- /dev/null +++ b/tooling/bats-core/.github/workflows/dependency-review.yml @@ -0,0 +1,22 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, +# surfacing known-vulnerable versions of the packages declared or updated in the PR. +# Once installed, if the workflow run is marked as required, +# PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: 'Dependency Review' + uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0 diff --git a/tooling/bats-core/.github/workflows/release.yml b/tooling/bats-core/.github/workflows/release.yml new file mode 100644 index 00000000000000..53aed02d1715e1 --- /dev/null +++ b/tooling/bats-core/.github/workflows/release.yml @@ -0,0 +1,35 @@ +name: Release + +on: + release: { types: [published] } + workflow_dispatch: + +permissions: + contents: read + +jobs: + npmjs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + registry-url: "https://registry.npmjs.org" + - run: npm publish --ignore-scripts + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + github-npm: + runs-on: ubuntu-latest + permissions: + packages: write + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + registry-url: "https://npm.pkg.github.com" + - name: scope package name as required by GitHub Packages + run: npm init -y --scope ${{ github.repository_owner }} + - run: npm publish --ignore-scripts + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/tooling/bats-core/.github/workflows/release_dockerhub.yml b/tooling/bats-core/.github/workflows/release_dockerhub.yml new file mode 100644 index 00000000000000..b088652e21423b --- /dev/null +++ b/tooling/bats-core/.github/workflows/release_dockerhub.yml @@ -0,0 +1,54 @@ +name: Release to docker hub + +on: + release: { types: [published] } + workflow_dispatch: + +permissions: + contents: read + +jobs: + dockerhub: + runs-on: ubuntu-latest + permissions: + packages: write + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - id: version + run: | + TAG_VERSION=${GITHUB_REF#refs/tags/v} # refs/tags/v1.2.3 -> 1.2.3 + echo ::set-output name=version::$TAG_VERSION + - name: Set up QEMU + uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 + + + - name: Login to DockerHub + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Log in to the GitHub Container registry + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 + + - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + with: + platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6 + tags: ${{ secrets.DOCKER_USERNAME }}/bats:${{ steps.version.outputs.version }},${{ secrets.DOCKER_USERNAME }}/bats:latest + push: true + + - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + with: + platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6 + tags: ${{ secrets.DOCKER_USERNAME }}/bats:${{ steps.version.outputs.version }}-no-faccessat2,${{ secrets.DOCKER_USERNAME }}/bats:latest-no-faccessat2 + push: true + build-args: bashver=5.1.4 diff --git a/tooling/bats-core/.github/workflows/scorecard.yml b/tooling/bats-core/.github/workflows/scorecard.yml new file mode 100644 index 00000000000000..0687516be50f5a --- /dev/null +++ b/tooling/bats-core/.github/workflows/scorecard.yml @@ -0,0 +1,72 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '44 10 * * 6' + push: + branches: [ "master" ] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + # Uncomment the permissions below if installing in a private repository. + # contents: read + # actions: read + + steps: + - name: "Checkout code" + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecard on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10 + with: + sarif_file: results.sarif diff --git a/tooling/bats-core/.github/workflows/set_nounset.bash b/tooling/bats-core/.github/workflows/set_nounset.bash new file mode 100644 index 00000000000000..a7d874069233e0 --- /dev/null +++ b/tooling/bats-core/.github/workflows/set_nounset.bash @@ -0,0 +1 @@ +set -uo noclobber diff --git a/tooling/bats-core/.github/workflows/tests.yml b/tooling/bats-core/.github/workflows/tests.yml new file mode 100644 index 00000000000000..e2b27985713a41 --- /dev/null +++ b/tooling/bats-core/.github/workflows/tests.yml @@ -0,0 +1,361 @@ +name: Tests + +# Controls when the action will run. +on: [push, pull_request, workflow_dispatch] + +permissions: + contents: read + +jobs: + changelog: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Check that PR is mentioned in Changelog + run: | + if ! ./.github/workflows/check_pr_label.sh "${{github.event.pull_request.number}}" "no changelog"; then + grep "#${{github.event.pull_request.number}}" docs/CHANGELOG.md + fi + if: ${{github.event.pull_request}} + + shfmt: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - run: | + curl https://github.com/mvdan/sh/releases/download/v3.5.1/shfmt_v3.5.1_linux_amd64 -o shfmt + chmod a+x shfmt + - run: ./shfmt --diff . + + # Ensure we detect when a change disables Bats from reporting failure. + # This would not be detectable by Bats' selftests. + failsafe: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Check failing tests fail suite, + run: "! bin/bats test/fixtures/bats/failing.bats" + + shellcheck: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Run shellcheck + run: | + sudo apt-get update -y + sudo apt-get install shellcheck + ./shellcheck.sh + + linux: + strategy: + matrix: + os: ['ubuntu-22.04', 'ubuntu-24.04'] + env_vars: + - '' + # allow for some parallelity without GNU parallel, since it is not installed by default + - 'BATS_NO_PARALLELIZE_ACROSS_FILES=1 BATS_NUMBER_OF_PARALLEL_JOBS=2' + - 'BATS_PARALLEL_BINARY_NAME=rush' + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Install rush + run: | + curl -sSfL https://github.com/shenwei356/rush/releases/download/v0.5.0/rush_linux_amd64.tar.gz | sudo tar xzf - -C /usr/local/bin + if: contains(matrix.env_vars, 'rush') + - name: Run test on OS ${{ matrix.os }} + shell: 'script -q -e -c "bash {0}"' # work around tty issues + env: + TERM: linux # fix tput for tty issue work around + run: | + bash --version + bash -c "time ${{ matrix.env_vars }} bin/bats --print-output-on-failure --formatter tap test" + + unset_variables: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Check unset variables + shell: 'script -q -e -c "bash {0}"' # work around tty issues + env: + TERM: linux # fix tput for tty issue work around + BASH_ENV: ${GITHUB_WORKSPACE}/.github/workflows/set_nounset.bash + run: bin/bats test --print-output-on-failure + + npm_on_linux: + strategy: + matrix: + os: ['ubuntu-22.04', 'ubuntu-24.04'] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: v18.20.2 + - run: npm pack ./ + - run: npm install -g ./bats-*.tgz + - name: Run test on OS ${{ matrix.os }} + shell: 'script -q -e -c "bash {0}"' # work around tty issues + env: + TERM: linux # fix tput for tty issue work around + run: bats test --print-output-on-failure + + windows: + runs-on: windows-2019 + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Check failing tests fail suite, + run: bash -c "! bin/bats test/fixtures/bats/failing.bats" + - run: | + bash --version + bash -c "time bin/bats --print-output-on-failure --formatter tap test" + + npm_on_windows: + strategy: + matrix: + os: ['windows-2019'] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: v18.20.2 + - run: npm pack ./ + - run: npm install -g (get-item .\bats-*.tgz).FullName + - run: bats -T --print-output-on-failure test + + macos: + strategy: + matrix: + os: ['macos-13', 'macos-14', 'macos-15'] + env_vars: + - '' + # allow for some parallelity without GNU parallel, since it is not installed by default + - 'BATS_NO_PARALLELIZE_ACROSS_FILES=1 BATS_NUMBER_OF_PARALLEL_JOBS=2' + - 'BATS_PARALLEL_BINARY_NAME=rush' + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Install unbuffer via expect + run: brew install expect + - name: Install rush + run: | + curl -sSfL https://github.com/shenwei356/rush/releases/download/v0.5.0/rush_darwin_amd64.tar.gz | sudo tar xzf - -C /usr/local/bin + if: contains(matrix.env_vars, 'rush') + + - name: Check failing tests fail suite, + shell: 'unbuffer bash {0}' # work around tty issues + env: + TERM: linux # fix tput for tty issue work around + run: bash -c '! bin/bats test/fixtures/bats/failing.bats' + + - name: Run test on OS ${{ matrix.os }} + shell: 'unbuffer bash {0}' # work around tty issues + env: + TERM: linux # fix tput for tty issue work around + run: | + bash --version + bash -c "time ${{ matrix.env_vars }} bin/bats --print-output-on-failure --formatter tap test" + + npm_on_macos: + strategy: + matrix: + os: ['macos-13', 'macos-14', 'macos-15'] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: v18.20.2 + - name: Install unbuffer via expect + run: brew install expect + - name: Run test on OS ${{ matrix.os }} + shell: 'unbuffer bash {0}' # work around tty issues + env: + TERM: linux # fix tput for tty issue work around + run: | + npm pack ./ + # somehow there is already an installed bats version around + npm install --force -g ./bats-*.tgz + bats --print-output-on-failure test + + bash-version: + strategy: + matrix: + version: ['3.2', '4.0', '4.1', '4.2', '4.3', '4.4', '4', '5.0', '5.1', '5', 'rc'] + env_vars: + - '' + # also test running (recursively!) in parallel + - '-e BATS_NUMBER_OF_PARALLEL_JOBS=2' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Run test on bash version ${{ matrix.version }} + shell: 'script -q -e -c "bash {0}"' # work around tty issues + run: | + set -e + docker build --build-arg bashver="${{ matrix.version }}" --tag "bats/bats:bash-${{ matrix.version }}" . + docker run -it "bash:${{ matrix.version }}" --version + time docker run -it ${{ matrix.env_vars }} "bats/bats:bash-${{ matrix.version }}" --print-output-on-failure --tap /opt/bats/test + + lib64-install: + runs-on: ubuntu-latest + permissions: + checks: write + pull-requests: write + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Install in lib64 + run: sudo ./install.sh /usr/ lib64 + - name: Run from env + shell: 'script -q -e -c "bash {0}"' # work around tty issues + env: + TERM: linux # fix tput for tty issue work around + run: | + mkdir test-results/ + time bats test --print-output-on-failure --report-formatter junit --output test-results + - name: Publish Test Results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + files: | + test-results/**/*.xml + + alpine: + runs-on: ubuntu-latest + container: alpine:latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Install dependencies + run: apk add bash ncurses util-linux + - name: Run test on bash version ${{ matrix.version }} + shell: 'script -q -e -c "bash {0}"' # work around tty issues + env: + TERM: linux # fix tput for tty issue work around + run: + time ./bin/bats --print-output-on-failure test/ + + freebsd: + runs-on: ubuntu-latest + strategy: + matrix: + packages: + - flock + - "" + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: vmactions/freebsd-vm@848dac7e118679d08e2c2f9d42cd96608d834323 # v1.1.8 + with: + prepare: pkg install -y bash parallel ${{ matrix.packages }} + run: | + time ./bin/bats --print-output-on-failure test/ + + find_broken_symlinks: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + # list symlinks that are broken and force non-zero exit if there are any + - run: "! find . -xtype l | grep ." + + rpm: + runs-on: ubuntu-latest + container: almalinux:8 + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - run: dnf install -y rpm-build rpmdevtools + - name: Build and install RPM and dependencies + run: | + rpmdev-setuptree + version=$(rpmspec -q --qf '%{version}' contrib/rpm/bats.spec) + tar --transform "s,^,bats-core-${version}/," -cf /github/home/rpmbuild/SOURCES/v${version}.tar.gz ./ + rpmbuild -v -bb ./contrib/rpm/bats.spec + ls -al /github/home/rpmbuild/RPMS/noarch/ + dnf install -y /github/home/rpmbuild/RPMS/noarch/bats-*.rpm + dnf -y install procps-ng # avoid timeout failure + - name: Run tests + shell: 'script -q -e -c "bash {0}"' # work around tty issues + env: + TERM: linux # fix tput for tty issue work around + run: bats --print-output-on-failure --filter-tags !dep:install_sh test/ + + dockerfile: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 + + - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0 + with: + platforms: linux/amd64 + tags: bats:test + load: true + + - run: docker run -itv "$PWD":/code bats:test --tap --print-output-on-failure test/ + shell: 'script -q -e -c "bash {0}"' # work around tty issues + env: + TERM: linux # fix tput for tty issue work around + + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + repository: bats-core/bats-assert + path: bats-assert + + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + repository: bats-core/bats-support + path: bats-support + + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + repository: bats-core/bats-file + path: bats-file + + - run: | + <test.sh + apk add sudo python3 # install bats-file's dependencies + ln -sf python3 /usr/bin/python # bats-file uses python without version + bats --tap --print-output-on-failure bats-*/test/ + EOF + docker run -itv "$PWD":/code --entrypoint bash bats:test test.sh + shell: 'script -q -e -c "bash {0}"' # work around tty issues + env: + TERM: linux # fix tput for tty issue work around + + coverage: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - run: | + wget https://github.com/SimonKagstrom/kcov/releases/download/v42/kcov-amd64.tar.gz + tar -xf kcov-amd64.tar.gz + - run: | + ./usr/local/bin/kcov --exclude-path=/tmp $PWD/coverage ./bin/bats --filter-tags '!no-kcov' test/ + shell: 'script -q -e -c "bash {0}"' # work around tty issues + env: + TERM: linux # fix tput for tty issue work around + + - name: Archive code coverage results + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + with: + name: code-coverage-report + path: coverage/* + + - name: Print the Total Coverage + id: coverage-percent + shell: bash + env: + minimum_coverage: 86.40 + run: | + value=$(jq '.percent_covered' + int=${1%.*} + decimals=${1#*.} + echo $int${decimals::2} + } + echo "Coverage: $value%" | tee "$GITHUB_STEP_SUMMARY" + if (( $(fixed_point $value) < $(fixed_point $expected) )); then + echo " is below required minimum coverage ($minimum_coverage%)." | tee -a "$GITHUB_STEP_SUMMARY" + exit 1 + fi diff --git a/tooling/bats-core/.gitignore b/tooling/bats-core/.gitignore new file mode 100644 index 00000000000000..9895e9ffe92d9d --- /dev/null +++ b/tooling/bats-core/.gitignore @@ -0,0 +1,10 @@ +/docker-compose.override.yml +/docs/build + +# npm +/bats-*.tgz +# we don't have any deps; un-ignore if that changes +/package-lock.json +test/.bats/run-logs/ +# scratch file that should never be committed +/test.bats \ No newline at end of file diff --git a/tooling/bats-core/.pre-commit-config.yaml b/tooling/bats-core/.pre-commit-config.yaml new file mode 100644 index 00000000000000..d8562a434e2406 --- /dev/null +++ b/tooling/bats-core/.pre-commit-config.yaml @@ -0,0 +1,14 @@ +repos: +- repo: https://github.com/gitleaks/gitleaks + rev: v8.16.3 + hooks: + - id: gitleaks +- repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: 3.0.0 + hooks: + - id: shellcheck +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace diff --git a/tooling/bats-core/.readthedocs.yml b/tooling/bats-core/.readthedocs.yml new file mode 100644 index 00000000000000..e111967872d487 --- /dev/null +++ b/tooling/bats-core/.readthedocs.yml @@ -0,0 +1,13 @@ +version: 2 + +sphinx: + configuration: docs/source/conf.py + +build: + os: ubuntu-22.04 + tools: + python: "3.12" + +python: + install: + - requirements: docs/source/requirements.txt diff --git a/tooling/bats-core/AUTHORS b/tooling/bats-core/AUTHORS new file mode 100644 index 00000000000000..71df331b13af43 --- /dev/null +++ b/tooling/bats-core/AUTHORS @@ -0,0 +1,4 @@ +Andrew Martin (https://control-plane.io/) +Bianca Tamayo (https://biancatamayo.me/) +Jason Karns (http://jasonkarns.com/) +Mike Bland (https://mike-bland.com/) diff --git a/tooling/bats-core/Dockerfile b/tooling/bats-core/Dockerfile new file mode 100644 index 00000000000000..c220de074c27b1 --- /dev/null +++ b/tooling/bats-core/Dockerfile @@ -0,0 +1,45 @@ +ARG bashver=latest + +FROM bash:${bashver} +ARG TINI_VERSION=v0.19.0 +ARG TARGETPLATFORM +ARG LIBS_VER_SUPPORT=0.3.0 +ARG LIBS_VER_FILE=0.4.0 +ARG LIBS_VER_ASSERT=2.1.0 +ARG LIBS_VER_DETIK=1.3.2 +ARG UID=1001 +ARG GID=115 + + +# https://github.com/opencontainers/image-spec/blob/main/annotations.md +LABEL maintainer="Bats-core Team" +LABEL org.opencontainers.image.authors="Bats-core Team" +LABEL org.opencontainers.image.title="Bats" +LABEL org.opencontainers.image.description="Bash Automated Testing System" +LABEL org.opencontainers.image.url="https://hub.docker.com/r/bats/bats" +LABEL org.opencontainers.image.source="https://github.com/bats-core/bats-core" +LABEL org.opencontainers.image.base.name="docker.io/bash" + +COPY ./docker /tmp/docker +# default to amd64 when not running in buildx environment that provides target platform +RUN /tmp/docker/install_tini.sh "${TARGETPLATFORM-linux/amd64}" +# Install bats libs +RUN /tmp/docker/install_libs.sh support ${LIBS_VER_SUPPORT} +RUN /tmp/docker/install_libs.sh file ${LIBS_VER_FILE} +RUN /tmp/docker/install_libs.sh assert ${LIBS_VER_ASSERT} +RUN /tmp/docker/install_libs.sh detik ${LIBS_VER_DETIK} + +# Install parallel and accept the citation notice (we aren't using this in a +# context where it make sense to cite GNU Parallel). +RUN apk add --no-cache parallel ncurses && \ + mkdir -p ~/.parallel && touch ~/.parallel/will-cite \ + && mkdir /code + +RUN ln -s "$(/usr/bin/env which bash)" "/bin/bash" + +RUN ln -s /opt/bats/bin/bats /usr/local/bin/bats +COPY . /opt/bats/ + +WORKDIR /code/ + +ENTRYPOINT ["/tini", "--", "/usr/local/bin/bash", "/usr/local/bin/bats"] diff --git a/tooling/bats-core/LICENSE.md b/tooling/bats-core/LICENSE.md new file mode 100644 index 00000000000000..0c74299786eaf4 --- /dev/null +++ b/tooling/bats-core/LICENSE.md @@ -0,0 +1,53 @@ +Copyright (c) 2017 bats-core contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--- + +* [bats-core] is a continuation of [bats]. Copyright for portions of the + bats-core project are held by Sam Stephenson, 2014 as part of the project + [bats], licensed under MIT: + +Copyright (c) 2014 Sam Stephenson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +For details, please see the [version control history][commits]. + +[bats-core]: https://github.com/bats-core/bats-core +[bats]:https://github.com/sstephenson/bats +[commits]:https://github.com/bats-core/bats-core/commits/master diff --git a/tooling/bats-core/README.md b/tooling/bats-core/README.md new file mode 100644 index 00000000000000..4ccc248e54b955 --- /dev/null +++ b/tooling/bats-core/README.md @@ -0,0 +1,135 @@ +[![Latest release](https://img.shields.io/github/release/bats-core/bats-core.svg)](https://github.com/bats-core/bats-core/releases/latest) +[![npm package](https://img.shields.io/npm/v/bats.svg)](https://www.npmjs.com/package/bats) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/bats-core/bats-core/blob/master/LICENSE.md) +[![Continuous integration status](https://github.com/bats-core/bats-core/workflows/Tests/badge.svg)](https://github.com/bats-core/bats-core/actions?query=workflow%3ATests) +[![Read the docs status](https://readthedocs.org/projects/bats-core/badge/)](https://bats-core.readthedocs.io) + +[![Join the chat in bats-core/bats-core on gitter](https://badges.gitter.im/bats-core/bats-core.svg)][gitter] + +
+ + + + +
+ +# Bats-core: Bash Automated Testing System + +Bats is a [TAP](https://testanything.org/)-compliant testing framework for Bash +3.2 or above. It provides a simple way to verify that the UNIX programs you +write behave as expected. + +A Bats test file is a Bash script with special syntax for defining test cases. +Under the hood, each test case is just a function with a description. + +```bash +#!/usr/bin/env bats + +@test "addition using bc" { + result="$(echo 2+2 | bc)" + [ "$result" -eq 4 ] +} + +@test "addition using dc" { + result="$(echo 2 2+p | dc)" + [ "$result" -eq 4 ] +} +``` + +Bats is most useful when testing software written in Bash, but you can use it to +test any UNIX program. + +Test cases consist of standard shell commands. Bats makes use of Bash's +`errexit` (`set -e`) option when running test cases. If every command in the +test case exits with a `0` status code (success), the test passes. In this way, +each line is an assertion of truth. + +## Table of contents + +**NOTE** The documentation has moved to + + + +- [Testing](#testing) +- [Support](#support) +- [Contributing](#contributing) +- [Contact](#contact) +- [Version history](#version-history) +- [Background](#background) + * [What's the plan and why?](#whats-the-plan-and-why) + * [Why was this fork created?](#why-was-this-fork-created) +- [Copyright](#copyright) + + + +## Testing + +```sh +bin/bats --tap test +``` + +See also the [CI](./.github/workflows/tests.yml) settings for the current test environment and +scripts. + +## Support + +The Bats source code repository is [hosted on +GitHub](https://github.com/bats-core/bats-core). There you can file bugs on the +issue tracker or submit tested pull requests for review. + +For real-world examples from open-source projects using Bats, see [Projects +Using Bats](https://github.com/bats-core/bats-core/wiki/Projects-Using-Bats) on +the wiki. + +To learn how to set up your editor for Bats syntax highlighting, see [Syntax +Highlighting](https://github.com/bats-core/bats-core/wiki/Syntax-Highlighting) +on the wiki. + +## Contributing + +For now see the [`docs`](docs) folder for project guides, work with us on the wiki +or look at the other communication channels. + +## Contact + +- You can find and chat with us on our [Gitter]. + +## Version history + +See `docs/CHANGELOG.md`. + +## Background + + +### Why was this fork created? + + +There was an initial [call for maintainers][call-maintain] for the original Bats repository, but write access to it could not be obtained. With development activity stalled, this fork allowed ongoing maintenance and forward progress for Bats. + +**Tuesday, September 19, 2017:** This was forked from [Bats][bats-orig] at +commit [0360811][]. It was created via `git clone --bare` and `git push +--mirror`. + +As of **Thursday, April 29, 2021:** the original [Bats][bats-orig] has been +archived by the owner and is now read-only. + +This [bats-core](https://github.com/bats-core/bats-core) repo is now the community-maintained Bats project. + +[call-maintain]: https://github.com/sstephenson/bats/issues/150 +[bats-orig]: https://github.com/sstephenson/bats +[0360811]: https://github.com/sstephenson/bats/commit/03608115df2071fff4eaaff1605768c275e5f81f + +## Copyright + +The Bats Logo was created by [Vukory](https://www.artstation.com/vukory) ([Github](https://github.com/vukory)) and sponsored by [SethFalco](https://github.com/SethFalco). If you want to use our logo, have a look at our [guidelines](./docs/source/assets/README.md#Usage-Guide-for-Third-Parties). + +© 2017-2024 bats-core organization + +© 2011-2016 Sam Stephenson + +Bats is released under an MIT-style license; see `LICENSE.md` for details. + +See the [parent project](https://github.com/bats-core) at GitHub or the +[AUTHORS](AUTHORS) file for the current project maintainer team. + +[gitter]: https://gitter.im/bats-core/bats-core diff --git a/tooling/bats-core/SECURITY.md b/tooling/bats-core/SECURITY.md new file mode 100644 index 00000000000000..a71634442d18ac --- /dev/null +++ b/tooling/bats-core/SECURITY.md @@ -0,0 +1,9 @@ +# Security Policy + +## Supported Versions + +Only the greatest published version (according to semver) will be supported. + +## Reporting a Vulnerability + +Use GitHub's builtin reporting mechanism under https://github.com/bats-core/bats-core/security/advisories/new diff --git a/tooling/bats-core/bin/bats b/tooling/bats-core/bin/bats new file mode 100755 index 00000000000000..25ad051b514c1f --- /dev/null +++ b/tooling/bats-core/bin/bats @@ -0,0 +1,75 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Note: We first need to use POSIX's `[ ... ]' instead of Bash's `[[ ... ]]' +# because this is the check for Bash, where the shell may not be Bash. Once we +# confirm that we are in Bash, we can use [[ ... ]] and (( ... )). Note that +# these [[ ... ]] and (( ... )) do not cause syntax errors in POSIX shells, +# though they can be parsed differently. +if [ -z "${BASH_VERSION-}" ] || + [[ -z "${BASH_VERSINFO-}" ]] || + ((BASH_VERSINFO[0] < 3 || (BASH_VERSINFO[0] == 3 && BASH_VERSINFO[1] < 2))) +then + printf 'bats: this program needs to be run by Bash >= 3.2\n' >&2 + exit 1 +fi + +if command -v greadlink >/dev/null; then + bats_readlinkf() { + greadlink -f "$1" + } +else + bats_readlinkf() { + readlink -f "$1" + } +fi + +fallback_to_readlinkf_posix() { + bats_readlinkf() { + [ "${1:-}" ] || return 1 + max_symlinks=40 + CDPATH='' # to avoid changing to an unexpected directory + + target=$1 + [ -e "${target%/}" ] || target=${1%"${1##*[!/]}"} # trim trailing slashes + [ -d "${target:-/}" ] && target="$target/" + + cd -P . 2>/dev/null || return 1 + while [ "$max_symlinks" -ge 0 ] && max_symlinks=$((max_symlinks - 1)); do + if [ ! "$target" = "${target%/*}" ]; then + case $target in + /*) cd -P "${target%/*}/" 2>/dev/null || break ;; + *) cd -P "./${target%/*}" 2>/dev/null || break ;; + esac + target=${target##*/} + fi + + if [ ! -L "$target" ]; then + target="${PWD%/}${target:+/}${target}" + printf '%s\n' "${target:-/}" + return 0 + fi + + # `ls -dl` format: "%s %u %s %s %u %s %s -> %s\n", + # , , , , + # , , , + # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html + link=$(ls -dl -- "$target" 2>/dev/null) || break + target=${link#*" $target -> "} + done + return 1 + } +} + +if ! BATS_PATH=$(bats_readlinkf "${BASH_SOURCE[0]}" 2>/dev/null); then + fallback_to_readlinkf_posix + BATS_PATH=$(bats_readlinkf "${BASH_SOURCE[0]}") +fi + +export BATS_SAVED_PATH=$PATH +BATS_BASE_LIBDIR=lib # this will be patched with the true value in install.sh + +export BATS_ROOT=${BATS_PATH%/*/*} +export -f bats_readlinkf +exec env BATS_ROOT="$BATS_ROOT" BATS_LIBDIR="${BATS_BASE_LIBDIR:-lib}" "$BATS_ROOT/libexec/bats-core/bats" "$@" diff --git a/tooling/bats-core/contrib/release.sh b/tooling/bats-core/contrib/release.sh new file mode 100755 index 00000000000000..2e4805e1f00ad8 --- /dev/null +++ b/tooling/bats-core/contrib/release.sh @@ -0,0 +1,178 @@ +#!/usr/bin/env bash +# +# bats-core git releaser +# +## Usage: %SCRIPT_NAME% [options] +## +## Options: +## --major Major version bump +## --minor Minor version bump +## --patch Patch version bump +## +## -v, --version Print version +## --debug Enable debug mode +## -h, --help Display this message +## + +set -Eeuo pipefail + +DIR=$(cd "$(dirname "${0}")" && pwd) +THIS_SCRIPT="${DIR}/$(basename "${0}")" +BATS_VERSION=$( + # shellcheck disable=SC1090 + source <(grep '^export BATS_VERSION=' libexec/bats-core/bats) + echo "${BATS_VERSION}" +) +declare -r DIR +declare -r THIS_SCRIPT +declare -r BATS_VERSION + +BUMP_INTERVAL="" +NEW_BATS_VERSION="" + +main() { + handle_arguments "${@}" + + if [[ "${BUMP_INTERVAL:-}" == "" ]]; then + echo "${BATS_VERSION}" + exit 0 + fi + + local NEW_BATS_VERSION + NEW_BATS_VERSION=$(semver bump "${BUMP_INTERVAL}" "${BATS_VERSION}") + declare -r NEW_BATS_VERSION + + local BATS_RELEASE_NOTES="/tmp/bats-release-${NEW_BATS_VERSION}" + + echo "Releasing: ${BATS_VERSION} to ${NEW_BATS_VERSION}" + echo + + echo "Ensure docs/CHANGELOG.md is correctly updated" + + replace_in_files + + write_changelog + + git diff --staged + + cat </dev/null + +get_version() { + echo "${THIS_SCRIPT_VERSION:-0.1}" +} + +main "${@}" diff --git a/tooling/bats-core/contrib/rpm/bats.spec b/tooling/bats-core/contrib/rpm/bats.spec new file mode 100644 index 00000000000000..8a3a0dcec6f33c --- /dev/null +++ b/tooling/bats-core/contrib/rpm/bats.spec @@ -0,0 +1,66 @@ +%global provider github.com +%global project bats-core +%global repo bats-core + +Name: bats +Version: 1.12.0 +Release: 1%{?dist} +Summary: Bash Automated Testing System + +Group: Development/Libraries +License: MIT +URL: https://%{provider}/%{project}/%{repo} +Source0: https://%{provider}/%{project}/%{repo}/archive/v%{version}.tar.gz + +BuildArch: noarch + +Requires: bash + +%description +Bats is a TAP-compliant testing framework for Bash. +It provides a simple way to verify that the UNIX programs you write behave as expected. +Bats is most useful when testing software written in Bash, but you can use it to test any UNIX program. + +%prep +%setup -q -n %{repo}-%{version} + +%install +mkdir -p ${RPM_BUILD_ROOT}%{_prefix} ${RPM_BUILD_ROOT}%{_libexecdir} ${RPM_BUILD_ROOT}%{_mandir} +./install.sh ${RPM_BUILD_ROOT}%{_prefix} + +%clean +rm -rf $RPM_BUILD_ROOT + +%check + +%files +%doc README.md LICENSE.md +%{_bindir}/%{name} +%{_libexecdir}/%{repo} +%{_mandir}/man1/%{name}.1.gz +%{_mandir}/man7/%{name}.7.gz +/usr/lib/%{repo}/common.bash +/usr/lib/%{repo}/formatter.bash +/usr/lib/%{repo}/preprocessing.bash +/usr/lib/%{repo}/semaphore.bash +/usr/lib/%{repo}/test_functions.bash +/usr/lib/%{repo}/tracing.bash +/usr/lib/%{repo}/validator.bash +/usr/lib/%{repo}/warnings.bash + +%changelog +* Wed Sep 07 2022 Marcel Hecko - 1.2.0-1 +- Fix and test RPM build on Rocky Linux release 8.6 + +* Sun Jul 08 2018 mbland - 1.1.0-1 +- Increase version to match upstream release + +* Mon Jun 18 2018 pixdrift - 1.0.2-1 +- Increase version to match upstream release +- Relocate libraries to bats-core subdirectory + +* Sat Jun 09 2018 pixdrift - 1.0.1-1 +- Increase version to match upstream release + +* Fri Jun 08 2018 pixdrift - 1.0.0-1 +- Initial package build of forked (bats-core) github project diff --git a/tooling/bats-core/contrib/semver b/tooling/bats-core/contrib/semver new file mode 100755 index 00000000000000..ab75586cc6098e --- /dev/null +++ b/tooling/bats-core/contrib/semver @@ -0,0 +1,358 @@ +#!/usr/bin/env bash + +# v3.0.0 +# https://github.com/fsaintjacques/semver-tool + +set -o errexit -o nounset -o pipefail + +NAT='0|[1-9][0-9]*' +ALPHANUM='[0-9]*[A-Za-z-][0-9A-Za-z-]*' +IDENT="$NAT|$ALPHANUM" +FIELD='[0-9A-Za-z-]+' + +SEMVER_REGEX="\ +^[vV]?\ +($NAT)\\.($NAT)\\.($NAT)\ +(\\-(${IDENT})(\\.(${IDENT}))*)?\ +(\\+${FIELD}(\\.${FIELD})*)?$" + +PROG=semver +PROG_VERSION="3.0.0" + +USAGE="\ +Usage: + $PROG bump (major|minor|patch|release|prerel |build ) + $PROG compare + $PROG get (major|minor|patch|release|prerel|build) + $PROG --help + $PROG --version + +Arguments: + A version must match the following regular expression: + \"${SEMVER_REGEX}\" + In English: + -- The version must match X.Y.Z[-PRERELEASE][+BUILD] + where X, Y and Z are non-negative integers. + -- PRERELEASE is a dot separated sequence of non-negative integers and/or + identifiers composed of alphanumeric characters and hyphens (with + at least one non-digit). Numeric identifiers must not have leading + zeros. A hyphen (\"-\") introduces this optional part. + -- BUILD is a dot separated sequence of identifiers composed of alphanumeric + characters and hyphens. A plus (\"+\") introduces this optional part. + + See definition. + + A string as defined by PRERELEASE above. + + A string as defined by BUILD above. + +Options: + -v, --version Print the version of this tool. + -h, --help Print this help message. + +Commands: + bump Bump by one of major, minor, patch; zeroing or removing + subsequent parts. \"bump prerel\" sets the PRERELEASE part and + removes any BUILD part. \"bump build\" sets the BUILD part. + \"bump release\" removes any PRERELEASE or BUILD parts. + The bumped version is written to stdout. + + compare Compare with , output to stdout the + following values: -1 if is newer, 0 if equal, 1 if + older. The BUILD part is not used in comparisons. + + get Extract given part of , where part is one of major, minor, + patch, prerel, build, or release. + +See also: + https://semver.org -- Semantic Versioning 2.0.0" + +function error { + echo -e "$1" >&2 + exit 1 +} + +function usage-help { + error "$USAGE" +} + +function usage-version { + echo -e "${PROG}: $PROG_VERSION" + exit 0 +} + +function validate-version { + local version=$1 + if [[ "$version" =~ $SEMVER_REGEX ]]; then + # if a second argument is passed, store the result in var named by $2 + if [ "$#" -eq "2" ]; then + local major=${BASH_REMATCH[1]} + local minor=${BASH_REMATCH[2]} + local patch=${BASH_REMATCH[3]} + local prere=${BASH_REMATCH[4]} + local build=${BASH_REMATCH[8]} + eval "$2=(\"$major\" \"$minor\" \"$patch\" \"$prere\" \"$build\")" + else + echo "$version" + fi + else + error "version $version does not match the semver scheme 'X.Y.Z(-PRERELEASE)(+BUILD)'. See help for more information." + fi +} + +function is-nat { + [[ "$1" =~ ^($NAT)$ ]] +} + +function is-null { + [ -z "$1" ] +} + +function order-nat { + [ "$1" -lt "$2" ] && { + echo -1 + return + } + [ "$1" -gt "$2" ] && { + echo 1 + return + } + echo 0 +} + +function order-string { + [[ $1 < $2 ]] && { + echo -1 + return + } + [[ $1 > $2 ]] && { + echo 1 + return + } + echo 0 +} + +# given two (named) arrays containing NAT and/or ALPHANUM fields, compare them +# one by one according to semver 2.0.0 spec. Return -1, 0, 1 if left array ($1) +# is less-than, equal, or greater-than the right array ($2). The longer array +# is considered greater-than the shorter if the shorter is a prefix of the longer. +# +function compare-fields { + local l="$1[@]" + local r="$2[@]" + local leftfield=("${!l}") + local rightfield=("${!r}") + local left + local right + + local i=$((-1)) + local order=$((0)) + + while true; do + [ $order -ne 0 ] && { + echo $order + return + } + + : $((i++)) + left="${leftfield[$i]}" + right="${rightfield[$i]}" + + is-null "$left" && is-null "$right" && { + echo 0 + return + } + is-null "$left" && { + echo -1 + return + } + is-null "$right" && { + echo 1 + return + } + + is-nat "$left" && is-nat "$right" && { + order=$(order-nat "$left" "$right") + continue + } + is-nat "$left" && { + echo -1 + return + } + is-nat "$right" && { + echo 1 + return + } + { + order=$(order-string "$left" "$right") + continue + } + done +} + +# shellcheck disable=SC2206 # checked by "validate"; ok to expand prerel id's into array +function compare-version { + local order + validate-version "$1" V + validate-version "$2" V_ + + # compare major, minor, patch + + local left=("${V[0]}" "${V[1]}" "${V[2]}") + local right=("${V_[0]}" "${V_[1]}" "${V_[2]}") + + order=$(compare-fields left right) + [ "$order" -ne 0 ] && { + echo "$order" + return + } + + # compare pre-release ids when M.m.p are equal + + local prerel="${V[3]:1}" + local prerel_="${V_[3]:1}" + local left=(${prerel//./ }) + local right=(${prerel_//./ }) + + # if left and right have no pre-release part, then left equals right + # if only one of left/right has pre-release part, that one is less than simple M.m.p + + [ -z "$prerel" ] && [ -z "$prerel_" ] && { + echo 0 + return + } + [ -z "$prerel" ] && { + echo 1 + return + } + [ -z "$prerel_" ] && { + echo -1 + return + } + + # otherwise, compare the pre-release id's + + compare-fields left right +} + +function command-bump { + local new + local version + local sub_version + local command + + case $# in + 2) case $1 in + major | minor | patch | release) + command=$1 + version=$2 + ;; + *) usage-help ;; + esac ;; + 3) case $1 in + prerel | build) + command=$1 + sub_version=$2 version=$3 + ;; + *) usage-help ;; + esac ;; + *) usage-help ;; + esac + + validate-version "$version" parts + # shellcheck disable=SC2154 + local major="${parts[0]}" + local minor="${parts[1]}" + local patch="${parts[2]}" + local prere="${parts[3]}" + local build="${parts[4]}" + + case "$command" in + major) new="$((major + 1)).0.0" ;; + minor) new="${major}.$((minor + 1)).0" ;; + patch) new="${major}.${minor}.$((patch + 1))" ;; + release) new="${major}.${minor}.${patch}" ;; + prerel) new=$(validate-version "${major}.${minor}.${patch}-${sub_version}") ;; + build) new=$(validate-version "${major}.${minor}.${patch}${prere}+${sub_version}") ;; + *) usage-help ;; + esac + + echo "$new" + exit 0 +} + +function command-compare { + local v + local v_ + + case $# in + 2) + v=$(validate-version "$1") + v_=$(validate-version "$2") + ;; + *) usage-help ;; + esac + + set +u # need unset array element to evaluate to null + compare-version "$v" "$v_" + exit 0 +} + +# shellcheck disable=SC2034 +function command-get { + local part version + + if [[ "$#" -ne "2" ]] || [[ -z "$1" ]] || [[ -z "$2" ]]; then + usage-help + exit 0 + fi + + part="$1" + version="$2" + + validate-version "$version" parts + local major="${parts[0]}" + local minor="${parts[1]}" + local patch="${parts[2]}" + local prerel="${parts[3]:1}" + local build="${parts[4]:1}" + local release="${major}.${minor}.${patch}" + + case "$part" in + major | minor | patch | release | prerel | build) echo "${!part}" ;; + *) usage-help ;; + esac + + exit 0 +} + +case $# in +0) + echo "Unknown command: $*" + usage-help + ;; +esac + +case $1 in +--help | -h) + echo -e "$USAGE" + exit 0 + ;; +--version | -v) usage-version ;; +bump) + shift + command-bump "$@" + ;; +get) + shift + command-get "$@" + ;; +compare) + shift + command-compare "$@" + ;; +*) + echo "Unknown arguments: $*" + usage-help + ;; +esac diff --git a/tooling/bats-core/docker-compose.override.dist b/tooling/bats-core/docker-compose.override.dist new file mode 100644 index 00000000000000..7e34ba81aa84e0 --- /dev/null +++ b/tooling/bats-core/docker-compose.override.dist @@ -0,0 +1,7 @@ +# Copy this file to docker-compose.override.yml +services: + bats: + entrypoint: + - "bash" +networks: + default: diff --git a/tooling/bats-core/docker-compose.yml b/tooling/bats-core/docker-compose.yml new file mode 100644 index 00000000000000..af978ed477801b --- /dev/null +++ b/tooling/bats-core/docker-compose.yml @@ -0,0 +1,12 @@ +services: + bats: + build: + context: "." + dockerfile: "Dockerfile" + networks: + - "default" + user: "root" + volumes: + - "./:/opt/bats" +networks: + default: diff --git a/tooling/bats-core/docker/install_libs.sh b/tooling/bats-core/docker/install_libs.sh new file mode 100755 index 00000000000000..455865375d940a --- /dev/null +++ b/tooling/bats-core/docker/install_libs.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset + + +LIBNAME="${1:-support}" +LIVERSION="${2:-0.3.0}" +BASEURL='https://github.com/bats-core' +DESTDIR="${BATS_LIBS_DEST_DIR:-/usr/lib/bats}" +TMPDIR=$(mktemp -d -t bats-libs-XXXXXX) +USAGE="Please provide the bats libe name and version \nFor example: install_libs.sh support 2.0.0\n" + +trap 'test -d "${TMPDIR}" && rm -fr "${TMPDIR}"' EXIT ERR SIGINT SIGTERM + +[[ $# -ne 2 ]] && { _log FATAL "$USAGE"; exit 1; } + +_log() { + printf "$(date "+%Y-%m-%d %H:%M:%S") - %s - %s\n" "${1}" "${2}" +} + +create_temp_dirs() { + mkdir -p "${TMPDIR}/${1}" + if [[ ${LIBNAME} != "detik" ]]; then + mkdir -p "${DESTDIR}/bats-${1}/src" + else + _log INFO "Skipping src 'cause Detik does not need it" + fi +} + +download_extract_source() { + wget -qO- ${BASEURL}/bats-"${1}"/archive/refs/tags/v"${2}".tar.gz | tar xz -C "${TMPDIR}/${1}" --strip-components 1 +} + +install_files() { + if [[ ${LIBNAME} != "detik" ]]; then + install -Dm755 "${TMPDIR}/${1}/load.bash" "${DESTDIR}/bats-${1}/load.bash" + for fn in "${TMPDIR}/${1}/src/"*.bash; do install -Dm755 "$fn" "${DESTDIR}/bats-${1}/src/$(basename "$fn")"; done + else + for fn in "${TMPDIR}/${1}/lib/"*.bash; do install -Dm755 "$fn" "${DESTDIR}/bats-${1}/$(basename "$fn")"; done + fi +} + +_log INFO "Starting to install ${LIBNAME} ver ${LIVERSION}" +_log INFO "Creating directories" +create_temp_dirs "${LIBNAME}" +_log INFO "Downloading" +download_extract_source "${LIBNAME}" "${LIVERSION}" +_log INFO "Installation" +install_files "${LIBNAME}" +_log INFO "Done, cleaning.." diff --git a/tooling/bats-core/docker/install_tini.sh b/tooling/bats-core/docker/install_tini.sh new file mode 100755 index 00000000000000..8d98da14c6a0e9 --- /dev/null +++ b/tooling/bats-core/docker/install_tini.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +set -e + +case ${1#linux/} in +386) + TINI_PLATFORM=i386 + ;; +arm/v7) + TINI_PLATFORM=armhf + ;; +arm/v6) + TINI_PLATFORM=armel + ;; +*) + TINI_PLATFORM=${1#linux/} + ;; +esac + +echo "Installing tini for $TINI_PLATFORM" + +wget "https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static-${TINI_PLATFORM}" -O /tini +wget "https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static-${TINI_PLATFORM}.asc" -O /tini.asc + +chmod +x /tini + +apk add gnupg +gpg --import = 3.2 (#873) + +### Fixed + +* `install.sh` now works for deviating `lib/` dirs (like `lib32`,`lib64`) (#487) +* catch unset `BATS_TEST_SOURCE` in `lib/bats-core/tracing.bash` so + `set -u`/`set -o nounset` works as expected (#827) +* fix `--gather-test-outputs-in` fails on tests with multiple `/` (#789) +* install does not create unused `/usr/share/bats` anymore (#857) +* ensure IFS is unchanged in `{setup,teardown}{_suite,_file,}`, `@test` and free code (#879) +* junit formatter: remove ANSI Codes to avoid invalid XML character (#886) + +### Changed + +* update Docker image with the latest `bats-file` version 0.4.0 (#780) +* update Docker image with the latest `bats-detik` version 1.3.0 (#876) + +#### Documentation + +* clarify docker usage (#741) +* update Arch Linux package URL in installation.rst (#821) +* rename bash-bats to bats for Arch Linux in installation.rst (#836) +* fix FAQ entry about setup-/teardown_suite, as they are available now (#861) +* added logo (#881) + +## [1.10.0] - 2023-07-15 + +### Added + +* add `${BATS_TEST_TAGS[@]}` for querying the tags during a test (#705) +* print tags on failing tests (#705) +* test for negative arguments to `--jobs` (#693) +* add tests for `--formatter cat` (#710) +* test coverage in CI (#718) +* Support for [rush](https://github.com/shenwei356/rush) as alternative to GNU parallel (#729) +* add `bats_pipe` helper function for `run` that executes `\|` as pipes (#663) +* publish docker images to ghcr.io (additionally to Dockerhub) (#740) + +### Documentation + +* clarify use cases of `--formatter cat` (#710) + +### Fixed + +* fix `run` with options overwriting the value of `i` (#726, #727) +* fix `${BATS_TEST_NAMES[@]}` containing only `--tags` instead of test name since Bats v1.8.0 (#705) +* fix `run --keep-empty-lines` counting trailing `\n` as (empty) new line (#711) +* fix short flag unpacker creating bogus command lines with valued flags (#732) +* fix formatter becoming confused with retries (#734) +* fix `--gather-test-outputs-in` fails on tests with `/` (#735) +* fix overriding `date` breaks `--timing` (#736) + +#### Documentation + +* typos, minor edits (#704) +* simplified contributing.md (#718) + +## [1.9.0] - 2023-02-12 + +### Added + +* add installation instructions for Debian, Fedora, Gentoo, and OpenSUSE (#659) +* add `--line-reference-format` to switch file/line references in stack traces (#665) + * `comma_line` (default): `file.bats, line 1` + * `colon`: `file.bats:1` + * `uri`: `file:///path/to/file.bats:1` + * `custom`: define your own formatter in `bats_format_file_line_reference_custom` +* add `bats:focus` tag to run only focused tests (#679) +* add bats-support, bats-assert, bats-file and bats-detik to Dockerfile (#674) + +### Documentation + +* add `--help` text and `man` page content for `--filter-tags` (#679) + +### Fixed + +* explicitly check for GNU parallel (#691) +* wait for report-formatter to finish before ending `bats`' execution, + to fix empty files with `--report-fomatter junit` under Docker (#692) + +#### Documentation + +* improved clarity of section about output in free code (#671) +* fixed typos (#673) +* clarify use cases of `run` (#366) + +## [1.8.2] - 2022-10-19 + +### Fixed + +* fix non zero return code on successful retried tests (#670) +* fix `skip` in `setup_file` failing test suite (#687) + +## [1.8.1] - 2022-10-19 + +### Fixed + +* `shfmt` all files and enforce via CI (#651) +* avoid kernel warning flood/hang with CTRL+C on Bash 5.2 RC (#656) +* Fix infinite wait with (invalid) `-j` (without space) (#657) + +## [1.8.0] - 2022-09-15 + +### Added + +* using external formatters via `--formatter ` (also works for + `--report-formatter`) (#602) +* running only tests that failed in the last run via `--filter-status failed` (#483) +* variable `BATS_TEST_RETRIES` that specifies how often a test should be + reattempted before it is considered failed (#618) +* Docker tags `latest-no-faccessat2` and `-no-faccessat2` for + avoiding `bash: bats: No such file or directory` on `docker<20.10` (or + `runc`/`# bats file_tags=` and + `--filter-tags ` for tagging tests for execution filters (#642) +* warning BW03: inform about `setup_suite` in wrong file (`.bats` instead of `setup_suite.bash`) (#652) + +#### Documentation + +* update gotcha about negated statements: Recommend using `run !` on Bats + versions >=1.5.0 (#593) +* add documentation for `bats_require_minimum_version` (#595) +* improve documentation about `setup_suite` (#652) + +### Fixed + +* added missing shebang (#597) +* remaining instances of `run -` being incorrectly documented as `run =` (#599) +* allow `--gather-test-outputs-in ` to work with existing, empty + directories (#603) + * also add `--clean-and-gather-test-outputs-in ` for improved UX +* double slashes in paths derived from TMPDIR on MacOS (#607) +* fix `load` in `teardown` marking failed tests as not run (#612) +* fix unset variable errors (with set -u) and add regression test (#621) +* `teardown_file` errors don't swallow `setup_file` errors anymore, the behavior + is more like `teardown`'s now (only `return`/last command can trigger `teardown` + errors) (#623) +* upgraded from deprecated CI envs for MacOS (10 -> 11,12) and Ubuntu + (18.04 -> 22.04) (#630) +* add `/usr/lib/bats` as default value for `BATS_LIB_PATH` (#628) +* fix unset variable in `bats-formatter-junit` when `setup_file` fails (#632) +* unify error behavior of `teardown`/`teardown_file`/`teardown_suite` functions: + only fail via return code, not via ERREXIT (#633) +* fix unbound variable errors with `set -u` on `setup_suite` failures (#643) +* fix `load` not being available in `setup_suite` (#644) +* fix RPM spec, add regression test (#648) +* fix handling of `IFS` by `run` (#650) +* only print `setup_suite`'s stderr on errors (#649) + +#### Documentation + +* fix typos, spelling and links (#596, #604, #619, #627) +* fix redirection order of an example in the tutorial (#617) + +## [1.7.0] - 2022-05-14 + +### Added + +* Pretty formatter print filename when entering file (#561) +* BATS_TEST_NAME_PREFIX allows prefixing test names on stdout and in reports (#561) +* setup_suite and teardown_suite (#571, #585) +* out-of-band warning infrastructure, with following warnings: + * BW01: run command not found (exit code 127) (#586) + * BW02: run uses flags without proper `bats_require_minimum_version` guard (#587) +* `bats_require_minimum_version` to guard code that would not run on older + versions (#587) + +#### Documentation + +* document `$BATS_VERSION` (#557) +* document new warning infrastructure (#589, #587, #586) + +### Fixed + +* unbound variable errors in formatters when using `SHELLOPTS=nounset` (`-u`) (#558) +* don't require `flock` *and* `shlock` for parallel mode test (#554) +* print name of failing test when using TAP13 with timing information (#559, #555) +* removed broken symlink, added regression test (#560) +* don't show empty lines as `#` with pretty formatter (#561) +* prevent `teardown`, `teardown_file`, and `teardown_suite` from overriding bats' + exit code by setting `$status` (e.g. via calling `run`) (#581, #575) + * **CRITICAL**: this can return exit code 0 despite failed tests, thus preventing + your CI from reporting test failures! The regression happened in version 1.6.0. +* `run --keep-empty-lines` now reports 0 lines on empty `$output` (#583) + +#### Documentation + +* remove 2018 in title, update copyright dates in README.md (#567) +* fix broken links (#568) +* corrected invalid documentation of `run -N` (had `=N` instead) (#579) + * **CRITICAL**: using the incorrect form can lead to silent errors. See + [issue #578](https://github.com/bats-core/bats-core/issues/578) for more + details and how to find out if your tests are affected. + +## [1.6.1] - 2022-05-14 + +### Fixed + +* prevent `teardown`, `teardown_file`, and `teardown_suite` from overriding bats' + exit code by setting `$status` (e.g. via calling `run`) (#581, #575) + * **CRITICAL**: this can return exit code 0 despite failed tests, thus preventing + your CI from reporting test failures! The regression happened in version 1.6.0. + +#### Documentation + +* corrected invalid documentation of `run -N` (had `=N` instead) (#579) + * **CRITICAL**: using the incorrect form can lead to silent errors. See + [issue #578](https://github.com/bats-core/bats-core/issues/578) for more + details and how to find out if your tests are affected. + +## [1.6.0] - 2022-02-24 + +### Added + +* new flag `--code-quote-style` (and `$BATS_CODE_QUOTE_STYLE`) to customize +quotes around code blocks in error output (#506) +* an example/regression test for running background tasks without blocking the + test run (#525, #535) +* `bats_load_library` for loading libraries from the search path + `$BATS_LIB_PATH` (#548) + +### Fixed + +* improved error trace for some broken cases (#279) +* removed leftover debug file `/tmp/latch` in selftest suite + (single use latch) (#516) +* fix recurring errors on CTRL+C tests with NPM on Windows in selftest suite (#516) +* fixed leaking of local variables from debug trap (#520) +* don't mark FD3 output from `teardown_file` as `` in junit output (#532) +* fix unbound variable error with Bash pre 4.4 (#550) + +#### Documentation + +* remove links to defunct freenode IRC channel (#515) +* improved grammar (#534) +* fixed link to TAP spec (#537) + +## [1.5.0] - 2021-10-22 + +### Added + +* new command line flags (#488) + * `--verbose-run`: Make `run` print `$output` by default + * `-x`, `--trace`: Print test commands as they are executed (like `set -x`)` + * `--show-output-of-passing-tests`: Print output of passing tests + * `--print-output-on-failure`: Automatically print the value of `$output` on + failed tests + * `--gather-test-outputs-in `: Gather the output of failing **and** + passing tests as files in directory +* Experimental: add return code checks to `run` via `!`/`-` (#367, #507) +* `install.sh` and `uninstall.sh` take an optional second parameter for the lib + folder name to allow for multilib install, e.g. into lib64 (#452) +* add `run` flag `--keep-empty-lines` to retain empty lines in `${lines[@]}` (#224, + a894fbfa) +* add `run` flag `--separate-stderr` which also fills `$stderr` and + `$stderr_lines` (#47, 5c9b173d, #507) + +### Fixed + +* don't glob `run`'s `$output` when splitting into `${lines[@]}` + (#151, #152, #158, #156, #281, #289) +* remove empty line after test with pretty formatter on some terminals (#481) +* don't run setup_file/teardown_file on files without tests, e.g. due to + filtering (#484) +* print final line without newline on Bash 3.2 for midtest (ERREXIT) failures + too (#495, #145) +* abort with error on missing flock/shlock when running in parallel mode (#496) +* improved `set -u` test and fixed some unset variable accesses (#498, #501) +* shorten suite/file/test temporary folder paths to leave enough space even on + restricted systems (#503) + +#### Documentation + +* minor edits (#478) + +## [1.4.1] - 2021-07-24 + +### Added + +* Docker image architectures amd64, 386, arm64, arm/v7, arm/v6, ppc64le, s390x (#438) + +### Fixed + +* automatic push to Dockerhub (#438) + +## [1.4.0] - 2021-07-23 + +### Added + +* added BATS_TEST_TMPDIR, BATS_FILE_TMPDIR, BATS_SUITE_TMPDIR (#413) +* added checks and improved documentation for `$BATS_TMPDIR` (#410) +* the docker container now uses [tini](https://github.com/krallin/tini) as the + container entrypoint to improve signal forwarding (#407) +* script to uninstall bats from a given prefix (#400) +* replace preprocessed file path (e.g. `/tmp/bats-run-22908-NP0f9h/bats.23102.src`) + with original filename in stdout/err (but not FD3!) (#429) +* print aborted command on SIGINT/CTRL+C (#368) +* print error message when BATS_RUN_TMPDIR could not be created (#422) + +#### Documentation + +* added tutorial for new users (#397) +* fixed example invocation of docker container (#440) +* minor edits (#431, #439, #445, #463, #464, #465) + +### Fixed + +* fix `bats_tap_stream_unknown: command not found` with pretty formatter, when + writing non compliant extended output (#412) +* avoid collisions on `$BATS_RUN_TMPDIR` with `--no-tempdir-cleanup` and docker + by using `mktemp` additionally to PID (#409) +* pretty printer now puts text that is printed to FD 3 below the test name (#426) +* `rm semaphores/slot-: No such file or directory` in parallel mode on MacOS + (#434, #433) +* fix YAML blocks in TAP13 formatter using `...` instead of `---` to start + a block (#442) +* fixed some typos in comments (#441, #447) +* ensure `/code` exists in docker container, to make examples work again (#440) +* also display error messages from free code (#429) +* npm installed version on Windows: fix broken internal LIBEXEC paths (#459) + +## [1.3.0] - 2021-03-08 + +### Added + +* custom test-file extension via `BATS_FILE_EXTENSION` when searching for test + files in a directory (#376) +* TAP13 formatter, including millisecond timing (#337) +* automatic release to NPM via GitHub Actions (#406) + +#### Documentation + +* added documentation about overusing `run` (#343) +* improved documentation of `load` (#332) + +### Changed + +* recursive suite mode will follow symlinks now (#370) +* split options for (file-) `--report-formatter` and (stdout) `--formatter` (#345) + * **WARNING**: This changes the meaning of `--formatter junit`. + stdout will now show unified xml instead of TAP. From now on, please use + `--report-formatter junit` to obtain the `.xml` report file! +* removed `--parallel-preserve-environment` flag, as this is the default + behavior (#324) +* moved CI from Travis/AppVeyor to GitHub Actions (#405) +* preprocessed files are no longer removed if `--no-tempdir-cleanup` is + specified (#395) + +#### Documentation + +* moved documentation to [readthedocs](https://bats-core.readthedocs.io/en/latest/) + +### Fixed + +#### Correctness + +* fix internal failures due to unbound variables when test files use `set -u` (#392) +* fix internal failures due to changes to `$PATH` in test files (#387) +* fix test duration always being 0 on busybox installs (#363) +* fix hangs on CTRL+C (#354) +* make `BATS_TEST_NUMBER` count per file again (#326) +* include `lib/` in npm package (#352) + +#### Performance + +* don't fork bomb in parallel mode (#339) +* preprocess each file only once (#335) +* avoid running duplicate files n^2 times (#338) + +#### Documentation + +* fix documentation for `--formatter junit` (#334) +* fix documentation for `setup_file` variables (#333) +* fix link to examples page (#331) +* fix link to "File Descriptor 3" section (#301) + +## [1.2.1] - 2020-07-06 + +### Added + +* JUnit output and extensible formatter rewrite (#246) +* `load` function now reads from absolute and relative paths, and $PATH (#282) +* Beginner-friendly examples in /docs/examples (#243) +* @peshay's `bats-file` fork contributed to `bats-core/bats-file` (#276) + +### Changed + +* Duplicate test names now error (previous behaviour was to issue a warning) (#286) +* Changed default formatter in Docker to pretty by adding `ncurses` to + Dockerfile, override with `--tap` (#239) +* Replace "readlink -f" dependency with Bash solution (#217) + +## [1.2.0] - 2020-04-25 + +Support parallel suite execution and filtering by test name. + +### Added + +* docs/CHANGELOG.md and docs/releasing.md (#122) +* The `-f, --filter` flag to run only the tests matching a regular expression (#126) +* Optimize stack trace capture (#138) +* `--jobs n` flag to support parallel execution of tests with GNU parallel (#172) + +### Changed + +* AppVeyor builds are now semver-compliant (#123) +* Add Bash 5 as test target (#181) +* Always use upper case signal names to avoid locale dependent err… (#215) +* Fix for tests reading from stdin (#227) +* Fix wrong line numbers of errors in bash < 4.4 (#229) +* Remove preprocessed source after test run (#232) + +## [1.1.0] - 2018-07-08 + +This is the first release with new features relative to the original Bats 0.4.0. + +### Added + +* The `-r, --recursive` flag to scan directory arguments recursively for + `*.bats` files (#109) +* The `contrib/rpm/bats.spec` file to build RPMs (#111) + +### Changed + +* Travis exercises latest versions of Bash from 3.2 through 4.4 (#116, #117) +* Error output highlights invalid command line options (#45, #46, #118) +* Replaced `echo` with `printf` (#120) + +### Fixed + +* Fixed `BATS_ERROR_STATUS` getting lost when `bats_error_trap` fired multiple + times under Bash 4.2.x (#110) +* Updated `bin/bats` symlink resolution, handling the case on CentOS where + `/bin` is a symlink to `/usr/bin` (#113, #115) + +## [1.0.2] - 2018-06-18 + +* Fixed sstephenson/bats#240, whereby `skip` messages containing parentheses + were truncated (#48) +* Doc improvements: + * Docker usage (#94) + * Better README badges (#101) + * Better installation instructions (#102, #104) +* Packaging/installation improvements: + * package.json update (#100) + * Moved `libexec/` files to `libexec/bats-core/`, improved `install.sh` (#105) + +## [1.0.1] - 2018-06-09 + +* Fixed a `BATS_CWD` bug introduced in #91 whereby it was set to the parent of + `PWD`, when it should've been set to `PWD` itself (#98). This caused file + names in stack traces to contain the basename of `PWD` as a prefix, when the + names should've been purely relative to `PWD`. +* Ensure the last line of test output prints when it doesn't end with a newline + (#99). This was a quasi-bug introduced by replacing `sed` with `while` in #88. + +## [1.0.0] - 2018-06-08 + +`1.0.0` generally preserves compatibility with `0.4.0`, but with some Bash +compatibility improvements and a massive performance boost. In other words: + +* all existing tests should remain compatible +* tests that might've failed or exhibited unexpected behavior on earlier + versions of Bash should now also pass or behave as expected + +Changes: + +* Added support for Docker. +* Added support for test scripts that have the [unofficial strict + mode](http://redsymbol.net/articles/unofficial-bash-strict-mode/) enabled. +* Improved stability on Windows and macOS platforms. +* Massive performance improvements, especially on Windows (#8) +* Workarounds for inconsistent behavior between Bash versions (#82) +* Workaround for preserving stack info after calling an exported function under + Bash < 4.4 (#87) +* Fixed TAP compliance for skipped tests +* Added support for tabs in test names. +* `bin/bats` and `install.sh` now work reliably on Windows (#91) + +## [0.4.0] - 2014-08-13 + +* Improved the display of failing test cases. Bats now shows the source code of + failing test lines, along with full stack traces including function names, + filenames, and line numbers. +* Improved the display of the pretty-printed test summary line to include the + number of skipped tests, if any. +* Improved the speed of the preprocessor, dramatically shortening test and suite + startup times. +* Added support for absolute pathnames to the `load` helper. +* Added support for single-line `@test` definitions. +* Added bats(1) and bats(7) manual pages. +* Modified the `bats` command to default to TAP output when the `$CI` variable + is set, to better support environments such as Travis CI. + +## [0.3.1] - 2013-10-28 + +* Fixed an incompatibility with the pretty formatter in certain environments + such as tmux. +* Fixed a bug where the pretty formatter would crash if the first line of a test + file's output was invalid TAP. + +## [0.3.0] - 2013-10-21 + +* Improved formatting for tests run from a terminal. Failing tests are now + colored in red, and the total number of failing tests is displayed at the end + of the test run. When Bats is not connected to a terminal (e.g. in CI runs), + or when invoked with the `--tap` flag, output is displayed in standard TAP + format. +* Added the ability to skip tests using the `skip` command. +* Added a message to failing test case output indicating the file and line + number of the statement that caused the test to fail. +* Added "ad-hoc" test suite support. You can now invoke `bats` with multiple + filename or directory arguments to run all the specified tests in aggregate. +* Added support for test files with Windows line endings. +* Fixed regular expression warnings from certain versions of Bash. +* Fixed a bug running tests containing lines that begin with `-e`. + +## [0.2.0] - 2012-11-16 + +* Added test suite support. The `bats` command accepts a directory name + containing multiple test files to be run in aggregate. +* Added the ability to count the number of test cases in a file or suite by + passing the `-c` flag to `bats`. +* Preprocessed sources are cached between test case runs in the same file for + better performance. + +## [0.1.0] - 2011-12-30 + +* Initial public release. + +[Unreleased]: https://github.com/bats-core/bats-core/compare/v1.7.0...HEAD +[1.7.0]: https://github.com/bats-core/bats-core/compare/v1.6.1...v1.7.0 +[1.6.1]: https://github.com/bats-core/bats-core/compare/v1.6.0...v1.6.1 +[1.6.0]: https://github.com/bats-core/bats-core/compare/v1.5.0...v1.6.0 +[1.5.0]: https://github.com/bats-core/bats-core/compare/v1.4.1...v1.5.0 +[1.4.1]: https://github.com/bats-core/bats-core/compare/v1.4.0...v1.4.1 +[1.4.0]: https://github.com/bats-core/bats-core/compare/v1.3.0...v1.4.0 +[1.3.0]: https://github.com/bats-core/bats-core/compare/v1.2.1...v1.3.0 +[1.2.1]: https://github.com/bats-core/bats-core/compare/v1.2.0...v1.2.1 +[1.2.0]: https://github.com/bats-core/bats-core/compare/v1.1.0...v1.2.0 +[1.1.0]: https://github.com/bats-core/bats-core/compare/v1.0.2...v1.1.0 +[1.0.2]: https://github.com/bats-core/bats-core/compare/v1.0.1...v1.0.2 +[1.0.1]: https://github.com/bats-core/bats-core/compare/v1.0.0...v1.0.1 +[1.0.0]: https://github.com/bats-core/bats-core/compare/v0.4.0...v1.0.0 +[0.4.0]: https://github.com/bats-core/bats-core/compare/v0.3.1...v0.4.0 +[0.3.1]: https://github.com/bats-core/bats-core/compare/v0.3.0...v0.3.1 +[0.3.0]: https://github.com/bats-core/bats-core/compare/v0.2.0...v0.3.0 +[0.2.0]: https://github.com/bats-core/bats-core/compare/v0.1.0...v0.2.0 +[0.1.0]: https://github.com/bats-core/bats-core/commits/v0.1.0 + diff --git a/tooling/bats-core/docs/CODEOWNERS b/tooling/bats-core/docs/CODEOWNERS new file mode 100644 index 00000000000000..2eb2333058e7e6 --- /dev/null +++ b/tooling/bats-core/docs/CODEOWNERS @@ -0,0 +1,4 @@ +# This enables automatic code review requests per: +# - https://help.github.com/articles/about-codeowners/ +# - https://help.github.com/articles/enabling-required-reviews-for-pull-requests/ +* @bats-core/bats-core diff --git a/tooling/bats-core/docs/CODE_OF_CONDUCT.md b/tooling/bats-core/docs/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000000..d8d6972d538d07 --- /dev/null +++ b/tooling/bats-core/docs/CODE_OF_CONDUCT.md @@ -0,0 +1,92 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting one of the current [project maintainers](#project-maintainers) listed below. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Project Maintainers + +### Current Maintainers + +* [Bianca Tamayo][bt-gh] +* [Mike Bland][mb-gh] +* [Jason Karns][jk-gh] +* [Andrew Martin][am-gh] + +### Past Maintainers + +* Sam Stephenson <> (Original author) + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[bt-gh]: https://github.com/btamayo +[mb-gh]: https://github.com/mbland +[jk-gh]: https://github.com/jasonkarns +[am-gh]: https://github.com/sublimino + +[homepage]: https://contributor-covenant.org +[version]: https://contributor-covenant.org/version/1/4/ diff --git a/tooling/bats-core/docs/CONTRIBUTING.md b/tooling/bats-core/docs/CONTRIBUTING.md new file mode 100644 index 00000000000000..622b552abe9915 --- /dev/null +++ b/tooling/bats-core/docs/CONTRIBUTING.md @@ -0,0 +1,232 @@ +# Contributing Guidelines + +## Welcome! + +Thank you for considering contributing to this project's +development and/or documentation. Just a reminder: if you're new to this project +or to OSS and want to find issues to work on, please check the following labels +on issues: + +- [help wanted][helpwantedlabel] +- [docs][docslabel] +- [good first issue][goodfirstissuelabel] + +[docslabel]: https://github.com/bats-core/bats-core/labels/docs +[helpwantedlabel]: https://github.com/bats-core/bats-core/labels/help%20wanted +[goodfirstissuelabel]: https://github.com/bats-core/bats-core/labels/good%20first%20issue + +To see all labels and their meanings, [check this wiki page][labelswiki]. + +[labelswiki]: https://github.com/bats-core/bats-core/wiki/GitHub-Issue-Labels + +## Table of contents + +* [Contributing Guidelines](#contributing-guidelines) + * [Welcome!](#welcome) + * [Table of contents](#table-of-contents) + * [Quick links](#quick-links) + * [Code of conduct](#code-of-conduct) + * [Asking questions](#asking-questions) + * [Updating documentation](#updating-documentation) + * [Testing](#testing) + * [Coding conventions](#coding-conventions) + * [Function declarations](#function-declarations) + * [Variable and parameter declarations](#variable-and-parameter-declarations) + * [Command substitution](#command-substitution) + * [Process substitution](#process-substitution) + * [Conditionals and loops](#conditionals-and-loops) + * [Generating output](#generating-output) + * [Signal names](#signal-names) + * [Gotchas](#gotchas) + * [Open Source License](#open-source-license) + * [Credits](#credits) + +## Quick links + +- [Gitter channel →][gitterurl]: Feel free to come chat with us on Gitter +- [README →][README] +- [Code of conduct →][CODE_OF_CONDUCT] +- [License information →][LICENSE] +- [Original repository →][repohome] +- [Issues →][repoissues] +- [Pull requests →][repoprs] +- [Milestones →][repomilestones] +- [Projects →][repoprojects] + +[README]: https://github.com/bats-core/bats-core/blob/master/README.md +[CODE_OF_CONDUCT]: https://github.com/bats-core/bats-core/blob/master/docs/CODE_OF_CONDUCT.md +[LICENSE]: https://github.com/bats-core/bats-core/blob/master/LICENSE.md + +## Code of conduct + +Harassment or rudeness of any kind will not be tolerated, period. For +specifics, see the [CODE_OF_CONDUCT][] file. + +## Asking questions + +Please check the [documentation][documentation] or existing [discussions][] and [issues][repoissues] first. + +If you cannot find an answer to your question, please feel free to hop on our +[Gitter][gitterurl]. [![Gitter](https://badges.gitter.im/bats-core/bats-core.svg)](https://gitter.im/bats-core/bats-core) + +## Updating documentation + +We love documentation and people who love documentation! + +If you love writing clear, accessible docs, please don't be shy about pull +requests. Remember: docs are just as important as code. + +Also: _no typo is too small to fix!_ Really. Of course, batches of fixes are +preferred, but even one nit is one nit too many. + +## Testing + +- Continuous integration status: [![Tests](https://github.com/bats-core/bats-core/workflows/Tests/badge.svg)](https://github.com/bats-core/bats-core/actions?query=workflow%3ATests) + +To run all tests: +```sh +bin/bats test +``` + +To run a single test file: +```sh +bin/bats test/file.bats +``` + +When running from a terminal, Bats uses the *pretty* formatter by default. +However, to debug Bats you might need to see the raw test output. +The **cat** formatter is intended as an internal debugging tool because +it does not process test outputs. +To use it, run Bats with the `--formatter cat` option. + +## Coding conventions + +Use [`shfmt`](https://github.com/mvdan/sh#shfmt) and [ShellCheck](https://www.shellcheck.net/). The CI will enforce this. + +Use `snake_case` for all identifiers. + +### Function declarations + +- Declare functions without the `function` keyword. +- Strive to always use `return`, never `exit`, unless an error condition is + severe enough to warrant it. + - Calling `exit` makes it difficult for the caller to recover from an error, + or to compose new commands from existing ones. + +### Variable and parameter declarations + +- Declare all variables inside functions using `local`. +- Declare temporary file-level variables using `declare`. Use `unset` to remove + them when finished. +- Don't use `local -r`, as a readonly local variable in one scope can cause a + conflict when it calls a function that declares a `local` variable of the same + name. +- Don't use type flags with `declare` or `local`. Assignments to integer + variables in particular may behave differently, and it has no effect on array + variables. +- For most functions, the first lines should use `local` declarations to + assign the original positional parameters to more meaningful names, e.g.: + ```bash + format_summary() { + local cmd_name="$1" + local summary="$2" + local longest_name_len="$3" + ``` + For very short functions, this _may not_ be necessary, e.g.: + ```bash + has_spaces() { + [[ "$1" != "${1//[[:space:]]/}" ]] + } + ``` + +### Command substitution + +- If possible, don't. While this capability is one of Bash's core strengths, + every new process created by Bats makes the framework slower, and speed is + critical to encouraging the practice of automated testing. (This is especially + true on Windows, [where process creation is one or two orders of magnitude + slower][win-slow]. See [bats-core/bats-core#8][pr-8] for an illustration of + the difference avoiding subshells makes.) Bash is quite powerful; see if you + can do what you need in pure Bash first. +- If you need to capture the output from a function, store the output using + `printf -v` instead if possible. `-v` specifies the name of the variable into + which to write the result; the caller can supply this name as a parameter. +- If you must use command substitution, use `$()` instead of backticks, as it's + more robust, more searchable, and can be nested. + +[win-slow]: https://rufflewind.com/2014-08-23/windows-bash-slow +[pr-8]: https://github.com/bats-core/bats-core/pull/8 + +### Process substitution + +- If possible, don't use it. See the advice on avoiding subprocesses and using + `printf -v` in the **Command substitution** section above. +- Use wherever necessary and possible, such as when piping input into a `while` + loop (which avoids having the loop body execute in a subshell) or running a + command taking multiple filename arguments based on output from a function or + pipeline (e.g. `diff`). +- *Warning*: It is impossible to directly determine the exit status of a process + substitution; emitting an exit status as the last line of output is a possible + workaround. + +### Conditionals and loops + +- Always use `[[` and `]]` for evaluating variables. Per the guideline under + **Formatting**, quote variables and strings within the brackets, but not + regular expressions (or variables containing regular expressions) appearing + on the right side of the `=~` operator. + +### Generating output + +- Use `printf` instead of `echo`. Both are Bash builtins, and there's no + perceptible performance difference when running Bats under the `time` builtin. + However, `printf` provides a more consistent experience in general, as `echo` + has limitations to the arguments it accepts, and even the same version of Bash + may produce different results for `echo` based on how the binary was compiled. + See [Stack Overflow: Why is printf better than echo?][printf-vs-echo] for + excruciating details. + +[printf-vs-echo]: https://unix.stackexchange.com/a/65819 + +### Signal names + +Always use upper case signal names (e.g. `trap - INT EXIT`) to avoid locale +dependent errors. In some locales (for example Turkish, see +[Turkish dotless i](https://en.wikipedia.org/wiki/Dotted_and_dotless_I)) lower +case signal names cause Bash to error. An example of the problem: + +```bash +$ echo "tr_TR.UTF-8 UTF-8" >> /etc/locale.gen && locale-gen tr_TR.UTF-8 # Ubuntu derivatives +$ LC_CTYPE=tr_TR.UTF-8 LC_MESSAGES=C bash -c 'trap - int && echo success' +bash: line 0: trap: int: invalid signal specification +$ LC_CTYPE=tr_TR.UTF-8 LC_MESSAGES=C bash -c 'trap - INT && echo success' +success +``` + + +## Credits + +The [official bash logo](https://github.com/odb/official-bash-logo) is copyrighted +by the [Free Software Foundation](https://www.fsf.org/), 2016 under the [Free Art License](http://artlibre.org/licence/lal/en/) + +This guide borrows **heavily** from [@mbland's go-script-bash][gsb] (with some +sections directly quoted), which in turn was +drafted with tips from [Wrangling Web Contributions: How to Build +a CONTRIBUTING.md][moz] and with some inspiration from [the Atom project's +CONTRIBUTING.md file][atom]. + +[gsb]: https://github.com/mbland/go-script-bash/blob/master/CONTRIBUTING.md +[moz]: https://mozillascience.github.io/working-open-workshop/contributing/ +[atom]: https://github.com/atom/atom/blob/master/CONTRIBUTING.md + +[discussions]: https://github.com/bats-core/bats-core/discussions +[documentation]: https://bats-core.readthedocs.io/ +[repoprojects]: https://github.com/bats-core/bats-core/projects +[repomilestones]: https://github.com/bats-core/bats-core/milestones +[repoprs]: https://github.com/bats-core/bats-core/pulls +[repoissues]: https://github.com/bats-core/bats-core/issues +[repohome]: https://github.com/bats-core/bats-core + +[osmit]: https://opensource.org/licenses/MIT + +[gitterurl]: https://gitter.im/bats-core/bats-core diff --git a/tooling/bats-core/docs/Makefile b/tooling/bats-core/docs/Makefile new file mode 100644 index 00000000000000..d0c3cbf1020d5c --- /dev/null +++ b/tooling/bats-core/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/tooling/bats-core/docs/PULL_REQUEST_TEMPLATE.md b/tooling/bats-core/docs/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000000000..c7c58d58b39f2e --- /dev/null +++ b/tooling/bats-core/docs/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,5 @@ +- [ ] I have reviewed the [Contributor Guidelines][contributor]. +- [ ] I have reviewed the [Code of Conduct][coc] and agree to abide by it + +[contributor]: https://github.com/bats-core/bats-core/blob/master/docs/CONTRIBUTING.md +[coc]: https://github.com/bats-core/bats-core/blob/master/docs/CODE_OF_CONDUCT.md diff --git a/tooling/bats-core/docs/examples/README.md b/tooling/bats-core/docs/examples/README.md new file mode 100644 index 00000000000000..5ef51342f4b541 --- /dev/null +++ b/tooling/bats-core/docs/examples/README.md @@ -0,0 +1,6 @@ +# Examples + +This directory contains example .bats files. +See the [bats-core wiki][examples] for more details. + +[examples]: https://github.com/bats-core/bats-core/wiki/Examples \ No newline at end of file diff --git a/tooling/bats-core/docs/examples/package-tarball b/tooling/bats-core/docs/examples/package-tarball new file mode 100644 index 00000000000000..b51cffd1768209 --- /dev/null +++ b/tooling/bats-core/docs/examples/package-tarball @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# "unofficial" bash strict mode +# See: http://redsymbol.net/articles/unofficial-bash-strict-mode +set -o errexit # Exit when simple command fails 'set -e' +set -o errtrace # Exit on error inside any functions or subshells. +set -o nounset # Trigger error when expanding unset variables 'set -u' +set -o pipefail # Do not hide errors within pipes 'set -o pipefail' +set -o xtrace # Display expanded command and arguments 'set -x' +IFS=$'\n\t' # Split words on \n\t rather than spaces + +main() { + tar -czf "$dst_tarball" -C "$src_dir" . +} + +main "$@" diff --git a/tooling/bats-core/docs/examples/package-tarball.bats b/tooling/bats-core/docs/examples/package-tarball.bats new file mode 100755 index 00000000000000..144318ae1936cf --- /dev/null +++ b/tooling/bats-core/docs/examples/package-tarball.bats @@ -0,0 +1,51 @@ +#!/usr/bin/env bats + +setup() { + export dst_tarball="${BATS_TMPDIR}/dst.tar.gz" + export src_dir="${BATS_TMPDIR}/src_dir" + + rm -rf "${dst_tarball}" "${src_dir}" + mkdir "${src_dir}" + touch "${src_dir}"/{a,b,c} +} + +main() { + bash "${BATS_TEST_DIRNAME}"/package-tarball +} + +@test "fail when \$src_dir and \$dst_tarball are unbound" { + unset src_dir dst_tarball + + run main + [ "${status}" -ne 0 ] +} + +@test "fail when \$src_dir is a non-existent directory" { + # shellcheck disable=SC2030 + src_dir='not-a-dir' + + run main + [ "${status}" -ne 0 ] +} + +# shellcheck disable=SC2016 +@test "pass when \$src_dir directory is empty" { + # shellcheck disable=SC2031,SC2030 + rm -rf "${src_dir:?}/*" + + run main + echo "$output" + [ "${status}" -eq 0 ] +} + +# shellcheck disable=SC2016 +@test "files in \$src_dir are added to tar archive" { + run main + [ "${status}" -eq 0 ] + + run tar tf "$dst_tarball" + [ "${status}" -eq 0 ] + [[ "${output}" =~ a ]] + [[ "${output}" =~ b ]] + [[ "${output}" =~ c ]] +} diff --git a/tooling/bats-core/docs/list-links.py b/tooling/bats-core/docs/list-links.py new file mode 100644 index 00000000000000..e8651ad66524f4 --- /dev/null +++ b/tooling/bats-core/docs/list-links.py @@ -0,0 +1,4 @@ +import pickle +with open("build/doctrees/environment.pickle", "rb") as f: + dat = pickle.load(f) +print(dat.domaindata['std']['labels']) diff --git a/tooling/bats-core/docs/make.bat b/tooling/bats-core/docs/make.bat new file mode 100644 index 00000000000000..9534b018135ed7 --- /dev/null +++ b/tooling/bats-core/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/tooling/bats-core/docs/releasing.md b/tooling/bats-core/docs/releasing.md new file mode 100644 index 00000000000000..cd0717b7e58780 --- /dev/null +++ b/tooling/bats-core/docs/releasing.md @@ -0,0 +1,127 @@ +# Releasing a new Bats version + +These notes reflect the current process. There's a lot more we could do, in +terms of automation and expanding the number of platforms to which we formally +release (see #103). + +## Update docs/CHANGELOG.md + +Create a new entry at the top of `docs/CHANGELOG.md` that enumerates the +significant updates to the new version. + +## Bumping the version number + +Bump the version numbers in the following files: + +- contrib/rpm/bats.spec +- libexec/bats-core/bats +- package.json + +Commit these changes (including the `docs/CHANGELOG.md` changes) in a commit +with the message `Bats `, where `` is the new version number. + +Create a new signed, annotated tag with: + +```bash +$ git tag -a -s +``` + +Include the `docs/CHANGELOG.md` notes corresponding to the new version as the +tag annotation, except the first line should be: `Bats - YYYY-MM-DD` +and any Markdown headings should become plain text, e.g.: + +```md +### Added +``` + +should become: + +```md +Added: +``` + +## Create a GitHub release + +Push the new version commit and tag to GitHub via the following: + +```bash +$ git push --follow-tags +``` + +Then visit https://github.com/bats-core/bats-core/releases, and: + +* Click **Draft a new release**. +* Select the new version tag. +* Name the release: `Bats `. +* Paste the same notes from the version tag annotation as the description, + except change the first line to read: `Released: YYYY-MM-DD`. +* Click **Publish release**. + +For more on `git push --follow-tags`, see: + +* [git push --follow-tags in the online manual][ft-man] +* [Stack Overflow: How to push a tag to a remote repository using Git?][ft-so] + +[ft-man]: https://git-scm.com/docs/git-push#git-push---follow-tags +[ft-so]: https://stackoverflow.com/a/26438076 + +## NPM + +`npm publish`. Pretty easy! + +For the paranoid, use `npm pack` and install the resulting tarball locally with +`npm install` before publishing. + +## Homebrew + +The basic instructions are in the [Submit a new version of an existing +formula][brew] section of the Homebrew docs. + +[brew]: https://github.com/Homebrew/brew/blob/master/docs/How-To-Open-a-Homebrew-Pull-Request.md#submit-a-new-version-of-an-existing-formula + +An example using v1.1.0 (notice that this uses the sha256 sum of the tarball): + +```bash +$ curl -LOv https://github.com/bats-core/bats-core/archive/v1.1.0.tar.gz +$ openssl sha256 v1.1.0.tar.gz +SHA256(v1.1.0.tar.gz)=855d8b8bed466bc505e61123d12885500ef6fcdb317ace1b668087364717ea82 + +# Add the --dry-run flag to see the individual steps without executing. +$ brew bump-formula-pr \ + --url=https://github.com/bats-core/bats-core/archive/v1.1.0.tar.gz \ + --sha256=855d8b8bed466bc505e61123d12885500ef6fcdb317ace1b668087364717ea82 +``` +This resulted in https://github.com/Homebrew/homebrew-core/pull/29864, which was +automatically merged once the build passed. + +## Alpine Linux + +An example using v1.1.0 (notice that this uses the sha512 sum of the Zip file): + +```bash +$ curl -LOv https://github.com/bats-core/bats-core/archive/v1.1.0.zip +$ openssl sha512 v1.1.0.zip +SHA512(v1.1.0.zip)=accd83cfec0025a2be40982b3f9a314c2bbf72f5c85daffa9e9419611904a8d34e376919a5d53e378382e0f3794d2bd781046d810225e2a77812474e427bed9e +``` + +After cloning alpinelinux/aports, I used the above information to create: +https://github.com/alpinelinux/aports/pull/4696 + +**Note:** Currently users must enable the `edge` branch of the `community` repo +by adding/uncommenting the corresponding entry in `/etc/apk/repositories`. + +## Announce + +It's worth making a brief announcement like [the v1.1.0 announcement via +Gitter][gitter]: + +[gitter]: https://gitter.im/bats-core/bats-core?at=5b42c9a57b811a6d63daacb5 + +``` +v1.1.0 is now available via Homebrew and npm: +https://github.com/bats-core/bats-core/releases/tag/v1.1.0 + +It'll eventually be available in Alpine via the edge branch of the community +repo once alpinelinux/aports#4696 gets merged. (Check /etc/apk/repositories to +ensure this repo is enabled.) +``` diff --git a/tooling/bats-core/docs/source/_static/.gitkeep b/tooling/bats-core/docs/source/_static/.gitkeep new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/tooling/bats-core/docs/source/_templates/.gitkeep b/tooling/bats-core/docs/source/_templates/.gitkeep new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/tooling/bats-core/docs/source/assets/README.md b/tooling/bats-core/docs/source/assets/README.md new file mode 100644 index 00000000000000..cfa3904cb8c234 --- /dev/null +++ b/tooling/bats-core/docs/source/assets/README.md @@ -0,0 +1,24 @@ +# Our Logo + +
+ + + + +
+ +## Usage Guide for Third Parties + +There may be cases where you want to use our logo. Please follow these rules: + +**DO** use our logo as a part of thumbnails, banners/images in articles, or on a README in reference to the this project. + +**DO** use our logo to relate resources back to the Bats project, like file associations or links to the project page. + +**DO NOT** use our logo as the face of a third-party tool or extension that is not affiliated with the Bats project or Bats maintainers. + +If in doubt, ask if your intended usecase is approved. + +## Credits + +The Bats Logo was created by [Vukory](https://www.artstation.com/vukory) ([Github](https://github.com/vukory)) and sponsored by [SethFalco](https://github.com/SethFalco). diff --git a/tooling/bats-core/docs/source/assets/dark_mode_bat.svg b/tooling/bats-core/docs/source/assets/dark_mode_bat.svg new file mode 100644 index 00000000000000..1e70621efe0d11 --- /dev/null +++ b/tooling/bats-core/docs/source/assets/dark_mode_bat.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tooling/bats-core/docs/source/assets/dark_mode_cube.svg b/tooling/bats-core/docs/source/assets/dark_mode_cube.svg new file mode 100644 index 00000000000000..2d324ae940e9f8 --- /dev/null +++ b/tooling/bats-core/docs/source/assets/dark_mode_cube.svg @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tooling/bats-core/docs/source/assets/dark_mode_wordmark_lowercase.svg b/tooling/bats-core/docs/source/assets/dark_mode_wordmark_lowercase.svg new file mode 100644 index 00000000000000..24df01984ce12e --- /dev/null +++ b/tooling/bats-core/docs/source/assets/dark_mode_wordmark_lowercase.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tooling/bats-core/docs/source/assets/dark_mode_wordmark_uppercase.svg b/tooling/bats-core/docs/source/assets/dark_mode_wordmark_uppercase.svg new file mode 100644 index 00000000000000..c2364bd4ecb177 --- /dev/null +++ b/tooling/bats-core/docs/source/assets/dark_mode_wordmark_uppercase.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tooling/bats-core/docs/source/assets/light_mode_bat.svg b/tooling/bats-core/docs/source/assets/light_mode_bat.svg new file mode 100644 index 00000000000000..915e447c885188 --- /dev/null +++ b/tooling/bats-core/docs/source/assets/light_mode_bat.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tooling/bats-core/docs/source/assets/light_mode_cube.svg b/tooling/bats-core/docs/source/assets/light_mode_cube.svg new file mode 100644 index 00000000000000..d4125ab3343caa --- /dev/null +++ b/tooling/bats-core/docs/source/assets/light_mode_cube.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tooling/bats-core/docs/source/assets/light_mode_wordmark_lowercase.svg b/tooling/bats-core/docs/source/assets/light_mode_wordmark_lowercase.svg new file mode 100644 index 00000000000000..8874ddcc828170 --- /dev/null +++ b/tooling/bats-core/docs/source/assets/light_mode_wordmark_lowercase.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tooling/bats-core/docs/source/assets/light_mode_wordmark_uppercase.svg b/tooling/bats-core/docs/source/assets/light_mode_wordmark_uppercase.svg new file mode 100644 index 00000000000000..b694f77b7f5e29 --- /dev/null +++ b/tooling/bats-core/docs/source/assets/light_mode_wordmark_uppercase.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + diff --git a/tooling/bats-core/docs/source/conf.py b/tooling/bats-core/docs/source/conf.py new file mode 100644 index 00000000000000..4c4191093510ed --- /dev/null +++ b/tooling/bats-core/docs/source/conf.py @@ -0,0 +1,74 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = 'bats-core' +copyright = '2022, bats-core organization' +author = 'bats-core organization' + +# The full version, including alpha/beta/rc tags +release = '1' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'recommonmark', + 'sphinxcontrib.programoutput', + 'sphinx.ext.autosectionlabel' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +html_sidebars = { '**': [ + 'about.html', + 'navigation.html', + 'relations.html', + 'searchbox.html', + 'donate.html'] } + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +#html_theme = 'alabaster' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static', 'assets'] +html_logo = "assets/light_mode_cube.svg" + +#man_pages = [ ('man.1', 'bats', 'bats documentation', ['bats-core Contributors'], 1)] + +def setup(app): + app.add_config_value('recommonmark_config', {'enable_eval_rst': True}, True) + import recommonmark + from recommonmark.transform import AutoStructify + app.add_transform(AutoStructify) diff --git a/tooling/bats-core/docs/source/docker-usage.md b/tooling/bats-core/docs/source/docker-usage.md new file mode 100644 index 00000000000000..16d77442739427 --- /dev/null +++ b/tooling/bats-core/docs/source/docker-usage.md @@ -0,0 +1,70 @@ +# Docker Usage Guide + +- [Docker Usage Guide](#docker-usage-guide) + * [Basic Usage](#basic-usage) + * [Basic Usage for bats project](#basic-usage-for-bats-project) + * [Docker Gotchas](#docker-gotchas) + * [Extending from the base image](#extending-from-the-base-image) + +## Basic Usage + +For test suites that are intended to run in isolation from their project code, you can mount the test directory and run the [official bats docker image](https://hub.docker.com/r/bats/bats): + +```bash +$ docker run -it -v "$PWD:/code" bats/bats:latest /code/test +``` + +This Docker image includes libraries like [bats-support](https://github.com/bats-core/bats-support) and [bats-assert](https://github.com/bats-core/bats-assert), which can be loaded in `setup` like this: + +```bash +setup() { + bats_load_library bats-support + bats_load_library bats-assert +} +``` + +## Basic Usage for Bats Project + +To build and run `bats`' own tests: +```bash +$ git clone https://github.com/bats-core/bats-core.git +Cloning into 'bats-core'... +remote: Counting objects: 1222, done. +remote: Compressing objects: 100% (53/53), done. +remote: Total 1222 (delta 34), reused 55 (delta 21), pack-reused 1146 +Receiving objects: 100% (1222/1222), 327.28 KiB | 1.70 MiB/s, done. +Resolving deltas: 100% (661/661), done. + +$ cd bats-core/ +$ docker build --tag bats/bats:latest . +... +$ docker run -it bats/bats:latest --formatter tap /opt/bats/test +``` + +To mount your tests into the container, first build the image as above. Then, for example with `bats`: +```bash +$ docker run -it -v "$PWD:/opt/bats" bats/bats:latest /opt/bats/test +``` +This runs the `test/` directory from the bats-core repository inside the bats Docker container. + +## Docker Gotchas + +Relying on functionality provided by your environment (ssh keys or agent, installed binaries, fixtures outside the mounted test directory) will fail when running inside Docker. + +`--interactive`/`-i` attaches an interactive terminal and is useful to kill hanging processes (otherwise has to be done via docker stop command). `--tty`/`-t` simulates a tty (often not used, but most similar to test runs from a Bash prompt). Interactivity is important to a user, but not a build, and TTYs are probably more important to a headless build. Everything's least-surprising to a new Docker use if both are used. + +## Extending from the base image + +Docker operates on a principle of isolation, and bundles all dependencies required into the Docker image. These can be mounted in at runtime (for test files, configuration, etc). For binary dependencies it may be better to extend the base Docker image with further tools and files. + +```dockerfile +FROM bats/bats + +RUN \ + apk \ + --no-cache \ + --update \ + add \ + openssh + +``` diff --git a/tooling/bats-core/docs/source/faq.rst b/tooling/bats-core/docs/source/faq.rst new file mode 100644 index 00000000000000..c1e24aad6ea216 --- /dev/null +++ b/tooling/bats-core/docs/source/faq.rst @@ -0,0 +1,172 @@ +FAQ +=== + +How do I set the working directory? +----------------------------------- + +The working directory is simply the directory where you started when executing bats. +If you want to enforce a specific directory, you can use `cd` in the `setup_file`/`setup` functions. +However, be aware that code outside any function will run before any of these setup functions and might interfere with bats' internals. + + +How do I see the output of the command under `run` when a test fails? +--------------------------------------------------------------------- + +`run` captures stdout and stderr of its command and stores it in the `$output` and `${lines[@]}` variables. +If you want to see this output, you need to print it yourself, or use functions like `assert_output` that will reproduce it on failure. + +Can I use `--filter` to exclude files/tests? +-------------------------------------------- + +No, not directly. `--filter` uses a regex to match against test names. So you could try to invert the regex. +The filename won't be part of the strings that are tested, so you cannot filter against files. + +How can I exclude a single test from a test run? +------------------------------------------------ + +If you want to exclude only few tests from a run, you can either `skip` them: + +.. code-block:: bash + + @test "Testname" { + # yadayada + } + +becomes + +.. code-block:: bash + + @test "Testname" { + skip 'Optional skip message' + # yadayada + } + +or comment them out, e.g.: + +.. code-block:: bash + + @test "Testname" { + +becomes + +.. code-block:: bash + + disabled() { # @test "Testname" { + +For multiple tests or all tests of a file, this becomes tedious, so read on. + +How can I exclude all tests of a file from a test run? +-------------------------------------------------------- + +If you run your test suite by naming individual files like: + +.. code-block:: bash + + $ bats test/a.bats test/b.bats ... + +you can simply omit your file. When running a folder like + + +.. code-block:: bash + + $ bats test/ + +you can prevent test files from being picked up by changing their extension to something other than `.bats`. + +It is also possible to `skip` in `setup_file`/`setup` which will skip all tests in the file. + +How can I include my own `.sh` files for testing? +------------------------------------------------- + +You can simply `source .sh` files. However, be aware that `source`ing files with errors outside of any function (or inside `setup_file`) will trip up bats +and lead to hard to diagnose errors. +Therefore, it is safest to only `source` inside `setup` or the test functions themselves. + +How can I debug a failing test? +------------------------------- + +Short of using a bash debugger you should make sure to use appropriate asserts for your task instead of raw bash comparisons, e.g.: + +.. code-block:: bash + + @test test { + run echo test failed + assert_output "test" + # instead of + [ "$output" = "test" ] + } + +Because the former will print the output when the test fails while the latter won't. +Similarly, you should use `assert_success`/`assert_failure` instead of `[ "$status" -eq 0 ]` for return code checks. + +Is there a mechanism to add file/test specific functionality to a common setup function? +---------------------------------------------------------------------------------------- + +Often the setup consists of parts that are common between different files of a test suite and parts that are specific to each file. +There is no suite wide setup functionality yet, so you should extract these common setup steps into their own file (e.g. `common-test-setup.sh`) and function (e.g. `commonSetup() {}`), +which can be `source`d or `load`ed and call it in `setup_file` or `setup`. + +How can I use helper libraries like bats-assert? +------------------------------------------------ + +This is a short reproduction of https://github.com/ztombol/bats-docs. + +At first, you should make sure the library is installed. This is usually done in the `test_helper/` folders alongside the `.bats` files, giving you a filesystem layout like this: + +.. code-block:: + + test/ + test.bats + test_helper/ + bats-support/ + bats-assert/ + +Next, you should load those helper libraries: + +.. code-block:: bash + + setup() { + load 'test_helper/bats-support/load' # this is required by bats-assert! + load 'test_helper/bats-assert/load' + } + +Now, you should be able to use the functions from these helpers inside your tests, e.g.: + +.. code-block:: bash + + @test "test" { + run echo test + assert_output "test" + } + +Note that you obviously need to load the library before using it. +If you need the library inside `setup_file` or `teardown_file` you need to load it in `setup_file`. + +How to set a test timeout in bats? +---------------------------------- + +Set the variable `$BATS_TEST_TIMEOUT` before `setup()` starts. This means you can set it either on the command line, +in free code in the test file or in `setup_file()`. + +How can I lint/shell-format my bats tests? +------------------------------------------ + +Due to their custom syntax (`@test`), `.bats` files are not standard bash. This prevents most tools from working with bats. +However, there is an alternative syntax `function_name { # @test` to declare tests in a bash compliant manner. + +- shellcheck support since version 0.7 +- shfmt support since version 3.2.0 (using `-ln bats`) + + +How can I check if a test failed/succeeded during teardown? +----------------------------------------------------------- + +You can check `BATS_TEST_COMPLETED` which will be set to 1 if the test was successful or empty if it was not. +There is also `BATS_TEST_SKIPPED` which will be non-empty (contains the skip message or -1) when `skip` was called. + +How can I setup/cleanup before/after all tests? +----------------------------------------------- + +Setup/cleanup before/after all tests can be achieved using the special `setup_suite` and `teardown_suite` functions. +These functions must be placed into a dedicated `setup_suite.bash` file next to your `.bats` files. +For more information check out the :ref:`setup and teardown section `. diff --git a/tooling/bats-core/docs/source/gotchas.rst b/tooling/bats-core/docs/source/gotchas.rst new file mode 100644 index 00000000000000..485b675030e646 --- /dev/null +++ b/tooling/bats-core/docs/source/gotchas.rst @@ -0,0 +1,132 @@ +Gotchas +======= + +My test fails although I return true? +------------------------------------- + +Using `return 1` to signify `true` for a success as is done often in other languages does not mesh well with Bash's +convention of using return code 0 to signify success and everything non-zero to indicate a failure. + +Please adhere to this idiom while using bats, or you will constantly work against your environment. + +My negated statement (e.g. ! true) does not fail the test, even when it should. +------------------------------------------------------------------------------- + +Bash deliberately excludes negated return values from causing a pipeline to exit (see bash's `-e` option). +Use `run !` on Bats 1.5.0 and above. For older bats versions, use one of `! x || false` or `run` with `[ $status != 0 ]`. + +If the negated command is the final statement in a test, that final statement's (negated) exit status will propagate through to the test's return code as usual. +Negated statements of one of the correct forms mentioned above will explicitly fail the test when the pipeline returns true, regardless of where they occur in the test. + +I cannot register a test multiple times via for loop. +----------------------------------------------------- + +The usual bats tests (`@test`) are preprocessed into functions. +Wrapping them into a for loop only redeclares this function. + +If you are interested in registering multiple calls to the same function, contribute your wishes to issue `#306 `_. + +I cannot pass parameters to test or .bats files. +------------------------------------------------ + +Especially while using bats via shebang: + +.. code-block:: bash + + #!/usr/bin/env bats + + @test "test" { + # ... + } + +You could be tempted to pass parameters to the test invocation like `./test.bats param1 param2`. +However, bats does not support passing parameters to files or tests. +If you need such a feature, please let us know about your usecase. + +As a workaround you can use environment variables to pass parameters. + +Why can't my function return results via a variable when using `run`? +--------------------------------------------------------------------- + +The `run` function executes its command in a subshell which means the changes to variables won't be available in the calling shell. + +If you want to test these functions, you should call them without `run`. + +`run` doesn't fail, although the same command without `run` does. +----------------------------------------------------------------- + +`run` is a wrapper that always succeeds. The wrapped command's exit code is stored in `$status` and the stdout/stderr in `$output`. +If you want to fail the test, you should explicitly check `$status` or omit `run`. See also `when not to use run `_. + +`load` won't load my `.sh` files. +--------------------------------- + +`load` is intended as an internal helper function that always loads `.bash` files (by appending this suffix). +If you want to load an `.sh` file, you can simple `source` it. + +I can't lint/shell-format my bats tests. +---------------------------------------- + +Bats uses a custom syntax for annotating tests (`@test`) that is not bash compliant. +Therefore, standard bash tooling won't be able to interact directly with `.bats` files. +Shellcheck supports bats' native syntax as of version 0.7. + +Additionally, there is bash compatible syntax for tests: + +.. code-block:: bash + + function bash_compliant_function_name_as_test_name { # @test + # your code + } + + +The output (stdout/err) from commands under `run` is not visible in failed tests. +--------------------------------------------------------------------------------- + +By default, `run` only stores stdout/stderr in `$output` (and `${lines[@]}`). +If you want to see this output, you either should use bat-assert's assertions or have to print `$output` before the check that fails. + +My piped command does not work under run. +----------------------------------------- + +Be careful with using pipes and with `run`. While your mind model of `run` might wrap the whole command behind it, bash's parser won't + +.. code-block:: bash + + run echo foo | grep bar + +Won't `run (echo foo | grep bar)` but will `(run echo foo) | grep bar`. If you need to incorporate pipes, you either should do + +.. code-block:: bash + + run bash -c 'echo foo | grep bar' + +or use a function to wrap the pipe in: + +.. code-block:: bash + + fun_with_pipes() { + echo foo | grep bar + } + + run fun_with_pipes + +`[[ ]]` (or `(( ))` did not fail my test +---------------------------------------- + +The `set -e` handling of `[[ ]]` and `(( ))` changed in Bash 4.1. Older versions, like 3.2 on MacOS, +don't abort the test when they fail, unless they are the last command before the (test) function returns, +making their exit code the return code. + +`[ ]` does not suffer from this, but is no replacement for all `[[ ]]` usecases. Appending ` || false` will work in all cases. + +Background tasks prevent the test run from terminating when finished +-------------------------------------------------------------------- + +When running a task in background, it will inherit the opened FDs of the process it was forked from. +This means that the background task forked from a Bats test will hold the FD for the pipe to the formatter that prints to the terminal, +thus keeping it open until the background task finished. +Due to implementation internals of Bats and bash, this pipe might be held in multiple FDs which all have to be closed by the background task. + +You can use `close_non_std_fds from `test/fixtures/bats/issue-205.bats` in the background job to close all FDs except stdin, stdout and stderr, thus solving the problem. +More details about the issue can be found in [#205](https://github.com/bats-core/bats-core/issues/205#issuecomment-973572596). diff --git a/tooling/bats-core/docs/source/index.rst b/tooling/bats-core/docs/source/index.rst new file mode 100644 index 00000000000000..5b41aa690eb59e --- /dev/null +++ b/tooling/bats-core/docs/source/index.rst @@ -0,0 +1,22 @@ +Welcome to bats-core's documentation! +===================================== + +Bats (Bash Automated Testing System) is a `TAP `_-compliant testing framework for Bash 3.2 or above. It provides a simple way to verify that the UNIX programs you write behave as expected. + +Bats is most useful when testing software written in Bash, but you can use it to test any UNIX program. + +Versions before v1.2.1 are documented over in `docs/versions.md `_. + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + tutorial + installation + usage + docker-usage + writing-tests + gotchas + faq + warnings/index + support-matrix diff --git a/tooling/bats-core/docs/source/installation.rst b/tooling/bats-core/docs/source/installation.rst new file mode 100644 index 00000000000000..583a36a42f8694 --- /dev/null +++ b/tooling/bats-core/docs/source/installation.rst @@ -0,0 +1,138 @@ + +Installation +============ + +Linux: Distribution Package Manager +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Following Linux distributions provide Bats via their package manager: + +* Arch Linux: `extra/bats `__ +* Alpine Linux: `bats `__ +* Debian Linux: `shells/bats `__ +* Fedora Linux: `rpms/bats `__ +* Gentoo Linux `dev-util/bats `__ +* OpenSUSE Linux: `bats `__ +* Ubuntu Linux `shells/bats `__ + +**Note**: Bats versions pre 1.0 are from sstephenson's original project. +Consider using one of the other installation methods below to get the latest Bats release. +The test matrix above only applies to the latest Bats version. + +If your favorite distribution is not listed above, +you can try one of the following package managers or install from source. + +MacOS: Homebrew +^^^^^^^^^^^^^^^ + +On macOS, you can install `Homebrew `__ if you haven't already, +then run: + +.. code-block:: bash + + $ brew install bats-core + +Any OS: npm +^^^^^^^^^^^ + +You can install the `Bats npm package `__ via: + +.. code-block:: + + # To install globally: + $ npm install -g bats + + # To install into your project and save it as one of the "devDependencies" in + # your package.json: + $ npm install --save-dev bats + +Any OS: Installing Bats from source +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Check out a copy of the Bats repository. Then, either add the Bats ``bin`` +directory to your ``$PATH``\ , or run the provided ``install.sh`` command with the +location to the prefix in which you want to install Bats. For example, to +install Bats into ``/usr/local``\ , + +.. code-block:: + + $ git clone https://github.com/bats-core/bats-core.git + $ cd bats-core + $ ./install.sh /usr/local + + +**Note:** You may need to run ``install.sh`` with ``sudo`` if you do not have +permission to write to the installation prefix. + +Windows: Installing Bats from source via Git Bash +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Check out a copy of the Bats repository and install it to ``$HOME``. This +will place the ``bats`` executable in ``$HOME/bin``\ , which should already be +in ``$PATH``. + +.. code-block:: + + $ git clone https://github.com/bats-core/bats-core.git + $ cd bats-core + $ ./install.sh $HOME + + +Running Bats in Docker +^^^^^^^^^^^^^^^^^^^^^^ + +There is an official image on the Docker Hub: + +.. code-block:: + + $ docker run -it bats/bats:latest --version + + +Building a Docker image +~~~~~~~~~~~~~~~~~~~~~~~ + +Check out a copy of the Bats repository, then build a container image: + +.. code-block:: + + $ git clone https://github.com/bats-core/bats-core.git + $ cd bats-core + $ docker build --tag bats/bats:latest . + + +This creates a local Docker image called ``bats/bats:latest`` based on `Alpine +Linux `__ +(to push to private registries, tag it with another organisation, e.g. +``my-org/bats:latest``\ ). + +To run Bats' internal test suite (which is in the container image at +``/opt/bats/test``\ ): + +.. code-block:: + + $ docker run -it bats/bats:latest /opt/bats/test + + +To run a test suite from a directory called ``test`` in the current directory of +your local machine, mount in a volume and direct Bats to its path inside the +container: + +.. code-block:: + + $ docker run -it -v "${PWD}:/code" bats/bats:latest test + + +.. + + ``/code`` is the working directory of the Docker image. "${PWD}/test" is the + location of the test directory on the local machine. + + +This is a minimal Docker image. If more tools are required this can be used as a +base image in a Dockerfile using ``FROM ``. In the future there may +be images based on Debian, and/or with more tools installed (\ ``curl`` and ``openssl``\ , +for example). If you require a specific configuration please search and +1 an +issue or `raise a new issue `__. + +Further usage examples are in +`the wiki `__. diff --git a/tooling/bats-core/docs/source/requirements.txt b/tooling/bats-core/docs/source/requirements.txt new file mode 100644 index 00000000000000..b61574d1e1732c --- /dev/null +++ b/tooling/bats-core/docs/source/requirements.txt @@ -0,0 +1,2 @@ +sphinxcontrib-programoutput +recommonmark \ No newline at end of file diff --git a/tooling/bats-core/docs/source/support-matrix.rst b/tooling/bats-core/docs/source/support-matrix.rst new file mode 100644 index 00000000000000..e25f30e0425532 --- /dev/null +++ b/tooling/bats-core/docs/source/support-matrix.rst @@ -0,0 +1,26 @@ +Support Matrix +============== + +Supported Bash versions +^^^^^^^^^^^^^^^^^^^^^^^ + +The following is a list of Bash versions that are currently supported by Bats and verified through automated tests: + + * 3.2.57(1) (macOS's highest bundled version) + * 4.0, 4.1, 4.2, 4.3, 4.4 + * 5.0, 5.1, 5.2 + +Supported Operating systems +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following Operating Systems are supported and tested automatically (CI) or manually during development: + + * Linux: Alpine (CI), Alma 8 (CI), Arch Linux (manual), Ubuntu 22.04/24.04 (CI) + * FreeBSD: 11 (CI) + * macOS: 11 (CI), 12 (CI) + * Windows: Server 2019 (CI), 10 (manual) + + * Git for Windows Bash (MSYS2 based) + * Windows Subsystem for Linux + * MSYS2 + * Cygwin diff --git a/tooling/bats-core/docs/source/tutorial.rst b/tooling/bats-core/docs/source/tutorial.rst new file mode 100644 index 00000000000000..663cf1eaa7934b --- /dev/null +++ b/tooling/bats-core/docs/source/tutorial.rst @@ -0,0 +1,661 @@ +Tutorial +======== + +This tutorial is intended for beginners with bats and possibly bash. +Make sure to also read the list of gotchas and the faq. + +For this tutorial we are assuming you already have a project in a git repository and want to add tests. +Ultimately they should run in the CI environment but will also be started locally during development. + +.. + TODO: link to example repository? + +Quick installation +------------------ + +Since we already have an existing git repository, it is very easy to include bats and its libraries as submodules. +We are aiming for following filesystem structure: + +.. code-block:: + + src/ + project.sh + ... + test/ + bats/ <- submodule + test_helper/ + bats-support/ <- submodule + bats-assert/ <- submodule + test.bats + ... + +So we start from the project root: + +.. code-block:: console + + git submodule add https://github.com/bats-core/bats-core.git test/bats + git submodule add https://github.com/bats-core/bats-support.git test/test_helper/bats-support + git submodule add https://github.com/bats-core/bats-assert.git test/test_helper/bats-assert + +Your first test +--------------- + +Now we want to add our first test. + +In the tutorial repository, we want to build up our project in a TDD fashion. +Thus, we start with an empty project and our first test is to just run our (nonexistent) shell script. + +We start by creating a new test file `test/test.bats` + +.. code-block:: bash + + @test "can run our script" { + ./project.sh + } + +and run it by + +.. code-block:: console + + $ ./test/bats/bin/bats test/test.bats + ✗ can run our script + (in test file test/test.bats, line 2) + `./project.sh' failed with status 127 + /tmp/bats-run-19605/bats.19627.src: line 2: ./project.sh: No such file or directory + + 1 test, 1 failure + +Okay, our test is red. Obviously, the project.sh doesn't exist, so we create the file `src/project.sh`: + +.. code-block:: console + + mkdir src/ + echo '#!/usr/bin/env bash' > src/project.sh + chmod a+x src/project.sh + +A new test run gives us + +.. code-block:: console + + $ ./test/bats/bin/bats test/test.bats + ✗ can run our script + (in test file test/test.bats, line 2) + `./project.sh' failed with status 127 + /tmp/bats-run-19605/bats.19627.src: line 2: ./project.sh: No such file or directory + + 1 test, 1 failure + +Oh, we still used the wrong path. No problem, we just need to use the correct path to `project.sh`. +Since we're still in the same directory as when we started `bats`, we can simply do: + +.. code-block:: bash + + @test "can run our script" { + ./src/project.sh + } + +and get: + +.. code-block:: console + + $ ./test/bats/bin/bats test/test.bats + ✓ can run our script + + 1 test, 0 failures + +Yesss! But that victory feels shallow: What if somebody less competent than us starts bats from another directory? + +Let's do some setup +------------------- + +The obvious solution to becoming independent of `$PWD` is using some fixed anchor point in the filesystem. +We can use the path to the test file itself as an anchor and rely on the internal project structure. +Since we are lazy people and want to treat our project's files as first class citizens in the executable world, we will also put them on the `$PATH`. +Our new `test/test.bats` now looks like this: + +.. code-block:: bash + + setup() { + # get the containing directory of this file + # use $BATS_TEST_FILENAME instead of ${BASH_SOURCE[0]} or $0, + # as those will point to the bats executable's location or the preprocessed file respectively + DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" + # make executables in src/ visible to PATH + PATH="$DIR/../src:$PATH" + } + + @test "can run our script" { + # notice the missing ./ + # As we added src/ to $PATH, we can omit the relative path to `src/project.sh`. + project.sh + } + +still giving us: + +.. code-block:: console + + $ ./test/bats/bin/bats test/test.bats + ✓ can run our script + + 1 test, 0 failures + +It still works as expected. This is because the newly added `setup` function put the absolute path to `src/` onto `$PATH`. +This setup function is automatically called before each test. +Therefore, our test could execute `project.sh` directly, without using a (relative) path. + +.. important:: + + The `setup` function will be called before each individual test in the file. + Each file can only define one setup function for all tests in the file. + However, the setup functions can differ between different files. + +Dealing with output +------------------- + +Okay, we have a green test but our executable does not do anything useful. +To keep things simple, let us start with an error message. Our new `src/project.sh` now reads: + +.. code-block:: bash + + #!/usr/bin/env bash + + echo "Welcome to our project!" + + echo "NOT IMPLEMENTED!" >&2 + exit 1 + +And gives is this test output: + +.. code-block:: console + + $ ./test/bats/bin/bats test/test.bats + ✗ can run our script + (in test file test/test.bats, line 11) + `project.sh' failed + Welcome to our project! + NOT IMPLEMENTED! + + 1 test, 1 failure + +Okay, our test failed, because we now exit with 1 instead of 0. +Additionally, we see the stdout and stderr of the failing program. + +Our goal now is to retarget our test and check that we get the welcome message. +bats-assert gives us some help with this, so we should now load it (and its dependency bats-support), +so we change `test/test.bats` to + +.. code-block:: bash + + setup() { + load 'test_helper/bats-support/load' + load 'test_helper/bats-assert/load' + # ... the remaining setup is unchanged + + # get the containing directory of this file + # use $BATS_TEST_FILENAME instead of ${BASH_SOURCE[0]} or $0, + # as those will point to the bats executable's location or the preprocessed file respectively + DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )" + # make executables in src/ visible to PATH + PATH="$DIR/../src:$PATH" + } + + @test "can run our script" { + run project.sh # notice `run`! + assert_output 'Welcome to our project!' + } + +which gives us the following test output: + +.. code-block:: console + + $ LANG=C ./test/bats/bin/bats test/test.bats + ✗ can run our script + (from function `assert_output' in file test/test_helper/bats-assert/src/assert_output.bash, line 194, + in test file test/test.bats, line 14) + `assert_output 'Welcome to our project!'' failed + + -- output differs -- + expected (1 lines): + Welcome to our project! + actual (2 lines): + Welcome to our project! + NOT IMPLEMENTED! + -- + + + 1 test, 1 failure + +The first change in this output is the failure description. We now fail on assert_output instead of the call itself. +We prefixed our call to `project.sh` with `run`, which is a function provided by bats that executes the command it gets passed as parameters. +Then, `run` sucks up the stdout and stderr of the command it ran and stores it in `$output`, stores the exit code in `$status` and returns 0. +This means `run` never fails the test and won't generate any context/output in the log of a failed test on its own. + +Marking the test as failed and printing context information is up to the consumers of `$status` and `$output`. +`assert_output` is such a consumer, it compares `$output` to the parameter it got and tells us quite succinctly that it did not match in this case. + +For our current test we don't care about any other output or the error message, so we want it gone. +`grep` is always at our fingertips, so we tape together this ramshackle construct + +.. code-block:: bash + + run project.sh 2>&1 | grep Welcome + +which gives us the following test result: + +.. code-block:: console + + $ ./test/bats/bin/bats test/test.bats + ✗ can run our script + (in test file test/test.bats, line 13) + `run project.sh | grep Welcome' failed + + 1 test, 1 failure + +Huh, what is going on? Why does it fail the `run` line again? + +This is a common mistake that can happen when our mind parses the file differently than the bash parser. +`run` is just a function, so the pipe won't actually be forwarded into the function. Bash reads this as `(run project.sh) | grep Welcome`, +instead of our intended `run (project.sh | grep Welcome)`. + +Unfortunately, the latter is not valid bash syntax, so we have to work around it, e.g. by using a function: + +.. code-block:: bash + + get_projectsh_welcome_message() { + project.sh 2>&1 | grep Welcome + } + + @test "Check welcome message" { + run get_projectsh_welcome_message + assert_output 'Welcome to our project!' + } + +Now our test passes again but having to write a function each time we want only a partial match does not accommodate our laziness. +Isn't there an app for that? Maybe we should look at the documentation? + + Partial matching can be enabled with the --partial option (-p for short). When used, the assertion fails if the expected substring is not found in $output. + + -- the documentation for `assert_output `_ + +Okay, so maybe we should try that: + +.. code-block:: bash + + @test "Check welcome message" { + run project.sh + assert_output --partial 'Welcome to our project!' + } + +Aaannnd ... the test stays green. Yay! + +There are many other asserts and options but this is not the place for all of them. +Skimming the documentation of `bats-assert `_ will give you a good idea what you can do. +You should also have a look at the other helper libraries `here `_ like `bats-file `_, +to avoid reinventing the wheel. + + +Cleaning up your mess +--------------------- + +Often our setup or tests leave behind some artifacts that clutter our test environment. +You can define a `teardown` function which will be called after each test, regardless whether it failed or not. + +For example, we now want our project.sh to only show the welcome message on the first invocation. +So we change our test to this: + +.. code-block:: bash + + @test "Show welcome message on first invocation" { + run project.sh + assert_output --partial 'Welcome to our project!' + + run project.sh + refute_output --partial 'Welcome to our project!' + } + +This test fails as expected: + +.. code-block:: console + + $ ./test/bats/bin/bats test/test.bats + ✗ Show welcome message on first invocation + (from function `refute_output' in file test/test_helper/bats-assert/src/refute_output.bash, line 189, + in test file test/test.bats, line 17) + `refute_output --partial 'Welcome to our project!'' failed + + -- output should not contain substring -- + substring (1 lines): + Welcome to our project! + output (2 lines): + Welcome to our project! + NOT IMPLEMENTED! + -- + + + 1 test, 1 failure + +Now, to get the test green again, we want to store the information that we already ran in the file `/tmp/bats-tutorial-project-ran`, +so our `src/project.sh` becomes: + +.. code-block:: bash + + #!/usr/bin/env bash + + FIRST_RUN_FILE=/tmp/bats-tutorial-project-ran + + if [[ ! -e "$FIRST_RUN_FILE" ]]; then + echo "Welcome to our project!" + touch "$FIRST_RUN_FILE" + fi + + echo "NOT IMPLEMENTED!" >&2 + exit 1 + +And our test says: + +.. code-block:: console + + $ ./test/bats/bin/bats test/test.bats + ✓ Show welcome message on first invocation + + 1 test, 0 failures + +Nice, we're done, or are we? Running the test again now gives: + +.. code-block:: console + + $ ./test/bats/bin/bats test/test.bats + ✗ Show welcome message on first invocation + (from function `assert_output' in file test/test_helper/bats-assert/src/assert_output.bash, line 186, + in test file test/test.bats, line 14) + `assert_output --partial 'Welcome to our project!'' failed + + -- output does not contain substring -- + substring : Welcome to our project! + output : NOT IMPLEMENTED! + -- + + + 1 test, 1 failure + +Now the first assert failed, because of the leftover `$FIRST_RUN_FILE` from the last test run. + +Luckily, bats offers the `teardown` function, which can take care of that, we add the following code to `test/test.bats`: + +.. code-block:: bash + + teardown() { + rm -f /tmp/bats-tutorial-project-ran + } + +Now running the test again first give us the same error, as the teardown has not run yet. +On the second try we get a clean `/tmp` folder again and our test passes consistently now. + +It is worth noting that we could do this `rm` in the test code itself but it would get skipped on failures. + +.. important:: + + A test ends at its first failure. None of the subsequent commands in this test will be executed. + The `teardown` function runs after each individual test in a file, regardless of test success or failure. + Similarly to `setup`, each `.bats` file can have its own `teardown` function which will be the same for all tests in the file. + +Test what you can +----------------- + +Sometimes tests rely on the environment to provide infrastructure that is needed for the test. +If not all test environments provide this infrastructure but we still want to test on them, +it would be unhelpful to get errors on parts that are not testable. + +Bats provides you with the `skip` command which can be used in `setup` and `test`. + +.. tip:: + + You should `skip` as early as you know it does not make sense to continue. + +In our example project we rewrite the welcome message test to `skip` instead of doing cleanup: + +.. code-block:: bash + + teardown() { + : # Look Ma! No cleanup! + } + + @test "Show welcome message on first invocation" { + if [[ -e /tmp/bats-tutorial-project-ran ]]; then + skip 'The FIRST_RUN_FILE already exists' + fi + + run project.sh + assert_output --partial 'Welcome to our project!' + + run project.sh + refute_output --partial 'Welcome to our project!' + } + +The first test run still works due to the cleanup from the last round. However, our second run gives us: + +.. code-block:: console + + $ ./test/bats/bin/bats test/test.bats + - Show welcome message on first invocation (skipped: The FIRST_RUN_FILE already exists) + + 1 test, 0 failures, 1 skipped + +.. important:: + + Skipped tests won't fail a test suite and are counted separately. + No test command after `skip` will be executed. If an error occurs before `skip`, the test will fail. + An optional reason can be passed to `skip` and will be printed in the test output. + +Setting up a multifile test suite +--------------------------------- + +With a growing project, putting all tests into one file becomes unwieldy. +For our example project, we will extract functionality into the additional file `src/helper.sh`: + +.. code-block:: bash + + #!/usr/bin/env bash + + _is_first_run() { + local FIRST_RUN_FILE=${1-/tmp/bats-tutorial-project-ran} + if [[ ! -e "$FIRST_RUN_FILE" ]]; then + touch "$FIRST_RUN_FILE" + return 0 + fi + return 1 + } + +This allows for testing it separately in a new file `test/helper.bats`: + +.. code-block:: bash + + setup() { + load 'test_helper/common-setup' + _common_setup + + source "$PROJECT_ROOT/src/helper.sh" + } + + teardown() { + rm -f "$NON_EXISTENT_FIRST_RUN_FILE" + rm -f "$EXISTING_FIRST_RUN_FILE" + } + + @test "Check first run" { + NON_EXISTENT_FIRST_RUN_FILE=$(mktemp -u) # only create the name, not the file itself + + assert _is_first_run "$NON_EXISTENT_FIRST_RUN_FILE" + refute _is_first_run "$NON_EXISTENT_FIRST_RUN_FILE" + refute _is_first_run "$NON_EXISTENT_FIRST_RUN_FILE" + + EXISTING_FIRST_RUN_FILE=$(mktemp) + refute _is_first_run "$EXISTING_FIRST_RUN_FILE" + refute _is_first_run "$EXISTING_FIRST_RUN_FILE" + } + +Since the setup function would have duplicated much of the other files', we split that out into the file `test/test_helper/common-setup.bash`: + +.. code-block:: bash + + #!/usr/bin/env bash + + _common_setup() { + load 'test_helper/bats-support/load' + load 'test_helper/bats-assert/load' + # get the containing directory of this file + # use $BATS_TEST_FILENAME instead of ${BASH_SOURCE[0]} or $0, + # as those will point to the bats executable's location or the preprocessed file respectively + PROJECT_ROOT="$( cd "$( dirname "$BATS_TEST_FILENAME" )/.." >/dev/null 2>&1 && pwd )" + # make executables in src/ visible to PATH + PATH="$PROJECT_ROOT/src:$PATH" + } + +with the following `setup` in `test/test.bats`: + +.. code-block:: bash + + setup() { + load 'test_helper/common-setup' + _common_setup + } + +Please note, that we gave our helper the extension `.bash`, which is automatically appended by `load`. + +.. important:: + + `load` automatically tries to append `.bash` to its argument. + +In our new `test/helper.bats` we can see, that loading `.sh` is simply done via `source`. + +.. tip:: + + Avoid using `load` and `source` outside of any functions. + If there is an error in the test file's "free code", the diagnostics are much worse than for code in `setup` or `@test`. + +With the new changes in place, we can run our tests again. However, our previous run command does not include the new file. +You could add the new file to the parameter list, e.g. by running `./test/bats/bin/bats test/*.bats`. +However, bats also can handle directories: + +.. code-block:: console + + $ ./test/bats/bin/bats test/ + ✓ Check first run + - Show welcome message on first invocation (skipped: The FIRST_RUN_FILE already exists) + + 2 tests, 0 failures, 1 skipped + +In this mode, bats will pick up all `.bats` files in the directory it was given. There is an additional `-r` switch that will recursively search for more `.bats` files. +However, in our project layout this would pick up the test files of bats itself from `test/bats/test`. We don't have test subfolders anyways, so we can do without `-r`. + + +Avoiding costly repeated setups +------------------------------- + +We already have seen the `setup` function in use, which is called before each test. +Sometimes our setup is very costly, such as booting up a service just for testing. +If we can reuse the same setup across multiple tests, we might want to do only one setup before all these tests. + +This usecase is exactly what the `setup_file` function was created for. +It can be defined per file and will run before all tests of the respective file. +Similarly, we have `teardown_file`, which will run after all tests of the file, even when you abort a test run or a test failed. + +As an example, we want to add an echo server capability to our project. First, we add the following `server.bats` to our suite: + +.. code-block:: bash + + setup_file() { + load 'test_helper/common-setup' + _common_setup + PORT=$(project.sh start-echo-server 2>&1 >/dev/null) + export PORT + } + + @test "server is reachable" { + nc -z localhost "$PORT" + } + +Which will obviously fail: + +Note that `export PORT` to make it visible to the test! +Running this gives us: + +.. + TODO: Update this example with fixed test name reporting from setup_file? (instead of "✗ ") + +.. code-block:: console + + $ ./test/bats/bin/bats test/server.bats + ✗ + (from function `setup_file' in test file test/server.bats, line 4) + `PORT=$(project.sh start-echo-server >/dev/null 2>&1)' failed + + 1 test, 1 failure + +Now that we got our red test, we need to get it green again. +Our new `project.sh` now ends with: + +.. code-block:: bash + + case $1 in + start-echo-server) + echo "Starting echo server" + PORT=2000 + ncat -l $PORT -k -c 'xargs -n1 echo' 2>/dev/null & # don't keep open this script's stderr + echo $! > /tmp/project-echo-server.pid + echo "$PORT" >&2 + ;; + *) + echo "NOT IMPLEMENTED!" >&2 + exit 1 + ;; + esac + +and the tests now say + +.. code-block:: console + + $ LANG=C ./test/bats/bin/bats test/server.bats + ✓ server is reachable + + 1 test, 0 failures + +However, running this a second time gives: + +.. code-block:: console + + $ ./test/bats/bin/bats test/server.bats + ✗ server is reachable + (in test file test/server.bats, line 14) + `nc -z -w 2 localhost "$PORT"' failed + 2000 + Ncat: bind to :::2000: Address already in use. QUITTING. + nc: port number invalid: 2000 + Ncat: bind to :::2000: Address already in use. QUITTING. + + 1 test, 1 failure + +Obviously, we did not turn off our server after testing. +This is a task for `teardown_file` in `server.bats`: + +.. code-block:: bash + + teardown_file() { + project.sh stop-echo-server + } + +Our `project.sh` should also get the new command: + +.. code-block:: bash + + stop-echo-server) + kill "$(< "/tmp/project-echo-server.pid")" + rm /tmp/project-echo-server.pid + ;; + +Now starting our tests again will overwrite the .pid file with the new instance's, so we have to do manual cleanup once. +From now on, our test should clean up after itself. + +.. note:: + + `teardown_file` will run regardless of tests failing or succeeding. diff --git a/tooling/bats-core/docs/source/usage.md b/tooling/bats-core/docs/source/usage.md new file mode 100644 index 00000000000000..bdbe407d50233c --- /dev/null +++ b/tooling/bats-core/docs/source/usage.md @@ -0,0 +1,114 @@ +# Usage + +Bats comes with two manual pages. After installation you can view them with `man +1 bats` (usage manual) and `man 7 bats` (writing test files manual). Also, you +can view the available command line options that Bats supports by calling Bats +with the `-h` or `--help` options. These are the options that Bats currently +supports: + +``` eval_rst +.. program-output:: ../../bin/bats --help +``` + +To run your tests, invoke the `bats` interpreter with one or more paths to test +files ending with the `.bats` extension, or paths to directories containing test +files. (`bats` will only execute `.bats` files at the top level of each +directory; it will not recurse unless you specify the `-r` flag.) + +Test cases from each file are run sequentially and in isolation. If all the test +cases pass, `bats` exits with a `0` status code. If there are any failures, +`bats` exits with a `1` status code. + +When you run Bats from a terminal, you'll see output as each test is performed, +with a check-mark next to the test's name if it passes or an "X" if it fails. + +```text +$ bats addition.bats + ✓ addition using bc + ✓ addition using dc + +2 tests, 0 failures +``` + +If Bats is not connected to a terminal—in other words, if you run it from a +continuous integration system, or redirect its output to a file—the results are +displayed in human-readable, machine-parsable [TAP format][tap-format]. + +You can force TAP output from a terminal by invoking Bats with the `--formatter tap` +option. + +```text +$ bats --formatter tap addition.bats +1..2 +ok 1 addition using bc +ok 2 addition using dc +``` + +With `--formatter junit`, it is possible +to output junit-compatible report files. + +```text +$ bats --formatter junit addition.bats +1..2 +ok 1 addition using bc +ok 2 addition using dc +``` + +If you have your own formatter, you can use an absolute path to the executable +to use it: + +```bash +$ bats --formatter /absolute/path/to/my-formatter addition.bats +addition using bc WORKED +addition using dc FAILED +``` + +You can also generate test report files via `--report-formatter` which accepts +the same options as `--formatter`. By default, the file is stored in the current +workdir. However, it may be placed elsewhere by specifying the `--output` flag. + +```text +$ bats --report-formatter junit addition.bats --output /tmp +1..2 +ok 1 addition using bc +ok 2 addition using dc + +$ cat /tmp/report.xml + + + + + + + +``` + +## Parallel Execution + +``` eval_rst +.. versionadded:: 1.0.0 +``` + +By default, Bats will execute your tests serially. However, Bats supports +parallel execution of tests (provided you have [GNU parallel][gnu-parallel] or +a compatible replacement installed) using the `--jobs` parameter. This can +result in your tests completing faster (depending on your tests and the testing +hardware). + +Ordering of parallelised tests is not guaranteed, so this mode may break suites +with dependencies between tests (or tests that write to shared locations). When +enabling `--jobs` for the first time be sure to re-run bats multiple times to +identify any inter-test dependencies or non-deterministic test behaviour. + +When parallelizing, the results of a file only become visible after it has been finished. +You can use `--no-parallelize-across-files` to get immediate output at the cost of reduced +overall parallelity, as parallelization will only happen within files and files will be run +sequentially. + +If you have files where tests within the file would interfere with each other, you can use +`--no-parallelize-within-files` to disable parallelization within all files. +If you want more fine-grained control, you can `export BATS_NO_PARALLELIZE_WITHIN_FILE=true` in `setup_file()` +or outside any function to disable parallelization only within the containing file. + +[tap-format]: https://testanything.org +[gnu-parallel]: https://www.gnu.org/software/parallel/ diff --git a/tooling/bats-core/docs/source/warnings/BW01.rst b/tooling/bats-core/docs/source/warnings/BW01.rst new file mode 100644 index 00000000000000..8ae8bb67db604c --- /dev/null +++ b/tooling/bats-core/docs/source/warnings/BW01.rst @@ -0,0 +1,17 @@ +BW01: `run`'s command `` exited with code 127, indicating 'Command not found'. Use run's return code checks, e.g. `run -127`, to fix this message. +=========================================================================================================================================================== + +Due to `run`'s default behavior of always succeeding, errors in the command string can remain hidden from the user, e.g.[here](https://github.com/bats-core/bats-core/issues/578). +As a proxy for this problem, the return code is checked for value 127 ("Command not found"). + +How to fix +---------- + +If your command should actually return code 127, then you can simply use `run -127 ` to state your intent and the message will go away. + +If your command should not return 127, you should fix the problem with the command. +Take a careful look at the command string in the warning message, to see if it contains code that you did not intend to run. + +If your command should sometimes return 127, but never 0, you can use `run ! `. + +If your command can sometimes return 127 and sometimes 0, the please submit an issue. \ No newline at end of file diff --git a/tooling/bats-core/docs/source/warnings/BW02.rst b/tooling/bats-core/docs/source/warnings/BW02.rst new file mode 100644 index 00000000000000..a58c395a2d9ba1 --- /dev/null +++ b/tooling/bats-core/docs/source/warnings/BW02.rst @@ -0,0 +1,46 @@ +BW02: requires at least BATS_VERSION=. Use `bats_require_minimum_version ` to fix this message. +=========================================================================================================================== + +Using a feature that is only available starting with a certain version can be a problem when your tests also run on older versions of Bats. +In most cases, running this code in older versions will generate an error due to a missing command. +However, in cases like `run`'s where old version simply take all parameters as command to execute, the failure can be silent. + +How to fix BW02 +--------------- + +When you encounter this warning, you can simply guard your code with `bats_require_minimum_version ` as the message says. +For example, consider the following code: + +.. code-block:: bash + + @test test { + bats_require_minimum_version 1.5.0 + # pre 1.5.0 the flag --separate-stderr would be interpreted as command to run + run --separate-stderr some-command + [ $output = "blablabla" ] + } + + +The call to `bats_require_minimum_version` can be put anywhere before the warning generating command, even in `setup`, `setup_file`, or even outside any function. +This can be used to give fine control over the version dependencies: + +.. code-block:: bash + + @test test { + bats_require_minimum_version 1.5.0 + # pre 1.5.0 the flag --separate-stderr would be interpreted as command to run + run --separate-stderr some-command + [ $output = "blablabla" ] + } + + @test test2 { + run some-other-command # no problem executing on earlier version + } + + +If the above code is executed on a system with a `BATS_VERSION` pre 1.5.0, the first test will fail on `bats_require_minimum_version 1.5.0`. + +Instances: +---------- + +- run's non command parameters like `--keep-empty-lines` are only available since 1.5.0 \ No newline at end of file diff --git a/tooling/bats-core/docs/source/warnings/BW03.rst b/tooling/bats-core/docs/source/warnings/BW03.rst new file mode 100644 index 00000000000000..fb79d56d66a843 --- /dev/null +++ b/tooling/bats-core/docs/source/warnings/BW03.rst @@ -0,0 +1,15 @@ +BW03: `setup_suite` is visible to test file '', but was not executed. It belongs into 'setup_suite.bash' to be picked up automatically. +============================================================================================================================================= + +In contrast to the other setup functions, `setup_suite` must not be defined in `*.bats` files but in `setup_suite.bash`. +When a file is executed and sees `setup_suite` defined but not run before the tests, this warning will be printed. + +How to fix BW03 +--------------- + +The fix depends on your actual intention. There are basically two cases: + +1. You want a setup before all tests and accidentally put `setup_suite` into a test file instead of `setup_suite.bash`. + Simply move `setup_suite` (and `teardown_suite`!) into `setup_suite.bash`. +2. You did not mean to run a setup before any test but need to defined a function named `setup_suite` in your test file. + In this case, you can silence this warning by assigning `BATS_SETUP_SUITE_COMPLETED='suppress BW03'`. \ No newline at end of file diff --git a/tooling/bats-core/docs/source/warnings/index.rst b/tooling/bats-core/docs/source/warnings/index.rst new file mode 100644 index 00000000000000..957fc4305fdbfd --- /dev/null +++ b/tooling/bats-core/docs/source/warnings/index.rst @@ -0,0 +1,28 @@ +Warnings +======== + +Starting with version 1.7.0 Bats shows warnings about issues it found during the test run. +They are printed on stderr after all other output: + +.. code-block:: bash + + BW01.bats + ✓ Trigger BW01 + + 1 test, 0 failures + + + The following warnings were encountered during tests: + BW01: `run`'s command `=0 actually-intended-command with some args` exited with code 127, indicating 'Command not found'. Use run's return code checks, e.g. `run -127`, to fix this message. + (from function `run' in file lib/bats-core/test_functions.bash, line 299, + in test file test/fixtures/warnings/BW01.bats, line 3) + +A warning will not make a successful run fail but should be investigated and taken seriously, since it hints at a possible error. + +Currently, Bats emits the following warnings: + +.. toctree:: + + BW01 + BW02 + BW03 \ No newline at end of file diff --git a/tooling/bats-core/docs/source/writing-tests.md b/tooling/bats-core/docs/source/writing-tests.md new file mode 100644 index 00000000000000..bbe178014c4403 --- /dev/null +++ b/tooling/bats-core/docs/source/writing-tests.md @@ -0,0 +1,699 @@ +# Writing tests + +Each Bats test file is evaluated _n+1_ times, where _n_ is the number of +test cases in the file. The first run counts the number of test cases, +then iterates over the test cases and executes each one in its own +process. + +For more details about how Bats evaluates test files, see [Bats Evaluation +Process][bats-eval] on the wiki. + +For sample test files, see [examples](https://github.com/bats-core/bats-core/tree/master/docs/examples). + +[bats-eval]: https://github.com/bats-core/bats-core/wiki/Bats-Evaluation-Process + +## Tagging tests + +Starting with version 1.8.0, Bats comes with a tagging system that allows users +to categorize their tests and filter according to those categories. + +Each test has a list of tags attached to it. Without specification, this list is empty. +Tags can be defined in two ways. The first being `# bats test_tags=`: + +```bash +# bats test_tags=tag:1, tag:2, tag:3 +@test "first test" { + # ... +} + +@test "second test" { + # ... +} +``` + +These tags (`tag:1`, `tag:2`, `tag:3`) will be attached to the test `first test`. +The second test will have no tags attached. Values defined in the `# bats test_tags=` +directive will be assigned to the next `@test` that is being encountered in the +file and forgotten after that. Only the value of the last `# bats test_tags=` directive +before a given test will be used. + +Sometimes, we want to give all tests in a file a set of the same tags. This can +be achieved via `# bats file_tags=`. They will be added to all tests in the file +after that directive. An additional `# bats file_tags=` directive will override +the previously defined values: + +```bash +@test "Zeroth test" { + # will have no tags +} + +# bats file_tags=a:b +# bats test_tags=c:d + +@test "First test" { + # will be tagged a:b, c:d +} + +# bats file_tags= + +@test "Second test" { + # will have no tags +} +``` + +Tags are case sensitive and must only consist of alphanumeric characters and `_`, + `-`, or `:`. They must not contain whitespaces! +The colon is intended as a separator for (recursive) namespacing. + +Tag lists must be separated by commas and are allowed to contain whitespace. +They must not contain empty tags like `test_tags=,b` (first tag is empty), +`test_tags=a,,c`, `test_tags=a, ,c` (second tag is only whitespace/empty), +`test_tags=a,b,` (third tag is empty). + +Every tag starting with `bats:` (case insensitive!) is reserved for Bats' +internal use. + +### Special tags + +#### Focusing on tests with `bats:focus` tag + +If a test with the tag `bats:focus` is encountered in a test suite, +all other tests will be filtered out and only those tagged with this tag will be executed. + +In focus mode, the exit code of successful runs will be overridden to 1 to prevent CI from silently running on a subset of tests due to an accidentally committed `bats:focus` tag. +Should you require the true exit code, e.g. for a `git bisect` operation, you can disable this behavior by setting +`BATS_NO_FAIL_FOCUS_RUN=1` when running `bats`, but make sure not to commit this to CI! + +### Filtering execution + +Tags can be used for more finegrained filtering of which tests to run via `--filter-tags`. +This accepts a comma separated list of tags. Only tests that match all of these +tags will be executed. For example, `bats --filter-tags a,b,c` will pick up tests +with tags `a,b,c`, but not tests that miss one or more of those tags. + +Additionally, you can specify negative tags via `bats --filter-tags a,!b,c`, +which now won't match tests with tags `a,b,c`, due to the `b`, but will select `a,c`. +To put it more formally, `--filter-tags` is a boolean conjunction. + +To allow for more complex queries, you can specify multiple `--filter-tags`. +A test will be executed, if it matches at least one of them. +This means multiple `--filter-tags` form a boolean disjunction. + +A query of `--filter-tags a,!b --filter-tags b,c` can be translated to: +Execute only tests that (have tag a, but not tag b) or (have tag b and c). + +An empty tag list matches tests without tags. + +## Comment syntax + +External tools (like `shellcheck`, `shfmt`, and various IDE's) may not support +the standard `.bats` syntax. Because of this, we provide a valid `bash` +alternative: + +```bash +function invoking_foo_without_arguments_prints_usage { #@test + run foo + [ "$status" -eq 1 ] + [ "${lines[0]}" = "usage: foo " ] +} +``` + +When using this syntax, the function name will be the title in the result output +and the value checked when using `--filter`. + +## `run`: Test other commands + +Many Bats tests need to run a command and then make assertions about its exit +status and output. Bats includes a `run` helper that invokes its arguments as a +command, saves the exit status and output into special global variables, and +then returns with a `0` status code so you can continue to make assertions in +your test case. + +For example, let's say you're testing that the `foo` command, when passed a +nonexistent filename, exits with a `1` status code and prints an error message. + +```bash +@test "invoking foo with a nonexistent file prints an error" { + run foo nonexistent_filename + [ "$status" -eq 1 ] + [ "$output" = "foo: no such file 'nonexistent_filename'" ] + [ "$BATS_RUN_COMMAND" = "foo nonexistent_filename" ] + +} +``` + +The `$status` variable contains the status code of the command, the +`$output` variable contains the combined contents of the command's standard +output and standard error streams, and the `$BATS_RUN_COMMAND` string contains the +command and command arguments passed to `run` for execution. + +If invoked with one of the following as the first argument, `run` +will perform an implicit check on the exit status of the invoked command: + +```pre + -N expect exit status N (0-255), fail if otherwise + ! expect nonzero exit status (1-255), fail if command succeeds +``` + +We can then write the above more elegantly as: + +```bash +@test "invoking foo with a nonexistent file prints an error" { + run -1 foo nonexistent_filename + [ "$output" = "foo: no such file 'nonexistent_filename'" ] +} +``` + +A third special variable, the `$lines` array, is available for easily accessing +individual lines of output. For example, if you want to test that invoking `foo` +without any arguments prints usage information on the first line: + +```bash +@test "invoking foo without arguments prints usage" { + run -1 foo + [ "${lines[0]}" = "usage: foo " ] +} +``` + +__Note:__ The `run` helper executes its argument(s) in a subshell, so if +writing tests against environmental side-effects like a variable's value +being changed, these changes will not persist after `run` completes. + +By default `run` leaves out empty lines in `${lines[@]}`. Use +`run --keep-empty-lines` to retain them. + +Additionally, you can use `--separate-stderr` to split stdout and stderr +into `$output`/`$stderr` and `${lines[@]}`/`${stderr_lines[@]}`. + +All additional parameters to run should come before the command. +If you want to run a command that starts with `-`, prefix it with `--` to +prevent `run` from parsing it as an option. + +### When not to use `run` + +In case you only need to check the command succeeded, it is better to not use `run`, since the following code + +```bash +run -0 command args ... +``` + +is equivalent to + +```bash +command args ... +``` + +(because bats sets `set -e` for all tests). + +__Note__: In contrast to the above, testing that a command failed is best done via + +```bash +run ! command args ... +``` + +because + +```bash +! command args ... +``` + +will only fail the test if it is the last command and thereby determines the test function's exit code. +This is due to Bash's decision to (counterintuitively?) not trigger `set -e` on `!` commands. +(See also [the associated gotcha](gotchas.html#my-negated-statement-e-g-true-does-not-fail-the-test-even-when-it-should)) + + +### `run` and pipes + +Don't fool yourself with pipes when using `run`. Bash parses the pipe outside of `run`, not internal to its command. Take this example: + +```bash +run command args ... | jq -e '.limit == 42' +``` + +Here, `jq` receives no input (which is captured by `run`), +executes no filters, and always succeeds, so the test does not work as +expected. + +To correctly handle commands with pipes see `bats_pipe`. + +## `bats_pipe`: Run commands with pipes + +The `bats_pipe` helper command is meant to handle piping between commands. Its +main purpose is to aide the `run` helper command (which cannot handle pipes, due +to bash parsing priority). `run command0 | command1` will parse `|` before +`run`, which is commonly not intended by test authors. + +Running `run bats_pipe command0 \| command1` will have the piped commands run +within the context of the `run` command, and thus have the output and status +variables properly contained within the normal `output` and `status` variables. + +Note that this requires the usage of `\|`, not `|`. This is to avoid bash +parsing out `|` first, instead sending `\|` to the `bats_pipe` command for it to +parse and set up intended piping. Running `bats_pipe` with no instances of `\|` +will always fail; this is intended to catch typos (accidentally using `|`) by +the test author. + +The `bats_pipe` command will also properly propagate exit status from the piped +commands. The default behavior mimics `set -o pipefail`, returning the status of +the last (rightmost) command that exits with a non-zero status. This ensures +that usage of pipes do not mask the exit statuses of earlier commands. + +```bash +@test "invoking foo piped to bar" { + run bats_pipe foo \| bar + # asserting foo or bar would return 17 (from foo if bar returns 0). + [ "$status" -eq 17 ] + [ "$output" = "bar output." ] +} +``` + +Alternatively, if the test always cares about the status of a specific command, +the `-` option can be given (e.g. `-0`) to always return the status of the +command of interest. + +```bash +@test "invoking foo piped to bar always return foo status" { + run bats_pipe -0 foo \| bar + # status of bar is ignored, status is always from foo. + [ "$status" -eq 2 ] + [ "$output" = "bar output." ] +} +``` + +Similarly, `--returned-status N` (or `--returned-status=N`) can be used for +similar functionality. This option supports negative values, which always return +the of the command starting from the end and in reverse order. + +```bash +@test "invoking foo piped to bar always return foo status" { + run bats_pipe --returned-status -2 foo \| bar + # status of bar is ignored, status is always from foo. + [ "$status" -eq 2 ] + [ "$output" = "bar output." ] +} +``` + +Piping of command output is especially helpful when the output needs to be +modified in some way (e.g. the command outputs binary data into stdout, which +cannot be stored as-is in an environment variable). + +```bash +@test "invoking foo that returns binary data" { + run bats_pipe foo \| hexdump -v -e "1/1 \"0x%02X \"" + [ "$status" -eq 17 ] + [[ "$output" =~ 0xDE\ 0xAD ]] +} +``` + +Any number of pipes can be used in conjunction to chain output between some set +of running commands. + +## `load`: Share common code + +You may want to share common code across multiple test files. Bats +includes a convenient `load` command for sourcing a Bash source files +relative to the current test file and from absolute paths. + +For example, if you have a Bats test in `test/foo.bats`, the command + +```bash +load test_helper.bash +``` + +will source the script `test/test_helper.bash` in your test file (limitations +apply, see below). This can be useful for sharing functions to set up your +environment or load fixtures. `load` delegates to Bash's `source` command after +resolving paths. + +If `load` encounters errors - e.g. because the targeted source file +errored - it will print a message with the failing library and Bats +exits. + +To allow to use `load` in conditions `bats_load_safe` has been added. +`bats_load_safe` prints a message and returns `1` if a source file cannot be +loaded instead of exiting Bats. +Aside from that `bats_load_safe` acts exactly like `load`. + +__Note:__ : As pointed out by @iatrou in the [Advanced Bash Scripting Guide +(section 9.2)](https://www.tldp.org/LDP/abs/html/declareref.html), +using the `declare` builtin restricts scope of a variable. Thus, since actual +`source`-ing is performed in context of the `load` function, symbols +defined using `declare` will _not_ be made available to callers of `load` (unless `declare -g` +is used). + +### `load` argument resolution + +`load` supports the following arguments: + +- absolute paths +- relative paths (to the current test file) + +> For backwards compatibility `load` first searches for a file ending in +> `.bash` (e.g. `load test_helper` searches for `test_helper.bash` before +> it looks for `test_helper`). This behaviour is deprecated and subject to +> change, please use exact filenames instead. + +If `argument` is an absolute path `load` tries to determine the load +path directly. + +If `argument` is a relative path or a name `load` looks for a matching +path in the directory of the current test. + +## `bats_load_library`: Load system wide libraries + +Some libraries are installed on the system, e.g. by `npm` or `brew`. +These should not be `load`ed, as their path depends on the installation method. +Instead, one should use `bats_load_library` together with setting +`BATS_LIB_PATH`, a `PATH`-like colon-delimited variable. + +`bats_load_library` has two modes of resolving requests: + +1. by relative path from the `BATS_LIB_PATH` to a file in the library +2. by library name, expecting libraries to have a `load.bash` entrypoint + +For example if your `BATS_LIB_PATH` is set to +`~/.bats/libs:/usr/lib/bats`, then `bats_load_library test_helper` +would look for existing files with the following paths: + +- `~/.bats/libs/test_helper` +- `~/.bats/libs/test_helper/load.bash` +- `/usr/lib/bats/test_helper` +- `/usr/lib/bats/test_helper/load.bash` + +The first existing file in this list will be sourced. + +If you want to load only part of a library or the entry point is not named `load.bash`, +you have to include it in the argument: +`bats_load_library library_name/file_to_load` will try + +- `~/.bats/libs/library_name/file_to_load` +- `~/.bats/libs/library_name/file_to_load/load.bash` +- `/usr/lib/bats/library_name/file_to_load` +- `/usr/lib/bats/library_name/file_to_load/load.bash` + +Apart from the changed lookup rules, `bats_load_library` behaves like `load`. + +__Note:__ As seen above `load.bash` is the entry point for libraries and +meant to load more files from its directory or other libraries. + +__Note:__ Obviously, the actual `BATS_LIB_PATH` is highly dependent on the environment. +To maintain a uniform location across systems, (distribution) package maintainers +are encouraged to use `/usr/lib/bats/` as the install path for libraries where possible. +However, if the package manager has another preferred location, like `npm` or `brew`, +you should use this instead. + +## `skip`: Easily skip tests + +Tests can be skipped by using the `skip` command at the point in a test you wish +to skip. + +```bash +@test "A test I don't want to execute for now" { + skip + run foo + [ "$status" -eq 0 ] +} +``` + +Optionally, you may include a reason for skipping: + +```bash +@test "A test I don't want to execute for now" { + skip "This command will return zero soon, but not now" + run foo + [ "$status" -eq 0 ] +} +``` + +Or you can skip conditionally: + +```bash +@test "A test which should run" { + if [ foo != bar ]; then + skip "foo isn't bar" + fi + + run foo + [ "$status" -eq 0 ] +} +``` + +__Note:__ `setup` and `teardown` hooks still run for skipped tests. + +## `setup` and `teardown`: Pre- and post-test hooks + +You can define special `setup` and `teardown` functions, which run before and +after each test case, respectively. Use these to load fixtures, set up your +environment, and clean up when you're done. + +You can also define `setup_file` and `teardown_file`, which will run once before +the first test's `setup` and after the last test's `teardown` for the containing +file. Variables that are exported in `setup_file` will be visible to all following +functions (`setup`, the test itself, `teardown`, `teardown_file`). + +Similarly, there is `setup_suite` (and `teardown_suite`) which run once before (and +after) all tests of the test run. + +__Note:__ As `setup_suite` and `teardown_suite` are intended for all files in a suite, +they must be defined in a separate `setup_suite.bash` file. Automatic discovery works +by searching for `setup_suite.bash` in the folder of the first `*.bats` file of the suite. +If this automatism does not work for your usecase, you can work around by specifying +`--setup-suite-file` on the `bats` command. If you have a `setup_suite.bash`, it must define +`setup_suite`! However, defining `teardown_suite` is optional. + + +
+ Example of setup/{,_file,_suite} (and teardown{,_file,_suite}) call order +For example the following call order would result from two files (file 1 with +tests 1 and 2, and file 2 with test3) with a corresponding `setup_suite.bash` file being tested: + +```text +setup_suite # from setup_suite.bash + setup_file # from file 1, on entering file 1 + setup + test1 + teardown + setup + test2 + teardown + teardown_file # from file 1, on leaving file 1 + setup_file # from file 2, on enter file 2 + setup + test3 + teardown + teardown_file # from file 2, on leaving file 2 +teardown_suite # from setup_suite.bash +``` + +
+ + +Note that the `teardown*` functions can fail a test, if their return code is nonzero. +This means, using `return 1` or having the last command in teardown fail, will +fail the teardown. Unlike `@test`, failing commands within `teardown` won't +trigger failure as ERREXIT is disabled. + + +
+ Example of different teardown failure modes + +```bash +teardown() { + false # this will fail the test, as it determines the return code +} + +teardown() { + false # this won't fail the test ... + echo some more code # ... and this will be executed too! +} + +teardown() { + return 1 # this will fail the test, but the rest won't be executed + echo some more code +} + +teardown() { + if true; then + false # this will also fail the test, as it is the last command in this function + else + true + fi +} +``` + +
+ + +## `bats::on_failure` hook + +While `teardown` unconditionally handles cleanup after the test ends, the `bats::on_failure` hook gets called +only when a test is aborted due to an error. `bats::on_failure` will be called before `teardown`. + +You can define `bats::on_failure` anywhere in your test files, even inside the test functions, to change its behavior midtest: + +```bash +@test "my awesome test" { + simple_test_setup + + bats::on_failure() { + handle_simple_error_case + } + + complex_test_setup + + bats::on_failure() { + print_debug_information_only_on_error + } + + do_actual_tests + + check_results +} +``` + +The `bats::on_failure` hook is available in `setup_suite`/`setup_file`/`setup`, their respective teardown functions, and test functions. + +## `bats_require_minimum_version ` + +Added in [v1.7.0](https://github.com/bats-core/bats-core/releases/tag/v1.7.0) + +Code for newer versions of Bats can be incompatible with older versions. +In the best case this will lead to an error message and a failed test suite. +In the worst case, the tests will pass erroneously, potentially masking a failure. + +Use `bats_require_minimum_version ` to avoid this. +It communicates in a concise manner, that you intend the following code to be run +under the given Bats version or higher. + +Additionally, this function will communicate the current Bats version floor to +subsequent code, allowing e.g. Bats' internal warning to give more informed warnings. + +__Note__: By default, calling `bats_require_minimum_version` with versions before +Bats 1.7.0 will fail regardless of the required version as the function is not +available. However, you can use the +[bats-backports plugin](https://github.com/bats-core/bats-backports) to make +your code usable with older versions, e.g. during migration while your CI system +is not yet upgraded. + +## Code outside of test cases + +In general you should avoid code outside tests, because each test file will be evaluated many times. +However, there are situations in which this might be useful, e.g. when you want to check for dependencies +and fail immediately if they're not present. + +In general, you should avoid printing outside of `@test`, `setup*` or `teardown*` functions. +Have a look at section [printing to the terminal](#printing-to-the-terminal) for more details. +## File descriptor 3 (read this if Bats hangs) + +Bats makes a separation between output from the code under test and output that +forms the TAP stream (which is produced by Bats internals). This is done in +order to produce TAP-compliant output. In the [Printing to the +terminal](#printing-to-the-terminal) section, there are details on how to use +file descriptor 3 to print custom text properly. + +A side effect of using file descriptor 3 is that, under some circumstances, it +can cause Bats to block and execution to seem dead without reason. This can +happen if a child process is spawned in the background from a test. In this +case, the child process will inherit file descriptor 3. Bats, as the parent +process, will wait for the file descriptor to be closed by the child process +before continuing execution. If the child process takes a lot of time to +complete (eg if the child process is a `sleep 100` command or a background +service that will run indefinitely), Bats will be similarly blocked for the same +amount of time. + +**To prevent this from happening, close FD 3 explicitly when running any command +that may launch long-running child processes**, e.g. `command_name 3>&-` . + +## Printing to the terminal + +Bats produces output compliant with [version 12 of the TAP protocol](https://testanything.org/tap-specification.html). The +produced TAP stream is by default piped to a pretty formatter for human +consumption, but if Bats is called with the `-t` flag, then the TAP stream is +directly printed to the console. + +This has implications if you try to print custom text to the terminal. As +mentioned in [File descriptor 3](#file-descriptor-3-read-this-if-bats-hangs), +bats provides a special file descriptor, `&3`, that you should use to print +your custom text. Here are some detailed guidelines to refer to: + +- Printing **from within a test function**: + - First you should consider if you want the text to be always visible or only + when the test fails. Text that is output directly to stdout or stderr (file + descriptor 1 or 2), ie `echo 'text'` is considered part of the test function + output and is printed only on test failures for diagnostic purposes, + regardless of the formatter used (TAP or pretty). + - To have text printed unconditionally from within a test function you need to + redirect the output to file descriptor 3, eg `echo 'text' >&3`. This output + will become part of the TAP stream. You are encouraged to prepend text printed + this way with a hash (eg `echo '# text' >&3`) in order to produce 100% TAP compliant + output. Otherwise, depending on the 3rd-party tools you use to analyze the + TAP stream, you can encounter unexpected behavior or errors. + +- Printing **from within the `setup*` or `teardown*` functions**: The same hold + true as for printing with test functions. + +- Printing **outside test or `setup*`/`teardown*` functions**: + - You should avoid printing in free code: Due to the multiple executions + contexts (`setup_file`, multiple `@test`s) of test files, output + will be printed more than once. + + - Regardless of where text is redirected to (stdout, stderr or file descriptor 3) + text is immediately visible in the terminal, as it is not piped into the formatter. + + - Text printed to stdout may interfere with formatters as it can + make output non-compliant with the TAP spec. The reason for this is that + such output will be produced before the [_plan line_][tap-plan] is printed, + contrary to the spec that requires the _plan line_ to be either the first or + the last line of the output. + + - Due to internal pipes/redirects, output to stderr is always printed first. + +[tap-plan]: https://testanything.org/tap-specification.html#the-plan + +## Special variables + +There are several global variables you can use to introspect on Bats tests: + +- `$BATS_RUN_COMMAND` is the run command used in your test case. +- `$BATS_TEST_FILENAME` is the fully expanded path to the Bats test file. +- `$BATS_TEST_DIRNAME` is the directory in which the Bats test file is located. +- `$BATS_TEST_NAMES` is an array of function names for each test case. +- `$BATS_TEST_NAME` is the name of the function containing the current test case. +- `BATS_TEST_NAME_PREFIX` will be prepended to the description of each test on + stdout and in reports. +- `$BATS_TEST_DESCRIPTION` is the description of the current test case. +- `BATS_TEST_RETRIES` is the maximum number of additional attempts that will be + made on a failed test before it is finally considered failed. + The default of 0 means the test must pass on the first attempt. +- `BATS_TEST_TIMEOUT` is the number of seconds after which a test (including setup) + will be aborted and marked as failed. Updates to this value in `setup()` or `@test` + cannot change the running timeout countdown, so the latest useful update location + is `setup_file()`. +- `$BATS_TEST_NUMBER` is the (1-based) index of the current test case in the test file. +- `$BATS_SUITE_TEST_NUMBER` is the (1-based) index of the current test case in the test suite (over all files). +- `$BATS_TEST_TAGS` the tags of the current test. +- `$BATS_TMPDIR` is the base temporary directory used by bats to create its + temporary files / directories. + (default: `$TMPDIR`. If `$TMPDIR` is not set, `/tmp` is used.) +- `$BATS_RUN_TMPDIR` is the location to the temporary directory used by bats to + store all its internal temporary files during the tests. + (default: `$BATS_TMPDIR/bats-run-$BATS_ROOT_PID-XXXXXX`) +- `$BATS_FILE_EXTENSION` (default: `bats`) specifies the extension of test files that should be found when running a suite (via `bats [-r] suite_folder/`) +- `$BATS_SUITE_TMPDIR` is a temporary directory common to all tests of a suite. + Could be used to create files required by multiple tests. +- `$BATS_FILE_TMPDIR` is a temporary directory common to all tests of a test file. + Could be used to create files required by multiple tests in the same test file. +- `$BATS_TEST_TMPDIR` is a temporary directory unique for each test. + Could be used to create files required only for specific tests. +- `$BATS_VERSION` is the version of Bats running the test. + +## Libraries and Add-ons + +Bats supports loading external assertion libraries and helpers. Those under `bats-core` are officially supported libraries (integration tests welcome!): + +- - common assertions for Bats +- - supporting library for Bats test helpers +- - common filesystem assertions for Bats +- - e2e tests of applications in K8s environments + +Furthermore, you can find a list of [3rd-party libraries](https://github.com/bats-core/bats-core/wiki/3rd%E2%80%90party-Libraries-for-Bats) in our Wiki. \ No newline at end of file diff --git a/tooling/bats-core/docs/versions.md b/tooling/bats-core/docs/versions.md new file mode 100644 index 00000000000000..5113077c413d86 --- /dev/null +++ b/tooling/bats-core/docs/versions.md @@ -0,0 +1,9 @@ +Here are the docs of following versions: + +* [v1.2.0](../../v1.2.0/README.md) +* [v1.1.0](../../v1.1.0/README.md) +* [v1.0.2](../../v1.0.2/README.md) +* [v0.4.0](../../v0.4.0/README.md) +* [v0.3.1](../../v0.3.1/README.md) +* [v0.2.0](../../v0.2.0/README.md) +* [v0.1.0](../../v0.1.0/README.md) diff --git a/tooling/bats-core/install.sh b/tooling/bats-core/install.sh new file mode 100755 index 00000000000000..edc26af7ea64a0 --- /dev/null +++ b/tooling/bats-core/install.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +set -e + +BATS_ROOT="${0%/*}" +PREFIX="${1%/}" +LIBDIR="${2:-lib}" + +if [[ -z "$PREFIX" ]]; then + printf '%s\n' \ + "usage: $0 [base_libdir]" \ + " e.g. $0 /usr/local" \ + " $0 /usr/local lib64" >&2 + exit 1 +fi + +install -d -m 755 "$PREFIX"/{bin,libexec/bats-core,"${LIBDIR}"/bats-core,share/man/man{1,7}} + +install -m 755 "$BATS_ROOT/bin"/* "$PREFIX/bin" +install -m 755 "$BATS_ROOT/libexec/bats-core"/* "$PREFIX/libexec/bats-core" +install -m 755 "$BATS_ROOT/lib/bats-core"/* "$PREFIX/${LIBDIR}/bats-core" +install -m 644 "$BATS_ROOT/man/bats.1" "$PREFIX/share/man/man1" +install -m 644 "$BATS_ROOT/man/bats.7" "$PREFIX/share/man/man7" + +read -rd '' BATS_EXE_CONTENTS <"$PREFIX/bin/bats" || true +BATS_EXE_CONTENTS=${BATS_EXE_CONTENTS/"BATS_BASE_LIBDIR=lib"/"BATS_BASE_LIBDIR=${LIBDIR}"} +printf "%s" "$BATS_EXE_CONTENTS" >| "$PREFIX/bin/bats" + +echo "Installed Bats to $PREFIX/bin/bats" diff --git a/tooling/bats-core/lib/bats-core/common.bash b/tooling/bats-core/lib/bats-core/common.bash new file mode 100644 index 00000000000000..7426fa065f193f --- /dev/null +++ b/tooling/bats-core/lib/bats-core/common.bash @@ -0,0 +1,258 @@ +#!/usr/bin/env bash + +bats_prefix_lines_for_tap_output() { + while IFS= read -r line; do + printf '# %s\n' "$line" || break # avoid feedback loop when errors are redirected into BATS_OUT (see #353) + done + if [[ -n "$line" ]]; then + printf '# %s\n' "$line" + fi +} + +function bats_replace_filename() { + local line + while read -r line; do + printf "%s\n" "${line//$BATS_TEST_SOURCE/$BATS_TEST_FILENAME}" + done + if [[ -n "$line" ]]; then + printf "%s\n" "${line//$BATS_TEST_SOURCE/$BATS_TEST_FILENAME}" + fi +} + +bats_quote_code() { # + printf -v "$1" -- "%s%s%s" "$BATS_BEGIN_CODE_QUOTE" "$2" "$BATS_END_CODE_QUOTE" +} + +bats_check_valid_version() { + if [[ ! $1 =~ [0-9]+.[0-9]+.[0-9]+ ]]; then + printf "ERROR: version '%s' must be of format ..!\n" "$1" >&2 + exit 1 + fi +} + +# compares two versions. Return 0 when version1 < version2 +bats_version_lt() { # + bats_check_valid_version "$1" + bats_check_valid_version "$2" + + local -a version1_parts version2_parts + IFS=. read -ra version1_parts <<<"$1" + IFS=. read -ra version2_parts <<<"$2" + + local -i i + for i in {0..2}; do + if ((version1_parts[i] < version2_parts[i])); then + return 0 + elif ((version1_parts[i] > version2_parts[i])); then + return 1 + fi + done + # if we made it this far, they are equal -> also not less then + return 2 # use other failing return code to distinguish equal from gt +} + +# ensure a minimum version of bats is running or exit with failure +bats_require_minimum_version() { # + local required_minimum_version=$1 + + if bats_version_lt "$BATS_VERSION" "$required_minimum_version"; then + printf "BATS_VERSION=%s does not meet required minimum %s\n" "$BATS_VERSION" "$required_minimum_version" + exit 1 + fi + + if bats_version_lt "$BATS_GUARANTEED_MINIMUM_VERSION" "$required_minimum_version"; then + BATS_GUARANTEED_MINIMUM_VERSION="$required_minimum_version" + fi +} + +bats_binary_search() { # + if [[ $# -ne 2 ]]; then + printf "ERROR: bats_binary_search requires exactly 2 arguments: \n" >&2 + return 2 + fi + + local -r search_value=$1 array_name=$2 + + # we'd like to test if array is set but we cannot distinguish unset from empty arrays, so we need to skip that + + local start=0 mid end mid_value + # start is inclusive, end is exclusive ... + eval "end=\${#${array_name}[@]}" + + # so start == end means empty search space + while ((start < end)); do + mid=$(((start + end) / 2)) + eval "mid_value=\${${array_name}[$mid]}" + if [[ "$mid_value" == "$search_value" ]]; then + return 0 + elif [[ "$mid_value" < "$search_value" ]]; then + # This branch excludes equality -> +1 to skip the mid element. + # This +1 also avoids endless recursion on odd sized search ranges. + start=$((mid + 1)) + else + end=$mid + fi + done + + # did not find it -> its not there + return 1 +} + +# store the values in ascending (string!) order in result array +# Intended for short lists! (uses insertion sort) +bats_sort() { # + local -r result_name=$1 + shift + + if (($# == 0)); then + eval "$result_name=()" + return 0 + fi + + local -a sorted_array=() + local -i i + while (( $# > 0 )); do # loop over input values + local current_value="$1" + shift + for ((i = ${#sorted_array[@]}; i >= 0; --i)); do # loop over output array from end + if (( i == 0 )) || [[ ${sorted_array[i - 1]} < $current_value ]]; then + # shift bigger elements one position to the end + sorted_array[i]=$current_value + break + else + # insert new element at (freed) desired location + sorted_array[i]=${sorted_array[i - 1]} + fi + done + done + + eval "$result_name=(\"\${sorted_array[@]}\")" +} + +# check if all search values (must be sorted!) are in the (sorted!) array +# Intended for short lists/arrays! +bats_all_in() { # + local -r haystack_array=$1 + shift + + local -i haystack_length # just to appease shellcheck + eval "local -r haystack_length=\${#${haystack_array}[@]}" + + local -i haystack_index=0 # initialize only here to continue from last search position + local search_value haystack_value # just to appease shellcheck + local -i i + for ((i = 1; i <= $#; ++i)); do + eval "local search_value=${!i}" + for (( ; haystack_index < haystack_length; ++haystack_index)); do + eval "local haystack_value=\${${haystack_array}[$haystack_index]}" + if [[ $haystack_value > "$search_value" ]]; then + # we passed the location this value would have been at -> not found + return 1 + elif [[ $haystack_value == "$search_value" ]]; then + continue 2 # search value found -> try the next one + fi + done + return 1 # we ran of the end of the haystack without finding the value! + done + + # did not return from loop above -> all search values were found + return 0 +} + +# check if any search value (must be sorted!) is in the (sorted!) array +# intended for short lists/arrays +bats_any_in() { # + local -r haystack_array=$1 + shift + + local -i haystack_length # just to appease shellcheck + eval "local -r haystack_length=\${#${haystack_array}[@]}" + + local -i haystack_index=0 # initialize only here to continue from last search position + local search_value haystack_value # just to appease shellcheck + local -i i + for ((i = 1; i <= $#; ++i)); do + eval "local search_value=${!i}" + for (( ; haystack_index < haystack_length; ++haystack_index)); do + eval "local haystack_value=\${${haystack_array}[$haystack_index]}" + if [[ $haystack_value > "$search_value" ]]; then + continue 2 # search value not in array! -> try next + elif [[ $haystack_value == "$search_value" ]]; then + return 0 # search value found + fi + done + done + + # did not return from loop above -> no search value was found + return 1 +} + +bats_trim() { # + local -r bats_trim_ltrimmed=${2#"${2%%[![:space:]]*}"} # cut off leading whitespace + # shellcheck disable=SC2034 # used in eval! + local -r bats_trim_trimmed=${bats_trim_ltrimmed%"${bats_trim_ltrimmed##*[![:space:]]}"} # cut off trailing whitespace + eval "$1=\$bats_trim_trimmed" +} + +# a helper function to work around unbound variable errors with ${arr[@]} on Bash 3 +bats_append_arrays_as_args() { # -- + local -a trailing_args=() + while (($# > 0)) && [[ $1 != -- ]]; do + local array=$1 + shift + + if eval "(( \${#${array}[@]} > 0 ))"; then + eval "trailing_args+=(\"\${${array}[@]}\")" + fi + done + shift # remove -- separator + + if (($# == 0)); then + printf "Error: append_arrays_as_args is missing a command or -- separator\n" >&2 + return 1 + fi + + if ((${#trailing_args[@]} > 0)); then + "$@" "${trailing_args[@]}" + else + "$@" + fi +} + +bats_format_file_line_reference() { # + # shellcheck disable=SC2034 # will be used in subimplementation + local output="${1?}" + shift + "bats_format_file_line_reference_${BATS_LINE_REFERENCE_FORMAT?}" "$@" +} + +bats_format_file_line_reference_comma_line() { + printf -v "$output" "%s, line %d" "$@" +} + +bats_format_file_line_reference_colon() { + printf -v "$output" "%s:%d" "$@" +} + +# approximate realpath without subshell +bats_approx_realpath() { # + local output=$1 path=$2 + if [[ $path != /* ]]; then + path="$PWD/$path" + fi + # x/./y -> x/y + path=${path//\/.\//\/} + printf -v "$output" "%s" "$path" +} + +bats_format_file_line_reference_uri() { + local filename=${1?} line=${2?} + bats_approx_realpath filename "$filename" + printf -v "$output" "file://%s:%d" "$filename" "$line" +} + +# execute command with backed up path +# to prevent path mocks from interfering with our internals +bats_execute() { # + PATH="${BATS_SAVED_PATH?}" "$@" +} diff --git a/tooling/bats-core/lib/bats-core/formatter.bash b/tooling/bats-core/lib/bats-core/formatter.bash new file mode 100644 index 00000000000000..aaf8096b49e460 --- /dev/null +++ b/tooling/bats-core/lib/bats-core/formatter.bash @@ -0,0 +1,151 @@ +#!/usr/bin/env bash + +# reads (extended) bats tap streams from stdin and calls callback functions for each line +# +# Segmenting functions +# ==================== +# bats_tap_stream_plan -> when the test plan is encountered +# bats_tap_stream_suite -> when a new file is begun WARNING: extended only +# bats_tap_stream_begin -> when a new test is begun WARNING: extended only +# +# Test result functions +# ===================== +# If timing was enabled, BATS_FORMATTER_TEST_DURATION will be set to their duration in milliseconds +# bats_tap_stream_ok -> when a test was successful +# bats_tap_stream_not_ok -> when a test has failed. If the failure was due to a timeout, +# BATS_FORMATTER_TEST_TIMEOUT is set to the timeout duration in seconds +# bats_tap_stream_skipped -> when a test was skipped +# +# Context functions +# ================= +# bats_tap_stream_comment -> when a comment line was encountered, +# scope tells the last encountered of plan, begin, ok, not_ok, skipped, suite +# bats_tap_stream_unknown -> when a line is encountered that does not match the previous entries, +# scope @see bats_tap_stream_comment +# forwards all input as is, when there is no TAP test plan header +function bats_parse_internal_extended_tap() { + local header_pattern='[0-9]+\.\.[0-9]+' + IFS= read -r header + + if [[ "$header" =~ $header_pattern ]]; then + bats_tap_stream_plan "${header:3}" + else + # If the first line isn't a TAP plan, print it and pass the rest through + printf '%s\n' "$header" + exec cat + fi + + ok_line_regexpr="ok ([0-9]+) (.*)" + skip_line_regexpr="ok ([0-9]+) (.*) # skip( (.*))?$" + timeout_line_regexpr="not ok ([0-9]+) (.*) # timeout after ([0-9]+)s$" + not_ok_line_regexpr="not ok ([0-9]+) (.*)" + + timing_expr="in ([0-9]+)ms$" + local test_name begin_index last_begin_index try_index ok_index not_ok_index index scope + begin_index=0 + last_begin_index=-1 + try_index=0 + index=0 + scope=plan + while IFS= read -r line; do + unset BATS_FORMATTER_TEST_DURATION BATS_FORMATTER_TEST_TIMEOUT + case "$line" in + 'begin '*) # this might only be called in extended tap output + scope=begin + begin_index=${line#begin } + begin_index=${begin_index%% *} + if [[ $begin_index == "$last_begin_index" ]]; then + (( ++try_index )) + else + try_index=0 + fi + test_name="${line#begin "$begin_index" }" + bats_tap_stream_begin "$begin_index" "$test_name" + ;; + 'ok '*) + ((++index)) + if [[ "$line" =~ $ok_line_regexpr ]]; then + ok_index="${BASH_REMATCH[1]}" + test_name="${BASH_REMATCH[2]}" + if [[ "$line" =~ $skip_line_regexpr ]]; then + scope=skipped + test_name="${BASH_REMATCH[2]}" # cut off name before "# skip" + local skip_reason="${BASH_REMATCH[4]}" + if [[ "$test_name" =~ $timing_expr ]]; then + local BATS_FORMATTER_TEST_DURATION="${BASH_REMATCH[1]}" + test_name="${test_name% in "${BATS_FORMATTER_TEST_DURATION}"ms}" + bats_tap_stream_skipped "$ok_index" "$test_name" "$skip_reason" + else + bats_tap_stream_skipped "$ok_index" "$test_name" "$skip_reason" + fi + else + scope=ok + if [[ "$line" =~ $timing_expr ]]; then + local BATS_FORMATTER_TEST_DURATION="${BASH_REMATCH[1]}" + bats_tap_stream_ok "$ok_index" "${test_name% in "${BASH_REMATCH[1]}"ms}" + else + bats_tap_stream_ok "$ok_index" "$test_name" + fi + fi + else + printf "ERROR: could not match ok line: %s" "$line" >&2 + exit 1 + fi + ;; + 'not ok '*) + ((++index)) + scope=not_ok + if [[ "$line" =~ $not_ok_line_regexpr ]]; then + not_ok_index="${BASH_REMATCH[1]}" + test_name="${BASH_REMATCH[2]}" + if [[ "$line" =~ $timeout_line_regexpr ]]; then + not_ok_index="${BASH_REMATCH[1]}" + test_name="${BASH_REMATCH[2]}" + # shellcheck disable=SC2034 # used in bats_tap_stream_ok + local BATS_FORMATTER_TEST_TIMEOUT="${BASH_REMATCH[3]}" + fi + if [[ "$test_name" =~ $timing_expr ]]; then + # shellcheck disable=SC2034 # used in bats_tap_stream_ok + local BATS_FORMATTER_TEST_DURATION="${BASH_REMATCH[1]}" + test_name="${test_name% in "${BASH_REMATCH[1]}"ms}" + fi + bats_tap_stream_not_ok "$not_ok_index" "$test_name" + else + printf "ERROR: could not match not ok line: %s" "$line" >&2 + exit 1 + fi + ;; + '# '*) + bats_tap_stream_comment "${line:2}" "$scope" + ;; + '#') + bats_tap_stream_comment "" "$scope" + ;; + 'suite '*) + scope=suite + # pass on the + bats_tap_stream_suite "${line:6}" + ;; + *) + bats_tap_stream_unknown "$line" "$scope" + ;; + esac + done +} + +normalize_base_path() { # + # the relative path root to use for reporting filenames + # this is mainly intended for suite mode, where this will be the suite root folder + local base_path="$2" + # use the containing directory when --base-path is a file + if [[ ! -d "$base_path" ]]; then + base_path="$(dirname "$base_path")" + fi + # get the absolute path + base_path="$(cd "$base_path" && pwd)" + # ensure the path ends with / to strip that later on + if [[ "${base_path}" != *"/" ]]; then + base_path="$base_path/" + fi + printf -v "$1" "%s" "$base_path" +} diff --git a/tooling/bats-core/lib/bats-core/preprocessing.bash b/tooling/bats-core/lib/bats-core/preprocessing.bash new file mode 100644 index 00000000000000..069cfd404de4b4 --- /dev/null +++ b/tooling/bats-core/lib/bats-core/preprocessing.bash @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +bats_export_preprocess_source_BATS_TEST_SOURCE() { + # export to make it visible to bats_evaluate_preprocessed_source + # since the latter runs in bats-exec-test's bash while this runs in bats-exec-file's + export BATS_TEST_SOURCE="$BATS_RUN_TMPDIR/${BATS_TEST_FILE_NUMBER?}-${BATS_TEST_FILENAME##*/}.src" +} + +bats_preprocess_source() { # index + bats_export_preprocess_source_BATS_TEST_SOURCE + # shellcheck disable=SC2153 + CHECK_BATS_COMMENT_COMMANDS=1 "$BATS_ROOT/libexec/bats-core/bats-preprocess" "$BATS_TEST_FILENAME" >"$BATS_TEST_SOURCE" +} + +bats_evaluate_preprocessed_source() { + # Dynamically loaded user files provided outside of Bats. + # shellcheck disable=SC1090 + source "${BATS_TEST_SOURCE?}" +} diff --git a/tooling/bats-core/lib/bats-core/semaphore.bash b/tooling/bats-core/lib/bats-core/semaphore.bash new file mode 100644 index 00000000000000..a196ac82d4bbbf --- /dev/null +++ b/tooling/bats-core/lib/bats-core/semaphore.bash @@ -0,0 +1,113 @@ +#!/usr/bin/env bash + +bats_run_under_flock() { + flock "$BATS_SEMAPHORE_DIR" "$@" +} + +bats_run_under_shlock() { + local lockfile="$BATS_SEMAPHORE_DIR/shlock.lock" + while ! shlock -p $$ -f "$lockfile"; do + sleep 1 + done + # we got the lock now, execute the command + "$@" + local status=$? + # free the lock + rm -f "$lockfile" + return $status + } + +# setup the semaphore environment for the loading file +bats_semaphore_setup() { + export -f bats_semaphore_get_free_slot_count + export -f bats_semaphore_acquire_while_locked + export BATS_SEMAPHORE_DIR="$BATS_RUN_TMPDIR/semaphores" + + if command -v flock >/dev/null; then + BATS_LOCKING_IMPLEMENTATION=flock + elif command -v shlock >/dev/null; then + BATS_LOCKING_IMPLEMENTATION=shlock + else + printf "ERROR: flock/shlock is required for parallelization within files!\n" >&2 + exit 1 + fi +} + +# $1 - output directory for stdout/stderr +# $@ - command to run +# run the given command in a semaphore +# block when there is no free slot for the semaphore +# when there is a free slot, run the command in background +# gather the output of the command in files in the given directory +bats_semaphore_run() { + local output_dir=$1 + shift + local semaphore_slot + semaphore_slot=$(bats_semaphore_acquire_slot) + bats_semaphore_release_wrapper "$output_dir" "$semaphore_slot" "$@" & + printf "%d\n" "$!" +} + +# $1 - output directory for stdout/stderr +# $@ - command to run +# this wraps the actual function call to install some traps on exiting +bats_semaphore_release_wrapper() { + local output_dir="$1" + local semaphore_name="$2" + shift 2 # all other parameters will be use for the command to execute + + # shellcheck disable=SC2064 # we want to expand the semaphore_name right now! + trap "status=$?; bats_semaphore_release_slot '$semaphore_name'; exit $status" EXIT + + mkdir -p "$output_dir" + "$@" 2>"$output_dir/stderr" >"$output_dir/stdout" + local status=$? + + # bash bug: the exit trap is not called for the background process + bats_semaphore_release_slot "$semaphore_name" + trap - EXIT # avoid calling release twice + return $status +} + +bats_semaphore_acquire_while_locked() { + if [[ $(bats_semaphore_get_free_slot_count) -gt 0 ]]; then + local slot=0 + while [[ -e "$BATS_SEMAPHORE_DIR/slot-$slot" ]]; do + ((++slot)) + done + if [[ $slot -lt $BATS_SEMAPHORE_NUMBER_OF_SLOTS ]]; then + touch "$BATS_SEMAPHORE_DIR/slot-$slot" && printf "%d\n" "$slot" && return 0 + fi + fi + return 1 +} + +# block until a semaphore slot becomes free +# prints the number of the slot that it received +bats_semaphore_acquire_slot() { + mkdir -p "$BATS_SEMAPHORE_DIR" + # wait for a slot to become free + # TODO: avoid busy waiting by using signals -> this opens op prioritizing possibilities as well + while true; do + # don't lock for reading, we are fine with spuriously getting no free slot + if [[ $(bats_semaphore_get_free_slot_count) -gt 0 ]]; then + bats_run_under_"$BATS_LOCKING_IMPLEMENTATION" \ + bash -c bats_semaphore_acquire_while_locked \ + && break + fi + sleep 1 + done +} + +bats_semaphore_release_slot() { + # we don't need to lock this, since only our process owns this file + # and freeing a semaphore cannot lead to conflicts with others + rm "$BATS_SEMAPHORE_DIR/slot-$1" # this will fail if we had not acquired a semaphore! +} + +bats_semaphore_get_free_slot_count() { + # find might error out without returning something useful when a file is deleted, + # while the directory is traversed -> only continue when there was no error + until used_slots=$(find "$BATS_SEMAPHORE_DIR" -name 'slot-*' 2>/dev/null | wc -l); do :; done + echo $((BATS_SEMAPHORE_NUMBER_OF_SLOTS - used_slots)) +} diff --git a/tooling/bats-core/lib/bats-core/test_functions.bash b/tooling/bats-core/lib/bats-core/test_functions.bash new file mode 100644 index 00000000000000..788d7ecc7992c8 --- /dev/null +++ b/tooling/bats-core/lib/bats-core/test_functions.bash @@ -0,0 +1,509 @@ +#!/usr/bin/env bash + +# this must be called for each test file! +_bats_test_functions_setup() { # + BATS_TEST_DIRNAME="${BATS_TEST_FILENAME%/*}" + BATS_TEST_NAMES=() + # shellcheck disable=SC2034 + BATS_TEST_NUMBER=${1?} +} + +# shellcheck source=lib/bats-core/warnings.bash +source "$BATS_ROOT/$BATS_LIBDIR/bats-core/warnings.bash" + +# find_in_bats_lib_path echoes the first recognized load path to +# a library in BATS_LIB_PATH or relative to BATS_TEST_DIRNAME. +# +# Libraries relative to BATS_TEST_DIRNAME take precedence over +# BATS_LIB_PATH. +# +# If no library is found find_in_bats_lib_path returns 1. +find_in_bats_lib_path() { # + local return_var="${1:?}" + local library_name="${2:?}" + + local -a bats_lib_paths + IFS=: read -ra bats_lib_paths <<<"$BATS_LIB_PATH" + + for path in "${bats_lib_paths[@]}"; do + if [[ -f "$path/$library_name" ]]; then + printf -v "$return_var" "%s" "$path/$library_name" + # A library load path was found, return + return 0 + elif [[ -f "$path/$library_name/load.bash" ]]; then + printf -v "$return_var" "%s" "$path/$library_name/load.bash" + # A library load path was found, return + return 0 + fi + done + + return 1 +} + +# bats_internal_load expects an absolute path that is a library load path. +# +# If the library load path points to a file (a library loader) it is +# sourced. +# +# If it points to a directory all files ending in .bash inside of the +# directory are sourced. +# +# If the sourcing of the library loader or of a file in a library +# directory fails bats_internal_load prints an error message and returns 1. +# +# If the passed library load path is not absolute or is not a valid file +# or directory bats_internal_load prints an error message and returns 1. +bats_internal_load() { + local library_load_path="${1:?}" + + if [[ "${library_load_path:0:1}" != / ]]; then + printf "Passed library load path is not an absolute path: %s\n" "$library_load_path" >&2 + return 1 + fi + + # library_load_path is a library loader + if [[ -f "$library_load_path" ]]; then + # shellcheck disable=SC1090 + if ! source "$library_load_path"; then + printf "Error while sourcing library loader at '%s'\n" "$library_load_path" >&2 + return 1 + fi + return 0 + fi + + printf "Passed library load path is neither a library loader nor library directory: %s\n" "$library_load_path" >&2 + return 1 +} + +# bats_load_safe accepts an argument called 'slug' and attempts to find and +# source a library based on the slug. +# +# A slug can be an absolute path or a relative path. +# +# If the slug is not an absolute path it is resolved relative to +# BATS_TEST_DIRNAME +# +# The resolved slug is passed to bats_internal_load. +# If bats_internal_load fails bats_load_safe returns 1. +# +# If no library load path can be found bats_load_safe prints an error message +# and returns 1. +bats_load_safe() { + local slug="${1:?}" + if [[ ${slug:0:1} != / ]]; then # relative paths are relative to BATS_TEST_DIRNAME + slug="$BATS_TEST_DIRNAME/$slug" + fi + + if [[ -f "$slug.bash" ]]; then + bats_internal_load "$slug.bash" + return $? + elif [[ -f "$slug" ]]; then + bats_internal_load "$slug" + return $? + fi + + # loading from PATH (retained for backwards compatibility) + if [[ ! -f "$1" ]] && type -P "$1" >/dev/null; then + # shellcheck disable=SC1090 + source "$1" + return $? + fi + + # No library load path can be found + printf "bats_load_safe: Could not find '%s'[.bash]\n" "$slug" >&2 + return 1 +} + +bats_load_library_safe() { # + local slug="${1:?}" library_path + + # Check for library load paths in BATS_TEST_DIRNAME and BATS_LIB_PATH + if [[ ${slug:0:1} != / ]]; then + if ! find_in_bats_lib_path library_path "$slug"; then + printf "Could not find library '%s' relative to test file or in BATS_LIB_PATH\n" "$slug" >&2 + return 1 + fi + else + # absolute paths are taken as is + library_path="$slug" + if [[ ! -f "$library_path" ]]; then + printf "Could not find library on absolute path '%s'\n" "$library_path" >&2 + return 1 + fi + fi + + bats_internal_load "$library_path" + return $? +} + +# immediately exit on error, use bats_load_library_safe to catch and handle errors +bats_load_library() { # + if ! bats_load_library_safe "$@"; then + exit 1 + fi +} + +# load acts like bats_load_safe but exits the shell instead of returning 1. +load() { + if ! bats_load_safe "$@"; then + exit 1 + fi +} + +bats_redirect_stderr_into_file() { + "$@" 2>>"$bats_run_separate_stderr_file" # use >> to see collisions' content +} + +bats_merge_stdout_and_stderr() { + "$@" 2>&1 +} + +# write separate lines from into +bats_separate_lines() { # + local -r output_array_name="$1" + local -r input_var_name="$2" + local input="${!input_var_name}" + if [[ $keep_empty_lines ]]; then + local bats_separate_lines_lines=() + if [[ -n "$input" ]]; then # avoid getting an empty line for empty input + # remove one trailing \n if it exists to compensate its addition by <<< + input=${input%$'\n'} + while IFS= read -r line; do + bats_separate_lines_lines+=("$line") + done <<<"${input}" + fi + eval "${output_array_name}=(\"\${bats_separate_lines_lines[@]}\")" + else + # shellcheck disable=SC2034,SC2206 + IFS=$'\n' read -d '' -r -a "$output_array_name" <<<"${!input_var_name}" || true # don't fail due to EOF + fi +} + +bats_pipe() { # [-N] [--] command0 [ \| command1 [ \| command2 [...]]] + # This will run each command given, piping them appropriately. + # Meant to be used in combination with `run` helper to allow piped commands + # to be used. + # Note that `\|` must be used, not `|`. + # By default, the exit code of this command will be the last failure in the + # chain of piped commands (similar to `set -o pipefail`). + # Supplying -N (e.g. -0) will instead always use the exit code of the command + # at that position in the chain. + # --returned-status=N could be used as an alternative to -N. This also allows + # for negative values (which count from the end in reverse order). + + local pipestatus_position= + + # parse options starting with - + while [[ $# -gt 0 ]] && [[ $1 == -* ]]; do + case "$1" in + -[0-9]*) + pipestatus_position="${1#-}" + ;; + --returned-status*) + if [ "$1" = "--returned-status" ]; then + pipestatus_position="$2" + shift + elif [[ "$1" =~ ^--returned-status= ]]; then + pipestatus_position="${1#--returned-status=}" + else + printf "Usage error: unknown flag '%s'" "$1" >&2 + return 1 + fi + ;; + --) + shift # eat the -- before breaking away + break + ;; + *) + printf "Usage error: unknown flag '%s'" "$1" >&2 + return 1 + ;; + esac + shift + done + + # parse and validate arguments, escape as necessary + local -a commands_and_args=("$@") + local -a escaped_args=() + local -i pipe_count=0 + local -i previous_pipe_index=-1 + local -i index=0 + for (( index = 0; index < $#; index++ )); do + local current_command_or_arg="${commands_and_args[$index]}" + local escaped_arg="$current_command_or_arg" + if [[ "$current_command_or_arg" != '|' ]]; then + # escape args to protect them when eval'd (e.g. if they contain whitespace). + printf -v escaped_arg "%q" "$current_command_or_arg" + elif [ "$current_command_or_arg" = "|" ]; then + if [ "$index" -eq 0 ]; then + printf "Usage error: Cannot have leading \`\\|\`.\n" >&2 + return 1 + fi + if (( (previous_pipe_index + 1) >= index )); then + printf "Usage error: Cannot have consecutive \`\\|\`. Found at argument position '%s'.\n" "$index" >&2 + return 1 + fi + (( ++pipe_count )) + previous_pipe_index="$index" + fi + escaped_args+=("$escaped_arg") + done + + if (( (previous_pipe_index > 0) && (previous_pipe_index == ($# - 1)) )); then + printf "Usage error: Cannot have trailing \`\\|\`.\n" >&2 + return 1 + fi + + if (( pipe_count == 0 )); then + # Don't allow for no pipes. This might be a typo in the test, + # e.g. `run bats_pipe command0 | command1` + # instead of `run bats_pipe command0 \| command1` + # Unfortunately, we can't catch `run bats_pipe command0 \| command1 | command2`. + # But this check is better than just allowing no pipes. + printf "Usage error: No \`\\|\`s found. Is this an error?\n" >&2 + return 1 + fi + + # there will be pipe_count + 1 entries in PIPE_STATUS (pipe_count number of \|'s between each entry). + # valid indices are [-(pipe_count + 1), pipe_count] + if [ -n "$pipestatus_position" ] && (( (pipestatus_position > pipe_count) || (-pipestatus_position > (pipe_count + 1)) )); then + printf "Usage error: Too large of -N argument (or --returned-status) given. Argument value: '%s'.\n" "$pipestatus_position" >&2 + return 1 + fi + + # run commands and return appropriate pipe status + local -a __bats_pipe_eval_pipe_status=() + eval "${escaped_args[*]}" '; __bats_pipe_eval_pipe_status=(${PIPESTATUS[@]})' + + local result_status= + if [ -z "$pipestatus_position" ]; then + # if we are performing default "last failure" behavior, + # iterate backwards through pipe_status to find the last error. + result_status=0 + for index in "${!__bats_pipe_eval_pipe_status[@]}"; do + # OSX bash doesn't support negative indexing. + local backward_iter_index="$((${#__bats_pipe_eval_pipe_status[@]} - index - 1))" + local status_at_backward_iter_index="${__bats_pipe_eval_pipe_status[$backward_iter_index]}" + if (( status_at_backward_iter_index != 0 )); then + result_status="$status_at_backward_iter_index" + break; + fi + done + elif (( pipestatus_position >= 0 )); then + result_status="${__bats_pipe_eval_pipe_status[$pipestatus_position]}" + else + # Must use positive values for some bash's (like OSX). + local backward_iter_index="$((${#__bats_pipe_eval_pipe_status[@]} + pipestatus_position))" + result_status="${__bats_pipe_eval_pipe_status[$backward_iter_index]}" + fi + + return "$result_status" +} + +run() { # [!|-N] [--keep-empty-lines] [--separate-stderr] [--] + # This has to be restored on exit from this function to avoid leaking our trap INT into surrounding code. + # Non zero exits won't restore under the assumption that they will fail the test before it can be aborted, + # which allows us to avoid duplicating the restore code on every exit path + trap bats_interrupt_trap_in_run INT + local expected_rc= + local keep_empty_lines= + local output_case=merged + local has_flags= + # parse options starting with - + while [[ $# -gt 0 ]] && [[ $1 == -* || $1 == '!' ]]; do + has_flags=1 + case "$1" in + '!') + expected_rc=-1 + ;; + -[0-9]*) + expected_rc=${1#-} + if [[ $expected_rc =~ [^0-9] ]]; then + printf "Usage error: run: '-NNN' requires numeric NNN (got: %s)\n" "$expected_rc" >&2 + return 1 + elif [[ $expected_rc -gt 255 ]]; then + printf "Usage error: run: '-NNN': NNN must be <= 255 (got: %d)\n" "$expected_rc" >&2 + return 1 + fi + ;; + --keep-empty-lines) + keep_empty_lines=1 + ;; + --separate-stderr) + output_case="separate" + ;; + --) + shift # eat the -- before breaking away + break + ;; + *) + printf "Usage error: unknown flag '%s'" "$1" >&2 + return 1 + ;; + esac + shift + done + + if [[ -n $has_flags ]]; then + bats_warn_minimum_guaranteed_version "Using flags on \`run\`" 1.5.0 + fi + + local pre_command= + + case "$output_case" in + merged) # redirects stderr into stdout and fills only $output/$lines + pre_command=bats_merge_stdout_and_stderr + ;; + separate) # splits stderr into own file and fills $stderr/$stderr_lines too + local bats_run_separate_stderr_file + bats_run_separate_stderr_file="$(mktemp "${BATS_TEST_TMPDIR}/separate-stderr-XXXXXX")" + pre_command=bats_redirect_stderr_into_file + ;; + esac + + local origFlags="$-" + set +eET + if [[ $keep_empty_lines ]]; then + # 'output', 'status', 'lines' are global variables available to tests. + # preserve trailing newlines by appending . and removing it later + # shellcheck disable=SC2034 + output="$( + "$pre_command" "$@" + status=$? + printf . + exit $status + )" && status=0 || status=$? + output="${output%.}" + else + # 'output', 'status', 'lines' are global variables available to tests. + # shellcheck disable=SC2034 + output="$("$pre_command" "$@")" && status=0 || status=$? + fi + + bats_separate_lines lines output + + if [[ "$output_case" == separate ]]; then + # shellcheck disable=SC2034 + read -d '' -r stderr <"$bats_run_separate_stderr_file" || true + bats_separate_lines stderr_lines stderr + else + unset stderr stderr_lines + fi + + # shellcheck disable=SC2034 + BATS_RUN_COMMAND="${*}" + set "-$origFlags" + + bats_run_print_output() { + if [[ -n "$output" ]]; then + printf "%s\n" "$output" + fi + if [[ "$output_case" == separate && -n "$stderr" ]]; then + printf "stderr:\n%s\n" "$stderr" + fi + } + + if [[ -n "$expected_rc" ]]; then + if [[ "$expected_rc" = "-1" ]]; then + if [[ "$status" -eq 0 ]]; then + BATS_ERROR_SUFFIX=", expected nonzero exit code!" + bats_run_print_output + return 1 + fi + elif [ "$status" -ne "$expected_rc" ]; then + # shellcheck disable=SC2034 + BATS_ERROR_SUFFIX=", expected exit code $expected_rc, got $status" + bats_run_print_output + return 1 + fi + elif [[ "$status" -eq 127 ]]; then # "command not found" + bats_generate_warning 1 "$BATS_RUN_COMMAND" + fi + + if [[ ${BATS_VERBOSE_RUN:-} ]]; then + bats_run_print_output + fi + + # don't leak our trap into surrounding code + trap bats_interrupt_trap INT +} + +setup() { + return 0 +} + +teardown() { + return 0 +} + +skip() { + # if this is a skip in teardown ... + if [[ -n "${BATS_TEARDOWN_STARTED-}" ]]; then + # ... we want to skip the rest of teardown. + # communicate to bats_exit_trap that the teardown was completed without error + # shellcheck disable=SC2034 + BATS_TEARDOWN_COMPLETED=1 + # if we are already in the exit trap (e.g. due to previous skip) ... + if [[ "$BATS_TEARDOWN_STARTED" == as-exit-trap ]]; then + # ... we need to do the rest of the tear_down_trap that would otherwise be skipped after the next call to exit + bats_exit_trap + # and then do the exit (at the end of this function) + fi + # if we aren't in exit trap, the normal exit handling should suffice + else + # ... this is either skip in test or skip in setup. + # Following variables are used in bats-exec-test which sources this file + # shellcheck disable=SC2034 + BATS_TEST_SKIPPED="${1:-1}" + # shellcheck disable=SC2034 + BATS_TEST_COMPLETED=1 + fi + exit 0 +} + +bats_test_function() { + local tags=() + while (( $# > 0 )); do + case "$1" in + --description) + local test_description= + # use eval to resolve variable references in test names + eval "printf -v test_description '%s' \"$2\"" + shift 2 + ;; + --tags) + IFS=',' read -ra tags <<<"$2" + shift 2 + ;; + --) + shift + break + ;; + *) + printf "ERROR: unknown option %s for bats_test_function" "$1" >&2 + exit 1 + ;; + esac + done + BATS_TEST_NAMES+=("$*") + local quoted_parameters + printf -v quoted_parameters " %q" "$@" + quoted_parameters=${quoted_parameters:1} # cut off leading space + + # if this is the currently selected test, set tags and name + # this should only be entered from bats-exec-test + if [[ ${BATS_TEST_NAME-} == "$quoted_parameters" ]]; then + # shellcheck disable=SC2034 + BATS_TEST_TAGS=("${tags[@]+${tags[@]}}") + export BATS_TEST_DESCRIPTION="${test_description-$*}" + # shellcheck disable=SC2034 + BATS_TEST_COMMAND=("$@") + fi +} + +# decides whether a failed test should be run again +bats_should_retry_test() { + # test try number starts at 1 + # 0 retries means run only first try + ((BATS_TEST_TRY_NUMBER <= BATS_TEST_RETRIES)) +} diff --git a/tooling/bats-core/lib/bats-core/tracing.bash b/tooling/bats-core/lib/bats-core/tracing.bash new file mode 100644 index 00000000000000..0fc12102f8ab27 --- /dev/null +++ b/tooling/bats-core/lib/bats-core/tracing.bash @@ -0,0 +1,425 @@ +#!/usr/bin/env bash + +# shellcheck source=lib/bats-core/common.bash +source "$BATS_ROOT/$BATS_LIBDIR/bats-core/common.bash" + +# set limit such that traces are only captured for calls at the same depth as this function in the calltree +bats_set_stacktrace_limit() { + BATS_STACK_TRACE_LIMIT=$(( ${#FUNCNAME[@]} - 1 )) # adjust by -1 to account for call to this functions +} + +bats_capture_stack_trace() { + local test_file + local funcname + local i + + BATS_DEBUG_LAST_STACK_TRACE=() + local limit=$(( ${#FUNCNAME[@]} - ${BATS_STACK_TRACE_LIMIT-0} )) + # TODO: why is the line number off by one in @test "--trace recurses into functions but not into run" + for ((i = 2; i < limit ; ++i)); do + # Use BATS_TEST_SOURCE if necessary to work around Bash < 4.4 bug whereby + # calling an exported function erases the test file's BASH_SOURCE entry. + test_file="${BASH_SOURCE[$i]:-$BATS_TEST_SOURCE}" + funcname="${FUNCNAME[$i]}" + BATS_DEBUG_LAST_STACK_TRACE+=("${BASH_LINENO[$((i - 1))]} $funcname $test_file") + done +} + +bats_get_failure_stack_trace() { + local stack_trace_var + # See bats_debug_trap for details. + if [[ -n "${BATS_DEBUG_LAST_STACK_TRACE_IS_VALID:-}" ]]; then + stack_trace_var=BATS_DEBUG_LAST_STACK_TRACE + else + stack_trace_var=BATS_DEBUG_LASTLAST_STACK_TRACE + fi + # shellcheck disable=SC2016 + eval "$(printf \ + '%s=(${%s[@]+"${%s[@]}"})' \ + "${1}" \ + "${stack_trace_var}" \ + "${stack_trace_var}")" +} + +bats_print_stack_trace() { + local frame + local index=1 + local count="${#@}" + local filename + local lineno + + for frame in "$@"; do + bats_frame_filename "$frame" 'filename' + bats_trim_filename "$filename" 'filename' + bats_frame_lineno "$frame" 'lineno' + + printf '%s' "${BATS_STACK_TRACE_PREFIX-# }" + if [[ $index -eq 1 ]]; then + printf '(' + else + printf ' ' + fi + + local fn + bats_frame_function "$frame" 'fn' + if [[ "$fn" != "${BATS_TEST_NAME-}" ]] && + # don't print "from function `source'"", + # when failing in free code during `source $test_file` from bats-exec-file + ! [[ "$fn" == 'source' && $index -eq $count ]]; then + local quoted_fn + bats_quote_code quoted_fn "$fn" + printf "from function %s " "$quoted_fn" + fi + + local reference + bats_format_file_line_reference reference "$filename" "$lineno" + if [[ $index -eq $count ]]; then + printf 'in test file %s)\n' "$reference" + else + printf 'in file %s,\n' "$reference" + fi + + ((++index)) + done +} + +bats_print_failed_command() { + local stack_trace=("${@}") + if [[ ${#stack_trace[@]} -eq 0 ]]; then + return 0 + fi + local frame="${stack_trace[${#stack_trace[@]} - 1]}" + local filename + local lineno + local failed_line + local failed_command + + bats_frame_filename "$frame" 'filename' + bats_frame_lineno "$frame" 'lineno' + bats_extract_line "$filename" "$lineno" 'failed_line' + bats_strip_string "$failed_line" 'failed_command' + local quoted_failed_command + bats_quote_code quoted_failed_command "$failed_command" + printf '# %s ' "${quoted_failed_command}" + + if [[ "${BATS_TIMED_OUT-NOTSET}" != NOTSET ]]; then + # the other values can be safely overwritten here, + # as the timeout is the primary reason for failure + BATS_ERROR_SUFFIX=" due to timeout" + fi + + if [[ "$BATS_ERROR_STATUS" -eq 1 ]]; then + printf 'failed%s\n' "$BATS_ERROR_SUFFIX" + else + printf 'failed with status %d%s\n' "$BATS_ERROR_STATUS" "$BATS_ERROR_SUFFIX" + fi +} + +bats_frame_lineno() { + printf -v "$2" '%s' "${1%% *}" +} + +bats_frame_function() { + local __bff_function="${1#* }" + printf -v "$2" '%s' "${__bff_function%% *}" +} + +bats_frame_filename() { + local __bff_filename="${1#* }" + __bff_filename="${__bff_filename#* }" + + if [[ "$__bff_filename" == "${BATS_TEST_SOURCE-}" ]]; then + __bff_filename="$BATS_TEST_FILENAME" + fi + printf -v "$2" '%s' "$__bff_filename" +} + +bats_extract_line() { + local __bats_extract_line_line + local __bats_extract_line_index=0 + + while IFS= read -r __bats_extract_line_line; do + if [[ "$((++__bats_extract_line_index))" -eq "$2" ]]; then + printf -v "$3" '%s' "${__bats_extract_line_line%$'\r'}" + break + fi + done <"$1" +} + +bats_strip_string() { + [[ "$1" =~ ^[[:space:]]*(.*)[[:space:]]*$ ]] + printf -v "$2" '%s' "${BASH_REMATCH[1]}" +} + +bats_trim_filename() { + printf -v "$2" '%s' "${1#"$BATS_CWD"/}" +} + +# normalize a windows path from e.g. C:/directory to /c/directory +# The path must point to an existing/accessible directory, not a file! +bats_normalize_windows_dir_path() { # + local output_var="$1" path="$2" + if [[ "$output_var" != NORMALIZED_INPUT ]]; then + local NORMALIZED_INPUT + fi + if [[ $path == ?:* ]]; then + NORMALIZED_INPUT="$( + cd "$path" || exit 1 + pwd + )" + else + NORMALIZED_INPUT="$path" + fi + printf -v "$output_var" "%s" "$NORMALIZED_INPUT" +} + +bats_emit_trace_context() { + local padding='$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$' + local reference + bats_format_file_line_reference reference "${file##*/}" "$line" + printf '%s [%s]\n' "${padding::${#BASH_LINENO[@]}-limit-3}" "$reference" >&4 +} + +bats_emit_trace_command() { + local padding='$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$' + printf '%s %s\n' "${padding::${#BASH_LINENO[@]}-limit-3}" "$BASH_COMMAND" >&4 + + # keep track of printed commands + BATS_LAST_BASH_COMMAND="$BASH_COMMAND" + BATS_LAST_BASH_LINENO="$line" +} + +BATS_EMIT_TRACE_LAST_STACK_DIFF=0 + +bats_emit_trace() { + if [[ ${BATS_TRACE_LEVEL:-0} -gt 0 ]]; then + local line=${BASH_LINENO[1]} limit=${BATS_STACK_TRACE_LIMIT-0} + # shellcheck disable=SC2016 + if (( ${#FUNCNAME[@]} > limit + 2 )) # only emit below BATS_STRACK_TRACE_LIMIT (adjust by 2 for trap+this function call) + # avoid printing the same line twice on errexit + [[ $BASH_COMMAND != "$BATS_LAST_BASH_COMMAND" || $line != "$BATS_LAST_BASH_LINENO" ]]; then + local file="${BASH_SOURCE[2]}" # index 2: skip over bats_emit_trace and bats_debug_trap + if [[ $file == "${BATS_TEST_SOURCE:-}" ]]; then + file="$BATS_TEST_FILENAME" + fi + # stack size difference since last call of this function + # <0: means new function call + # >0: means return + # =0: in same function as before (assuming we did not skip return/call) + local stack_diff=$(( BATS_LAST_STACK_DEPTH - ${#BASH_LINENO[@]} )) + # show context immediately when returning or on second command in new function + # as the first "command" is the function itself + if (( stack_diff > 0 )) || (( BATS_EMIT_TRACE_LAST_STACK_DIFF < 0 )); then + bats_emit_trace_context + fi + # only print command when moving up or staying in same function + # again, avoids printing the first command (the function itself) in new function + if (( stack_diff >= 0 )); then + bats_emit_trace_command + fi + + BATS_EMIT_TRACE_LAST_STACK_DIFF=$stack_diff + fi + # always update to detect stack depth changes regardless of printing + BATS_LAST_STACK_DEPTH="${#BASH_LINENO[@]}" + fi +} + +# bats_debug_trap tracks the last line of code executed within a test. This is +# necessary because $BASH_LINENO is often incorrect inside of ERR and EXIT +# trap handlers. +# +# Below are tables describing different command failure scenarios and the +# reliability of $BASH_LINENO within different the executed DEBUG, ERR, and EXIT +# trap handlers. Naturally, the behaviors change between versions of Bash. +# +# Table rows should be read left to right. For example, on bash version +# 4.0.44(2)-release, if a test executes `false` (or any other failing external +# command), bash will do the following in order: +# 1. Call the DEBUG trap handler (bats_debug_trap) with $BASH_LINENO referring +# to the source line containing the `false` command, then +# 2. Call the DEBUG trap handler again, but with an incorrect $BASH_LINENO, then +# 3. Call the ERR trap handler, but with a (possibly-different) incorrect +# $BASH_LINENO, then +# 4. Call the DEBUG trap handler again, but with $BASH_LINENO set to 1, then +# 5. Call the EXIT trap handler, with $BASH_LINENO set to 1. +# +# bash version 4.4.20(1)-release +# command | first DEBUG | second DEBUG | ERR | third DEBUG | EXIT +# -------------+-------------+--------------+---------+-------------+-------- +# false | OK | OK | OK | BAD[1] | BAD[1] +# [[ 1 = 2 ]] | OK | BAD[2] | BAD[2] | BAD[1] | BAD[1] +# (( 1 = 2 )) | OK | BAD[2] | BAD[2] | BAD[1] | BAD[1] +# ! true | OK | --- | BAD[4] | --- | BAD[1] +# $var_dne | OK | --- | --- | BAD[1] | BAD[1] +# source /dne | OK | --- | --- | BAD[1] | BAD[1] +# +# bash version 4.0.44(2)-release +# command | first DEBUG | second DEBUG | ERR | third DEBUG | EXIT +# -------------+-------------+--------------+---------+-------------+-------- +# false | OK | BAD[3] | BAD[3] | BAD[1] | BAD[1] +# [[ 1 = 2 ]] | OK | --- | BAD[3] | --- | BAD[1] +# (( 1 = 2 )) | OK | --- | BAD[3] | --- | BAD[1] +# ! true | OK | --- | BAD[3] | --- | BAD[1] +# $var_dne | OK | --- | --- | BAD[1] | BAD[1] +# source /dne | OK | --- | --- | BAD[1] | BAD[1] +# +# [1] The reported line number is always 1. +# [2] The reported source location is that of the beginning of the function +# calling the command. +# [3] The reported line is that of the last command executed in the DEBUG trap +# handler. +# [4] The reported source location is that of the call to the function calling +# the command. +bats_debug_trap() { + # on windows we sometimes get a mix of paths (when install via nmp install -g) + # which have C:/... or /c/... comparing them is going to be problematic. + # We need to normalize them to a common format! + local NORMALIZED_INPUT + bats_normalize_windows_dir_path NORMALIZED_INPUT "${1%/*}" + local path + for path in "${BATS_DEBUG_EXCLUDE_PATHS[@]}"; do + if [[ "$NORMALIZED_INPUT" == "$path"* ]]; then + return # skip this call + fi + done + + # don't update the trace within library functions or we get backtraces from inside traps + # also don't record new stack traces while handling interruptions, to avoid overriding the interrupted command + if [[ "${BATS_INTERRUPTED-NOTSET}" == NOTSET && + "${BATS_TIMED_OUT-NOTSET}" == NOTSET ]]; then + BATS_DEBUG_LASTLAST_STACK_TRACE=( + ${BATS_DEBUG_LAST_STACK_TRACE[@]+"${BATS_DEBUG_LAST_STACK_TRACE[@]}"} + ) + + BATS_DEBUG_LAST_LINENO=(${BASH_LINENO[@]+"${BASH_LINENO[@]}"}) + BATS_DEBUG_LAST_SOURCE=(${BASH_SOURCE[@]+"${BASH_SOURCE[@]}"}) + bats_capture_stack_trace + bats_emit_trace + fi +} + +# For some versions of Bash, the `ERR` trap may not always fire for every +# command failure, but the `EXIT` trap will. Also, some command failures may not +# set `$?` properly. See #72 and #81 for details. +# +# For this reason, we call `bats_check_status_from_trap` at the very beginning +# of `bats_teardown_trap` and check the value of `$BATS_TEST_COMPLETED` before +# taking other actions. We also adjust the exit status value if needed. +# +# See `bats_exit_trap` for an additional EXIT error handling case when `$?` +# isn't set properly during `teardown()` errors. +bats_check_status_from_trap() { + local status="$?" + if [[ -z "${BATS_TEST_COMPLETED:-}" ]]; then + BATS_ERROR_STATUS="${BATS_ERROR_STATUS:-$status}" + if [[ "$BATS_ERROR_STATUS" -eq 0 ]]; then + BATS_ERROR_STATUS=1 + fi + trap - DEBUG + fi +} + +bats_add_debug_exclude_path() { # + if [[ -z "$1" ]]; then # don't exclude everything + printf "bats_add_debug_exclude_path: Exclude path must not be empty!\n" >&2 + return 1 + fi + if [[ "$OSTYPE" == cygwin || "$OSTYPE" == msys ]]; then + local normalized_dir + bats_normalize_windows_dir_path normalized_dir "$1" + BATS_DEBUG_EXCLUDE_PATHS+=("$normalized_dir") + else + BATS_DEBUG_EXCLUDE_PATHS+=("$1") + fi +} + +bats_setup_tracing() { + # Variables for capturing accurate stack traces. See bats_debug_trap for + # details. + # + # BATS_DEBUG_LAST_LINENO, BATS_DEBUG_LAST_SOURCE, and + # BATS_DEBUG_LAST_STACK_TRACE hold data from the most recent call to + # bats_debug_trap. + # + # BATS_DEBUG_LASTLAST_STACK_TRACE holds data from two bats_debug_trap calls + # ago. + # + # BATS_DEBUG_LAST_STACK_TRACE_IS_VALID indicates that + # BATS_DEBUG_LAST_STACK_TRACE contains the stack trace of the test's error. If + # unset, BATS_DEBUG_LAST_STACK_TRACE is unreliable and + # BATS_DEBUG_LASTLAST_STACK_TRACE should be used instead. + BATS_DEBUG_LASTLAST_STACK_TRACE=() + BATS_DEBUG_LAST_LINENO=() + BATS_DEBUG_LAST_SOURCE=() + BATS_DEBUG_LAST_STACK_TRACE=() + BATS_DEBUG_LAST_STACK_TRACE_IS_VALID= + BATS_ERROR_SUFFIX= + BATS_DEBUG_EXCLUDE_PATHS=() + # exclude some paths by default + bats_add_debug_exclude_path "$BATS_ROOT/$BATS_LIBDIR/" + bats_add_debug_exclude_path "$BATS_ROOT/libexec/" + + exec 4<&1 # used for tracing + if [[ "${BATS_TRACE_LEVEL:-0}" -gt 0 ]]; then + # avoid undefined variable errors + BATS_LAST_BASH_COMMAND= + BATS_LAST_BASH_LINENO= + BATS_LAST_STACK_DEPTH= + # try to exclude helper libraries if found, this is only relevant for tracing + while read -r path; do + bats_add_debug_exclude_path "$path" + done < <(find "$PWD" -type d -name bats-assert -o -name bats-support) + fi + + local exclude_paths path + # exclude user defined libraries + IFS=':' read -r exclude_paths <<<"${BATS_DEBUG_EXCLUDE_PATHS:-}" + for path in "${exclude_paths[@]}"; do + if [[ -n "$path" ]]; then + bats_add_debug_exclude_path "$path" + fi + done + + # turn on traps after setting excludes to avoid tracing the exclude setup + trap 'bats_debug_trap "$BASH_SOURCE"' DEBUG + trap 'bats_error_trap' ERR +} + +# predefine to avoid problems when the user does not declare one +bats::on_failure() { + : +} + +bats_error_trap() { + bats_check_status_from_trap + bats::on_failure "$BATS_ERROR_STATUS" + + # If necessary, undo the most recent stack trace captured by bats_debug_trap. + # See bats_debug_trap for details. + if [[ "${BASH_LINENO[*]}" = "${BATS_DEBUG_LAST_LINENO[*]:-}" && + "${BASH_SOURCE[*]}" = "${BATS_DEBUG_LAST_SOURCE[*]:-}" && + -z "$BATS_DEBUG_LAST_STACK_TRACE_IS_VALID" ]]; then + BATS_DEBUG_LAST_STACK_TRACE=( + ${BATS_DEBUG_LASTLAST_STACK_TRACE[@]+"${BATS_DEBUG_LASTLAST_STACK_TRACE[@]}"} + ) + fi + BATS_DEBUG_LAST_STACK_TRACE_IS_VALID=1 +} + +bats_interrupt_trap() { + # mark the interruption, to handle during exit + BATS_INTERRUPTED=true + BATS_ERROR_STATUS=130 + # debug trap fires before interrupt trap but gets wrong linenumber (line 1) + # -> use last stack trace instead of BATS_DEBUG_LAST_STACK_TRACE_IS_VALID=true +} + +# this is used inside run() +bats_interrupt_trap_in_run() { + # mark the interruption, to handle during exit + BATS_INTERRUPTED=true + BATS_ERROR_STATUS=130 + BATS_DEBUG_LAST_STACK_TRACE_IS_VALID=true + exit 130 +} diff --git a/tooling/bats-core/lib/bats-core/validator.bash b/tooling/bats-core/lib/bats-core/validator.bash new file mode 100644 index 00000000000000..59fc2c1e69ee45 --- /dev/null +++ b/tooling/bats-core/lib/bats-core/validator.bash @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +bats_test_count_validator() { + trap '' INT # continue forwarding + header_pattern='[0-9]+\.\.[0-9]+' + IFS= read -r header + # repeat the header + printf "%s\n" "$header" + + # if we detect a TAP plan + if [[ "$header" =~ $header_pattern ]]; then + # extract the number of tests ... + local expected_number_of_tests="${header:3}" + # ... count the actual number of [not ] oks... + local actual_number_of_tests=0 + while IFS= read -r line; do + # forward line + printf "%s\n" "$line" + case "$line" in + 'ok '*) + ((++actual_number_of_tests)) + ;; + 'not ok'*) + ((++actual_number_of_tests)) + ;; + esac + done + # ... and error if they are not the same + if [[ "${actual_number_of_tests}" != "${expected_number_of_tests}" ]]; then + printf '# bats warning: Executed %s instead of expected %s tests\n' "$actual_number_of_tests" "$expected_number_of_tests" + return 1 + fi + else + # forward output unchanged + cat + fi +} diff --git a/tooling/bats-core/lib/bats-core/warnings.bash b/tooling/bats-core/lib/bats-core/warnings.bash new file mode 100644 index 00000000000000..5762d7430ec3cf --- /dev/null +++ b/tooling/bats-core/lib/bats-core/warnings.bash @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +# shellcheck source=lib/bats-core/tracing.bash +source "$BATS_ROOT/$BATS_LIBDIR/bats-core/tracing.bash" + +# generate a warning report for the parent call's call site +bats_generate_warning() { # [--no-stacktrace] [...] + local warning_number="${1-}" padding="00" + shift + local no_stacktrace= + if [[ ${1-} == --no-stacktrace ]]; then + no_stacktrace=1 + shift + fi + if [[ $warning_number =~ [0-9]+ ]] && ((warning_number < ${#BATS_WARNING_SHORT_DESCS[@]})); then + { + printf "BW%s: ${BATS_WARNING_SHORT_DESCS[$warning_number]}\n" "${padding:${#warning_number}}${warning_number}" "$@" + if [[ -z "$no_stacktrace" ]]; then + bats_capture_stack_trace + BATS_STACK_TRACE_PREFIX=' ' bats_print_stack_trace "${BATS_DEBUG_LAST_STACK_TRACE[@]}" + fi + } >>"$BATS_WARNING_FILE" 2>&3 + else + printf "Invalid Bats warning number '%s'. It must be an integer between 1 and %d." "$warning_number" "$((${#BATS_WARNING_SHORT_DESCS[@]} - 1))" >&2 + exit 1 + fi +} + +# generate a warning if the BATS_GUARANTEED_MINIMUM_VERSION is not high enough +bats_warn_minimum_guaranteed_version() { # + if bats_version_lt "$BATS_GUARANTEED_MINIMUM_VERSION" "$2"; then + bats_generate_warning 2 "$1" "$2" "$2" + fi +} + +# put after functions to avoid line changes in tests when new ones get added +BATS_WARNING_SHORT_DESCS=( + # to start with 1 + 'PADDING' + # see issue #578 for context + "\`run\`'s command \`%s\` exited with code 127, indicating 'Command not found'. Use run's return code checks, e.g. \`run -127\`, to fix this message." + "%s requires at least BATS_VERSION=%s. Use \`bats_require_minimum_version %s\` to fix this message." + "\`setup_suite\` is visible to test file '%s', but was not executed. It belongs into 'setup_suite.bash' to be picked up automatically." +) diff --git a/tooling/bats-core/libexec/bats-core/bats b/tooling/bats-core/libexec/bats-core/bats new file mode 100755 index 00000000000000..1ae3329233faf3 --- /dev/null +++ b/tooling/bats-core/libexec/bats-core/bats @@ -0,0 +1,516 @@ +#!/usr/bin/env bash +set -e + +export BATS_VERSION='1.12.0' +VALID_FORMATTERS="pretty, junit, tap, tap13" + +version() { + printf 'Bats %s\n' "$BATS_VERSION" +} + +abort() { + local print_usage=1 + if [[ ${1:-} == --no-print-usage ]]; then + print_usage= + shift + fi + printf 'Error: %s\n' "$1" >&2 + if [[ -n $print_usage ]]; then + usage >&2 + fi + exit 1 +} + +usage() { + local cmd="${0##*/}" + local line + + cat < + ${cmd} [-h | -v] + +HELP_TEXT_HEADER + + cat <<'HELP_TEXT_BODY' + is the path to a Bats test file, or the path to a directory + containing Bats test files (ending with ".bats") + + -c, --count Count test cases without running any tests + --code-quote-style