diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 497b6ba1..a36a57aa 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -10,7 +10,13 @@ "Bash(git show:*)", "WebFetch(domain:stackoverflow.com)", "WebFetch(domain:www.electronjs.org)", - "WebFetch(domain:www.electron.build)" + "WebFetch(domain:www.electron.build)", + "Bash(cargo test)", + "Bash(cargo test:*)", + "Bash(bun:*)", + "Bash(cargo clippy:*)", + "Bash(cargo clean:*)", + "Bash(awk:*)" ], "deny": [], "ask": [] diff --git a/.github/workflows/ci-controller.yml b/.github/workflows/ci-controller.yml index e103892b..1127ed30 100644 --- a/.github/workflows/ci-controller.yml +++ b/.github/workflows/ci-controller.yml @@ -3,16 +3,19 @@ name: CI Controller on: push: branches: - - '**' + - 'main' + - 'dev' pull_request: branches: - - main - - dev + - '**' jobs: run-tests: uses: ./.github/workflows/test-runner.yml + native-build-check: + uses: ./.github/workflows/native-build-check.yml + # This job ONLY runs for pushes to 'dev' and 'main' deploy-server: needs: run-tests diff --git a/.github/workflows/native-build-check.yml b/.github/workflows/native-build-check.yml new file mode 100644 index 00000000..ca239592 --- /dev/null +++ b/.github/workflows/native-build-check.yml @@ -0,0 +1,74 @@ +name: Native Build Check + +on: + workflow_call: + +jobs: + build-check-mac: + runs-on: macos-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + targets: 'x86_64-apple-darwin,aarch64-apple-darwin' + + - name: Cache Rust dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + native/target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Verify native binaries compile (x86_64) + working-directory: native + run: cargo build --workspace --release --target x86_64-apple-darwin + + - name: Verify native binaries compile (aarch64) + working-directory: native + run: cargo build --workspace --release --target aarch64-apple-darwin + + build-check-windows: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install build dependencies + run: | + sudo apt-get update + sudo apt-get install -y mingw-w64 + + - name: Set up Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + targets: 'x86_64-pc-windows-gnu' + + - name: Cache Rust dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + native/target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Verify native binaries compile (Windows) + working-directory: native + run: cargo build --workspace --release --target x86_64-pc-windows-gnu diff --git a/.github/workflows/test-runner.yml b/.github/workflows/test-runner.yml index 57acf913..c05c8faa 100644 --- a/.github/workflows/test-runner.yml +++ b/.github/workflows/test-runner.yml @@ -25,3 +25,9 @@ jobs: - name: Check code linting run: bun lint:app + + - name: Check Rust formatting + run: bun format:native + + - name: Check Rust linting + run: bun lint:native diff --git a/CLAUDE.md b/CLAUDE.md index 44d809d2..c658595a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -20,12 +20,89 @@ Main development branch: `dev` - Dev: `bun dev` (starts electron-vite dev with watch) - Server: `docker compose up --build` (run from server directory) - Build: `bun build:app:mac` or `bun build:app:windows` -- Test: `bun runAllTests` (runs both lib and server tests) +- Test: `bun runAllTests` (runs lib, server, and native tests) - Lib tests: `bun runLibTests` - Server tests: `bun runServerTests` -- Lint: `bun lint` (check) or `bun lint:fix` (fix) + - Native tests: `bun runNativeTests` (or see "Native Binary Tests" section) +- Lint: + - TypeScript: `bun lint` (check) or `bun lint:fix` (fix) + - Rust: `bun lint:native` (check) or `bun lint:fix:native` (fix) - Type check: `bun type-check` -- Format: `bun format` (check) or `bun format:fix` (fix) +- Format: + - TypeScript: `bun format` (check) or `bun format:fix` (fix) + - Rust: `bun format:native` (check) or `bun format:fix:native` (fix) + +## Native Binary Tests + +The `native/` directory contains Rust binaries that power the app's core functionality. The modules are organized as a Cargo workspace, allowing you to test and build all modules with a single command. + +### Running Tests + +Test all native modules: +```bash +cd native +cargo test --workspace +``` + +Or use the npm script: +```bash +bun runNativeTests +``` + +Test a single module: +```bash +cd native/global-key-listener +cargo test +``` + +### Native Modules + +- `global-key-listener` - Keyboard event capture and hotkey management +- `audio-recorder` - Audio recording with sample rate conversion +- `text-writer` - Cross-platform text input simulation +- `active-application` - Active window detection +- `selected-text-reader` - Selected text extraction + +### Linting and Formatting + +Rust code follows standard formatting and linting rules defined in `native/`: +- **rustfmt.toml** - Code formatting configuration (100 char width, Unix line endings) +- **clippy.toml** - Linter configuration (cognitive complexity threshold) +- **Cargo.toml** - Workspace-level lint rules (pedantic + nursery warnings) + +Run checks locally: +```bash +# Check formatting +bun format:native + +# Auto-fix formatting +bun format:fix:native + +# Check lints +bun lint:native + +# Auto-fix lints (where possible) +bun lint:fix:native +``` + +### CI/CD + +Native tests and builds are integrated into the existing CI workflows: + +**Tests** (`.github/workflows/test-runner.yml`): +- Unit tests run on macOS runner (OS-agnostic tests) +- Runs automatically via `bun runAllTests` on all pushes and PRs +- Executed as part of the main CI controller workflow + +**Compilation Checks** (`.github/workflows/native-build-check.yml`): +- macOS: Verifies compilation for x86_64 and aarch64 architectures +- Windows: Verifies cross-compilation for x86_64-pc-windows-gnu +- Runs automatically on all pushes and PRs via the CI controller +- Ensures binaries compile correctly for both platforms before merging + +**Release Builds** (`.github/workflows/build.yml`): +- Full release compilation happens during tagged releases +- Also includes compilation verification before packaging ## Code Style Preferences diff --git a/build-app.sh b/build-app.sh index 5a1981d7..c2c97658 100755 --- a/build-app.sh +++ b/build-app.sh @@ -107,13 +107,18 @@ build_native_modules() { case $platform in "mac") - ./build-binaries.sh --mac --universal + # Build for both architectures for release + ./build-binaries.sh --mac + ./build-binaries.sh --mac --x64 ;; "windows") ./build-binaries.sh --windows ;; "all") - ./build-binaries.sh --all --universal + # Build for all platforms and architectures for release + ./build-binaries.sh --mac + ./build-binaries.sh --mac --x64 + ./build-binaries.sh --windows ;; *) print_error "Invalid platform: $platform. Use 'mac', 'windows', or 'all'" diff --git a/build-binaries.sh b/build-binaries.sh index b4ee532d..ae8cbe4a 100755 --- a/build-binaries.sh +++ b/build-binaries.sh @@ -22,81 +22,62 @@ print_error() { echo -e "${RED}Error:${NC} $1" >&2 } -# --- This function builds a single Rust native module --- -build_native_module() { - local module_name=$1 - if [ ! -d "native/$module_name" ]; then - print_error "Directory native/$module_name not found. Skipping." - return - fi +# --- Build the entire native workspace --- +build_native_workspace() { + print_status "Building native workspace..." - print_status "Building module: ${module_name}" - - # Change into the module's directory - cd "native/$module_name" + # Change into the native workspace directory + cd "native" - # Install dependencies - print_info "Installing dependencies for $module_name..." - # Check if we're compiling on a Windows machine compiling_on_windows=false if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]] || [[ "$OS" == "Windows_NT" ]]; then compiling_on_windows=true fi - + + # Install dependencies + print_info "Installing dependencies for workspace..." cargo fetch # --- macOS Build --- if [ "$BUILD_MAC" = true ]; then - print_info "Building macOS binaries for $module_name..." - - # Build for Intel - print_info "Building for x86_64-apple-darwin (Intel)..." - cargo build --release --target x86_64-apple-darwin - - # Build for Apple Silicon - print_info "Building for aarch64-apple-darwin (Apple Silicon)..." - cargo build --release --target aarch64-apple-darwin - - # If --universal flag is passed, create a single binary for both architectures - if [[ " ${ARGS[*]} " == *" --universal "* ]]; then - print_info "Creating Universal macOS binary for $module_name..." - - local universal_dir="target/universal" - mkdir -p "$universal_dir" - - lipo -create \ - "target/x86_64-apple-darwin/release/$module_name" \ - "target/aarch64-apple-darwin/release/$module_name" \ - -output "$universal_dir/$module_name" - - print_info "Universal binary created at $universal_dir/$module_name" + # Determine target architecture (default to arm64) + local mac_target="aarch64-apple-darwin" + local arch_name="Apple Silicon (arm64)" + + if [[ " ${ARGS[*]} " == *" --x64 "* ]]; then + mac_target="x86_64-apple-darwin" + arch_name="Intel (x64)" fi - print_status "Renaming Rust target directories for electron-builder..." - # This aligns the directory names with electron-builder's {arch} variable. + print_info "Building macOS binaries for entire workspace ($arch_name)..." + cargo build --release --workspace --target "$mac_target" - rm -rf "target/arm64-apple-darwin" - rm -rf "target/x64-apple-darwin" - mv "target/aarch64-apple-darwin" "target/arm64-apple-darwin" - mv "target/x86_64-apple-darwin" "target/x64-apple-darwin" + # Create symlinks for electron-builder compatibility + if [ "$mac_target" = "aarch64-apple-darwin" ]; then + print_info "Creating symlink: arm64-apple-darwin -> aarch64-apple-darwin" + ln -sfn aarch64-apple-darwin target/arm64-apple-darwin + else + print_info "Creating symlink: x64-apple-darwin -> x86_64-apple-darwin" + ln -sfn x86_64-apple-darwin target/x64-apple-darwin + fi fi # --- Windows Build --- if [ "$BUILD_WINDOWS" = true ]; then - print_info "Building Windows binary for $module_name..." - + print_info "Building Windows binaries for entire workspace..." + # Use GNU target (more reliable than MSVC) if [ "$compiling_on_windows" = true ]; then - cargo +stable-x86_64-pc-windows-gnu build --release --target x86_64-pc-windows-gnu + cargo +stable-x86_64-pc-windows-gnu build --release --workspace --target x86_64-pc-windows-gnu else # Cross-compile from macOS/Linux using default toolchain - cargo build --release --target x86_64-pc-windows-gnu + cargo build --release --workspace --target x86_64-pc-windows-gnu fi fi - # Return to the project root for the next module - cd ../.. + # Return to the project root + cd .. } @@ -127,15 +108,26 @@ fi # If no platform flags are provided, print usage and exit. if [ "$BUILD_MAC" = false ] && [ "$BUILD_WINDOWS" = false ]; then print_error "No platform specified. Use --mac, --windows, or --all." - echo "Usage: $0 [--mac] [--windows] [--all] [--universal]" + echo "Usage: $0 [--mac] [--windows] [--all] [--x64]" + echo "" + echo "Options:" + echo " --mac Build for macOS (defaults to arm64, use --x64 for Intel)" + echo " --windows Build for Windows" + echo " --all Build for all platforms" + echo " --x64 Build for x64/Intel instead of arm64 (macOS only)" exit 1 fi # Add required Rust targets if [ "$BUILD_MAC" = true ]; then - print_status "Adding macOS targets..." - rustup target add x86_64-apple-darwin - rustup target add aarch64-apple-darwin + # Determine which macOS target to add + if [[ " ${ARGS[*]} " == *" --x64 "* ]]; then + print_status "Adding macOS x64 target..." + rustup target add x86_64-apple-darwin + else + print_status "Adding macOS arm64 target..." + rustup target add aarch64-apple-darwin + fi fi if [ "$BUILD_WINDOWS" = true ]; then print_status "Adding Windows target..." @@ -175,12 +167,7 @@ if [ "$BUILD_WINDOWS" = true ]; then fi -# --- Build all native modules --- -build_native_module "global-key-listener" -build_native_module "audio-recorder" -build_native_module "text-writer" -build_native_module "active-application" -build_native_module "selected-text-reader" - +# --- Build the native workspace --- +build_native_workspace -print_status "All native module builds completed successfully!" \ No newline at end of file +print_status "Native workspace build completed successfully!" \ No newline at end of file diff --git a/electron-builder.config.js b/electron-builder.config.js index d2eb59a9..20407a87 100644 --- a/electron-builder.config.js +++ b/electron-builder.config.js @@ -9,13 +9,13 @@ const nativeBinaries = [ const getMacResources = () => nativeBinaries.map(binary => ({ - from: `native/${binary}/target/\${arch}-apple-darwin/release/${binary}`, + from: `native/target/\${arch}-apple-darwin/release/${binary}`, to: `binaries/${binary}`, })) const getWindowsResources = () => nativeBinaries.map(binary => ({ - from: `native/${binary}/target/x86_64-pc-windows-gnu/release/${binary}.exe`, + from: `native/target/x86_64-pc-windows-gnu/release/${binary}.exe`, to: `binaries/${binary}.exe`, })) diff --git a/lib/media/audio.test.ts b/lib/media/audio.test.ts index 110cdf06..e2c75d02 100644 --- a/lib/media/audio.test.ts +++ b/lib/media/audio.test.ts @@ -45,6 +45,7 @@ mock.module('electron', () => ({ mock.module('os', () => ({ default: { platform: mock(() => 'darwin'), + arch: mock(() => 'arm64'), }, })) @@ -62,6 +63,7 @@ const waitForProcessing = () => new Promise(resolve => setTimeout(resolve, 10)) // Import after mocking import { audioRecorderService } from './audio' +import { arch } from 'os' describe('AudioRecorderService', () => { beforeEach(() => { @@ -143,105 +145,6 @@ describe('AudioRecorderService', () => { }) }) - describe('Binary Path Resolution Business Logic', () => { - test('should resolve Darwin development binary path correctly', () => { - audioRecorderService.initialize() - - expect(mockSpawn).toHaveBeenCalledWith( - expect.stringContaining( - 'native/audio-recorder/target/universal/audio-recorder', - ), - [], - { stdio: ['pipe', 'pipe', 'pipe'] }, - ) - }) - - test('should resolve Windows development binary path correctly', async () => { - // Mock Windows platform - const osModule = await import('os') - const originalPlatform = osModule.default.platform - osModule.default.platform = mock(() => 'win32' as any) - - try { - audioRecorderService.terminate() - audioRecorderService.initialize() - - expect(mockSpawn).toHaveBeenCalledWith( - expect.stringContaining( - 'native/audio-recorder/target/x86_64-pc-windows-gnu/release/audio-recorder.exe', - ), - [], - { stdio: ['pipe', 'pipe', 'pipe'] }, - ) - } finally { - // Restore original platform function - osModule.default.platform = originalPlatform - } - }) - - test('should resolve production binary path correctly', async () => { - // Mock production mode by mocking the electron module - const originalElectronModule = await import('electron') - const mockElectronModule = { - ...originalElectronModule, - app: { - ...originalElectronModule.app, - isPackaged: true, - }, - } - - // Mock the module - mock.module('electron', () => mockElectronModule) - - try { - audioRecorderService.terminate() - audioRecorderService.initialize() - - expect(mockSpawn).toHaveBeenCalledWith( - expect.stringContaining('binaries/audio-recorder'), - [], - { stdio: ['pipe', 'pipe', 'pipe'] }, - ) - } finally { - // Restore original electron module - mock.module('electron', () => ({ - app: { - isPackaged: false, - }, - })) - } - }) - - test('should handle unsupported development platform gracefully', async () => { - // Mock unsupported platform - const osModule = await import('os') - const originalPlatform = osModule.default.platform - osModule.default.platform = mock(() => 'freebsd' as any) - - let errorEmitted = false - audioRecorderService.on('error', () => { - errorEmitted = true - }) - - try { - audioRecorderService.initialize() - - // Wait for error handling to complete - await waitForProcessing() - - expect(mockElectronLog.error).toHaveBeenCalledWith( - expect.stringContaining( - 'Unsupported development platform for audio-recorder: freebsd', - ), - ) - expect(errorEmitted).toBe(true) - } finally { - // Restore original platform function - osModule.default.platform = originalPlatform - } - }) - }) - describe('Process Lifecycle Business Logic', () => { beforeEach(() => { audioRecorderService.initialize() diff --git a/lib/media/audio.ts b/lib/media/audio.ts index 10e25721..5a2bd196 100644 --- a/lib/media/audio.ts +++ b/lib/media/audio.ts @@ -1,9 +1,7 @@ import { spawn, ChildProcessWithoutNullStreams } from 'child_process' -import { join } from 'path' -import { app } from 'electron' -import os from 'os' import log from 'electron-log' import { EventEmitter } from 'events' +import { getNativeBinaryPath } from './native-interface' // Message types from the native binary const MSG_TYPE_JSON = 1 @@ -39,7 +37,7 @@ class AudioRecorderService extends EventEmitter { return } - const binaryPath = this.#getBinaryPath() + const binaryPath = getNativeBinaryPath('audio-recorder') if (!binaryPath) { log.error( '[AudioService] Could not determine audio recorder binary path.', @@ -291,33 +289,6 @@ class AudioRecorderService extends EventEmitter { const rms = Math.sqrt(sumOfSquares / (buffer.length / 2)) return Math.min(rms / 32767, 1.0) } - - #getBinaryPath(): string | null { - const isDev = !app.isPackaged - const platform = os.platform() - const binaryName = - platform === 'win32' ? 'audio-recorder.exe' : 'audio-recorder' - const baseDir = isDev - ? join(__dirname, '../../native/audio-recorder/target') - : join(process.resourcesPath, 'binaries') - - if (isDev) { - let archPath - if (platform === 'darwin') { - archPath = 'universal' - } else if (platform === 'win32') { - archPath = 'x86_64-pc-windows-gnu/release' - } else { - log.error( - `Unsupported development platform for audio-recorder: ${platform}`, - ) - return null - } - return join(baseDir, archPath, binaryName) - } else { - return join(process.resourcesPath, 'binaries', binaryName) - } - } } // Export a singleton instance of the service diff --git a/lib/media/native-interface.test.ts b/lib/media/native-interface.test.ts index 3a381476..5012ded2 100644 --- a/lib/media/native-interface.test.ts +++ b/lib/media/native-interface.test.ts @@ -15,6 +15,7 @@ mock.module('electron', () => ({ const mockOs = { platform: mock(() => 'darwin'), + arch: mock(() => 'arm64'), } mock.module('os', () => ({ default: mockOs, @@ -36,27 +37,32 @@ describe('Native Interface Module', () => { // Reset all mocks mockJoin.mockClear() mockOs.platform.mockClear() + mockOs.arch.mockClear() // Reset module state delete require.cache[require.resolve('./native-interface')] - // Set default platform + // Set default platform and arch mockOs.platform.mockReturnValue('darwin') + mockOs.arch.mockReturnValue('arm64') mockApp.isPackaged = false }) describe('Platform-Specific Path Resolution Business Logic', () => { test('should resolve Darwin development binary path correctly', async () => { mockOs.platform.mockReturnValue('darwin') + mockOs.arch.mockReturnValue('arm64') const { getNativeBinaryPath } = await import('./native-interface') const result = getNativeBinaryPath('global-key-listener') expect(mockJoin).toHaveBeenLastCalledWith( - expect.stringContaining('native/global-key-listener/target/universal'), + expect.stringContaining('native/target/aarch64-apple-darwin/release'), 'global-key-listener', ) - expect(result).toContain('universal/global-key-listener') + expect(result).toContain( + 'aarch64-apple-darwin/release/global-key-listener', + ) }) test('should resolve Windows development binary path correctly', async () => { @@ -66,9 +72,7 @@ describe('Native Interface Module', () => { const result = getNativeBinaryPath('audio-recorder') expect(mockJoin).toHaveBeenLastCalledWith( - expect.stringContaining( - 'native/audio-recorder/target/x86_64-pc-windows-gnu/release', - ), + expect.stringContaining('native/target/x86_64-pc-windows-gnu/release'), 'audio-recorder.exe', ) expect(result).toContain( @@ -206,7 +210,7 @@ describe('Native Interface Module', () => { const prodImport = await import('./native-interface') const prodResult = prodImport.getNativeBinaryPath('test-module') - expect(devResult).toContain('target/universal') + expect(devResult).toContain('target/aarch64-apple-darwin/release') expect(prodResult).toContain('resources/binaries') expect(devResult).not.toBe(prodResult) } finally { diff --git a/lib/media/native-interface.ts b/lib/media/native-interface.ts index bf052b0b..be1fe5be 100644 --- a/lib/media/native-interface.ts +++ b/lib/media/native-interface.ts @@ -8,28 +8,29 @@ const isDev = !app.isPackaged export const getNativeBinaryPath = ( nativeModuleName: string, ): string | null => { - const targetDir = getTargetDir(nativeModuleName) + const targetDir = getTargetDir() const binaryName = platform === 'win32' ? `${nativeModuleName}.exe` : `${nativeModuleName}` if (!targetDir) { console.error( - `Cannot determine ${nativeModuleName} binary path for platform ${os.platform()}`, + `Cannot determine ${nativeModuleName} binary path for platform ${platform}`, ) return null } return join(targetDir, binaryName) } -const getTargetDir = (nativeModuleName: string): string | null => { +const getTargetDir = (): string | null => { if (isDev) { - const targetBase = join( - __dirname, - `../../native/${nativeModuleName}/target`, - ) + const targetBase = join(__dirname, '../../native/target') if (platform === 'darwin') { - return join(targetBase, 'universal') + // Detect current architecture + const arch = os.arch() // 'arm64' or 'x64' + const cargoArch = arch === 'arm64' ? 'aarch64' : 'x86_64' + const targetDir = join(targetBase, `${cargoArch}-apple-darwin/release`) + return targetDir } else if (platform === 'win32') { return join(targetBase, 'x86_64-pc-windows-gnu/release') } diff --git a/native/Cargo.lock b/native/Cargo.lock new file mode 100644 index 00000000..740c5b04 --- /dev/null +++ b/native/Cargo.lock @@ -0,0 +1,3209 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "accessibility-ng" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7cb28d49c934e5f32a0b2227510e00999423596eff62f257962db130c3fa716" +dependencies = [ + "accessibility-sys-ng", + "cocoa 0.24.1", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", + "objc", + "thiserror", +] + +[[package]] +name = "accessibility-sys-ng" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02eadf4b9910301a47799cea1a8eefa659536fec71f5b8496b583b5e521db0b3" +dependencies = [ + "core-foundation-sys 0.8.7", +] + +[[package]] +name = "active-application" +version = "0.1.0" +dependencies = [ + "active-win-pos-rs 0.9.1", + "serde", + "serde_json", +] + +[[package]] +name = "active-win-pos-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e227f8493de9f5e493f8e762ac7516d2ae42464df2e8122fcafd604f0b16c634" +dependencies = [ + "appkit-nsworkspace-bindings", + "core-foundation 0.9.4", + "core-graphics 0.23.2", + "objc", + "windows 0.48.0", + "xcb", +] + +[[package]] +name = "active-win-pos-rs" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b376311b66ae164d60150395ade1b382584d25be0c5ac2d837b8eb2e549ca224" +dependencies = [ + "appkit-nsworkspace-bindings", + "core-foundation 0.9.4", + "core-graphics 0.23.2", + "objc", + "windows 0.48.0", + "xcb", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "alsa" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" +dependencies = [ + "alsa-sys", + "bitflags 2.9.4", + "cfg-if", + "libc", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "appkit-nsworkspace-bindings" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "062382938604cfa02c03689ab75af0e7eb79175ba0d0b2bcfad18f5190702dd7" +dependencies = [ + "bindgen", + "objc", +] + +[[package]] +name = "arboard" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" +dependencies = [ + "clipboard-win", + "image", + "log", + "objc2 0.6.3", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.2", + "parking_lot", + "percent-encoding", + "windows-sys 0.60.2", + "x11rb", +] + +[[package]] +name = "audio-recorder" +version = "0.1.0" +dependencies = [ + "anyhow", + "cpal", + "crossbeam-channel", + "dasp_sample", + "num-traits", + "rubato", + "serde", + "serde_json", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bindgen" +version = "0.68.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" +dependencies = [ + "bitflags 2.9.4", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", + "which", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[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.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link 0.2.1", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "clipboard-win" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" +dependencies = [ + "error-code", +] + +[[package]] +name = "cocoa" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "667fdc068627a2816b9ff831201dd9864249d6ee8d190b9532357f1fc0f61ea7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation 0.9.4", + "core-graphics 0.21.0", + "foreign-types 0.3.2", + "libc", + "objc", +] + +[[package]] +name = "cocoa" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation 0.9.4", + "core-graphics 0.22.3", + "foreign-types 0.3.2", + "libc", + "objc", +] + +[[package]] +name = "cocoa" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation 0.9.4", + "core-graphics 0.23.2", + "foreign-types 0.5.0", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", + "libc", + "objc", +] + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys 0.7.0", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys 0.8.7", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys 0.8.7", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.7.0", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a67c4378cf203eace8fb6567847eb641fd6ff933c1145a115c6ee820ebb978" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", + "core-graphics-types 0.2.0", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", + "core-graphics-types 0.2.0", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", + "libc", +] + +[[package]] +name = "coreaudio-rs" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aae284fbaf7d27aa0e292f7677dfbe26503b0d555026f702940805a630eac17" +dependencies = [ + "bitflags 1.3.2", + "libc", + "objc2-audio-toolbox", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", +] + +[[package]] +name = "cpal" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbd307f43cc2a697e2d1f8bc7a1d824b5269e052209e28883e5bc04d095aaa3f" +dependencies = [ + "alsa", + "coreaudio-rs", + "dasp_sample", + "jni", + "js-sys", + "libc", + "mach2", + "ndk", + "ndk-context", + "num-derive", + "num-traits", + "objc2-audio-toolbox", + "objc2-core-audio", + "objc2-core-audio-types", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows 0.54.0", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "dasp_sample" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" + +[[package]] +name = "derive-new" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.3", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "enigo" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0087a01fc8591217447d28005379fb5a183683cc83f0a4707af28cc6603f70fb" +dependencies = [ + "core-graphics 0.23.2", + "foreign-types-shared 0.3.1", + "icrate", + "libc", + "log", + "objc2 0.5.2", + "windows 0.56.0", + "xkbcommon 0.7.0", + "xkeysym", +] + +[[package]] +name = "enigo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cf6f550bbbdd5fe66f39d429cb2604bcdacbf00dca0f5bbe2e9306a0009b7c6" +dependencies = [ + "core-foundation 0.10.1", + "core-graphics 0.24.0", + "foreign-types-shared 0.3.1", + "libc", + "log", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "windows 0.58.0", + "xkbcommon 0.8.0", + "xkeysym", +] + +[[package]] +name = "enigo" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c6c56e50f7acae2906a0dcbb34529ca647e40421119ad5d12e7f8ba6e50010" +dependencies = [ + "core-foundation 0.10.1", + "core-graphics 0.25.0", + "foreign-types-shared 0.3.1", + "libc", + "log", + "nom 8.0.0", + "objc2 0.6.3", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", + "windows 0.61.3", + "x11rb", + "xkbcommon 0.9.0", + "xkeysym", +] + +[[package]] +name = "epoll" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e74d68fe2927dbf47aa976d14d93db9b23dced457c7bb2bdc6925a16d31b736e" +dependencies = [ + "bitflags 2.9.4", + "libc", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "error-code" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" + +[[package]] +name = "evdev" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab6055a93a963297befb0f4f6e18f314aec9767a4bbe88b151126df2433610a7" +dependencies = [ + "bitvec", + "cfg-if", + "libc", + "nix 0.23.2", + "thiserror", +] + +[[package]] +name = "evdev-rs" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b92abc30d5fd1e4f6440dee4d626abc68f4a9b5014dc1de575901e23c2e02321" +dependencies = [ + "bitflags 1.3.2", + "evdev-sys", + "libc", + "log", +] + +[[package]] +name = "evdev-sys" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdcf0d489f4d9a80ac2b3b35b92fdd8fcf68d33bb67f947afe5cd36e482de576" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fax" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "gethostname" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55" +dependencies = [ + "rustix 1.1.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "global-key-listener" +version = "0.1.0" +dependencies = [ + "chrono", + "cocoa 0.25.0", + "core-foundation 0.9.4", + "core-graphics 0.22.3", + "evdev", + "objc", + "rdev", + "serde", + "serde_json", + "winapi", + "x11", +] + +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys 0.8.7", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[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 = "image" +version = "0.25.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "png", + "tiff", +] + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown 0.16.0", +] + +[[package]] +name = "inotify" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46dd0a94b393c730779ccfd2a872b67b1eb67be3fc33082e733bdb38b5fde4d4" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link 0.2.1", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "memmap2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed" +dependencies = [ + "libc", +] + +[[package]] +name = "memmap2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "moxcms" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cc7d85f3d741164e8972ad355e26ac6e51b20fcae5f911c7da8f2d8bbbb3f33" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.9.4", + "jni-sys", + "log", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.9.4", + "block2 0.5.1", + "libc", + "objc2 0.5.2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation 0.2.2", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.3", + "objc2-core-graphics", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-audio-toolbox" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6948501a91121d6399b79abaa33a8aa4ea7857fe019f341b8c23ad6e81b79b08" +dependencies = [ + "bitflags 2.9.4", + "libc", + "objc2 0.6.3", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-audio" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1eebcea8b0dbff5f7c8504f3107c68fc061a3eb44932051c8cf8a68d969c3b2" +dependencies = [ + "dispatch2", + "objc2 0.6.3", + "objc2-core-audio-types", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-core-audio-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.3", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.9.4", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.9.4", + "dispatch2", + "objc2 0.6.3", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.9.4", + "dispatch2", + "objc2 0.6.3", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.9.4", + "block2 0.5.1", + "libc", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.3", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.3", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.9.4", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.9.4", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "os_pipe" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link 0.2.1", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "png" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" +dependencies = [ + "bitflags 2.9.4", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "primal-check" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0d895b311e3af9902528fbb8f928688abbd95872819320517cc24ca6b2bd08" +dependencies = [ + "num-integer", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pxfm" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83f9b339b02259ada5c0f4a389b7fb472f933aa17ce176fd2ad98f28bb401fde" +dependencies = [ + "num-traits", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.37.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rdev" +version = "0.4.4" +source = "git+https://github.com/heyito/rdev?branch=main#7a8cc54b5f8c33f676954cb803a33e1e45c4b3f5" +dependencies = [ + "cocoa 0.22.0", + "core-foundation 0.7.0", + "core-foundation-sys 0.7.0", + "core-graphics 0.19.2", + "epoll", + "evdev-rs", + "inotify", + "lazy_static", + "libc", + "winapi", + "x11", +] + +[[package]] +name = "realfft" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f821338fddb99d089116342c46e9f1fbf3828dba077674613e734e01d6ea8677" +dependencies = [ + "rustfft", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.9.4", +] + +[[package]] +name = "regex" +version = "1.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + +[[package]] +name = "rubato" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5258099699851cfd0082aeb645feb9c084d9a5e1f1b8d5372086b989fc5e56a1" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "realfft", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustfft" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21db5f9893e91f41798c88680037dba611ca6674703c1a18601b01a72c8adb89" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "primal-check", + "strength_reduce", + "transpose", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "selected-text-reader" +version = "0.1.0" +dependencies = [ + "accessibility-ng", + "accessibility-sys-ng", + "active-win-pos-rs 0.8.4", + "arboard", + "core-foundation 0.9.4", + "crossbeam-channel", + "enigo 0.6.1", + "libc", + "lru", + "parking_lot", + "selection", + "serde", + "serde_json", +] + +[[package]] +name = "selection" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56bdfb3cbb220dd9ae541e7a50318f6073cc7920949684c9788c54ba78edd64" +dependencies = [ + "accessibility-ng", + "accessibility-sys-ng", + "arboard", + "core-foundation 0.9.4", + "enigo 0.2.1", + "log", + "windows 0.56.0", + "wl-clipboard-rs", + "x11-clipboard", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix 1.1.2", + "windows-sys 0.61.2", +] + +[[package]] +name = "text-writer" +version = "0.1.0" +dependencies = [ + "clap", + "clipboard-win", + "cocoa 0.25.0", + "core-foundation 0.9.4", + "core-graphics 0.23.2", + "enigo 0.3.0", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tiff" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +dependencies = [ + "winnow", +] + +[[package]] +name = "transpose" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" +dependencies = [ + "num-integer", + "strength_reduce", +] + +[[package]] +name = "tree_magic_mini" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f943391d896cdfe8eec03a04d7110332d445be7df856db382dd96a730667562c" +dependencies = [ + "memchr", + "nom 7.1.3", + "once_cell", + "petgraph", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wayland-backend" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35" +dependencies = [ + "cc", + "downcast-rs", + "rustix 1.1.2", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" +dependencies = [ + "bitflags 2.9.4", + "rustix 1.1.2", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" +dependencies = [ + "bitflags 2.9.4", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" +dependencies = [ + "bitflags 2.9.4", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3" +dependencies = [ + "proc-macro2", + "quick-xml 0.37.5", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "weezl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" +dependencies = [ + "windows-core 0.54.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" +dependencies = [ + "windows-core 0.56.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +dependencies = [ + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" +dependencies = [ + "windows-implement 0.56.0", + "windows-interface 0.56.0", + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement 0.60.2", + "windows-interface 0.59.3", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement 0.60.2", + "windows-interface 0.59.3", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "wl-clipboard-rs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b41773911497b18ca8553c3daaf8ec9fe9819caf93d451d3055f69de028adb" +dependencies = [ + "derive-new", + "libc", + "log", + "nix 0.28.0", + "os_pipe", + "tempfile", + "thiserror", + "tree_magic_mini", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-wlr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-clipboard" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662d74b3d77e396b8e5beb00b9cad6a9eccf40b2ef68cc858784b14c41d535a3" +dependencies = [ + "libc", + "x11rb", +] + +[[package]] +name = "x11rb" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" +dependencies = [ + "gethostname", + "rustix 1.1.2", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" + +[[package]] +name = "xcb" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f07c123b796139bfe0603e654eaf08e132e52387ba95b252c78bad3640ba37ea" +dependencies = [ + "bitflags 1.3.2", + "libc", + "quick-xml 0.30.0", +] + +[[package]] +name = "xkbcommon" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13867d259930edc7091a6c41b4ce6eee464328c6ff9659b7e4c668ca20d4c91e" +dependencies = [ + "libc", + "memmap2 0.8.0", + "xkeysym", +] + +[[package]] +name = "xkbcommon" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d66ca9352cbd4eecbbc40871d8a11b4ac8107cfc528a6e14d7c19c69d0e1ac9" +dependencies = [ + "libc", + "memmap2 0.9.8", + "xkeysym", +] + +[[package]] +name = "xkbcommon" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a974f48060a14e95705c01f24ad9c3345022f4d97441b8a36beb7ed5c4a02d" +dependencies = [ + "libc", + "memmap2 0.9.8", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-jpeg" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +dependencies = [ + "zune-core", +] diff --git a/native/Cargo.toml b/native/Cargo.toml new file mode 100644 index 00000000..358888b4 --- /dev/null +++ b/native/Cargo.toml @@ -0,0 +1,25 @@ +[workspace] +members = [ + "global-key-listener", + "audio-recorder", + "text-writer", + "active-application", + "selected-text-reader", +] + +resolver = "2" + +[workspace.dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" + +# Workspace-wide linting configuration +[workspace.lints.clippy] +all = { level = "warn", priority = -1 } +dbg_macro = "deny" # No debug prints should reach production +todo = "warn" # Flag TODO comments for review + +[workspace.lints.rust] +# Allow warnings that are unavoidable with current architecture +unexpected_cfgs = "allow" # Third-party objc macro issues +static_mut_refs = "allow" # Global state for hotkey tracking diff --git a/native/active-application/Cargo.toml b/native/active-application/Cargo.toml index 9c1b4e75..ca657066 100644 --- a/native/active-application/Cargo.toml +++ b/native/active-application/Cargo.toml @@ -7,3 +7,6 @@ edition = "2024" active-win-pos-rs = "0.9.0" serde = "1.0.219" serde_json = "1.0.141" + +[lints] +workspace = true diff --git a/native/audio-recorder/Cargo.toml b/native/audio-recorder/Cargo.toml index 961cb77a..4c6dcbfa 100644 --- a/native/audio-recorder/Cargo.toml +++ b/native/audio-recorder/Cargo.toml @@ -12,3 +12,6 @@ anyhow = "1.0.98" rubato = "0.16.2" num-traits = "0.2.19" dasp_sample = "0.11.0" + +[lints] +workspace = true diff --git a/native/audio-recorder/src/main.rs b/native/audio-recorder/src/main.rs index 317b5f7c..22eb01f9 100644 --- a/native/audio-recorder/src/main.rs +++ b/native/audio-recorder/src/main.rs @@ -57,16 +57,14 @@ fn main() { thread::spawn(move || { let stdin = io::stdin(); - for line in stdin.lock().lines() { - if let Ok(l) = line { - if l.trim().is_empty() { - continue; - } - if let Ok(command) = serde_json::from_str::(&l) { - cmd_tx - .send(command) - .expect("Failed to send command to processor"); - } + for l in stdin.lock().lines().map_while(Result::ok) { + if l.trim().is_empty() { + continue; + } + if let Ok(command) = serde_json::from_str::(&l) { + cmd_tx + .send(command) + .expect("Failed to send command to processor"); } } }); @@ -104,7 +102,8 @@ impl CommandProcessor { let host = { #[cfg(target_os = "windows")] { - // On Windows, prefer WASAPI directly for best performance (10-30ms latency vs DirectSound's 50-80ms) + // On Windows, prefer WASAPI directly for best performance (10-30ms latency vs + // DirectSound's 50-80ms) match cpal::host_from_id(cpal::platform::HostId::Wasapi) { Ok(wasapi_host) => { eprintln!("[audio-recorder] Using WASAPI host (optimal for Windows)"); @@ -224,57 +223,6 @@ impl CommandProcessor { } } -// --- MODIFIED: Function now accepts chunk_size as a parameter --- -fn process_and_write_data( - data: &[T], - resampler: &mut Option>, - buffer: &mut Vec, - stdout: &Arc>, - chunk_size: usize, - num_channels: usize, -) where - T: Sample, - f32: FromSample, -{ - // Downmix to mono by averaging channels per frame to keep timebase correct - let mono_samples: Vec = if num_channels <= 1 { - data.iter().map(|s| s.to_sample::()).collect() - } else { - let mut out: Vec = Vec::with_capacity(data.len() / num_channels); - let mut i = 0; - while i + num_channels <= data.len() { - let mut sum = 0.0f32; - for c in 0..num_channels { - sum += data[i + c].to_sample::(); - } - out.push(sum / (num_channels as f32)); - i += num_channels; - } - out - }; - - if let Some(resampler_instance) = resampler { - buffer.extend_from_slice(&mono_samples); - - while buffer.len() >= chunk_size { - let chunk_to_process = buffer.drain(..chunk_size).collect::>(); - - match resampler_instance.process(&[chunk_to_process], None) { - Ok(mut resampled) => { - if !resampled.is_empty() { - write_audio_chunk(&resampled.remove(0), stdout); - } - } - Err(e) => { - eprintln!("[audio-recorder] CRITICAL: Resampling failed: {}", e); - } - } - } - } else { - write_audio_chunk(&mono_samples, stdout); - } -} - fn write_audio_chunk(data: &[f32], stdout: &Arc>) { let mut writer = stdout.lock().unwrap(); let mut buffer = Vec::with_capacity(data.len() * 2); @@ -304,7 +252,8 @@ where if num_channels <= 1 { return data.iter().map(|s| s.to_sample::()).collect(); } - // Select the dominant channel to avoid amplitude loss when one channel is near-silent + // Select the dominant channel to avoid amplitude loss when one channel is + // near-silent let frames = data.len() / num_channels; if frames == 0 { return Vec::new(); @@ -320,6 +269,7 @@ where } let mut best_channel = 0usize; let mut best_energy = energy_per_channel[0]; + #[allow(clippy::needless_range_loop)] for c in 1..num_channels { if energy_per_channel[c] > best_energy { best_energy = energy_per_channel[c]; @@ -432,15 +382,13 @@ fn writer_loop( ), } } - } else { - if input_sample_rate != TARGET_SAMPLE_RATE { - let resampled = linear_resample_mono(&frame, input_sample_rate, TARGET_SAMPLE_RATE); - if !resampled.is_empty() { - write_audio_chunk(&resampled, &stdout); - } - } else { - write_audio_chunk(&frame, &stdout); + } else if input_sample_rate != TARGET_SAMPLE_RATE { + let resampled = linear_resample_mono(&frame, input_sample_rate, TARGET_SAMPLE_RATE); + if !resampled.is_empty() { + write_audio_chunk(&resampled, &stdout); } + } else { + write_audio_chunk(&frame, &stdout); } } @@ -528,7 +476,7 @@ fn start_capture( { let cfg = AudioConfig { response_type: "audio-config".to_string(), - input_sample_rate: input_sample_rate, + input_sample_rate, output_sample_rate: TARGET_SAMPLE_RATE, channels: 1, }; @@ -637,3 +585,80 @@ fn start_capture( writer_handle, }) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_downmix_to_mono_single_channel() { + let mono_samples: Vec = vec![0.5, -0.5, 1.0, -1.0]; + let result = downmix_to_mono_vec(&mono_samples, 1); + + assert_eq!(result.len(), 4); + assert_eq!(result, vec![0.5, -0.5, 1.0, -1.0]); + } + + #[test] + fn test_downmix_to_mono_stereo() { + // Stereo: L,R,L,R pattern + let stereo_samples: Vec = vec![0.8, 0.2, -0.6, -0.4]; + let result = downmix_to_mono_vec(&stereo_samples, 2); + + assert_eq!(result.len(), 2); + assert_eq!(result[0], 0.8); // Left channel sample 1 + assert_eq!(result[1], -0.6); // Left channel sample 2 + } + + #[test] + fn test_downmix_to_mono_quad() { + // 4 channels: one frame with values [1.0, 0.5, 0.25, 0.25] + let quad_samples: Vec = vec![1.0, 0.5, 0.25, 0.25]; // One frame + let result = downmix_to_mono_vec(&quad_samples, 4); + + assert_eq!(result.len(), 1); + assert_eq!(result[0], 1.0); // Channel 0 sample + } + + #[test] + fn test_downmix_partial_frame() { + // 5 samples with 2 channels - last sample incomplete, should be ignored + let samples: Vec = vec![0.8, 0.2, -0.6, -0.4, 1.0]; + let result = downmix_to_mono_vec(&samples, 2); + + assert_eq!(result.len(), 2); // Only 2 complete frames + assert_eq!(result[0], 0.8); // Left channel sample 1 + assert_eq!(result[1], -0.6); // Left channel sample 2 + } + + #[test] + fn test_write_framed_message_structure() { + let mut buffer = Vec::new(); + let test_data = b"test"; + + write_framed_message(&mut buffer, MSG_TYPE_JSON, test_data).unwrap(); + + // Check structure: [msg_type(1)] + [length(4)] + [data(4)] + assert_eq!(buffer.len(), 9); + assert_eq!(buffer[0], MSG_TYPE_JSON); + + // Length bytes (little-endian u32 = 4) + let length = u32::from_le_bytes([buffer[1], buffer[2], buffer[3], buffer[4]]); + assert_eq!(length, 4); + + // Data + assert_eq!(&buffer[5..9], test_data); + } + + #[test] + fn test_write_framed_message_audio_type() { + let mut buffer = Vec::new(); + let audio_data = vec![0u8; 100]; + + write_framed_message(&mut buffer, MSG_TYPE_AUDIO, &audio_data).unwrap(); + + assert_eq!(buffer[0], MSG_TYPE_AUDIO); + let length = u32::from_le_bytes([buffer[1], buffer[2], buffer[3], buffer[4]]); + assert_eq!(length, 100); + } +} diff --git a/native/clippy.toml b/native/clippy.toml new file mode 100644 index 00000000..07f8b045 --- /dev/null +++ b/native/clippy.toml @@ -0,0 +1,14 @@ +# Clippy configuration +# https://rust-lang.github.io/rust-clippy/master/index.html + +# Warn on all clippy lints by default +# Can be overridden with #[allow(clippy::lint_name)] on specific items + +# Cognitive complexity threshold +cognitive-complexity-threshold = 30 + +# Disallowed methods (methods that shouldn't be used) +# disallowed-methods = [] + +# Disallowed types +# disallowed-types = [] diff --git a/native/global-key-listener/Cargo.toml b/native/global-key-listener/Cargo.toml index 4cf391bf..cb4f4cbb 100644 --- a/native/global-key-listener/Cargo.toml +++ b/native/global-key-listener/Cargo.toml @@ -25,3 +25,6 @@ core-foundation = "0.9" core-graphics = "0.22" cocoa = "0.25" objc = "0.2" + +[lints] +workspace = true diff --git a/native/global-key-listener/src/key_codes.rs b/native/global-key-listener/src/key_codes.rs index 9fa42573..fa031820 100644 --- a/native/global-key-listener/src/key_codes.rs +++ b/native/global-key-listener/src/key_codes.rs @@ -94,3 +94,61 @@ pub fn key_to_code(key: &Key) -> Option { _ => None, // For keys that don't have a standard code } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_key_to_code_letters() { + // Test common letter keys + assert_eq!(key_to_code(&Key::KeyA), Some(65)); + assert_eq!(key_to_code(&Key::KeyZ), Some(90)); + assert_eq!(key_to_code(&Key::KeyC), Some(67)); + } + + #[test] + fn test_key_to_code_numbers() { + // Test number keys + assert_eq!(key_to_code(&Key::Num0), Some(48)); + assert_eq!(key_to_code(&Key::Num5), Some(53)); + assert_eq!(key_to_code(&Key::Num9), Some(57)); + } + + #[test] + fn test_key_to_code_modifiers() { + // Test modifier keys + assert_eq!(key_to_code(&Key::ControlLeft), Some(17)); + assert_eq!(key_to_code(&Key::ControlRight), Some(17)); + assert_eq!(key_to_code(&Key::ShiftLeft), Some(16)); + assert_eq!(key_to_code(&Key::ShiftRight), Some(16)); + assert_eq!(key_to_code(&Key::Alt), Some(18)); + } + + #[test] + fn test_key_to_code_function_keys() { + // Test function keys + assert_eq!(key_to_code(&Key::F1), Some(112)); + assert_eq!(key_to_code(&Key::F12), Some(123)); + assert_eq!(key_to_code(&Key::Function), Some(179)); + } + + #[test] + fn test_key_to_code_special_keys() { + // Test special keys + assert_eq!(key_to_code(&Key::Escape), Some(27)); + assert_eq!(key_to_code(&Key::Return), Some(13)); + assert_eq!(key_to_code(&Key::Space), Some(32)); + assert_eq!(key_to_code(&Key::Tab), Some(9)); + assert_eq!(key_to_code(&Key::Backspace), Some(8)); + } + + #[test] + fn test_key_to_code_arrow_keys() { + // Test arrow keys + assert_eq!(key_to_code(&Key::UpArrow), Some(38)); + assert_eq!(key_to_code(&Key::DownArrow), Some(40)); + assert_eq!(key_to_code(&Key::LeftArrow), Some(37)); + assert_eq!(key_to_code(&Key::RightArrow), Some(39)); + } +} diff --git a/native/global-key-listener/src/main.rs b/native/global-key-listener/src/main.rs index a7a5362b..3cc4aef2 100644 --- a/native/global-key-listener/src/main.rs +++ b/native/global-key-listener/src/main.rs @@ -28,17 +28,22 @@ enum Command { } // Global state for registered hotkeys and currently pressed keys +#[allow(static_mut_refs)] static mut REGISTERED_HOTKEYS: Vec = Vec::new(); +#[allow(static_mut_refs)] static mut CURRENTLY_PRESSED: Vec = Vec::new(); // Global state for tracking modifier keys to detect Cmd+C/Ctrl+C combinations +#[allow(static_mut_refs)] static mut CMD_PRESSED: bool = false; +#[allow(static_mut_refs)] static mut CTRL_PRESSED: bool = false; +#[allow(static_mut_refs)] static mut COPY_IN_PROGRESS: bool = false; /// Prevents macOS App Nap from suspending this process. -/// Returns an activity token that must be retained for the entire process lifetime. -/// On non-macOS platforms, returns a dummy value. +/// Returns an activity token that must be retained for the entire process +/// lifetime. On non-macOS platforms, returns a dummy value. #[cfg(target_os = "macos")] fn prevent_app_nap() -> id { unsafe { @@ -70,12 +75,10 @@ fn main() { // Spawn a thread to read commands from stdin thread::spawn(|| { let stdin = io::stdin(); - for line in stdin.lock().lines() { - if let Ok(line) = line { - match serde_json::from_str::(&line) { - Ok(command) => handle_command(command), - Err(e) => eprintln!("Error parsing command: {}", e), - } + for line in stdin.lock().lines().map_while(Result::ok) { + match serde_json::from_str::(&line) { + Ok(command) => handle_command(command), + Err(e) => eprintln!("Error parsing command: {}", e), } } }); @@ -141,12 +144,14 @@ fn callback(event: Event) -> Option { let key_name = format!("{:?}", key); // Check for copy combinations before updating modifier states - // Ignore Cmd+C (macOS) and Ctrl+C (Windows/Linux) combinations to prevent feedback loops with selected-text-reader + // Ignore Cmd+C (macOS) and Ctrl+C (Windows/Linux) combinations to prevent + // feedback loops with selected-text-reader if matches!(key, Key::KeyC) && unsafe { CMD_PRESSED || CTRL_PRESSED } { unsafe { COPY_IN_PROGRESS = true; } - // Still pass through the event to the system but don't output it to our listener + // Still pass through the event to the system but don't output it to our + // listener return Some(event); } @@ -179,11 +184,16 @@ fn callback(event: Event) -> Option { output_event("keydown", &key); // Check if we should block based on exact hotkey match + #[allow(clippy::if_same_then_else)] if should_block() { None // Block the event from reaching the OS - } else if key_name == "Unknown(179)" && unsafe { - REGISTERED_HOTKEYS.iter().any(|hotkey| hotkey.keys.contains(&"Function".to_string())) - } { + } else if key_name == "Unknown(179)" + && unsafe { + REGISTERED_HOTKEYS + .iter() + .any(|hotkey| hotkey.keys.contains(&"Function".to_string())) + } + { None // Block Unknown(179) if any hotkey uses Function } else { Some(event) // Let it through @@ -205,14 +215,14 @@ fn callback(event: Event) -> Option { } // Check for C key release while copy is in progress or modifiers are still held - if matches!(key, Key::KeyC) { - if unsafe { COPY_IN_PROGRESS || CMD_PRESSED || CTRL_PRESSED } { - unsafe { - COPY_IN_PROGRESS = false; - } - // Don't output this C key release event - return Some(event); + if matches!(key, Key::KeyC) + && unsafe { COPY_IN_PROGRESS || CMD_PRESSED || CTRL_PRESSED } + { + unsafe { + COPY_IN_PROGRESS = false; } + // Don't output this C key release event + return Some(event); } // Track modifier key states diff --git a/native/rustfmt.toml b/native/rustfmt.toml new file mode 100644 index 00000000..6e10903e --- /dev/null +++ b/native/rustfmt.toml @@ -0,0 +1,11 @@ +edition = "2021" +max_width = 100 +tab_spaces = 4 +newline_style = "Unix" +use_small_heuristics = "Default" +reorder_imports = true +reorder_modules = true +remove_nested_parens = true +format_code_in_doc_comments = true +normalize_comments = true +wrap_comments = true diff --git a/native/selected-text-reader/Cargo.toml b/native/selected-text-reader/Cargo.toml index 5f84d2dd..7696b592 100644 --- a/native/selected-text-reader/Cargo.toml +++ b/native/selected-text-reader/Cargo.toml @@ -21,3 +21,6 @@ accessibility-sys-ng = "0.1" active-win-pos-rs = "0.8" core-foundation = "0.9" libc = "0.2" + +[lints] +workspace = true diff --git a/native/selected-text-reader/src/macos.rs b/native/selected-text-reader/src/macos.rs index f5232cb2..a262758a 100644 --- a/native/selected-text-reader/src/macos.rs +++ b/native/selected-text-reader/src/macos.rs @@ -1,14 +1,11 @@ use arboard::Clipboard; use libc::c_void; -use lru::LruCache; -use parking_lot::Mutex; use std::ptr; use std::thread; use std::time::Duration; -static GET_SELECTED_TEXT_METHOD: Mutex>> = Mutex::new(None); - -// Count characters as the editor sees them (on macOS, just use normal char count) +// Count characters as the editor sees them (on macOS, just use normal char +// count) pub fn count_editor_chars(text: &str) -> usize { text.chars().count() } @@ -22,10 +19,8 @@ type CGKeyCode = u16; type CGEventFlags = u64; const CG_EVENT_FLAG_MASK_COMMAND: CGEventFlags = 0x100000; const CG_EVENT_FLAG_MASK_SHIFT: CGEventFlags = 0x020000; -const CG_EVENT_FLAG_MASK_CONTROL: CGEventFlags = 0x040000; type CGEventTapLocation = u32; -const CG_HID_EVENT_TAP: CGEventTapLocation = 0; const CG_SESSION_EVENT_TAP: CGEventTapLocation = 1; extern "C" { @@ -60,13 +55,15 @@ pub fn get_selected_text() -> Result> { // Get the copied text from clipboard (this is what was selected) let selected_text = clipboard.get_text().unwrap_or_default(); - // Always restore original clipboard contents - ITO is cutting on behalf of user for context + // Always restore original clipboard contents - ITO is cutting on behalf of user + // for context let _ = clipboard.set_text(original_clipboard); Ok(selected_text) } -// Native macOS Cmd+C implementation using raw Quartz C API - matching Python exactly +// Native macOS Cmd+C implementation using raw Quartz C API - matching Python +// exactly pub fn native_cmd_c() -> Result<(), Box> { unsafe { // Key code for 'C' is 8 on macOS @@ -112,8 +109,9 @@ pub fn select_previous_chars_and_copy( char_count: usize, clipboard: &mut Clipboard, ) -> Result> { - // Send Shift+Left N times to select precursor text (copied from working get_context) - for i in 0..char_count { + // Send Shift+Left N times to select precursor text (copied from working + // get_context) + for _i in 0..char_count { unsafe { let key_down_event = CGEventCreateKeyboardEvent(ptr::null_mut(), 123, true); // Left arrow let key_up_event = CGEventCreateKeyboardEvent(ptr::null_mut(), 123, false); @@ -172,14 +170,15 @@ pub fn select_previous_chars_and_copy( Ok(context_text) } - // Shift cursor right while deselecting text -pub fn shift_cursor_right_with_deselect(char_count: usize) -> Result<(), Box> { +pub fn shift_cursor_right_with_deselect( + char_count: usize, +) -> Result<(), Box> { if char_count == 0 { return Ok(()); } - for i in 0..char_count { + for _i in 0..char_count { unsafe { let right_arrow_key_code: CGKeyCode = 124; // Right Arrow key code let key_down = CGEventCreateKeyboardEvent(ptr::null_mut(), right_arrow_key_code, true); @@ -210,3 +209,16 @@ pub fn shift_cursor_right_with_deselect(char_count: usize) -> Result<(), Box(&l) { - if let Err(e) = cmd_tx.send(command) { - eprintln!( - "[selected-text-reader] Failed to send command to processor: {}", - e - ); - break; - } + for l in stdin.lock().lines().map_while(Result::ok) { + if l.trim().is_empty() { + continue; + } + if let Ok(command) = serde_json::from_str::(&l) { + if let Err(e) = cmd_tx.send(command) { + eprintln!( + "[selected-text-reader] Failed to send command to processor: {}", + e + ); + break; } } } @@ -216,7 +214,7 @@ fn get_selected_text() -> Result> { macos::get_selected_text() } -#[cfg(any(target_os = "windows"))] +#[cfg(target_os = "windows")] fn get_selected_text() -> Result> { windows::get_selected_text() } @@ -276,7 +274,8 @@ fn get_cursor_context(context_length: usize) -> Result Result { let full_context_char_count = count_editor_chars(&full_context_text); - // Undo by the absolute difference between original selected text and total selection - let chars_to_undo = (full_context_char_count as i32 - - selected_char_count as i32) - .abs() as usize; + // Undo by the absolute difference between original selected text and + // total selection + let chars_to_undo = + (full_context_char_count as i32 - selected_char_count as i32) + .unsigned_abs() as usize; if chars_to_undo > 0 { let _ = shift_cursor_right_with_deselect(chars_to_undo); } - // Return only the newly added context (first n characters where n is the difference) + // Return only the newly added context (first n characters where n is + // the difference) let new_context_char_count = full_context_char_count - selected_char_count; full_context_text @@ -322,7 +323,7 @@ fn copy_selected_text() -> Result<(), Box> { macos::native_cmd_c() } -#[cfg(any(target_os = "windows"))] +#[cfg(target_os = "windows")] fn copy_selected_text() -> Result<(), Box> { windows::copy_selected_text() } @@ -335,7 +336,7 @@ fn select_previous_chars_and_copy( macos::select_previous_chars_and_copy(char_count, clipboard) } -#[cfg(any(target_os = "windows"))] +#[cfg(target_os = "windows")] fn select_previous_chars_and_copy( char_count: usize, clipboard: &mut Clipboard, @@ -348,7 +349,7 @@ fn shift_cursor_right_with_deselect(char_count: usize) -> Result<(), Box Result<(), Box> { windows::shift_cursor_right_with_deselect(char_count) } @@ -358,7 +359,7 @@ fn count_editor_chars(text: &str) -> usize { macos::count_editor_chars(text) } -#[cfg(any(target_os = "windows"))] +#[cfg(target_os = "windows")] fn count_editor_chars(text: &str) -> usize { windows::count_editor_chars(text) } diff --git a/native/selected-text-reader/src/windows.rs b/native/selected-text-reader/src/windows.rs index 870bcfd3..0f8a8111 100644 --- a/native/selected-text-reader/src/windows.rs +++ b/native/selected-text-reader/src/windows.rs @@ -1,11 +1,13 @@ use arboard::Clipboard; +use selection::get_text; use std::thread; use std::time::Duration; -use selection::get_text; -// Count characters as the editor sees them (CRLF = 1 cursor position on Windows) +// Count characters as the editor sees them (CRLF = 1 cursor position on +// Windows) pub fn count_editor_chars(text: &str) -> usize { - // On Windows, editors treat CRLF as a single cursor position when navigating with arrow keys + // On Windows, editors treat CRLF as a single cursor position when navigating + // with arrow keys text.replace("\r\n", "\n").chars().count() } @@ -14,9 +16,8 @@ pub fn get_selected_text() -> Result> { Ok(selected_text) } - pub fn copy_selected_text() -> Result<(), Box> { - use enigo::{Enigo, Key, Keyboard, Settings, Direction}; + use enigo::{Direction, Enigo, Key, Keyboard, Settings}; let mut enigo = Enigo::new(&Settings::default())?; enigo.key(Key::Control, Direction::Press)?; @@ -27,7 +28,7 @@ pub fn copy_selected_text() -> Result<(), Box> { } fn cut_selected_text() -> Result<(), Box> { - use enigo::{Enigo, Key, Keyboard, Settings, Direction}; + use enigo::{Direction, Enigo, Key, Keyboard, Settings}; let mut enigo = Enigo::new(&Settings::default())?; enigo.key(Key::Control, Direction::Press)?; @@ -37,7 +38,6 @@ fn cut_selected_text() -> Result<(), Box> { Ok(()) } - // Simple function to select previous N characters and copy them pub fn select_previous_chars_and_copy( char_count: usize, @@ -47,7 +47,7 @@ pub fn select_previous_chars_and_copy( for _ in 0..char_count { #[cfg(target_os = "windows")] { - use enigo::{Enigo, Key, Keyboard, Settings, Direction}; + use enigo::{Direction, Enigo, Key, Keyboard, Settings}; let mut enigo = Enigo::new(&Settings::default())?; enigo.key(Key::Shift, Direction::Press)?; enigo.key(Key::LeftArrow, Direction::Click)?; @@ -91,7 +91,7 @@ pub fn shift_cursor_right_with_deselect( for _ in 0..char_count { { - use enigo::{Enigo, Key, Keyboard, Settings, Direction}; + use enigo::{Direction, Enigo, Key, Keyboard, Settings}; let mut enigo = Enigo::new(&Settings::default())?; enigo.key(Key::Shift, Direction::Press)?; enigo.key(Key::RightArrow, Direction::Click)?; @@ -105,3 +105,44 @@ pub fn shift_cursor_right_with_deselect( Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_count_editor_chars_normal_text() { + assert_eq!(count_editor_chars("hello"), 5); + } + + #[test] + fn test_count_editor_chars_with_unix_newline() { + assert_eq!(count_editor_chars("line1\nline2"), 11); + } + + #[test] + fn test_count_editor_chars_with_crlf() { + // Windows CRLF should count as single character + assert_eq!(count_editor_chars("line1\r\nline2"), 11); + } + + #[test] + fn test_count_editor_chars_multiple_crlf() { + assert_eq!(count_editor_chars("a\r\nb\r\nc"), 5); + } + + #[test] + fn test_count_editor_chars_unicode() { + assert_eq!(count_editor_chars("Hello δΈ–η•Œ"), 8); + } + + #[test] + fn test_count_editor_chars_emoji() { + assert_eq!(count_editor_chars("Hi πŸ‘‹"), 4); + } + + #[test] + fn test_count_editor_chars_empty() { + assert_eq!(count_editor_chars(""), 0); + } +} diff --git a/native/text-writer/Cargo.toml b/native/text-writer/Cargo.toml index 4d073db9..3f5772bf 100644 --- a/native/text-writer/Cargo.toml +++ b/native/text-writer/Cargo.toml @@ -17,3 +17,6 @@ clipboard-win = "5.0" core-graphics = "0.23" core-foundation = "0.9" cocoa = "0.25" + +[lints] +workspace = true diff --git a/native/text-writer/src/macos_writer.rs b/native/text-writer/src/macos_writer.rs index c7ac6a40..6969f128 100644 --- a/native/text-writer/src/macos_writer.rs +++ b/native/text-writer/src/macos_writer.rs @@ -8,7 +8,8 @@ use std::thread; use std::time::Duration; /// Type text on macOS using clipboard paste approach -/// This avoids character-by-character typing which can cause issues in some apps +/// This avoids character-by-character typing which can cause issues in some +/// apps pub fn type_text_macos(text: &str, _char_delay: u64) -> Result<(), String> { unsafe { // Create an autorelease pool for memory management @@ -66,7 +67,8 @@ pub fn type_text_macos(text: &str, _char_delay: u64) -> Result<(), String> { thread::sleep(Duration::from_millis(10)); key_v_up.post(core_graphics::event::CGEventTapLocation::HID); - // Restore old clipboard contents in background after delay in separate thread to not block + // Restore old clipboard contents in background after delay in separate thread + // to not block if old_contents != nil { // Convert Objective-C string to Rust String to make it Send-safe let old_contents_str = { diff --git a/native/text-writer/src/main.rs b/native/text-writer/src/main.rs index 270a5d4c..fadc13d5 100644 --- a/native/text-writer/src/main.rs +++ b/native/text-writer/src/main.rs @@ -97,7 +97,8 @@ fn main() { // Patch fix: Send 'A' key release to clean up any phantom stuck KeyA events // This addresses a bug where synthetic events from text typing can cause - // the global key listener to receive keydown events without corresponding keyup events + // the global key listener to receive keydown events without corresponding keyup + // events if let Err(e) = enigo.key(Key::Unicode('a'), enigo::Direction::Release) { // Don't exit on this error since it's just a cleanup operation eprintln!("Warning: Failed to send cleanup 'a' key release: {}", e); diff --git a/native/text-writer/src/windows_writer.rs b/native/text-writer/src/windows_writer.rs index 27d9dd3c..8f68975b 100644 --- a/native/text-writer/src/windows_writer.rs +++ b/native/text-writer/src/windows_writer.rs @@ -5,7 +5,8 @@ use std::thread; use std::time::Duration; /// Type text on Windows using clipboard paste approach -/// This mimics the macOS implementation to avoid character-by-character typing issues +/// This mimics the macOS implementation to avoid character-by-character typing +/// issues pub fn type_text_windows(text: &str, _char_delay: u64) -> Result<(), String> { // Store current clipboard contents to restore later let old_contents: Result = get_clipboard(formats::Unicode); diff --git a/package.json b/package.json index 924bd24c..429fedb7 100644 --- a/package.json +++ b/package.json @@ -33,13 +33,19 @@ "type-check": "tsc --noEmit --project tsconfig.node.json", "format:app": "prettier app lib --check", "format": "prettier . --check", - "runAllTests": "bun runLibTests && bun runServerTests", + "runAllTests": "bun runLibTests && bun runServerTests && bun runNativeTests", "runLibTests": "find lib -name \"*.test.ts\" | xargs -I {} sh -c 'bun test --preload lib/__tests__/setup.ts {} || exit 255'", "runServerTests": "find server/src -name \"*.test.ts\" | xargs -I {} sh -c 'bun test {} || exit 255'", + "runNativeTests": "cd native && cargo test --workspace --quiet", "runTest": "bun test --preload lib/__tests__/setup.ts", + "format:native": "cd native && cargo fmt --all -- --check", + "format:fix:native": "cd native && cargo fmt --all", + "lint:native": "cd native && cargo clippy --workspace --all-targets -- -D warnings", + "lint:fix:native": "cd native && cargo clippy --workspace --all-targets --fix --allow-dirty --allow-staged", "clean": "rm -rf node_modules dist .vite", "clean:ito-app-data": "bun run scripts/clean-app-data.js", - "build:rust:mac": "bash ./build-binaries.sh --mac --universal", + "build:rust:mac": "bash ./build-binaries.sh --mac", + "build:rust:mac:x64": "bash ./build-binaries.sh --mac --x64", "build:rust:win": "bash ./build-binaries.sh --windows", "build:win": "bash ./build-app.sh windows", "build:mac": "bash ./build-app.sh mac",