Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,38 @@ concurrency:

jobs:
check:
name: Format, lints and tests
runs-on: macos-15
name: Format, lints and tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-15, windows-2025]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
- run: cargo fmt --all -- --check
- name: The probe body is formatted too
run: rustfmt --check --edition 2024 crates/cp-mac/examples/probe/battery.rs
- run: cargo clippy --workspace --all-targets -- -D warnings
- run: cargo test --workspace
# El ciclo real contra el portapapeles del sistema. No cabe en cargo
# test porque NSPasteboard exige el hilo principal y el runner no lo
# garantiza.
- run: cargo run -p cp-mac --example probe
if: runner.os == 'macOS'
- run: cargo run -p cp-win --example probe
if: runner.os == 'Windows'

cross:
name: The macOS crates still build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-apple-darwin
- uses: Swatinem/rust-cache@v2
- run: cargo check --target aarch64-apple-darwin -p cp-mac -p cp-mac-sys

deny:
name: Dependency audit
Expand Down
66 changes: 48 additions & 18 deletions .github/workflows/rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ jobs:

- name: The core produces no terminal output
run: |
# Al principio de línea o tras un operador: un `println!` dentro de
# una cadena de prueba es el texto que se clasifica, no una impresión.
if grep -rnE '^[^"]*(^|[ \t{;(=>|&])(e?print(ln)?!)' crates/cp-core/src --include='*.rs'; then
echo "cp-core no imprime: usa tracing"; exit 1
fi
Expand All @@ -40,7 +38,7 @@ jobs:
- name: No Spanish identifiers
run: |
if grep -rnE '\b(fecha|limite|prioridad|filtro|tarea|titulo|etiqueta|imagen|archivo) *:' \
crates/*/src --include='*.rs' | grep -v '"'; then
crates/*/src --include='*.rs' | grep -v '"' | grep -vE ':[0-9]+: *///?!?'; then
echo "los identificadores van en ingles"; exit 1
fi

Expand All @@ -58,15 +56,32 @@ jobs:
echo "espanol neutro: archivo, computador, presiona"; exit 1
fi

- name: No prose blocks in the code
- name: The code carries no comments but SAFETY
run: |
awk '/^[ \t]*\/\/[^\/!]/ { n++; if (n > 3) { print FILENAME":"FNR": bloque de prosa"; bad = 1 }; next }
{ n = 0 }
if grep -rnE '^[ ]*//' crates --include='*.rs' | grep -v 'SAFETY:'; then
echo "el codigo va sin comentarios; lo que haya que explicar va al expediente"; exit 1
fi

- name: Every SAFETY note is one line of English
run: |
if ! grep -rh 'SAFETY:' crates --include='*.rs' | iconv -f utf-8 -t ascii >/dev/null; then
echo "las notas SAFETY van en ingles"; exit 1
fi
awk '/SAFETY:/ { safety = 1; next }
/^[ ]*\/\// { if (safety) { print FILENAME":"FNR": la nota SAFETY sigue en otra linea"; bad = 1 } }
{ safety = 0 }
END { exit bad }' $(find crates -name '*.rs')

deterministic:
name: Tests are deterministic
runs-on: macos-15
name: Tests are deterministic (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-15, windows-2025]
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
Expand All @@ -75,17 +90,22 @@ jobs:
run: for i in $(seq 1 20); do cargo test -p cp-core --quiet || exit 1; done

mutants:
name: The suite kills every mutant
runs-on: macos-15
name: Every mutant dies in the crates without a system call (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: macos-15
crates: -p cp-core -p cp-store
- os: windows-2025
crates: -p cp-core -p cp-store -p cp-win
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@cargo-mutants
# Una prueba que pasa contra un núcleo mutado no está probando nada. El
# criterio de aceptación de la Etapa 0 es exactamente este: la batería
# tiene que fallar contra una implementación que no sepa lo que sabemos.
- run: cargo mutants -p cp-core -p cp-store --no-times
- run: cargo mutants ${{ matrix.crates }} --no-times

coverage:
name: Coverage does not slip
Expand All @@ -97,12 +117,24 @@ jobs:
components: llvm-tools-preview
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@cargo-llvm-cov
# El arnés entra en la medición: sin él, todo el código de plataforma
# aparece a cero y el número miente en las dos direcciones.
- run: cargo llvm-cov --no-report --workspace
- run: cargo llvm-cov --no-report run -p cp-mac --example probe
- run: cargo llvm-cov report --fail-under-lines 90 --summary-only

coverage-windows:
name: Coverage does not slip on Windows
runs-on: windows-2025
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@cargo-llvm-cov
- run: cargo llvm-cov --no-report -p cp-core -p cp-store -p cp-win -p cp-win-sys
- run: cargo llvm-cov --no-report run -p cp-win --example probe
- run: cargo llvm-cov report --fail-under-lines 95 --summary-only

budget:
name: Latency stays within budget
runs-on: macos-15
Expand All @@ -112,6 +144,4 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
# Busca regresiones de orden de magnitud —una consulta que deja de usar
# el índice—, no microsegundos. Por eso corre en release y con holgura.
- run: cargo run -p cp-store --release --example budget
123 changes: 123 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ cp-core = { path = "crates/cp-core" }
cp-store = { path = "crates/cp-store" }
cp-mac-sys = { path = "crates/cp-mac-sys" }
cp-mac = { path = "crates/cp-mac" }
cp-win = { path = "crates/cp-win" }
cp-win-sys = { path = "crates/cp-win-sys" }

thiserror = "2"
tracing = "0.1"
Expand All @@ -28,6 +30,29 @@ image = { version = "0.25", default-features = false, features = ["png", "jpeg",
proptest = "1"
tempfile = "3"

windows = { version = "0.62", features = [
"Win32_Foundation",
"Win32_System_DataExchange",
"Win32_System_Memory",
"Win32_System_Ole",
"Win32_System_Threading",
"Win32_UI_WindowsAndMessaging",
"Win32_Graphics_Gdi",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_Security",
"Media_Ocr",
"Graphics_Imaging",
"Storage_Streams",
"Foundation_Collections",
"Win32_UI_Shell",
"Win32_UI_Shell_PropertiesSystem",
"Win32_System_Com",
"Win32_System_Com_StructuredStorage",
"Win32_System_Variant",
] }

windows-future = "0.3"

objc2 = "0.6"
objc2-foundation = "0.3"
objc2-app-kit = "0.3"
Expand Down
1 change: 1 addition & 0 deletions PRIVACY.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ For each clipboard item, CopyPaste also stores:
- **Timestamp** — When the item was copied
- **Content type** — Text, Image, File, Folder, Link, Audio, or Video
- **Source application** — The name of the app where you copied from (_window title_)
- **Source URL** — For content copied from a browser, the address of the page it came from, when the browser offers it. Rich text (HTML) can also carry that address embedded in the content itself. **This includes the full query string**, so a page reached through a password-reset link, a signed URL or a session token keeps that token in your history until the entry is deleted or expires under your retention setting.
- **User labels** — Custom labels you assign to items (optional)
- **Color tags** — Color categories you assign (optional)
- **Pin status** — Whether you pinned the item
Expand Down
Loading
Loading