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/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 00000000000000..5c0b5c4082bb8f --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# 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) +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/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 00000000000000..95a652c3aa04f3 --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# 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 + +SCRIPT_DIR=$(cd -- "$(dirname -- "$0")" && pwd) +ROOT_DIR=$(cd -- "$SCRIPT_DIR/.." && pwd) + +# 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 + +# 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/|test/|tooling/|\.github/workflows/|starter/|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*) + # When remote_sha is all zeros, use upstream remote tip if available + base="$remote_sha" + if [[ "$remote_sha" =~ ^0+$ ]]; then + # Try origin/main; if unavailable, fall back to empty tree + if base=$(git rev-parse --quiet --verify origin/main); then :; else + base=$(git hash-object -t tree /dev/null) + fi + 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/.github/workflows/patch-workflow-tests.yml b/.github/workflows/patch-workflow-tests.yml new file mode 100644 index 00000000000000..c1ebd46d360c73 --- /dev/null +++ b/.github/workflows/patch-workflow-tests.yml @@ -0,0 +1,32 @@ +name: Patch Workflow Tests + +on: + push: + branches: + - main + - macOS-modernization-** + pull_request: + +jobs: + tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y kcov + - name: Configure git + run: | + git config --global user.email "ci@example.com" + git config --global user.name "Patch Workflow CI" + git config --global commit.gpgsign false + - name: Run workflow tests + run: script/test.sh + - name: Upload coverage artifact + if: always() + uses: actions/upload-artifact@v3 + with: + name: kcov-report + path: target/kcov + if-no-files-found: ignore 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/20250924-cumulative.patch b/.reapply-patches/macOS-modernization/20250924-cumulative.patch new file mode 100644 index 00000000000000..7c8596f2a64803 --- /dev/null +++ b/.reapply-patches/macOS-modernization/20250924-cumulative.patch @@ -0,0 +1,482 @@ +diff --git a/Cargo.lock b/Cargo.lock +index 46de7e804b..4bf6350e8f 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -781,24 +781,6 @@ dependencies = [ + "zbus", + ] + +-[[package]] +-name = "ashpd" +-version = "0.12.0" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-checksum = "da0986d5b4f0802160191ad75f8d33ada000558757db3defb70299ca95d9fcbd" +-dependencies = [ +- "async-fs", +- "async-net", +- "enumflags2", +- "futures-channel", +- "futures-util", +- "rand 0.9.1", +- "serde", +- "serde_repr", +- "url", +- "zbus", +-] +- + [[package]] + name = "askpass" + version = "0.1.0" +@@ -1350,6 +1332,22 @@ 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", ++ "log", ++ "pin-project-lite", ++ "tokio", ++ "tungstenite 0.27.0", ++] ++ + [[package]] + name = "async_zip" + version = "0.0.17" +@@ -2324,7 +2322,7 @@ dependencies = [ + "log", + "mint", + "naga", +- "objc2", ++ "objc2 0.6.1", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", +@@ -2382,13 +2380,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]] +@@ -3102,7 +3119,7 @@ name = "client" + version = "0.1.0" + dependencies = [ + "anyhow", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "base64 0.22.1", + "chrono", + "clock", +@@ -3324,7 +3341,7 @@ dependencies = [ + "assistant_context", + "assistant_slash_command", + "async-trait", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "audio", + "aws-config", + "aws-sdk-kinesis", +@@ -4937,7 +4954,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" + dependencies = [ + "bitflags 2.9.0", +- "objc2", ++ "objc2 0.6.1", + ] + + [[package]] +@@ -6204,7 +6221,7 @@ name = "fs" + version = "0.1.0" + dependencies = [ + "anyhow", +- "ashpd 0.11.0", ++ "ashpd", + "async-tar", + "async-trait", + "cocoa 0.26.0", +@@ -7035,7 +7052,7 @@ version = "0.1.0" + dependencies = [ + "anyhow", + "as-raw-xcb-connection", +- "ashpd 0.11.0", ++ "ashpd", + "async-task", + "backtrace", + "bindgen 0.71.1", +@@ -7067,18 +7084,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", +@@ -7749,6 +7768,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" +@@ -8450,7 +8479,7 @@ source = "git+https://github.com/ConradIrwin/runtimed?rev=7130c804216b6914355d15 + dependencies = [ + "anyhow", + "async-trait", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "futures 0.3.31", + "jupyter-protocol", + "serde", +@@ -9400,6 +9429,10 @@ dependencies = [ + "libc", + ] + ++[[package]] ++name = "macos_appkit_bridge" ++version = "0.1.0" ++ + [[package]] + name = "malloc_buf" + version = "0.0.6" +@@ -10414,6 +10447,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" +@@ -10430,7 +10479,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", +@@ -10444,7 +10493,7 @@ checksum = "10cbe18d879e20a4aea544f8befe38bcf52255eb63d3f23eca2842f3319e4c07" + dependencies = [ + "bitflags 2.9.0", + "libc", +- "objc2", ++ "objc2 0.6.1", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", +@@ -10458,7 +10507,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", + ] +@@ -10470,7 +10519,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "c0f1cc99bb07ad2ddb6527ddf83db6a15271bb036b3eb94b801cd44fdc666ee1" + dependencies = [ + "bitflags 2.9.0", +- "objc2", ++ "objc2 0.6.1", + ] + + [[package]] +@@ -10481,7 +10530,7 @@ checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" + dependencies = [ + "bitflags 2.9.0", + "dispatch2", +- "objc2", ++ "objc2 0.6.1", + ] + + [[package]] +@@ -10497,7 +10546,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", + ] + +@@ -10508,9 +10557,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", + ] +@@ -10522,7 +10571,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", +@@ -10535,7 +10584,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", +@@ -10629,12 +10678,12 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + + [[package]] + name = "oo7" +-version = "0.5.0" ++version = "0.4.3" + source = "registry+https://github.com/rust-lang/crates.io-index" +-checksum = "e3299dd401feaf1d45afd8fd1c0586f10fcfb22f244bb9afa942cec73503b89d" ++checksum = "6cb23d3ec3527d65a83be1c1795cb883c52cfa57147d42acc797127df56fc489" + dependencies = [ + "aes", +- "ashpd 0.12.0", ++ "ashpd", + "async-fs", + "async-io", + "async-lock", +@@ -13093,7 +13142,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", +@@ -13442,7 +13492,7 @@ name = "rpc" + version = "0.1.0" + dependencies = [ + "anyhow", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "base64 0.22.1", + "chrono", + "collections", +@@ -17163,6 +17213,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" +@@ -19602,7 +19669,7 @@ dependencies = [ + "arrayvec", + "async-compression", + "async-std", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "aws-config", + "aws-credential-types", + "aws-runtime", +@@ -19699,7 +19766,7 @@ dependencies = [ + "num-iter", + "num-rational", + "num-traits", +- "objc2", ++ "objc2 0.6.1", + "objc2-core-foundation", + "objc2-foundation", + "objc2-metal", +@@ -20156,7 +20223,7 @@ dependencies = [ + "agent_settings", + "agent_ui", + "anyhow", +- "ashpd 0.11.0", ++ "ashpd", + "askpass", + "assets", + "assistant_tools", +diff --git a/crates/collab/src/db/ids.rs b/crates/collab/src/db/ids.rs +index 8f116cfd63..6a536b2b2a 100644 +--- a/crates/collab/src/db/ids.rs ++++ b/crates/collab/src/db/ids.rs +@@ -62,8 +62,8 @@ macro_rules! id_type { + } + + impl sea_orm::sea_query::Nullable for $name { +- fn null() -> Value { +- Value::Int(None) ++ fn null() -> sea_orm::sea_query::Value { ++ sea_orm::sea_query::Value::Int(None) + } + } + }; +diff --git a/crates/macos_appkit_bridge/build.rs b/crates/macos_appkit_bridge/build.rs +new file mode 100644 +index 0000000000..e9cb6e0d5e +--- /dev/null ++++ b/crates/macos_appkit_bridge/build.rs +@@ -0,0 +1,53 @@ ++#[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 ++ ++ // Rebuild when the Swift sources change. ++ println!("cargo:rerun-if-changed=swift/Package.swift"); ++ println!("cargo:rerun-if-changed=swift/Sources"); ++ ++ // Select target architecture so cross-compiles (e.g. x86_64 on arm64) link correctly. ++ let target = std::env::var("TARGET").expect("TARGET unset"); ++ let arch_flag = match target.as_str() { ++ "aarch64-apple-darwin" => Some("arm64"), ++ "x86_64-apple-darwin" => Some("x86_64"), ++ _ => None, ++ }; ++ ++ // Build the Swift package containing our shim and the generated bridge. ++ let mut build_cmd = std::process::Command::new("swift"); ++ build_cmd.current_dir(&swift_dir).args(["build", "-c", "release"]); ++ if let Some(arch) = arch_flag { ++ build_cmd.args(["--arch", arch]); ++ } ++ let status = build_cmd.status().expect("Failed to spawn swift build"); ++ if !status.success() { ++ panic!("swift build failed: {:?}", status); ++ } ++ ++ // Link the produced static library; prefer arch-specific directory when present. ++ let arch_lib_dir = arch_flag.map(|arch| { ++ swift_dir ++ .join(".build") ++ .join(format!("{}-apple-macosx", arch)) ++ .join("release") ++ }); ++ let generic_lib_dir = swift_dir.join(".build").join("release"); ++ let lib_dir = arch_lib_dir ++ .as_ref() ++ .filter(|path| path.exists()) ++ .unwrap_or(&generic_lib_dir); ++ 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/repl/Cargo.toml b/crates/repl/Cargo.toml +index 6386dc330a..edfebcd112 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/.reapply-patches/macOS-modernization/20250925-cumulative.patch b/.reapply-patches/macOS-modernization/20250925-cumulative.patch new file mode 100644 index 00000000000000..b8e8a28db29db8 --- /dev/null +++ b/.reapply-patches/macOS-modernization/20250925-cumulative.patch @@ -0,0 +1,14747 @@ +diff --git a/.cargo/ci-config.toml b/.cargo/ci-config.toml +index d5e312c242..09e1af5c18 100644 +--- a/.cargo/ci-config.toml ++++ b/.cargo/ci-config.toml +@@ -10,15 +10,3 @@ + # Here, we opted to use `[target.'cfg(all())']` instead of `[build]` because `[target.'**']` is guaranteed to be cumulative. + [target.'cfg(all())'] + rustflags = ["-D", "warnings"] +- +-# Use Mold on Linux, because it's faster than GNU ld and LLD. +-# +-# We no longer set this in the default `config.toml` so that developers can opt in to Wild, which +-# is faster than Mold, in their own ~/.cargo/config.toml. +-[target.x86_64-unknown-linux-gnu] +-linker = "clang" +-rustflags = ["-C", "link-arg=-fuse-ld=mold"] +- +-[target.aarch64-unknown-linux-gnu] +-linker = "clang" +-rustflags = ["-C", "link-arg=-fuse-ld=mold"] +diff --git a/.cargo/config.toml b/.cargo/config.toml +index 9b2e6f51c9..a882cd67bf 100644 +--- a/.cargo/config.toml ++++ b/.cargo/config.toml +@@ -5,8 +5,15 @@ rustflags = ["-C", "symbol-mangling-version=v0", "--cfg", "tokio_unstable"] + [alias] + xtask = "run --package xtask --" + perf-test = ["test", "--profile", "release-fast", "--lib", "--bins", "--tests", "--all-features", "--config", "target.'cfg(true)'.runner='cargo run -p perf --release'", "--config", "target.'cfg(true)'.rustflags=[\"--cfg\", \"perf_enabled\"]"] +-# Keep similar flags here to share some ccache +-perf-compare = ["run", "--profile", "release-fast", "-p", "perf", "--config", "target.'cfg(true)'.rustflags=[\"--cfg\", \"perf_enabled\"]", "--", "compare"] ++perf-compare = ["run", "--release", "-p", "perf", "--", "compare"] ++ ++[target.x86_64-unknown-linux-gnu] ++linker = "clang" ++rustflags = ["-C", "link-arg=-fuse-ld=mold"] ++ ++[target.aarch64-unknown-linux-gnu] ++linker = "clang" ++rustflags = ["-C", "link-arg=-fuse-ld=mold"] + + [target.'cfg(target_os = "windows")'] + rustflags = [ +diff --git a/.config/hakari.toml b/.config/hakari.toml +index 9cc9c1e4ee..b1e2954743 100644 +--- a/.config/hakari.toml ++++ b/.config/hakari.toml +@@ -26,7 +26,7 @@ third-party = [ + # build of remote_server should not include scap / its x11 dependency + { name = "scap", git = "https://github.com/zed-industries/scap", rev = "808aa5c45b41e8f44729d02e38fd00a2fe2722e7" }, + # build of remote_server should not need to include on libalsa through rodio +- { name = "rodio", git = "https://github.com/RustAudio/rodio" }, ++ { name = "rodio", git = "https://github.com/RustAudio/rodio", branch = "better_wav_output"}, + ] + + [final-excludes] +diff --git a/Cargo.lock b/Cargo.lock +index d33f1d0290..a2f0aafef7 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -195,9 +195,9 @@ dependencies = [ + + [[package]] + name = "agent-client-protocol" +-version = "0.4.3" ++version = "0.4.2" + source = "registry+https://github.com/rust-lang/crates.io-index" +-checksum = "3aaa2bd05a2401887945f8bfd70026e90bc3cf96c62ab9eba2779835bf21dc60" ++checksum = "00e33b9f4bd34d342b6f80b7156d3a37a04aeec16313f264001e52d6a9118600" + dependencies = [ + "anyhow", + "async-broadcast", +@@ -486,6 +486,7 @@ dependencies = [ + "client", + "cloud_llm_client", + "component", ++ "feature_flags", + "gpui", + "language_model", + "serde", +@@ -780,24 +781,6 @@ dependencies = [ + "zbus", + ] + +-[[package]] +-name = "ashpd" +-version = "0.12.0" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-checksum = "da0986d5b4f0802160191ad75f8d33ada000558757db3defb70299ca95d9fcbd" +-dependencies = [ +- "async-fs", +- "async-net", +- "enumflags2", +- "futures-channel", +- "futures-util", +- "rand 0.9.1", +- "serde", +- "serde_repr", +- "url", +- "zbus", +-] +- + [[package]] + name = "askpass" + version = "0.1.0" +@@ -1350,6 +1333,22 @@ 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", ++ "log", ++ "pin-project-lite", ++ "tokio", ++ "tungstenite 0.27.0", ++] ++ + [[package]] + name = "async_zip" + version = "0.0.17" +@@ -1405,7 +1404,6 @@ dependencies = [ + "async-tar", + "collections", + "crossbeam", +- "denoise", + "gpui", + "libwebrtc", + "log", +@@ -2325,7 +2323,7 @@ dependencies = [ + "log", + "mint", + "naga", +- "objc2", ++ "objc2 0.6.1", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", +@@ -2383,13 +2381,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]] +@@ -2728,7 +2745,7 @@ dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -2757,7 +2774,7 @@ dependencies = [ + "maybe-owned", + "rustix 1.0.7", + "rustix-linux-procfs", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + "winx", + ] + +@@ -3103,7 +3120,7 @@ name = "client" + version = "0.1.0" + dependencies = [ + "anyhow", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "base64 0.22.1", + "chrono", + "clock", +@@ -3325,7 +3342,7 @@ dependencies = [ + "assistant_context", + "assistant_slash_command", + "async-trait", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "audio", + "aws-config", + "aws-sdk-kinesis", +@@ -4938,7 +4955,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" + dependencies = [ + "bitflags 2.9.0", +- "objc2", ++ "objc2 0.6.1", + ] + + [[package]] +@@ -5487,7 +5504,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" + dependencies = [ + "libc", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -5854,7 +5871,7 @@ checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" + dependencies = [ + "cfg-if", + "rustix 1.0.7", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -6205,7 +6222,7 @@ name = "fs" + version = "0.1.0" + dependencies = [ + "anyhow", +- "ashpd 0.11.0", ++ "ashpd", + "async-tar", + "async-trait", + "cocoa 0.26.0", +@@ -6242,7 +6259,7 @@ checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" + dependencies = [ + "io-lifetimes", + "rustix 1.0.7", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -7036,7 +7053,7 @@ version = "0.1.0" + dependencies = [ + "anyhow", + "as-raw-xcb-connection", +- "ashpd 0.11.0", ++ "ashpd", + "async-task", + "backtrace", + "bindgen 0.71.1", +@@ -7068,18 +7085,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", +@@ -7087,7 +7106,6 @@ dependencies = [ + "parking_lot", + "pathfinder_geometry", + "postage", +- "pretty_assertions", + "profiling", + "rand 0.9.1", + "raw-window-handle", +@@ -7751,6 +7769,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" +@@ -8145,7 +8173,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "2285ddfe3054097ef4b2fe909ef8c3bcd1ea52a8f0d274416caebeef39f04a65" + dependencies = [ + "io-lifetimes", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -8218,7 +8246,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" + dependencies = [ + "hermit-abi 0.5.0", + "libc", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -8452,7 +8480,7 @@ source = "git+https://github.com/ConradIrwin/runtimed?rev=7130c804216b6914355d15 + dependencies = [ + "anyhow", + "async-trait", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "futures 0.3.31", + "jupyter-protocol", + "serde", +@@ -8682,6 +8710,7 @@ dependencies = [ + "credentials_provider", + "deepseek", + "editor", ++ "feature_flags", + "fs", + "futures 0.3.31", + "google_ai", +@@ -8706,6 +8735,7 @@ dependencies = [ + "settings", + "smol", + "strum 0.27.1", ++ "theme", + "thiserror 2.0.12", + "tiktoken-rs", + "tokio", +@@ -9400,6 +9430,10 @@ dependencies = [ + "libc", + ] + ++[[package]] ++name = "macos_appkit_bridge" ++version = "0.1.0" ++ + [[package]] + name = "malloc_buf" + version = "0.0.6" +@@ -10414,6 +10448,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" +@@ -10430,7 +10480,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", +@@ -10444,7 +10494,7 @@ checksum = "10cbe18d879e20a4aea544f8befe38bcf52255eb63d3f23eca2842f3319e4c07" + dependencies = [ + "bitflags 2.9.0", + "libc", +- "objc2", ++ "objc2 0.6.1", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", +@@ -10458,7 +10508,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", + ] +@@ -10470,7 +10520,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "c0f1cc99bb07ad2ddb6527ddf83db6a15271bb036b3eb94b801cd44fdc666ee1" + dependencies = [ + "bitflags 2.9.0", +- "objc2", ++ "objc2 0.6.1", + ] + + [[package]] +@@ -10481,7 +10531,7 @@ checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" + dependencies = [ + "bitflags 2.9.0", + "dispatch2", +- "objc2", ++ "objc2 0.6.1", + ] + + [[package]] +@@ -10497,7 +10547,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", + ] + +@@ -10508,9 +10558,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", + ] +@@ -10522,7 +10572,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", +@@ -10535,7 +10585,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", +@@ -10629,12 +10679,12 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + + [[package]] + name = "oo7" +-version = "0.5.0" ++version = "0.4.3" + source = "registry+https://github.com/rust-lang/crates.io-index" +-checksum = "e3299dd401feaf1d45afd8fd1c0586f10fcfb22f244bb9afa942cec73503b89d" ++checksum = "6cb23d3ec3527d65a83be1c1795cb883c52cfa57147d42acc797127df56fc489" + dependencies = [ + "aes", +- "ashpd 0.12.0", ++ "ashpd", + "async-fs", + "async-io", + "async-lock", +@@ -12559,7 +12609,7 @@ dependencies = [ + "once_cell", + "socket2", + "tracing", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -13091,7 +13141,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", +@@ -13399,7 +13450,7 @@ dependencies = [ + [[package]] + name = "rodio" + version = "0.21.1" +-source = "git+https://github.com/RustAudio/rodio#e2074c6c2acf07b57cf717e076bdda7a9ac6e70b" ++source = "git+https://github.com/RustAudio/rodio?branch=better_wav_output#82514bd1f2c6cfd9a1a885019b26a8ffea75bc5c" + dependencies = [ + "cpal", + "dasp_sample", +@@ -13440,7 +13491,7 @@ name = "rpc" + version = "0.1.0" + dependencies = [ + "anyhow", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "base64 0.22.1", + "chrono", + "collections", +@@ -13641,7 +13692,7 @@ dependencies = [ + "errno 0.3.11", + "libc", + "linux-raw-sys 0.4.15", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -13654,7 +13705,7 @@ dependencies = [ + "errno 0.3.11", + "libc", + "linux-raw-sys 0.9.4", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -13776,7 +13827,7 @@ dependencies = [ + "security-framework 3.2.0", + "security-framework-sys", + "webpki-root-certs", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -14461,7 +14512,6 @@ dependencies = [ + "serde_with", + "settings_macros", + "smallvec", +- "strum 0.27.1", + "tree-sitter", + "tree-sitter-json", + "unindent", +@@ -14522,7 +14572,6 @@ dependencies = [ + "serde", + "session", + "settings", +- "strum 0.27.1", + "theme", + "ui", + "util", +@@ -15160,7 +15209,7 @@ dependencies = [ + "cfg-if", + "libc", + "psm", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -15853,7 +15902,7 @@ dependencies = [ + "fd-lock", + "io-lifetimes", + "rustix 0.38.44", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + "winx", + ] + +@@ -16035,7 +16084,7 @@ dependencies = [ + "getrandom 0.3.2", + "once_cell", + "rustix 1.0.7", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -16069,7 +16118,6 @@ dependencies = [ + "gpui", + "itertools 0.14.0", + "libc", +- "log", + "rand 0.9.1", + "regex", + "release_channel", +@@ -17193,6 +17241,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" +@@ -17527,7 +17592,6 @@ dependencies = [ + "libc", + "log", + "nix 0.29.0", +- "pretty_assertions", + "rand 0.9.1", + "regex", + "rust-embed", +@@ -18619,7 +18683,7 @@ version = "0.1.9" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" + dependencies = [ +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -19331,7 +19395,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d" + dependencies = [ + "bitflags 2.9.0", +- "windows-sys 0.52.0", ++ "windows-sys 0.59.0", + ] + + [[package]] +@@ -19634,7 +19698,7 @@ dependencies = [ + "arrayvec", + "async-compression", + "async-std", +- "async-tungstenite", ++ "async-tungstenite 0.29.1", + "aws-config", + "aws-credential-types", + "aws-runtime", +@@ -19723,6 +19787,7 @@ dependencies = [ + "nix 0.29.0", + "nix 0.30.1", + "nom 7.1.3", ++ "num", + "num-bigint", + "num-bigint-dig", + "num-complex", +@@ -19730,7 +19795,7 @@ dependencies = [ + "num-iter", + "num-rational", + "num-traits", +- "objc2", ++ "objc2 0.6.1", + "objc2-core-foundation", + "objc2-foundation", + "objc2-metal", +@@ -20187,7 +20252,7 @@ dependencies = [ + "agent_settings", + "agent_ui", + "anyhow", +- "ashpd 0.11.0", ++ "ashpd", + "askpass", + "assets", + "assistant_tools", +@@ -20613,7 +20678,6 @@ dependencies = [ + "arrayvec", + "chrono", + "client", +- "clock", + "cloud_llm_client", + "cloud_zeta2_prompt", + "edit_prediction", +@@ -20624,12 +20688,9 @@ dependencies = [ + "language", + "language_model", + "log", +- "lsp", +- "pretty_assertions", + "project", + "release_channel", + "serde_json", +- "settings", + "thiserror 2.0.12", + "util", + "uuid", +@@ -20645,7 +20706,6 @@ dependencies = [ + "chrono", + "clap", + "client", +- "cloud_llm_client", + "collections", + "edit_prediction_context", + "editor", +diff --git a/Cargo.toml b/Cargo.toml +index 3ad8bd2348..7f3818afed 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -376,7 +376,7 @@ remote_server = { path = "crates/remote_server" } + repl = { path = "crates/repl" } + reqwest_client = { path = "crates/reqwest_client" } + rich_text = { path = "crates/rich_text" } +-rodio = { git = "https://github.com/RustAudio/rodio" } ++rodio = { git = "https://github.com/RustAudio/rodio", branch = "better_wav_output"} + rope = { path = "crates/rope" } + rpc = { path = "crates/rpc" } + rules_library = { path = "crates/rules_library" } +@@ -440,7 +440,7 @@ zlog_settings = { path = "crates/zlog_settings" } + # External crates + # + +-agent-client-protocol = { version = "0.4.3", features = ["unstable"] } ++agent-client-protocol = { version = "0.4.2", features = ["unstable"] } + aho-corasick = "1.1" + alacritty_terminal = "0.25.1-rc1" + any_vec = "0.14" +@@ -615,7 +615,7 @@ rsa = "0.9.6" + runtimelib = { git = "https://github.com/ConradIrwin/runtimed", rev = "7130c804216b6914355d15d0b91ea91f6babd734", default-features = false, features = [ + "async-dispatcher-runtime", + ] } +-rust-embed = { version = "8.4", features = ["include-exclude"] } ++rust-embed = { version = "8.7", features = ["include-exclude", "debug-embed"] } + rustc-demangle = "0.1.23" + rustc-hash = "2.1.0" + rustls = { version = "0.23.26" } +diff --git a/assets/keymaps/default-windows.json b/assets/keymaps/default-windows.json +index fe9efe0f72..65de7a522b 100644 +--- a/assets/keymaps/default-windows.json ++++ b/assets/keymaps/default-windows.json +@@ -607,6 +607,8 @@ + "shift-alt--": ["workspace::DecreaseActiveDockSize", { "px": 0 }], + "shift-alt-=": ["workspace::IncreaseActiveDockSize", { "px": 0 }], + "shift-alt-0": "workspace::ResetOpenDocksSize", ++ "ctrl-shift-alt--": ["workspace::DecreaseOpenDocksSize", { "px": 0 }], ++ "ctrl-shift-alt-=": ["workspace::IncreaseOpenDocksSize", { "px": 0 }], + "ctrl-shift-f": "pane::DeploySearch", + "ctrl-shift-h": ["pane::DeploySearch", { "replace_enabled": true }], + "ctrl-shift-t": "pane::ReopenClosedItem", +@@ -1110,7 +1112,6 @@ + "alt-f": ["terminal::SendText", "\u001bf"], + "alt-.": ["terminal::SendText", "\u001b."], + "ctrl-delete": ["terminal::SendText", "\u001bd"], +- "ctrl-n": "workspace::NewTerminal", + // Overrides for conflicting keybindings + "ctrl-b": ["terminal::SendKeystroke", "ctrl-b"], + "ctrl-c": ["terminal::SendKeystroke", "ctrl-c"], +diff --git a/assets/settings/default.json b/assets/settings/default.json +index 298bce8245..514dcd4fb3 100644 +--- a/assets/settings/default.json ++++ b/assets/settings/default.json +@@ -115,7 +115,6 @@ + // Whether to enable vim modes and key bindings. + "vim_mode": false, + // Whether to enable helix mode and key bindings. +- // Enabling this mode will automatically enable vim mode. + "helix_mode": false, + // Whether to show the informational hover box when moving the mouse + // over symbols in the editor. +@@ -412,33 +411,15 @@ + "experimental.rodio_audio": false, + // Requires 'rodio_audio: true' + // +- // Automatically increase or decrease you microphone's volume. This affects how +- // loud you sound to others. +- // +- // Recommended: off (default) +- // Microphones are too quite in zed, until everyone is on experimental +- // audio and has auto speaker volume on this will make you very loud +- // compared to other speakers. +- "experimental.auto_microphone_volume": false, +- // Requires 'rodio_audio: true' +- // +- // Automatically increate or decrease the volume of other call members. +- // This only affects how things sound for you. +- "experimental.auto_speaker_volume": true, ++ // Use the new audio systems automatic gain control for your microphone. ++ // This affects how loud you sound to others. ++ "experimental.control_input_volume": false, + // Requires 'rodio_audio: true' + // +- // Remove background noises. Works great for typing, cars, dogs, AC. Does +- // not work well on music. +- "experimental.denoise": true, +- // Requires 'rodio_audio: true' +- // +- // Use audio parameters compatible with the previous versions of +- // experimental audio and non-experimental audio. When this is false you +- // will sound strange to anyone not on the latest experimental audio. In +- // the future we will migrate by setting this to false +- // +- // You need to rejoin a call for this setting to apply +- "experimental.legacy_audio_compatible": true ++ // Use the new audio systems automatic gain control on everyone in the ++ // call. This makes call members who are too quite louder and those who are ++ // too loud quieter. This only affects how things sound for you. ++ "experimental.control_output_volume": false + }, + // Scrollbar related settings + "scrollbar": { +@@ -1451,7 +1432,7 @@ + // + // The shell running in the terminal needs to be configured to emit the title. + // Example: `echo -e "\e]2;New Title\007";` +- "breadcrumbs": false ++ "breadcrumbs": true + }, + // Scrollbar-related settings + "scrollbar": { +diff --git a/crates/acp_thread/src/acp_thread.rs b/crates/acp_thread/src/acp_thread.rs +index 185eed3cd7..b63e9a2a84 100644 +--- a/crates/acp_thread/src/acp_thread.rs ++++ b/crates/acp_thread/src/acp_thread.rs +@@ -1780,26 +1780,20 @@ impl AcpThread { + limit: Option, + reuse_shared_snapshot: bool, + cx: &mut Context, +- ) -> Task> { ++ ) -> Task> { + // Args are 1-based, move to 0-based + let line = line.unwrap_or_default().saturating_sub(1); + let limit = limit.unwrap_or(u32::MAX); + let project = self.project.clone(); + let action_log = self.action_log.clone(); + cx.spawn(async move |this, cx| { +- let load = project +- .update(cx, |project, cx| { +- let path = project +- .project_path_for_absolute_path(&path, cx) +- .ok_or_else(|| { +- acp::Error::resource_not_found(Some(path.display().to_string())) +- })?; +- Ok(project.open_buffer(path, cx)) +- }) +- .map_err(|e| acp::Error::internal_error().with_data(e.to_string())) +- .flatten()?; +- +- let buffer = load.await?; ++ let load = project.update(cx, |project, cx| { ++ let path = project ++ .project_path_for_absolute_path(&path, cx) ++ .context("invalid path")?; ++ anyhow::Ok(project.open_buffer(path, cx)) ++ }); ++ let buffer = load??.await?; + + let snapshot = if reuse_shared_snapshot { + this.read_with(cx, |this, _| { +@@ -1826,17 +1820,15 @@ impl AcpThread { + }; + + let max_point = snapshot.max_point(); +- let start_position = Point::new(line, 0); +- +- if start_position > max_point { +- return Err(acp::Error::invalid_params().with_data(format!( ++ if line >= max_point.row { ++ anyhow::bail!( + "Attempting to read beyond the end of the file, line {}:{}", + max_point.row + 1, + max_point.column +- ))); ++ ); + } + +- let start = snapshot.anchor_before(start_position); ++ let start = snapshot.anchor_before(Point::new(line, 0)); + let end = snapshot.anchor_before(Point::new(line.saturating_add(limit), 0)); + + project.update(cx, |project, cx| { +@@ -2457,81 +2449,6 @@ mod tests { + + assert_eq!(content, "two\nthree\n"); + +- // Invalid +- let err = thread +- .update(cx, |thread, cx| { +- thread.read_text_file(path!("/tmp/foo").into(), Some(6), Some(2), false, cx) +- }) +- .await +- .unwrap_err(); +- +- assert_eq!( +- err.to_string(), +- "Invalid params: \"Attempting to read beyond the end of the file, line 5:0\"" +- ); +- } +- +- #[gpui::test] +- async fn test_reading_empty_file(cx: &mut TestAppContext) { +- init_test(cx); +- +- let fs = FakeFs::new(cx.executor()); +- fs.insert_tree(path!("/tmp"), json!({"foo": ""})).await; +- let project = Project::test(fs.clone(), [], cx).await; +- project +- .update(cx, |project, cx| { +- project.find_or_create_worktree(path!("/tmp/foo"), true, cx) +- }) +- .await +- .unwrap(); +- +- let connection = Rc::new(FakeAgentConnection::new()); +- +- let thread = cx +- .update(|cx| connection.new_thread(project, Path::new(path!("/tmp")), cx)) +- .await +- .unwrap(); +- +- // Whole file +- let content = thread +- .update(cx, |thread, cx| { +- thread.read_text_file(path!("/tmp/foo").into(), None, None, false, cx) +- }) +- .await +- .unwrap(); +- +- assert_eq!(content, ""); +- +- // Only start line +- let content = thread +- .update(cx, |thread, cx| { +- thread.read_text_file(path!("/tmp/foo").into(), Some(1), None, false, cx) +- }) +- .await +- .unwrap(); +- +- assert_eq!(content, ""); +- +- // Only limit +- let content = thread +- .update(cx, |thread, cx| { +- thread.read_text_file(path!("/tmp/foo").into(), None, Some(2), false, cx) +- }) +- .await +- .unwrap(); +- +- assert_eq!(content, ""); +- +- // Range +- let content = thread +- .update(cx, |thread, cx| { +- thread.read_text_file(path!("/tmp/foo").into(), Some(1), Some(1), false, cx) +- }) +- .await +- .unwrap(); +- +- assert_eq!(content, ""); +- + // Invalid + let err = thread + .update(cx, |thread, cx| { +@@ -2542,40 +2459,9 @@ mod tests { + + assert_eq!( + err.to_string(), +- "Invalid params: \"Attempting to read beyond the end of the file, line 1:0\"" ++ "Attempting to read beyond the end of the file, line 5:0" + ); + } +- #[gpui::test] +- async fn test_reading_non_existing_file(cx: &mut TestAppContext) { +- init_test(cx); +- +- let fs = FakeFs::new(cx.executor()); +- fs.insert_tree(path!("/tmp"), json!({})).await; +- let project = Project::test(fs.clone(), [], cx).await; +- project +- .update(cx, |project, cx| { +- project.find_or_create_worktree(path!("/tmp"), true, cx) +- }) +- .await +- .unwrap(); +- +- let connection = Rc::new(FakeAgentConnection::new()); +- +- let thread = cx +- .update(|cx| connection.new_thread(project, Path::new(path!("/tmp")), cx)) +- .await +- .unwrap(); +- +- // Out of project file +- let err = thread +- .update(cx, |thread, cx| { +- thread.read_text_file(path!("/foo").into(), None, None, false, cx) +- }) +- .await +- .unwrap_err(); +- +- assert_eq!(err.code, acp::ErrorCode::RESOURCE_NOT_FOUND.code); +- } + + #[gpui::test] + async fn test_succeeding_canceled_toolcall(cx: &mut TestAppContext) { +diff --git a/crates/acp_thread/src/mention.rs b/crates/acp_thread/src/mention.rs +index bbd13da5fa..122cd9a5ca 100644 +--- a/crates/acp_thread/src/mention.rs ++++ b/crates/acp_thread/src/mention.rs +@@ -126,39 +126,6 @@ impl MentionUri { + abs_path: None, + line_range, + }) +- } else if let Some(name) = path.strip_prefix("/agent/symbol/") { +- let fragment = url +- .fragment() +- .context("Missing fragment for untitled buffer selection")?; +- let line_range = parse_line_range(fragment)?; +- let path = +- single_query_param(&url, "path")?.context("Missing path for symbol")?; +- Ok(Self::Symbol { +- name: name.to_string(), +- abs_path: path.into(), +- line_range, +- }) +- } else if path.starts_with("/agent/file") { +- let path = +- single_query_param(&url, "path")?.context("Missing path for file")?; +- Ok(Self::File { +- abs_path: path.into(), +- }) +- } else if path.starts_with("/agent/directory") { +- let path = +- single_query_param(&url, "path")?.context("Missing path for directory")?; +- Ok(Self::Directory { +- abs_path: path.into(), +- }) +- } else if path.starts_with("/agent/selection") { +- let fragment = url.fragment().context("Missing fragment for selection")?; +- let line_range = parse_line_range(fragment)?; +- let path = +- single_query_param(&url, "path")?.context("Missing path for selection")?; +- Ok(Self::Selection { +- abs_path: Some(path.into()), +- line_range, +- }) + } else { + bail!("invalid zed url: {:?}", input); + } +@@ -213,29 +180,20 @@ impl MentionUri { + pub fn to_uri(&self) -> Url { + match self { + MentionUri::File { abs_path } => { +- let mut url = Url::parse("zed:///").unwrap(); +- url.set_path("/agent/file"); +- url.query_pairs_mut() +- .append_pair("path", &abs_path.to_string_lossy()); +- url ++ Url::from_file_path(abs_path).expect("mention path should be absolute") + } + MentionUri::PastedImage => Url::parse("zed:///agent/pasted-image").unwrap(), + MentionUri::Directory { abs_path } => { +- let mut url = Url::parse("zed:///").unwrap(); +- url.set_path("/agent/directory"); +- url.query_pairs_mut() +- .append_pair("path", &abs_path.to_string_lossy()); +- url ++ Url::from_directory_path(abs_path).expect("mention path should be absolute") + } + MentionUri::Symbol { + abs_path, + name, + line_range, + } => { +- let mut url = Url::parse("zed:///").unwrap(); +- url.set_path(&format!("/agent/symbol/{name}")); +- url.query_pairs_mut() +- .append_pair("path", &abs_path.to_string_lossy()); ++ let mut url = ++ Url::from_file_path(abs_path).expect("mention path should be absolute"); ++ url.query_pairs_mut().append_pair("symbol", name); + url.set_fragment(Some(&format!( + "L{}:{}", + line_range.start() + 1, +@@ -244,16 +202,15 @@ impl MentionUri { + url + } + MentionUri::Selection { +- abs_path, ++ abs_path: path, + line_range, + } => { +- let mut url = Url::parse("zed:///").unwrap(); +- if let Some(abs_path) = abs_path { +- url.set_path("/agent/selection"); +- url.query_pairs_mut() +- .append_pair("path", &abs_path.to_string_lossy()); ++ let mut url = if let Some(path) = path { ++ Url::from_file_path(path).expect("mention path should be absolute") + } else { ++ let mut url = Url::parse("zed:///").unwrap(); + url.set_path("/agent/untitled-buffer"); ++ url + }; + url.set_fragment(Some(&format!( + "L{}:{}", +@@ -338,32 +295,37 @@ mod tests { + + #[test] + fn test_parse_file_uri() { +- let old_uri = uri!("file:///path/to/file.rs"); +- let parsed = MentionUri::parse(old_uri).unwrap(); ++ let file_uri = uri!("file:///path/to/file.rs"); ++ let parsed = MentionUri::parse(file_uri).unwrap(); + match &parsed { + MentionUri::File { abs_path } => { + assert_eq!(abs_path.to_str().unwrap(), path!("/path/to/file.rs")); + } + _ => panic!("Expected File variant"), + } +- let new_uri = parsed.to_uri().to_string(); +- assert!(new_uri.starts_with("zed:///agent/file")); +- assert_eq!(MentionUri::parse(&new_uri).unwrap(), parsed); ++ assert_eq!(parsed.to_uri().to_string(), file_uri); + } + + #[test] + fn test_parse_directory_uri() { +- let old_uri = uri!("file:///path/to/dir/"); +- let parsed = MentionUri::parse(old_uri).unwrap(); ++ let file_uri = uri!("file:///path/to/dir/"); ++ let parsed = MentionUri::parse(file_uri).unwrap(); + match &parsed { + MentionUri::Directory { abs_path } => { + assert_eq!(abs_path.to_str().unwrap(), path!("/path/to/dir/")); + } + _ => panic!("Expected Directory variant"), + } +- let new_uri = parsed.to_uri().to_string(); +- assert!(new_uri.starts_with("zed:///agent/directory")); +- assert_eq!(MentionUri::parse(&new_uri).unwrap(), parsed); ++ assert_eq!(parsed.to_uri().to_string(), file_uri); ++ } ++ ++ #[test] ++ fn test_to_directory_uri_with_slash() { ++ let uri = MentionUri::Directory { ++ abs_path: PathBuf::from(path!("/path/to/dir/")), ++ }; ++ let expected = uri!("file:///path/to/dir/"); ++ assert_eq!(uri.to_uri().to_string(), expected); + } + + #[test] +@@ -371,15 +333,14 @@ mod tests { + let uri = MentionUri::Directory { + abs_path: PathBuf::from(path!("/path/to/dir")), + }; +- let uri_string = uri.to_uri().to_string(); +- assert!(uri_string.starts_with("zed:///agent/directory")); +- assert_eq!(MentionUri::parse(&uri_string).unwrap(), uri); ++ let expected = uri!("file:///path/to/dir/"); ++ assert_eq!(uri.to_uri().to_string(), expected); + } + + #[test] + fn test_parse_symbol_uri() { +- let old_uri = uri!("file:///path/to/file.rs?symbol=MySymbol#L10:20"); +- let parsed = MentionUri::parse(old_uri).unwrap(); ++ let symbol_uri = uri!("file:///path/to/file.rs?symbol=MySymbol#L10:20"); ++ let parsed = MentionUri::parse(symbol_uri).unwrap(); + match &parsed { + MentionUri::Symbol { + abs_path: path, +@@ -393,15 +354,13 @@ mod tests { + } + _ => panic!("Expected Symbol variant"), + } +- let new_uri = parsed.to_uri().to_string(); +- assert!(new_uri.starts_with("zed:///agent/symbol/MySymbol")); +- assert_eq!(MentionUri::parse(&new_uri).unwrap(), parsed); ++ assert_eq!(parsed.to_uri().to_string(), symbol_uri); + } + + #[test] + fn test_parse_selection_uri() { +- let old_uri = uri!("file:///path/to/file.rs#L5:15"); +- let parsed = MentionUri::parse(old_uri).unwrap(); ++ let selection_uri = uri!("file:///path/to/file.rs#L5:15"); ++ let parsed = MentionUri::parse(selection_uri).unwrap(); + match &parsed { + MentionUri::Selection { + abs_path: path, +@@ -416,9 +375,7 @@ mod tests { + } + _ => panic!("Expected Selection variant"), + } +- let new_uri = parsed.to_uri().to_string(); +- assert!(new_uri.starts_with("zed:///agent/selection")); +- assert_eq!(MentionUri::parse(&new_uri).unwrap(), parsed); ++ assert_eq!(parsed.to_uri().to_string(), selection_uri); + } + + #[test] +diff --git a/crates/agent/src/context.rs b/crates/agent/src/context.rs +index 80062b1e46..fdcf0316a0 100644 +--- a/crates/agent/src/context.rs ++++ b/crates/agent/src/context.rs +@@ -159,7 +159,7 @@ pub struct FileContextHandle { + #[derive(Debug, Clone)] + pub struct FileContext { + pub handle: FileContextHandle, +- pub full_path: String, ++ pub full_path: Arc, + pub text: SharedString, + pub is_outline: bool, + } +@@ -187,7 +187,7 @@ impl FileContextHandle { + log::error!("file context missing path"); + return Task::ready(None); + }; +- let full_path = file.full_path(cx).to_string_lossy().to_string(); ++ let full_path: Arc = file.full_path(cx).into(); + let rope = buffer_ref.as_rope().clone(); + let buffer = self.buffer.clone(); + +@@ -236,7 +236,7 @@ pub struct DirectoryContextHandle { + #[derive(Debug, Clone)] + pub struct DirectoryContext { + pub handle: DirectoryContextHandle, +- pub full_path: String, ++ pub full_path: Arc, + pub descendants: Vec, + } + +@@ -274,16 +274,13 @@ impl DirectoryContextHandle { + } + + let directory_path = entry.path.clone(); +- let directory_full_path = worktree_ref +- .full_path(&directory_path) +- .to_string_lossy() +- .to_string(); ++ let directory_full_path = worktree_ref.full_path(&directory_path).into(); + + let file_paths = collect_files_in_path(worktree_ref, &directory_path); + let descendants_future = future::join_all(file_paths.into_iter().map(|path| { + let worktree_ref = worktree.read(cx); + let worktree_id = worktree_ref.id(); +- let full_path = worktree_ref.full_path(&path).to_string_lossy().to_string(); ++ let full_path = worktree_ref.full_path(&path); + + let rel_path = path + .strip_prefix(&directory_path) +@@ -364,7 +361,7 @@ pub struct SymbolContextHandle { + #[derive(Debug, Clone)] + pub struct SymbolContext { + pub handle: SymbolContextHandle, +- pub full_path: String, ++ pub full_path: Arc, + pub line_range: Range, + pub text: SharedString, + } +@@ -403,7 +400,7 @@ impl SymbolContextHandle { + log::error!("symbol context's file has no path"); + return Task::ready(None); + }; +- let full_path = file.full_path(cx).to_string_lossy().to_string(); ++ let full_path = file.full_path(cx).into(); + let line_range = self.enclosing_range.to_point(&buffer_ref.snapshot()); + let text = self.text(cx); + let buffer = self.buffer.clone(); +@@ -437,7 +434,7 @@ pub struct SelectionContextHandle { + #[derive(Debug, Clone)] + pub struct SelectionContext { + pub handle: SelectionContextHandle, +- pub full_path: String, ++ pub full_path: Arc, + pub line_range: Range, + pub text: SharedString, + } +@@ -476,7 +473,7 @@ impl SelectionContextHandle { + let text = self.text(cx); + let buffer = self.buffer.clone(); + let context = AgentContext::Selection(SelectionContext { +- full_path: full_path.to_string_lossy().to_string(), ++ full_path: full_path.into(), + line_range: self.line_range(cx), + text, + handle: self, +@@ -706,7 +703,7 @@ impl Display for RulesContext { + #[derive(Debug, Clone)] + pub struct ImageContext { + pub project_path: Option, +- pub full_path: Option, ++ pub full_path: Option>, + pub original_image: Arc, + // TODO: handle this elsewhere and remove `ignore-interior-mutability` opt-out in clippy.toml + // needed due to a false positive of `clippy::mutable_key_type`. +@@ -986,17 +983,14 @@ fn collect_files_in_path(worktree: &Worktree, path: &RelPath) -> Vec>) -> String { ++fn codeblock_tag(full_path: &Path, line_range: Option>) -> String { + let mut result = String::new(); + +- if let Some(extension) = Path::new(full_path) +- .extension() +- .and_then(|ext| ext.to_str()) +- { ++ if let Some(extension) = full_path.extension().and_then(|ext| ext.to_str()) { + let _ = write!(result, "{} ", extension); + } + +- let _ = write!(result, "{}", full_path); ++ let _ = write!(result, "{}", full_path.display()); + + if let Some(range) = line_range { + if range.start.row == range.end.row { +diff --git a/crates/agent/src/context_store.rs b/crates/agent/src/context_store.rs +index c4aa0abc25..9b96537000 100644 +--- a/crates/agent/src/context_store.rs ++++ b/crates/agent/src/context_store.rs +@@ -312,7 +312,7 @@ impl ContextStore { + let item = image_item.read(cx); + this.insert_image( + Some(item.project_path(cx)), +- Some(item.file.full_path(cx).to_string_lossy().to_string()), ++ Some(item.file.full_path(cx).into()), + item.image.clone(), + remove_if_exists, + cx, +@@ -328,7 +328,7 @@ impl ContextStore { + fn insert_image( + &mut self, + project_path: Option, +- full_path: Option, ++ full_path: Option>, + image: Arc, + remove_if_exists: bool, + cx: &mut Context, +diff --git a/crates/agent/src/thread_store.rs b/crates/agent/src/thread_store.rs +index 91b2f3b684..fe73b959b7 100644 +--- a/crates/agent/src/thread_store.rs ++++ b/crates/agent/src/thread_store.rs +@@ -235,7 +235,7 @@ impl ThreadStore { + if items.iter().any(|(path, _, _)| { + RULES_FILE_NAMES + .iter() +- .any(|name| path.as_ref() == RelPath::unix(name).unwrap()) ++ .any(|name| path.as_ref() == RelPath::new(name).unwrap()) + }) { + self.enqueue_system_prompt_reload(); + } +@@ -368,7 +368,7 @@ impl ThreadStore { + .into_iter() + .filter_map(|name| { + worktree +- .entry_for_path(RelPath::unix(name).unwrap()) ++ .entry_for_path(RelPath::new(name).unwrap()) + .filter(|entry| entry.is_file()) + .map(|entry| entry.path.clone()) + }) +diff --git a/crates/agent2/src/agent.rs b/crates/agent2/src/agent.rs +index fe47c66fea..f3324da448 100644 +--- a/crates/agent2/src/agent.rs ++++ b/crates/agent2/src/agent.rs +@@ -475,7 +475,7 @@ impl NativeAgent { + .into_iter() + .filter_map(|name| { + worktree +- .entry_for_path(RelPath::unix(name).unwrap()) ++ .entry_for_path(RelPath::new(name).unwrap()) + .filter(|entry| entry.is_file()) + .map(|entry| entry.path.clone()) + }) +@@ -559,7 +559,7 @@ impl NativeAgent { + if items.iter().any(|(path, _, _)| { + RULES_FILE_NAMES + .iter() +- .any(|name| path.as_ref() == RelPath::unix(name).unwrap()) ++ .any(|name| path.as_ref() == RelPath::new(name).unwrap()) + }) { + self.project_context_needs_refresh.send(()).ok(); + } +@@ -1205,7 +1205,7 @@ mod tests { + use acp_thread::{AgentConnection, AgentModelGroupName, AgentModelInfo, MentionUri}; + use fs::FakeFs; + use gpui::TestAppContext; +- use indoc::formatdoc; ++ use indoc::indoc; + use language_model::fake_provider::FakeLanguageModel; + use serde_json::json; + use settings::SettingsStore; +@@ -1502,17 +1502,13 @@ mod tests { + summary_model.end_last_completion_stream(); + + send.await.unwrap(); +- let uri = MentionUri::File { +- abs_path: path!("/a/b.md").into(), +- } +- .to_uri(); + acp_thread.read_with(cx, |thread, cx| { + assert_eq!( + thread.to_markdown(cx), +- formatdoc! {" ++ indoc! {" + ## User + +- What does [@b.md]({uri}) mean? ++ What does [@b.md](file:///a/b.md) mean? + + ## Assistant + +@@ -1548,10 +1544,10 @@ mod tests { + acp_thread.read_with(cx, |thread, cx| { + assert_eq!( + thread.to_markdown(cx), +- formatdoc! {" ++ indoc! {" + ## User + +- What does [@b.md]({uri}) mean? ++ What does [@b.md](file:///a/b.md) mean? + + ## Assistant + +diff --git a/crates/agent2/src/tools/edit_file_tool.rs b/crates/agent2/src/tools/edit_file_tool.rs +index 3b1bf6f408..9f2e8e3e31 100644 +--- a/crates/agent2/src/tools/edit_file_tool.rs ++++ b/crates/agent2/src/tools/edit_file_tool.rs +@@ -541,7 +541,7 @@ fn resolve_path( + .path + .file_name() + .and_then(|file_name| file_name.to_str()) +- .and_then(|file_name| RelPath::unix(file_name).ok()) ++ .and_then(|file_name| RelPath::new(file_name).ok()) + .context("Can't create file: invalid filename")?; + + let new_file_path = parent_project_path.map(|parent| ProjectPath { +@@ -565,7 +565,7 @@ mod tests { + use prompt_store::ProjectContext; + use serde_json::json; + use settings::SettingsStore; +- use util::{path, rel_path::rel_path}; ++ use util::path; + + #[gpui::test] + async fn test_edit_nonexistent_file(cx: &mut TestAppContext) { +@@ -614,13 +614,13 @@ mod tests { + let mode = &EditFileMode::Create; + + let result = test_resolve_path(mode, "root/new.txt", cx); +- assert_resolved_path_eq(result.await, rel_path("new.txt")); ++ assert_resolved_path_eq(result.await, "new.txt"); + + let result = test_resolve_path(mode, "new.txt", cx); +- assert_resolved_path_eq(result.await, rel_path("new.txt")); ++ assert_resolved_path_eq(result.await, "new.txt"); + + let result = test_resolve_path(mode, "dir/new.txt", cx); +- assert_resolved_path_eq(result.await, rel_path("dir/new.txt")); ++ assert_resolved_path_eq(result.await, "dir/new.txt"); + + let result = test_resolve_path(mode, "root/dir/subdir/existing.txt", cx); + assert_eq!( +@@ -642,10 +642,10 @@ mod tests { + let path_with_root = "root/dir/subdir/existing.txt"; + let path_without_root = "dir/subdir/existing.txt"; + let result = test_resolve_path(mode, path_with_root, cx); +- assert_resolved_path_eq(result.await, rel_path(path_without_root)); ++ assert_resolved_path_eq(result.await, path_without_root); + + let result = test_resolve_path(mode, path_without_root, cx); +- assert_resolved_path_eq(result.await, rel_path(path_without_root)); ++ assert_resolved_path_eq(result.await, path_without_root); + + let result = test_resolve_path(mode, "root/nonexistent.txt", cx); + assert_eq!( +@@ -691,9 +691,10 @@ mod tests { + } + + #[track_caller] +- fn assert_resolved_path_eq(path: anyhow::Result, expected: &RelPath) { ++ fn assert_resolved_path_eq(path: anyhow::Result, expected: &str) { + let actual = path.expect("Should return valid path").path; +- assert_eq!(actual.as_ref(), expected); ++ let actual = actual.as_str(); ++ assert_eq!(actual, expected); + } + + #[gpui::test] +diff --git a/crates/agent2/src/tools/read_file_tool.rs b/crates/agent2/src/tools/read_file_tool.rs +index ce8dcba102..fcbe897858 100644 +--- a/crates/agent2/src/tools/read_file_tool.rs ++++ b/crates/agent2/src/tools/read_file_tool.rs +@@ -225,12 +225,9 @@ impl AgentTool for ReadFileTool { + Ok(result.into()) + } else { + // No line ranges specified, so check file size to see if it's too big. +- let buffer_content = outline::get_buffer_content_or_outline( +- buffer.clone(), +- Some(&abs_path.to_string_lossy()), +- cx, +- ) +- .await?; ++ let buffer_content = ++ outline::get_buffer_content_or_outline(buffer.clone(), Some(&abs_path), cx) ++ .await?; + + action_log.update(cx, |log, cx| { + log.buffer_read(buffer.clone(), cx); +diff --git a/crates/agent_ui/src/acp/message_editor.rs b/crates/agent_ui/src/acp/message_editor.rs +index dec9b0beb2..689d3e25eb 100644 +--- a/crates/agent_ui/src/acp/message_editor.rs ++++ b/crates/agent_ui/src/acp/message_editor.rs +@@ -48,7 +48,7 @@ use std::{ + use text::OffsetRangeExt; + use theme::ThemeSettings; + use ui::{ButtonLike, TintColor, Toggleable, prelude::*}; +-use util::{ResultExt, debug_panic, rel_path::RelPath}; ++use util::{ResultExt, debug_panic, paths::PathStyle, rel_path::RelPath}; + use workspace::{Workspace, notifications::NotifyResultExt as _}; + use zed_actions::agent::Chat; + +@@ -108,6 +108,11 @@ impl MessageEditor { + available_commands.clone(), + )); + let mention_set = MentionSet::default(); ++ // TODO: fix mentions when remoting with mixed path styles. ++ let host_and_guest_paths_differ = project ++ .read(cx) ++ .remote_client() ++ .is_some_and(|client| client.read(cx).path_style() != PathStyle::local()); + let editor = cx.new(|cx| { + let buffer = cx.new(|cx| Buffer::local("", cx).with_language(Arc::new(language), cx)); + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); +@@ -117,7 +122,9 @@ impl MessageEditor { + editor.set_show_indent_guides(false, cx); + editor.set_soft_wrap(); + editor.set_use_modal_editing(true); +- editor.set_completion_provider(Some(completion_provider.clone())); ++ if !host_and_guest_paths_differ { ++ editor.set_completion_provider(Some(completion_provider.clone())); ++ } + editor.set_context_menu_options(ContextMenuOptions { + min_entries_visible: 12, + max_entries_visible: 12, +@@ -452,12 +459,9 @@ impl MessageEditor { + .update(cx, |project, cx| project.open_buffer(project_path, cx)); + cx.spawn(async move |_, cx| { + let buffer = buffer.await?; +- let buffer_content = outline::get_buffer_content_or_outline( +- buffer.clone(), +- Some(&abs_path.to_string_lossy()), +- &cx, +- ) +- .await?; ++ let buffer_content = ++ outline::get_buffer_content_or_outline(buffer.clone(), Some(&abs_path), &cx) ++ .await?; + + Ok(Mention::Text { + content: buffer_content.text, +@@ -1177,20 +1181,14 @@ fn full_mention_for_directory( + abs_path: &Path, + cx: &mut App, + ) -> Task> { +- fn collect_files_in_path(worktree: &Worktree, path: &RelPath) -> Vec<(Arc, String)> { ++ fn collect_files_in_path(worktree: &Worktree, path: &RelPath) -> Vec<(Arc, PathBuf)> { + let mut files = Vec::new(); + + for entry in worktree.child_entries(path) { + if entry.is_dir() { + files.extend(collect_files_in_path(worktree, &entry.path)); + } else if entry.is_file() { +- files.push(( +- entry.path.clone(), +- worktree +- .full_path(&entry.path) +- .to_string_lossy() +- .to_string(), +- )); ++ files.push((entry.path.clone(), worktree.full_path(&entry.path))); + } + } + +@@ -1268,7 +1266,7 @@ fn full_mention_for_directory( + }) + } + +-fn render_directory_contents(entries: Vec<(Arc, String, String)>) -> String { ++fn render_directory_contents(entries: Vec<(Arc, PathBuf, String)>) -> String { + let mut output = String::new(); + for (_relative_path, full_path, content) in entries { + let fence = codeblock_fence_for_path(Some(&full_path), None); +@@ -1602,7 +1600,7 @@ mod tests { + use serde_json::json; + use text::Point; + use ui::{App, Context, IntoElement, Render, SharedString, Window}; +- use util::{path, paths::PathStyle, rel_path::rel_path}; ++ use util::{path, paths::PathStyle, rel_path::rel_path, uri}; + use workspace::{AppState, Item, Workspace}; + + use crate::acp::{ +@@ -2268,11 +2266,7 @@ mod tests { + editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx); + }); + +- let url_one = MentionUri::File { +- abs_path: path!("/dir/a/one.txt").into(), +- } +- .to_uri() +- .to_string(); ++ let url_one = uri!("file:///dir/a/one.txt"); + editor.update(&mut cx, |editor, cx| { + let text = editor.text(cx); + assert_eq!(text, format!("Lorem [@one.txt]({url_one}) ")); +@@ -2377,11 +2371,7 @@ mod tests { + .into_values() + .collect::>(); + +- let url_eight = MentionUri::File { +- abs_path: path!("/dir/b/eight.txt").into(), +- } +- .to_uri() +- .to_string(); ++ let url_eight = uri!("file:///dir/b/eight.txt"); + + { + let [_, (uri, Mention::Text { content, .. })] = contents.as_slice() else { +@@ -2480,12 +2470,6 @@ mod tests { + editor.confirm_completion(&editor::actions::ConfirmCompletion::default(), window, cx); + }); + +- let symbol = MentionUri::Symbol { +- abs_path: path!("/dir/a/one.txt").into(), +- name: "MySymbol".into(), +- line_range: 0..=0, +- }; +- + let contents = message_editor + .update(&mut cx, |message_editor, cx| { + message_editor.mention_set().contents( +@@ -2505,7 +2489,12 @@ mod tests { + panic!("Unexpected mentions"); + }; + pretty_assertions::assert_eq!(content, "1"); +- pretty_assertions::assert_eq!(uri, &symbol); ++ pretty_assertions::assert_eq!( ++ uri, ++ &format!("{url_one}?symbol=MySymbol#L1:1") ++ .parse::() ++ .unwrap() ++ ); + } + + cx.run_until_parked(); +@@ -2513,10 +2502,7 @@ mod tests { + editor.read_with(&cx, |editor, cx| { + assert_eq!( + editor.text(cx), +- format!( +- "Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) [@MySymbol]({}) ", +- symbol.to_uri(), +- ) ++ format!("Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) [@MySymbol]({url_one}?symbol=MySymbol#L1:1) ") + ); + }); + +@@ -2526,7 +2512,7 @@ mod tests { + editor.update(&mut cx, |editor, cx| { + assert_eq!( + editor.text(cx), +- format!("Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) [@MySymbol]({}) @file x.png", symbol.to_uri()) ++ format!("Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) [@MySymbol]({url_one}?symbol=MySymbol#L1:1) @file x.png") + ); + assert!(editor.has_visible_completions_menu()); + assert_eq!(current_completion_labels(editor), &[format!("x.png dir{slash}")]); +@@ -2555,10 +2541,7 @@ mod tests { + editor.read_with(&cx, |editor, cx| { + assert_eq!( + editor.text(cx), +- format!( +- "Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) [@MySymbol]({}) ", +- symbol.to_uri() +- ) ++ format!("Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) [@MySymbol]({url_one}?symbol=MySymbol#L1:1) ") + ); + }); + +@@ -2568,7 +2551,7 @@ mod tests { + editor.update(&mut cx, |editor, cx| { + assert_eq!( + editor.text(cx), +- format!("Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) [@MySymbol]({}) @file x.png", symbol.to_uri()) ++ format!("Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) [@MySymbol]({url_one}?symbol=MySymbol#L1:1) @file x.png") + ); + assert!(editor.has_visible_completions_menu()); + assert_eq!(current_completion_labels(editor), &[format!("x.png dir{slash}")]); +@@ -2583,14 +2566,11 @@ mod tests { + + // Mention was removed + editor.read_with(&cx, |editor, cx| { +- assert_eq!( +- editor.text(cx), +- format!( +- "Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) [@MySymbol]({}) ", +- symbol.to_uri() +- ) +- ); +- }); ++ assert_eq!( ++ editor.text(cx), ++ format!("Lorem [@one.txt]({url_one}) Ipsum [@eight.txt]({url_eight}) [@MySymbol]({url_one}?symbol=MySymbol#L1:1) ") ++ ); ++ }); + + // Now getting the contents succeeds, because the invalid mention was removed + let contents = message_editor +diff --git a/crates/agent_ui/src/ui/context_pill.rs b/crates/agent_ui/src/ui/context_pill.rs +index c42d33c6d3..a015d6305e 100644 +--- a/crates/agent_ui/src/ui/context_pill.rs ++++ b/crates/agent_ui/src/ui/context_pill.rs +@@ -17,7 +17,6 @@ use agent::context::{ + FileContextHandle, ImageContext, ImageStatus, RulesContextHandle, SelectionContextHandle, + SymbolContextHandle, TextThreadContextHandle, ThreadContextHandle, + }; +-use util::paths::PathStyle; + + #[derive(IntoElement)] + pub enum ContextPill { +@@ -304,54 +303,33 @@ impl AddedContext { + cx: &App, + ) -> Option { + match handle { +- AgentContextHandle::File(handle) => { +- Self::pending_file(handle, project.path_style(cx), cx) +- } ++ AgentContextHandle::File(handle) => Self::pending_file(handle, cx), + AgentContextHandle::Directory(handle) => Self::pending_directory(handle, project, cx), +- AgentContextHandle::Symbol(handle) => { +- Self::pending_symbol(handle, project.path_style(cx), cx) +- } +- AgentContextHandle::Selection(handle) => { +- Self::pending_selection(handle, project.path_style(cx), cx) +- } ++ AgentContextHandle::Symbol(handle) => Self::pending_symbol(handle, cx), ++ AgentContextHandle::Selection(handle) => Self::pending_selection(handle, cx), + AgentContextHandle::FetchedUrl(handle) => Some(Self::fetched_url(handle)), + AgentContextHandle::Thread(handle) => Some(Self::pending_thread(handle, cx)), + AgentContextHandle::TextThread(handle) => Some(Self::pending_text_thread(handle, cx)), + AgentContextHandle::Rules(handle) => Self::pending_rules(handle, prompt_store, cx), +- AgentContextHandle::Image(handle) => { +- Some(Self::image(handle, model, project.path_style(cx), cx)) +- } ++ AgentContextHandle::Image(handle) => Some(Self::image(handle, model, cx)), + } + } + +- fn pending_file( +- handle: FileContextHandle, +- path_style: PathStyle, +- cx: &App, +- ) -> Option { +- let full_path = handle +- .buffer +- .read(cx) +- .file()? +- .full_path(cx) +- .to_string_lossy() +- .to_string(); +- Some(Self::file(handle, &full_path, path_style, cx)) ++ fn pending_file(handle: FileContextHandle, cx: &App) -> Option { ++ let full_path = handle.buffer.read(cx).file()?.full_path(cx); ++ Some(Self::file(handle, &full_path, cx)) + } + +- fn file( +- handle: FileContextHandle, +- full_path: &str, +- path_style: PathStyle, +- cx: &App, +- ) -> AddedContext { +- let (name, parent) = extract_file_name_and_directory_from_full_path(full_path, path_style); ++ fn file(handle: FileContextHandle, full_path: &Path, cx: &App) -> AddedContext { ++ let full_path_string: SharedString = full_path.to_string_lossy().into_owned().into(); ++ let (name, parent) = ++ extract_file_name_and_directory_from_full_path(full_path, &full_path_string); + AddedContext { + kind: ContextKind::File, + name, + parent, +- tooltip: Some(SharedString::new(full_path)), +- icon_path: FileIcons::get_icon(Path::new(full_path), cx), ++ tooltip: Some(full_path_string), ++ icon_path: FileIcons::get_icon(full_path, cx), + status: ContextStatus::Ready, + render_hover: None, + handle: AgentContextHandle::File(handle), +@@ -365,24 +343,19 @@ impl AddedContext { + ) -> Option { + let worktree = project.worktree_for_entry(handle.entry_id, cx)?.read(cx); + let entry = worktree.entry_for_id(handle.entry_id)?; +- let full_path = worktree +- .full_path(&entry.path) +- .to_string_lossy() +- .to_string(); +- Some(Self::directory(handle, &full_path, project.path_style(cx))) ++ let full_path = worktree.full_path(&entry.path); ++ Some(Self::directory(handle, &full_path)) + } + +- fn directory( +- handle: DirectoryContextHandle, +- full_path: &str, +- path_style: PathStyle, +- ) -> AddedContext { +- let (name, parent) = extract_file_name_and_directory_from_full_path(full_path, path_style); ++ fn directory(handle: DirectoryContextHandle, full_path: &Path) -> AddedContext { ++ let full_path_string: SharedString = full_path.to_string_lossy().into_owned().into(); ++ let (name, parent) = ++ extract_file_name_and_directory_from_full_path(full_path, &full_path_string); + AddedContext { + kind: ContextKind::Directory, + name, + parent, +- tooltip: Some(SharedString::new(full_path)), ++ tooltip: Some(full_path_string), + icon_path: None, + status: ContextStatus::Ready, + render_hover: None, +@@ -390,17 +363,9 @@ impl AddedContext { + } + } + +- fn pending_symbol( +- handle: SymbolContextHandle, +- path_style: PathStyle, +- cx: &App, +- ) -> Option { +- let excerpt = ContextFileExcerpt::new( +- &handle.full_path(cx)?.to_string_lossy(), +- handle.enclosing_line_range(cx), +- path_style, +- cx, +- ); ++ fn pending_symbol(handle: SymbolContextHandle, cx: &App) -> Option { ++ let excerpt = ++ ContextFileExcerpt::new(&handle.full_path(cx)?, handle.enclosing_line_range(cx), cx); + Some(AddedContext { + kind: ContextKind::Symbol, + name: handle.symbol.clone(), +@@ -418,17 +383,8 @@ impl AddedContext { + }) + } + +- fn pending_selection( +- handle: SelectionContextHandle, +- path_style: PathStyle, +- cx: &App, +- ) -> Option { +- let excerpt = ContextFileExcerpt::new( +- &handle.full_path(cx)?.to_string_lossy(), +- handle.line_range(cx), +- path_style, +- cx, +- ); ++ fn pending_selection(handle: SelectionContextHandle, cx: &App) -> Option { ++ let excerpt = ContextFileExcerpt::new(&handle.full_path(cx)?, handle.line_range(cx), cx); + Some(AddedContext { + kind: ContextKind::Selection, + name: excerpt.file_name_and_range.clone(), +@@ -529,13 +485,13 @@ impl AddedContext { + fn image( + context: ImageContext, + model: Option<&Arc>, +- path_style: PathStyle, + cx: &App, + ) -> AddedContext { + let (name, parent, icon_path) = if let Some(full_path) = context.full_path.as_ref() { ++ let full_path_string: SharedString = full_path.to_string_lossy().into_owned().into(); + let (name, parent) = +- extract_file_name_and_directory_from_full_path(full_path, path_style); +- let icon_path = FileIcons::get_icon(Path::new(full_path), cx); ++ extract_file_name_and_directory_from_full_path(full_path, &full_path_string); ++ let icon_path = FileIcons::get_icon(full_path, cx); + (name, parent, icon_path) + } else { + ("Image".into(), None, None) +@@ -584,20 +540,19 @@ impl AddedContext { + } + + fn extract_file_name_and_directory_from_full_path( +- path: &str, +- path_style: PathStyle, ++ path: &Path, ++ name_fallback: &SharedString, + ) -> (SharedString, Option) { +- let (parent, file_name) = path_style.split(path); +- let parent = parent.and_then(|parent| { +- let parent = parent.trim_end_matches(path_style.separator()); +- let (_, parent) = path_style.split(parent); +- if parent.is_empty() { +- None +- } else { +- Some(SharedString::new(parent)) +- } +- }); +- (SharedString::new(file_name), parent) ++ let name = path ++ .file_name() ++ .map(|n| n.to_string_lossy().into_owned().into()) ++ .unwrap_or_else(|| name_fallback.clone()); ++ let parent = path ++ .parent() ++ .and_then(|p| p.file_name()) ++ .map(|n| n.to_string_lossy().into_owned().into()); ++ ++ (name, parent) + } + + #[derive(Debug, Clone)] +@@ -609,25 +564,25 @@ struct ContextFileExcerpt { + } + + impl ContextFileExcerpt { +- pub fn new(full_path: &str, line_range: Range, path_style: PathStyle, cx: &App) -> Self { +- let (parent, file_name) = path_style.split(full_path); ++ pub fn new(full_path: &Path, line_range: Range, cx: &App) -> Self { ++ let full_path_string = full_path.to_string_lossy().into_owned(); ++ let file_name = full_path ++ .file_name() ++ .map(|n| n.to_string_lossy().into_owned()) ++ .unwrap_or_else(|| full_path_string.clone()); ++ + let line_range_text = format!(" ({}-{})", line_range.start.row + 1, line_range.end.row + 1); +- let mut full_path_and_range = full_path.to_owned(); ++ let mut full_path_and_range = full_path_string; + full_path_and_range.push_str(&line_range_text); +- let mut file_name_and_range = file_name.to_owned(); ++ let mut file_name_and_range = file_name; + file_name_and_range.push_str(&line_range_text); + +- let parent_name = parent.and_then(|parent| { +- let parent = parent.trim_end_matches(path_style.separator()); +- let (_, parent) = path_style.split(parent); +- if parent.is_empty() { +- None +- } else { +- Some(SharedString::new(parent)) +- } +- }); ++ let parent_name = full_path ++ .parent() ++ .and_then(|p| p.file_name()) ++ .map(|n| n.to_string_lossy().into_owned().into()); + +- let icon_path = FileIcons::get_icon(Path::new(full_path), cx); ++ let icon_path = FileIcons::get_icon(full_path, cx); + + ContextFileExcerpt { + file_name_and_range: file_name_and_range.into(), +@@ -735,7 +690,6 @@ impl Component for AddedContext { + image_task: Task::ready(Some(LanguageModelImage::empty())).shared(), + }, + None, +- PathStyle::local(), + cx, + ), + ); +@@ -756,7 +710,6 @@ impl Component for AddedContext { + .shared(), + }, + None, +- PathStyle::local(), + cx, + ), + ); +@@ -772,7 +725,6 @@ impl Component for AddedContext { + image_task: Task::ready(None).shared(), + }, + None, +- PathStyle::local(), + cx, + ), + ); +@@ -815,8 +767,7 @@ mod tests { + full_path: None, + }; + +- let added_context = +- AddedContext::image(image_context, Some(&model), PathStyle::local(), cx); ++ let added_context = AddedContext::image(image_context, Some(&model), cx); + + assert!(matches!( + added_context.status, +@@ -839,7 +790,7 @@ mod tests { + full_path: None, + }; + +- let added_context = AddedContext::image(image_context, None, PathStyle::local(), cx); ++ let added_context = AddedContext::image(image_context, None, cx); + + assert!( + matches!(added_context.status, ContextStatus::Ready), +diff --git a/crates/ai_onboarding/Cargo.toml b/crates/ai_onboarding/Cargo.toml +index 95a45b1a6f..cf3e6e9cd6 100644 +--- a/crates/ai_onboarding/Cargo.toml ++++ b/crates/ai_onboarding/Cargo.toml +@@ -18,6 +18,7 @@ default = [] + client.workspace = true + cloud_llm_client.workspace = true + component.workspace = true ++feature_flags.workspace = true + gpui.workspace = true + language_model.workspace = true + serde.workspace = true +diff --git a/crates/ai_onboarding/src/ai_onboarding.rs b/crates/ai_onboarding/src/ai_onboarding.rs +index d953ae6121..35e5832d3e 100644 +--- a/crates/ai_onboarding/src/ai_onboarding.rs ++++ b/crates/ai_onboarding/src/ai_onboarding.rs +@@ -18,6 +18,7 @@ pub use young_account_banner::YoungAccountBanner; + use std::sync::Arc; + + use client::{Client, UserStore, zed_urls}; ++use feature_flags::{BillingV2FeatureFlag, FeatureFlagAppExt as _}; + use gpui::{AnyElement, Entity, IntoElement, ParentElement}; + use ui::{Divider, RegisterComponent, Tooltip, prelude::*}; + +@@ -84,7 +85,7 @@ impl ZedAiOnboarding { + self + } + +- fn render_sign_in_disclaimer(&self, _cx: &mut App) -> AnyElement { ++ fn render_sign_in_disclaimer(&self, cx: &mut App) -> AnyElement { + let signing_in = matches!(self.sign_in_status, SignInStatus::SigningIn); + + v_flex() +@@ -95,7 +96,7 @@ impl ZedAiOnboarding { + .color(Color::Muted) + .mb_2(), + ) +- .child(PlanDefinitions.pro_plan(true, false)) ++ .child(PlanDefinitions.pro_plan(cx.has_flag::(), false)) + .child( + Button::new("sign_in", "Try Zed Pro for Free") + .disabled(signing_in) +@@ -119,7 +120,7 @@ impl ZedAiOnboarding { + .max_w_full() + .gap_1() + .child(Headline::new("Welcome to Zed AI")) +- .child(YoungAccountBanner) ++ .child(YoungAccountBanner::new(is_v2)) + .child( + v_flex() + .mt_2() +@@ -306,7 +307,7 @@ impl RenderOnce for ZedAiOnboarding { + fn render(self, _window: &mut ui::Window, cx: &mut App) -> impl IntoElement { + if matches!(self.sign_in_status, SignInStatus::SignedIn) { + match self.plan { +- None => self.render_free_plan_state(true, cx), ++ None => self.render_free_plan_state(cx.has_flag::(), cx), + Some(plan @ (Plan::V1(PlanV1::ZedFree) | Plan::V2(PlanV2::ZedFree))) => { + self.render_free_plan_state(plan.is_v2(), cx) + } +diff --git a/crates/ai_onboarding/src/ai_upsell_card.rs b/crates/ai_onboarding/src/ai_upsell_card.rs +index 91191688b5..f6a4759666 100644 +--- a/crates/ai_onboarding/src/ai_upsell_card.rs ++++ b/crates/ai_onboarding/src/ai_upsell_card.rs +@@ -2,6 +2,7 @@ use std::sync::Arc; + + use client::{Client, UserStore, zed_urls}; + use cloud_llm_client::{Plan, PlanV1, PlanV2}; ++use feature_flags::{BillingV2FeatureFlag, FeatureFlagAppExt}; + use gpui::{AnyElement, App, Entity, IntoElement, RenderOnce, Window}; + use ui::{CommonAnimationExt, Divider, Vector, VectorName, prelude::*}; + +@@ -49,7 +50,9 @@ impl AiUpsellCard { + + impl RenderOnce for AiUpsellCard { + fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { +- let is_v2_plan = self.user_plan.map_or(true, |plan| plan.is_v2()); ++ let is_v2_plan = self ++ .user_plan ++ .map_or(cx.has_flag::(), |plan| plan.is_v2()); + + let pro_section = v_flex() + .flex_grow() +@@ -172,7 +175,7 @@ impl RenderOnce for AiUpsellCard { + .child(Label::new("Try Zed AI").size(LabelSize::Large)) + .map(|this| { + if self.account_too_young { +- this.child(YoungAccountBanner).child( ++ this.child(YoungAccountBanner::new(is_v2_plan)).child( + v_flex() + .mt_2() + .gap_1() +diff --git a/crates/ai_onboarding/src/young_account_banner.rs b/crates/ai_onboarding/src/young_account_banner.rs +index c4a7887364..fde9a31c49 100644 +--- a/crates/ai_onboarding/src/young_account_banner.rs ++++ b/crates/ai_onboarding/src/young_account_banner.rs +@@ -2,17 +2,30 @@ use gpui::{IntoElement, ParentElement}; + use ui::{Banner, prelude::*}; + + #[derive(IntoElement)] +-pub struct YoungAccountBanner; ++pub struct YoungAccountBanner { ++ is_v2: bool, ++} ++ ++impl YoungAccountBanner { ++ pub fn new(is_v2: bool) -> Self { ++ Self { is_v2 } ++ } ++} + + impl RenderOnce for YoungAccountBanner { + fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { +- const YOUNG_ACCOUNT_DISCLAIMER: &str = "To prevent abuse of our service, GitHub accounts created fewer than 30 days ago are not eligible for the Pro trial. You can request an exception by reaching out to billing-support@zed.dev"; ++ const YOUNG_ACCOUNT_DISCLAIMER: &str = "To prevent abuse of our service, GitHub accounts created fewer than 30 days ago are not eligible for free plan usage or Pro plan free trial. You can request an exception by reaching out to billing-support@zed.dev"; ++ const YOUNG_ACCOUNT_DISCLAIMER_V2: &str = "To prevent abuse of our service, GitHub accounts created fewer than 30 days ago are not eligible for the Pro trial. You can request an exception by reaching out to billing-support@zed.dev"; + + let label = div() + .w_full() + .text_sm() + .text_color(cx.theme().colors().text_muted) +- .child(YOUNG_ACCOUNT_DISCLAIMER); ++ .child(if self.is_v2 { ++ YOUNG_ACCOUNT_DISCLAIMER_V2 ++ } else { ++ YOUNG_ACCOUNT_DISCLAIMER ++ }); + + div() + .max_w_full() +diff --git a/crates/assistant_context/src/assistant_context.rs b/crates/assistant_context/src/assistant_context.rs +index 6c06cc2c8e..23aeabbc89 100644 +--- a/crates/assistant_context/src/assistant_context.rs ++++ b/crates/assistant_context/src/assistant_context.rs +@@ -2669,7 +2669,7 @@ impl AssistantContext { + } + + pub fn summarize(&mut self, mut replace_old: bool, cx: &mut Context) { +- let Some(model) = LanguageModelRegistry::read_global(cx).thread_summary_model() else { ++ let Some(model) = LanguageModelRegistry::read_global(cx).default_model() else { + return; + }; + +diff --git a/crates/assistant_context/src/assistant_context_tests.rs b/crates/assistant_context/src/assistant_context_tests.rs +index 413e32dfcb..8b182685cf 100644 +--- a/crates/assistant_context/src/assistant_context_tests.rs ++++ b/crates/assistant_context/src/assistant_context_tests.rs +@@ -1329,12 +1329,13 @@ fn setup_context_editor_with_fake_model( + cx.update(|cx| { + init_test(cx); + LanguageModelRegistry::global(cx).update(cx, |registry, cx| { +- let configured_model = ConfiguredModel { +- provider: fake_provider.clone(), +- model: fake_model.clone(), +- }; +- registry.set_default_model(Some(configured_model.clone()), cx); +- registry.set_thread_summary_model(Some(configured_model), cx); ++ registry.set_default_model( ++ Some(ConfiguredModel { ++ provider: fake_provider.clone(), ++ model: fake_model.clone(), ++ }), ++ cx, ++ ) + }) + }); + +diff --git a/crates/assistant_slash_commands/src/file_command.rs b/crates/assistant_slash_commands/src/file_command.rs +index 0968a297b8..afb3d942fe 100644 +--- a/crates/assistant_slash_commands/src/file_command.rs ++++ b/crates/assistant_slash_commands/src/file_command.rs +@@ -290,7 +290,7 @@ fn collect_files( + folded_directory_names.join(&path_including_worktree_name); + } else { + folded_directory_names = +- folded_directory_names.join(RelPath::unix(&filename).unwrap()); ++ folded_directory_names.join(RelPath::new(&filename).unwrap()); + } + continue; + } +@@ -320,7 +320,7 @@ fn collect_files( + directory_stack.push(entry.path.clone()); + } else { + let entry_name = +- folded_directory_names.join(RelPath::unix(&filename).unwrap()); ++ folded_directory_names.join(RelPath::new(&filename).unwrap()); + let entry_name = entry_name.display(path_style); + events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection { + icon: IconName::Folder, +@@ -355,7 +355,9 @@ fn collect_files( + let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?; + append_buffer_to_output( + &snapshot, +- Some(path_including_worktree_name.display(path_style).as_ref()), ++ Some(Path::new( ++ path_including_worktree_name.display(path_style).as_ref(), ++ )), + &mut output, + ) + .log_err(); +@@ -380,18 +382,18 @@ fn collect_files( + } + + pub fn codeblock_fence_for_path( +- path: Option<&str>, ++ path: Option<&Path>, + row_range: Option>, + ) -> String { + let mut text = String::new(); + write!(text, "```").unwrap(); + + if let Some(path) = path { +- if let Some(extension) = Path::new(path).extension().and_then(|ext| ext.to_str()) { ++ if let Some(extension) = path.extension().and_then(|ext| ext.to_str()) { + write!(text, "{} ", extension).unwrap(); + } + +- write!(text, "{path}").unwrap(); ++ write!(text, "{}", path.display()).unwrap(); + } else { + write!(text, "untitled").unwrap(); + } +@@ -411,12 +413,12 @@ pub struct FileCommandMetadata { + + pub fn build_entry_output_section( + range: Range, +- path: Option<&str>, ++ path: Option<&Path>, + is_directory: bool, + line_range: Option>, + ) -> SlashCommandOutputSection { + let mut label = if let Some(path) = path { +- path.to_string() ++ path.to_string_lossy().to_string() + } else { + "untitled".to_string() + }; +@@ -439,7 +441,7 @@ pub fn build_entry_output_section( + } else { + path.and_then(|path| { + serde_json::to_value(FileCommandMetadata { +- path: path.to_string(), ++ path: path.to_string_lossy().to_string(), + }) + .ok() + }) +@@ -503,7 +505,7 @@ mod custom_path_matcher { + .iter() + .zip(self.sources_with_trailing_slash.iter()) + .any(|(source, with_slash)| { +- let as_bytes = other.as_unix_str().as_bytes(); ++ let as_bytes = other.as_str().as_bytes(); + let with_slash = if source.ends_with('/') { + source.as_bytes() + } else { +@@ -512,12 +514,12 @@ mod custom_path_matcher { + + as_bytes.starts_with(with_slash) || as_bytes.ends_with(source.as_bytes()) + }) +- || self.glob.is_match(other.as_std_path()) ++ || self.glob.is_match(other) + || self.check_with_end_separator(other) + } + + fn check_with_end_separator(&self, path: &RelPath) -> bool { +- let path_str = path.as_unix_str(); ++ let path_str = path.as_str(); + let separator = "/"; + if path_str.ends_with(separator) { + false +@@ -530,7 +532,7 @@ mod custom_path_matcher { + + pub fn append_buffer_to_output( + buffer: &BufferSnapshot, +- path: Option<&str>, ++ path: Option<&Path>, + output: &mut SlashCommandOutput, + ) -> Result<()> { + let prev_len = output.text.len(); +diff --git a/crates/assistant_slash_commands/src/selection_command.rs b/crates/assistant_slash_commands/src/selection_command.rs +index 068a66339b..c5f01ee94c 100644 +--- a/crates/assistant_slash_commands/src/selection_command.rs ++++ b/crates/assistant_slash_commands/src/selection_command.rs +@@ -137,9 +137,7 @@ pub fn selections_creases( + None + }; + let language_name = language_name.as_deref().unwrap_or(""); +- let filename = snapshot +- .file_at(range.start) +- .map(|file| file.full_path(cx).to_string_lossy().to_string()); ++ let filename = snapshot.file_at(range.start).map(|file| file.full_path(cx)); + let text = if language_name == "markdown" { + selected_text + .lines() +@@ -189,9 +187,9 @@ pub fn selections_creases( + let start_line = range.start.row + 1; + let end_line = range.end.row + 1; + if start_line == end_line { +- format!("{path}, Line {start_line}") ++ format!("{}, Line {}", path.display(), start_line) + } else { +- format!("{path}, Lines {start_line} to {end_line}") ++ format!("{}, Lines {} to {}", path.display(), start_line, end_line) + } + } else { + "Quoted selection".to_string() +diff --git a/crates/assistant_slash_commands/src/symbols_command.rs b/crates/assistant_slash_commands/src/symbols_command.rs +index c537ced296..c700319800 100644 +--- a/crates/assistant_slash_commands/src/symbols_command.rs ++++ b/crates/assistant_slash_commands/src/symbols_command.rs +@@ -7,8 +7,8 @@ use editor::Editor; + use gpui::{AppContext as _, Task, WeakEntity}; + use language::{BufferSnapshot, LspAdapterDelegate}; + use std::sync::Arc; +-use std::sync::atomic::AtomicBool; +-use ui::{App, IconName, SharedString, Window}; ++use std::{path::Path, sync::atomic::AtomicBool}; ++use ui::{App, IconName, Window}; + use workspace::Workspace; + + pub struct OutlineSlashCommand; +@@ -67,13 +67,13 @@ impl SlashCommand for OutlineSlashCommand { + }; + + let snapshot = buffer.read(cx).snapshot(); +- let path = snapshot.resolve_file_path(true, cx); ++ let path = snapshot.resolve_file_path(cx, true); + + cx.background_spawn(async move { + let outline = snapshot.outline(None); + +- let path = path.as_deref().unwrap_or("untitled"); +- let mut outline_text = format!("Symbols for {path}:\n"); ++ let path = path.as_deref().unwrap_or(Path::new("untitled")); ++ let mut outline_text = format!("Symbols for {}:\n", path.display()); + for item in &outline.path_candidates { + outline_text.push_str("- "); + outline_text.push_str(&item.string); +@@ -84,7 +84,7 @@ impl SlashCommand for OutlineSlashCommand { + sections: vec![SlashCommandOutputSection { + range: 0..outline_text.len(), + icon: IconName::ListTree, +- label: SharedString::new(path), ++ label: path.to_string_lossy().to_string().into(), + metadata: None, + }], + text: outline_text, +diff --git a/crates/assistant_slash_commands/src/tab_command.rs b/crates/assistant_slash_commands/src/tab_command.rs +index 9fd38128ca..a124beed63 100644 +--- a/crates/assistant_slash_commands/src/tab_command.rs ++++ b/crates/assistant_slash_commands/src/tab_command.rs +@@ -8,9 +8,12 @@ use editor::Editor; + use futures::future::join_all; + use gpui::{Task, WeakEntity}; + use language::{BufferSnapshot, CodeLabel, HighlightId, LspAdapterDelegate}; +-use std::sync::{Arc, atomic::AtomicBool}; ++use std::{ ++ path::PathBuf, ++ sync::{Arc, atomic::AtomicBool}, ++}; + use ui::{ActiveTheme, App, Window, prelude::*}; +-use util::{ResultExt, paths::PathStyle}; ++use util::ResultExt; + use workspace::Workspace; + + use crate::file_command::append_buffer_to_output; +@@ -69,42 +72,35 @@ impl SlashCommand for TabSlashCommand { + return Task::ready(Ok(Vec::new())); + } + +- let Some(workspace) = workspace.and_then(|workspace| workspace.upgrade()) else { +- return Task::ready(Err(anyhow::anyhow!("no workspace"))); +- }; +- +- let active_item_path = workspace.update(cx, |workspace, cx| { +- let snapshot = active_item_buffer(workspace, cx).ok()?; +- snapshot.resolve_file_path(true, cx) ++ let active_item_path = workspace.as_ref().and_then(|workspace| { ++ workspace ++ .update(cx, |workspace, cx| { ++ let snapshot = active_item_buffer(workspace, cx).ok()?; ++ snapshot.resolve_file_path(cx, true) ++ }) ++ .ok() ++ .flatten() + }); +- let path_style = workspace.read(cx).path_style(cx); +- + let current_query = arguments.last().cloned().unwrap_or_default(); +- let tab_items_search = tab_items_for_queries( +- Some(workspace.downgrade()), +- &[current_query], +- cancel, +- false, +- window, +- cx, +- ); ++ let tab_items_search = ++ tab_items_for_queries(workspace, &[current_query], cancel, false, window, cx); + + let comment_id = cx.theme().syntax().highlight_id("comment").map(HighlightId); + window.spawn(cx, async move |_| { + let tab_items = tab_items_search.await?; + let run_command = tab_items.len() == 1; + let tab_completion_items = tab_items.into_iter().filter_map(|(path, ..)| { +- let path = path?; +- if argument_set.contains(&path) { ++ let path_string = path.as_deref()?.to_string_lossy().to_string(); ++ if argument_set.contains(&path_string) { + return None; + } +- if active_item_path.as_ref() == Some(&path) { ++ if active_item_path.is_some() && active_item_path == path { + return None; + } +- let label = create_tab_completion_label(&path, path_style, comment_id); ++ let label = create_tab_completion_label(path.as_ref()?, comment_id); + Some(ArgumentCompletion { + label, +- new_text: path, ++ new_text: path_string, + replace_previous_arguments: false, + after_completion: run_command.into(), + }) +@@ -113,9 +109,8 @@ impl SlashCommand for TabSlashCommand { + let active_item_completion = active_item_path + .as_deref() + .map(|active_item_path| { +- let path_string = active_item_path.to_string(); +- let label = +- create_tab_completion_label(active_item_path, path_style, comment_id); ++ let path_string = active_item_path.to_string_lossy().to_string(); ++ let label = create_tab_completion_label(active_item_path, comment_id); + ArgumentCompletion { + label, + new_text: path_string, +@@ -174,7 +169,7 @@ fn tab_items_for_queries( + strict_match: bool, + window: &mut Window, + cx: &mut App, +-) -> Task, BufferSnapshot, usize)>>> { ++) -> Task, BufferSnapshot, usize)>>> { + let empty_query = queries.is_empty() || queries.iter().all(|query| query.trim().is_empty()); + let queries = queries.to_owned(); + window.spawn(cx, async move |cx| { +@@ -184,7 +179,7 @@ fn tab_items_for_queries( + .update(cx, |workspace, cx| { + if strict_match && empty_query { + let snapshot = active_item_buffer(workspace, cx)?; +- let full_path = snapshot.resolve_file_path(true, cx); ++ let full_path = snapshot.resolve_file_path(cx, true); + return anyhow::Ok(vec![(full_path, snapshot, 0)]); + } + +@@ -206,7 +201,7 @@ fn tab_items_for_queries( + && visited_buffers.insert(buffer.read(cx).remote_id()) + { + let snapshot = buffer.read(cx).snapshot(); +- let full_path = snapshot.resolve_file_path(true, cx); ++ let full_path = snapshot.resolve_file_path(cx, true); + open_buffers.push((full_path, snapshot, *timestamp)); + } + } +@@ -229,7 +224,10 @@ fn tab_items_for_queries( + let match_candidates = open_buffers + .iter() + .enumerate() +- .filter_map(|(id, (full_path, ..))| Some((id, full_path.clone()?))) ++ .filter_map(|(id, (full_path, ..))| { ++ let path_string = full_path.as_deref()?.to_string_lossy().to_string(); ++ Some((id, path_string)) ++ }) + .fold(HashMap::default(), |mut candidates, (id, path_string)| { + candidates + .entry(path_string) +@@ -251,7 +249,8 @@ fn tab_items_for_queries( + .iter() + .enumerate() + .filter_map(|(id, (full_path, ..))| { +- Some(fuzzy::StringMatchCandidate::new(id, full_path.as_ref()?)) ++ let path_string = full_path.as_deref()?.to_string_lossy().to_string(); ++ Some(fuzzy::StringMatchCandidate::new(id, &path_string)) + }) + .collect::>(); + let mut processed_matches = HashSet::default(); +@@ -303,15 +302,21 @@ fn active_item_buffer( + } + + fn create_tab_completion_label( +- path: &str, +- path_style: PathStyle, ++ path: &std::path::Path, + comment_id: Option, + ) -> CodeLabel { +- let (parent_path, file_name) = path_style.split(path); ++ let file_name = path ++ .file_name() ++ .map(|f| f.to_string_lossy()) ++ .unwrap_or_default(); ++ let parent_path = path ++ .parent() ++ .map(|p| p.to_string_lossy()) ++ .unwrap_or_default(); + let mut label = CodeLabel::default(); +- label.push_str(file_name, None); ++ label.push_str(&file_name, None); + label.push_str(" ", None); +- label.push_str(parent_path.unwrap_or_default(), comment_id); ++ label.push_str(&parent_path, comment_id); + label.filter_range = 0..file_name.len(); + label + } +diff --git a/crates/assistant_tool/src/outline.rs b/crates/assistant_tool/src/outline.rs +index 4c8e2efefd..fa5ad561ee 100644 +--- a/crates/assistant_tool/src/outline.rs ++++ b/crates/assistant_tool/src/outline.rs +@@ -5,6 +5,7 @@ use language::{Buffer, OutlineItem, ParseStatus}; + use project::Project; + use regex::Regex; + use std::fmt::Write; ++use std::path::Path; + use text::Point; + + /// For files over this size, instead of reading them (or including them in context), +@@ -142,7 +143,7 @@ pub struct BufferContent { + /// For smaller files, returns the full content. + pub async fn get_buffer_content_or_outline( + buffer: Entity, +- path: Option<&str>, ++ path: Option<&Path>, + cx: &AsyncApp, + ) -> Result { + let file_size = buffer.read_with(cx, |buffer, _| buffer.text().len())?; +@@ -169,10 +170,15 @@ pub async fn get_buffer_content_or_outline( + + let text = if let Some(path) = path { + format!( +- "# File outline for {path} (file too large to show full content)\n\n{outline_text}", ++ "# File outline for {} (file too large to show full content)\n\n{}", ++ path.display(), ++ outline_text + ) + } else { +- format!("# File outline (file too large to show full content)\n\n{outline_text}",) ++ format!( ++ "# File outline (file too large to show full content)\n\n{}", ++ outline_text ++ ) + }; + Ok(BufferContent { + text, +diff --git a/crates/assistant_tools/src/edit_agent.rs b/crates/assistant_tools/src/edit_agent.rs +index 829287f654..29ac53e2a6 100644 +--- a/crates/assistant_tools/src/edit_agent.rs ++++ b/crates/assistant_tools/src/edit_agent.rs +@@ -26,13 +26,13 @@ use language_model::{ + use project::{AgentLocation, Project}; + use schemars::JsonSchema; + use serde::{Deserialize, Serialize}; +-use std::{cmp, iter, mem, ops::Range, pin::Pin, sync::Arc, task::Poll}; ++use std::{cmp, iter, mem, ops::Range, path::PathBuf, pin::Pin, sync::Arc, task::Poll}; + use streaming_diff::{CharOperation, StreamingDiff}; + use streaming_fuzzy_matcher::StreamingFuzzyMatcher; + + #[derive(Serialize)] + struct CreateFilePromptTemplate { +- path: Option, ++ path: Option, + edit_description: String, + } + +@@ -42,7 +42,7 @@ impl Template for CreateFilePromptTemplate { + + #[derive(Serialize)] + struct EditFileXmlPromptTemplate { +- path: Option, ++ path: Option, + edit_description: String, + } + +@@ -52,7 +52,7 @@ impl Template for EditFileXmlPromptTemplate { + + #[derive(Serialize)] + struct EditFileDiffFencedPromptTemplate { +- path: Option, ++ path: Option, + edit_description: String, + } + +@@ -115,7 +115,7 @@ impl EditAgent { + let conversation = conversation.clone(); + let output = cx.spawn(async move |cx| { + let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?; +- let path = cx.update(|cx| snapshot.resolve_file_path(true, cx))?; ++ let path = cx.update(|cx| snapshot.resolve_file_path(cx, true))?; + let prompt = CreateFilePromptTemplate { + path, + edit_description, +@@ -229,7 +229,7 @@ impl EditAgent { + let edit_format = self.edit_format; + let output = cx.spawn(async move |cx| { + let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?; +- let path = cx.update(|cx| snapshot.resolve_file_path(true, cx))?; ++ let path = cx.update(|cx| snapshot.resolve_file_path(cx, true))?; + let prompt = match edit_format { + EditFormat::XmlTags => EditFileXmlPromptTemplate { + path, +diff --git a/crates/assistant_tools/src/edit_file_tool.rs b/crates/assistant_tools/src/edit_file_tool.rs +index c8b7add0b8..f7ed5e28bf 100644 +--- a/crates/assistant_tools/src/edit_file_tool.rs ++++ b/crates/assistant_tools/src/edit_file_tool.rs +@@ -554,7 +554,7 @@ fn resolve_path( + .context("Can't create file: invalid filename")?; + + let new_file_path = parent_project_path.map(|parent| ProjectPath { +- path: parent.path.join(RelPath::unix(file_name).unwrap()), ++ path: parent.path.join(RelPath::new(file_name).unwrap()), + ..parent + }); + +diff --git a/crates/assistant_tools/src/list_directory_tool.rs b/crates/assistant_tools/src/list_directory_tool.rs +index 7d70f41a8c..d46ac3ac0d 100644 +--- a/crates/assistant_tools/src/list_directory_tool.rs ++++ b/crates/assistant_tools/src/list_directory_tool.rs +@@ -86,7 +86,6 @@ impl Tool for ListDirectoryTool { + _window: Option, + cx: &mut App, + ) -> ToolResult { +- let path_style = project.read(cx).path_style(cx); + let input = match serde_json::from_value::(input) { + Ok(input) => input, + Err(err) => return Task::ready(Err(anyhow!(err))).into(), +@@ -101,7 +100,7 @@ impl Tool for ListDirectoryTool { + .filter_map(|worktree| { + worktree.read(cx).root_entry().and_then(|entry| { + if entry.is_dir() { +- Some(entry.path.display(path_style)) ++ Some(entry.path.as_str()) + } else { + None + } +diff --git a/crates/assistant_tools/src/read_file_tool.rs b/crates/assistant_tools/src/read_file_tool.rs +index f9f68491e5..7006cc6903 100644 +--- a/crates/assistant_tools/src/read_file_tool.rs ++++ b/crates/assistant_tools/src/read_file_tool.rs +@@ -261,8 +261,9 @@ impl Tool for ReadFileTool { + Ok(result) + } else { + // No line ranges specified, so check file size to see if it's too big. ++ let path_buf = std::path::PathBuf::from(&file_path); + let buffer_content = +- outline::get_buffer_content_or_outline(buffer.clone(), Some(&file_path), cx) ++ outline::get_buffer_content_or_outline(buffer.clone(), Some(&path_buf), cx) + .await?; + + action_log.update(cx, |log, cx| { +diff --git a/crates/audio/Cargo.toml b/crates/audio/Cargo.toml +index 7f2fed80e2..c083c9a659 100644 +--- a/crates/audio/Cargo.toml ++++ b/crates/audio/Cargo.toml +@@ -18,7 +18,6 @@ async-tar.workspace = true + collections.workspace = true + crossbeam.workspace = true + gpui.workspace = true +-denoise = { path = "../denoise" } + log.workspace = true + parking_lot.workspace = true + rodio = { workspace = true, features = [ "wav", "playback", "wav_output" ] } +diff --git a/crates/audio/src/audio.rs b/crates/audio/src/audio.rs +index 379af34751..f60ddb87b9 100644 +--- a/crates/audio/src/audio.rs ++++ b/crates/audio/src/audio.rs +@@ -9,7 +9,7 @@ mod non_windows_and_freebsd_deps { + pub(super) use log::info; + pub(super) use parking_lot::Mutex; + pub(super) use rodio::cpal::Sample; +- pub(super) use rodio::source::LimitSettings; ++ pub(super) use rodio::source::{LimitSettings, UniformSourceIterator}; + pub(super) use std::sync::Arc; + } + +@@ -31,20 +31,18 @@ pub use rodio_ext::RodioExt; + + use crate::audio_settings::LIVE_SETTINGS; + +-// We are migrating to 16kHz sample rate from 48kHz. In the future +-// once we are reasonably sure most users have upgraded we will +-// remove the LEGACY parameters. ++// NOTE: We used to use WebRTC's mixer which only supported ++// 16kHz, 32kHz and 48kHz. As 48 is the most common "next step up" ++// for audio output devices like speakers/bluetooth, we just hard-code ++// this; and downsample when we need to. + // +-// We migrate to 16kHz because it is sufficient for speech and required +-// by the denoiser and future Speech to Text layers. +-pub const SAMPLE_RATE: NonZero = nz!(16000); +-pub const CHANNEL_COUNT: NonZero = nz!(1); ++// Since most noise cancelling requires 16kHz we will move to ++// that in the future. ++pub const SAMPLE_RATE: NonZero = nz!(48000); ++pub const CHANNEL_COUNT: NonZero = nz!(2); + pub const BUFFER_SIZE: usize = // echo canceller and livekit want 10ms of audio + (SAMPLE_RATE.get() as usize / 100) * CHANNEL_COUNT.get() as usize; + +-pub const LEGACY_SAMPLE_RATE: NonZero = nz!(48000); +-pub const LEGACY_CHANNEL_COUNT: NonZero = nz!(2); +- + pub const REPLAY_DURATION: Duration = Duration::from_secs(30); + + pub fn init(cx: &mut App) { +@@ -108,16 +106,11 @@ impl Global for Audio {} + + impl Audio { + fn ensure_output_exists(&mut self) -> Result<&Mixer> { +- #[cfg(debug_assertions)] +- log::warn!( +- "Audio does not sound correct without optimizations. Use a release build to debug audio issues" +- ); +- + if self.output_handle.is_none() { +- let output_handle = OutputStreamBuilder::open_default_stream() +- .context("Could not open default output stream")?; +- info!("Output stream: {:?}", output_handle); +- self.output_handle = Some(output_handle); ++ self.output_handle = Some( ++ OutputStreamBuilder::open_default_stream() ++ .context("Could not open default output stream")?, ++ ); + if let Some(output_handle) = &self.output_handle { + let (mixer, source) = rodio::mixer::mixer(CHANNEL_COUNT, SAMPLE_RATE); + // or the mixer will end immediately as its empty. +@@ -167,20 +160,13 @@ impl Audio { + let stream = rodio::microphone::MicrophoneBuilder::new() + .default_device()? + .default_config()? +- .prefer_sample_rates([ +- SAMPLE_RATE, // sample rates trivially resamplable to `SAMPLE_RATE` +- SAMPLE_RATE.saturating_mul(nz!(2)), +- SAMPLE_RATE.saturating_mul(nz!(3)), +- SAMPLE_RATE.saturating_mul(nz!(4)), +- ]) +- .prefer_channel_counts([nz!(1), nz!(2), nz!(3), nz!(4)]) ++ .prefer_sample_rates([SAMPLE_RATE, SAMPLE_RATE.saturating_mul(nz!(2))]) ++ // .prefer_channel_counts([nz!(1), nz!(2)]) + .prefer_buffer_sizes(512..) + .open_stream()?; + info!("Opened microphone: {:?}", stream.config()); + +- let stream = stream +- .possibly_disconnected_channels_to_mono() +- .constant_samplerate(SAMPLE_RATE) ++ let (replay, stream) = UniformSourceIterator::new(stream, CHANNEL_COUNT, SAMPLE_RATE) + .limit(LimitSettings::live_performance()) + .process_buffer::(move |buffer| { + let mut int_buffer: [i16; _] = buffer.map(|s| s.to_sample()); +@@ -201,27 +187,15 @@ impl Audio { + } + } + }) +- .denoise() +- .context("Could not set up denoiser")? +- .automatic_gain_control(0.90, 1.0, 0.0, 5.0) ++ .automatic_gain_control(1.0, 4.0, 0.0, 5.0) + .periodic_access(Duration::from_millis(100), move |agc_source| { +- agc_source +- .set_enabled(LIVE_SETTINGS.auto_microphone_volume.load(Ordering::Relaxed)); +- let denoise = agc_source.inner_mut(); +- denoise.set_enabled(LIVE_SETTINGS.denoise.load(Ordering::Relaxed)); +- }); +- +- let stream = if voip_parts.legacy_audio_compatible { +- stream.constant_params(LEGACY_CHANNEL_COUNT, LEGACY_SAMPLE_RATE) +- } else { +- stream.constant_params(CHANNEL_COUNT, SAMPLE_RATE) +- }; +- +- let (replay, stream) = stream.replayable(REPLAY_DURATION)?; ++ agc_source.set_enabled(LIVE_SETTINGS.control_input_volume.load(Ordering::Relaxed)); ++ }) ++ .replayable(REPLAY_DURATION)?; ++ + voip_parts + .replays + .add_voip_stream("local microphone".to_string(), replay); +- + Ok(stream) + } + +@@ -232,10 +206,9 @@ impl Audio { + cx: &mut App, + ) -> anyhow::Result<()> { + let (replay_source, source) = source +- .constant_params(CHANNEL_COUNT, SAMPLE_RATE) +- .automatic_gain_control(0.90, 1.0, 0.0, 5.0) ++ .automatic_gain_control(1.0, 4.0, 0.0, 5.0) + .periodic_access(Duration::from_millis(100), move |agc_source| { +- agc_source.set_enabled(LIVE_SETTINGS.auto_speaker_volume.load(Ordering::Relaxed)); ++ agc_source.set_enabled(LIVE_SETTINGS.control_input_volume.load(Ordering::Relaxed)); + }) + .replayable(REPLAY_DURATION) + .expect("REPLAY_DURATION is longer than 100ms"); +@@ -296,7 +269,6 @@ impl Audio { + pub struct VoipParts { + echo_canceller: Arc>, + replays: replays::Replays, +- legacy_audio_compatible: bool, + } + + #[cfg(not(any(all(target_os = "windows", target_env = "gnu"), target_os = "freebsd")))] +@@ -305,12 +277,8 @@ impl VoipParts { + let (apm, replays) = cx.try_read_default_global::(|audio, _| { + (Arc::clone(&audio.echo_canceller), audio.replays.clone()) + })?; +- let legacy_audio_compatible = +- AudioSettings::try_read_global(cx, |settings| settings.legacy_audio_compatible) +- .unwrap_or(true); + + Ok(Self { +- legacy_audio_compatible, + echo_canceller: apm, + replays, + }) +diff --git a/crates/audio/src/audio_settings.rs b/crates/audio/src/audio_settings.rs +index cba7d45c31..2c9db4989e 100644 +--- a/crates/audio/src/audio_settings.rs ++++ b/crates/audio/src/audio_settings.rs +@@ -6,38 +6,18 @@ use settings::{Settings, SettingsStore}; + #[derive(Clone, Debug)] + pub struct AudioSettings { + /// Opt into the new audio system. +- /// +- /// You need to rejoin a call for this setting to apply + pub rodio_audio: bool, // default is false + /// Requires 'rodio_audio: true' + /// +- /// Automatically increase or decrease you microphone's volume. This affects how +- /// loud you sound to others. +- /// +- /// Recommended: off (default) +- /// Microphones are too quite in zed, until everyone is on experimental +- /// audio and has auto speaker volume on this will make you very loud +- /// compared to other speakers. +- pub auto_microphone_volume: bool, +- /// Requires 'rodio_audio: true' +- /// +- /// Automatically increate or decrease the volume of other call members. +- /// This only affects how things sound for you. +- pub auto_speaker_volume: bool, +- /// Requires 'rodio_audio: true' +- /// +- /// Remove background noises. Works great for typing, cars, dogs, AC. Does +- /// not work well on music. +- pub denoise: bool, ++ /// Use the new audio systems automatic gain control for your microphone. ++ /// This affects how loud you sound to others. ++ pub control_input_volume: bool, + /// Requires 'rodio_audio: true' + /// +- /// Use audio parameters compatible with the previous versions of +- /// experimental audio and non-experimental audio. When this is false you +- /// will sound strange to anyone not on the latest experimental audio. In +- /// the future we will migrate by setting this to false +- /// +- /// You need to rejoin a call for this setting to apply +- pub legacy_audio_compatible: bool, ++ /// Use the new audio systems automatic gain control on everyone in the ++ /// call. This makes call members who are too quite louder and those who are ++ /// too loud quieter. This only affects how things sound for you. ++ pub control_output_volume: bool, + } + + /// Configuration of audio in Zed +@@ -45,66 +25,46 @@ impl Settings for AudioSettings { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { + let audio = &content.audio.as_ref().unwrap(); + AudioSettings { ++ control_input_volume: audio.control_input_volume.unwrap(), ++ control_output_volume: audio.control_output_volume.unwrap(), + rodio_audio: audio.rodio_audio.unwrap(), +- auto_microphone_volume: audio.auto_microphone_volume.unwrap(), +- auto_speaker_volume: audio.auto_speaker_volume.unwrap(), +- denoise: audio.denoise.unwrap(), +- legacy_audio_compatible: audio.legacy_audio_compatible.unwrap(), + } + } ++ ++ fn import_from_vscode( ++ _vscode: &settings::VsCodeSettings, ++ _current: &mut settings::SettingsContent, ++ ) { ++ } + } + + /// See docs on [LIVE_SETTINGS] + pub(crate) struct LiveSettings { +- pub(crate) auto_microphone_volume: AtomicBool, +- pub(crate) auto_speaker_volume: AtomicBool, +- pub(crate) denoise: AtomicBool, ++ pub(crate) control_input_volume: AtomicBool, ++ pub(crate) control_output_volume: AtomicBool, + } + + impl LiveSettings { + pub(crate) fn initialize(&self, cx: &mut App) { + cx.observe_global::(move |cx| { +- LIVE_SETTINGS.auto_microphone_volume.store( +- AudioSettings::get_global(cx).auto_microphone_volume, ++ LIVE_SETTINGS.control_input_volume.store( ++ AudioSettings::get_global(cx).control_input_volume, + Ordering::Relaxed, + ); +- LIVE_SETTINGS.auto_speaker_volume.store( +- AudioSettings::get_global(cx).auto_speaker_volume, ++ LIVE_SETTINGS.control_output_volume.store( ++ AudioSettings::get_global(cx).control_output_volume, + Ordering::Relaxed, + ); +- +- let denoise_enabled = AudioSettings::get_global(cx).denoise; +- #[cfg(debug_assertions)] +- { +- static DENOISE_WARNING_SEND: AtomicBool = AtomicBool::new(false); +- if denoise_enabled && !DENOISE_WARNING_SEND.load(Ordering::Relaxed) { +- DENOISE_WARNING_SEND.store(true, Ordering::Relaxed); +- log::warn!("Denoise does not work on debug builds, not enabling") +- } +- } +- #[cfg(not(debug_assertions))] +- LIVE_SETTINGS +- .denoise +- .store(denoise_enabled, Ordering::Relaxed); + }) + .detach(); + + let init_settings = AudioSettings::get_global(cx); + LIVE_SETTINGS +- .auto_microphone_volume +- .store(init_settings.auto_microphone_volume, Ordering::Relaxed); +- LIVE_SETTINGS +- .auto_speaker_volume +- .store(init_settings.auto_speaker_volume, Ordering::Relaxed); +- let denoise_enabled = AudioSettings::get_global(cx).denoise; +- #[cfg(debug_assertions)] +- if denoise_enabled { +- log::warn!("Denoise does not work on debug builds, not enabling") +- } +- #[cfg(not(debug_assertions))] ++ .control_input_volume ++ .store(init_settings.control_input_volume, Ordering::Relaxed); + LIVE_SETTINGS +- .denoise +- .store(denoise_enabled, Ordering::Relaxed); ++ .control_output_volume ++ .store(init_settings.control_output_volume, Ordering::Relaxed); + } + } + +@@ -113,7 +73,6 @@ impl LiveSettings { + /// real time and must each run in a dedicated OS thread, therefore we can not + /// use the background executor. + pub(crate) static LIVE_SETTINGS: LiveSettings = LiveSettings { +- auto_microphone_volume: AtomicBool::new(true), +- auto_speaker_volume: AtomicBool::new(true), +- denoise: AtomicBool::new(true), ++ control_input_volume: AtomicBool::new(true), ++ control_output_volume: AtomicBool::new(true), + }; +diff --git a/crates/audio/src/rodio_ext.rs b/crates/audio/src/rodio_ext.rs +index af4cc89252..e80b00e15a 100644 +--- a/crates/audio/src/rodio_ext.rs ++++ b/crates/audio/src/rodio_ext.rs +@@ -1,5 +1,4 @@ + use std::{ +- num::NonZero, + sync::{ + Arc, Mutex, + atomic::{AtomicBool, Ordering}, +@@ -8,22 +7,12 @@ use std::{ + }; + + use crossbeam::queue::ArrayQueue; +-use denoise::{Denoiser, DenoiserError}; +-use log::warn; +-use rodio::{ +- ChannelCount, Sample, SampleRate, Source, conversions::SampleRateConverter, nz, +- source::UniformSourceIterator, +-}; +- +-const MAX_CHANNELS: usize = 8; ++use rodio::{ChannelCount, Sample, SampleRate, Source}; + + #[derive(Debug, thiserror::Error)] + #[error("Replay duration is too short must be >= 100ms")] + pub struct ReplayDurationTooShort; + +-// These all require constant sources (so the span is infinitely long) +-// this is not guaranteed by rodio however we know it to be true in all our +-// applications. Rodio desperately needs a constant source concept. + pub trait RodioExt: Source + Sized { + fn process_buffer(self, callback: F) -> ProcessBuffer + where +@@ -36,14 +25,6 @@ pub trait RodioExt: Source + Sized { + duration: Duration, + ) -> Result<(Replay, Replayable), ReplayDurationTooShort>; + fn take_samples(self, n: usize) -> TakeSamples; +- fn denoise(self) -> Result, DenoiserError>; +- fn constant_params( +- self, +- channel_count: ChannelCount, +- sample_rate: SampleRate, +- ) -> UniformSourceIterator; +- fn constant_samplerate(self, sample_rate: SampleRate) -> ConstantSampleRate; +- fn possibly_disconnected_channels_to_mono(self) -> ToMono; + } + + impl RodioExt for S { +@@ -120,149 +101,8 @@ impl RodioExt for S { + left_to_take: n, + } + } +- fn denoise(self) -> Result, DenoiserError> { +- let res = Denoiser::try_new(self); +- res +- } +- fn constant_params( +- self, +- channel_count: ChannelCount, +- sample_rate: SampleRate, +- ) -> UniformSourceIterator { +- UniformSourceIterator::new(self, channel_count, sample_rate) +- } +- fn constant_samplerate(self, sample_rate: SampleRate) -> ConstantSampleRate { +- ConstantSampleRate::new(self, sample_rate) +- } +- fn possibly_disconnected_channels_to_mono(self) -> ToMono { +- ToMono::new(self) +- } +-} +- +-pub struct ConstantSampleRate { +- inner: SampleRateConverter, +- channels: ChannelCount, +- sample_rate: SampleRate, +-} +- +-impl ConstantSampleRate { +- fn new(source: S, target_rate: SampleRate) -> Self { +- let input_sample_rate = source.sample_rate(); +- let channels = source.channels(); +- let inner = SampleRateConverter::new(source, input_sample_rate, target_rate, channels); +- Self { +- inner, +- channels, +- sample_rate: target_rate, +- } +- } +-} +- +-impl Iterator for ConstantSampleRate { +- type Item = rodio::Sample; +- +- fn next(&mut self) -> Option { +- self.inner.next() +- } +- +- fn size_hint(&self) -> (usize, Option) { +- self.inner.size_hint() +- } +-} +- +-impl Source for ConstantSampleRate { +- fn current_span_len(&self) -> Option { +- None +- } +- +- fn channels(&self) -> ChannelCount { +- self.channels +- } +- +- fn sample_rate(&self) -> SampleRate { +- self.sample_rate +- } +- +- fn total_duration(&self) -> Option { +- None // not supported (not used by us) +- } +-} +- +-const TYPICAL_NOISE_FLOOR: Sample = 1e-3; +- +-/// constant source, only works on a single span +-pub struct ToMono { +- inner: S, +- input_channel_count: ChannelCount, +- connected_channels: ChannelCount, +- /// running mean of second channel 'volume' +- means: [f32; MAX_CHANNELS], +-} +-impl ToMono { +- fn new(input: S) -> Self { +- let channels = input +- .channels() +- .min(const { NonZero::::new(MAX_CHANNELS as u16).unwrap() }); +- if channels < input.channels() { +- warn!("Ignoring input channels {}..", channels.get()); +- } +- +- Self { +- connected_channels: channels, +- input_channel_count: channels, +- inner: input, +- means: [TYPICAL_NOISE_FLOOR; MAX_CHANNELS], +- } +- } +-} +- +-impl Source for ToMono { +- fn current_span_len(&self) -> Option { +- None +- } +- +- fn channels(&self) -> ChannelCount { +- rodio::nz!(1) +- } +- +- fn sample_rate(&self) -> SampleRate { +- self.inner.sample_rate() +- } +- +- fn total_duration(&self) -> Option { +- self.inner.total_duration() +- } +-} +- +-fn update_mean(mean: &mut f32, sample: Sample) { +- const HISTORY: f32 = 500.0; +- *mean *= (HISTORY - 1.0) / HISTORY; +- *mean += sample.abs() / HISTORY; +-} +- +-impl Iterator for ToMono { +- type Item = Sample; +- +- fn next(&mut self) -> Option { +- let mut mono_sample = 0f32; +- let mut active_channels = 0; +- for channel in 0..self.input_channel_count.get() as usize { +- let sample = self.inner.next()?; +- mono_sample += sample; +- +- update_mean(&mut self.means[channel], sample); +- if self.means[channel] > TYPICAL_NOISE_FLOOR / 10.0 { +- active_channels += 1; +- } +- } +- mono_sample /= self.connected_channels.get() as f32; +- self.connected_channels = NonZero::new(active_channels).unwrap_or(nz!(1)); +- +- Some(mono_sample) +- } + } + +-/// constant source, only works on a single span + pub struct TakeSamples { + inner: S, + left_to_take: usize, +@@ -307,7 +147,6 @@ impl Source for TakeSamples { + } + } + +-/// constant source, only works on a single span + #[derive(Debug)] + struct ReplayQueue { + inner: ArrayQueue>, +@@ -354,7 +193,6 @@ impl ReplayQueue { + } + } + +-/// constant source, only works on a single span + pub struct ProcessBuffer + where + S: Source + Sized, +@@ -422,7 +260,6 @@ where + } + } + +-/// constant source, only works on a single span + pub struct InspectBuffer + where + S: Source + Sized, +@@ -487,7 +324,6 @@ where + } + } + +-/// constant source, only works on a single span + #[derive(Debug)] + pub struct Replayable { + inner: S, +@@ -539,7 +375,6 @@ impl Source for Replayable { + } + } + +-/// constant source, only works on a single span + #[derive(Debug)] + pub struct Replay { + rx: Arc, +diff --git a/crates/auto_update/src/auto_update.rs b/crates/auto_update/src/auto_update.rs +index 31121aa6f6..6c46c145c1 100644 +--- a/crates/auto_update/src/auto_update.rs ++++ b/crates/auto_update/src/auto_update.rs +@@ -3,8 +3,7 @@ use client::{Client, TelemetrySettings}; + use db::RELEASE_CHANNEL; + use db::kvp::KEY_VALUE_STORE; + use gpui::{ +- App, AppContext as _, AsyncApp, BackgroundExecutor, Context, Entity, Global, SemanticVersion, +- Task, Window, actions, ++ App, AppContext as _, AsyncApp, Context, Entity, Global, SemanticVersion, Task, Window, actions, + }; + use http_client::{AsyncBody, HttpClient, HttpClientWithUrl}; + use paths::remote_servers_dir; +@@ -13,7 +12,6 @@ use serde::{Deserialize, Serialize}; + use settings::{Settings, SettingsStore}; + use smol::{fs, io::AsyncReadExt}; + use smol::{fs::File, process::Command}; +-use std::mem; + use std::{ + env::{ + self, +@@ -86,37 +84,31 @@ pub struct JsonRelease { + pub url: String, + } + +-struct MacOsUnmounter<'a> { ++struct MacOsUnmounter { + mount_path: PathBuf, +- background_executor: &'a BackgroundExecutor, + } + +-impl Drop for MacOsUnmounter<'_> { ++impl Drop for MacOsUnmounter { + fn drop(&mut self) { +- let mount_path = mem::take(&mut self.mount_path); +- self.background_executor +- .spawn(async move { +- let unmount_output = Command::new("hdiutil") +- .args(["detach", "-force"]) +- .arg(&mount_path) +- .output() +- .await; +- match unmount_output { +- Ok(output) if output.status.success() => { +- log::info!("Successfully unmounted the disk image"); +- } +- Ok(output) => { +- log::error!( +- "Failed to unmount disk image: {:?}", +- String::from_utf8_lossy(&output.stderr) +- ); +- } +- Err(error) => { +- log::error!("Error while trying to unmount disk image: {:?}", error); +- } +- } +- }) +- .detach(); ++ let unmount_output = std::process::Command::new("hdiutil") ++ .args(["detach", "-force"]) ++ .arg(&self.mount_path) ++ .output(); ++ ++ match unmount_output { ++ Ok(output) if output.status.success() => { ++ log::info!("Successfully unmounted the disk image"); ++ } ++ Ok(output) => { ++ log::error!( ++ "Failed to unmount disk image: {:?}", ++ String::from_utf8_lossy(&output.stderr) ++ ); ++ } ++ Err(error) => { ++ log::error!("Error while trying to unmount disk image: {:?}", error); ++ } ++ } + } + } + +@@ -904,7 +896,6 @@ async fn install_release_macos( + // Create an MacOsUnmounter that will be dropped (and thus unmount the disk) when this function exits + let _unmounter = MacOsUnmounter { + mount_path: mount_path.clone(), +- background_executor: cx.background_executor(), + }; + + let output = Command::new("rsync") +diff --git a/crates/client/src/telemetry.rs b/crates/client/src/telemetry.rs +index 35c8d0d7d0..5d43b4543c 100644 +--- a/crates/client/src/telemetry.rs ++++ b/crates/client/src/telemetry.rs +@@ -858,7 +858,7 @@ mod tests { + .enumerate() + .filter_map(|(i, path)| { + Some(( +- Arc::from(RelPath::unix(path).ok()?), ++ Arc::from(RelPath::new(path).ok()?), + ProjectEntryId::from_proto(i as u64 + 1), + PathChange::Added, + )) +diff --git a/crates/cloud_llm_client/Cargo.toml b/crates/cloud_llm_client/Cargo.toml +index 1ef978f0a7..700893dd40 100644 +--- a/crates/cloud_llm_client/Cargo.toml ++++ b/crates/cloud_llm_client/Cargo.toml +@@ -5,9 +5,6 @@ publish.workspace = true + edition.workspace = true + license = "Apache-2.0" + +-[features] +-test-support = [] +- + [lints] + workspace = true + +diff --git a/crates/cloud_llm_client/src/cloud_llm_client.rs b/crates/cloud_llm_client/src/cloud_llm_client.rs +index 4ae72ce0a4..e0cc42af76 100644 +--- a/crates/cloud_llm_client/src/cloud_llm_client.rs ++++ b/crates/cloud_llm_client/src/cloud_llm_client.rs +@@ -55,9 +55,6 @@ pub const CLIENT_SUPPORTS_STATUS_MESSAGES_HEADER_NAME: &str = + pub const SERVER_SUPPORTS_STATUS_MESSAGES_HEADER_NAME: &str = + "x-zed-server-supports-status-messages"; + +-/// The name of the header used by the client to indicate that it supports receiving xAI models. +-pub const CLIENT_SUPPORTS_X_AI_HEADER_NAME: &str = "x-zed-client-supports-x-ai"; +- + #[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)] + #[serde(rename_all = "snake_case")] + pub enum UsageLimit { +@@ -147,7 +144,6 @@ pub enum LanguageModelProvider { + Anthropic, + OpenAi, + Google, +- XAi, + } + + #[derive(Debug, Clone, Serialize, Deserialize)] +diff --git a/crates/cloud_llm_client/src/predict_edits_v3.rs b/crates/cloud_llm_client/src/predict_edits_v3.rs +index 03bd5359cd..9c5123fdb8 100644 +--- a/crates/cloud_llm_client/src/predict_edits_v3.rs ++++ b/crates/cloud_llm_client/src/predict_edits_v3.rs +@@ -5,7 +5,6 @@ use std::{ + path::{Path, PathBuf}, + sync::Arc, + }; +-use strum::EnumIter; + use uuid::Uuid; + + use crate::PredictEditsGitInfo; +@@ -43,33 +42,14 @@ pub struct PredictEditsRequest { + pub prompt_format: PromptFormat, + } + +-#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, EnumIter)] ++#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq)] + pub enum PromptFormat { + #[default] + MarkedExcerpt, + LabeledSections, +- /// Prompt format intended for use via zeta_cli +- OnlySnippets, +-} +- +-impl PromptFormat { +- pub fn iter() -> impl Iterator { +- ::iter() +- } +-} +- +-impl std::fmt::Display for PromptFormat { +- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +- match self { +- PromptFormat::MarkedExcerpt => write!(f, "Marked Excerpt"), +- PromptFormat::LabeledSections => write!(f, "Labeled Sections"), +- PromptFormat::OnlySnippets => write!(f, "Only Snippets"), +- } +- } + } + + #[derive(Debug, Clone, Serialize, Deserialize)] +-#[cfg_attr(any(test, feature = "test-support"), derive(PartialEq))] + #[serde(tag = "event")] + pub enum Event { + BufferChange { +diff --git a/crates/cloud_zeta2_prompt/src/cloud_zeta2_prompt.rs b/crates/cloud_zeta2_prompt/src/cloud_zeta2_prompt.rs +index 9c1b64013a..cc5c8cb8b2 100644 +--- a/crates/cloud_zeta2_prompt/src/cloud_zeta2_prompt.rs ++++ b/crates/cloud_zeta2_prompt/src/cloud_zeta2_prompt.rs +@@ -54,8 +54,6 @@ pub fn system_prompt(format: PromptFormat) -> &'static str { + match format { + PromptFormat::MarkedExcerpt => MARKED_EXCERPT_SYSTEM_PROMPT, + PromptFormat::LabeledSections => LABELED_SECTIONS_SYSTEM_PROMPT, +- // only intended for use via zeta_cli +- PromptFormat::OnlySnippets => "", + } + } + +@@ -345,7 +343,6 @@ impl<'a> PlannedPrompt<'a> { + self.request.excerpt_range.start + self.request.cursor_offset, + CURSOR_MARKER, + )], +- PromptFormat::OnlySnippets => vec![], + }; + + let mut prompt = String::new(); +@@ -435,13 +432,12 @@ impl<'a> PlannedPrompt<'a> { + } + + writeln!(output, "```{}", file_path.display()).ok(); +- let mut skipped_last_snippet = false; + for (snippet, range) in disjoint_snippets { + let section_index = section_ranges.len(); + + match self.request.prompt_format { +- PromptFormat::MarkedExcerpt | PromptFormat::OnlySnippets => { +- if range.start > 0 && !skipped_last_snippet { ++ PromptFormat::MarkedExcerpt => { ++ if range.start > 0 { + output.push_str("…\n"); + } + } +@@ -458,38 +454,25 @@ impl<'a> PlannedPrompt<'a> { + } + + if is_excerpt_file { +- if self.request.prompt_format == PromptFormat::OnlySnippets { +- if range.start >= self.request.excerpt_range.start +- && range.end <= self.request.excerpt_range.end +- { +- skipped_last_snippet = true; +- } else { +- skipped_last_snippet = false; +- output.push_str(snippet.text); ++ excerpt_index = Some(section_index); ++ let mut last_offset = range.start; ++ let mut i = 0; ++ while i < excerpt_file_insertions.len() { ++ let (offset, insertion) = &excerpt_file_insertions[i]; ++ let found = *offset >= range.start && *offset <= range.end; ++ if found { ++ output.push_str( ++ &snippet.text[last_offset - range.start..offset - range.start], ++ ); ++ output.push_str(insertion); ++ last_offset = *offset; ++ excerpt_file_insertions.remove(i); ++ continue; + } +- } else { +- let mut last_offset = range.start; +- let mut i = 0; +- while i < excerpt_file_insertions.len() { +- let (offset, insertion) = &excerpt_file_insertions[i]; +- let found = *offset >= range.start && *offset <= range.end; +- if found { +- excerpt_index = Some(section_index); +- output.push_str( +- &snippet.text[last_offset - range.start..offset - range.start], +- ); +- output.push_str(insertion); +- last_offset = *offset; +- excerpt_file_insertions.remove(i); +- continue; +- } +- i += 1; +- } +- skipped_last_snippet = false; +- output.push_str(&snippet.text[last_offset - range.start..]); ++ i += 1; + } ++ output.push_str(&snippet.text[last_offset - range.start..]); + } else { +- skipped_last_snippet = false; + output.push_str(snippet.text); + } + +@@ -500,11 +483,7 @@ impl<'a> PlannedPrompt<'a> { + } + + Ok(SectionLabels { +- // TODO: Clean this up +- excerpt_index: match self.request.prompt_format { +- PromptFormat::OnlySnippets => 0, +- _ => excerpt_index.context("bug: no snippet found for excerpt")?, +- }, ++ excerpt_index: excerpt_index.context("bug: no snippet found for excerpt")?, + section_ranges, + }) + } +diff --git a/crates/collab/src/db/ids.rs b/crates/collab/src/db/ids.rs +index 8f116cfd63..6a536b2b2a 100644 +--- a/crates/collab/src/db/ids.rs ++++ b/crates/collab/src/db/ids.rs +@@ -62,8 +62,8 @@ macro_rules! id_type { + } + + impl sea_orm::sea_query::Nullable for $name { +- fn null() -> Value { +- Value::Int(None) ++ fn null() -> sea_orm::sea_query::Value { ++ sea_orm::sea_query::Value::Int(None) + } + } + }; +diff --git a/crates/collab/src/tests/editor_tests.rs b/crates/collab/src/tests/editor_tests.rs +index 5ead2cd1d1..947af01224 100644 +--- a/crates/collab/src/tests/editor_tests.rs ++++ b/crates/collab/src/tests/editor_tests.rs +@@ -1408,12 +1408,12 @@ async fn test_share_project( + project_b.read_with(cx_b, |project, cx| { + let worktree = project.worktrees(cx).next().unwrap().read(cx); + assert_eq!( +- worktree.paths().collect::>(), ++ worktree.paths().map(AsRef::as_ref).collect::>(), + [ +- rel_path(".gitignore"), +- rel_path("a.txt"), +- rel_path("b.txt"), +- rel_path("ignored-dir"), ++ Path::new(".gitignore"), ++ Path::new("a.txt"), ++ Path::new("b.txt"), ++ Path::new("ignored-dir"), + ] + ); + }); +@@ -1433,14 +1433,14 @@ async fn test_share_project( + project_b.read_with(cx_b, |project, cx| { + let worktree = project.worktrees(cx).next().unwrap().read(cx); + assert_eq!( +- worktree.paths().collect::>(), ++ worktree.paths().map(AsRef::as_ref).collect::>(), + [ +- rel_path(".gitignore"), +- rel_path("a.txt"), +- rel_path("b.txt"), +- rel_path("ignored-dir"), +- rel_path("ignored-dir/c.txt"), +- rel_path("ignored-dir/d.txt"), ++ Path::new(".gitignore"), ++ Path::new("a.txt"), ++ Path::new("b.txt"), ++ Path::new("ignored-dir"), ++ Path::new("ignored-dir/c.txt"), ++ Path::new("ignored-dir/d.txt"), + ] + ); + }); +diff --git a/crates/collab/src/tests/following_tests.rs b/crates/collab/src/tests/following_tests.rs +index 6f4a819f44..1bf0a28e34 100644 +--- a/crates/collab/src/tests/following_tests.rs ++++ b/crates/collab/src/tests/following_tests.rs +@@ -632,16 +632,13 @@ async fn test_following_tab_order( + let pane_paths = |pane: &Entity, cx: &mut VisualTestContext| { + pane.update(cx, |pane, cx| { + pane.items() +- .map(|item| item.project_path(cx).unwrap().path) ++ .map(|item| item.project_path(cx).unwrap().path.as_str().to_owned()) + .collect::>() + }) + }; + + //Verify that the tabs opened in the order we expect +- assert_eq!( +- &pane_paths(&pane_a, cx_a), +- &[rel_path("1.txt").into(), rel_path("3.txt").into()] +- ); ++ assert_eq!(&pane_paths(&pane_a, cx_a), &["1.txt", "3.txt"]); + + //Follow client B as client A + workspace_a.update_in(cx_a, |workspace, window, cx| { +@@ -659,14 +656,7 @@ async fn test_following_tab_order( + executor.run_until_parked(); + + // Verify that newly opened followed file is at the end +- assert_eq!( +- &pane_paths(&pane_a, cx_a), +- &[ +- rel_path("1.txt").into(), +- rel_path("3.txt").into(), +- rel_path("2.txt").into() +- ] +- ); ++ assert_eq!(&pane_paths(&pane_a, cx_a), &["1.txt", "3.txt", "2.txt"]); + + //Open just 1 on client B + workspace_b +@@ -675,21 +665,11 @@ async fn test_following_tab_order( + }) + .await + .unwrap(); +- assert_eq!( +- &pane_paths(&pane_b, cx_b), +- &[rel_path("2.txt").into(), rel_path("1.txt").into()] +- ); ++ assert_eq!(&pane_paths(&pane_b, cx_b), &["2.txt", "1.txt"]); + executor.run_until_parked(); + + // Verify that following into 1 did not reorder +- assert_eq!( +- &pane_paths(&pane_a, cx_a), +- &[ +- rel_path("1.txt").into(), +- rel_path("3.txt").into(), +- rel_path("2.txt").into() +- ] +- ); ++ assert_eq!(&pane_paths(&pane_a, cx_a), &["1.txt", "3.txt", "2.txt"]); + } + + #[gpui::test(iterations = 10)] +diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs +index 98acecb108..93c3665c11 100644 +--- a/crates/collab/src/tests/integration_tests.rs ++++ b/crates/collab/src/tests/integration_tests.rs +@@ -1699,8 +1699,13 @@ async fn test_project_reconnect( + ); + assert!(worktree_a3.read(cx).has_update_observer()); + assert_eq!( +- worktree_a3.read(cx).snapshot().paths().collect::>(), +- vec![rel_path("w.txt"), rel_path("x.txt"), rel_path("y.txt")] ++ worktree_a3 ++ .read(cx) ++ .snapshot() ++ .paths() ++ .map(|p| p.as_str()) ++ .collect::>(), ++ vec!["w.txt", "x.txt", "y.txt"] + ); + }); + +@@ -1732,8 +1737,9 @@ async fn test_project_reconnect( + .read(cx) + .snapshot() + .paths() ++ .map(|p| p.as_str()) + .collect::>(), +- vec![rel_path("w.txt"), rel_path("x.txt"), rel_path("y.txt")] ++ vec!["w.txt", "x.txt", "y.txt"] + ); + }); + +@@ -1827,7 +1833,7 @@ async fn test_project_reconnect( + .read(cx) + .snapshot() + .paths() +- .map(|p| p.as_unix_str()) ++ .map(|p| p.as_str()) + .collect::>(), + vec!["z.txt"] + ); +@@ -2465,39 +2471,39 @@ async fn test_propagate_saves_and_fs_changes( + + worktree_a.read_with(cx_a, |tree, _| { + assert_eq!( +- tree.paths().collect::>(), +- [rel_path("file1.js"), rel_path("file3"), rel_path("file4")] ++ tree.paths().map(|p| p.as_str()).collect::>(), ++ ["file1.js", "file3", "file4"] + ) + }); + + worktree_b.read_with(cx_b, |tree, _| { + assert_eq!( +- tree.paths().collect::>(), +- [rel_path("file1.js"), rel_path("file3"), rel_path("file4")] ++ tree.paths().map(|p| p.as_str()).collect::>(), ++ ["file1.js", "file3", "file4"] + ) + }); + + worktree_c.read_with(cx_c, |tree, _| { + assert_eq!( +- tree.paths().collect::>(), +- [rel_path("file1.js"), rel_path("file3"), rel_path("file4")] ++ tree.paths().map(|p| p.as_str()).collect::>(), ++ ["file1.js", "file3", "file4"] + ) + }); + + // Ensure buffer files are updated as well. + + buffer_a.read_with(cx_a, |buffer, _| { +- assert_eq!(buffer.file().unwrap().path().as_ref(), rel_path("file1.js")); ++ assert_eq!(buffer.file().unwrap().path().as_str(), "file1.js"); + assert_eq!(buffer.language().unwrap().name(), "JavaScript".into()); + }); + + buffer_b.read_with(cx_b, |buffer, _| { +- assert_eq!(buffer.file().unwrap().path().as_ref(), rel_path("file1.js")); ++ assert_eq!(buffer.file().unwrap().path().as_str(), "file1.js"); + assert_eq!(buffer.language().unwrap().name(), "JavaScript".into()); + }); + + buffer_c.read_with(cx_c, |buffer, _| { +- assert_eq!(buffer.file().unwrap().path().as_ref(), rel_path("file1.js")); ++ assert_eq!(buffer.file().unwrap().path().as_str(), "file1.js"); + assert_eq!(buffer.language().unwrap().name(), "JavaScript".into()); + }); + +@@ -3211,15 +3217,15 @@ async fn test_fs_operations( + + worktree_a.read_with(cx_a, |worktree, _| { + assert_eq!( +- worktree.paths().collect::>(), +- [rel_path("a.txt"), rel_path("b.txt"), rel_path("c.txt")] ++ worktree.paths().map(|p| p.as_str()).collect::>(), ++ ["a.txt", "b.txt", "c.txt"] + ); + }); + + worktree_b.read_with(cx_b, |worktree, _| { + assert_eq!( +- worktree.paths().collect::>(), +- [rel_path("a.txt"), rel_path("b.txt"), rel_path("c.txt")] ++ worktree.paths().map(|p| p.as_str()).collect::>(), ++ ["a.txt", "b.txt", "c.txt"] + ); + }); + +@@ -3234,17 +3240,14 @@ async fn test_fs_operations( + + worktree_a.read_with(cx_a, |worktree, _| { + assert_eq!( +- worktree.paths().collect::>(), +- [rel_path("a.txt"), rel_path("b.txt"), rel_path("d.txt")] ++ worktree.paths().map(|p| p.as_str()).collect::>(), ++ ["a.txt", "b.txt", "d.txt"] + ); + }); + + worktree_b.read_with(cx_b, |worktree, _| { + assert_eq!( +- worktree +- .paths() +- .map(|p| p.as_unix_str()) +- .collect::>(), ++ worktree.paths().map(|p| p.as_str()).collect::>(), + ["a.txt", "b.txt", "d.txt"] + ); + }); +@@ -3260,20 +3263,14 @@ async fn test_fs_operations( + + worktree_a.read_with(cx_a, |worktree, _| { + assert_eq!( +- worktree +- .paths() +- .map(|p| p.as_unix_str()) +- .collect::>(), ++ worktree.paths().map(|p| p.as_str()).collect::>(), + ["DIR", "a.txt", "b.txt", "d.txt"] + ); + }); + + worktree_b.read_with(cx_b, |worktree, _| { + assert_eq!( +- worktree +- .paths() +- .map(|p| p.as_unix_str()) +- .collect::>(), ++ worktree.paths().map(|p| p.as_str()).collect::>(), + ["DIR", "a.txt", "b.txt", "d.txt"] + ); + }); +@@ -3389,20 +3386,14 @@ async fn test_fs_operations( + + worktree_a.read_with(cx_a, |worktree, _| { + assert_eq!( +- worktree +- .paths() +- .map(|p| p.as_unix_str()) +- .collect::>(), ++ worktree.paths().map(|p| p.as_str()).collect::>(), + ["a.txt", "b.txt", "d.txt", "f.txt"] + ); + }); + + worktree_b.read_with(cx_b, |worktree, _| { + assert_eq!( +- worktree +- .paths() +- .map(|p| p.as_unix_str()) +- .collect::>(), ++ worktree.paths().map(|p| p.as_str()).collect::>(), + ["a.txt", "b.txt", "d.txt", "f.txt"] + ); + }); +@@ -3416,20 +3407,14 @@ async fn test_fs_operations( + + worktree_a.read_with(cx_a, |worktree, _| { + assert_eq!( +- worktree +- .paths() +- .map(|p| p.as_unix_str()) +- .collect::>(), ++ worktree.paths().map(|p| p.as_str()).collect::>(), + ["a.txt", "b.txt", "f.txt"] + ); + }); + + worktree_b.read_with(cx_b, |worktree, _| { + assert_eq!( +- worktree +- .paths() +- .map(|p| p.as_unix_str()) +- .collect::>(), ++ worktree.paths().map(|p| p.as_str()).collect::>(), + ["a.txt", "b.txt", "f.txt"] + ); + }); +diff --git a/crates/collab/src/tests/random_project_collaboration_tests.rs b/crates/collab/src/tests/random_project_collaboration_tests.rs +index 7e9b84c057..0cc4a4eade 100644 +--- a/crates/collab/src/tests/random_project_collaboration_tests.rs ++++ b/crates/collab/src/tests/random_project_collaboration_tests.rs +@@ -973,7 +973,7 @@ impl RandomizedTest for ProjectCollaborationTest { + let dot_git_dir = repo_path.join(".git"); + let contents = contents + .iter() +- .map(|(path, contents)| (path.as_unix_str(), contents.clone())) ++ .map(|(path, contents)| (path.as_str(), contents.clone())) + .collect::>(); + if client.fs().metadata(&dot_git_dir).await?.is_none() { + client.fs().create_dir(&dot_git_dir).await?; +@@ -1031,7 +1031,7 @@ impl RandomizedTest for ProjectCollaborationTest { + + let statuses = statuses + .iter() +- .map(|(path, val)| (path.as_unix_str(), *val)) ++ .map(|(path, val)| (path.as_str(), *val)) + .collect::>(); + + if client.fs().metadata(&dot_git_dir).await?.is_none() { +@@ -1463,7 +1463,7 @@ fn generate_git_operation(rng: &mut StdRng, client: &TestClient) -> GitOperation + paths + .iter() + .map(|path| { +- RelPath::new(path.strip_prefix(repo_path).unwrap(), PathStyle::local()) ++ RelPath::from_std_path(path.strip_prefix(repo_path).unwrap(), PathStyle::local()) + .unwrap() + .to_rel_path_buf() + }) +diff --git a/crates/dap_adapters/src/python.rs b/crates/dap_adapters/src/python.rs +index 5a6bd729ce..468edf5664 100644 +--- a/crates/dap_adapters/src/python.rs ++++ b/crates/dap_adapters/src/python.rs +@@ -726,7 +726,7 @@ impl DebugAdapter for PythonDebugAdapter { + .config + .get("cwd") + .and_then(|cwd| { +- RelPath::new( ++ RelPath::from_std_path( + cwd.as_str() + .map(Path::new)? + .strip_prefix(delegate.worktree_root_path()) +@@ -740,7 +740,7 @@ impl DebugAdapter for PythonDebugAdapter { + .toolchain_store() + .active_toolchain( + delegate.worktree_id(), +- base_path.into_arc(), ++ base_path, + language::LanguageName::new(Self::LANGUAGE_NAME), + cx, + ) +diff --git a/crates/debugger_ui/src/debugger_panel.rs b/crates/debugger_ui/src/debugger_panel.rs +index 9154047aa5..57f17e577e 100644 +--- a/crates/debugger_ui/src/debugger_panel.rs ++++ b/crates/debugger_ui/src/debugger_panel.rs +@@ -1062,10 +1062,10 @@ impl DebugPanel { + directory_in_worktree: dir, + .. + } => { +- let relative_path = if dir.ends_with(RelPath::unix(".vscode").unwrap()) { +- dir.join(RelPath::unix("launch.json").unwrap()) ++ let relative_path = if dir.ends_with(RelPath::new(".vscode").unwrap()) { ++ dir.join(RelPath::new("launch.json").unwrap()) + } else { +- dir.join(RelPath::unix("debug.json").unwrap()) ++ dir.join(RelPath::new("debug.json").unwrap()) + }; + ProjectPath { + worktree_id: id, +@@ -1136,7 +1136,7 @@ impl DebugPanel { + } + path.pop(); + +- path.push(paths::local_debug_file_relative_path().as_std_path()); ++ path.push(paths::local_debug_file_relative_path()); + let path = path.as_path(); + + if !fs.is_file(path).await { +diff --git a/crates/debugger_ui/src/new_process_modal.rs b/crates/debugger_ui/src/new_process_modal.rs +index cb8edb88b5..2ee8d13732 100644 +--- a/crates/debugger_ui/src/new_process_modal.rs ++++ b/crates/debugger_ui/src/new_process_modal.rs +@@ -1037,10 +1037,10 @@ impl DebugDelegate { + + match path.components().next_back() { + Some(".zed") => { +- path.push(RelPath::unix("debug.json").unwrap()); ++ path.push(RelPath::new("debug.json").unwrap()); + } + Some(".vscode") => { +- path.push(RelPath::unix("launch.json").unwrap()); ++ path.push(RelPath::new("launch.json").unwrap()); + } + _ => {} + } +@@ -1133,7 +1133,7 @@ impl DebugDelegate { + id: _, + directory_in_worktree: dir, + id_base: _, +- } => dir.ends_with(RelPath::unix(".zed").unwrap()), ++ } => dir.ends_with(RelPath::new(".zed").unwrap()), + _ => false, + }); + +@@ -1154,7 +1154,7 @@ impl DebugDelegate { + id_base: _, + } => { + !(hide_vscode +- && dir.ends_with(RelPath::unix(".vscode").unwrap())) ++ && dir.ends_with(RelPath::new(".vscode").unwrap())) + } + _ => true, + }) +diff --git a/crates/debugger_ui/src/session/running/breakpoint_list.rs b/crates/debugger_ui/src/session/running/breakpoint_list.rs +index cec906e293..f0f86b124a 100644 +--- a/crates/debugger_ui/src/session/running/breakpoint_list.rs ++++ b/crates/debugger_ui/src/session/running/breakpoint_list.rs +@@ -682,11 +682,10 @@ impl Render for BreakpointList { + breakpoints.into_iter().filter_map(move |breakpoint| { + debug_assert_eq!(&path, &breakpoint.path); + let file_name = breakpoint.path.file_name()?; +- let breakpoint_path = RelPath::new(&breakpoint.path, path_style).ok(); + + let dir = relative_worktree_path +- .as_deref() +- .or(breakpoint_path.as_deref())? ++ .clone() ++ .or_else(|| RelPath::from_std_path(&breakpoint.path, path_style).ok())? + .parent() + .map(|parent| SharedString::from(parent.display(path_style).to_string())); + let name = file_name +diff --git a/crates/denoise/src/engine.rs b/crates/denoise/src/engine.rs +index be0548c689..5196b70b5b 100644 +--- a/crates/denoise/src/engine.rs ++++ b/crates/denoise/src/engine.rs +@@ -138,13 +138,13 @@ impl Engine { + + const SPECTRUM_INPUT: &str = "input_2"; + const MEMORY_INPUT: &str = "input_3"; +- let spectrum = ++ let memory_input = + Tensor::from_slice::<_, f32>(&self.in_magnitude, (1, 1, FFT_OUT_SIZE), &Device::Cpu) + .expect("the in magnitude has enough elements to fill the Tensor"); + + let inputs = HashMap::from([ +- (SPECTRUM_INPUT.to_string(), spectrum), +- (MEMORY_INPUT.to_string(), self.spectral_memory.clone()), ++ (MEMORY_INPUT.to_string(), memory_input), ++ (SPECTRUM_INPUT.to_string(), self.spectral_memory.clone()), + ]); + inputs + } +diff --git a/crates/denoise/src/lib.rs b/crates/denoise/src/lib.rs +index f6cbf0fadf..1422c81a4b 100644 +--- a/crates/denoise/src/lib.rs ++++ b/crates/denoise/src/lib.rs +@@ -84,7 +84,7 @@ impl Denoiser { + .spawn(move || { + run_neural_denoiser(denoised_tx, input_rx); + }) +- .expect("Should be ablet to spawn threads"); ++ .unwrap(); + + Ok(Self { + inner: source, +diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs +index b9fe990dca..01655dd12e 100644 +--- a/crates/editor/src/editor.rs ++++ b/crates/editor/src/editor.rs +@@ -592,22 +592,11 @@ pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle { + .inlay_hints + .show_background; + +- let mut style = cx.theme().syntax().get("hint"); +- +- if style.color.is_none() { +- style.color = Some(cx.theme().status().hint); +- } +- +- if !show_background { +- style.background_color = None; +- return style; ++ HighlightStyle { ++ color: Some(cx.theme().status().hint), ++ background_color: show_background.then(|| cx.theme().status().hint_background), ++ ..HighlightStyle::default() + } +- +- if style.background_color.is_none() { +- style.background_color = Some(cx.theme().status().hint_background); +- } +- +- style + } + + pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles { +@@ -3069,7 +3058,7 @@ impl Editor { + self.buffer.update(cx, |buffer, cx| { + buffer.set_active_selections( + &selection_anchors, +- self.selections.line_mode(), ++ self.selections.line_mode, + self.cursor_shape, + cx, + ) +@@ -6911,7 +6900,7 @@ impl Editor { + if !EditorSettings::get_global(cx).selection_highlight { + return None; + } +- if self.selections.count() != 1 || self.selections.line_mode() { ++ if self.selections.count() != 1 || self.selections.line_mode { + return None; + } + let selection = self.selections.newest::(cx); +@@ -12280,7 +12269,7 @@ impl Editor { + let mut is_first = true; + for selection in &mut selections { + let is_entire_line = +- (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode(); ++ (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode; + if is_entire_line { + selection.start = Point::new(selection.start.row, 0); + if !selection.is_empty() && selection.end.column == 0 { +@@ -12380,7 +12369,7 @@ impl Editor { + for selection in &selections { + let mut start = selection.start; + let mut end = selection.end; +- let is_entire_line = selection.is_empty() || self.selections.line_mode(); ++ let is_entire_line = selection.is_empty() || self.selections.line_mode; + if is_entire_line { + start = Point::new(start.row, 0); + end = cmp::min(max_point, Point::new(end.row + 1, 0)); +@@ -21368,7 +21357,7 @@ impl Editor { + if self.leader_id.is_none() { + buffer.set_active_selections( + &self.selections.disjoint_anchors_arc(), +- self.selections.line_mode(), ++ self.selections.line_mode, + self.cursor_shape, + cx, + ); +diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs +index b85998c6b8..7a1a6f4983 100644 +--- a/crates/editor/src/editor_tests.rs ++++ b/crates/editor/src/editor_tests.rs +@@ -5370,8 +5370,8 @@ async fn test_manipulate_text(cx: &mut TestAppContext) { + «HeLlO, wOrLD!ˇ» + "}); + +- // Test selections with `line_mode() = true`. +- cx.update_editor(|editor, _window, _cx| editor.selections.set_line_mode(true)); ++ // Test selections with `line_mode = true`. ++ cx.update_editor(|editor, _window, _cx| editor.selections.line_mode = true); + cx.set_state(indoc! {" + «The quick brown + fox jumps over +@@ -20905,10 +20905,7 @@ async fn test_display_diff_hunks(cx: &mut TestAppContext) { + for buffer in &buffers { + let snapshot = buffer.read(cx).snapshot(); + multibuffer.set_excerpts_for_path( +- PathKey::namespaced( +- 0, +- buffer.read(cx).file().unwrap().path().as_unix_str().into(), +- ), ++ PathKey::namespaced(0, buffer.read(cx).file().unwrap().path().as_str().into()), + buffer.clone(), + vec![text::Anchor::MIN.to_point(&snapshot)..text::Anchor::MAX.to_point(&snapshot)], + 2, +diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs +index 73ee2ae01e..90dd2a599a 100644 +--- a/crates/editor/src/element.rs ++++ b/crates/editor/src/element.rs +@@ -1371,7 +1371,7 @@ impl EditorElement { + + let layout = SelectionLayout::new( + selection, +- editor.selections.line_mode(), ++ editor.selections.line_mode, + editor.cursor_shape, + &snapshot.display_snapshot, + is_newest, +@@ -3149,7 +3149,7 @@ impl EditorElement { + let newest = editor.selections.newest::(cx); + SelectionLayout::new( + newest, +- editor.selections.line_mode(), ++ editor.selections.line_mode, + editor.cursor_shape, + &snapshot.display_snapshot, + true, +@@ -3782,17 +3782,13 @@ impl EditorElement { + let file = for_excerpt.buffer.file(); + let can_open_excerpts = Editor::can_open_excerpts_in_file(file); + let path_style = file.map(|file| file.path_style(cx)); +- let relative_path = for_excerpt.buffer.resolve_file_path(include_root, cx); +- let (parent_path, filename) = if let Some(path) = &relative_path { +- if let Some(path_style) = path_style { +- let (dir, file_name) = path_style.split(path); +- (dir.map(|dir| dir.to_owned()), Some(file_name.to_owned())) +- } else { +- (None, Some(path.clone())) +- } +- } else { +- (None, None) +- }; ++ let relative_path = for_excerpt.buffer.resolve_file_path(cx, include_root); ++ let filename = relative_path ++ .as_ref() ++ .and_then(|path| Some(path.file_name()?.to_string_lossy().to_string())); ++ let parent_path = relative_path.as_ref().and_then(|path| { ++ Some(path.parent()?.to_string_lossy().to_string() + path_style?.separator()) ++ }); + let focus_handle = editor.focus_handle(cx); + let colors = cx.theme().colors(); + +diff --git a/crates/editor/src/hover_links.rs b/crates/editor/src/hover_links.rs +index c2a0108915..8177a4dca1 100644 +--- a/crates/editor/src/hover_links.rs ++++ b/crates/editor/src/hover_links.rs +@@ -666,7 +666,9 @@ pub(crate) fn find_url( + ) -> Option<(Range, String)> { + const LIMIT: usize = 2048; + +- let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot()).ok()?; ++ let Ok(snapshot) = buffer.read_with(&cx, |buffer, _| buffer.snapshot()) else { ++ return None; ++ }; + + let offset = position.to_offset(&snapshot); + let mut token_start = offset; +diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs +index e8ce3b81f3..3e592e4bdc 100644 +--- a/crates/editor/src/items.rs ++++ b/crates/editor/src/items.rs +@@ -190,7 +190,7 @@ impl FollowableItem for Editor { + self.buffer.update(cx, |buffer, cx| { + buffer.set_active_selections( + &self.selections.disjoint_anchors_arc(), +- self.selections.line_mode(), ++ self.selections.line_mode, + self.cursor_shape, + cx, + ); +@@ -963,12 +963,13 @@ impl Item for Editor { + buffer + .snapshot() + .resolve_file_path( ++ cx, + self.project + .as_ref() + .map(|project| project.read(cx).visible_worktrees(cx).count() > 1) + .unwrap_or_default(), +- cx, + ) ++ .map(|path| path.to_string_lossy().to_string()) + .unwrap_or_else(|| { + if multibuffer.is_singleton() { + multibuffer.title(cx).to_string() +diff --git a/crates/editor/src/selections_collection.rs b/crates/editor/src/selections_collection.rs +index 7fb44ab4b4..4343443ff8 100644 +--- a/crates/editor/src/selections_collection.rs ++++ b/crates/editor/src/selections_collection.rs +@@ -1,6 +1,6 @@ + use std::{ + cell::Ref, +- cmp, fmt, iter, mem, ++ cmp, iter, mem, + ops::{Deref, DerefMut, Range, Sub}, + sync::Arc, + }; +@@ -29,7 +29,7 @@ pub struct SelectionsCollection { + display_map: Entity, + buffer: Entity, + next_selection_id: usize, +- line_mode: bool, ++ pub line_mode: bool, + /// The non-pending, non-overlapping selections. + /// The [SelectionsCollection::pending] selection could possibly overlap these + disjoint: Arc<[Selection]>, +@@ -424,14 +424,6 @@ impl SelectionsCollection { + pub fn next_selection_id(&self) -> usize { + self.next_selection_id + } +- +- pub fn line_mode(&self) -> bool { +- self.line_mode +- } +- +- pub fn set_line_mode(&mut self, line_mode: bool) { +- self.line_mode = line_mode; +- } + } + + pub struct MutableSelectionsCollection<'a> { +@@ -922,10 +914,10 @@ fn selection_to_anchor_selection( + where + T: ToOffset + Ord, + { +- let end_bias = if selection.start == selection.end { +- Bias::Right +- } else { ++ let end_bias = if selection.end > selection.start { + Bias::Left ++ } else { ++ Bias::Right + }; + Selection { + id: selection.id, +@@ -936,59 +928,49 @@ where + } + } + +-fn resolve_selections_point<'a>( ++// Panics if passed selections are not in order ++fn resolve_selections_display<'a>( + selections: impl 'a + IntoIterator>, + map: &'a DisplaySnapshot, +-) -> impl 'a + Iterator> { ++) -> impl 'a + Iterator> { + let (to_summarize, selections) = selections.into_iter().tee(); + let mut summaries = map + .buffer_snapshot + .summaries_for_anchors::(to_summarize.flat_map(|s| [&s.start, &s.end])) + .into_iter(); +- selections.map(move |s| { +- let start = summaries.next().unwrap(); +- let end = summaries.next().unwrap(); +- assert!(start <= end, "start: {:?}, end: {:?}", start, end); +- Selection { +- id: s.id, +- start, +- end, +- reversed: s.reversed, +- goal: s.goal, +- } +- }) +-} ++ let mut selections = selections ++ .map(move |s| { ++ let start = summaries.next().unwrap(); ++ let end = summaries.next().unwrap(); ++ ++ let display_start = map.point_to_display_point(start, Bias::Left); ++ let display_end = if start == end { ++ map.point_to_display_point(end, Bias::Right) ++ } else { ++ map.point_to_display_point(end, Bias::Left) ++ }; + +-// Panics if passed selections are not in order +-fn resolve_selections_display<'a>( +- selections: impl 'a + IntoIterator>, +- map: &'a DisplaySnapshot, +-) -> impl 'a + Iterator> { +- let selections = resolve_selections_point(selections, map).map(move |s| { +- let display_start = map.point_to_display_point(s.start, Bias::Left); +- let display_end = map.point_to_display_point( +- s.end, +- if s.start == s.end { +- Bias::Right ++ Selection { ++ id: s.id, ++ start: display_start, ++ end: display_end, ++ reversed: s.reversed, ++ goal: s.goal, ++ } ++ }) ++ .peekable(); ++ iter::from_fn(move || { ++ let mut selection = selections.next()?; ++ while let Some(next_selection) = selections.peek() { ++ if selection.end >= next_selection.start { ++ selection.end = cmp::max(selection.end, next_selection.end); ++ selections.next(); + } else { +- Bias::Left +- }, +- ); +- assert!( +- display_start <= display_end, +- "display_start: {:?}, display_end: {:?}", +- display_start, +- display_end +- ); +- Selection { +- id: s.id, +- start: display_start, +- end: display_end, +- reversed: s.reversed, +- goal: s.goal, ++ break; ++ } + } +- }); +- coalesce_selections(selections) ++ Some(selection) ++ }) + } + + // Panics if passed selections are not in order +@@ -1006,13 +988,11 @@ where + .dimensions_from_points::(to_convert.flat_map(|s| { + let start = map.display_point_to_point(s.start, Bias::Left); + let end = map.display_point_to_point(s.end, Bias::Right); +- assert!(start <= end, "start: {:?}, end: {:?}", start, end); + [start, end] + })); + selections.map(move |s| { + let start = converted_endpoints.next().unwrap(); + let end = converted_endpoints.next().unwrap(); +- assert!(start <= end, "start: {:?}, end: {:?}", start, end); + Selection { + id: s.id, + start, +@@ -1022,33 +1002,3 @@ where + } + }) + } +- +-fn coalesce_selections( +- selections: impl Iterator>, +-) -> impl Iterator> { +- let mut selections = selections.peekable(); +- iter::from_fn(move || { +- let mut selection = selections.next()?; +- while let Some(next_selection) = selections.peek() { +- if selection.end >= next_selection.start { +- if selection.reversed == next_selection.reversed { +- selection.end = cmp::max(selection.end, next_selection.end); +- selections.next(); +- } else { +- selection.end = cmp::max(selection.start, next_selection.start); +- break; +- } +- } else { +- break; +- } +- } +- assert!( +- selection.start <= selection.end, +- "selection.start: {:?}, selection.end: {:?}, selection.reversed: {:?}", +- selection.start, +- selection.end, +- selection.reversed +- ); +- Some(selection) +- }) +-} +diff --git a/crates/editor/src/test/editor_test_context.rs b/crates/editor/src/test/editor_test_context.rs +index 8cf1608374..06fd01c85f 100644 +--- a/crates/editor/src/test/editor_test_context.rs ++++ b/crates/editor/src/test/editor_test_context.rs +@@ -296,7 +296,7 @@ impl EditorTestContext { + let path = self.update_buffer(|buffer, _| buffer.file().unwrap().path().clone()); + fs.set_head_for_repo( + &Self::root_path().join(".git"), +- &[(path.as_unix_str(), diff_base.to_string())], ++ &[(path.as_str(), diff_base.to_string())], + "deadbeef", + ); + self.cx.run_until_parked(); +@@ -317,7 +317,7 @@ impl EditorTestContext { + let path = self.update_buffer(|buffer, _| buffer.file().unwrap().path().clone()); + fs.set_index_for_repo( + &Self::root_path().join(".git"), +- &[(path.as_unix_str(), diff_base.to_string())], ++ &[(path.as_str(), diff_base.to_string())], + ); + self.cx.run_until_parked(); + } +diff --git a/crates/eval/src/examples/add_arg_to_trait_method.rs b/crates/eval/src/examples/add_arg_to_trait_method.rs +index 41fa7c3dc6..0626be5a4e 100644 +--- a/crates/eval/src/examples/add_arg_to_trait_method.rs ++++ b/crates/eval/src/examples/add_arg_to_trait_method.rs +@@ -67,7 +67,7 @@ impl Example for AddArgToTraitMethod { + + for tool_name in add_ignored_window_paths { + let path_str = format!("crates/assistant_tools/src/{}.rs", tool_name); +- let edits = edits.get(RelPath::unix(&path_str).unwrap()); ++ let edits = edits.get(RelPath::new(&path_str).unwrap()); + + let ignored = edits.is_some_and(|edits| { + edits.has_added_line(" _window: Option,\n") +@@ -86,7 +86,7 @@ impl Example for AddArgToTraitMethod { + // Adds unignored argument to `batch_tool` + + let batch_tool_edits = +- edits.get(RelPath::unix("crates/assistant_tools/src/batch_tool.rs").unwrap()); ++ edits.get(RelPath::new("crates/assistant_tools/src/batch_tool.rs").unwrap()); + + cx.assert( + batch_tool_edits.is_some_and(|edits| { +diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs +index 73207b3036..16e695f04f 100644 +--- a/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs ++++ b/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs +@@ -425,7 +425,7 @@ impl ExtensionImports for WasmState { + let location = location.as_ref().and_then(|location| { + Some(::settings::SettingsLocation { + worktree_id: WorktreeId::from_proto(location.worktree_id), +- path: RelPath::unix(&location.path).ok()?, ++ path: RelPath::new(&location.path).ok()?, + }) + }); + +diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_6_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_6_0.rs +index 861f73f4a4..9e608b9e8e 100644 +--- a/crates/extension_host/src/wasm_host/wit/since_v0_6_0.rs ++++ b/crates/extension_host/src/wasm_host/wit/since_v0_6_0.rs +@@ -564,7 +564,7 @@ impl HostWorktree for WasmState { + ) -> wasmtime::Result> { + let delegate = self.table.get(&delegate)?; + Ok(delegate +- .read_text_file(RelPath::unix(&path)?) ++ .read_text_file(RelPath::new(&path)?) + .await + .map_err(|error| error.to_string())) + } +@@ -917,7 +917,7 @@ impl ExtensionImports for WasmState { + let location = location.as_ref().and_then(|location| { + Some(::settings::SettingsLocation { + worktree_id: WorktreeId::from_proto(location.worktree_id), +- path: RelPath::unix(&location.path).ok()?, ++ path: RelPath::new(&location.path).ok()?, + }) + }); + +diff --git a/crates/feature_flags/src/flags.rs b/crates/feature_flags/src/flags.rs +index 47b6f1230a..bacb22bd8d 100644 +--- a/crates/feature_flags/src/flags.rs ++++ b/crates/feature_flags/src/flags.rs +@@ -6,6 +6,16 @@ impl FeatureFlag for PredictEditsRateCompletionsFeatureFlag { + const NAME: &'static str = "predict-edits-rate-completions"; + } + ++pub struct BillingV2FeatureFlag {} ++ ++impl FeatureFlag for BillingV2FeatureFlag { ++ const NAME: &'static str = "billing-v2"; ++ ++ fn enabled_for_all() -> bool { ++ true ++ } ++} ++ + pub struct NotebookFeatureFlag; + + impl FeatureFlag for NotebookFeatureFlag { +diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs +index 08c54dabc2..4126d37a3f 100644 +--- a/crates/file_finder/src/file_finder.rs ++++ b/crates/file_finder/src/file_finder.rs +@@ -666,7 +666,7 @@ impl Matches { + } + + if let Some(filename) = panel_match.0.path.file_name() { +- let path_str = panel_match.0.path.as_unix_str(); ++ let path_str = panel_match.0.path.as_str(); + + if let Some(filename_pos) = path_str.rfind(filename) + && panel_match.0.positions[0] >= filename_pos +@@ -940,7 +940,7 @@ impl FileFinderDelegate { + + let path_style = self.project.read(cx).path_style(cx); + let query_path = query.raw_query.as_str(); +- if let Ok(mut query_path) = RelPath::new(Path::new(query_path), path_style) { ++ if let Ok(mut query_path) = RelPath::from_std_path(Path::new(query_path), path_style) { + let available_worktree = self + .project + .read(cx) +@@ -953,7 +953,7 @@ impl FileFinderDelegate { + let worktree_root = worktree.read(cx).root_name(); + if worktree_count > 1 { + if let Ok(suffix) = query_path.strip_prefix(worktree_root) { +- query_path = Cow::Owned(suffix.to_owned()); ++ query_path = suffix.into(); + expect_worktree = Some(worktree); + break; + } +@@ -973,7 +973,7 @@ impl FileFinderDelegate { + { + self.matches.matches.push(Match::CreateNew(ProjectPath { + worktree_id: worktree.id(), +- path: query_path.into_arc(), ++ path: query_path, + })); + } + } +@@ -1128,7 +1128,7 @@ impl FileFinderDelegate { + let mut path_positions = path_match.positions.clone(); + + let file_name = full_path.file_name().unwrap_or(""); +- let file_name_start = full_path.as_unix_str().len() - file_name.len(); ++ let file_name_start = full_path.as_str().len() - file_name.len(); + let file_name_positions = path_positions + .iter() + .filter_map(|pos| { +@@ -1315,8 +1315,8 @@ impl PickerDelegate for FileFinderDelegate { + let raw_query = raw_query.trim(); + + let raw_query = match &raw_query.get(0..2) { +- Some(".\\" | "./") => &raw_query[2..], +- Some(prefix @ ("a\\" | "a/" | "b\\" | "b/")) => { ++ Some(".\\") | Some("./") => &raw_query[2..], ++ Some("a\\") | Some("a/") => { + if self + .workspace + .upgrade() +@@ -1325,7 +1325,25 @@ impl PickerDelegate for FileFinderDelegate { + .all(|worktree| { + worktree + .read(cx) +- .entry_for_path(RelPath::unix(prefix.split_at(1).0).unwrap()) ++ .entry_for_path(RelPath::new("a").unwrap()) ++ .is_none_or(|entry| !entry.is_dir()) ++ }) ++ { ++ &raw_query[2..] ++ } else { ++ raw_query ++ } ++ } ++ Some("b\\") | Some("b/") => { ++ if self ++ .workspace ++ .upgrade() ++ .into_iter() ++ .flat_map(|workspace| workspace.read(cx).worktrees(cx)) ++ .all(|worktree| { ++ worktree ++ .read(cx) ++ .entry_for_path(RelPath::new("b").unwrap()) + .is_none_or(|entry| !entry.is_dir()) + }) + { +diff --git a/crates/file_finder/src/file_finder_tests.rs b/crates/file_finder/src/file_finder_tests.rs +index dffbaff797..75b2101101 100644 +--- a/crates/file_finder/src/file_finder_tests.rs ++++ b/crates/file_finder/src/file_finder_tests.rs +@@ -2192,7 +2192,7 @@ async fn test_nonexistent_history_items_not_shown(cx: &mut gpui::TestAppContext) + collect_search_matches(picker).history, + vec![ + rel_path("test/first.rs").into(), +- rel_path("test/third.rs").into() ++ rel_path("test/third.rs").into(), + ], + "Should have all opened files in the history, except the ones that do not exist on disk" + ); +diff --git a/crates/fs/src/fake_git_repo.rs b/crates/fs/src/fake_git_repo.rs +index 91c7113214..940210a710 100644 +--- a/crates/fs/src/fake_git_repo.rs ++++ b/crates/fs/src/fake_git_repo.rs +@@ -226,7 +226,7 @@ impl GitRepository for FakeGitRepository { + .read_file_sync(path) + .ok() + .map(|content| String::from_utf8(content).unwrap())?; +- let repo_path = RelPath::new(repo_path, PathStyle::local()).ok()?; ++ let repo_path = RelPath::from_std_path(repo_path, PathStyle::local()).ok()?; + Some((repo_path.into(), (content, is_ignored))) + }) + .collect(); +diff --git a/crates/fs/src/fs.rs b/crates/fs/src/fs.rs +index 11ff637ad4..a1ee23cf5f 100644 +--- a/crates/fs/src/fs.rs ++++ b/crates/fs/src/fs.rs +@@ -1671,10 +1671,10 @@ impl FakeFs { + for (path, content) in workdir_contents { + use util::{paths::PathStyle, rel_path::RelPath}; + +- let repo_path: RepoPath = RelPath::new(path.strip_prefix(&workdir_path).unwrap(), PathStyle::local()).unwrap().into(); ++ let repo_path: RepoPath = RelPath::from_std_path(path.strip_prefix(&workdir_path).unwrap(), PathStyle::local()).unwrap().into(); + let status = statuses + .iter() +- .find_map(|(p, status)| (*p == repo_path.as_unix_str()).then_some(status)); ++ .find_map(|(p, status)| (*p == repo_path.as_str()).then_some(status)); + let mut content = String::from_utf8_lossy(&content).to_string(); + + let mut index_content = None; +diff --git a/crates/fuzzy/src/paths.rs b/crates/fuzzy/src/paths.rs +index 6fc52361e3..fa6d3f8504 100644 +--- a/crates/fuzzy/src/paths.rs ++++ b/crates/fuzzy/src/paths.rs +@@ -52,7 +52,7 @@ impl<'a> MatchCandidate for PathMatchCandidate<'a> { + } + + fn candidate_chars(&self) -> impl Iterator { +- self.path.as_unix_str().chars() ++ self.path.as_str().chars() + } + } + +@@ -184,11 +184,8 @@ pub async fn match_path_sets<'a, Set: PathMatchCandidateSet<'a>>( + let candidates = candidate_set.candidates(start).take(end - start); + + let worktree_id = candidate_set.id(); +- let mut prefix = candidate_set +- .prefix() +- .as_unix_str() +- .chars() +- .collect::>(); ++ let mut prefix = ++ candidate_set.prefix().as_str().chars().collect::>(); + if !candidate_set.root_is_file() && !prefix.is_empty() { + prefix.push('/'); + } +diff --git a/crates/git/src/blame.rs b/crates/git/src/blame.rs +index e58b9cb7e0..a06d5081b7 100644 +--- a/crates/git/src/blame.rs ++++ b/crates/git/src/blame.rs +@@ -77,7 +77,7 @@ async fn run_git_blame( + .arg("-w") + .arg("--contents") + .arg("-") +- .arg(path.as_unix_str()) ++ .arg(path.as_str()) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) +diff --git a/crates/git/src/repository.rs b/crates/git/src/repository.rs +index 5708999860..b455f5b14c 100644 +--- a/crates/git/src/repository.rs ++++ b/crates/git/src/repository.rs +@@ -12,7 +12,6 @@ use parking_lot::Mutex; + use rope::Rope; + use schemars::JsonSchema; + use serde::Deserialize; +-use std::borrow::Cow; + use std::ffi::{OsStr, OsString}; + use std::io::prelude::*; + use std::process::{ExitStatus, Stdio}; +@@ -720,7 +719,7 @@ impl GitRepository for RealGitRepository { + let mut newline = [b'\0']; + for (path, status_code) in changes { + // git-show outputs `/`-delimited paths even on Windows. +- let Some(rel_path) = RelPath::unix(path).log_err() else { ++ let Ok(rel_path) = RelPath::new(path) else { + continue; + }; + +@@ -829,7 +828,7 @@ impl GitRepository for RealGitRepository { + .current_dir(&working_directory?) + .envs(env.iter()) + .args(["checkout", &commit, "--"]) +- .args(paths.iter().map(|path| path.as_unix_str())) ++ .args(paths.iter().map(|path| path.as_str())) + .output() + .await?; + anyhow::ensure!( +@@ -921,7 +920,7 @@ impl GitRepository for RealGitRepository { + .current_dir(&working_directory) + .envs(env.iter()) + .args(["update-index", "--add", "--cacheinfo", "100644", sha]) +- .arg(path.as_unix_str()) ++ .arg(path.as_str()) + .output() + .await?; + +@@ -936,7 +935,7 @@ impl GitRepository for RealGitRepository { + .current_dir(&working_directory) + .envs(env.iter()) + .args(["update-index", "--force-remove"]) +- .arg(path.as_unix_str()) ++ .arg(path.as_str()) + .output() + .await?; + anyhow::ensure!( +@@ -1254,7 +1253,7 @@ impl GitRepository for RealGitRepository { + .current_dir(&working_directory?) + .envs(env.iter()) + .args(["update-index", "--add", "--remove", "--"]) +- .args(paths.iter().map(|p| p.as_unix_str())) ++ .args(paths.iter().map(|p| p.as_str())) + .output() + .await?; + anyhow::ensure!( +@@ -1283,7 +1282,7 @@ impl GitRepository for RealGitRepository { + .current_dir(&working_directory?) + .envs(env.iter()) + .args(["reset", "--quiet", "--"]) +- .args(paths.iter().map(|p| p.as_std_path())) ++ .args(paths.iter().map(|p| p.as_ref())) + .output() + .await?; + +@@ -1312,7 +1311,7 @@ impl GitRepository for RealGitRepository { + .args(["stash", "push", "--quiet"]) + .arg("--include-untracked"); + +- cmd.args(paths.iter().map(|p| p.as_unix_str())); ++ cmd.args(paths.iter().map(|p| p.as_ref())); + + let output = cmd.output().await?; + +@@ -1818,7 +1817,7 @@ fn git_status_args(path_prefixes: &[RepoPath]) -> Vec { + if path_prefix.is_empty() { + Path::new(".").into() + } else { +- path_prefix.as_std_path().into() ++ path_prefix.as_os_str().into() + } + })); + args +@@ -2074,7 +2073,7 @@ pub struct RepoPath(pub Arc); + + impl RepoPath { + pub fn new + ?Sized>(s: &S) -> Result { +- let rel_path = RelPath::unix(s.as_ref())?; ++ let rel_path = RelPath::new(s)?; + Ok(rel_path.into()) + } + +@@ -2084,14 +2083,14 @@ impl RepoPath { + } + + pub fn from_std_path(path: &Path, path_style: PathStyle) -> Result { +- let rel_path = RelPath::new(path, path_style)?; +- Ok(Self(rel_path.as_ref().into())) ++ let rel_path = RelPath::from_std_path(path, path_style)?; ++ Ok(rel_path.into()) + } + } + + #[cfg(any(test, feature = "test-support"))] + pub fn repo_path + ?Sized>(s: &S) -> RepoPath { +- RepoPath(RelPath::unix(s.as_ref()).unwrap().into()) ++ RepoPath(RelPath::new(s).unwrap().into()) + } + + impl From<&RelPath> for RepoPath { +@@ -2100,12 +2099,6 @@ impl From<&RelPath> for RepoPath { + } + } + +-impl<'a> From> for RepoPath { +- fn from(value: Cow<'a, RelPath>) -> Self { +- value.as_ref().into() +- } +-} +- + impl From> for RepoPath { + fn from(value: Arc) -> Self { + RepoPath(value) +@@ -2126,11 +2119,11 @@ impl std::ops::Deref for RepoPath { + } + } + +-// impl AsRef for RepoPath { +-// fn as_ref(&self) -> &Path { +-// RelPath::as_ref(&self.0) +-// } +-// } ++impl AsRef for RepoPath { ++ fn as_ref(&self) -> &Path { ++ RelPath::as_ref(&self.0) ++ } ++} + + #[derive(Debug)] + pub struct RepoPathDescendants<'a>(pub &'a RepoPath); +diff --git a/crates/git/src/status.rs b/crates/git/src/status.rs +index c3f28aa204..2bcd0809db 100644 +--- a/crates/git/src/status.rs ++++ b/crates/git/src/status.rs +@@ -448,7 +448,7 @@ impl FromStr for GitStatus { + let status = entry.as_bytes()[0..2].try_into().unwrap(); + let status = FileStatus::from_bytes(status).log_err()?; + // git-status outputs `/`-delimited repo paths, even on Windows. +- let path = RepoPath(RelPath::unix(path).log_err()?.into()); ++ let path = RepoPath(RelPath::new(path).log_err()?.into()); + Some((path, status)) + }) + .collect::>(); +diff --git a/crates/git_ui/src/commit_view.rs b/crates/git_ui/src/commit_view.rs +index ac00955b61..038a5beaac 100644 +--- a/crates/git_ui/src/commit_view.rs ++++ b/crates/git_ui/src/commit_view.rs +@@ -128,7 +128,7 @@ impl CommitView { + let mut metadata_buffer_id = None; + if let Some(worktree_id) = first_worktree_id { + let file = Arc::new(CommitMetadataFile { +- title: RelPath::unix(&format!("commit {}", commit.sha)) ++ title: RelPath::new(&format!("commit {}", commit.sha)) + .unwrap() + .into(), + worktree_id, +@@ -145,7 +145,7 @@ impl CommitView { + }); + multibuffer.update(cx, |multibuffer, cx| { + multibuffer.set_excerpts_for_path( +- PathKey::namespaced(COMMIT_METADATA_NAMESPACE, file.title.as_unix_str().into()), ++ PathKey::namespaced(COMMIT_METADATA_NAMESPACE, file.title.as_str().into()), + buffer.clone(), + vec![Point::zero()..buffer.read(cx).max_point()], + 0, +@@ -193,7 +193,7 @@ impl CommitView { + .collect::>(); + let path = snapshot.file().unwrap().path().clone(); + let _is_newly_added = multibuffer.set_excerpts_for_path( +- PathKey::namespaced(FILE_NAMESPACE, path.as_unix_str().into()), ++ PathKey::namespaced(FILE_NAMESPACE, path.as_str().into()), + buffer, + diff_hunk_ranges, + multibuffer_context_lines(cx), +@@ -275,7 +275,7 @@ impl language::File for CommitMetadataFile { + } + + fn full_path(&self, _: &App) -> PathBuf { +- PathBuf::from(self.title.as_unix_str().to_owned()) ++ PathBuf::from(self.title.as_str().to_owned()) + } + + fn file_name<'a>(&'a self, _: &'a App) -> &'a str { +diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs +index 6ab2b24e2a..e66da36576 100644 +--- a/crates/git_ui/src/git_panel.rs ++++ b/crates/git_ui/src/git_panel.rs +@@ -4550,6 +4550,7 @@ impl RenderOnce for PanelRepoFooter { + }; + + let repo_selector_trigger = Button::new("repo-selector", truncated_repo_name) ++ .style(ButtonStyle::Transparent) + .size(ButtonSize::None) + .label_size(LabelSize::Small) + .color(Color::Muted); +@@ -4570,6 +4571,7 @@ impl RenderOnce for PanelRepoFooter { + .into_any_element(); + + let branch_selector_button = Button::new("branch-selector", truncated_branch_name) ++ .style(ButtonStyle::Transparent) + .size(ButtonSize::None) + .label_size(LabelSize::Small) + .truncate(true) +@@ -4590,31 +4592,34 @@ impl RenderOnce for PanelRepoFooter { + }); + + h_flex() +- .h(px(36.)) + .w_full() + .px_2() ++ .h(px(36.)) ++ .items_center() + .justify_between() + .gap_1() + .child( + h_flex() + .flex_1() + .overflow_hidden() +- .gap_px() ++ .items_center() + .child( +- Icon::new(IconName::GitBranchAlt) +- .size(IconSize::Small) +- .color(if single_repo { +- Color::Disabled +- } else { +- Color::Muted +- }), ++ div().child( ++ Icon::new(IconName::GitBranchAlt) ++ .size(IconSize::Small) ++ .color(if single_repo { ++ Color::Disabled ++ } else { ++ Color::Muted ++ }), ++ ), + ) + .child(repo_selector) + .when(show_separator, |this| { + this.child( + div() ++ .text_color(cx.theme().colors().text_muted) + .text_sm() +- .text_color(cx.theme().colors().icon_muted.opacity(0.5)) + .child("/"), + ) + }) +diff --git a/crates/git_ui/src/project_diff.rs b/crates/git_ui/src/project_diff.rs +index 0508cd4c25..a226caab34 100644 +--- a/crates/git_ui/src/project_diff.rs ++++ b/crates/git_ui/src/project_diff.rs +@@ -243,7 +243,7 @@ impl ProjectDiff { + TRACKED_NAMESPACE + }; + +- let path_key = PathKey::namespaced(namespace, entry.repo_path.as_unix_str().into()); ++ let path_key = PathKey::namespaced(namespace, entry.repo_path.as_str().into()); + + self.move_to_path(path_key, window, cx) + } +@@ -397,7 +397,7 @@ impl ProjectDiff { + } else { + TRACKED_NAMESPACE + }; +- let path_key = PathKey::namespaced(namespace, entry.repo_path.as_unix_str().into()); ++ let path_key = PathKey::namespaced(namespace, entry.repo_path.as_str().into()); + + previous_paths.remove(&path_key); + let load_buffer = self +diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml +index 4544b561c3..2919fecabf 100644 +--- a/crates/gpui/Cargo.toml ++++ b/crates/gpui/Cargo.toml +@@ -230,10 +230,9 @@ collections = { workspace = true, features = ["test-support"] } + env_logger.workspace = true + http_client = { workspace = true, features = ["test-support"] } + lyon = { version = "1.0", features = ["extra"] } +-pretty_assertions.workspace = true + rand.workspace = true +-reqwest_client = { workspace = true, features = ["test-support"] } + unicode-segmentation.workspace = true ++reqwest_client = { workspace = true, features = ["test-support"] } + util = { workspace = true, features = ["test-support"] } + + [target.'cfg(target_os = "windows")'.build-dependencies] +diff --git a/crates/gpui/examples/set_menus.rs b/crates/gpui/examples/set_menus.rs +index 8a97a8d8a2..2488b5c100 100644 +--- a/crates/gpui/examples/set_menus.rs ++++ b/crates/gpui/examples/set_menus.rs +@@ -1,13 +1,17 @@ + use gpui::{ +- App, Application, Context, Menu, MenuItem, SystemMenuType, Window, WindowOptions, actions, div, +- prelude::*, rgb, ++ App, Application, Context, FocusHandle, KeyBinding, Menu, MenuItem, PromptLevel, ++ SystemMenuType, Window, WindowOptions, actions, div, prelude::*, rgb, + }; + +-struct SetMenus; ++struct SetMenus { ++ focus_handle: FocusHandle, ++} + + impl Render for SetMenus { + fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { + div() ++ .key_context("root") ++ .track_focus(&self.focus_handle) + .flex() + .bg(rgb(0x2e7d32)) + .size_full() +@@ -15,6 +19,16 @@ impl Render for SetMenus { + .items_center() + .text_xl() + .text_color(rgb(0xffffff)) ++ // Actions can also be registered within elements so they are only active when relevant ++ .on_action(|_: &Open, window, cx| { ++ let _ = window.prompt(PromptLevel::Info, "Open action fired", None, &["OK"], cx); ++ }) ++ .on_action(|_: &Copy, window, cx| { ++ let _ = window.prompt(PromptLevel::Info, "Copy action fired", None, &["OK"], cx); ++ }) ++ .on_action(|_: &Paste, window, cx| { ++ let _ = window.prompt(PromptLevel::Info, "Paste action fired", None, &["OK"], cx); ++ }) + .child("Set Menus Example") + } + } +@@ -23,24 +37,47 @@ fn main() { + Application::new().run(|cx: &mut App| { + // Bring the menu bar to the foreground (so you can see the menu bar) + cx.activate(true); ++ // Bind keys to some menu actions ++ cx.bind_keys([ ++ KeyBinding::new("secondary-o", Open, None), ++ KeyBinding::new("secondary-c", Copy, None), ++ KeyBinding::new("secondary-v", Paste, None), ++ ]); + // Register the `quit` function so it can be referenced by the `MenuItem::action` in the menu bar + cx.on_action(quit); + // Add menu items +- cx.set_menus(vec![Menu { +- name: "set_menus".into(), +- items: vec![ +- MenuItem::os_submenu("Services", SystemMenuType::Services), +- MenuItem::separator(), +- MenuItem::action("Quit", Quit), +- ], +- }]); +- cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| SetMenus {})) +- .unwrap(); ++ cx.set_menus(vec![ ++ Menu { ++ name: "set_menus".into(), ++ items: vec![ ++ MenuItem::os_submenu("Services", SystemMenuType::Services), ++ MenuItem::separator(), ++ MenuItem::action("Quit", Quit), ++ ], ++ }, ++ Menu { ++ name: "File".into(), ++ items: vec![MenuItem::action("Open", Open)], ++ }, ++ Menu { ++ name: "Edit".into(), ++ items: vec![ ++ MenuItem::action("Copy", Copy), ++ MenuItem::action("Paste", Paste), ++ ], ++ }, ++ ]); ++ cx.open_window(WindowOptions::default(), |_, cx| { ++ cx.new(|cx| SetMenus { ++ focus_handle: cx.focus_handle(), ++ }) ++ }) ++ .unwrap(); + }); + } + + // Associate actions using the `actions!` macro (or `Action` derive macro) +-actions!(set_menus, [Quit]); ++actions!(set_menus, [Quit, Open, Copy, Paste]); + + // Define the quit function that is registered with the App + fn quit(_: &Quit, cx: &mut App) { +diff --git a/crates/gpui/src/color.rs b/crates/gpui/src/color.rs +index 3af5731bb5..b84f8699e3 100644 +--- a/crates/gpui/src/color.rs ++++ b/crates/gpui/src/color.rs +@@ -362,7 +362,7 @@ pub const fn transparent_black() -> Hsla { + } + } + +-/// Transparent white in [`Hsla`] ++/// Transparent black in [`Hsla`] + pub const fn transparent_white() -> Hsla { + Hsla { + h: 0., +diff --git a/crates/gpui/src/elements/div.rs b/crates/gpui/src/elements/div.rs +index 9e747d864b..bd2eed3397 100644 +--- a/crates/gpui/src/elements/div.rs ++++ b/crates/gpui/src/elements/div.rs +@@ -618,32 +618,13 @@ pub trait InteractiveElement: Sized { + self + } + +- /// Designate this element as a tab stop, equivalent to `tab_index(0)`. +- /// This should be the primary mechanism for tab navigation within the application. +- fn tab_stop(mut self) -> Self { +- self.tab_index(0) +- } +- +- /// Set index of the tab stop order. This should only be used in conjunction with `tab_group` +- /// in order to not interfere with the tab index of other elements. ++ /// Set index of the tab stop order. + fn tab_index(mut self, index: isize) -> Self { + self.interactivity().focusable = true; + self.interactivity().tab_index = Some(index); + self + } + +- /// Designate this div as a "tab group". Tab groups have their own location in the tab-index order, +- /// but for children of the tab group, the tab index is reset to 0. This can be useful for swapping +- /// the order of tab stops within the group, without having to renumber all the tab stops in the whole +- /// application. +- fn tab_group(mut self) -> Self { +- self.interactivity().tab_group = true; +- if self.interactivity().tab_index.is_none() { +- self.interactivity().tab_index = Some(0); +- } +- self +- } +- + /// Set the keymap context for this element. This will be used to determine + /// which action to dispatch from the keymap. + fn key_context(mut self, key_context: C) -> Self +@@ -1500,7 +1481,6 @@ pub struct Interactivity { + pub(crate) window_control: Option, + pub(crate) hitbox_behavior: HitboxBehavior, + pub(crate) tab_index: Option, +- pub(crate) tab_group: bool, + + #[cfg(any(feature = "inspector", debug_assertions))] + pub(crate) source_location: Option<&'static core::panic::Location<'static>>, +@@ -1786,12 +1766,8 @@ impl Interactivity { + return ((), element_state); + } + +- let mut tab_group = None; +- if self.tab_group { +- tab_group = self.tab_index; +- } + if let Some(focus_handle) = &self.tracked_focus_handle { +- window.next_frame.tab_stops.insert(focus_handle); ++ window.next_frame.tab_handles.insert(focus_handle); + } + + window.with_element_opacity(style.opacity, |window| { +@@ -1800,59 +1776,55 @@ impl Interactivity { + window.with_content_mask( + style.overflow_mask(bounds, window.rem_size()), + |window| { +- window.with_tab_group(tab_group, |window| { +- if let Some(hitbox) = hitbox { +- #[cfg(debug_assertions)] +- self.paint_debug_info( +- global_id, hitbox, &style, window, cx, +- ); +- +- if let Some(drag) = cx.active_drag.as_ref() { +- if let Some(mouse_cursor) = drag.cursor_style { +- window.set_window_cursor_style(mouse_cursor); +- } +- } else { +- if let Some(mouse_cursor) = style.mouse_cursor { +- window.set_cursor_style(mouse_cursor, hitbox); +- } ++ if let Some(hitbox) = hitbox { ++ #[cfg(debug_assertions)] ++ self.paint_debug_info( ++ global_id, hitbox, &style, window, cx, ++ ); ++ ++ if let Some(drag) = cx.active_drag.as_ref() { ++ if let Some(mouse_cursor) = drag.cursor_style { ++ window.set_window_cursor_style(mouse_cursor); + } +- +- if let Some(group) = self.group.clone() { +- GroupHitboxes::push(group, hitbox.id, cx); ++ } else { ++ if let Some(mouse_cursor) = style.mouse_cursor { ++ window.set_cursor_style(mouse_cursor, hitbox); + } ++ } + +- if let Some(area) = self.window_control { +- window.insert_window_control_hitbox( +- area, +- hitbox.clone(), +- ); +- } ++ if let Some(group) = self.group.clone() { ++ GroupHitboxes::push(group, hitbox.id, cx); ++ } + +- self.paint_mouse_listeners( +- hitbox, +- element_state.as_mut(), +- window, +- cx, +- ); +- self.paint_scroll_listener(hitbox, &style, window, cx); ++ if let Some(area) = self.window_control { ++ window ++ .insert_window_control_hitbox(area, hitbox.clone()); + } + +- self.paint_keyboard_listeners(window, cx); +- f(&style, window, cx); ++ self.paint_mouse_listeners( ++ hitbox, ++ element_state.as_mut(), ++ window, ++ cx, ++ ); ++ self.paint_scroll_listener(hitbox, &style, window, cx); ++ } + +- if let Some(_hitbox) = hitbox { +- #[cfg(any(feature = "inspector", debug_assertions))] +- window.insert_inspector_hitbox( +- _hitbox.id, +- _inspector_id, +- cx, +- ); ++ self.paint_keyboard_listeners(window, cx); ++ f(&style, window, cx); + +- if let Some(group) = self.group.as_ref() { +- GroupHitboxes::pop(group, cx); +- } ++ if let Some(_hitbox) = hitbox { ++ #[cfg(any(feature = "inspector", debug_assertions))] ++ window.insert_inspector_hitbox( ++ _hitbox.id, ++ _inspector_id, ++ cx, ++ ); ++ ++ if let Some(group) = self.group.as_ref() { ++ GroupHitboxes::pop(group, cx); + } +- }) ++ } + }, + ); + }); +diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs +index 444b60ac15..05b597e9b6 100644 +--- a/crates/gpui/src/platform.rs ++++ b/crates/gpui/src/platform.rs +@@ -250,6 +250,7 @@ pub(crate) trait Platform: 'static { + fn on_app_menu_action(&self, callback: Box); + fn on_will_open_app_menu(&self, callback: Box); + fn on_validate_app_menu_command(&self, callback: Box bool>); ++ fn on_action_triggered(&self, action: &dyn Action); + + fn compositor_name(&self) -> &'static str { + "" +diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs +index 7796af806f..1f60920bcc 100644 +--- a/crates/gpui/src/platform/blade/blade_renderer.rs ++++ b/crates/gpui/src/platform/blade/blade_renderer.rs +@@ -83,8 +83,6 @@ struct ShaderUnderlinesData { + #[derive(blade_macros::ShaderData)] + struct ShaderMonoSpritesData { + globals: GlobalParams, +- gamma_ratios: [f32; 4], +- grayscale_enhanced_contrast: f32, + t_sprite: gpu::TextureView, + s_sprite: gpu::Sampler, + b_mono_sprites: gpu::BufferPiece, +@@ -336,11 +334,11 @@ pub struct BladeRenderer { + atlas_sampler: gpu::Sampler, + #[cfg(target_os = "macos")] + core_video_texture_cache: CVMetalTextureCache, ++ path_sample_count: u32, + path_intermediate_texture: gpu::Texture, + path_intermediate_texture_view: gpu::TextureView, + path_intermediate_msaa_texture: Option, + path_intermediate_msaa_texture_view: Option, +- rendering_parameters: RenderingParameters, + } + + impl BladeRenderer { +@@ -366,12 +364,17 @@ impl BladeRenderer { + name: "main", + buffer_count: 2, + }); +- let rendering_parameters = RenderingParameters::from_env(context); +- let pipelines = BladePipelines::new( +- &context.gpu, +- surface.info(), +- rendering_parameters.path_sample_count, +- ); ++ // workaround for https://github.com/zed-industries/zed/issues/26143 ++ let path_sample_count = std::env::var("ZED_PATH_SAMPLE_COUNT") ++ .ok() ++ .and_then(|v| v.parse().ok()) ++ .or_else(|| { ++ [4, 2, 1] ++ .into_iter() ++ .find(|&n| (context.gpu.capabilities().sample_count_mask & n) != 0) ++ }) ++ .unwrap_or(1); ++ let pipelines = BladePipelines::new(&context.gpu, surface.info(), path_sample_count); + let instance_belt = BufferBelt::new(BufferBeltDescriptor { + memory: gpu::Memory::Shared, + min_chunk_size: 0x1000, +@@ -398,7 +401,7 @@ impl BladeRenderer { + surface.info().format, + config.size.width, + config.size.height, +- rendering_parameters.path_sample_count, ++ path_sample_count, + ) + .unzip(); + +@@ -422,11 +425,11 @@ impl BladeRenderer { + atlas_sampler, + #[cfg(target_os = "macos")] + core_video_texture_cache, ++ path_sample_count, + path_intermediate_texture, + path_intermediate_texture_view, + path_intermediate_msaa_texture, + path_intermediate_msaa_texture_view, +- rendering_parameters, + }) + } + +@@ -503,7 +506,7 @@ impl BladeRenderer { + self.surface.info().format, + gpu_size.width, + gpu_size.height, +- self.rendering_parameters.path_sample_count, ++ self.path_sample_count, + ) + .unzip(); + self.path_intermediate_msaa_texture = path_intermediate_msaa_texture; +@@ -518,11 +521,8 @@ impl BladeRenderer { + self.gpu + .reconfigure_surface(&mut self.surface, self.surface_config); + self.pipelines.destroy(&self.gpu); +- self.pipelines = BladePipelines::new( +- &self.gpu, +- self.surface.info(), +- self.rendering_parameters.path_sample_count, +- ); ++ self.pipelines = ++ BladePipelines::new(&self.gpu, self.surface.info(), self.path_sample_count); + } + } + +@@ -783,10 +783,6 @@ impl BladeRenderer { + 0, + &ShaderMonoSpritesData { + globals, +- gamma_ratios: self.rendering_parameters.gamma_ratios, +- grayscale_enhanced_contrast: self +- .rendering_parameters +- .grayscale_enhanced_contrast, + t_sprite: tex_info.raw_view, + s_sprite: self.atlas_sampler, + b_mono_sprites: instance_buf, +@@ -988,85 +984,3 @@ fn create_msaa_texture_if_needed( + + Some((texture_msaa, texture_view_msaa)) + } +- +-/// A set of parameters that can be set using a corresponding environment variable. +-struct RenderingParameters { +- // Env var: ZED_PATH_SAMPLE_COUNT +- // workaround for https://github.com/zed-industries/zed/issues/26143 +- path_sample_count: u32, +- +- // Env var: ZED_FONTS_GAMMA +- // Allowed range [1.0, 2.2], other values are clipped +- // Default: 1.8 +- gamma_ratios: [f32; 4], +- // Env var: ZED_FONTS_GRAYSCALE_ENHANCED_CONTRAST +- // Allowed range: [0.0, ..), other values are clipped +- // Default: 1.0 +- grayscale_enhanced_contrast: f32, +-} +- +-impl RenderingParameters { +- fn from_env(context: &BladeContext) -> Self { +- use std::env; +- +- let path_sample_count = env::var("ZED_PATH_SAMPLE_COUNT") +- .ok() +- .and_then(|v| v.parse().ok()) +- .or_else(|| { +- [4, 2, 1] +- .into_iter() +- .find(|&n| (context.gpu.capabilities().sample_count_mask & n) != 0) +- }) +- .unwrap_or(1); +- let gamma = env::var("ZED_FONTS_GAMMA") +- .ok() +- .and_then(|v| v.parse().ok()) +- .unwrap_or(1.8_f32) +- .clamp(1.0, 2.2); +- let gamma_ratios = Self::get_gamma_ratios(gamma); +- let grayscale_enhanced_contrast = env::var("ZED_FONTS_GRAYSCALE_ENHANCED_CONTRAST") +- .ok() +- .and_then(|v| v.parse().ok()) +- .unwrap_or(1.0_f32) +- .max(0.0); +- +- Self { +- path_sample_count, +- gamma_ratios, +- grayscale_enhanced_contrast, +- } +- } +- +- // Gamma ratios for brightening/darkening edges for better contrast +- // https://github.com/microsoft/terminal/blob/1283c0f5b99a2961673249fa77c6b986efb5086c/src/renderer/atlas/dwrite.cpp#L50 +- fn get_gamma_ratios(gamma: f32) -> [f32; 4] { +- const GAMMA_INCORRECT_TARGET_RATIOS: [[f32; 4]; 13] = [ +- [0.0000 / 4.0, 0.0000 / 4.0, 0.0000 / 4.0, 0.0000 / 4.0], // gamma = 1.0 +- [0.0166 / 4.0, -0.0807 / 4.0, 0.2227 / 4.0, -0.0751 / 4.0], // gamma = 1.1 +- [0.0350 / 4.0, -0.1760 / 4.0, 0.4325 / 4.0, -0.1370 / 4.0], // gamma = 1.2 +- [0.0543 / 4.0, -0.2821 / 4.0, 0.6302 / 4.0, -0.1876 / 4.0], // gamma = 1.3 +- [0.0739 / 4.0, -0.3963 / 4.0, 0.8167 / 4.0, -0.2287 / 4.0], // gamma = 1.4 +- [0.0933 / 4.0, -0.5161 / 4.0, 0.9926 / 4.0, -0.2616 / 4.0], // gamma = 1.5 +- [0.1121 / 4.0, -0.6395 / 4.0, 1.1588 / 4.0, -0.2877 / 4.0], // gamma = 1.6 +- [0.1300 / 4.0, -0.7649 / 4.0, 1.3159 / 4.0, -0.3080 / 4.0], // gamma = 1.7 +- [0.1469 / 4.0, -0.8911 / 4.0, 1.4644 / 4.0, -0.3234 / 4.0], // gamma = 1.8 +- [0.1627 / 4.0, -1.0170 / 4.0, 1.6051 / 4.0, -0.3347 / 4.0], // gamma = 1.9 +- [0.1773 / 4.0, -1.1420 / 4.0, 1.7385 / 4.0, -0.3426 / 4.0], // gamma = 2.0 +- [0.1908 / 4.0, -1.2652 / 4.0, 1.8650 / 4.0, -0.3476 / 4.0], // gamma = 2.1 +- [0.2031 / 4.0, -1.3864 / 4.0, 1.9851 / 4.0, -0.3501 / 4.0], // gamma = 2.2 +- ]; +- +- const NORM13: f32 = ((0x10000 as f64) / (255.0 * 255.0) * 4.0) as f32; +- const NORM24: f32 = ((0x100 as f64) / (255.0) * 4.0) as f32; +- +- let index = ((gamma * 10.0).round() as usize).clamp(10, 22) - 10; +- let ratios = GAMMA_INCORRECT_TARGET_RATIOS[index]; +- +- [ +- ratios[0] * NORM13, +- ratios[1] * NORM24, +- ratios[2] * NORM13, +- ratios[3] * NORM24, +- ] +- } +-} +diff --git a/crates/gpui/src/platform/blade/shaders.wgsl b/crates/gpui/src/platform/blade/shaders.wgsl +index 55a85c1ec8..95980b54fe 100644 +--- a/crates/gpui/src/platform/blade/shaders.wgsl ++++ b/crates/gpui/src/platform/blade/shaders.wgsl +@@ -28,35 +28,6 @@ fn heat_map_color(value: f32, minValue: f32, maxValue: f32, position: vec2) + + */ + +-fn color_brightness(color: vec3) -> f32 { +- // REC. 601 luminance coefficients for perceived brightness +- return dot(color, vec3(0.30, 0.59, 0.11)); +-} +- +-fn light_on_dark_contrast(enhancedContrast: f32, color: vec3) -> f32 { +- let brightness = color_brightness(color); +- let multiplier = saturate(4.0 * (0.75 - brightness)); +- return enhancedContrast * multiplier; +-} +- +-fn enhance_contrast(alpha: f32, k: f32) -> f32 { +- return alpha * (k + 1.0) / (alpha * k + 1.0); +-} +- +-fn apply_alpha_correction(a: f32, b: f32, g: vec4) -> f32 { +- let brightness_adjustment = g.x * b + g.y; +- let correction = brightness_adjustment * a + (g.z * b + g.w); +- return a + a * (1.0 - a) * correction; +-} +- +-fn apply_contrast_and_gamma_correction(sample: f32, color: vec3, enhanced_contrast_factor: f32, gamma_ratios: vec4) -> f32 { +- let enhanced_contrast = light_on_dark_contrast(enhanced_contrast_factor, color); +- let brightness = color_brightness(color); +- +- let contrasted = enhance_contrast(sample, enhanced_contrast); +- return apply_alpha_correction(contrasted, brightness, gamma_ratios); +-} +- + struct GlobalParams { + viewport_size: vec2, + premultiplied_alpha: u32, +@@ -64,8 +35,6 @@ struct GlobalParams { + } + + var globals: GlobalParams; +-var gamma_ratios: vec4; +-var grayscale_enhanced_contrast: f32; + var t_sprite: texture_2d; + var s_sprite: sampler; + +@@ -1155,13 +1124,11 @@ fn vs_mono_sprite(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index + @fragment + fn fs_mono_sprite(input: MonoSpriteVarying) -> @location(0) vec4 { + let sample = textureSample(t_sprite, s_sprite, input.tile_position).r; +- let alpha_corrected = apply_contrast_and_gamma_correction(sample, input.color.rgb, grayscale_enhanced_contrast, gamma_ratios); +- + // Alpha clip after using the derivatives. + if (any(input.clip_distances < vec4(0.0))) { + return vec4(0.0); + } +- return blend_color(input.color, alpha_corrected); ++ return blend_color(input.color, sample); + } + + // --- polychrome sprites --- // +diff --git a/crates/gpui/src/platform/linux/platform.rs b/crates/gpui/src/platform/linux/platform.rs +index 196e5b65d0..a6e22c42da 100644 +--- a/crates/gpui/src/platform/linux/platform.rs ++++ b/crates/gpui/src/platform/linux/platform.rs +@@ -442,6 +442,8 @@ impl Platform for P { + }); + } + ++ fn on_action_triggered(&self, _action: &dyn Action) {} ++ + fn app_path(&self) -> Result { + // get the path of the executable of the current process + let app_path = env::current_exe()?; +diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs +index 9909c78c47..e0a1d7770d 100644 +--- a/crates/gpui/src/platform/mac/platform.rs ++++ b/crates/gpui/src/platform/mac/platform.rs +@@ -177,6 +177,8 @@ pub(crate) struct MacPlatformState { + dock_menu: Option, + menus: Option>, + keyboard_mapper: Rc, ++ action_menus: Vec<(Box, id)>, ++ handling_menu_item: bool, + } + + impl Default for MacPlatform { +@@ -219,6 +221,8 @@ impl MacPlatform { + on_keyboard_layout_change: None, + menus: None, + keyboard_mapper, ++ handling_menu_item: false, ++ action_menus: Vec::new(), + })) + } + +@@ -241,6 +245,7 @@ impl MacPlatform { + menus: &Vec, + delegate: id, + actions: &mut Vec>, ++ action_menus: &mut Vec<(Box, id)>, + keymap: &Keymap, + ) -> id { + unsafe { +@@ -258,6 +263,7 @@ impl MacPlatform { + item_config, + delegate, + actions, ++ action_menus, + keymap, + )); + } +@@ -292,6 +298,7 @@ impl MacPlatform { + &item_config, + delegate, + actions, ++ &mut Vec::new(), + keymap, + )); + } +@@ -304,6 +311,7 @@ impl MacPlatform { + item: &MenuItem, + delegate: id, + actions: &mut Vec>, ++ action_menus: &mut Vec<(Box, id)>, + keymap: &Keymap, + ) -> id { + static DEFAULT_CONTEXT: OnceLock> = OnceLock::new(); +@@ -412,6 +420,7 @@ impl MacPlatform { + let tag = actions.len() as NSInteger; + let _: () = msg_send![item, setTag: tag]; + actions.push(action.boxed_clone()); ++ action_menus.push((action.boxed_clone(), item)); + item + } + MenuItem::Submenu(Menu { name, items }) => { +@@ -419,7 +428,13 @@ impl MacPlatform { + let submenu = NSMenu::new(nil).autorelease(); + submenu.setDelegate_(delegate); + for item in items { +- submenu.addItem_(Self::create_menu_item(item, delegate, actions, keymap)); ++ submenu.addItem_(Self::create_menu_item( ++ item, ++ delegate, ++ actions, ++ action_menus, ++ keymap, ++ )); + } + item.setSubmenu_(submenu); + item.setTitle_(ns_string(name)); +@@ -888,6 +903,30 @@ impl Platform for MacPlatform { + self.0.lock().validate_menu_command = Some(callback); + } + ++ fn on_action_triggered(&self, action: &dyn Action) { ++ let menu_item = { ++ let mut state = self.0.lock(); ++ let Some(menu_item) = state ++ .action_menus ++ .iter() ++ .find(|(menu_action, _)| menu_action.partial_eq(action)) ++ .map(|(_, menu)| *menu) ++ else { ++ return; ++ }; ++ ++ state.handling_menu_item = true; ++ menu_item ++ }; ++ ++ unsafe { ++ let parent: id = msg_send![menu_item, menu]; ++ let index: NSInteger = msg_send![parent, indexOfItem: menu_item]; ++ let _: () = msg_send![parent, performActionForItemAtIndex: index]; ++ } ++ self.0.lock().handling_menu_item = false; ++ } ++ + fn keyboard_layout(&self) -> Box { + Box::new(MacKeyboardLayout::new()) + } +@@ -905,15 +944,24 @@ impl Platform for MacPlatform { + } + + fn set_menus(&self, menus: Vec, keymap: &Keymap) { ++ let mut action_menus = Vec::new(); + unsafe { + let app: id = msg_send![APP_CLASS, sharedApplication]; + let mut state = self.0.lock(); + let actions = &mut state.menu_actions; +- let menu = self.create_menu_bar(&menus, NSWindow::delegate(app), actions, keymap); ++ let menu = self.create_menu_bar( ++ &menus, ++ NSWindow::delegate(app), ++ actions, ++ &mut action_menus, ++ keymap, ++ ); + drop(state); + app.setMainMenu_(menu); + } +- self.0.lock().menus = Some(menus.into_iter().map(|menu| menu.owned()).collect()); ++ let mut state = self.0.lock(); ++ state.menus = Some(menus.into_iter().map(|menu| menu.owned()).collect()); ++ state.action_menus = action_menus; + } + + fn get_menus(&self) -> Option> { +@@ -1465,6 +1513,12 @@ extern "C" fn handle_menu_item(this: &mut Object, _: Sel, item: id) { + unsafe { + let platform = get_mac_platform(this); + let mut lock = platform.0.lock(); ++ ++ // If the menu item is currently being handled, i.e., this action is being triggered as a ++ // result of a keyboard shortcut causing the menu to flash, don't do anything. ++ if lock.handling_menu_item { ++ return; ++ } + if let Some(mut callback) = lock.menu_command.take() { + let tag: NSInteger = msg_send![item, tag]; + let index = tag as usize; +diff --git a/crates/gpui/src/platform/test/platform.rs b/crates/gpui/src/platform/test/platform.rs +index 15b909199f..85b84248ff 100644 +--- a/crates/gpui/src/platform/test/platform.rs ++++ b/crates/gpui/src/platform/test/platform.rs +@@ -1,5 +1,5 @@ + use crate::{ +- AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DevicePixels, ++ Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DevicePixels, + DummyKeyboardMapper, ForegroundExecutor, Keymap, NoopTextSystem, Platform, PlatformDisplay, + PlatformKeyboardLayout, PlatformKeyboardMapper, PlatformTextSystem, PromptButton, + ScreenCaptureFrame, ScreenCaptureSource, ScreenCaptureStream, SourceMetadata, Task, +@@ -378,6 +378,8 @@ impl Platform for TestPlatform { + + fn on_validate_app_menu_command(&self, _callback: Box bool>) {} + ++ fn on_action_triggered(&self, _action: &dyn Action) {} ++ + fn app_path(&self) -> Result { + unimplemented!() + } +diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs +index 2eb1862f36..0ad343f2d3 100644 +--- a/crates/gpui/src/platform/windows/platform.rs ++++ b/crates/gpui/src/platform/windows/platform.rs +@@ -536,6 +536,8 @@ impl Platform for WindowsPlatform { + .validate_app_menu_command = Some(callback); + } + ++ fn on_action_triggered(&self, _action: &dyn Action) {} ++ + fn app_path(&self) -> Result { + Ok(std::env::current_exe()?) + } +diff --git a/crates/gpui/src/tab_stop.rs b/crates/gpui/src/tab_stop.rs +index ea69bd1130..c4d2fda6e9 100644 +--- a/crates/gpui/src/tab_stop.rs ++++ b/crates/gpui/src/tab_stop.rs +@@ -1,320 +1,74 @@ +-use std::fmt::Debug; +- +-use ::sum_tree::SumTree; +-use collections::FxHashMap; +-use sum_tree::Bias; +- + use crate::{FocusHandle, FocusId}; + +-/// Represents a collection of focus handles using the tab-index APIs. +-#[derive(Debug)] +-pub(crate) struct TabStopMap { +- current_path: TabStopPath, +- pub(crate) insertion_history: Vec, +- by_id: FxHashMap, +- order: SumTree, ++/// Represents a collection of tab handles. ++/// ++/// Used to manage the `Tab` event to switch between focus handles. ++#[derive(Default)] ++pub(crate) struct TabHandles { ++ pub(crate) handles: Vec, + } + +-#[derive(Debug, Clone)] +-pub enum TabStopOperation { +- Insert(FocusHandle), +- Group(TabIndex), +- GroupEnd, +-} +- +-impl TabStopOperation { +- fn focus_handle(&self) -> Option<&FocusHandle> { +- match self { +- TabStopOperation::Insert(focus_handle) => Some(focus_handle), +- _ => None, ++impl TabHandles { ++ pub(crate) fn insert(&mut self, focus_handle: &FocusHandle) { ++ if !focus_handle.tab_stop { ++ return; + } +- } +-} +- +-type TabIndex = isize; +- +-#[derive(Debug, Default, PartialEq, Eq, Clone, Ord, PartialOrd)] +-struct TabStopPath(smallvec::SmallVec<[TabIndex; 6]>); +- +-#[derive(Clone, Debug, Default, Eq, PartialEq)] +-struct TabStopNode { +- /// Path to access the node in the tree +- /// The final node in the list is a leaf node corresponding to an actual focus handle, +- /// all other nodes are group nodes +- path: TabStopPath, +- /// index into the backing array of nodes. Corresponds to insertion order +- node_insertion_index: usize, + +- /// Whether this node is a tab stop +- tab_stop: bool, +-} ++ let focus_handle = focus_handle.clone(); + +-impl Ord for TabStopNode { +- fn cmp(&self, other: &Self) -> std::cmp::Ordering { +- self.path +- .cmp(&other.path) +- .then(self.node_insertion_index.cmp(&other.node_insertion_index)) +- } +-} +- +-impl PartialOrd for TabStopNode { +- fn partial_cmp(&self, other: &Self) -> Option { +- Some(self.cmp(&other)) +- } +-} +- +-impl Default for TabStopMap { +- fn default() -> Self { +- Self { +- current_path: TabStopPath::default(), +- insertion_history: Vec::new(), +- by_id: FxHashMap::default(), +- order: SumTree::new(()), +- } +- } +-} +- +-impl TabStopMap { +- pub fn insert(&mut self, focus_handle: &FocusHandle) { +- self.insertion_history +- .push(TabStopOperation::Insert(focus_handle.clone())); +- let mut path = self.current_path.clone(); +- path.0.push(focus_handle.tab_index); +- let order = TabStopNode { +- node_insertion_index: self.insertion_history.len() - 1, +- tab_stop: focus_handle.tab_stop, +- path, +- }; +- self.by_id.insert(focus_handle.id, order.clone()); +- self.order.insert_or_replace(order, ()); +- } +- +- pub fn begin_group(&mut self, tab_index: isize) { +- self.insertion_history +- .push(TabStopOperation::Group(tab_index)); +- self.current_path.0.push(tab_index); +- } +- +- pub fn end_group(&mut self) { +- self.insertion_history.push(TabStopOperation::GroupEnd); +- self.current_path.0.pop(); +- } +- +- pub fn clear(&mut self) { +- *self = Self::default(); +- self.current_path.0.clear(); +- self.insertion_history.clear(); +- self.by_id.clear(); +- self.order = SumTree::new(()); +- } +- +- pub fn next(&self, focused_id: Option<&FocusId>) -> Option { +- let Some(focused_id) = focused_id else { +- let first = self.order.first()?; +- if first.tab_stop { +- return self.focus_handle_for_order(first); +- } else { +- return self +- .next_inner(first) +- .and_then(|order| self.focus_handle_for_order(order)); +- } +- }; +- +- let node = self.tab_node_for_focus_id(focused_id)?; +- let item = self.next_inner(node); +- +- if let Some(item) = item { +- self.focus_handle_for_order(&item) +- } else { +- self.next(None) +- } +- } +- +- fn next_inner(&self, node: &TabStopNode) -> Option<&TabStopNode> { +- let mut cursor = self.order.cursor::(()); +- cursor.seek(&node, Bias::Left); +- cursor.next(); +- while let Some(item) = cursor.item() +- && !item.tab_stop ++ // Insert handle with same tab_index last ++ if let Some(ix) = self ++ .handles ++ .iter() ++ .position(|tab| tab.tab_index > focus_handle.tab_index) + { +- cursor.next(); +- } +- +- cursor.item() +- } +- +- pub fn prev(&self, focused_id: Option<&FocusId>) -> Option { +- let Some(focused_id) = focused_id else { +- let last = self.order.last()?; +- if last.tab_stop { +- return self.focus_handle_for_order(last); +- } else { +- return self +- .prev_inner(last) +- .and_then(|order| self.focus_handle_for_order(order)); +- } +- }; +- +- let node = self.tab_node_for_focus_id(focused_id)?; +- let item = self.prev_inner(node); +- +- if let Some(item) = item { +- self.focus_handle_for_order(&item) ++ self.handles.insert(ix, focus_handle); + } else { +- self.prev(None) ++ self.handles.push(focus_handle); + } + } + +- fn prev_inner(&self, node: &TabStopNode) -> Option<&TabStopNode> { +- let mut cursor = self.order.cursor::(()); +- cursor.seek(&node, Bias::Left); +- cursor.prev(); +- while let Some(item) = cursor.item() +- && !item.tab_stop +- { +- cursor.prev(); +- } +- +- cursor.item() ++ pub(crate) fn clear(&mut self) { ++ self.handles.clear(); + } + +- pub fn replay(&mut self, nodes: &[TabStopOperation]) { +- for node in nodes { +- match node { +- TabStopOperation::Insert(focus_handle) => self.insert(focus_handle), +- TabStopOperation::Group(tab_index) => self.begin_group(*tab_index), +- TabStopOperation::GroupEnd => self.end_group(), +- } +- } ++ fn current_index(&self, focused_id: Option<&FocusId>) -> Option { ++ self.handles.iter().position(|h| Some(&h.id) == focused_id) + } + +- pub fn paint_index(&self) -> usize { +- self.insertion_history.len() +- } ++ pub(crate) fn next(&self, focused_id: Option<&FocusId>) -> Option { ++ let next_ix = self ++ .current_index(focused_id) ++ .and_then(|ix| { ++ let next_ix = ix + 1; ++ (next_ix < self.handles.len()).then_some(next_ix) ++ }) ++ .unwrap_or_default(); + +- fn focus_handle_for_order(&self, order: &TabStopNode) -> Option { +- let handle = self.insertion_history[order.node_insertion_index].focus_handle(); +- debug_assert!( +- handle.is_some(), +- "The order node did not correspond to an element, this is a GPUI bug" +- ); +- handle.cloned() ++ self.handles.get(next_ix).cloned() + } + +- fn tab_node_for_focus_id(&self, focused_id: &FocusId) -> Option<&TabStopNode> { +- let Some(order) = self.by_id.get(focused_id) else { +- return None; ++ pub(crate) fn prev(&self, focused_id: Option<&FocusId>) -> Option { ++ let ix = self.current_index(focused_id).unwrap_or_default(); ++ let prev_ix = if ix == 0 { ++ self.handles.len().saturating_sub(1) ++ } else { ++ ix.saturating_sub(1) + }; +- Some(order) +- } +-} +- +-mod sum_tree_impl { +- use sum_tree::SeekTarget; +- +- use crate::tab_stop::{TabStopNode, TabStopPath}; +- +- #[derive(Clone, Debug)] +- pub struct TabStopOrderNodeSummary { +- max_index: usize, +- max_path: TabStopPath, +- pub tab_stops: usize, +- } +- +- pub type TabStopCount = usize; +- +- impl sum_tree::ContextLessSummary for TabStopOrderNodeSummary { +- fn zero() -> Self { +- TabStopOrderNodeSummary { +- max_index: 0, +- max_path: TabStopPath::default(), +- tab_stops: 0, +- } +- } +- +- fn add_summary(&mut self, summary: &Self) { +- self.max_index = summary.max_index; +- self.max_path = summary.max_path.clone(); +- self.tab_stops += summary.tab_stops; +- } +- } +- +- impl sum_tree::KeyedItem for TabStopNode { +- type Key = Self; +- +- fn key(&self) -> Self::Key { +- self.clone() +- } +- } +- +- impl sum_tree::Item for TabStopNode { +- type Summary = TabStopOrderNodeSummary; +- +- fn summary(&self, _cx: ::Context<'_>) -> Self::Summary { +- TabStopOrderNodeSummary { +- max_index: self.node_insertion_index, +- max_path: self.path.clone(), +- tab_stops: if self.tab_stop { 1 } else { 0 }, +- } +- } +- } +- +- impl<'a> sum_tree::Dimension<'a, TabStopOrderNodeSummary> for TabStopCount { +- fn zero(_: ::Context<'_>) -> Self { +- 0 +- } +- +- fn add_summary( +- &mut self, +- summary: &'a TabStopOrderNodeSummary, +- _: ::Context<'_>, +- ) { +- *self += summary.tab_stops; +- } +- } +- +- impl<'a> sum_tree::Dimension<'a, TabStopOrderNodeSummary> for TabStopNode { +- fn zero(_: ::Context<'_>) -> Self { +- TabStopNode::default() +- } + +- fn add_summary( +- &mut self, +- summary: &'a TabStopOrderNodeSummary, +- _: ::Context<'_>, +- ) { +- self.node_insertion_index = summary.max_index; +- self.path = summary.max_path.clone(); +- } +- } +- +- impl<'a, 'b> SeekTarget<'a, TabStopOrderNodeSummary, TabStopNode> for &'b TabStopNode { +- fn cmp( +- &self, +- cursor_location: &TabStopNode, +- _: ::Context<'_>, +- ) -> std::cmp::Ordering { +- Iterator::cmp(self.path.0.iter(), cursor_location.path.0.iter()).then( +- ::cmp( +- &self.node_insertion_index, +- &cursor_location.node_insertion_index, +- ), +- ) +- } ++ self.handles.get(prev_ix).cloned() + } + } + + #[cfg(test)] + mod tests { +- use itertools::Itertools as _; +- +- use crate::{FocusHandle, FocusId, FocusMap, TabStopMap}; ++ use crate::{FocusHandle, FocusMap, TabHandles}; + use std::sync::Arc; + + #[test] + fn test_tab_handles() { + let focus_map = Arc::new(FocusMap::default()); +- let mut tab_index_map = TabStopMap::default(); ++ let mut tab = TabHandles::default(); + + let focus_handles = vec![ + FocusHandle::new(&focus_map).tab_stop(true).tab_index(0), +@@ -327,281 +81,72 @@ mod tests { + ]; + + for handle in focus_handles.iter() { +- tab_index_map.insert(handle); ++ tab.insert(handle); + } +- let expected = [ +- focus_handles[0].clone(), +- focus_handles[5].clone(), +- focus_handles[1].clone(), +- focus_handles[2].clone(), +- focus_handles[6].clone(), +- ]; +- +- let mut prev = None; +- let mut found = vec![]; +- for _ in 0..expected.len() { +- let handle = tab_index_map.next(prev.as_ref()).unwrap(); +- prev = Some(handle.id); +- found.push(handle.id); +- } +- + assert_eq!( +- found, +- expected.iter().map(|handle| handle.id).collect::>() ++ tab.handles ++ .iter() ++ .map(|handle| handle.id) ++ .collect::>(), ++ vec![ ++ focus_handles[0].id, ++ focus_handles[5].id, ++ focus_handles[1].id, ++ focus_handles[2].id, ++ focus_handles[6].id, ++ ] + ); + + // Select first tab index if no handle is currently focused. +- assert_eq!(tab_index_map.next(None), Some(expected[0].clone())); ++ assert_eq!(tab.next(None), Some(tab.handles[0].clone())); + // Select last tab index if no handle is currently focused. +- assert_eq!(tab_index_map.prev(None), expected.last().cloned(),); ++ assert_eq!( ++ tab.prev(None), ++ Some(tab.handles[tab.handles.len() - 1].clone()) ++ ); + + assert_eq!( +- tab_index_map.next(Some(&expected[0].id)), +- Some(expected[1].clone()) ++ tab.next(Some(&tab.handles[0].id)), ++ Some(tab.handles[1].clone()) + ); + assert_eq!( +- tab_index_map.next(Some(&expected[1].id)), +- Some(expected[2].clone()) ++ tab.next(Some(&tab.handles[1].id)), ++ Some(tab.handles[2].clone()) + ); + assert_eq!( +- tab_index_map.next(Some(&expected[2].id)), +- Some(expected[3].clone()) ++ tab.next(Some(&tab.handles[2].id)), ++ Some(tab.handles[3].clone()) + ); + assert_eq!( +- tab_index_map.next(Some(&expected[3].id)), +- Some(expected[4].clone()) ++ tab.next(Some(&tab.handles[3].id)), ++ Some(tab.handles[4].clone()) + ); + assert_eq!( +- tab_index_map.next(Some(&expected[4].id)), +- Some(expected[0].clone()) ++ tab.next(Some(&tab.handles[4].id)), ++ Some(tab.handles[0].clone()) + ); + + // prev +- assert_eq!(tab_index_map.prev(None), Some(expected[4].clone())); ++ assert_eq!(tab.prev(None), Some(tab.handles[4].clone())); + assert_eq!( +- tab_index_map.prev(Some(&expected[0].id)), +- Some(expected[4].clone()) ++ tab.prev(Some(&tab.handles[0].id)), ++ Some(tab.handles[4].clone()) + ); + assert_eq!( +- tab_index_map.prev(Some(&expected[1].id)), +- Some(expected[0].clone()) ++ tab.prev(Some(&tab.handles[1].id)), ++ Some(tab.handles[0].clone()) + ); + assert_eq!( +- tab_index_map.prev(Some(&expected[2].id)), +- Some(expected[1].clone()) ++ tab.prev(Some(&tab.handles[2].id)), ++ Some(tab.handles[1].clone()) + ); + assert_eq!( +- tab_index_map.prev(Some(&expected[3].id)), +- Some(expected[2].clone()) ++ tab.prev(Some(&tab.handles[3].id)), ++ Some(tab.handles[2].clone()) + ); + assert_eq!( +- tab_index_map.prev(Some(&expected[4].id)), +- Some(expected[3].clone()) ++ tab.prev(Some(&tab.handles[4].id)), ++ Some(tab.handles[3].clone()) + ); + } +- +- #[test] +- fn test_tab_non_stop_filtering() { +- let focus_map = Arc::new(FocusMap::default()); +- let mut tab_index_map = TabStopMap::default(); +- +- // Check that we can query next from a non-stop tab +- let tab_non_stop_1 = FocusHandle::new(&focus_map).tab_stop(false).tab_index(1); +- let tab_stop_2 = FocusHandle::new(&focus_map).tab_stop(true).tab_index(2); +- tab_index_map.insert(&tab_non_stop_1); +- tab_index_map.insert(&tab_stop_2); +- let result = tab_index_map.next(Some(&tab_non_stop_1.id)).unwrap(); +- assert_eq!(result.id, tab_stop_2.id); +- +- // Check that we skip over non-stop tabs +- let tab_stop_0 = FocusHandle::new(&focus_map).tab_stop(true).tab_index(0); +- let tab_non_stop_0 = FocusHandle::new(&focus_map).tab_stop(false).tab_index(0); +- tab_index_map.insert(&tab_stop_0); +- tab_index_map.insert(&tab_non_stop_0); +- let result = tab_index_map.next(Some(&tab_stop_0.id)).unwrap(); +- assert_eq!(result.id, tab_stop_2.id); +- } +- +- #[must_use] +- struct TabStopMapTest { +- tab_map: TabStopMap, +- focus_map: Arc, +- expected: Vec<(usize, FocusId)>, +- } +- +- impl TabStopMapTest { +- #[must_use] +- fn new() -> Self { +- Self { +- tab_map: TabStopMap::default(), +- focus_map: Arc::new(FocusMap::default()), +- expected: Vec::default(), +- } +- } +- +- #[must_use] +- fn tab_non_stop(mut self, index: isize) -> Self { +- let handle = FocusHandle::new(&self.focus_map) +- .tab_stop(false) +- .tab_index(index); +- self.tab_map.insert(&handle); +- self +- } +- +- #[must_use] +- fn tab_stop(mut self, index: isize, expected: usize) -> Self { +- let handle = FocusHandle::new(&self.focus_map) +- .tab_stop(true) +- .tab_index(index); +- self.tab_map.insert(&handle); +- self.expected.push((expected, handle.id)); +- self.expected.sort_by_key(|(expected, _)| *expected); +- self +- } +- +- #[must_use] +- fn tab_group(mut self, tab_index: isize, children: impl FnOnce(Self) -> Self) -> Self { +- self.tab_map.begin_group(tab_index); +- self = children(self); +- self.tab_map.end_group(); +- self +- } +- +- fn traverse_tab_map( +- &self, +- traverse: impl Fn(&TabStopMap, Option<&FocusId>) -> Option, +- ) -> Vec { +- let mut last_focus_id = None; +- let mut found = vec![]; +- for _ in 0..self.expected.len() { +- let handle = traverse(&self.tab_map, last_focus_id.as_ref()).unwrap(); +- last_focus_id = Some(handle.id); +- found.push(handle.id); +- } +- found +- } +- +- fn assert(self) { +- let mut expected = self.expected.iter().map(|(_, id)| *id).collect_vec(); +- +- // Check next order +- let forward_found = self.traverse_tab_map(|tab_map, prev| tab_map.next(prev)); +- assert_eq!(forward_found, expected); +- +- // Test overflow. Last to first +- assert_eq!( +- self.tab_map +- .next(forward_found.last()) +- .map(|handle| handle.id), +- expected.first().cloned() +- ); +- +- // Check previous order +- let reversed_found = self.traverse_tab_map(|tab_map, prev| tab_map.prev(prev)); +- expected.reverse(); +- assert_eq!(reversed_found, expected); +- +- // Test overflow. First to last +- assert_eq!( +- self.tab_map +- .prev(reversed_found.last()) +- .map(|handle| handle.id), +- expected.first().cloned(), +- ); +- } +- } +- +- #[test] +- fn test_with_disabled_tab_stop() { +- TabStopMapTest::new() +- .tab_stop(0, 0) +- .tab_non_stop(1) +- .tab_stop(2, 1) +- .tab_stop(3, 2) +- .assert(); +- } +- +- #[test] +- fn test_with_multiple_disabled_tab_stops() { +- TabStopMapTest::new() +- .tab_non_stop(0) +- .tab_stop(1, 0) +- .tab_non_stop(3) +- .tab_stop(3, 1) +- .tab_non_stop(4) +- .assert(); +- } +- +- #[test] +- fn test_tab_group_functionality() { +- TabStopMapTest::new() +- .tab_stop(0, 0) +- .tab_stop(0, 1) +- .tab_group(2, |t| t.tab_stop(0, 2).tab_stop(1, 3)) +- .tab_stop(3, 4) +- .tab_stop(4, 5) +- .assert() +- } +- +- #[test] +- fn test_sibling_groups() { +- TabStopMapTest::new() +- .tab_stop(0, 0) +- .tab_stop(1, 1) +- .tab_group(2, |test| test.tab_stop(0, 2).tab_stop(1, 3)) +- .tab_stop(3, 4) +- .tab_stop(4, 5) +- .tab_group(6, |test| test.tab_stop(0, 6).tab_stop(1, 7)) +- .tab_stop(7, 8) +- .tab_stop(8, 9) +- .assert(); +- } +- +- #[test] +- fn test_nested_group() { +- TabStopMapTest::new() +- .tab_stop(0, 0) +- .tab_stop(1, 1) +- .tab_group(2, |t| { +- t.tab_group(0, |t| t.tab_stop(0, 2).tab_stop(1, 3)) +- .tab_stop(1, 4) +- }) +- .tab_stop(3, 5) +- .tab_stop(4, 6) +- .assert(); +- } +- +- #[test] +- fn test_sibling_nested_groups() { +- TabStopMapTest::new() +- .tab_stop(0, 0) +- .tab_stop(1, 1) +- .tab_group(2, |builder| { +- builder +- .tab_stop(0, 2) +- .tab_stop(2, 5) +- .tab_group(1, |builder| builder.tab_stop(0, 3).tab_stop(1, 4)) +- .tab_group(3, |builder| builder.tab_stop(0, 6).tab_stop(1, 7)) +- }) +- .tab_stop(3, 8) +- .tab_stop(4, 9) +- .assert(); +- } +- +- #[test] +- fn test_sibling_nested_groups_out_of_order() { +- TabStopMapTest::new() +- .tab_stop(9, 9) +- .tab_stop(8, 8) +- .tab_group(7, |builder| { +- builder +- .tab_stop(0, 2) +- .tab_stop(2, 5) +- .tab_group(3, |builder| builder.tab_stop(1, 7).tab_stop(0, 6)) +- .tab_group(1, |builder| builder.tab_stop(0, 3).tab_stop(1, 4)) +- }) +- .tab_stop(3, 0) +- .tab_stop(4, 1) +- .assert(); +- } + } +diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs +index 19faa1135f..e81751f61c 100644 +--- a/crates/gpui/src/window.rs ++++ b/crates/gpui/src/window.rs +@@ -13,7 +13,7 @@ use crate::{ + Render, RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, Replay, ResizeEdge, + SMOOTH_SVG_SCALE_FACTOR, SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y, ScaledPixels, Scene, Shadow, + SharedString, Size, StrikethroughStyle, Style, SubscriberSet, Subscription, SystemWindowTab, +- SystemWindowTabController, TabStopMap, TaffyLayoutEngine, Task, TextStyle, TextStyleRefinement, ++ SystemWindowTabController, TabHandles, TaffyLayoutEngine, Task, TextStyle, TextStyleRefinement, + TransformationMatrix, Underline, UnderlineStyle, WindowAppearance, WindowBackgroundAppearance, + WindowBounds, WindowControls, WindowDecorations, WindowOptions, WindowParams, WindowTextSystem, + point, prelude::*, px, rems, size, transparent_black, +@@ -684,7 +684,7 @@ pub(crate) struct Frame { + pub(crate) next_inspector_instance_ids: FxHashMap, usize>, + #[cfg(any(feature = "inspector", debug_assertions))] + pub(crate) inspector_hitboxes: FxHashMap, +- pub(crate) tab_stops: TabStopMap, ++ pub(crate) tab_handles: TabHandles, + } + + #[derive(Clone, Default)] +@@ -733,7 +733,7 @@ impl Frame { + + #[cfg(any(feature = "inspector", debug_assertions))] + inspector_hitboxes: FxHashMap::default(), +- tab_stops: TabStopMap::default(), ++ tab_handles: TabHandles::default(), + } + } + +@@ -749,7 +749,7 @@ impl Frame { + self.hitboxes.clear(); + self.window_control_hitboxes.clear(); + self.deferred_draws.clear(); +- self.tab_stops.clear(); ++ self.tab_handles.clear(); + self.focus = None; + + #[cfg(any(feature = "inspector", debug_assertions))] +@@ -1415,7 +1415,7 @@ impl Window { + return; + } + +- if let Some(handle) = self.rendered_frame.tab_stops.next(self.focus.as_ref()) { ++ if let Some(handle) = self.rendered_frame.tab_handles.next(self.focus.as_ref()) { + self.focus(&handle) + } + } +@@ -1426,7 +1426,7 @@ impl Window { + return; + } + +- if let Some(handle) = self.rendered_frame.tab_stops.prev(self.focus.as_ref()) { ++ if let Some(handle) = self.rendered_frame.tab_handles.prev(self.focus.as_ref()) { + self.focus(&handle) + } + } +@@ -2285,7 +2285,7 @@ impl Window { + input_handlers_index: self.next_frame.input_handlers.len(), + cursor_styles_index: self.next_frame.cursor_styles.len(), + accessed_element_states_index: self.next_frame.accessed_element_states.len(), +- tab_handle_index: self.next_frame.tab_stops.paint_index(), ++ tab_handle_index: self.next_frame.tab_handles.handles.len(), + line_layout_index: self.text_system.layout_index(), + } + } +@@ -2315,9 +2315,11 @@ impl Window { + .iter() + .map(|(id, type_id)| (GlobalElementId(id.0.clone()), *type_id)), + ); +- self.next_frame.tab_stops.replay( +- &self.rendered_frame.tab_stops.insertion_history +- [range.start.tab_handle_index..range.end.tab_handle_index], ++ self.next_frame.tab_handles.handles.extend( ++ self.rendered_frame.tab_handles.handles ++ [range.start.tab_handle_index..range.end.tab_handle_index] ++ .iter() ++ .cloned(), + ); + + self.text_system +@@ -2732,19 +2734,6 @@ impl Window { + } + } + +- /// Executes the given closure within the context of a tab group. +- #[inline] +- pub fn with_tab_group(&mut self, index: Option, f: impl FnOnce(&mut Self) -> R) -> R { +- if let Some(index) = index { +- self.next_frame.tab_stops.begin_group(index); +- let result = f(self); +- self.next_frame.tab_stops.end_group(); +- result +- } else { +- f(self) +- } +- } +- + /// Defers the drawing of the given element, scheduling it to be painted on top of the currently-drawn tree + /// at a later time. The `priority` parameter determines the drawing order relative to other deferred elements, + /// with higher values being drawn on top. +@@ -4034,6 +4023,8 @@ impl Window { + let any_action = action.as_any(); + if action_type == any_action.type_id() { + cx.propagate_event = false; // Actions stop propagation by default during the bubble phase ++ cx.platform.on_action_triggered(action); ++ + listener(any_action, DispatchPhase::Bubble, self, cx); + + if !cx.propagate_event { +@@ -4051,6 +4042,7 @@ impl Window { + for listener in global_listeners.iter().rev() { + cx.propagate_event = false; // Actions stop propagation by default during the bubble phase + ++ cx.platform.on_action_triggered(action); + listener(action.as_any(), DispatchPhase::Bubble, cx); + if !cx.propagate_event { + break; +diff --git a/crates/keymap_editor/src/keymap_editor.rs b/crates/keymap_editor/src/keymap_editor.rs +index 23854df2e4..8a1e494d09 100644 +--- a/crates/keymap_editor/src/keymap_editor.rs ++++ b/crates/keymap_editor/src/keymap_editor.rs +@@ -1569,7 +1569,7 @@ impl Render for KeymapEditor { + h_flex() + .gap_2() + .child( +- h_flex() ++ div() + .key_context({ + let mut context = KeyContext::new_with_defaults(); + context.add("BufferSearchBar"); +diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs +index e6f11d38d2..b76bb7521b 100644 +--- a/crates/language/src/buffer.rs ++++ b/crates/language/src/buffer.rs +@@ -4628,12 +4628,12 @@ impl BufferSnapshot { + self.file.as_ref() + } + +- pub fn resolve_file_path(&self, include_root: bool, cx: &App) -> Option { ++ pub fn resolve_file_path(&self, cx: &App, include_root: bool) -> Option { + if let Some(file) = self.file() { + if file.path().file_name().is_none() || include_root { +- Some(file.full_path(cx).to_string_lossy().to_string()) ++ Some(file.full_path(cx)) + } else { +- Some(file.path().display(file.path_style(cx)).to_string()) ++ Some(file.path().as_std_path().to_owned()) + } + } else { + None +diff --git a/crates/language_model/src/language_model.rs b/crates/language_model/src/language_model.rs +index 38f2b09590..418a864648 100644 +--- a/crates/language_model/src/language_model.rs ++++ b/crates/language_model/src/language_model.rs +@@ -50,9 +50,6 @@ pub const OPEN_AI_PROVIDER_ID: LanguageModelProviderId = LanguageModelProviderId + pub const OPEN_AI_PROVIDER_NAME: LanguageModelProviderName = + LanguageModelProviderName::new("OpenAI"); + +-pub const X_AI_PROVIDER_ID: LanguageModelProviderId = LanguageModelProviderId::new("x_ai"); +-pub const X_AI_PROVIDER_NAME: LanguageModelProviderName = LanguageModelProviderName::new("xAI"); +- + pub const ZED_CLOUD_PROVIDER_ID: LanguageModelProviderId = LanguageModelProviderId::new("zed.dev"); + pub const ZED_CLOUD_PROVIDER_NAME: LanguageModelProviderName = + LanguageModelProviderName::new("Zed"); +diff --git a/crates/language_models/Cargo.toml b/crates/language_models/Cargo.toml +index 28cfe69d96..d4ae4b26b6 100644 +--- a/crates/language_models/Cargo.toml ++++ b/crates/language_models/Cargo.toml +@@ -28,6 +28,8 @@ convert_case.workspace = true + copilot.workspace = true + credentials_provider.workspace = true + deepseek = { workspace = true, features = ["schemars"] } ++editor.workspace = true ++feature_flags.workspace = true + fs.workspace = true + futures.workspace = true + google_ai = { workspace = true, features = ["schemars"] } +@@ -51,6 +53,7 @@ serde_json.workspace = true + settings.workspace = true + smol.workspace = true + strum.workspace = true ++theme.workspace = true + thiserror.workspace = true + tiktoken-rs.workspace = true + tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } +diff --git a/crates/language_models/src/provider/anthropic.rs b/crates/language_models/src/provider/anthropic.rs +index ae2d324b6f..c9cd56f632 100644 +--- a/crates/language_models/src/provider/anthropic.rs ++++ b/crates/language_models/src/provider/anthropic.rs +@@ -1,11 +1,14 @@ ++use crate::api_key::ApiKeyState; ++use crate::ui::InstructionListItem; + use anthropic::{ + ANTHROPIC_API_URL, AnthropicError, AnthropicModelMode, ContentDelta, Event, ResponseContent, + ToolResultContent, ToolResultPart, Usage, + }; + use anyhow::{Result, anyhow}; + use collections::{BTreeMap, HashMap}; ++use editor::{Editor, EditorElement, EditorStyle}; + use futures::{FutureExt, Stream, StreamExt, future, future::BoxFuture, stream::BoxStream}; +-use gpui::{AnyView, App, AsyncApp, Context, Entity, Task}; ++use gpui::{AnyView, App, AsyncApp, Context, Entity, FontStyle, Task, TextStyle, WhiteSpace}; + use http_client::HttpClient; + use language_model::{ + AuthenticateError, ConfigurationViewTargetAgent, LanguageModel, +@@ -20,14 +23,11 @@ use std::pin::Pin; + use std::str::FromStr; + use std::sync::{Arc, LazyLock}; + use strum::IntoEnumIterator; ++use theme::ThemeSettings; + use ui::{Icon, IconName, List, Tooltip, prelude::*}; +-use ui_input::SingleLineInput; + use util::{ResultExt, truncate_and_trailoff}; + use zed_env_vars::{EnvVar, env_var}; + +-use crate::api_key::ApiKeyState; +-use crate::ui::InstructionListItem; +- + pub use settings::AnthropicAvailableModel as AvailableModel; + + const PROVIDER_ID: LanguageModelProviderId = language_model::ANTHROPIC_PROVIDER_ID; +@@ -42,7 +42,7 @@ pub struct AnthropicSettings { + + pub struct AnthropicLanguageModelProvider { + http_client: Arc, +- state: Entity, ++ state: gpui::Entity, + } + + const API_KEY_ENV_VAR_NAME: &str = "ANTHROPIC_API_KEY"; +@@ -123,7 +123,7 @@ impl AnthropicLanguageModelProvider { + impl LanguageModelProviderState for AnthropicLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +@@ -226,7 +226,7 @@ impl LanguageModelProvider for AnthropicLanguageModelProvider { + pub struct AnthropicModel { + id: LanguageModelId, + model: anthropic::Model, +- state: Entity, ++ state: gpui::Entity, + http_client: Arc, + request_limiter: RateLimiter, + } +@@ -823,8 +823,8 @@ fn convert_usage(usage: &Usage) -> language_model::TokenUsage { + } + + struct ConfigurationView { +- api_key_editor: Entity, +- state: Entity, ++ api_key_editor: Entity, ++ state: gpui::Entity, + load_credentials_task: Option>, + target_agent: ConfigurationViewTargetAgent, + } +@@ -833,7 +833,7 @@ impl ConfigurationView { + const PLACEHOLDER_TEXT: &'static str = "sk-ant-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + + fn new( +- state: Entity, ++ state: gpui::Entity, + target_agent: ConfigurationViewTargetAgent, + window: &mut Window, + cx: &mut Context, +@@ -862,7 +862,11 @@ impl ConfigurationView { + })); + + Self { +- api_key_editor: cx.new(|cx| SingleLineInput::new(window, cx, Self::PLACEHOLDER_TEXT)), ++ api_key_editor: cx.new(|cx| { ++ let mut editor = Editor::single_line(window, cx); ++ editor.set_placeholder_text(Self::PLACEHOLDER_TEXT, window, cx); ++ editor ++ }), + state, + load_credentials_task, + target_agent, +@@ -901,6 +905,31 @@ impl ConfigurationView { + .detach_and_log_err(cx); + } + ++ fn render_api_key_editor(&self, cx: &mut Context) -> impl IntoElement { ++ let settings = ThemeSettings::get_global(cx); ++ let text_style = TextStyle { ++ color: cx.theme().colors().text, ++ font_family: settings.ui_font.family.clone(), ++ font_features: settings.ui_font.features.clone(), ++ font_fallbacks: settings.ui_font.fallbacks.clone(), ++ font_size: rems(0.875).into(), ++ font_weight: settings.ui_font.weight, ++ font_style: FontStyle::Normal, ++ line_height: relative(1.3), ++ white_space: WhiteSpace::Normal, ++ ..Default::default() ++ }; ++ EditorElement::new( ++ &self.api_key_editor, ++ EditorStyle { ++ background: cx.theme().colors().editor_background, ++ local_player: cx.theme().players().local(), ++ text: text_style, ++ ..Default::default() ++ }, ++ ) ++ } ++ + fn should_render_editor(&self, cx: &mut Context) -> bool { + !self.state.read(cx).is_authenticated() + } +@@ -933,7 +962,18 @@ impl Render for ConfigurationView { + InstructionListItem::text_only("Paste your API key below and hit enter to start using the agent") + ) + ) +- .child(self.api_key_editor.clone()) ++ .child( ++ h_flex() ++ .w_full() ++ .my_2() ++ .px_2() ++ .py_1() ++ .bg(cx.theme().colors().editor_background) ++ .border_1() ++ .border_color(cx.theme().colors().border) ++ .rounded_sm() ++ .child(self.render_api_key_editor(cx)), ++ ) + .child( + Label::new( + format!("You can also assign the {API_KEY_ENV_VAR_NAME} environment variable and restart Zed."), +diff --git a/crates/language_models/src/provider/bedrock.rs b/crates/language_models/src/provider/bedrock.rs +index 47dd565f6a..a81e4b30d2 100644 +--- a/crates/language_models/src/provider/bedrock.rs ++++ b/crates/language_models/src/provider/bedrock.rs +@@ -23,8 +23,12 @@ use bedrock::{ + }; + use collections::{BTreeMap, HashMap}; + use credentials_provider::CredentialsProvider; ++use editor::{Editor, EditorElement, EditorStyle}; + use futures::{FutureExt, Stream, StreamExt, future::BoxFuture, stream::BoxStream}; +-use gpui::{AnyView, App, AsyncApp, Context, Entity, FontWeight, Subscription, Task}; ++use gpui::{ ++ AnyView, App, AsyncApp, Context, Entity, FontStyle, FontWeight, Subscription, Task, TextStyle, ++ WhiteSpace, ++}; + use gpui_tokio::Tokio; + use http_client::HttpClient; + use language_model::{ +@@ -41,8 +45,8 @@ use serde_json::Value; + use settings::{BedrockAvailableModel as AvailableModel, Settings, SettingsStore}; + use smol::lock::OnceCell; + use strum::{EnumIter, IntoEnumIterator, IntoStaticStr}; ++use theme::ThemeSettings; + use ui::{Icon, IconName, List, Tooltip, prelude::*}; +-use ui_input::SingleLineInput; + use util::ResultExt; + + use crate::AllLanguageModelSettings; +@@ -239,7 +243,7 @@ impl State { + pub struct BedrockLanguageModelProvider { + http_client: AwsHttpClient, + handle: tokio::runtime::Handle, +- state: Entity, ++ state: gpui::Entity, + } + + impl BedrockLanguageModelProvider { +@@ -362,7 +366,7 @@ impl LanguageModelProvider for BedrockLanguageModelProvider { + impl LanguageModelProviderState for BedrockLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +@@ -373,7 +377,7 @@ struct BedrockModel { + http_client: AwsHttpClient, + handle: tokio::runtime::Handle, + client: OnceCell, +- state: Entity, ++ state: gpui::Entity, + request_limiter: RateLimiter, + } + +@@ -1006,11 +1010,11 @@ pub fn map_to_language_model_completion_events( + } + + struct ConfigurationView { +- access_key_id_editor: Entity, +- secret_access_key_editor: Entity, +- session_token_editor: Entity, +- region_editor: Entity, +- state: Entity, ++ access_key_id_editor: Entity, ++ secret_access_key_editor: Entity, ++ session_token_editor: Entity, ++ region_editor: Entity, ++ state: gpui::Entity, + load_credentials_task: Option>, + } + +@@ -1021,7 +1025,7 @@ impl ConfigurationView { + const PLACEHOLDER_SESSION_TOKEN_TEXT: &'static str = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; + const PLACEHOLDER_REGION: &'static str = "us-east-1"; + +- fn new(state: Entity, window: &mut Window, cx: &mut Context) -> Self { ++ fn new(state: gpui::Entity, window: &mut Window, cx: &mut Context) -> Self { + cx.observe(&state, |_, _, cx| { + cx.notify(); + }) +@@ -1047,19 +1051,24 @@ impl ConfigurationView { + + Self { + access_key_id_editor: cx.new(|cx| { +- SingleLineInput::new(window, cx, Self::PLACEHOLDER_ACCESS_KEY_ID_TEXT) +- .label("Access Key ID") ++ let mut editor = Editor::single_line(window, cx); ++ editor.set_placeholder_text(Self::PLACEHOLDER_ACCESS_KEY_ID_TEXT, window, cx); ++ editor + }), + secret_access_key_editor: cx.new(|cx| { +- SingleLineInput::new(window, cx, Self::PLACEHOLDER_SECRET_ACCESS_KEY_TEXT) +- .label("Secret Access Key") ++ let mut editor = Editor::single_line(window, cx); ++ editor.set_placeholder_text(Self::PLACEHOLDER_SECRET_ACCESS_KEY_TEXT, window, cx); ++ editor + }), + session_token_editor: cx.new(|cx| { +- SingleLineInput::new(window, cx, Self::PLACEHOLDER_SESSION_TOKEN_TEXT) +- .label("Session Token (Optional)") ++ let mut editor = Editor::single_line(window, cx); ++ editor.set_placeholder_text(Self::PLACEHOLDER_SESSION_TOKEN_TEXT, window, cx); ++ editor + }), + region_editor: cx.new(|cx| { +- SingleLineInput::new(window, cx, Self::PLACEHOLDER_REGION).label("Region") ++ let mut editor = Editor::single_line(window, cx); ++ editor.set_placeholder_text(Self::PLACEHOLDER_REGION, window, cx); ++ editor + }), + state, + load_credentials_task, +@@ -1139,6 +1148,41 @@ impl ConfigurationView { + .detach_and_log_err(cx); + } + ++ fn make_text_style(&self, cx: &Context) -> TextStyle { ++ let settings = ThemeSettings::get_global(cx); ++ TextStyle { ++ color: cx.theme().colors().text, ++ font_family: settings.ui_font.family.clone(), ++ font_features: settings.ui_font.features.clone(), ++ font_fallbacks: settings.ui_font.fallbacks.clone(), ++ font_size: rems(0.875).into(), ++ font_weight: settings.ui_font.weight, ++ font_style: FontStyle::Normal, ++ line_height: relative(1.3), ++ background_color: None, ++ underline: None, ++ strikethrough: None, ++ white_space: WhiteSpace::Normal, ++ text_overflow: None, ++ text_align: Default::default(), ++ line_clamp: None, ++ } ++ } ++ ++ fn make_input_styles(&self, cx: &Context) -> Div { ++ let bg_color = cx.theme().colors().editor_background; ++ let border_color = cx.theme().colors().border; ++ ++ h_flex() ++ .w_full() ++ .px_2() ++ .py_1() ++ .bg(bg_color) ++ .border_1() ++ .border_color(border_color) ++ .rounded_sm() ++ } ++ + fn should_render_editor(&self, cx: &Context) -> bool { + self.state.read(cx).is_authenticated() + } +@@ -1221,8 +1265,8 @@ impl Render for ConfigurationView { + ) + ) + ) +- .child(self.render_static_credentials_ui()) +- .child(self.region_editor.clone()) ++ .child(self.render_static_credentials_ui(cx)) ++ .child(self.render_common_fields(cx)) + .child( + Label::new( + format!("You can also assign the {ZED_BEDROCK_ACCESS_KEY_ID_VAR}, {ZED_BEDROCK_SECRET_ACCESS_KEY_VAR} AND {ZED_BEDROCK_REGION_VAR} environment variables and restart Zed."), +@@ -1243,7 +1287,63 @@ impl Render for ConfigurationView { + } + + impl ConfigurationView { +- fn render_static_credentials_ui(&self) -> AnyElement { ++ fn render_access_key_id_editor(&self, cx: &mut Context) -> impl IntoElement { ++ let text_style = self.make_text_style(cx); ++ ++ EditorElement::new( ++ &self.access_key_id_editor, ++ EditorStyle { ++ background: cx.theme().colors().editor_background, ++ local_player: cx.theme().players().local(), ++ text: text_style, ++ ..Default::default() ++ }, ++ ) ++ } ++ ++ fn render_secret_key_editor(&self, cx: &mut Context) -> impl IntoElement { ++ let text_style = self.make_text_style(cx); ++ ++ EditorElement::new( ++ &self.secret_access_key_editor, ++ EditorStyle { ++ background: cx.theme().colors().editor_background, ++ local_player: cx.theme().players().local(), ++ text: text_style, ++ ..Default::default() ++ }, ++ ) ++ } ++ ++ fn render_session_token_editor(&self, cx: &mut Context) -> impl IntoElement { ++ let text_style = self.make_text_style(cx); ++ ++ EditorElement::new( ++ &self.session_token_editor, ++ EditorStyle { ++ background: cx.theme().colors().editor_background, ++ local_player: cx.theme().players().local(), ++ text: text_style, ++ ..Default::default() ++ }, ++ ) ++ } ++ ++ fn render_region_editor(&self, cx: &mut Context) -> impl IntoElement { ++ let text_style = self.make_text_style(cx); ++ ++ EditorElement::new( ++ &self.region_editor, ++ EditorStyle { ++ background: cx.theme().colors().editor_background, ++ local_player: cx.theme().players().local(), ++ text: text_style, ++ ..Default::default() ++ }, ++ ) ++ } ++ ++ fn render_static_credentials_ui(&self, cx: &mut Context) -> AnyElement { + v_flex() + .my_2() + .gap_1p5() +@@ -1276,10 +1376,41 @@ impl ConfigurationView { + "Enter these credentials below", + )), + ) +- .child(self.access_key_id_editor.clone()) +- .child(self.secret_access_key_editor.clone()) +- .child(self.session_token_editor.clone()) +- .child(self.region_editor.clone()) ++ .child( ++ v_flex() ++ .gap_0p5() ++ .child(Label::new("Access Key ID").size(LabelSize::Small)) ++ .child( ++ self.make_input_styles(cx) ++ .child(self.render_access_key_id_editor(cx)), ++ ), ++ ) ++ .child( ++ v_flex() ++ .gap_0p5() ++ .child(Label::new("Secret Access Key").size(LabelSize::Small)) ++ .child(self.make_input_styles(cx).child(self.render_secret_key_editor(cx))), ++ ) ++ .child( ++ v_flex() ++ .gap_0p5() ++ .child(Label::new("Session Token (Optional)").size(LabelSize::Small)) ++ .child( ++ self.make_input_styles(cx) ++ .child(self.render_session_token_editor(cx)), ++ ), ++ ) ++ .into_any_element() ++ } ++ ++ fn render_common_fields(&self, cx: &mut Context) -> AnyElement { ++ v_flex() ++ .gap_0p5() ++ .child(Label::new("Region").size(LabelSize::Small)) ++ .child( ++ self.make_input_styles(cx) ++ .child(self.render_region_editor(cx)), ++ ) + .into_any_element() + } + } +diff --git a/crates/language_models/src/provider/cloud.rs b/crates/language_models/src/provider/cloud.rs +index 1c21e566d6..65fcae0f6a 100644 +--- a/crates/language_models/src/provider/cloud.rs ++++ b/crates/language_models/src/provider/cloud.rs +@@ -4,13 +4,14 @@ use anyhow::{Context as _, Result, anyhow}; + use chrono::{DateTime, Utc}; + use client::{Client, ModelRequestUsage, UserStore, zed_urls}; + use cloud_llm_client::{ +- CLIENT_SUPPORTS_STATUS_MESSAGES_HEADER_NAME, CLIENT_SUPPORTS_X_AI_HEADER_NAME, +- CURRENT_PLAN_HEADER_NAME, CompletionBody, CompletionEvent, CompletionRequestStatus, +- CountTokensBody, CountTokensResponse, EXPIRED_LLM_TOKEN_HEADER_NAME, ListModelsResponse, +- MODEL_REQUESTS_RESOURCE_HEADER_VALUE, Plan, PlanV1, PlanV2, +- SERVER_SUPPORTS_STATUS_MESSAGES_HEADER_NAME, SUBSCRIPTION_LIMIT_RESOURCE_HEADER_NAME, +- TOOL_USE_LIMIT_REACHED_HEADER_NAME, ZED_VERSION_HEADER_NAME, ++ CLIENT_SUPPORTS_STATUS_MESSAGES_HEADER_NAME, CURRENT_PLAN_HEADER_NAME, CompletionBody, ++ CompletionEvent, CompletionRequestStatus, CountTokensBody, CountTokensResponse, ++ EXPIRED_LLM_TOKEN_HEADER_NAME, ListModelsResponse, MODEL_REQUESTS_RESOURCE_HEADER_VALUE, Plan, ++ PlanV1, PlanV2, SERVER_SUPPORTS_STATUS_MESSAGES_HEADER_NAME, ++ SUBSCRIPTION_LIMIT_RESOURCE_HEADER_NAME, TOOL_USE_LIMIT_REACHED_HEADER_NAME, ++ ZED_VERSION_HEADER_NAME, + }; ++use feature_flags::{BillingV2FeatureFlag, FeatureFlagAppExt}; + use futures::{ + AsyncBufReadExt, FutureExt, Stream, StreamExt, future::BoxFuture, stream::BoxStream, + }; +@@ -46,7 +47,6 @@ use util::{ResultExt as _, maybe}; + use crate::provider::anthropic::{AnthropicEventMapper, count_anthropic_tokens, into_anthropic}; + use crate::provider::google::{GoogleEventMapper, into_google}; + use crate::provider::open_ai::{OpenAiEventMapper, count_open_ai_tokens, into_open_ai}; +-use crate::provider::x_ai::count_xai_tokens; + + const PROVIDER_ID: LanguageModelProviderId = language_model::ZED_CLOUD_PROVIDER_ID; + const PROVIDER_NAME: LanguageModelProviderName = language_model::ZED_CLOUD_PROVIDER_NAME; +@@ -77,7 +77,7 @@ impl From for AnthropicModelMode { + + pub struct CloudLanguageModelProvider { + client: Arc, +- state: Entity, ++ state: gpui::Entity, + _maintain_client_status: Task<()>, + } + +@@ -217,7 +217,6 @@ impl State { + + let request = http_client::Request::builder() + .method(Method::GET) +- .header(CLIENT_SUPPORTS_X_AI_HEADER_NAME, "true") + .uri(http_client.build_zed_llm_url("/models", &[])?.as_ref()) + .header("Authorization", format!("Bearer {token}")) + .body(AsyncBody::empty())?; +@@ -289,7 +288,7 @@ impl CloudLanguageModelProvider { + impl LanguageModelProviderState for CloudLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +@@ -581,7 +580,6 @@ impl LanguageModel for CloudLanguageModel { + Anthropic => language_model::ANTHROPIC_PROVIDER_ID, + OpenAi => language_model::OPEN_AI_PROVIDER_ID, + Google => language_model::GOOGLE_PROVIDER_ID, +- XAi => language_model::X_AI_PROVIDER_ID, + } + } + +@@ -591,7 +589,6 @@ impl LanguageModel for CloudLanguageModel { + Anthropic => language_model::ANTHROPIC_PROVIDER_NAME, + OpenAi => language_model::OPEN_AI_PROVIDER_NAME, + Google => language_model::GOOGLE_PROVIDER_NAME, +- XAi => language_model::X_AI_PROVIDER_NAME, + } + } + +@@ -622,8 +619,7 @@ impl LanguageModel for CloudLanguageModel { + fn tool_input_format(&self) -> LanguageModelToolSchemaFormat { + match self.model.provider { + cloud_llm_client::LanguageModelProvider::Anthropic +- | cloud_llm_client::LanguageModelProvider::OpenAi +- | cloud_llm_client::LanguageModelProvider::XAi => { ++ | cloud_llm_client::LanguageModelProvider::OpenAi => { + LanguageModelToolSchemaFormat::JsonSchema + } + cloud_llm_client::LanguageModelProvider::Google => { +@@ -653,7 +649,6 @@ impl LanguageModel for CloudLanguageModel { + }) + } + cloud_llm_client::LanguageModelProvider::OpenAi +- | cloud_llm_client::LanguageModelProvider::XAi + | cloud_llm_client::LanguageModelProvider::Google => None, + } + } +@@ -674,13 +669,6 @@ impl LanguageModel for CloudLanguageModel { + }; + count_open_ai_tokens(request, model, cx) + } +- cloud_llm_client::LanguageModelProvider::XAi => { +- let model = match x_ai::Model::from_id(&self.model.id.0) { +- Ok(model) => model, +- Err(err) => return async move { Err(anyhow!(err)) }.boxed(), +- }; +- count_xai_tokens(request, model, cx) +- } + cloud_llm_client::LanguageModelProvider::Google => { + let client = self.client.clone(); + let llm_api_token = self.llm_api_token.clone(); +@@ -858,56 +846,6 @@ impl LanguageModel for CloudLanguageModel { + }); + async move { Ok(future.await?.boxed()) }.boxed() + } +- cloud_llm_client::LanguageModelProvider::XAi => { +- let client = self.client.clone(); +- let model = match x_ai::Model::from_id(&self.model.id.0) { +- Ok(model) => model, +- Err(err) => return async move { Err(anyhow!(err).into()) }.boxed(), +- }; +- let request = into_open_ai( +- request, +- model.id(), +- model.supports_parallel_tool_calls(), +- model.supports_prompt_cache_key(), +- None, +- None, +- ); +- let llm_api_token = self.llm_api_token.clone(); +- let future = self.request_limiter.stream(async move { +- let PerformLlmCompletionResponse { +- response, +- usage, +- includes_status_messages, +- tool_use_limit_reached, +- } = Self::perform_llm_completion( +- client.clone(), +- llm_api_token, +- app_version, +- CompletionBody { +- thread_id, +- prompt_id, +- intent, +- mode, +- provider: cloud_llm_client::LanguageModelProvider::XAi, +- model: request.model.clone(), +- provider_request: serde_json::to_value(&request) +- .map_err(|e| anyhow!(e))?, +- }, +- ) +- .await?; +- +- let mut mapper = OpenAiEventMapper::new(); +- Ok(map_cloud_completion_events( +- Box::pin( +- response_lines(response, includes_status_messages) +- .chain(usage_updated_event(usage)) +- .chain(tool_use_limit_reached_event(tool_use_limit_reached)), +- ), +- move |event| mapper.map_event(event), +- )) +- }); +- async move { Ok(future.await?.boxed()) }.boxed() +- } + cloud_llm_client::LanguageModelProvider::Google => { + let client = self.client.clone(); + let request = +@@ -1036,10 +974,13 @@ struct ZedAiConfiguration { + } + + impl RenderOnce for ZedAiConfiguration { +- fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement { ++ fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { + let is_pro = self.plan.is_some_and(|plan| { + matches!(plan, Plan::V1(PlanV1::ZedPro) | Plan::V2(PlanV2::ZedPro)) + }); ++ let is_free_v2 = self ++ .plan ++ .is_some_and(|plan| plan == Plan::V2(PlanV2::ZedFree)); + let subscription_text = match (self.plan, self.subscription_period) { + (Some(Plan::V1(PlanV1::ZedPro) | Plan::V2(PlanV2::ZedPro)), Some(_)) => { + "You have access to Zed's hosted models through your Pro subscription." +@@ -1106,7 +1047,10 @@ impl RenderOnce for ZedAiConfiguration { + + v_flex().gap_2().w_full().map(|this| { + if self.account_too_young { +- this.child(YoungAccountBanner).child( ++ this.child(YoungAccountBanner::new( ++ is_free_v2 || cx.has_flag::(), ++ )) ++ .child( + Button::new("upgrade", "Upgrade to Pro") + .style(ui::ButtonStyle::Tinted(ui::TintColor::Accent)) + .full_width() +diff --git a/crates/language_models/src/provider/copilot_chat.rs b/crates/language_models/src/provider/copilot_chat.rs +index 64a2c65f0d..b7ece55fed 100644 +--- a/crates/language_models/src/provider/copilot_chat.rs ++++ b/crates/language_models/src/provider/copilot_chat.rs +@@ -89,7 +89,7 @@ impl CopilotChatLanguageModelProvider { + impl LanguageModelProviderState for CopilotChatLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +diff --git a/crates/language_models/src/provider/deepseek.rs b/crates/language_models/src/provider/deepseek.rs +index ec420bfd83..a8f08a4206 100644 +--- a/crates/language_models/src/provider/deepseek.rs ++++ b/crates/language_models/src/provider/deepseek.rs +@@ -1,10 +1,13 @@ + use anyhow::{Result, anyhow}; + use collections::{BTreeMap, HashMap}; + use deepseek::DEEPSEEK_API_URL; +- ++use editor::{Editor, EditorElement, EditorStyle}; + use futures::Stream; + use futures::{FutureExt, StreamExt, future, future::BoxFuture, stream::BoxStream}; +-use gpui::{AnyView, App, AsyncApp, Context, Entity, SharedString, Task, Window}; ++use gpui::{ ++ AnyView, App, AsyncApp, Context, Entity, FontStyle, SharedString, Task, TextStyle, WhiteSpace, ++ Window, ++}; + use http_client::HttpClient; + use language_model::{ + AuthenticateError, LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent, +@@ -18,9 +21,8 @@ use settings::{Settings, SettingsStore}; + use std::pin::Pin; + use std::str::FromStr; + use std::sync::{Arc, LazyLock}; +- ++use theme::ThemeSettings; + use ui::{Icon, IconName, List, prelude::*}; +-use ui_input::SingleLineInput; + use util::{ResultExt, truncate_and_trailoff}; + use zed_env_vars::{EnvVar, env_var}; + +@@ -525,15 +527,18 @@ impl DeepSeekEventMapper { + } + + struct ConfigurationView { +- api_key_editor: Entity, ++ api_key_editor: Entity, + state: Entity, + load_credentials_task: Option>, + } + + impl ConfigurationView { + fn new(state: Entity, window: &mut Window, cx: &mut Context) -> Self { +- let api_key_editor = +- cx.new(|cx| SingleLineInput::new(window, cx, "sk-00000000000000000000000000000000")); ++ let api_key_editor = cx.new(|cx| { ++ let mut editor = Editor::single_line(window, cx); ++ editor.set_placeholder_text("sk-00000000000000000000000000000000", window, cx); ++ editor ++ }); + + cx.observe(&state, |_, _, cx| { + cx.notify(); +@@ -593,6 +598,34 @@ impl ConfigurationView { + .detach_and_log_err(cx); + } + ++ fn render_api_key_editor(&self, cx: &mut Context) -> impl IntoElement { ++ let settings = ThemeSettings::get_global(cx); ++ let text_style = TextStyle { ++ color: cx.theme().colors().text, ++ font_family: settings.ui_font.family.clone(), ++ font_features: settings.ui_font.features.clone(), ++ font_fallbacks: settings.ui_font.fallbacks.clone(), ++ font_size: rems(0.875).into(), ++ font_weight: settings.ui_font.weight, ++ font_style: FontStyle::Normal, ++ line_height: relative(1.3), ++ background_color: None, ++ underline: None, ++ strikethrough: None, ++ white_space: WhiteSpace::Normal, ++ ..Default::default() ++ }; ++ EditorElement::new( ++ &self.api_key_editor, ++ EditorStyle { ++ background: cx.theme().colors().editor_background, ++ local_player: cx.theme().players().local(), ++ text: text_style, ++ ..Default::default() ++ }, ++ ) ++ } ++ + fn should_render_editor(&self, cx: &mut Context) -> bool { + !self.state.read(cx).is_authenticated() + } +@@ -620,7 +653,18 @@ impl Render for ConfigurationView { + "Paste your API key below and hit enter to start using the assistant", + )), + ) +- .child(self.api_key_editor.clone()) ++ .child( ++ h_flex() ++ .w_full() ++ .my_2() ++ .px_2() ++ .py_1() ++ .bg(cx.theme().colors().editor_background) ++ .border_1() ++ .border_color(cx.theme().colors().border) ++ .rounded_sm() ++ .child(self.render_api_key_editor(cx)), ++ ) + .child( + Label::new(format!( + "Or set the {API_KEY_ENV_VAR_NAME} environment variable." +diff --git a/crates/language_models/src/provider/google.rs b/crates/language_models/src/provider/google.rs +index f6ac364611..48712e33a7 100644 +--- a/crates/language_models/src/provider/google.rs ++++ b/crates/language_models/src/provider/google.rs +@@ -1,12 +1,16 @@ + use anyhow::{Context as _, Result, anyhow}; + use collections::BTreeMap; + use credentials_provider::CredentialsProvider; ++use editor::{Editor, EditorElement, EditorStyle}; + use futures::{FutureExt, Stream, StreamExt, future, future::BoxFuture}; + use google_ai::{ + FunctionDeclaration, GenerateContentResponse, GoogleModelMode, Part, SystemInstruction, + ThinkingConfig, UsageMetadata, + }; +-use gpui::{AnyView, App, AsyncApp, Context, Entity, SharedString, Task, Window}; ++use gpui::{ ++ AnyView, App, AsyncApp, Context, Entity, FontStyle, SharedString, Task, TextStyle, WhiteSpace, ++ Window, ++}; + use http_client::HttpClient; + use language_model::{ + AuthenticateError, ConfigurationViewTargetAgent, LanguageModelCompletionError, +@@ -28,8 +32,8 @@ use std::sync::{ + atomic::{self, AtomicU64}, + }; + use strum::IntoEnumIterator; ++use theme::ThemeSettings; + use ui::{Icon, IconName, List, Tooltip, prelude::*}; +-use ui_input::SingleLineInput; + use util::{ResultExt, truncate_and_trailoff}; + use zed_env_vars::EnvVar; + +@@ -59,7 +63,7 @@ pub enum ModelMode { + + pub struct GoogleLanguageModelProvider { + http_client: Arc, +- state: Entity, ++ state: gpui::Entity, + } + + pub struct State { +@@ -161,7 +165,7 @@ impl GoogleLanguageModelProvider { + impl LanguageModelProviderState for GoogleLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +@@ -251,7 +255,7 @@ impl LanguageModelProvider for GoogleLanguageModelProvider { + pub struct GoogleLanguageModel { + id: LanguageModelId, + model: google_ai::Model, +- state: Entity, ++ state: gpui::Entity, + http_client: Arc, + request_limiter: RateLimiter, + } +@@ -751,15 +755,15 @@ fn convert_usage(usage: &UsageMetadata) -> language_model::TokenUsage { + } + + struct ConfigurationView { +- api_key_editor: Entity, +- state: Entity, ++ api_key_editor: Entity, ++ state: gpui::Entity, + target_agent: language_model::ConfigurationViewTargetAgent, + load_credentials_task: Option>, + } + + impl ConfigurationView { + fn new( +- state: Entity, ++ state: gpui::Entity, + target_agent: language_model::ConfigurationViewTargetAgent, + window: &mut Window, + cx: &mut Context, +@@ -788,7 +792,11 @@ impl ConfigurationView { + })); + + Self { +- api_key_editor: cx.new(|cx| SingleLineInput::new(window, cx, "AIzaSy...")), ++ api_key_editor: cx.new(|cx| { ++ let mut editor = Editor::single_line(window, cx); ++ editor.set_placeholder_text("AIzaSy...", window, cx); ++ editor ++ }), + target_agent, + state, + load_credentials_task, +@@ -827,6 +835,31 @@ impl ConfigurationView { + .detach_and_log_err(cx); + } + ++ fn render_api_key_editor(&self, cx: &mut Context) -> impl IntoElement { ++ let settings = ThemeSettings::get_global(cx); ++ let text_style = TextStyle { ++ color: cx.theme().colors().text, ++ font_family: settings.ui_font.family.clone(), ++ font_features: settings.ui_font.features.clone(), ++ font_fallbacks: settings.ui_font.fallbacks.clone(), ++ font_size: rems(0.875).into(), ++ font_weight: settings.ui_font.weight, ++ font_style: FontStyle::Normal, ++ line_height: relative(1.3), ++ white_space: WhiteSpace::Normal, ++ ..Default::default() ++ }; ++ EditorElement::new( ++ &self.api_key_editor, ++ EditorStyle { ++ background: cx.theme().colors().editor_background, ++ local_player: cx.theme().players().local(), ++ text: text_style, ++ ..Default::default() ++ }, ++ ) ++ } ++ + fn should_render_editor(&self, cx: &mut Context) -> bool { + !self.state.read(cx).is_authenticated() + } +@@ -857,7 +890,18 @@ impl Render for ConfigurationView { + "Paste your API key below and hit enter to start using the assistant", + )), + ) +- .child(self.api_key_editor.clone()) ++ .child( ++ h_flex() ++ .w_full() ++ .my_2() ++ .px_2() ++ .py_1() ++ .bg(cx.theme().colors().editor_background) ++ .border_1() ++ .border_color(cx.theme().colors().border) ++ .rounded_sm() ++ .child(self.render_api_key_editor(cx)), ++ ) + .child( + Label::new( + format!("You can also assign the {GEMINI_API_KEY_VAR_NAME} environment variable and restart Zed."), +diff --git a/crates/language_models/src/provider/lmstudio.rs b/crates/language_models/src/provider/lmstudio.rs +index c0b3509c0e..f98906f5be 100644 +--- a/crates/language_models/src/provider/lmstudio.rs ++++ b/crates/language_models/src/provider/lmstudio.rs +@@ -2,7 +2,7 @@ use anyhow::{Result, anyhow}; + use collections::HashMap; + use futures::Stream; + use futures::{FutureExt, StreamExt, future::BoxFuture, stream::BoxStream}; +-use gpui::{AnyView, App, AsyncApp, Context, Entity, Subscription, Task}; ++use gpui::{AnyView, App, AsyncApp, Context, Subscription, Task}; + use http_client::HttpClient; + use language_model::{ + AuthenticateError, LanguageModelCompletionError, LanguageModelCompletionEvent, +@@ -41,7 +41,7 @@ pub struct LmStudioSettings { + + pub struct LmStudioLanguageModelProvider { + http_client: Arc, +- state: Entity, ++ state: gpui::Entity, + } + + pub struct State { +@@ -162,7 +162,7 @@ impl LmStudioLanguageModelProvider { + impl LanguageModelProviderState for LmStudioLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +@@ -635,12 +635,12 @@ fn add_message_content_part( + } + + struct ConfigurationView { +- state: Entity, ++ state: gpui::Entity, + loading_models_task: Option>, + } + + impl ConfigurationView { +- pub fn new(state: Entity, cx: &mut Context) -> Self { ++ pub fn new(state: gpui::Entity, cx: &mut Context) -> Self { + let loading_models_task = Some(cx.spawn({ + let state = state.clone(); + async move |this, cx| { +diff --git a/crates/language_models/src/provider/mistral.rs b/crates/language_models/src/provider/mistral.rs +index 7623f123c6..b3375e528c 100644 +--- a/crates/language_models/src/provider/mistral.rs ++++ b/crates/language_models/src/provider/mistral.rs +@@ -1,7 +1,11 @@ + use anyhow::{Result, anyhow}; + use collections::BTreeMap; ++use editor::{Editor, EditorElement, EditorStyle}; + use futures::{FutureExt, Stream, StreamExt, future, future::BoxFuture, stream::BoxStream}; +-use gpui::{AnyView, App, AsyncApp, Context, Entity, SharedString, Task, Window}; ++use gpui::{ ++ AnyView, App, AsyncApp, Context, Entity, FontStyle, SharedString, Task, TextStyle, WhiteSpace, ++ Window, ++}; + use http_client::HttpClient; + use language_model::{ + AuthenticateError, LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent, +@@ -18,8 +22,8 @@ use std::pin::Pin; + use std::str::FromStr; + use std::sync::{Arc, LazyLock}; + use strum::IntoEnumIterator; ++use theme::ThemeSettings; + use ui::{Icon, IconName, List, Tooltip, prelude::*}; +-use ui_input::SingleLineInput; + use util::{ResultExt, truncate_and_trailoff}; + use zed_env_vars::{EnvVar, env_var}; + +@@ -39,7 +43,7 @@ pub struct MistralSettings { + + pub struct MistralLanguageModelProvider { + http_client: Arc, +- state: Entity, ++ state: gpui::Entity, + } + + pub struct State { +@@ -117,7 +121,7 @@ impl MistralLanguageModelProvider { + impl LanguageModelProviderState for MistralLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +@@ -211,7 +215,7 @@ impl LanguageModelProvider for MistralLanguageModelProvider { + pub struct MistralLanguageModel { + id: LanguageModelId, + model: mistral::Model, +- state: Entity, ++ state: gpui::Entity, + http_client: Arc, + request_limiter: RateLimiter, + } +@@ -690,15 +694,18 @@ struct RawToolCall { + } + + struct ConfigurationView { +- api_key_editor: Entity, +- state: Entity, ++ api_key_editor: Entity, ++ state: gpui::Entity, + load_credentials_task: Option>, + } + + impl ConfigurationView { +- fn new(state: Entity, window: &mut Window, cx: &mut Context) -> Self { +- let api_key_editor = +- cx.new(|cx| SingleLineInput::new(window, cx, "0aBCDEFGhIjKLmNOpqrSTUVwxyzabCDE1f2")); ++ fn new(state: gpui::Entity, window: &mut Window, cx: &mut Context) -> Self { ++ let api_key_editor = cx.new(|cx| { ++ let mut editor = Editor::single_line(window, cx); ++ editor.set_placeholder_text("0aBCDEFGhIjKLmNOpqrSTUVwxyzabCDE1f2", window, cx); ++ editor ++ }); + + cx.observe(&state, |_, _, cx| { + cx.notify(); +@@ -763,6 +770,31 @@ impl ConfigurationView { + .detach_and_log_err(cx); + } + ++ fn render_api_key_editor(&self, cx: &mut Context) -> impl IntoElement { ++ let settings = ThemeSettings::get_global(cx); ++ let text_style = TextStyle { ++ color: cx.theme().colors().text, ++ font_family: settings.ui_font.family.clone(), ++ font_features: settings.ui_font.features.clone(), ++ font_fallbacks: settings.ui_font.fallbacks.clone(), ++ font_size: rems(0.875).into(), ++ font_weight: settings.ui_font.weight, ++ font_style: FontStyle::Normal, ++ line_height: relative(1.3), ++ white_space: WhiteSpace::Normal, ++ ..Default::default() ++ }; ++ EditorElement::new( ++ &self.api_key_editor, ++ EditorStyle { ++ background: cx.theme().colors().editor_background, ++ local_player: cx.theme().players().local(), ++ text: text_style, ++ ..Default::default() ++ }, ++ ) ++ } ++ + fn should_render_editor(&self, cx: &mut Context) -> bool { + !self.state.read(cx).is_authenticated() + } +@@ -793,7 +825,18 @@ impl Render for ConfigurationView { + "Paste your API key below and hit enter to start using the assistant", + )), + ) +- .child(self.api_key_editor.clone()) ++ .child( ++ h_flex() ++ .w_full() ++ .my_2() ++ .px_2() ++ .py_1() ++ .bg(cx.theme().colors().editor_background) ++ .border_1() ++ .border_color(cx.theme().colors().border) ++ .rounded_sm() ++ .child(self.render_api_key_editor(cx)), ++ ) + .child( + Label::new( + format!("You can also assign the {API_KEY_ENV_VAR_NAME} environment variable and restart Zed."), +diff --git a/crates/language_models/src/provider/ollama.rs b/crates/language_models/src/provider/ollama.rs +index d3a4289f24..9e9c88dd99 100644 +--- a/crates/language_models/src/provider/ollama.rs ++++ b/crates/language_models/src/provider/ollama.rs +@@ -2,7 +2,7 @@ use anyhow::{Result, anyhow}; + use fs::Fs; + use futures::{FutureExt, StreamExt, future::BoxFuture, stream::BoxStream}; + use futures::{Stream, TryFutureExt, stream}; +-use gpui::{AnyView, App, AsyncApp, Context, CursorStyle, Entity, Task}; ++use gpui::{AnyView, App, AsyncApp, Context, Task}; + use http_client::HttpClient; + use language_model::{ + AuthenticateError, LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent, +@@ -48,7 +48,7 @@ pub struct OllamaSettings { + + pub struct OllamaLanguageModelProvider { + http_client: Arc, +- state: Entity, ++ state: gpui::Entity, + } + + pub struct State { +@@ -209,7 +209,7 @@ impl OllamaLanguageModelProvider { + impl LanguageModelProviderState for OllamaLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +@@ -322,7 +322,7 @@ pub struct OllamaLanguageModel { + model: ollama::Model, + http_client: Arc, + request_limiter: RateLimiter, +- state: Entity, ++ state: gpui::Entity, + } + + impl OllamaLanguageModel { +@@ -623,13 +623,13 @@ fn map_to_language_model_completion_events( + } + + struct ConfigurationView { +- api_key_editor: Entity, +- api_url_editor: Entity, +- state: Entity, ++ api_key_editor: gpui::Entity, ++ api_url_editor: gpui::Entity, ++ state: gpui::Entity, + } + + impl ConfigurationView { +- pub fn new(state: Entity, window: &mut Window, cx: &mut Context) -> Self { ++ pub fn new(state: gpui::Entity, window: &mut Window, cx: &mut Context) -> Self { + let api_key_editor = + cx.new(|cx| SingleLineInput::new(window, cx, "63e02e...").label("API key")); + +@@ -900,7 +900,7 @@ impl Render for ConfigurationView { + this.child( + ButtonLike::new("connected") + .disabled(true) +- .cursor_style(CursorStyle::Arrow) ++ .cursor_style(gpui::CursorStyle::Arrow) + .child( + h_flex() + .gap_2() +diff --git a/crates/language_models/src/provider/open_ai.rs b/crates/language_models/src/provider/open_ai.rs +index 3eaaa8b585..ade2e47ca3 100644 +--- a/crates/language_models/src/provider/open_ai.rs ++++ b/crates/language_models/src/provider/open_ai.rs +@@ -41,7 +41,7 @@ pub struct OpenAiSettings { + + pub struct OpenAiLanguageModelProvider { + http_client: Arc, +- state: Entity, ++ state: gpui::Entity, + } + + pub struct State { +@@ -119,7 +119,7 @@ impl OpenAiLanguageModelProvider { + impl LanguageModelProviderState for OpenAiLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +@@ -203,7 +203,7 @@ impl LanguageModelProvider for OpenAiLanguageModelProvider { + pub struct OpenAiLanguageModel { + id: LanguageModelId, + model: open_ai::Model, +- state: Entity, ++ state: gpui::Entity, + http_client: Arc, + request_limiter: RateLimiter, + } +@@ -676,12 +676,12 @@ pub fn count_open_ai_tokens( + + struct ConfigurationView { + api_key_editor: Entity, +- state: Entity, ++ state: gpui::Entity, + load_credentials_task: Option>, + } + + impl ConfigurationView { +- fn new(state: Entity, window: &mut Window, cx: &mut Context) -> Self { ++ fn new(state: gpui::Entity, window: &mut Window, cx: &mut Context) -> Self { + let api_key_editor = cx.new(|cx| { + SingleLineInput::new( + window, +diff --git a/crates/language_models/src/provider/open_ai_compatible.rs b/crates/language_models/src/provider/open_ai_compatible.rs +index cca49c982c..788a412a82 100644 +--- a/crates/language_models/src/provider/open_ai_compatible.rs ++++ b/crates/language_models/src/provider/open_ai_compatible.rs +@@ -33,7 +33,7 @@ pub struct OpenAiCompatibleLanguageModelProvider { + id: LanguageModelProviderId, + name: LanguageModelProviderName, + http_client: Arc, +- state: Entity, ++ state: gpui::Entity, + } + + pub struct State { +@@ -125,7 +125,7 @@ impl OpenAiCompatibleLanguageModelProvider { + impl LanguageModelProviderState for OpenAiCompatibleLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +@@ -195,7 +195,7 @@ pub struct OpenAiCompatibleLanguageModel { + provider_id: LanguageModelProviderId, + provider_name: LanguageModelProviderName, + model: AvailableModel, +- state: Entity, ++ state: gpui::Entity, + http_client: Arc, + request_limiter: RateLimiter, + } +@@ -341,12 +341,12 @@ impl LanguageModel for OpenAiCompatibleLanguageModel { + + struct ConfigurationView { + api_key_editor: Entity, +- state: Entity, ++ state: gpui::Entity, + load_credentials_task: Option>, + } + + impl ConfigurationView { +- fn new(state: Entity, window: &mut Window, cx: &mut Context) -> Self { ++ fn new(state: gpui::Entity, window: &mut Window, cx: &mut Context) -> Self { + let api_key_editor = cx.new(|cx| { + SingleLineInput::new( + window, +diff --git a/crates/language_models/src/provider/open_router.rs b/crates/language_models/src/provider/open_router.rs +index 5bfc97c41f..bbc5c44cdc 100644 +--- a/crates/language_models/src/provider/open_router.rs ++++ b/crates/language_models/src/provider/open_router.rs +@@ -1,7 +1,10 @@ + use anyhow::{Result, anyhow}; + use collections::HashMap; ++use editor::{Editor, EditorElement, EditorStyle}; + use futures::{FutureExt, Stream, StreamExt, future, future::BoxFuture}; +-use gpui::{AnyView, App, AsyncApp, Context, Entity, SharedString, Task}; ++use gpui::{ ++ AnyView, App, AsyncApp, Context, Entity, FontStyle, SharedString, Task, TextStyle, WhiteSpace, ++}; + use http_client::HttpClient; + use language_model::{ + AuthenticateError, LanguageModel, LanguageModelCompletionError, LanguageModelCompletionEvent, +@@ -17,8 +20,8 @@ use settings::{OpenRouterAvailableModel as AvailableModel, Settings, SettingsSto + use std::pin::Pin; + use std::str::FromStr as _; + use std::sync::{Arc, LazyLock}; ++use theme::ThemeSettings; + use ui::{Icon, IconName, List, Tooltip, prelude::*}; +-use ui_input::SingleLineInput; + use util::{ResultExt, truncate_and_trailoff}; + use zed_env_vars::{EnvVar, env_var}; + +@@ -38,7 +41,7 @@ pub struct OpenRouterSettings { + + pub struct OpenRouterLanguageModelProvider { + http_client: Arc, +- state: Entity, ++ state: gpui::Entity, + } + + pub struct State { +@@ -171,7 +174,7 @@ impl OpenRouterLanguageModelProvider { + impl LanguageModelProviderState for OpenRouterLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +@@ -257,7 +260,7 @@ impl LanguageModelProvider for OpenRouterLanguageModelProvider { + pub struct OpenRouterLanguageModel { + id: LanguageModelId, + model: open_router::Model, +- state: Entity, ++ state: gpui::Entity, + http_client: Arc, + request_limiter: RateLimiter, + } +@@ -692,19 +695,21 @@ pub fn count_open_router_tokens( + } + + struct ConfigurationView { +- api_key_editor: Entity, +- state: Entity, ++ api_key_editor: Entity, ++ state: gpui::Entity, + load_credentials_task: Option>, + } + + impl ConfigurationView { +- fn new(state: Entity, window: &mut Window, cx: &mut Context) -> Self { ++ fn new(state: gpui::Entity, window: &mut Window, cx: &mut Context) -> Self { + let api_key_editor = cx.new(|cx| { +- SingleLineInput::new( ++ let mut editor = Editor::single_line(window, cx); ++ editor.set_placeholder_text( ++ "sk_or_000000000000000000000000000000000000000000000000", + window, + cx, +- "sk_or_000000000000000000000000000000000000000000000000", +- ) ++ ); ++ editor + }); + + cx.observe(&state, |_, _, cx| { +@@ -769,6 +774,31 @@ impl ConfigurationView { + .detach_and_log_err(cx); + } + ++ fn render_api_key_editor(&self, cx: &mut Context) -> impl IntoElement { ++ let settings = ThemeSettings::get_global(cx); ++ let text_style = TextStyle { ++ color: cx.theme().colors().text, ++ font_family: settings.ui_font.family.clone(), ++ font_features: settings.ui_font.features.clone(), ++ font_fallbacks: settings.ui_font.fallbacks.clone(), ++ font_size: rems(0.875).into(), ++ font_weight: settings.ui_font.weight, ++ font_style: FontStyle::Normal, ++ line_height: relative(1.3), ++ white_space: WhiteSpace::Normal, ++ ..Default::default() ++ }; ++ EditorElement::new( ++ &self.api_key_editor, ++ EditorStyle { ++ background: cx.theme().colors().editor_background, ++ local_player: cx.theme().players().local(), ++ text: text_style, ++ ..Default::default() ++ }, ++ ) ++ } ++ + fn should_render_editor(&self, cx: &mut Context) -> bool { + !self.state.read(cx).is_authenticated() + } +@@ -799,7 +829,18 @@ impl Render for ConfigurationView { + "Paste your API key below and hit enter to start using the assistant", + )), + ) +- .child(self.api_key_editor.clone()) ++ .child( ++ h_flex() ++ .w_full() ++ .my_2() ++ .px_2() ++ .py_1() ++ .bg(cx.theme().colors().editor_background) ++ .border_1() ++ .border_color(cx.theme().colors().border) ++ .rounded_sm() ++ .child(self.render_api_key_editor(cx)), ++ ) + .child( + Label::new( + format!("You can also assign the {API_KEY_ENV_VAR_NAME} environment variable and restart Zed."), +diff --git a/crates/language_models/src/provider/vercel.rs b/crates/language_models/src/provider/vercel.rs +index ad12e5a628..4b2ebb8a16 100644 +--- a/crates/language_models/src/provider/vercel.rs ++++ b/crates/language_models/src/provider/vercel.rs +@@ -36,7 +36,7 @@ pub struct VercelSettings { + + pub struct VercelLanguageModelProvider { + http_client: Arc, +- state: Entity, ++ state: gpui::Entity, + } + + pub struct State { +@@ -114,7 +114,7 @@ impl VercelLanguageModelProvider { + impl LanguageModelProviderState for VercelLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +@@ -195,7 +195,7 @@ impl LanguageModelProvider for VercelLanguageModelProvider { + pub struct VercelLanguageModel { + id: LanguageModelId, + model: vercel::Model, +- state: Entity, ++ state: gpui::Entity, + http_client: Arc, + request_limiter: RateLimiter, + } +@@ -363,12 +363,12 @@ pub fn count_vercel_tokens( + + struct ConfigurationView { + api_key_editor: Entity, +- state: Entity, ++ state: gpui::Entity, + load_credentials_task: Option>, + } + + impl ConfigurationView { +- fn new(state: Entity, window: &mut Window, cx: &mut Context) -> Self { ++ fn new(state: gpui::Entity, window: &mut Window, cx: &mut Context) -> Self { + let api_key_editor = cx.new(|cx| { + SingleLineInput::new( + window, +diff --git a/crates/language_models/src/provider/x_ai.rs b/crates/language_models/src/provider/x_ai.rs +index 4e9f591707..d75c8ce78c 100644 +--- a/crates/language_models/src/provider/x_ai.rs ++++ b/crates/language_models/src/provider/x_ai.rs +@@ -36,7 +36,7 @@ pub struct XAiSettings { + + pub struct XAiLanguageModelProvider { + http_client: Arc, +- state: Entity, ++ state: gpui::Entity, + } + + pub struct State { +@@ -114,7 +114,7 @@ impl XAiLanguageModelProvider { + impl LanguageModelProviderState for XAiLanguageModelProvider { + type ObservableEntity = State; + +- fn observable_entity(&self) -> Option> { ++ fn observable_entity(&self) -> Option> { + Some(self.state.clone()) + } + } +@@ -195,7 +195,7 @@ impl LanguageModelProvider for XAiLanguageModelProvider { + pub struct XAiLanguageModel { + id: LanguageModelId, + model: x_ai::Model, +- state: Entity, ++ state: gpui::Entity, + http_client: Arc, + request_limiter: RateLimiter, + } +@@ -357,12 +357,12 @@ pub fn count_xai_tokens( + + struct ConfigurationView { + api_key_editor: Entity, +- state: Entity, ++ state: gpui::Entity, + load_credentials_task: Option>, + } + + impl ConfigurationView { +- fn new(state: Entity, window: &mut Window, cx: &mut Context) -> Self { ++ fn new(state: gpui::Entity, window: &mut Window, cx: &mut Context) -> Self { + let api_key_editor = cx.new(|cx| { + SingleLineInput::new( + window, +diff --git a/crates/language_tools/src/lsp_button.rs b/crates/language_tools/src/lsp_button.rs +index 614eaa4f05..8bf40ccc1a 100644 +--- a/crates/language_tools/src/lsp_button.rs ++++ b/crates/language_tools/src/lsp_button.rs +@@ -162,7 +162,7 @@ impl LanguageServerState { + let relative_path = + abs_path.strip_prefix(&worktree.abs_path()).ok()?; + let relative_path = +- RelPath::new(relative_path, path_style) ++ RelPath::from_std_path(relative_path, path_style) + .log_err()?; + let entry = worktree.entry_for_path(&relative_path)?; + let project_path = +diff --git a/crates/languages/src/json.rs b/crates/languages/src/json.rs +index e59a369375..512653eab7 100644 +--- a/crates/languages/src/json.rs ++++ b/crates/languages/src/json.rs +@@ -55,8 +55,8 @@ impl ContextProvider for JsonTaskProvider { + let Some(file) = project::File::from_dyn(file.as_ref()).cloned() else { + return Task::ready(None); + }; +- let is_package_json = file.path.ends_with(RelPath::unix("package.json").unwrap()); +- let is_composer_json = file.path.ends_with(RelPath::unix("composer.json").unwrap()); ++ let is_package_json = file.path.ends_with(RelPath::new("package.json").unwrap()); ++ let is_composer_json = file.path.ends_with(RelPath::new("composer.json").unwrap()); + if !is_package_json && !is_composer_json { + return Task::ready(None); + } +diff --git a/crates/languages/src/python.rs b/crates/languages/src/python.rs +index a70137f3c2..8b6abc9c72 100644 +--- a/crates/languages/src/python.rs ++++ b/crates/languages/src/python.rs +@@ -55,7 +55,7 @@ impl ManifestProvider for PyprojectTomlManifestProvider { + }: ManifestQuery, + ) -> Option> { + for path in path.ancestors().take(depth) { +- let p = path.join(RelPath::unix("pyproject.toml").unwrap()); ++ let p = path.join(RelPath::new("pyproject.toml").unwrap()); + if delegate.exists(&p, Some(false)) { + return Some(path.into()); + } +@@ -107,13 +107,13 @@ impl TyLspAdapter { + + #[cfg(target_os = "linux")] + impl TyLspAdapter { +- const GITHUB_ASSET_KIND: AssetKind = AssetKind::TarGz; ++ const GITHUB_ASSET_KIND: AssetKind = AssetKind::Gz; + const ARCH_SERVER_NAME: &str = "unknown-linux-gnu"; + } + + #[cfg(target_os = "freebsd")] + impl TyLspAdapter { +- const GITHUB_ASSET_KIND: AssetKind = AssetKind::TarGz; ++ const GITHUB_ASSET_KIND: AssetKind = AssetKind::Gz; + const ARCH_SERVER_NAME: &str = "unknown-freebsd"; + } + +@@ -1030,7 +1030,7 @@ impl ToolchainLister for PythonToolchainProvider { + config.workspace_directories = Some( + subroot_relative_path + .ancestors() +- .map(|ancestor| worktree_root.join(ancestor.as_std_path())) ++ .map(|ancestor| worktree_root.join(ancestor)) + .collect(), + ); + for locator in locators.iter() { +diff --git a/crates/languages/src/rust.rs b/crates/languages/src/rust.rs +index 04a1eba033..b8f5c78dce 100644 +--- a/crates/languages/src/rust.rs ++++ b/crates/languages/src/rust.rs +@@ -92,7 +92,7 @@ impl ManifestProvider for CargoManifestProvider { + ) -> Option> { + let mut outermost_cargo_toml = None; + for path in path.ancestors().take(depth) { +- let p = path.join(RelPath::unix("Cargo.toml").unwrap()); ++ let p = path.join(RelPath::new("Cargo.toml").unwrap()); + if delegate.exists(&p, Some(false)) { + outermost_cargo_toml = Some(Arc::from(path)); + } +diff --git a/crates/languages/src/typescript.rs b/crates/languages/src/typescript.rs +index 4d1282e28a..6e3661fa6f 100644 +--- a/crates/languages/src/typescript.rs ++++ b/crates/languages/src/typescript.rs +@@ -269,7 +269,7 @@ impl TypeScriptContextProvider { + ) -> Task> { + let new_json_data = file_relative_path + .ancestors() +- .map(|path| worktree_root.join(path.as_std_path())) ++ .map(|path| worktree_root.join(path)) + .map(|parent_path| { + self.package_json_data(&parent_path, self.last_package_json.clone(), fs.clone(), cx) + }) +@@ -533,7 +533,7 @@ impl TypeScriptLspAdapter { + } + async fn tsdk_path(&self, adapter: &Arc) -> Option<&'static str> { + let is_yarn = adapter +- .read_text_file(RelPath::unix(".yarn/sdks/typescript/lib/typescript.js").unwrap()) ++ .read_text_file(RelPath::new(".yarn/sdks/typescript/lib/typescript.js").unwrap()) + .await + .is_ok(); + +diff --git a/crates/languages/src/vtsls.rs b/crates/languages/src/vtsls.rs +index 9124a64227..053d15775b 100644 +--- a/crates/languages/src/vtsls.rs ++++ b/crates/languages/src/vtsls.rs +@@ -36,7 +36,7 @@ impl VtslsLspAdapter { + + async fn tsdk_path(&self, adapter: &Arc) -> Option<&'static str> { + let is_yarn = adapter +- .read_text_file(RelPath::unix(".yarn/sdks/typescript/lib/typescript.js").unwrap()) ++ .read_text_file(RelPath::new(".yarn/sdks/typescript/lib/typescript.js").unwrap()) + .await + .is_ok(); + +diff --git a/crates/livekit_client/src/livekit_client.rs b/crates/livekit_client/src/livekit_client.rs +index 30a13bd910..45e929cb2e 100644 +--- a/crates/livekit_client/src/livekit_client.rs ++++ b/crates/livekit_client/src/livekit_client.rs +@@ -1,6 +1,6 @@ + use std::sync::Arc; + +-use anyhow::{Context as _, Result, anyhow}; ++use anyhow::{Context as _, Result}; + use audio::AudioSettings; + use collections::HashMap; + use futures::{SinkExt, channel::mpsc}; +@@ -12,10 +12,7 @@ use settings::Settings; + + mod playback; + +-use crate::{ +- LocalTrack, Participant, RemoteTrack, RoomEvent, TrackPublication, +- livekit_client::playback::Speaker, +-}; ++use crate::{LocalTrack, Participant, RemoteTrack, RoomEvent, TrackPublication}; + pub use playback::AudioStream; + pub(crate) use playback::{RemoteVideoFrame, play_remote_video_track}; + +@@ -135,20 +132,11 @@ impl Room { + track: &RemoteAudioTrack, + cx: &mut App, + ) -> Result { +- let speaker: Speaker = +- serde_urlencoded::from_str(&track.0.name()).unwrap_or_else(|_| Speaker { +- name: track.0.name(), +- is_staff: false, +- sends_legacy_audio: true, +- }); +- + if AudioSettings::get_global(cx).rodio_audio { + info!("Using experimental.rodio_audio audio pipeline for output"); +- playback::play_remote_audio_track(&track.0, speaker, cx) +- } else if speaker.sends_legacy_audio { +- Ok(self.playback.play_remote_audio_track(&track.0)) ++ playback::play_remote_audio_track(&track.0, cx) + } else { +- Err(anyhow!("Client version too old to play audio in call")) ++ Ok(self.playback.play_remote_audio_track(&track.0)) + } + } + } +diff --git a/crates/livekit_client/src/livekit_client/playback.rs b/crates/livekit_client/src/livekit_client/playback.rs +index cdd766453c..df8b5ea54f 100644 +--- a/crates/livekit_client/src/livekit_client/playback.rs ++++ b/crates/livekit_client/src/livekit_client/playback.rs +@@ -1,6 +1,6 @@ + use anyhow::{Context as _, Result}; + +-use audio::{AudioSettings, CHANNEL_COUNT, LEGACY_CHANNEL_COUNT, LEGACY_SAMPLE_RATE, SAMPLE_RATE}; ++use audio::{AudioSettings, CHANNEL_COUNT, SAMPLE_RATE}; + use cpal::traits::{DeviceTrait, StreamTrait as _}; + use futures::channel::mpsc::UnboundedSender; + use futures::{Stream, StreamExt as _}; +@@ -43,15 +43,12 @@ pub(crate) struct AudioStack { + + pub(crate) fn play_remote_audio_track( + track: &livekit::track::RemoteAudioTrack, +- speaker: Speaker, + cx: &mut gpui::App, + ) -> Result { +- info!("speaker: {speaker:?}"); +- let stream = +- source::LiveKitStream::new(cx.background_executor(), track, speaker.sends_legacy_audio); +- + let stop_handle = Arc::new(AtomicBool::new(false)); + let stop_handle_clone = stop_handle.clone(); ++ let stream = source::LiveKitStream::new(cx.background_executor(), track); ++ + let stream = stream + .stoppable() + .periodic_access(Duration::from_millis(50), move |s| { +@@ -60,8 +57,10 @@ pub(crate) fn play_remote_audio_track( + } + }); + +- info!("sample_rate: {:?}", stream.sample_rate()); +- info!("channel_count: {:?}", stream.channels()); ++ let speaker: Speaker = serde_urlencoded::from_str(&track.name()).unwrap_or_else(|_| Speaker { ++ name: track.name(), ++ is_staff: false, ++ }); + audio::Audio::play_voip_stream(stream, speaker.name, speaker.is_staff, cx) + .context("Could not play audio")?; + +@@ -97,8 +96,8 @@ impl AudioStack { + let next_ssrc = self.next_ssrc.fetch_add(1, Ordering::Relaxed); + let source = AudioMixerSource { + ssrc: next_ssrc, +- sample_rate: LEGACY_SAMPLE_RATE.get(), +- num_channels: LEGACY_CHANNEL_COUNT.get() as u32, ++ sample_rate: SAMPLE_RATE.get(), ++ num_channels: CHANNEL_COUNT.get() as u32, + buffer: Arc::default(), + }; + self.mixer.lock().add_source(source.clone()); +@@ -138,14 +137,9 @@ impl AudioStack { + let apm = self.apm.clone(); + let mixer = self.mixer.clone(); + async move { +- Self::play_output( +- apm, +- mixer, +- LEGACY_SAMPLE_RATE.get(), +- LEGACY_CHANNEL_COUNT.get().into(), +- ) +- .await +- .log_err(); ++ Self::play_output(apm, mixer, SAMPLE_RATE.get(), CHANNEL_COUNT.get().into()) ++ .await ++ .log_err(); + } + })); + *self._output_task.borrow_mut() = Arc::downgrade(&task); +@@ -158,36 +152,19 @@ impl AudioStack { + is_staff: bool, + cx: &AsyncApp, + ) -> Result<(crate::LocalAudioTrack, AudioStream)> { +- let legacy_audio_compatible = +- AudioSettings::try_read_global(cx, |setting| setting.legacy_audio_compatible) +- .unwrap_or(true); +- +- let source = if legacy_audio_compatible { +- NativeAudioSource::new( +- // n.b. this struct's options are always ignored, noise cancellation is provided by apm. +- AudioSourceOptions::default(), +- LEGACY_SAMPLE_RATE.get(), +- LEGACY_CHANNEL_COUNT.get().into(), +- 10, +- ) +- } else { +- NativeAudioSource::new( +- // n.b. this struct's options are always ignored, noise cancellation is provided by apm. +- AudioSourceOptions::default(), +- SAMPLE_RATE.get(), +- CHANNEL_COUNT.get().into(), +- 10, +- ) +- }; ++ let source = NativeAudioSource::new( ++ // n.b. this struct's options are always ignored, noise cancellation is provided by apm. ++ AudioSourceOptions::default(), ++ SAMPLE_RATE.get(), ++ CHANNEL_COUNT.get().into(), ++ 10, ++ ); + +- let speaker = Speaker { ++ let track_name = serde_urlencoded::to_string(Speaker { + name: user_name, + is_staff, +- sends_legacy_audio: legacy_audio_compatible, +- }; +- log::info!("Microphone speaker: {speaker:?}"); +- let track_name = serde_urlencoded::to_string(speaker) +- .context("Could not encode user information in track name")?; ++ }) ++ .context("Could not encode user information in track name")?; + + let track = track::LocalAudioTrack::create_audio_track( + &track_name, +@@ -209,32 +186,22 @@ impl AudioStack { + let capture_task = if rodio_pipeline { + info!("Using experimental.rodio_audio audio pipeline"); + let voip_parts = audio::VoipParts::new(cx)?; +- // Audio needs to run real-time and should never be paused. That is +- // why we are using a normal std::thread and not a background task ++ // Audio needs to run real-time and should never be paused. That is why we are using a ++ // normal std::thread and not a background task + thread::Builder::new() +- .name("MicrophoneToLivekit".to_string()) ++ .name("AudioCapture".to_string()) + .spawn(move || { + // microphone is non send on mac +- let microphone = match audio::Audio::open_microphone(voip_parts) { +- Ok(m) => m, +- Err(e) => { +- log::error!("Could not open microphone: {e}"); +- return; +- } +- }; ++ let microphone = audio::Audio::open_microphone(voip_parts)?; + send_to_livekit(frame_tx, microphone); ++ Ok::<(), anyhow::Error>(()) + }) +- .expect("should be able to spawn threads"); ++ .unwrap(); + Task::ready(Ok(())) + } else { + self.executor.spawn(async move { +- Self::capture_input( +- apm, +- frame_tx, +- LEGACY_SAMPLE_RATE.get(), +- LEGACY_CHANNEL_COUNT.get().into(), +- ) +- .await ++ Self::capture_input(apm, frame_tx, SAMPLE_RATE.get(), CHANNEL_COUNT.get().into()) ++ .await + }) + }; + +@@ -421,31 +388,26 @@ impl AudioStack { + } + } + +-#[derive(Serialize, Deserialize, Debug)] +-pub struct Speaker { +- pub name: String, +- pub is_staff: bool, +- pub sends_legacy_audio: bool, ++#[derive(Serialize, Deserialize)] ++struct Speaker { ++ name: String, ++ is_staff: bool, + } + + fn send_to_livekit(frame_tx: UnboundedSender>, mut microphone: impl Source) { + use cpal::Sample; +- let sample_rate = microphone.sample_rate().get(); +- let num_channels = microphone.channels().get() as u32; +- let buffer_size = sample_rate / 100 * num_channels; +- + loop { + let sampled: Vec<_> = microphone + .by_ref() +- .take(buffer_size as usize) ++ .take(audio::BUFFER_SIZE) + .map(|s| s.to_sample()) + .collect(); + + if frame_tx + .unbounded_send(AudioFrame { +- sample_rate, +- num_channels, +- samples_per_channel: sampled.len() as u32 / num_channels, ++ sample_rate: SAMPLE_RATE.get(), ++ num_channels: CHANNEL_COUNT.get() as u32, ++ samples_per_channel: sampled.len() as u32 / CHANNEL_COUNT.get() as u32, + data: Cow::Owned(sampled), + }) + .is_err() +diff --git a/crates/livekit_client/src/livekit_client/playback/source.rs b/crates/livekit_client/src/livekit_client/playback/source.rs +index cde4b19fda..f605b3d517 100644 +--- a/crates/livekit_client/src/livekit_client/playback/source.rs ++++ b/crates/livekit_client/src/livekit_client/playback/source.rs +@@ -3,19 +3,17 @@ use std::num::NonZero; + use futures::StreamExt; + use libwebrtc::{audio_stream::native::NativeAudioStream, prelude::AudioFrame}; + use livekit::track::RemoteAudioTrack; +-use rodio::{ +- ChannelCount, SampleRate, Source, buffer::SamplesBuffer, conversions::SampleTypeConverter, +-}; ++use rodio::{Source, buffer::SamplesBuffer, conversions::SampleTypeConverter, nz}; + +-use audio::{CHANNEL_COUNT, LEGACY_CHANNEL_COUNT, LEGACY_SAMPLE_RATE, SAMPLE_RATE}; ++use audio::{CHANNEL_COUNT, SAMPLE_RATE}; + + fn frame_to_samplesbuffer(frame: AudioFrame) -> SamplesBuffer { + let samples = frame.data.iter().copied(); + let samples = SampleTypeConverter::<_, _>::new(samples); + let samples: Vec = samples.collect(); + SamplesBuffer::new( +- NonZero::new(frame.num_channels as u16).expect("zero channels is nonsense"), +- NonZero::new(frame.sample_rate).expect("samplerate zero is nonsense"), ++ nz!(2), // frame always has two channels ++ NonZero::new(frame.sample_rate).expect("audio frame sample rate is nonzero"), + samples, + ) + } +@@ -24,26 +22,14 @@ pub struct LiveKitStream { + // shared_buffer: SharedBuffer, + inner: rodio::queue::SourcesQueueOutput, + _receiver_task: gpui::Task<()>, +- channel_count: ChannelCount, +- sample_rate: SampleRate, + } + + impl LiveKitStream { +- pub fn new( +- executor: &gpui::BackgroundExecutor, +- track: &RemoteAudioTrack, +- legacy: bool, +- ) -> Self { +- let (channel_count, sample_rate) = if legacy { +- (LEGACY_CHANNEL_COUNT, LEGACY_SAMPLE_RATE) +- } else { +- (CHANNEL_COUNT, SAMPLE_RATE) +- }; +- ++ pub fn new(executor: &gpui::BackgroundExecutor, track: &RemoteAudioTrack) -> Self { + let mut stream = NativeAudioStream::new( + track.rtc_track(), +- sample_rate.get() as i32, +- channel_count.get().into(), ++ SAMPLE_RATE.get() as i32, ++ CHANNEL_COUNT.get().into(), + ); + let (queue_input, queue_output) = rodio::queue::queue(true); + // spawn rtc stream +@@ -59,8 +45,6 @@ impl LiveKitStream { + LiveKitStream { + _receiver_task: receiver_task, + inner: queue_output, +- sample_rate, +- channel_count, + } + } + } +@@ -79,11 +63,17 @@ impl Source for LiveKitStream { + } + + fn channels(&self) -> rodio::ChannelCount { +- self.channel_count ++ // This must be hardcoded because the playback source assumes constant ++ // sample rate and channel count. The queue upon which this is build ++ // will however report different counts and rates. Even though we put in ++ // only items with our (constant) CHANNEL_COUNT & SAMPLE_RATE this will ++ // play silence on one channel and at 44100 which is not what our ++ // constants are. ++ CHANNEL_COUNT + } + + fn sample_rate(&self) -> rodio::SampleRate { +- self.sample_rate ++ SAMPLE_RATE // see comment on channels + } + + fn total_duration(&self) -> Option { +diff --git a/crates/macos_appkit_bridge/build.rs b/crates/macos_appkit_bridge/build.rs +new file mode 100644 +index 0000000000..e9cb6e0d5e +--- /dev/null ++++ b/crates/macos_appkit_bridge/build.rs +@@ -0,0 +1,53 @@ ++#[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 ++ ++ // Rebuild when the Swift sources change. ++ println!("cargo:rerun-if-changed=swift/Package.swift"); ++ println!("cargo:rerun-if-changed=swift/Sources"); ++ ++ // Select target architecture so cross-compiles (e.g. x86_64 on arm64) link correctly. ++ let target = std::env::var("TARGET").expect("TARGET unset"); ++ let arch_flag = match target.as_str() { ++ "aarch64-apple-darwin" => Some("arm64"), ++ "x86_64-apple-darwin" => Some("x86_64"), ++ _ => None, ++ }; ++ ++ // Build the Swift package containing our shim and the generated bridge. ++ let mut build_cmd = std::process::Command::new("swift"); ++ build_cmd.current_dir(&swift_dir).args(["build", "-c", "release"]); ++ if let Some(arch) = arch_flag { ++ build_cmd.args(["--arch", arch]); ++ } ++ let status = build_cmd.status().expect("Failed to spawn swift build"); ++ if !status.success() { ++ panic!("swift build failed: {:?}", status); ++ } ++ ++ // Link the produced static library; prefer arch-specific directory when present. ++ let arch_lib_dir = arch_flag.map(|arch| { ++ swift_dir ++ .join(".build") ++ .join(format!("{}-apple-macosx", arch)) ++ .join("release") ++ }); ++ let generic_lib_dir = swift_dir.join(".build").join("release"); ++ let lib_dir = arch_lib_dir ++ .as_ref() ++ .filter(|path| path.exists()) ++ .unwrap_or(&generic_lib_dir); ++ 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/outline_panel/src/outline_panel.rs b/crates/outline_panel/src/outline_panel.rs +index a2c404af80..4ba6369218 100644 +--- a/crates/outline_panel/src/outline_panel.rs ++++ b/crates/outline_panel/src/outline_panel.rs +@@ -6660,7 +6660,7 @@ outline: struct OutlineEntryExcerpt + .read(cx) + .root_name() + .join(&directory.entry.path) +- .as_unix_str() ++ .as_str() + .to_string() + } else { + directory +diff --git a/crates/paths/src/paths.rs b/crates/paths/src/paths.rs +index ac68cf8631..b860cc1b02 100644 +--- a/crates/paths/src/paths.rs ++++ b/crates/paths/src/paths.rs +@@ -31,12 +31,12 @@ static CONFIG_DIR: OnceLock = OnceLock::new(); + + /// Returns the relative path to the zed_server directory on the ssh host. + pub fn remote_server_dir_relative() -> &'static RelPath { +- RelPath::unix(".zed_server").unwrap() ++ RelPath::new(".zed_server").unwrap() + } + + /// Returns the relative path to the zed_wsl_server directory on the wsl host. + pub fn remote_wsl_server_dir_relative() -> &'static RelPath { +- RelPath::unix(".zed_wsl_server").unwrap() ++ RelPath::new(".zed_wsl_server").unwrap() + } + + /// Sets a custom directory for all user data, overriding the default data directory. +@@ -410,17 +410,17 @@ pub fn local_vscode_folder_name() -> &'static str { + + /// Returns the relative path to a `settings.json` file within a project. + pub fn local_settings_file_relative_path() -> &'static RelPath { +- RelPath::unix(".zed/settings.json").unwrap() ++ RelPath::new(".zed/settings.json").unwrap() + } + + /// Returns the relative path to a `tasks.json` file within a project. + pub fn local_tasks_file_relative_path() -> &'static RelPath { +- RelPath::unix(".zed/tasks.json").unwrap() ++ RelPath::new(".zed/tasks.json").unwrap() + } + + /// Returns the relative path to a `.vscode/tasks.json` file within a project. + pub fn local_vscode_tasks_file_relative_path() -> &'static RelPath { +- RelPath::unix(".vscode/tasks.json").unwrap() ++ RelPath::new(".vscode/tasks.json").unwrap() + } + + pub fn debug_task_file_name() -> &'static str { +@@ -434,12 +434,12 @@ pub fn task_file_name() -> &'static str { + /// Returns the relative path to a `debug.json` file within a project. + /// .zed/debug.json + pub fn local_debug_file_relative_path() -> &'static RelPath { +- RelPath::unix(".zed/debug.json").unwrap() ++ RelPath::new(".zed/debug.json").unwrap() + } + + /// Returns the relative path to a `.vscode/launch.json` file within a project. + pub fn local_vscode_launch_file_relative_path() -> &'static RelPath { +- RelPath::unix(".vscode/launch.json").unwrap() ++ RelPath::new(".vscode/launch.json").unwrap() + } + + pub fn user_ssh_config_file() -> PathBuf { +diff --git a/crates/project/src/git_store.rs b/crates/project/src/git_store.rs +index 1a6f966b89..168549d4eb 100644 +--- a/crates/project/src/git_store.rs ++++ b/crates/project/src/git_store.rs +@@ -989,7 +989,7 @@ impl GitStore { + parse_git_remote_url(provider_registry, &origin_url) + .context("parsing Git remote URL")?; + +- let path = repo_path.as_unix_str(); ++ let path = repo_path.as_str(); + + Ok(provider.build_permalink( + remote, +@@ -1315,7 +1315,7 @@ impl GitStore { + }); + if let Some((repo, path)) = self.repository_and_path_for_buffer_id(buffer_id, cx) { + let recv = repo.update(cx, |repo, cx| { +- log::debug!("hunks changed for {}", path.as_unix_str()); ++ log::debug!("hunks changed for {}", path.as_str()); + repo.spawn_set_index_text_job( + path, + new_index_text.as_ref().map(|rope| rope.to_string()), +@@ -3118,7 +3118,7 @@ impl Repository { + let repo_path = this.abs_path_to_repo_path(&abs_path)?; + log::debug!( + "start reload diff bases for repo path {}", +- repo_path.as_unix_str() ++ repo_path.as_str() + ); + diff_state.update(cx, |diff_state, _| { + let has_unstaged_diff = diff_state +@@ -4162,10 +4162,7 @@ impl Repository { + Some(GitJobKey::WriteIndex(path.clone())), + None, + move |git_repo, mut cx| async move { +- log::debug!( +- "start updating index text for buffer {}", +- path.as_unix_str() +- ); ++ log::debug!("start updating index text for buffer {}", path.as_str()); + match git_repo { + RepositoryState::Local { + backend, +@@ -4187,10 +4184,7 @@ impl Repository { + .await?; + } + } +- log::debug!( +- "finish updating index text for buffer {}", +- path.as_unix_str() +- ); ++ log::debug!("finish updating index text for buffer {}", path.as_str()); + + if let Some(hunk_staging_operation_count) = hunk_staging_operation_count { + let project_path = this +diff --git a/crates/project/src/git_store/git_traversal.rs b/crates/project/src/git_store/git_traversal.rs +index ca4a22b14d..3da56b0246 100644 +--- a/crates/project/src/git_store/git_traversal.rs ++++ b/crates/project/src/git_store/git_traversal.rs +@@ -332,7 +332,7 @@ mod tests { + + let traversal = GitTraversal::new( + &repo_snapshots, +- worktree_snapshot.traverse_from_path(true, false, true, RelPath::unix("x").unwrap()), ++ worktree_snapshot.traverse_from_path(true, false, true, RelPath::new("x").unwrap()), + ); + let entries = traversal + .map(|entry| (entry.path.clone(), entry.git_summary)) +diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs +index ce1b52999a..77ec10d01e 100644 +--- a/crates/project/src/lsp_store.rs ++++ b/crates/project/src/lsp_store.rs +@@ -1850,7 +1850,7 @@ impl LocalLspStore { + if !extra_buffers.is_empty() { + extra_buffers.push_str(", "); + } +- extra_buffers.push_str(path.path.as_unix_str()); ++ extra_buffers.push_str(path.path.as_str()); + } + }) + .ok(); +@@ -3284,7 +3284,7 @@ impl LocalLspStore { + let literal_prefix = glob_literal_prefix(relative); + Some(( + worktree.clone(), +- RelPath::new(&literal_prefix, path_style).ok()?.into_arc(), ++ RelPath::from_std_path(&literal_prefix, path_style).ok()?, + relative.to_string_lossy().to_string(), + )) + } +@@ -3300,7 +3300,7 @@ impl LocalLspStore { + literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern))); + Some(( + worktree.clone(), +- RelPath::new(&literal_prefix, path_style).ok()?.into_arc(), ++ RelPath::from_std_path(&literal_prefix, path_style).ok()?, + rp.pattern.clone(), + )) + } +@@ -7936,8 +7936,11 @@ impl LspStore { + let relative_path = if let Some(known_path) = known_relative_path { + known_path + } else { +- RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())? +- .into_arc() ++ RelPath::from_std_path( ++ abs_path.strip_prefix(worktree_root)?, ++ PathStyle::local(), ++ ) ++ .context("failed to create relative path")? + }; + (worktree, relative_path) + }; +diff --git a/crates/project/src/manifest_tree/path_trie.rs b/crates/project/src/manifest_tree/path_trie.rs +index 9710bb46d0..2dd301fb13 100644 +--- a/crates/project/src/manifest_tree/path_trie.rs ++++ b/crates/project/src/manifest_tree/path_trie.rs +@@ -61,7 +61,7 @@ impl RootPathTrie