diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..b576125 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,91 @@ +name: test +on: + workflow_dispatch: + push: + branches: [main] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + testbed: + runs-on: [self-hosted, intel-cpu, 8-cpu, ci] + container: + image: ubuntu:22.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + apt update + DEBIAN_FRONTEND=noninteractive apt install -y pkg-config protobuf-compiler libssl-dev curl build-essential git-all gfortran + + - name: Install Rust toolchain + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + rustflags: '' + toolchain: nightly + + - name: Install Python 3.10 + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install node 18 + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install yarn + run: | + npm i -g yarn + + - name: Set up cargo cache + uses: actions/cache@v3 + continue-on-error: false + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }} + + - name: Build project + run: cargo build -r + + - name: Run testbed + run: cargo run --bin testbed -r -- --api-token $API_TOKEN -r `pwd`/crates/testbed/repositories-ci.yaml + if: github.event_name == 'push' || github.event_name == 'pull_request' + env: + API_TOKEN: ${{ secrets.API_TOKEN }} + + - name: Run testbed + run: cargo run --bin testbed -r -- --api-token $API_TOKEN + if: github.event_name == 'workflow_dispatch' + env: + API_TOKEN: ${{ secrets.API_TOKEN }} + + - name: Find Comment + uses: peter-evans/find-comment@v2 + id: fc + if: github.event_name == 'pull_request' + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: '| Repository name | Source type | Average hole completion time (s) | Pass percentage |' + + - name: Create or update comment + if: github.event_name == 'pull_request' + uses: peter-evans/create-or-update-comment@v3 + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body-path: results.md + edit-mode: replace + diff --git a/.gitignore b/.gitignore index 5076b76..23e953b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ +.vscode/ dist/ target/ +.DS_Store +__pycache__/ +results.md +.pytest_cache/ diff --git a/Cargo.lock b/Cargo.lock index 02c6fb8..ad417b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,21 +18,71 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -name = "aho-corasick" -version = "0.7.20" +name = "aes" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] -name = "aho-corasick" -version = "1.0.5" +name = "anstream" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" dependencies = [ - "memchr", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +dependencies = [ + "anstyle", + "windows-sys", ] [[package]] @@ -78,7 +128,7 @@ checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", "axum-core", - "bitflags", + "bitflags 1.3.2", "bytes", "futures-util", "http", @@ -146,12 +196,33 @@ version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.13.0" @@ -170,12 +241,34 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] @@ -185,6 +278,93 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.31", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.3.2" @@ -237,6 +417,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "darling" version = "0.14.4" @@ -322,6 +512,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "either" version = "1.9.0" @@ -338,10 +539,32 @@ dependencies = [ ] [[package]] -name = "esaxx-rs" -version = "0.1.8" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f748b253ceca9fed5f42f8b5ceb3851e93102199bc25b64b65369f76e5c0a35" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "esaxx-rs" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6" + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "flate2" @@ -359,6 +582,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.0" @@ -376,6 +614,7 @@ checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -398,6 +637,17 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.28" @@ -445,6 +695,16 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -474,7 +734,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -493,12 +753,27 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "home" version = "0.5.5" @@ -580,6 +855,19 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -606,6 +894,25 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "indexmap" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad227c3af19d4914570ad36d30409928b75967c298feb9ea1969db3a610bb14e" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "ipnet" version = "2.8.0" @@ -614,18 +921,9 @@ checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "itertools" -version = "0.8.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] @@ -636,6 +934,15 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.64" @@ -657,6 +964,12 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "linux-raw-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" + [[package]] name = "llm-ls" version = "0.4.0" @@ -713,13 +1026,24 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "lsp-client" +version = "0.1.0" +dependencies = [ + "lsp-types", + "serde", + "serde_json", + "tokio", + "tracing", +] + [[package]] name = "lsp-types" version = "0.94.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1" dependencies = [ - "bitflags", + "bitflags 1.3.2", "serde", "serde_json", "serde_repr", @@ -728,9 +1052,9 @@ dependencies = [ [[package]] name = "macro_rules_attribute" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf0c9b980bf4f3a37fd7b1c066941dd1b1d0152ce6ee6e8fe8c49b9f6810d862" +checksum = "8a82271f7bc033d84bbca59a3ce3e4159938cb08a9c3aebbe54d215131518a13" dependencies = [ "macro_rules_attribute-proc_macro", "paste", @@ -738,9 +1062,9 @@ dependencies = [ [[package]] name = "macro_rules_attribute-proc_macro" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58093314a45e00c77d5c508f76e77c3396afbbc0d01506e7fae47b018bac2b1d" +checksum = "b8dd856d451cc0da70e2ef2ce95a18e39a93b7558bedf10201ad28503f918568" [[package]] name = "matchers" @@ -834,6 +1158,24 @@ dependencies = [ "syn 2.0.31", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nom" version = "7.1.3" @@ -885,7 +1227,7 @@ version = "6.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", "once_cell", "onig_sys", @@ -901,6 +1243,50 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "openssl" +version = "0.10.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.31", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "overload" version = "0.1.1" @@ -930,12 +1316,35 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "paste" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + [[package]] name = "percent-encoding" version = "2.3.0" @@ -1060,9 +1469,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -1070,25 +1479,23 @@ dependencies = [ [[package]] name = "rayon-cond" -version = "0.1.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd1259362c9065e5ea39a789ef40b1e3fd934c94beb7b5ab3ac6629d3b5e7cb7" +checksum = "059f538b55efd2309c9794130bc149c6a553db90e9d99c2030785c82f0bd7df9" dependencies = [ "either", - "itertools 0.8.2", + "itertools", "rayon", ] [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] @@ -1097,7 +1504,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1106,7 +1513,7 @@ version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" dependencies = [ - "aho-corasick 1.0.5", + "aho-corasick", "memchr", "regex-automata 0.3.8", "regex-syntax 0.7.5", @@ -1127,7 +1534,7 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" dependencies = [ - "aho-corasick 1.0.5", + "aho-corasick", "memchr", "regex-syntax 0.7.5", ] @@ -1160,10 +1567,12 @@ dependencies = [ "http-body", "hyper", "hyper-rustls", + "hyper-tls", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -1173,11 +1582,14 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", + "tokio-native-tls", "tokio-rustls", + "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "webpki-roots", "winreg", @@ -1214,6 +1626,19 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustix" +version = "0.38.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "rustls" version = "0.21.7" @@ -1257,6 +1682,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1273,6 +1707,29 @@ dependencies = [ "untrusted", ] +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.188" @@ -1337,6 +1794,41 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +dependencies = [ + "indexmap 2.0.1", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -1420,6 +1912,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -1449,19 +1947,59 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] -name = "thiserror" -version = "1.0.48" +name = "tempfile" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys", +] + +[[package]] +name = "testbed" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "futures", + "futures-util", + "home", + "lsp-client", + "lsp-types", + "rand", + "reqwest", + "ropey", + "serde", + "serde_json", + "serde_yaml", + "tempfile", + "tokio", + "tokio-util", + "tracing", + "tracing-subscriber", + "url", + "uuid", + "zip", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", @@ -1523,15 +2061,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokenizers" -version = "0.13.4" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aea68938177975ab09da68552b720eac941779ff386baceaf77e0f5f9cea645f" +checksum = "d9be88c795d8b9f9c4002b3a8f26a6d0876103a6f523b32ea3bac52d8560c17c" dependencies = [ - "aho-corasick 0.7.20", + "aho-corasick", "derive_builder", "esaxx-rs", "getrandom", - "itertools 0.9.0", + "itertools", "lazy_static", "log", "macro_rules_attribute", @@ -1582,6 +2120,16 @@ dependencies = [ "syn 2.0.31", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -1600,6 +2148,7 @@ checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -1981,6 +2530,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -2023,6 +2578,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "unsafe-libyaml" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" + [[package]] name = "untrusted" version = "0.7.1" @@ -2042,10 +2603,16 @@ dependencies = [ ] [[package]] -name = "uuid" -version = "1.4.1" +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" dependencies = [ "getrandom", "rand", @@ -2058,6 +2625,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -2145,6 +2718,19 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +[[package]] +name = "wasm-streams" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.64" @@ -2314,9 +2900,45 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" dependencies = [ + "aes", "byteorder", + "bzip2", + "constant_time_eq", "crc32fast", "crossbeam-utils", "flate2", + "hmac", + "pbkdf2", + "sha1", "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", ] diff --git a/Cargo.toml b/Cargo.toml index 5a0df45..05e3a1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,17 @@ [workspace] members = ["xtask/", "crates/*"] resolver = "2" +exclude = ["crates/testbed/repositories/*"] [workspace.package] edition = "2021" license = "Apache-2.0" authors = ["Luc Georges "] -[profile.dev] +# [profile.dev] # Disabling debug info speeds up builds a bunch, # and we don't rely on it for debugging that much. -debug = 0 +# debug = 0 [profile.dev.package] # This speeds up `cargo xtask dist`. diff --git a/crates/llm-ls/Cargo.toml b/crates/llm-ls/Cargo.toml index bd8b823..cdc75cc 100644 --- a/crates/llm-ls/Cargo.toml +++ b/crates/llm-ls/Cargo.toml @@ -9,11 +9,20 @@ name = "llm-ls" [dependencies] home = "0.5" ropey = "1.6" -reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] } +reqwest = { version = "0.11", default-features = false, features = [ + "json", + "rustls-tls", +] } serde = { version = "1", features = ["derive"] } serde_json = "1" -tokenizers = { version = "0.13", default-features = false, features = ["onig"] } -tokio = { version = "1", features = ["fs", "io-std", "io-util", "macros", "rt-multi-thread"] } +tokenizers = { version = "0.14", default-features = false, features = ["onig"] } +tokio = { version = "1", features = [ + "fs", + "io-std", + "io-util", + "macros", + "rt-multi-thread", +] } tower-lsp = "0.20" tracing = "0.1" tracing-appender = "0.2" @@ -43,8 +52,4 @@ tree-sitter-typescript = "0.20" [dependencies.uuid] version = "1.4" -features = [ - "v4", - "fast-rng", - "serde", -] +features = ["v4", "fast-rng", "serde"] diff --git a/crates/llm-ls/src/main.rs b/crates/llm-ls/src/main.rs index 1b8ed40..17c2149 100644 --- a/crates/llm-ls/src/main.rs +++ b/crates/llm-ls/src/main.rs @@ -663,7 +663,7 @@ impl LanguageServer for Backend { async fn initialized(&self, _: InitializedParams) { self.client - .log_message(MessageType::INFO, "{llm-ls} initialized") + .log_message(MessageType::INFO, "llm-ls initialized") .await; info!("initialized language server"); } @@ -686,15 +686,15 @@ impl LanguageServer for Backend { Err(err) => error!("error opening {uri}: {err}"), } self.client - .log_message(MessageType::INFO, "{llm-ls} file opened") + .log_message(MessageType::INFO, format!("{uri} opened")) .await; } async fn did_change(&self, params: DidChangeTextDocumentParams) { - self.client - .log_message(MessageType::INFO, "{llm-ls} file changed") - .await; let uri = params.text_document.uri.to_string(); + self.client + .log_message(MessageType::INFO, format!("{uri} changed")) + .await; let mut document_map = self.document_map.write().await; let doc = document_map.get_mut(&uri); if let Some(doc) = doc { @@ -708,20 +708,20 @@ impl LanguageServer for Backend { } async fn did_save(&self, params: DidSaveTextDocumentParams) { - self.client - .log_message(MessageType::INFO, "{llm-ls} file saved") - .await; let uri = params.text_document.uri.to_string(); + self.client + .log_message(MessageType::INFO, format!("{uri} saved")) + .await; info!("{uri} saved"); } // TODO: // textDocument/didClose async fn did_close(&self, params: DidCloseTextDocumentParams) { - self.client - .log_message(MessageType::INFO, "{llm-ls} file closed") - .await; let uri = params.text_document.uri.to_string(); + self.client + .log_message(MessageType::INFO, format!("{uri} closed")) + .await; info!("{uri} closed"); } diff --git a/crates/lsp-client/Cargo.toml b/crates/lsp-client/Cargo.toml new file mode 100644 index 0000000..8dcd552 --- /dev/null +++ b/crates/lsp-client/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "lsp-client" +version = "0.1.0" +edition.workspace = true +license.workspace = true +authors.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +lsp-types = "0.94" +serde = "1" +serde_json = "1" +tokio = { version = "1", features = ["io-util", "process"] } +tracing = "0.1" + diff --git a/crates/lsp-client/README.md b/crates/lsp-client/README.md new file mode 100644 index 0000000..1160f5d --- /dev/null +++ b/crates/lsp-client/README.md @@ -0,0 +1,5 @@ +# LSP Client + +Rust LSP Client. + +Heavily inspired by rust-analyzer's lsp-server implementation. diff --git a/crates/lsp-client/src/client.rs b/crates/lsp-client/src/client.rs new file mode 100644 index 0000000..8fe3789 --- /dev/null +++ b/crates/lsp-client/src/client.rs @@ -0,0 +1,130 @@ +use std::sync::Arc; + +use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender}; +use tokio::sync::{oneshot, Mutex}; +use tokio::task::JoinHandle; +use tracing::{debug, error}; + +use crate::error::Result; +use crate::msg::{Message, Notification, Request, Response}; +use crate::res_queue::ResQueue; +use crate::server::Server; + +pub struct Connection { + pub(crate) sender: UnboundedSender, + pub(crate) receiver: UnboundedReceiver, +} + +#[derive(Clone)] +pub struct LspClient { + reader_thread: Arc>, + res_queue: Arc>>>, + server: Arc, + server_sender: UnboundedSender, +} + +impl LspClient { + pub async fn new(conn: Connection, server: Server) -> Self { + let res_queue = Arc::new(Mutex::new(ResQueue::default())); + let res_queue_clone = res_queue.clone(); + let mut rx = conn.receiver; + let reader_thread = tokio::spawn(async move { + while let Some(msg) = rx.recv().await { + match msg { + Message::Request(req) => Self::on_request(req), + Message::Notification(not) => Self::on_notification(not), + Message::Response(res) => { + Self::complete_request(res_queue_clone.clone(), res).await + } + } + } + }); + Self { + reader_thread: Arc::new(reader_thread), + res_queue, + server: Arc::new(server), + server_sender: conn.sender, + } + } + + fn on_request(_req: Request) { + todo!("requests are not handled by client"); + } + + fn on_notification(not: Notification) { + debug!("received notification: {not:?}"); + } + + pub async fn send_request( + &self, + params: R::Params, + ) -> Result { + let (sender, receiver) = oneshot::channel::(); + let request = + self.res_queue + .lock() + .await + .outgoing + .register(R::METHOD.to_string(), params, sender); + + self.send(request.into()); + Ok(receiver.await?) + } + + async fn complete_request( + res_queue: Arc>>>, + response: Response, + ) { + let sender = res_queue + .lock() + .await + .outgoing + .complete(response.id.clone()) + .expect("received response for unknown request"); + + sender.send(response).unwrap(); + } + + pub fn send_notification(&self, params: N::Params) { + let not = Notification::new(N::METHOD.to_string(), params); + self.send(not.into()); + } + + pub async fn shutdown(&self) -> Result<()> { + self.send_request::(()) + .await?; + Ok(()) + } + + /// Exit will join on server threads waiting for exit. + /// + /// This will fail if there are other strong references to the [`Server`] instance + pub async fn exit(self) { + self.send_notification::(()); + + match Arc::into_inner(self.reader_thread) { + Some(reader) => match reader.await { + Ok(r) => r, + Err(err) => { + error!("client reader panicked!"); + std::panic::panic_any(err) + } + }, + None => error!("error joining client thread, resources may have been leaked"), + }; + + match Arc::into_inner(self.server) { + Some(server) => { + match server.join().await { + Ok(_) => (), + Err(err) => error!("thread exited with error: {}", err), + }; + } + None => error!("error joining server threads, resources may have been leaked"), + }; + } + + fn send(&self, message: Message) { + self.server_sender.send(message).unwrap(); + } +} diff --git a/crates/lsp-client/src/error.rs b/crates/lsp-client/src/error.rs new file mode 100644 index 0000000..32f82fb --- /dev/null +++ b/crates/lsp-client/src/error.rs @@ -0,0 +1,95 @@ +use std::fmt; +use std::io; + +use tokio::sync::oneshot::error::RecvError; + +use crate::msg::ResponseError; + +#[derive(Debug, Clone, PartialEq)] +pub struct ProtocolError(pub(crate) String); + +impl std::error::Error for ProtocolError {} + +impl fmt::Display for ProtocolError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +#[derive(Debug)] +pub enum ExtractError { + /// The extracted message was of a different method than expected. + MethodMismatch(String, String), + /// Failed to deserialize the message. + JsonError { + msg_type: String, + method: Option, + error: serde_json::Error, + }, + /// Server responded with an Error + ResponseError { error: ResponseError }, +} + +impl std::error::Error for ExtractError {} + +impl fmt::Display for ExtractError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ExtractError::MethodMismatch(asked, req_method) => { + write!( + f, + "Method mismatch for request, extract for '{}' != request method '{}'", + asked, req_method + ) + } + ExtractError::JsonError { + msg_type, + method, + error, + } => { + let method = if let Some(method) = method { + method.clone() + } else { + "None".to_owned() + }; + write!(f, "Invalid message body\nMessage type: {msg_type}\nMethod: {method}\n error: {error}",) + } + ExtractError::ResponseError { error } => { + write!(f, "Server answered with an error message\n error: {error}",) + } + } + } +} + +#[derive(Debug)] +pub enum Error { + ChannelClosed(RecvError), + Io(io::Error), + MissingBinaryPath, +} + +impl std::error::Error for Error {} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::ChannelClosed(e) => write!(f, "Channel closed: {}", e), + Error::Io(e) => write!(f, "IO error: {}", e), + Error::MissingBinaryPath => write!(f, "Missing binary path"), + } + } +} + +impl From for Error { + fn from(value: RecvError) -> Self { + Self::ChannelClosed(value) + } +} + +impl From for Error { + fn from(value: io::Error) -> Self { + Self::Io(value) + } +} + +pub type Result = std::result::Result; diff --git a/crates/lsp-client/src/lib.rs b/crates/lsp-client/src/lib.rs new file mode 100644 index 0000000..f0c7284 --- /dev/null +++ b/crates/lsp-client/src/lib.rs @@ -0,0 +1,5 @@ +pub mod client; +pub mod error; +pub mod msg; +pub mod res_queue; +pub mod server; diff --git a/crates/lsp-client/src/msg.rs b/crates/lsp-client/src/msg.rs new file mode 100644 index 0000000..5cbfa00 --- /dev/null +++ b/crates/lsp-client/src/msg.rs @@ -0,0 +1,458 @@ +use std::{ + fmt::{self, Display}, + io, + marker::Unpin, +}; + +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncReadExt, AsyncWrite, AsyncWriteExt}; +use tracing::debug; + +use crate::error::ExtractError; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum Message { + Request(Request), + Response(Response), + Notification(Notification), +} + +impl From for Message { + fn from(request: Request) -> Message { + Message::Request(request) + } +} + +impl From for Message { + fn from(response: Response) -> Message { + Message::Response(response) + } +} + +impl From for Message { + fn from(notification: Notification) -> Message { + Message::Notification(notification) + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[serde(transparent)] +pub struct RequestId(IdRepr); + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[serde(untagged)] +enum IdRepr { + I32(i32), + String(String), +} + +impl From for RequestId { + fn from(id: i32) -> RequestId { + RequestId(IdRepr::I32(id)) + } +} + +impl From for RequestId { + fn from(id: String) -> RequestId { + RequestId(IdRepr::String(id)) + } +} + +impl fmt::Display for RequestId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.0 { + IdRepr::I32(it) => fmt::Display::fmt(it, f), + // Use debug here, to make it clear that `92` and `"92"` are + // different, and to reduce WTF factor if the sever uses `" "` as an + // ID. + IdRepr::String(it) => fmt::Debug::fmt(it, f), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Request { + pub id: RequestId, + pub method: String, + #[serde(default = "serde_json::Value::default")] + #[serde(skip_serializing_if = "serde_json::Value::is_null")] + pub params: serde_json::Value, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "lowercase")] +pub enum ResponseContent { + Result(serde_json::Value), + Error(ResponseError), +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Response { + // JSON RPC allows this to be null if it was impossible + // to decode the request's id. Ignore this special case + // and just die horribly. + pub id: RequestId, + #[serde(flatten)] + pub content: ResponseContent, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ResponseError { + pub code: i32, + pub message: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +impl Display for ResponseError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match ErrorCode::try_from_i32(self.code) { + Ok(code) => write!(f, "{:?} [{}]: {}", code, self.code, self.message), + Err(_) => write!(f, "Unknown error code [{}]: {}", self.code, self.message), + } + } +} + +#[derive(Clone, Copy, Debug)] +#[non_exhaustive] +pub enum ErrorCode { + // Defined by JSON RPC: + ParseError = -32700, + InvalidRequest = -32600, + MethodNotFound = -32601, + InvalidParams = -32602, + InternalError = -32603, + ServerErrorStart = -32099, + ServerErrorEnd = -32000, + + /// Error code indicating that a server received a notification or + /// request before the server has received the `initialize` request. + ServerNotInitialized = -32002, + UnknownErrorCode = -32001, + + // Defined by the protocol: + /// The client has canceled a request and a server has detected + /// the cancel. + RequestCanceled = -32800, + + /// The server detected that the content of a document got + /// modified outside normal conditions. A server should + /// NOT send this error code if it detects a content change + /// in it unprocessed messages. The result even computed + /// on an older state might still be useful for the client. + /// + /// If a client decides that a result is not of any use anymore + /// the client should cancel the request. + ContentModified = -32801, + + /// The server cancelled the request. This error code should + /// only be used for requests that explicitly support being + /// server cancellable. + /// + /// @since 3.17.0 + ServerCancelled = -32802, + + /// A request failed but it was syntactically correct, e.g the + /// method name was known and the parameters were valid. The error + /// message should contain human readable information about why + /// the request failed. + /// + /// @since 3.17.0 + RequestFailed = -32803, +} + +impl ErrorCode { + fn try_from_i32(code: i32) -> Result { + match code { + -32700 => Ok(ErrorCode::ParseError), + -32600 => Ok(ErrorCode::InvalidRequest), + -32601 => Ok(ErrorCode::MethodNotFound), + -32602 => Ok(ErrorCode::InvalidParams), + -32603 => Ok(ErrorCode::InternalError), + -32099 => Ok(ErrorCode::ServerErrorStart), + -32000 => Ok(ErrorCode::ServerErrorEnd), + -32002 => Ok(ErrorCode::ServerNotInitialized), + -32001 => Ok(ErrorCode::UnknownErrorCode), + -32800 => Ok(ErrorCode::RequestCanceled), + -32801 => Ok(ErrorCode::ContentModified), + -32802 => Ok(ErrorCode::ServerCancelled), + -32803 => Ok(ErrorCode::RequestFailed), + _ => Err(()), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Notification { + pub method: String, + #[serde(default = "serde_json::Value::default")] + #[serde(skip_serializing_if = "serde_json::Value::is_null")] + pub params: serde_json::Value, +} + +impl Message { + pub async fn read(r: &mut R) -> io::Result> { + Message::_read(r).await + } + + async fn _read(r: &mut R) -> io::Result> { + let text = match read_msg_text(r).await? { + None => return Ok(None), + Some(text) => text, + }; + let msg = serde_json::from_str(&text)?; + Ok(Some(msg)) + } + + pub async fn write(self, w: &mut W) -> io::Result<()> { + self._write(w).await + } + + async fn _write(self, w: &mut W) -> io::Result<()> { + #[derive(Serialize)] + struct JsonRpc { + jsonrpc: &'static str, + #[serde(flatten)] + msg: Message, + } + let text = serde_json::to_string(&JsonRpc { + jsonrpc: "2.0", + msg: self, + })?; + write_msg_text(w, &text).await + } +} + +impl Response { + pub fn new_ok(id: RequestId, result: R) -> Response { + Response { + id, + content: ResponseContent::Result(serde_json::to_value(result).unwrap()), + } + } + pub fn new_err(id: RequestId, code: i32, message: String) -> Response { + let error = ResponseError { + code, + message, + data: None, + }; + Response { + id, + content: ResponseContent::Error(error), + } + } + + pub fn extract(self) -> Result<(RequestId, P), ExtractError> { + match self.content { + ResponseContent::Result(result) => match serde_json::from_value(result) { + Ok(params) => Ok((self.id, params)), + Err(error) => Err(ExtractError::JsonError { + msg_type: "response".to_owned(), + method: None, + error, + }), + }, + ResponseContent::Error(error) => Err(ExtractError::ResponseError { error }), + } + } +} + +impl Request { + pub fn new(id: RequestId, method: String, params: P) -> Request { + Request { + id, + method, + params: serde_json::to_value(params).unwrap(), + } + } + + pub fn extract( + self, + method: &str, + ) -> Result<(RequestId, P), ExtractError> { + if self.method != method { + return Err(ExtractError::MethodMismatch(self.method, method.to_owned())); + } + match serde_json::from_value(self.params) { + Ok(params) => Ok((self.id, params)), + Err(error) => Err(ExtractError::JsonError { + msg_type: "request".to_owned(), + method: Some(self.method), + error, + }), + } + } +} + +impl Notification { + pub fn new(method: String, params: impl Serialize) -> Notification { + Notification { + method, + params: serde_json::to_value(params).unwrap(), + } + } + + pub fn extract(self, method: &str) -> Result { + if self.method != method { + return Err(ExtractError::MethodMismatch(self.method, method.to_owned())); + } + match serde_json::from_value(self.params) { + Ok(params) => Ok(params), + Err(error) => Err(ExtractError::JsonError { + msg_type: "notification".to_owned(), + method: Some(self.method), + error, + }), + } + } + + pub(crate) fn is_exit(&self) -> bool { + self.method == "exit" + } +} + +async fn read_msg_text( + inp: &mut R, +) -> io::Result> { + fn invalid_data(error: impl Into>) -> io::Error { + io::Error::new(io::ErrorKind::InvalidData, error) + } + macro_rules! invalid_data { + ($($tt:tt)*) => (invalid_data(format!($($tt)*))) + } + + let mut size = None; + let mut buf = String::new(); + loop { + buf.clear(); + if inp.read_line(&mut buf).await? == 0 { + return Ok(None); + } + if !buf.ends_with("\r\n") { + return Err(invalid_data!("malformed header: {:?}", buf)); + } + let buf = &buf[..buf.len() - 2]; + if buf.is_empty() { + break; + } + let mut parts = buf.splitn(2, ": "); + let header_name = parts.next().unwrap(); + let header_value = parts + .next() + .ok_or_else(|| invalid_data!("malformed header: {:?}", buf))?; + if header_name.eq_ignore_ascii_case("Content-Length") { + size = Some(header_value.parse::().map_err(invalid_data)?); + } + } + let size: usize = size.ok_or_else(|| invalid_data!("no Content-Length"))?; + let mut buf = buf.into_bytes(); + buf.resize(size, 0); + inp.read_exact(&mut buf).await?; + let buf = String::from_utf8(buf).map_err(invalid_data)?; + debug!("< {}", buf); + Ok(Some(buf)) +} + +async fn write_msg_text(out: &mut W, msg: &str) -> io::Result<()> { + debug!("> {}", msg); + out.write_all(format!("Content-Length: {}\r\n\r\n", msg.len()).as_bytes()) + .await?; + out.write_all(msg.as_bytes()).await?; + out.flush().await?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use crate::msg::{ResponseContent, ResponseError}; + + use super::{Message, Notification, Request, RequestId, Response}; + + #[test] + fn shutdown_with_explicit_null() { + let text = "{\"jsonrpc\": \"2.0\",\"id\": 3,\"method\": \"shutdown\", \"params\": null }"; + let msg: Message = serde_json::from_str(text).unwrap(); + + assert!( + matches!(msg, Message::Request(req) if req.id == 3.into() && req.method == "shutdown") + ); + } + + #[test] + fn shutdown_with_no_params() { + let text = "{\"jsonrpc\": \"2.0\",\"id\": 3,\"method\": \"shutdown\"}"; + let msg: Message = serde_json::from_str(text).unwrap(); + + assert!( + matches!(msg, Message::Request(req) if req.id == 3.into() && req.method == "shutdown") + ); + } + + #[test] + fn notification_with_explicit_null() { + let text = "{\"jsonrpc\": \"2.0\",\"method\": \"exit\", \"params\": null }"; + let msg: Message = serde_json::from_str(text).unwrap(); + + assert!(matches!(msg, Message::Notification(not) if not.method == "exit")); + } + + #[test] + fn notification_with_no_params() { + let text = "{\"jsonrpc\": \"2.0\",\"method\": \"exit\"}"; + let msg: Message = serde_json::from_str(text).unwrap(); + + assert!(matches!(msg, Message::Notification(not) if not.method == "exit")); + } + + #[test] + fn serialize_request_with_null_params() { + let msg = Message::Request(Request { + id: RequestId::from(3), + method: "shutdown".into(), + params: serde_json::Value::Null, + }); + let serialized = serde_json::to_string(&msg).unwrap(); + + assert_eq!("{\"id\":3,\"method\":\"shutdown\"}", serialized); + } + + #[test] + fn serialize_notification_with_null_params() { + let msg = Message::Notification(Notification { + method: "exit".into(), + params: serde_json::Value::Null, + }); + let serialized = serde_json::to_string(&msg).unwrap(); + + assert_eq!("{\"method\":\"exit\"}", serialized); + } + + #[test] + fn serialize_response_with_null_result() { + let text = "{\"id\":1,\"result\":null}"; + let msg = Message::Response(Response { + id: RequestId::from(1), + content: ResponseContent::Result(serde_json::Value::Null), + }); + let serialized = serde_json::to_string(&msg).unwrap(); + + assert_eq!(text, serialized); + } + + #[test] + fn serialize_response_with_error() { + let text = "{\"id\":1,\"error\":{\"code\":-32603,\"message\":\"some error message\"}}"; + let msg = Message::Response(Response { + id: RequestId::from(1), + content: ResponseContent::Error(ResponseError { + code: -32603, + message: "some error message".to_owned(), + data: None, + }), + }); + let serialized = serde_json::to_string(&msg).unwrap(); + + assert_eq!(text, serialized); + } +} diff --git a/crates/lsp-client/src/res_queue.rs b/crates/lsp-client/src/res_queue.rs new file mode 100644 index 0000000..fd1e066 --- /dev/null +++ b/crates/lsp-client/src/res_queue.rs @@ -0,0 +1,41 @@ +use std::collections::HashMap; + +use serde::Serialize; + +use crate::msg::{Request, RequestId}; + +/// Manages the set of pending responses +#[derive(Debug)] +pub struct ResQueue { + pub outgoing: Outgoing, +} + +impl Default for ResQueue { + fn default() -> ResQueue { + ResQueue { + outgoing: Outgoing { + next_id: 0, + pending: HashMap::default(), + }, + } + } +} + +#[derive(Debug)] +pub struct Outgoing { + next_id: i32, + pending: HashMap, +} + +impl Outgoing { + pub fn register(&mut self, method: String, params: P, data: O) -> Request { + let id = RequestId::from(self.next_id); + self.pending.insert(id.clone(), data); + self.next_id += 1; + Request::new(id, method, params) + } + + pub fn complete(&mut self, id: RequestId) -> Option { + self.pending.remove(&id) + } +} diff --git a/crates/lsp-client/src/server.rs b/crates/lsp-client/src/server.rs new file mode 100644 index 0000000..4b807fd --- /dev/null +++ b/crates/lsp-client/src/server.rs @@ -0,0 +1,148 @@ +use std::{io, path::PathBuf, process::Stdio}; + +use tokio::{ + io::{BufReader, BufWriter}, + process::{Child, Command}, + sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, + task::JoinHandle, +}; +use tracing::{debug, error}; + +use crate::msg::Message; +use crate::{ + client::Connection, + error::{Error, Result}, +}; + +pub struct Server { + threads: IoThreads, +} + +impl Server { + pub fn build() -> ServerBuilder { + ServerBuilder { + binary_path: None, + command: None, + transport: Transport::default(), + } + } + + /// join server's threads to the current thread + pub async fn join(self) -> Result<()> { + self.threads.join().await?; + Ok(()) + } +} + +#[derive(Default)] +pub enum Transport { + #[default] + Stdio, + Socket, +} + +pub struct ServerBuilder { + binary_path: Option, + command: Option, + transport: Transport, +} + +impl ServerBuilder { + pub fn binary_path(mut self, binary_path: PathBuf) -> Self { + self.binary_path = Some(binary_path); + self + } + + pub fn command(mut self, command: Command) -> Self { + self.command = Some(command); + self + } + + pub fn transport(mut self, transport: Transport) -> Self { + self.transport = transport; + self + } + + pub async fn start(self) -> Result<(Connection, Server)> { + let mut command = if let Some(command) = self.command { + command + } else if let Some(path) = self.binary_path { + Command::new(path) + } else { + return Err(Error::MissingBinaryPath); + }; + match self.transport { + Transport::Stdio => { + let child = command + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + let (sender, receiver, threads) = stdio(child); + Ok((Connection { sender, receiver }, Server { threads })) + } + Transport::Socket => { + todo!("socket transport not implemented"); + } + } + } +} + +fn stdio( + mut child: Child, +) -> ( + UnboundedSender, + UnboundedReceiver, + IoThreads, +) { + let (writer_sender, mut writer_receiver) = unbounded_channel::(); + let writer = tokio::spawn(async move { + let stdin = child.stdin.take().unwrap(); + let mut bufr = BufWriter::new(stdin); + while let Some(it) = writer_receiver.recv().await { + let is_exit = matches!(&it, Message::Notification(n) if n.is_exit()); + debug!("sending message {:#?}", it); + it.write(&mut bufr).await?; + if is_exit { + break; + } + } + Ok(()) + }); + let (reader_sender, reader_receiver) = unbounded_channel::(); + let reader = tokio::spawn(async move { + let stdout = child.stdout.take().unwrap(); + let mut reader = BufReader::new(stdout); + while let Some(msg) = Message::read(&mut reader).await? { + debug!("received message {:#?}", msg); + reader_sender + .send(msg) + .expect("receiver was dropped, failed to send a message"); + } + Ok(()) + }); + let threads = IoThreads { reader, writer }; + (writer_sender, reader_receiver, threads) +} + +pub struct IoThreads { + reader: JoinHandle>, + writer: JoinHandle>, +} + +impl IoThreads { + pub async fn join(self) -> io::Result<()> { + match self.reader.await? { + Ok(_) => (), + Err(err) => { + error!("reader err: {err}"); + } + } + match self.writer.await? { + Ok(_) => (), + Err(err) => { + error!("writer err: {err}"); + } + } + Ok(()) + } +} diff --git a/crates/testbed/Cargo.toml b/crates/testbed/Cargo.toml new file mode 100644 index 0000000..fdde7cc --- /dev/null +++ b/crates/testbed/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "testbed" +version = "0.1.0" +resolver = "2" +edition.workspace = true +license.workspace = true +authors.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1" +clap = { version = "4", features = ["derive"] } +futures = "0.3" +futures-util = "0.3" +home = "0.5" +lsp-client = { path = "../lsp-client" } +lsp-types = "0.94" +rand = "0.8" +reqwest = { version = "0.11", features = ["stream"] } +ropey = "1.6" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +serde_yaml = "0.9" +tempfile = "3" +tokio = "1" +tokio-util = { version = "0.7", features = ["compat"] } +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } +url = "2" +zip = "0.6" + +[dependencies.uuid] +version = "1.5" +features = ["v4", "fast-rng", "serde"] diff --git a/crates/testbed/README.md b/crates/testbed/README.md new file mode 100644 index 0000000..cd19ccf --- /dev/null +++ b/crates/testbed/README.md @@ -0,0 +1,80 @@ +# testbed + +testbed is a framework to evaluate the efficiency of the completions generated by llm-ls and the underlying model. + +It works by first making holes in files, then generates completions for a given list of repositories and finally runs the associated unit tests. + +The result is a table containing a line for each repository and the total with the average percentage of successful unit tests. + +Here is a simplified pseudo code algorithm for testbed: +``` +read the repositories file +read the holes file(s) +for each repository + spawn a thread + setup the repository + for each hole + make the hole as specified by the file + generate completions + build the code + run the tests +print results +``` + +## Running testbed + +Before running testbed you will need to create a repositories file. It is a YAML file containing a list of repositories to test. + +It also contains the parameters to the `llm-ls/getCompletions` request. + +Repositories can either be sourced from your local storage or Github. + +You can check the repositories files at the root of the crate to see the full structure. + +### Generating holes + +Before running testbed, you will need to generate a holes file for each repository. To generate a holes file run testbed with the `-g` option. You can specify the number of holes to make with `-n `. It will take the list of repositories in your YAML file and create the associated files at the defined path. + +### Setup + +testbed runs completions for each repository in parallel. It will first create a temporary directory, then copy or download the repository's source files to that location and finally run the setup commands. + +Setup commands are useful to install dependencies. + +```yaml +setup_commands: + - ["python3", ["-m", "venv", "huggingface_hub-venv"]] + - ["huggingface_hub-venv/bin/python3", ["-m", "pip", "install", ".[dev]"]] +``` + +### Build + +Before running the tests, testbed will run a build command to check if the code is valid. + +To configure the commands, you can do the following: + +```yaml +build_command: huggingface_hub-venv/bin/python3 +build_args: ["-m", "compileall", "-q", "."] +``` + +### Runners + +testbed supports two test runners at the moment: +- cargo +- pytest + +To configure your runner, you have the following options: +```yaml +runner: pytest +runner_command: huggingface_hub-venv/bin/python3 +runner_extra_args: + - "-k" + - "_utils_ and not _utils_cache and not _utils_http and not paginate and not git" +``` + +You can override the runners command with `runner_command`, which is useful when setting up dependencies in a venv. + +## References + +testbed was inspired by [human-eval](https://github.com/openai/human-eval) and [RepoEval](https://arxiv.org/abs/2303.12570). diff --git a/crates/testbed/holes/async-executor-smol.json b/crates/testbed/holes/async-executor-smol.json new file mode 100644 index 0000000..f9ebc39 --- /dev/null +++ b/crates/testbed/holes/async-executor-smol.json @@ -0,0 +1 @@ +[{"cursor":{"line":38,"character":6},"file":"src/lib.rs"},{"cursor":{"line":568,"character":8},"file":"src/lib.rs"},{"cursor":{"line":271,"character":11},"file":"src/lib.rs"},{"cursor":{"line":887,"character":14},"file":"src/lib.rs"},{"cursor":{"line":697,"character":12},"file":"src/lib.rs"},{"cursor":{"line":707,"character":6},"file":"src/lib.rs"},{"cursor":{"line":240,"character":10},"file":"src/lib.rs"},{"cursor":{"line":387,"character":13},"file":"src/lib.rs"},{"cursor":{"line":501,"character":8},"file":"src/lib.rs"},{"cursor":{"line":178,"character":6},"file":"src/lib.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/async-executor.json b/crates/testbed/holes/async-executor.json new file mode 100644 index 0000000..3de5e4a --- /dev/null +++ b/crates/testbed/holes/async-executor.json @@ -0,0 +1 @@ +[{"cursor":{"line":86,"character":2},"file":"src/lib.rs"},{"cursor":{"line":266,"character":3},"file":"src/lib.rs"},{"cursor":{"line":565,"character":6},"file":"src/lib.rs"},{"cursor":{"line":914,"character":12},"file":"src/lib.rs"},{"cursor":{"line":261,"character":3},"file":"src/lib.rs"},{"cursor":{"line":839,"character":4},"file":"src/lib.rs"},{"cursor":{"line":337,"character":4},"file":"src/lib.rs"},{"cursor":{"line":517,"character":0},"file":"src/lib.rs"},{"cursor":{"line":763,"character":12},"file":"src/lib.rs"},{"cursor":{"line":551,"character":1},"file":"src/lib.rs"},{"cursor":{"line":461,"character":14},"file":"src/lib.rs"},{"cursor":{"line":847,"character":0},"file":"src/lib.rs"},{"cursor":{"line":835,"character":14},"file":"src/lib.rs"},{"cursor":{"line":793,"character":4},"file":"src/lib.rs"},{"cursor":{"line":901,"character":13},"file":"src/lib.rs"},{"cursor":{"line":191,"character":3},"file":"src/lib.rs"},{"cursor":{"line":694,"character":7},"file":"src/lib.rs"},{"cursor":{"line":824,"character":5},"file":"src/lib.rs"},{"cursor":{"line":840,"character":3},"file":"src/lib.rs"},{"cursor":{"line":310,"character":0},"file":"src/lib.rs"},{"cursor":{"line":762,"character":7},"file":"src/lib.rs"},{"cursor":{"line":664,"character":2},"file":"src/lib.rs"},{"cursor":{"line":267,"character":1},"file":"src/lib.rs"},{"cursor":{"line":484,"character":12},"file":"src/lib.rs"},{"cursor":{"line":24,"character":4},"file":"src/lib.rs"},{"cursor":{"line":100,"character":4},"file":"src/lib.rs"},{"cursor":{"line":873,"character":9},"file":"src/lib.rs"},{"cursor":{"line":690,"character":2},"file":"src/lib.rs"},{"cursor":{"line":876,"character":13},"file":"src/lib.rs"},{"cursor":{"line":435,"character":4},"file":"src/lib.rs"},{"cursor":{"line":79,"character":11},"file":"src/lib.rs"},{"cursor":{"line":552,"character":4},"file":"src/lib.rs"},{"cursor":{"line":472,"character":0},"file":"src/lib.rs"},{"cursor":{"line":762,"character":0},"file":"src/lib.rs"},{"cursor":{"line":845,"character":5},"file":"src/lib.rs"},{"cursor":{"line":707,"character":4},"file":"src/lib.rs"},{"cursor":{"line":433,"character":10},"file":"src/lib.rs"},{"cursor":{"line":754,"character":1},"file":"src/lib.rs"},{"cursor":{"line":758,"character":12},"file":"src/lib.rs"},{"cursor":{"line":811,"character":8},"file":"src/lib.rs"},{"cursor":{"line":760,"character":13},"file":"src/lib.rs"},{"cursor":{"line":898,"character":8},"file":"src/lib.rs"},{"cursor":{"line":149,"character":3},"file":"src/lib.rs"},{"cursor":{"line":242,"character":14},"file":"src/lib.rs"},{"cursor":{"line":805,"character":6},"file":"src/lib.rs"},{"cursor":{"line":830,"character":4},"file":"src/lib.rs"},{"cursor":{"line":578,"character":4},"file":"src/lib.rs"},{"cursor":{"line":701,"character":11},"file":"src/lib.rs"},{"cursor":{"line":181,"character":10},"file":"src/lib.rs"},{"cursor":{"line":704,"character":14},"file":"src/lib.rs"},{"cursor":{"line":852,"character":8},"file":"src/lib.rs"},{"cursor":{"line":311,"character":1},"file":"src/lib.rs"},{"cursor":{"line":707,"character":6},"file":"src/lib.rs"},{"cursor":{"line":75,"character":0},"file":"src/lib.rs"},{"cursor":{"line":699,"character":1},"file":"src/lib.rs"},{"cursor":{"line":600,"character":0},"file":"src/lib.rs"},{"cursor":{"line":191,"character":3},"file":"src/lib.rs"},{"cursor":{"line":150,"character":1},"file":"src/lib.rs"},{"cursor":{"line":767,"character":10},"file":"src/lib.rs"},{"cursor":{"line":739,"character":0},"file":"src/lib.rs"},{"cursor":{"line":919,"character":3},"file":"src/lib.rs"},{"cursor":{"line":143,"character":6},"file":"src/lib.rs"},{"cursor":{"line":234,"character":5},"file":"src/lib.rs"},{"cursor":{"line":860,"character":6},"file":"src/lib.rs"},{"cursor":{"line":519,"character":0},"file":"src/lib.rs"},{"cursor":{"line":668,"character":14},"file":"src/lib.rs"},{"cursor":{"line":184,"character":7},"file":"src/lib.rs"},{"cursor":{"line":607,"character":10},"file":"src/lib.rs"},{"cursor":{"line":931,"character":5},"file":"src/lib.rs"},{"cursor":{"line":191,"character":0},"file":"src/lib.rs"},{"cursor":{"line":710,"character":6},"file":"src/lib.rs"},{"cursor":{"line":509,"character":1},"file":"src/lib.rs"},{"cursor":{"line":873,"character":11},"file":"src/lib.rs"},{"cursor":{"line":539,"character":12},"file":"src/lib.rs"},{"cursor":{"line":524,"character":9},"file":"src/lib.rs"},{"cursor":{"line":959,"character":1},"file":"src/lib.rs"},{"cursor":{"line":147,"character":11},"file":"src/lib.rs"},{"cursor":{"line":620,"character":2},"file":"src/lib.rs"},{"cursor":{"line":903,"character":6},"file":"src/lib.rs"},{"cursor":{"line":931,"character":13},"file":"src/lib.rs"},{"cursor":{"line":830,"character":3},"file":"src/lib.rs"},{"cursor":{"line":832,"character":11},"file":"src/lib.rs"},{"cursor":{"line":652,"character":3},"file":"src/lib.rs"},{"cursor":{"line":673,"character":7},"file":"src/lib.rs"},{"cursor":{"line":22,"character":9},"file":"src/lib.rs"},{"cursor":{"line":150,"character":6},"file":"src/lib.rs"},{"cursor":{"line":853,"character":13},"file":"src/lib.rs"},{"cursor":{"line":658,"character":13},"file":"src/lib.rs"},{"cursor":{"line":616,"character":0},"file":"src/lib.rs"},{"cursor":{"line":457,"character":12},"file":"src/lib.rs"},{"cursor":{"line":856,"character":10},"file":"src/lib.rs"},{"cursor":{"line":795,"character":11},"file":"src/lib.rs"},{"cursor":{"line":763,"character":3},"file":"src/lib.rs"},{"cursor":{"line":778,"character":6},"file":"src/lib.rs"},{"cursor":{"line":866,"character":1},"file":"src/lib.rs"},{"cursor":{"line":764,"character":4},"file":"src/lib.rs"},{"cursor":{"line":181,"character":9},"file":"src/lib.rs"},{"cursor":{"line":780,"character":11},"file":"src/lib.rs"},{"cursor":{"line":846,"character":5},"file":"src/lib.rs"},{"cursor":{"line":651,"character":2},"file":"src/lib.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/cached-smol.json b/crates/testbed/holes/cached-smol.json new file mode 100644 index 0000000..c092b7e --- /dev/null +++ b/crates/testbed/holes/cached-smol.json @@ -0,0 +1 @@ +[{"cursor":{"line":115,"character":0},"file":"src/stores/mod.rs"},{"cursor":{"line":136,"character":1},"file":"src/stores/expiring_value_cache.rs"},{"cursor":{"line":92,"character":4},"file":"src/lru_list.rs"},{"cursor":{"line":280,"character":14},"file":"src/stores/timed.rs"},{"cursor":{"line":294,"character":14},"file":"src/stores/unbound.rs"},{"cursor":{"line":267,"character":1},"file":"src/stores/unbound.rs"},{"cursor":{"line":142,"character":0},"file":"src/stores/expiring_value_cache.rs"},{"cursor":{"line":370,"character":12},"file":"src/stores/sized.rs"},{"cursor":{"line":280,"character":10},"file":"src/proc_macro.rs"},{"cursor":{"line":177,"character":5},"file":"src/stores/timed_sized.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/cached.json b/crates/testbed/holes/cached.json new file mode 100644 index 0000000..b8ac9da --- /dev/null +++ b/crates/testbed/holes/cached.json @@ -0,0 +1 @@ +[{"cursor":{"line":417,"character":8},"file":"src/stores/timed_sized.rs"},{"cursor":{"line":233,"character":3},"file":"src/stores/expiring_value_cache.rs"},{"cursor":{"line":250,"character":5},"file":"src/stores/timed.rs"},{"cursor":{"line":151,"character":3},"file":"src/stores/expiring_value_cache.rs"},{"cursor":{"line":126,"character":4},"file":"src/stores/mod.rs"},{"cursor":{"line":110,"character":0},"file":"src/stores/redis.rs"},{"cursor":{"line":133,"character":2},"file":"src/stores/expiring_value_cache.rs"},{"cursor":{"line":110,"character":7},"file":"src/stores/mod.rs"},{"cursor":{"line":654,"character":13},"file":"src/stores/sized.rs"},{"cursor":{"line":69,"character":6},"file":"src/stores/mod.rs"},{"cursor":{"line":276,"character":8},"file":"src/stores/timed.rs"},{"cursor":{"line":334,"character":10},"file":"src/stores/timed_sized.rs"},{"cursor":{"line":341,"character":2},"file":"src/stores/timed.rs"},{"cursor":{"line":172,"character":11},"file":"src/stores/redis.rs"},{"cursor":{"line":341,"character":3},"file":"src/macros.rs"},{"cursor":{"line":199,"character":11},"file":"src/lib.rs"},{"cursor":{"line":264,"character":2},"file":"src/macros.rs"},{"cursor":{"line":267,"character":7},"file":"src/stores/expiring_value_cache.rs"},{"cursor":{"line":77,"character":14},"file":"src/stores/mod.rs"},{"cursor":{"line":393,"character":9},"file":"src/macros.rs"},{"cursor":{"line":3,"character":14},"file":"src/proc_macro.rs"},{"cursor":{"line":324,"character":12},"file":"src/stores/timed_sized.rs"},{"cursor":{"line":398,"character":10},"file":"src/stores/timed.rs"},{"cursor":{"line":115,"character":10},"file":"src/macros.rs"},{"cursor":{"line":23,"character":1},"file":"src/stores/expiring_value_cache.rs"},{"cursor":{"line":108,"character":1},"file":"src/stores/unbound.rs"},{"cursor":{"line":298,"character":1},"file":"src/stores/unbound.rs"},{"cursor":{"line":48,"character":1},"file":"src/lru_list.rs"},{"cursor":{"line":7,"character":8},"file":"src/lib.rs"},{"cursor":{"line":78,"character":5},"file":"src/stores/mod.rs"},{"cursor":{"line":29,"character":8},"file":"src/stores/mod.rs"},{"cursor":{"line":159,"character":7},"file":"src/stores/timed.rs"},{"cursor":{"line":132,"character":9},"file":"src/stores/expiring_value_cache.rs"},{"cursor":{"line":157,"character":1},"file":"src/stores/sized.rs"},{"cursor":{"line":249,"character":2},"file":"src/stores/timed_sized.rs"},{"cursor":{"line":286,"character":2},"file":"src/stores/sized.rs"},{"cursor":{"line":201,"character":11},"file":"src/stores/timed.rs"},{"cursor":{"line":183,"character":3},"file":"src/stores/timed_sized.rs"},{"cursor":{"line":425,"character":10},"file":"src/stores/timed.rs"},{"cursor":{"line":12,"character":2},"file":"src/stores/mod.rs"},{"cursor":{"line":60,"character":1},"file":"src/stores/mod.rs"},{"cursor":{"line":416,"character":13},"file":"src/stores/sized.rs"},{"cursor":{"line":565,"character":8},"file":"src/stores/timed_sized.rs"},{"cursor":{"line":323,"character":4},"file":"src/stores/timed.rs"},{"cursor":{"line":141,"character":7},"file":"src/stores/timed.rs"},{"cursor":{"line":649,"character":6},"file":"src/stores/redis.rs"},{"cursor":{"line":243,"character":11},"file":"src/stores/unbound.rs"},{"cursor":{"line":273,"character":1},"file":"src/proc_macro.rs"},{"cursor":{"line":535,"character":0},"file":"src/stores/sized.rs"},{"cursor":{"line":19,"character":5},"file":"src/stores/mod.rs"},{"cursor":{"line":180,"character":0},"file":"src/stores/unbound.rs"},{"cursor":{"line":30,"character":13},"file":"src/stores/timed.rs"},{"cursor":{"line":716,"character":5},"file":"src/stores/redis.rs"},{"cursor":{"line":224,"character":10},"file":"src/stores/timed_sized.rs"},{"cursor":{"line":459,"character":8},"file":"src/macros.rs"},{"cursor":{"line":137,"character":0},"file":"src/stores/mod.rs"},{"cursor":{"line":52,"character":7},"file":"src/lru_list.rs"},{"cursor":{"line":109,"character":8},"file":"src/stores/timed.rs"},{"cursor":{"line":23,"character":1},"file":"src/stores/mod.rs"},{"cursor":{"line":11,"character":11},"file":"src/stores/timed.rs"},{"cursor":{"line":13,"character":0},"file":"src/stores/redis.rs"},{"cursor":{"line":36,"character":10},"file":"src/stores/mod.rs"},{"cursor":{"line":337,"character":11},"file":"src/macros.rs"},{"cursor":{"line":176,"character":5},"file":"src/stores/unbound.rs"},{"cursor":{"line":308,"character":7},"file":"src/macros.rs"},{"cursor":{"line":11,"character":1},"file":"src/stores/timed.rs"},{"cursor":{"line":127,"character":12},"file":"src/stores/mod.rs"},{"cursor":{"line":184,"character":11},"file":"src/stores/redis.rs"},{"cursor":{"line":190,"character":10},"file":"src/stores/unbound.rs"},{"cursor":{"line":89,"character":9},"file":"src/stores/mod.rs"},{"cursor":{"line":259,"character":2},"file":"src/stores/timed_sized.rs"},{"cursor":{"line":238,"character":1},"file":"src/stores/expiring_value_cache.rs"},{"cursor":{"line":482,"character":4},"file":"src/stores/timed_sized.rs"},{"cursor":{"line":404,"character":4},"file":"src/macros.rs"},{"cursor":{"line":60,"character":0},"file":"src/stores/mod.rs"},{"cursor":{"line":48,"character":1},"file":"src/stores/unbound.rs"},{"cursor":{"line":106,"character":2},"file":"src/stores/mod.rs"},{"cursor":{"line":67,"character":9},"file":"src/stores/mod.rs"},{"cursor":{"line":82,"character":13},"file":"src/macros.rs"},{"cursor":{"line":213,"character":3},"file":"src/macros.rs"},{"cursor":{"line":498,"character":4},"file":"src/stores/timed.rs"},{"cursor":{"line":517,"character":4},"file":"src/stores/timed_sized.rs"},{"cursor":{"line":26,"character":4},"file":"src/stores/mod.rs"},{"cursor":{"line":222,"character":8},"file":"src/stores/timed.rs"},{"cursor":{"line":25,"character":0},"file":"src/stores/unbound.rs"},{"cursor":{"line":401,"character":2},"file":"src/stores/timed_sized.rs"},{"cursor":{"line":468,"character":4},"file":"src/macros.rs"},{"cursor":{"line":121,"character":3},"file":"src/stores/unbound.rs"},{"cursor":{"line":411,"character":3},"file":"src/macros.rs"},{"cursor":{"line":133,"character":11},"file":"src/stores/mod.rs"},{"cursor":{"line":312,"character":6},"file":"src/macros.rs"},{"cursor":{"line":264,"character":4},"file":"src/stores/expiring_value_cache.rs"},{"cursor":{"line":395,"character":8},"file":"src/macros.rs"},{"cursor":{"line":271,"character":1},"file":"src/stores/expiring_value_cache.rs"},{"cursor":{"line":50,"character":6},"file":"src/stores/mod.rs"},{"cursor":{"line":567,"character":4},"file":"src/stores/redis.rs"},{"cursor":{"line":79,"character":9},"file":"src/stores/timed_sized.rs"},{"cursor":{"line":650,"character":0},"file":"src/stores/sized.rs"},{"cursor":{"line":168,"character":2},"file":"src/stores/timed.rs"},{"cursor":{"line":297,"character":1},"file":"src/stores/sized.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/constrandom-smol.json b/crates/testbed/holes/constrandom-smol.json new file mode 100644 index 0000000..a3432de --- /dev/null +++ b/crates/testbed/holes/constrandom-smol.json @@ -0,0 +1 @@ +[{"cursor":{"line":12,"character":3},"file":"src/lib.rs"},{"cursor":{"line":12,"character":11},"file":"src/lib.rs"},{"cursor":{"line":12,"character":5},"file":"src/lib.rs"},{"cursor":{"line":0,"character":4},"file":"src/lib.rs"},{"cursor":{"line":12,"character":3},"file":"src/lib.rs"},{"cursor":{"line":12,"character":6},"file":"src/lib.rs"},{"cursor":{"line":0,"character":10},"file":"src/lib.rs"},{"cursor":{"line":0,"character":3},"file":"src/lib.rs"},{"cursor":{"line":12,"character":4},"file":"src/lib.rs"},{"cursor":{"line":0,"character":10},"file":"src/lib.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/constrandom.json b/crates/testbed/holes/constrandom.json new file mode 100644 index 0000000..adaed80 --- /dev/null +++ b/crates/testbed/holes/constrandom.json @@ -0,0 +1 @@ +[{"cursor":{"line":12,"character":2},"file":"src/lib.rs"},{"cursor":{"line":0,"character":1},"file":"src/lib.rs"},{"cursor":{"line":12,"character":14},"file":"src/lib.rs"},{"cursor":{"line":12,"character":12},"file":"src/lib.rs"},{"cursor":{"line":0,"character":4},"file":"src/lib.rs"},{"cursor":{"line":12,"character":4},"file":"src/lib.rs"},{"cursor":{"line":0,"character":0},"file":"src/lib.rs"},{"cursor":{"line":12,"character":0},"file":"src/lib.rs"},{"cursor":{"line":0,"character":8},"file":"src/lib.rs"},{"cursor":{"line":0,"character":9},"file":"src/lib.rs"},{"cursor":{"line":0,"character":7},"file":"src/lib.rs"},{"cursor":{"line":12,"character":8},"file":"src/lib.rs"},{"cursor":{"line":12,"character":14},"file":"src/lib.rs"},{"cursor":{"line":0,"character":9},"file":"src/lib.rs"},{"cursor":{"line":0,"character":2},"file":"src/lib.rs"},{"cursor":{"line":12,"character":10},"file":"src/lib.rs"},{"cursor":{"line":0,"character":3},"file":"src/lib.rs"},{"cursor":{"line":0,"character":10},"file":"src/lib.rs"},{"cursor":{"line":12,"character":11},"file":"src/lib.rs"},{"cursor":{"line":12,"character":11},"file":"src/lib.rs"},{"cursor":{"line":12,"character":4},"file":"src/lib.rs"},{"cursor":{"line":0,"character":9},"file":"src/lib.rs"},{"cursor":{"line":12,"character":13},"file":"src/lib.rs"},{"cursor":{"line":12,"character":13},"file":"src/lib.rs"},{"cursor":{"line":0,"character":1},"file":"src/lib.rs"},{"cursor":{"line":12,"character":10},"file":"src/lib.rs"},{"cursor":{"line":12,"character":13},"file":"src/lib.rs"},{"cursor":{"line":12,"character":9},"file":"src/lib.rs"},{"cursor":{"line":12,"character":9},"file":"src/lib.rs"},{"cursor":{"line":0,"character":4},"file":"src/lib.rs"},{"cursor":{"line":12,"character":12},"file":"src/lib.rs"},{"cursor":{"line":12,"character":7},"file":"src/lib.rs"},{"cursor":{"line":12,"character":11},"file":"src/lib.rs"},{"cursor":{"line":0,"character":3},"file":"src/lib.rs"},{"cursor":{"line":12,"character":5},"file":"src/lib.rs"},{"cursor":{"line":0,"character":0},"file":"src/lib.rs"},{"cursor":{"line":0,"character":4},"file":"src/lib.rs"},{"cursor":{"line":0,"character":9},"file":"src/lib.rs"},{"cursor":{"line":0,"character":6},"file":"src/lib.rs"},{"cursor":{"line":12,"character":11},"file":"src/lib.rs"},{"cursor":{"line":0,"character":8},"file":"src/lib.rs"},{"cursor":{"line":12,"character":5},"file":"src/lib.rs"},{"cursor":{"line":0,"character":5},"file":"src/lib.rs"},{"cursor":{"line":0,"character":7},"file":"src/lib.rs"},{"cursor":{"line":0,"character":0},"file":"src/lib.rs"},{"cursor":{"line":12,"character":11},"file":"src/lib.rs"},{"cursor":{"line":0,"character":6},"file":"src/lib.rs"},{"cursor":{"line":0,"character":0},"file":"src/lib.rs"},{"cursor":{"line":0,"character":6},"file":"src/lib.rs"},{"cursor":{"line":12,"character":2},"file":"src/lib.rs"},{"cursor":{"line":0,"character":0},"file":"src/lib.rs"},{"cursor":{"line":12,"character":10},"file":"src/lib.rs"},{"cursor":{"line":0,"character":5},"file":"src/lib.rs"},{"cursor":{"line":12,"character":4},"file":"src/lib.rs"},{"cursor":{"line":0,"character":3},"file":"src/lib.rs"},{"cursor":{"line":12,"character":9},"file":"src/lib.rs"},{"cursor":{"line":12,"character":12},"file":"src/lib.rs"},{"cursor":{"line":0,"character":8},"file":"src/lib.rs"},{"cursor":{"line":0,"character":5},"file":"src/lib.rs"},{"cursor":{"line":12,"character":11},"file":"src/lib.rs"},{"cursor":{"line":0,"character":8},"file":"src/lib.rs"},{"cursor":{"line":0,"character":9},"file":"src/lib.rs"},{"cursor":{"line":0,"character":0},"file":"src/lib.rs"},{"cursor":{"line":12,"character":13},"file":"src/lib.rs"},{"cursor":{"line":12,"character":1},"file":"src/lib.rs"},{"cursor":{"line":12,"character":10},"file":"src/lib.rs"},{"cursor":{"line":0,"character":3},"file":"src/lib.rs"},{"cursor":{"line":12,"character":3},"file":"src/lib.rs"},{"cursor":{"line":12,"character":2},"file":"src/lib.rs"},{"cursor":{"line":12,"character":10},"file":"src/lib.rs"},{"cursor":{"line":0,"character":9},"file":"src/lib.rs"},{"cursor":{"line":0,"character":5},"file":"src/lib.rs"},{"cursor":{"line":12,"character":14},"file":"src/lib.rs"},{"cursor":{"line":0,"character":8},"file":"src/lib.rs"},{"cursor":{"line":0,"character":7},"file":"src/lib.rs"},{"cursor":{"line":12,"character":5},"file":"src/lib.rs"},{"cursor":{"line":0,"character":2},"file":"src/lib.rs"},{"cursor":{"line":12,"character":11},"file":"src/lib.rs"},{"cursor":{"line":0,"character":1},"file":"src/lib.rs"},{"cursor":{"line":12,"character":13},"file":"src/lib.rs"},{"cursor":{"line":0,"character":5},"file":"src/lib.rs"},{"cursor":{"line":12,"character":8},"file":"src/lib.rs"},{"cursor":{"line":12,"character":13},"file":"src/lib.rs"},{"cursor":{"line":12,"character":0},"file":"src/lib.rs"},{"cursor":{"line":12,"character":10},"file":"src/lib.rs"},{"cursor":{"line":0,"character":1},"file":"src/lib.rs"},{"cursor":{"line":12,"character":3},"file":"src/lib.rs"},{"cursor":{"line":12,"character":14},"file":"src/lib.rs"},{"cursor":{"line":0,"character":1},"file":"src/lib.rs"},{"cursor":{"line":0,"character":7},"file":"src/lib.rs"},{"cursor":{"line":0,"character":8},"file":"src/lib.rs"},{"cursor":{"line":0,"character":7},"file":"src/lib.rs"},{"cursor":{"line":12,"character":12},"file":"src/lib.rs"},{"cursor":{"line":0,"character":5},"file":"src/lib.rs"},{"cursor":{"line":12,"character":9},"file":"src/lib.rs"},{"cursor":{"line":0,"character":7},"file":"src/lib.rs"},{"cursor":{"line":0,"character":8},"file":"src/lib.rs"},{"cursor":{"line":12,"character":7},"file":"src/lib.rs"},{"cursor":{"line":0,"character":4},"file":"src/lib.rs"},{"cursor":{"line":12,"character":13},"file":"src/lib.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/fastapi-smol.json b/crates/testbed/holes/fastapi-smol.json new file mode 100644 index 0000000..c8173bb --- /dev/null +++ b/crates/testbed/holes/fastapi-smol.json @@ -0,0 +1 @@ +[{"cursor":{"line":1300,"character":8},"file":"fastapi/param_functions.py"},{"cursor":{"line":0,"character":12},"file":"fastapi/middleware/trustedhost.py"},{"cursor":{"line":1,"character":5},"file":"fastapi/middleware/httpsredirect.py"},{"cursor":{"line":177,"character":14},"file":"fastapi/openapi/docs.py"},{"cursor":{"line":37,"character":5},"file":"fastapi/security/http.py"},{"cursor":{"line":0,"character":7},"file":"fastapi/testclient.py"},{"cursor":{"line":647,"character":6},"file":"fastapi/param_functions.py"},{"cursor":{"line":419,"character":0},"file":"fastapi/_compat.py"},{"cursor":{"line":100,"character":1},"file":"fastapi/exceptions.py"},{"cursor":{"line":107,"character":14},"file":"fastapi/security/oauth2.py"}] \ No newline at end of file diff --git a/crates/testbed/holes/fastapi.json b/crates/testbed/holes/fastapi.json new file mode 100644 index 0000000..f23fbfc --- /dev/null +++ b/crates/testbed/holes/fastapi.json @@ -0,0 +1 @@ +[{"cursor":{"line":17,"character":0},"file":"fastapi/dependencies/utils.py"},{"cursor":{"line":5,"character":13},"file":"fastapi/exception_handlers.py"},{"cursor":{"line":0,"character":9},"file":"fastapi/staticfiles.py"},{"cursor":{"line":12,"character":12},"file":"fastapi/security/__init__.py"},{"cursor":{"line":179,"character":14},"file":"fastapi/security/api_key.py"},{"cursor":{"line":1,"character":13},"file":"fastapi/types.py"},{"cursor":{"line":74,"character":9},"file":"fastapi/encoders.py"},{"cursor":{"line":0,"character":5},"file":"fastapi/middleware/cors.py"},{"cursor":{"line":1,"character":12},"file":"fastapi/openapi/constants.py"},{"cursor":{"line":219,"character":14},"file":"fastapi/utils.py"},{"cursor":{"line":30,"character":9},"file":"fastapi/security/http.py"},{"cursor":{"line":1,"character":14},"file":"fastapi/middleware/httpsredirect.py"},{"cursor":{"line":9,"character":10},"file":"fastapi/types.py"},{"cursor":{"line":261,"character":9},"file":"fastapi/openapi/models.py"},{"cursor":{"line":63,"character":8},"file":"fastapi/params.py"},{"cursor":{"line":7,"character":2},"file":"fastapi/types.py"},{"cursor":{"line":176,"character":1},"file":"fastapi/datastructures.py"},{"cursor":{"line":2,"character":3},"file":"fastapi/websockets.py"},{"cursor":{"line":57,"character":11},"file":"fastapi/dependencies/models.py"},{"cursor":{"line":1,"character":8},"file":"fastapi/websockets.py"},{"cursor":{"line":600,"character":13},"file":"fastapi/security/oauth2.py"},{"cursor":{"line":1711,"character":8},"file":"fastapi/param_functions.py"},{"cursor":{"line":582,"character":12},"file":"fastapi/security/oauth2.py"},{"cursor":{"line":486,"character":11},"file":"fastapi/_compat.py"},{"cursor":{"line":228,"character":6},"file":"fastapi/_compat.py"},{"cursor":{"line":16,"character":8},"file":"fastapi/_compat.py"},{"cursor":{"line":74,"character":0},"file":"fastapi/security/http.py"},{"cursor":{"line":772,"character":9},"file":"fastapi/params.py"},{"cursor":{"line":29,"character":2},"file":"fastapi/security/http.py"},{"cursor":{"line":705,"character":5},"file":"fastapi/params.py"},{"cursor":{"line":2,"character":0},"file":"fastapi/middleware/trustedhost.py"},{"cursor":{"line":15,"character":12},"file":"fastapi/middleware/asyncexitstack.py"},{"cursor":{"line":268,"character":13},"file":"fastapi/dependencies/utils.py"},{"cursor":{"line":39,"character":1},"file":"fastapi/responses.py"},{"cursor":{"line":105,"character":1},"file":"fastapi/openapi/docs.py"},{"cursor":{"line":376,"character":6},"file":"fastapi/openapi/models.py"},{"cursor":{"line":6,"character":12},"file":"fastapi/security/utils.py"},{"cursor":{"line":9,"character":6},"file":"fastapi/types.py"},{"cursor":{"line":405,"character":7},"file":"fastapi/security/http.py"},{"cursor":{"line":23,"character":2},"file":"fastapi/__init__.py"},{"cursor":{"line":1,"character":3},"file":"fastapi/websockets.py"},{"cursor":{"line":234,"character":1},"file":"fastapi/_compat.py"},{"cursor":{"line":22,"character":10},"file":"fastapi/utils.py"},{"cursor":{"line":24,"character":9},"file":"fastapi/security/oauth2.py"},{"cursor":{"line":374,"character":8},"file":"fastapi/security/oauth2.py"},{"cursor":{"line":194,"character":10},"file":"fastapi/encoders.py"},{"cursor":{"line":3,"character":3},"file":"fastapi/security/utils.py"},{"cursor":{"line":9,"character":11},"file":"fastapi/security/utils.py"},{"cursor":{"line":209,"character":7},"file":"fastapi/utils.py"},{"cursor":{"line":10,"character":5},"file":"fastapi/openapi/utils.py"},{"cursor":{"line":193,"character":4},"file":"fastapi/dependencies/utils.py"},{"cursor":{"line":231,"character":13},"file":"fastapi/security/api_key.py"},{"cursor":{"line":4067,"character":12},"file":"fastapi/routing.py"},{"cursor":{"line":4,"character":10},"file":"fastapi/security/utils.py"},{"cursor":{"line":469,"character":4},"file":"fastapi/dependencies/utils.py"},{"cursor":{"line":2,"character":1},"file":"fastapi/middleware/trustedhost.py"},{"cursor":{"line":0,"character":4},"file":"fastapi/security/base.py"},{"cursor":{"line":0,"character":1},"file":"fastapi/openapi/constants.py"},{"cursor":{"line":604,"character":8},"file":"fastapi/dependencies/utils.py"},{"cursor":{"line":13,"character":5},"file":"fastapi/exception_handlers.py"},{"cursor":{"line":195,"character":9},"file":"fastapi/utils.py"},{"cursor":{"line":8,"character":4},"file":"fastapi/types.py"},{"cursor":{"line":7,"character":11},"file":"fastapi/middleware/asyncexitstack.py"},{"cursor":{"line":1,"character":13},"file":"fastapi/openapi/constants.py"},{"cursor":{"line":163,"character":11},"file":"fastapi/utils.py"},{"cursor":{"line":106,"character":5},"file":"fastapi/datastructures.py"},{"cursor":{"line":0,"character":6},"file":"fastapi/security/base.py"},{"cursor":{"line":224,"character":3},"file":"fastapi/security/oauth2.py"},{"cursor":{"line":0,"character":5},"file":"fastapi/middleware/cors.py"},{"cursor":{"line":84,"character":1},"file":"fastapi/encoders.py"},{"cursor":{"line":158,"character":9},"file":"fastapi/security/oauth2.py"},{"cursor":{"line":2,"character":0},"file":"fastapi/middleware/trustedhost.py"},{"cursor":{"line":393,"character":5},"file":"fastapi/_compat.py"},{"cursor":{"line":34,"character":14},"file":"fastapi/concurrency.py"},{"cursor":{"line":0,"character":11},"file":"fastapi/middleware/wsgi.py"},{"cursor":{"line":440,"character":1},"file":"fastapi/openapi/utils.py"},{"cursor":{"line":0,"character":11},"file":"fastapi/staticfiles.py"},{"cursor":{"line":3281,"character":5},"file":"fastapi/applications.py"},{"cursor":{"line":2022,"character":7},"file":"fastapi/param_functions.py"},{"cursor":{"line":0,"character":12},"file":"fastapi/templating.py"},{"cursor":{"line":1,"character":14},"file":"fastapi/types.py"},{"cursor":{"line":9,"character":12},"file":"fastapi/security/utils.py"},{"cursor":{"line":2,"character":9},"file":"fastapi/middleware/asyncexitstack.py"},{"cursor":{"line":25,"character":11},"file":"fastapi/dependencies/models.py"},{"cursor":{"line":0,"character":7},"file":"fastapi/middleware/cors.py"},{"cursor":{"line":9,"character":1},"file":"fastapi/background.py"},{"cursor":{"line":353,"character":5},"file":"fastapi/params.py"},{"cursor":{"line":0,"character":8},"file":"fastapi/middleware/cors.py"},{"cursor":{"line":1451,"character":6},"file":"fastapi/param_functions.py"},{"cursor":{"line":53,"character":14},"file":"fastapi/security/api_key.py"},{"cursor":{"line":91,"character":2},"file":"fastapi/openapi/models.py"},{"cursor":{"line":0,"character":0},"file":"fastapi/middleware/gzip.py"},{"cursor":{"line":2,"character":1},"file":"fastapi/middleware/httpsredirect.py"},{"cursor":{"line":413,"character":7},"file":"fastapi/openapi/models.py"},{"cursor":{"line":92,"character":11},"file":"fastapi/exceptions.py"},{"cursor":{"line":1,"character":13},"file":"fastapi/openapi/constants.py"},{"cursor":{"line":4,"character":1},"file":"fastapi/security/base.py"},{"cursor":{"line":6,"character":0},"file":"fastapi/types.py"},{"cursor":{"line":53,"character":14},"file":"fastapi/params.py"},{"cursor":{"line":10,"character":1},"file":"fastapi/exceptions.py"}] \ No newline at end of file diff --git a/crates/testbed/holes/helix-smol.json b/crates/testbed/holes/helix-smol.json new file mode 100644 index 0000000..1a2b62b --- /dev/null +++ b/crates/testbed/holes/helix-smol.json @@ -0,0 +1 @@ +[{"cursor":{"line":73,"character":10},"file":"helix-core/src/chars.rs"},{"cursor":{"line":257,"character":11},"file":"helix-dap/src/types.rs"},{"cursor":{"line":39,"character":14},"file":"helix-view/src/info.rs"},{"cursor":{"line":116,"character":12},"file":"helix-term/src/ui/mod.rs"},{"cursor":{"line":1,"character":14},"file":"helix-term/src/ui/text.rs"},{"cursor":{"line":2,"character":5},"file":"helix-core/src/config.rs"},{"cursor":{"line":151,"character":14},"file":"helix-view/src/gutter.rs"},{"cursor":{"line":11,"character":10},"file":"helix-term/src/ui/lsp.rs"},{"cursor":{"line":18,"character":0},"file":"helix-term/src/ui/text.rs"},{"cursor":{"line":230,"character":3},"file":"helix-term/src/ui/markdown.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/helix.json b/crates/testbed/holes/helix.json new file mode 100644 index 0000000..3eaab1c --- /dev/null +++ b/crates/testbed/holes/helix.json @@ -0,0 +1 @@ +[{"cursor":{"line":294,"character":0},"file":"helix-term/src/ui/editor.rs"},{"cursor":{"line":21,"character":0},"file":"helix-core/src/doc_formatter/test.rs"},{"cursor":{"line":69,"character":13},"file":"helix-tui/src/backend/crossterm.rs"},{"cursor":{"line":65,"character":5},"file":"helix-term/src/ui/picker.rs"},{"cursor":{"line":255,"character":9},"file":"helix-tui/src/widgets/block.rs"},{"cursor":{"line":50,"character":2},"file":"helix-term/src/config.rs"},{"cursor":{"line":116,"character":12},"file":"helix-term/src/ui/popup.rs"},{"cursor":{"line":9,"character":11},"file":"helix-core/src/match_brackets.rs"},{"cursor":{"line":1037,"character":3},"file":"helix-term/src/commands/lsp.rs"},{"cursor":{"line":8,"character":3},"file":"helix-core/src/config.rs"},{"cursor":{"line":99,"character":0},"file":"helix-term/src/ui/menu.rs"},{"cursor":{"line":11,"character":0},"file":"helix-loader/src/config.rs"},{"cursor":{"line":33,"character":2},"file":"helix-core/src/increment/date_time.rs"},{"cursor":{"line":38,"character":10},"file":"helix-view/src/register.rs"},{"cursor":{"line":151,"character":6},"file":"helix-core/src/increment/integer.rs"},{"cursor":{"line":9,"character":1},"file":"helix-tui/src/backend/mod.rs"},{"cursor":{"line":89,"character":5},"file":"helix-term/src/job.rs"},{"cursor":{"line":75,"character":12},"file":"helix-vcs/src/diff/worker/test.rs"},{"cursor":{"line":135,"character":1},"file":"helix-vcs/src/diff/line_cache.rs"},{"cursor":{"line":45,"character":4},"file":"helix-core/src/lib.rs"},{"cursor":{"line":134,"character":11},"file":"helix-core/src/comment.rs"},{"cursor":{"line":369,"character":0},"file":"helix-tui/src/layout.rs"},{"cursor":{"line":146,"character":11},"file":"helix-dap/src/types.rs"},{"cursor":{"line":49,"character":4},"file":"helix-core/src/lib.rs"},{"cursor":{"line":90,"character":14},"file":"helix-term/src/args.rs"},{"cursor":{"line":60,"character":5},"file":"helix-term/src/config.rs"},{"cursor":{"line":527,"character":13},"file":"helix-term/src/ui/prompt.rs"},{"cursor":{"line":95,"character":9},"file":"helix-tui/src/backend/test.rs"},{"cursor":{"line":81,"character":8},"file":"helix-view/src/handlers/dap.rs"},{"cursor":{"line":143,"character":7},"file":"helix-view/src/tree.rs"},{"cursor":{"line":386,"character":6},"file":"helix-view/src/handlers/dap.rs"},{"cursor":{"line":891,"character":10},"file":"helix-core/src/movement.rs"},{"cursor":{"line":4,"character":6},"file":"helix-term/build.rs"},{"cursor":{"line":499,"character":11},"file":"helix-core/src/textobject.rs"},{"cursor":{"line":158,"character":3},"file":"helix-term/src/config.rs"},{"cursor":{"line":1342,"character":2},"file":"helix-view/src/editor.rs"},{"cursor":{"line":91,"character":14},"file":"helix-vcs/src/diff/worker/test.rs"},{"cursor":{"line":313,"character":9},"file":"helix-core/src/history.rs"},{"cursor":{"line":82,"character":5},"file":"helix-loader/src/lib.rs"},{"cursor":{"line":161,"character":10},"file":"helix-view/src/view.rs"},{"cursor":{"line":453,"character":7},"file":"helix-tui/src/widgets/block.rs"},{"cursor":{"line":271,"character":12},"file":"helix-core/src/doc_formatter.rs"},{"cursor":{"line":470,"character":2},"file":"helix-term/src/ui/mod.rs"},{"cursor":{"line":0,"character":0},"file":"helix-core/src/fuzzy.rs"},{"cursor":{"line":65,"character":2},"file":"helix-core/src/search.rs"},{"cursor":{"line":165,"character":5},"file":"helix-term/src/ui/document.rs"},{"cursor":{"line":80,"character":6},"file":"helix-term/src/ui/statusline.rs"},{"cursor":{"line":598,"character":2},"file":"helix-term/src/ui/prompt.rs"},{"cursor":{"line":158,"character":0},"file":"helix-term/src/ui/markdown.rs"},{"cursor":{"line":80,"character":14},"file":"helix-vcs/src/diff/line_cache.rs"},{"cursor":{"line":164,"character":0},"file":"helix-core/src/shellwords.rs"},{"cursor":{"line":39,"character":13},"file":"helix-core/src/diagnostic.rs"},{"cursor":{"line":175,"character":2},"file":"helix-tui/src/widgets/paragraph.rs"},{"cursor":{"line":137,"character":6},"file":"helix-view/src/theme.rs"},{"cursor":{"line":311,"character":13},"file":"helix-term/src/commands/lsp.rs"},{"cursor":{"line":22,"character":1},"file":"helix-core/src/chars.rs"},{"cursor":{"line":177,"character":6},"file":"helix-term/src/config.rs"},{"cursor":{"line":833,"character":3},"file":"helix-view/src/document.rs"},{"cursor":{"line":833,"character":5},"file":"helix-core/src/position.rs"},{"cursor":{"line":1,"character":0},"file":"helix-loader/src/main.rs"},{"cursor":{"line":14,"character":8},"file":"helix-core/src/search.rs"},{"cursor":{"line":69,"character":1},"file":"helix-tui/src/symbols.rs"},{"cursor":{"line":1023,"character":2},"file":"helix-view/src/view.rs"},{"cursor":{"line":513,"character":6},"file":"helix-term/src/commands/lsp.rs"},{"cursor":{"line":252,"character":10},"file":"helix-core/src/auto_pairs.rs"},{"cursor":{"line":185,"character":5},"file":"helix-term/src/ui/document.rs"},{"cursor":{"line":479,"character":3},"file":"helix-term/src/keymap.rs"},{"cursor":{"line":177,"character":6},"file":"helix-view/src/gutter.rs"},{"cursor":{"line":1736,"character":13},"file":"helix-core/src/movement.rs"},{"cursor":{"line":479,"character":0},"file":"helix-core/src/indent.rs"},{"cursor":{"line":25,"character":10},"file":"helix-core/src/path.rs"},{"cursor":{"line":178,"character":2},"file":"helix-core/src/position.rs"},{"cursor":{"line":64,"character":1},"file":"helix-term/src/ui/text.rs"},{"cursor":{"line":221,"character":14},"file":"helix-term/src/ui/mod.rs"},{"cursor":{"line":464,"character":2},"file":"helix-dap/src/types.rs"},{"cursor":{"line":272,"character":2},"file":"helix-loader/src/lib.rs"},{"cursor":{"line":190,"character":9},"file":"helix-tui/src/widgets/reflow.rs"},{"cursor":{"line":353,"character":14},"file":"helix-term/src/ui/mod.rs"},{"cursor":{"line":39,"character":9},"file":"helix-term/src/lib.rs"},{"cursor":{"line":339,"character":10},"file":"helix-term/src/ui/mod.rs"},{"cursor":{"line":227,"character":8},"file":"helix-tui/src/layout.rs"},{"cursor":{"line":35,"character":7},"file":"helix-view/src/gutter.rs"},{"cursor":{"line":16,"character":1},"file":"helix-tui/src/backend/crossterm.rs"},{"cursor":{"line":182,"character":14},"file":"helix-tui/src/widgets/paragraph.rs"},{"cursor":{"line":2770,"character":1},"file":"helix-term/src/commands/typed.rs"},{"cursor":{"line":111,"character":2},"file":"helix-view/src/base64.rs"},{"cursor":{"line":13,"character":2},"file":"helix-core/src/lib.rs"},{"cursor":{"line":158,"character":4},"file":"helix-tui/src/backend/crossterm.rs"},{"cursor":{"line":34,"character":13},"file":"helix-term/src/ui/spinner.rs"},{"cursor":{"line":133,"character":5},"file":"helix-tui/src/symbols.rs"},{"cursor":{"line":2330,"character":9},"file":"helix-term/src/commands/typed.rs"},{"cursor":{"line":88,"character":5},"file":"helix-lsp/src/transport.rs"},{"cursor":{"line":436,"character":11},"file":"helix-core/src/textobject.rs"},{"cursor":{"line":120,"character":13},"file":"helix-term/src/job.rs"},{"cursor":{"line":6,"character":13},"file":"helix-view/src/info.rs"},{"cursor":{"line":94,"character":3},"file":"helix-view/src/base64.rs"},{"cursor":{"line":11,"character":9},"file":"helix-view/src/lib.rs"},{"cursor":{"line":2,"character":3},"file":"helix-view/src/handlers/dap.rs"},{"cursor":{"line":1410,"character":1},"file":"helix-view/src/document.rs"},{"cursor":{"line":854,"character":1},"file":"helix-core/src/movement.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/huggingface_hub-smol.json b/crates/testbed/holes/huggingface_hub-smol.json new file mode 100644 index 0000000..441b5be --- /dev/null +++ b/crates/testbed/holes/huggingface_hub-smol.json @@ -0,0 +1 @@ +[{"cursor":{"line":485,"character":14},"file":"src/huggingface_hub/__init__.py"},{"cursor":{"line":134,"character":9},"file":"src/huggingface_hub/_space_api.py"},{"cursor":{"line":122,"character":3},"file":"src/huggingface_hub/inference_api.py"},{"cursor":{"line":1485,"character":0},"file":"src/huggingface_hub/file_download.py"},{"cursor":{"line":184,"character":4},"file":"src/huggingface_hub/inference/_common.py"},{"cursor":{"line":157,"character":13},"file":"src/huggingface_hub/utils/_validators.py"},{"cursor":{"line":32,"character":10},"file":"src/huggingface_hub/utils/_paths.py"},{"cursor":{"line":1596,"character":11},"file":"src/huggingface_hub/file_download.py"},{"cursor":{"line":20,"character":4},"file":"src/huggingface_hub/commands/__init__.py"},{"cursor":{"line":47,"character":8},"file":"src/huggingface_hub/commands/user.py"}] \ No newline at end of file diff --git a/crates/testbed/holes/huggingface_hub.json b/crates/testbed/holes/huggingface_hub.json new file mode 100644 index 0000000..5ea7ba4 --- /dev/null +++ b/crates/testbed/holes/huggingface_hub.json @@ -0,0 +1 @@ +[{"cursor":{"line":41,"character":14},"file":"src/huggingface_hub/utils/_deprecation.py"},{"cursor":{"line":222,"character":7},"file":"src/huggingface_hub/_multi_commits.py"},{"cursor":{"line":3,"character":3},"file":"src/huggingface_hub/utils/_fixes.py"},{"cursor":{"line":72,"character":14},"file":"src/huggingface_hub/utils/__init__.py"},{"cursor":{"line":109,"character":6},"file":"src/huggingface_hub/constants.py"},{"cursor":{"line":387,"character":0},"file":"src/huggingface_hub/repocard_data.py"},{"cursor":{"line":139,"character":14},"file":"src/huggingface_hub/commands/upload.py"},{"cursor":{"line":284,"character":10},"file":"src/huggingface_hub/utils/_cache_manager.py"},{"cursor":{"line":50,"character":0},"file":"src/huggingface_hub/utils/_datetime.py"},{"cursor":{"line":208,"character":7},"file":"src/huggingface_hub/commands/delete_cache.py"},{"cursor":{"line":1,"character":0},"file":"src/huggingface_hub/utils/sha.py"},{"cursor":{"line":112,"character":14},"file":"src/huggingface_hub/utils/_cache_assets.py"},{"cursor":{"line":304,"character":13},"file":"src/huggingface_hub/inference/_text_generation.py"},{"cursor":{"line":93,"character":14},"file":"src/huggingface_hub/utils/_hf_folder.py"},{"cursor":{"line":146,"character":5},"file":"src/huggingface_hub/inference/_types.py"},{"cursor":{"line":28,"character":11},"file":"src/huggingface_hub/inference/_types.py"},{"cursor":{"line":41,"character":8},"file":"src/huggingface_hub/commands/user.py"},{"cursor":{"line":14,"character":12},"file":"src/huggingface_hub/inference/_types.py"},{"cursor":{"line":48,"character":11},"file":"src/huggingface_hub/utils/_hf_folder.py"},{"cursor":{"line":415,"character":6},"file":"src/huggingface_hub/lfs.py"},{"cursor":{"line":228,"character":4},"file":"src/huggingface_hub/utils/_http.py"},{"cursor":{"line":30,"character":12},"file":"src/huggingface_hub/inference/_common.py"},{"cursor":{"line":281,"character":2},"file":"src/huggingface_hub/utils/_http.py"},{"cursor":{"line":159,"character":11},"file":"src/huggingface_hub/utils/_errors.py"},{"cursor":{"line":276,"character":2},"file":"src/huggingface_hub/repocard_data.py"},{"cursor":{"line":192,"character":0},"file":"src/huggingface_hub/__init__.py"},{"cursor":{"line":25,"character":9},"file":"src/huggingface_hub/commands/__init__.py"},{"cursor":{"line":96,"character":8},"file":"src/huggingface_hub/utils/__init__.py"},{"cursor":{"line":795,"character":9},"file":"src/huggingface_hub/file_download.py"},{"cursor":{"line":540,"character":2},"file":"src/huggingface_hub/repository.py"},{"cursor":{"line":40,"character":12},"file":"src/huggingface_hub/utils/_telemetry.py"},{"cursor":{"line":1553,"character":3},"file":"src/huggingface_hub/inference/_generated/_async_client.py"},{"cursor":{"line":81,"character":11},"file":"src/huggingface_hub/utils/_hf_folder.py"},{"cursor":{"line":72,"character":5},"file":"src/huggingface_hub/commands/user.py"},{"cursor":{"line":518,"character":1},"file":"src/huggingface_hub/repository.py"},{"cursor":{"line":0,"character":4},"file":"src/huggingface_hub/hub_mixin.py"},{"cursor":{"line":33,"character":8},"file":"src/huggingface_hub/utils/_deprecation.py"},{"cursor":{"line":57,"character":14},"file":"src/huggingface_hub/utils/logging.py"},{"cursor":{"line":317,"character":0},"file":"src/huggingface_hub/hub_mixin.py"},{"cursor":{"line":281,"character":7},"file":"src/huggingface_hub/_commit_scheduler.py"},{"cursor":{"line":1930,"character":3},"file":"src/huggingface_hub/inference/_generated/_async_client.py"},{"cursor":{"line":69,"character":3},"file":"src/huggingface_hub/_webhooks_payload.py"},{"cursor":{"line":90,"character":1},"file":"src/huggingface_hub/inference_api.py"},{"cursor":{"line":1141,"character":11},"file":"src/huggingface_hub/inference/_client.py"},{"cursor":{"line":140,"character":9},"file":"src/huggingface_hub/_commit_api.py"},{"cursor":{"line":61,"character":5},"file":"src/huggingface_hub/commands/_cli_utils.py"},{"cursor":{"line":21,"character":13},"file":"src/huggingface_hub/utils/_errors.py"},{"cursor":{"line":115,"character":8},"file":"src/huggingface_hub/commands/lfs.py"},{"cursor":{"line":166,"character":3},"file":"src/huggingface_hub/utils/logging.py"},{"cursor":{"line":16,"character":13},"file":"src/huggingface_hub/utils/_experimental.py"},{"cursor":{"line":46,"character":3},"file":"src/huggingface_hub/utils/_pagination.py"},{"cursor":{"line":2,"character":12},"file":"src/huggingface_hub/utils/sha.py"},{"cursor":{"line":932,"character":14},"file":"src/huggingface_hub/inference/_generated/_async_client.py"},{"cursor":{"line":131,"character":2},"file":"src/huggingface_hub/utils/_cache_assets.py"},{"cursor":{"line":166,"character":4},"file":"src/huggingface_hub/commands/lfs.py"},{"cursor":{"line":10,"character":0},"file":"src/huggingface_hub/utils/sha.py"},{"cursor":{"line":734,"character":6},"file":"src/huggingface_hub/repository.py"},{"cursor":{"line":407,"character":14},"file":"src/huggingface_hub/inference/_generated/_async_client.py"},{"cursor":{"line":18,"character":2},"file":"src/huggingface_hub/utils/endpoint_helpers.py"},{"cursor":{"line":179,"character":7},"file":"src/huggingface_hub/utils/endpoint_helpers.py"},{"cursor":{"line":139,"character":4},"file":"src/huggingface_hub/community.py"},{"cursor":{"line":165,"character":6},"file":"src/huggingface_hub/repository.py"},{"cursor":{"line":366,"character":4},"file":"src/huggingface_hub/utils/_cache_manager.py"},{"cursor":{"line":19,"character":14},"file":"src/huggingface_hub/utils/_chunk_utils.py"},{"cursor":{"line":1249,"character":9},"file":"src/huggingface_hub/repository.py"},{"cursor":{"line":58,"character":8},"file":"src/huggingface_hub/commands/_cli_utils.py"},{"cursor":{"line":153,"character":1},"file":"src/huggingface_hub/inference/_text_generation.py"},{"cursor":{"line":574,"character":1},"file":"src/huggingface_hub/utils/_cache_manager.py"},{"cursor":{"line":60,"character":7},"file":"src/huggingface_hub/commands/scan_cache.py"},{"cursor":{"line":78,"character":10},"file":"src/huggingface_hub/utils/_cache_assets.py"},{"cursor":{"line":98,"character":0},"file":"src/huggingface_hub/utils/_subprocess.py"},{"cursor":{"line":84,"character":11},"file":"src/huggingface_hub/utils/_cache_assets.py"},{"cursor":{"line":30,"character":8},"file":"src/huggingface_hub/utils/_runtime.py"},{"cursor":{"line":89,"character":8},"file":"src/huggingface_hub/commands/delete_cache.py"},{"cursor":{"line":33,"character":14},"file":"src/huggingface_hub/commands/huggingface_cli.py"},{"cursor":{"line":272,"character":8},"file":"src/huggingface_hub/utils/_http.py"},{"cursor":{"line":277,"character":5},"file":"src/huggingface_hub/community.py"},{"cursor":{"line":206,"character":7},"file":"src/huggingface_hub/utils/_headers.py"},{"cursor":{"line":1250,"character":9},"file":"src/huggingface_hub/inference/_generated/_async_client.py"},{"cursor":{"line":57,"character":13},"file":"src/huggingface_hub/commands/_cli_utils.py"},{"cursor":{"line":164,"character":1},"file":"src/huggingface_hub/utils/endpoint_helpers.py"},{"cursor":{"line":46,"character":10},"file":"src/huggingface_hub/utils/tqdm.py"},{"cursor":{"line":183,"character":6},"file":"src/huggingface_hub/commands/download.py"},{"cursor":{"line":27,"character":0},"file":"src/huggingface_hub/utils/_paths.py"},{"cursor":{"line":133,"character":0},"file":"src/huggingface_hub/commands/scan_cache.py"},{"cursor":{"line":68,"character":4},"file":"src/huggingface_hub/constants.py"},{"cursor":{"line":11,"character":9},"file":"src/huggingface_hub/hub_mixin.py"},{"cursor":{"line":101,"character":1},"file":"src/huggingface_hub/_multi_commits.py"},{"cursor":{"line":105,"character":1},"file":"src/huggingface_hub/_webhooks_payload.py"},{"cursor":{"line":1,"character":9},"file":"src/huggingface_hub/utils/sha.py"},{"cursor":{"line":51,"character":2},"file":"src/huggingface_hub/commands/user.py"},{"cursor":{"line":75,"character":4},"file":"src/huggingface_hub/utils/_deprecation.py"},{"cursor":{"line":61,"character":12},"file":"src/huggingface_hub/utils/_fixes.py"},{"cursor":{"line":4394,"character":9},"file":"src/huggingface_hub/hf_api.py"},{"cursor":{"line":65,"character":1},"file":"src/huggingface_hub/utils/logging.py"},{"cursor":{"line":16,"character":5},"file":"src/huggingface_hub/commands/download.py"},{"cursor":{"line":110,"character":12},"file":"src/huggingface_hub/_space_api.py"},{"cursor":{"line":187,"character":8},"file":"src/huggingface_hub/commands/user.py"},{"cursor":{"line":36,"character":7},"file":"src/huggingface_hub/utils/_datetime.py"},{"cursor":{"line":290,"character":2},"file":"src/huggingface_hub/community.py"}] \ No newline at end of file diff --git a/crates/testbed/holes/io-ts-smol.json b/crates/testbed/holes/io-ts-smol.json new file mode 100644 index 0000000..32b61b3 --- /dev/null +++ b/crates/testbed/holes/io-ts-smol.json @@ -0,0 +1 @@ +[{"cursor":{"line":54,"character":12},"file":"src/Type.ts"},{"cursor":{"line":108,"character":1},"file":"src/Eq.ts"},{"cursor":{"line":6,"character":4},"file":"src/Reporter.ts"},{"cursor":{"line":98,"character":7},"file":"src/Type.ts"},{"cursor":{"line":88,"character":1},"file":"src/Type.ts"},{"cursor":{"line":140,"character":11},"file":"src/Eq.ts"},{"cursor":{"line":52,"character":2},"file":"src/Kleisli.ts"},{"cursor":{"line":47,"character":2},"file":"src/PathReporter.ts"},{"cursor":{"line":109,"character":11},"file":"src/Schemable.ts"},{"cursor":{"line":484,"character":1},"file":"src/TaskDecoder.ts"}] \ No newline at end of file diff --git a/crates/testbed/holes/io-ts.json b/crates/testbed/holes/io-ts.json new file mode 100644 index 0000000..5d09fcb --- /dev/null +++ b/crates/testbed/holes/io-ts.json @@ -0,0 +1 @@ +[{"cursor":{"line":130,"character":3},"file":"src/Encoder.ts"},{"cursor":{"line":85,"character":13},"file":"src/Codec.ts"},{"cursor":{"line":9,"character":3},"file":"src/Reporter.ts"},{"cursor":{"line":44,"character":14},"file":"src/FreeSemigroup.ts"},{"cursor":{"line":169,"character":12},"file":"src/Kleisli.ts"},{"cursor":{"line":44,"character":1},"file":"src/Schema.ts"},{"cursor":{"line":510,"character":14},"file":"src/Decoder.ts"},{"cursor":{"line":19,"character":0},"file":"src/FreeSemigroup.ts"},{"cursor":{"line":31,"character":2},"file":"src/PathReporter.ts"},{"cursor":{"line":2,"character":3},"file":"src/Reporter.ts"},{"cursor":{"line":37,"character":8},"file":"src/Type.ts"},{"cursor":{"line":3,"character":3},"file":"src/ThrowReporter.ts"},{"cursor":{"line":9,"character":3},"file":"src/TaskDecoder.ts"},{"cursor":{"line":5,"character":8},"file":"src/PathReporter.ts"},{"cursor":{"line":13,"character":0},"file":"src/PathReporter.ts"},{"cursor":{"line":31,"character":2},"file":"src/Decoder.ts"},{"cursor":{"line":231,"character":2},"file":"src/Kleisli.ts"},{"cursor":{"line":50,"character":1},"file":"src/Eq.ts"},{"cursor":{"line":1740,"character":2},"file":"src/index.ts"},{"cursor":{"line":231,"character":5},"file":"src/Type.ts"},{"cursor":{"line":157,"character":12},"file":"src/Schemable.ts"},{"cursor":{"line":41,"character":12},"file":"src/PathReporter.ts"},{"cursor":{"line":515,"character":6},"file":"src/TaskDecoder.ts"},{"cursor":{"line":286,"character":0},"file":"src/Kleisli.ts"},{"cursor":{"line":31,"character":1},"file":"src/Schema.ts"},{"cursor":{"line":18,"character":2},"file":"src/ThrowReporter.ts"},{"cursor":{"line":444,"character":7},"file":"src/index.ts"},{"cursor":{"line":0,"character":1},"file":"src/Eq.ts"},{"cursor":{"line":39,"character":12},"file":"src/PathReporter.ts"},{"cursor":{"line":122,"character":4},"file":"src/Type.ts"},{"cursor":{"line":193,"character":11},"file":"src/Type.ts"},{"cursor":{"line":19,"character":2},"file":"src/Guard.ts"},{"cursor":{"line":134,"character":4},"file":"src/Kleisli.ts"},{"cursor":{"line":2,"character":2},"file":"src/FreeSemigroup.ts"},{"cursor":{"line":428,"character":12},"file":"src/Decoder.ts"},{"cursor":{"line":3,"character":3},"file":"src/ThrowReporter.ts"},{"cursor":{"line":218,"character":2},"file":"src/Kleisli.ts"},{"cursor":{"line":2,"character":7},"file":"src/ThrowReporter.ts"},{"cursor":{"line":94,"character":5},"file":"src/Encoder.ts"},{"cursor":{"line":8,"character":2},"file":"src/Schema.ts"},{"cursor":{"line":6,"character":13},"file":"src/PathReporter.ts"},{"cursor":{"line":1932,"character":2},"file":"src/index.ts"},{"cursor":{"line":194,"character":6},"file":"src/Type.ts"},{"cursor":{"line":264,"character":3},"file":"src/TaskDecoder.ts"},{"cursor":{"line":86,"character":2},"file":"src/TaskDecoder.ts"},{"cursor":{"line":71,"character":3},"file":"src/FreeSemigroup.ts"},{"cursor":{"line":8,"character":14},"file":"src/Reporter.ts"},{"cursor":{"line":1,"character":12},"file":"src/ThrowReporter.ts"},{"cursor":{"line":3,"character":0},"file":"src/ThrowReporter.ts"},{"cursor":{"line":48,"character":5},"file":"src/Schema.ts"},{"cursor":{"line":72,"character":12},"file":"src/DecodeError.ts"},{"cursor":{"line":151,"character":10},"file":"src/DecodeError.ts"},{"cursor":{"line":25,"character":10},"file":"src/DecodeError.ts"},{"cursor":{"line":82,"character":3},"file":"src/Kleisli.ts"},{"cursor":{"line":2,"character":0},"file":"src/PathReporter.ts"},{"cursor":{"line":210,"character":8},"file":"src/Type.ts"},{"cursor":{"line":14,"character":6},"file":"src/PathReporter.ts"},{"cursor":{"line":46,"character":3},"file":"src/Eq.ts"},{"cursor":{"line":89,"character":2},"file":"src/Schemable.ts"},{"cursor":{"line":6,"character":13},"file":"src/Reporter.ts"},{"cursor":{"line":1236,"character":6},"file":"src/index.ts"},{"cursor":{"line":121,"character":0},"file":"src/Eq.ts"},{"cursor":{"line":9,"character":9},"file":"src/Reporter.ts"},{"cursor":{"line":15,"character":2},"file":"src/PathReporter.ts"},{"cursor":{"line":34,"character":2},"file":"src/FreeSemigroup.ts"},{"cursor":{"line":237,"character":5},"file":"src/index.ts"},{"cursor":{"line":188,"character":13},"file":"src/TaskDecoder.ts"},{"cursor":{"line":1718,"character":4},"file":"src/index.ts"},{"cursor":{"line":208,"character":4},"file":"src/Schemable.ts"},{"cursor":{"line":65,"character":1},"file":"src/Guard.ts"},{"cursor":{"line":8,"character":0},"file":"src/Reporter.ts"},{"cursor":{"line":23,"character":10},"file":"src/FreeSemigroup.ts"},{"cursor":{"line":91,"character":2},"file":"src/Schemable.ts"},{"cursor":{"line":43,"character":0},"file":"src/PathReporter.ts"},{"cursor":{"line":250,"character":1},"file":"src/Type.ts"},{"cursor":{"line":2,"character":0},"file":"src/ThrowReporter.ts"},{"cursor":{"line":10,"character":2},"file":"src/ThrowReporter.ts"},{"cursor":{"line":310,"character":0},"file":"src/Kleisli.ts"},{"cursor":{"line":353,"character":3},"file":"src/TaskDecoder.ts"},{"cursor":{"line":10,"character":0},"file":"src/Reporter.ts"},{"cursor":{"line":126,"character":9},"file":"src/Encoder.ts"},{"cursor":{"line":252,"character":4},"file":"src/Guard.ts"},{"cursor":{"line":38,"character":0},"file":"src/Decoder.ts"},{"cursor":{"line":146,"character":14},"file":"src/Type.ts"},{"cursor":{"line":7,"character":1},"file":"src/Schema.ts"},{"cursor":{"line":1572,"character":7},"file":"src/index.ts"},{"cursor":{"line":136,"character":14},"file":"src/Encoder.ts"},{"cursor":{"line":17,"character":9},"file":"src/FreeSemigroup.ts"},{"cursor":{"line":360,"character":11},"file":"src/TaskDecoder.ts"},{"cursor":{"line":232,"character":7},"file":"src/Kleisli.ts"},{"cursor":{"line":540,"character":3},"file":"src/Decoder.ts"},{"cursor":{"line":86,"character":13},"file":"src/Schemable.ts"},{"cursor":{"line":36,"character":2},"file":"src/Eq.ts"},{"cursor":{"line":582,"character":12},"file":"src/Decoder.ts"},{"cursor":{"line":4,"character":13},"file":"src/ThrowReporter.ts"},{"cursor":{"line":8,"character":6},"file":"src/Reporter.ts"},{"cursor":{"line":60,"character":2},"file":"src/Encoder.ts"},{"cursor":{"line":166,"character":4},"file":"src/DecodeError.ts"},{"cursor":{"line":169,"character":14},"file":"src/DecodeError.ts"},{"cursor":{"line":372,"character":14},"file":"src/TaskDecoder.ts"}] \ No newline at end of file diff --git a/crates/testbed/holes/lance-smol.json b/crates/testbed/holes/lance-smol.json new file mode 100644 index 0000000..c44b1e8 --- /dev/null +++ b/crates/testbed/holes/lance-smol.json @@ -0,0 +1 @@ +[{"cursor":{"line":136,"character":0},"file":"rust/lance/src/utils/sql.rs"},{"cursor":{"line":121,"character":7},"file":"rust/lance-index/src/vector/utils.rs"},{"cursor":{"line":182,"character":1},"file":"rust/lance-linalg/src/simd/i32.rs"},{"cursor":{"line":527,"character":2},"file":"rust/lance-core/src/io/writer.rs"},{"cursor":{"line":123,"character":0},"file":"rust/lance/benches/scan.rs"},{"cursor":{"line":14,"character":1},"file":"rust/lance-core/src/utils.rs"},{"cursor":{"line":211,"character":2},"file":"rust/lance-core/src/encodings/dictionary.rs"},{"cursor":{"line":508,"character":8},"file":"rust/lance-core/src/datatypes/field.rs"},{"cursor":{"line":624,"character":7},"file":"rust/lance/src/dataset/cleanup.rs"},{"cursor":{"line":396,"character":5},"file":"rust/lance/src/index/vector/opq.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/lance.json b/crates/testbed/holes/lance.json new file mode 100644 index 0000000..0b41aa2 --- /dev/null +++ b/crates/testbed/holes/lance.json @@ -0,0 +1 @@ +[{"cursor":{"line":1246,"character":9},"file":"rust/lance-core/src/io/writer/statistics.rs"},{"cursor":{"line":1165,"character":11},"file":"rust/lance/src/index/vector/ivf.rs"},{"cursor":{"line":156,"character":5},"file":"rust/lance/src/index/append.rs"},{"cursor":{"line":73,"character":10},"file":"rust/lance-linalg/benches/kmeans.rs"},{"cursor":{"line":32,"character":0},"file":"rust/lance-arrow/src/bfloat16.rs"},{"cursor":{"line":159,"character":2},"file":"rust/lance/benches/vector_index.rs"},{"cursor":{"line":57,"character":10},"file":"rust/lance/benches/vector_index.rs"},{"cursor":{"line":170,"character":12},"file":"rust/lance/src/index/prefilter.rs"},{"cursor":{"line":7,"character":0},"file":"rust/lance-index/build.rs"},{"cursor":{"line":308,"character":0},"file":"rust/lance-arrow/src/bfloat16.rs"},{"cursor":{"line":16,"character":13},"file":"rust/lance-index/src/vector/residual.rs"},{"cursor":{"line":141,"character":6},"file":"rust/lance-linalg/src/distance/l2.rs"},{"cursor":{"line":548,"character":6},"file":"rust/lance-arrow/src/lib.rs"},{"cursor":{"line":22,"character":6},"file":"rust/lance-index/src/vector/kmeans.rs"},{"cursor":{"line":301,"character":4},"file":"rust/lance/src/io/commit.rs"},{"cursor":{"line":133,"character":14},"file":"rust/lance/src/utils/sql.rs"},{"cursor":{"line":770,"character":12},"file":"rust/lance-core/src/datatypes/field.rs"},{"cursor":{"line":15,"character":0},"file":"rust/lance-core/src/format.rs"},{"cursor":{"line":72,"character":0},"file":"rust/lance-core/src/io.rs"},{"cursor":{"line":61,"character":4},"file":"rust/lance-index/src/vector/residual.rs"},{"cursor":{"line":90,"character":4},"file":"rust/lance-index/src/scalar/lance.rs"},{"cursor":{"line":813,"character":1},"file":"rust/lance/src/dataset/optimize.rs"},{"cursor":{"line":3105,"character":5},"file":"rust/lance/src/dataset.rs"},{"cursor":{"line":130,"character":3},"file":"rust/lance-core/src/datatypes.rs"},{"cursor":{"line":81,"character":1},"file":"rust/lance-index/src/vector/pq/transform.rs"},{"cursor":{"line":148,"character":7},"file":"rust/lance-core/src/io/commit.rs"},{"cursor":{"line":216,"character":2},"file":"rust/lance/src/arrow/svd.rs"},{"cursor":{"line":89,"character":13},"file":"rust/lance-datagen/benches/array_gen.rs"},{"cursor":{"line":179,"character":8},"file":"rust/lance/src/index.rs"},{"cursor":{"line":259,"character":12},"file":"rust/lance/src/io/exec/scan.rs"},{"cursor":{"line":29,"character":10},"file":"rust/lance-core/src/lib.rs"},{"cursor":{"line":211,"character":13},"file":"rust/lance/src/index/vector/ivf.rs"},{"cursor":{"line":61,"character":3},"file":"rust/lance-core/src/io/stream.rs"},{"cursor":{"line":1463,"character":13},"file":"rust/lance/src/dataset/optimize.rs"},{"cursor":{"line":99,"character":0},"file":"rust/lance-core/src/io/local.rs"},{"cursor":{"line":113,"character":11},"file":"rust/lance-linalg/src/distance/norm_l2.rs"},{"cursor":{"line":263,"character":11},"file":"rust/lance/src/io/exec/knn.rs"},{"cursor":{"line":184,"character":14},"file":"rust/lance/src/io/exec/projection.rs"},{"cursor":{"line":465,"character":4},"file":"rust/lance-index/src/scalar/btree.rs"},{"cursor":{"line":195,"character":9},"file":"rust/lance-index/src/vector/utils.rs"},{"cursor":{"line":212,"character":1},"file":"rust/lance-core/src/format/fragment.rs"},{"cursor":{"line":72,"character":1},"file":"rust/lance-core/src/io/traits.rs"},{"cursor":{"line":149,"character":11},"file":"rust/lance-core/src/io/object_store/tracing.rs"},{"cursor":{"line":31,"character":1},"file":"rust/lance/src/index/vector/graph.rs"},{"cursor":{"line":107,"character":4},"file":"rust/lance-index/src/vector/residual.rs"},{"cursor":{"line":77,"character":3},"file":"rust/lance-index/src/vector.rs"},{"cursor":{"line":664,"character":14},"file":"rust/lance/src/io/exec/planner.rs"},{"cursor":{"line":81,"character":9},"file":"rust/lance-index/src/scalar/flat.rs"},{"cursor":{"line":170,"character":5},"file":"rust/lance/src/index/vector/pq.rs"},{"cursor":{"line":10,"character":1},"file":"rust/lance-index/build.rs"},{"cursor":{"line":636,"character":6},"file":"rust/lance/src/dataset/cleanup.rs"},{"cursor":{"line":308,"character":5},"file":"rust/lance/src/index.rs"},{"cursor":{"line":35,"character":9},"file":"rust/lance-linalg/benches/argmin.rs"},{"cursor":{"line":322,"character":11},"file":"rust/lance/src/index/vector/diskann/builder.rs"},{"cursor":{"line":31,"character":11},"file":"rust/lance/src/index/vector/diskann/row_vertex.rs"},{"cursor":{"line":133,"character":1},"file":"rust/lance/src/dataset/updater.rs"},{"cursor":{"line":190,"character":11},"file":"rust/lance-core/src/error.rs"},{"cursor":{"line":67,"character":0},"file":"rust/lance-linalg/benches/kmeans.rs"},{"cursor":{"line":223,"character":11},"file":"rust/lance-linalg/src/matrix.rs"},{"cursor":{"line":125,"character":10},"file":"rust/lance-index/src/vector/flat.rs"},{"cursor":{"line":110,"character":5},"file":"rust/lance-testing/src/datagen.rs"},{"cursor":{"line":42,"character":8},"file":"rust/lance-linalg/src/distance/l2.rs"},{"cursor":{"line":145,"character":7},"file":"rust/lance/src/datafusion/physical_expr.rs"},{"cursor":{"line":39,"character":3},"file":"rust/lance-core/src/datatypes/schema.rs"},{"cursor":{"line":141,"character":2},"file":"rust/lance-linalg/src/kernels.rs"},{"cursor":{"line":93,"character":4},"file":"rust/lance/benches/vector_index.rs"},{"cursor":{"line":862,"character":13},"file":"rust/lance-core/src/encodings/plain.rs"},{"cursor":{"line":286,"character":4},"file":"rust/lance/src/dataset/transaction.rs"},{"cursor":{"line":17,"character":12},"file":"rust/lance-linalg/benches/kmeans.rs"},{"cursor":{"line":67,"character":12},"file":"rust/lance-linalg/src/distance.rs"},{"cursor":{"line":121,"character":14},"file":"rust/lance-linalg/src/distance/norm_l2.rs"},{"cursor":{"line":1604,"character":3},"file":"rust/lance-core/src/io/reader.rs"},{"cursor":{"line":35,"character":4},"file":"rust/lance-datagen/benches/array_gen.rs"},{"cursor":{"line":49,"character":8},"file":"rust/lance-core/src/io/object_reader.rs"},{"cursor":{"line":211,"character":1},"file":"rust/lance/src/arrow/json.rs"},{"cursor":{"line":373,"character":1},"file":"rust/lance-core/src/encodings/plain.rs"},{"cursor":{"line":30,"character":11},"file":"rust/lance/src/bin/lq.rs"},{"cursor":{"line":198,"character":14},"file":"rust/lance/src/index/vector/diskann/search.rs"},{"cursor":{"line":141,"character":4},"file":"rust/lance-core/src/io/deletion.rs"},{"cursor":{"line":296,"character":2},"file":"rust/lance-linalg/src/kmeans.rs"},{"cursor":{"line":22,"character":1},"file":"rust/lance/src/dataset/index.rs"},{"cursor":{"line":22,"character":8},"file":"rust/lance-core/src/encodings.rs"},{"cursor":{"line":175,"character":7},"file":"rust/lance-core/src/io/deletion.rs"},{"cursor":{"line":101,"character":6},"file":"rust/lance-linalg/benches/dot.rs"},{"cursor":{"line":40,"character":7},"file":"rust/lance-linalg/src/kmeans.rs"},{"cursor":{"line":63,"character":10},"file":"rust/lance-core/src/encodings/binary.rs"},{"cursor":{"line":189,"character":14},"file":"rust/lance-core/src/io/reader.rs"},{"cursor":{"line":84,"character":14},"file":"rust/lance/src/lib.rs"},{"cursor":{"line":1663,"character":1},"file":"rust/lance-core/src/io/writer/statistics.rs"},{"cursor":{"line":174,"character":11},"file":"rust/lance/src/index/vector/diskann/search.rs"},{"cursor":{"line":87,"character":7},"file":"rust/lance/src/utils/tfrecord.rs"},{"cursor":{"line":79,"character":3},"file":"rust/lance/src/index/vector/traits.rs"},{"cursor":{"line":29,"character":9},"file":"rust/lance/src/index/vector/pq.rs"},{"cursor":{"line":136,"character":12},"file":"rust/lance-datagen/benches/array_gen.rs"},{"cursor":{"line":374,"character":1},"file":"rust/lance/src/io/exec/knn.rs"},{"cursor":{"line":31,"character":0},"file":"rust/lance-core/src/encodings/binary.rs"},{"cursor":{"line":1502,"character":0},"file":"rust/lance/src/dataset/optimize.rs"},{"cursor":{"line":36,"character":1},"file":"rust/lance-linalg/src/simd/i32.rs"},{"cursor":{"line":38,"character":10},"file":"rust/lance-linalg/src/simd/i32.rs"},{"cursor":{"line":52,"character":4},"file":"rust/lance-core/src/io/stream.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/lancedb-smol.json b/crates/testbed/holes/lancedb-smol.json new file mode 100644 index 0000000..9d73ee0 --- /dev/null +++ b/crates/testbed/holes/lancedb-smol.json @@ -0,0 +1 @@ +[{"cursor":{"line":0,"character":6},"file":"rust/vectordb/src/io.rs"},{"cursor":{"line":65,"character":4},"file":"rust/vectordb/src/utils.rs"},{"cursor":{"line":138,"character":7},"file":"rust/vectordb/src/data/inspect.rs"},{"cursor":{"line":25,"character":3},"file":"rust/vectordb/src/error.rs"},{"cursor":{"line":479,"character":3},"file":"rust/vectordb/src/table.rs"},{"cursor":{"line":133,"character":10},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":54,"character":1},"file":"rust/vectordb/src/utils.rs"},{"cursor":{"line":138,"character":9},"file":"rust/vectordb/src/table.rs"},{"cursor":{"line":34,"character":10},"file":"rust/vectordb/src/database.rs"},{"cursor":{"line":159,"character":1},"file":"rust/vectordb/src/data/inspect.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/lancedb.json b/crates/testbed/holes/lancedb.json new file mode 100644 index 0000000..3f57aec --- /dev/null +++ b/crates/testbed/holes/lancedb.json @@ -0,0 +1 @@ +[{"cursor":{"line":135,"character":2},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":111,"character":1},"file":"rust/vectordb/src/index/vector.rs"},{"cursor":{"line":0,"character":2},"file":"rust/vectordb/src/io.rs"},{"cursor":{"line":103,"character":1},"file":"rust/vectordb/src/index/vector.rs"},{"cursor":{"line":65,"character":14},"file":"rust/vectordb/src/data/inspect.rs"},{"cursor":{"line":271,"character":1},"file":"rust/vectordb/src/database.rs"},{"cursor":{"line":76,"character":13},"file":"rust/vectordb/src/database.rs"},{"cursor":{"line":385,"character":9},"file":"rust/vectordb/src/io/object_store.rs"},{"cursor":{"line":36,"character":3},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":23,"character":7},"file":"rust/vectordb/src/lib.rs"},{"cursor":{"line":65,"character":0},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":18,"character":4},"file":"rust/vectordb/src/lib.rs"},{"cursor":{"line":120,"character":2},"file":"rust/vectordb/src/io/object_store.rs"},{"cursor":{"line":94,"character":10},"file":"rust/vectordb/src/data/inspect.rs"},{"cursor":{"line":310,"character":9},"file":"rust/vectordb/src/io/object_store.rs"},{"cursor":{"line":0,"character":7},"file":"rust/vectordb/src/io.rs"},{"cursor":{"line":27,"character":2},"file":"rust/vectordb/src/error.rs"},{"cursor":{"line":16,"character":10},"file":"rust/vectordb/src/data.rs"},{"cursor":{"line":0,"character":1},"file":"rust/vectordb/src/io.rs"},{"cursor":{"line":64,"character":11},"file":"rust/vectordb/src/data/inspect.rs"},{"cursor":{"line":19,"character":7},"file":"rust/vectordb/src/error.rs"},{"cursor":{"line":203,"character":8},"file":"rust/vectordb/src/table.rs"},{"cursor":{"line":290,"character":8},"file":"rust/vectordb/src/table.rs"},{"cursor":{"line":273,"character":2},"file":"rust/vectordb/src/database.rs"},{"cursor":{"line":63,"character":0},"file":"rust/vectordb/src/error.rs"},{"cursor":{"line":20,"character":2},"file":"rust/vectordb/src/index/vector.rs"},{"cursor":{"line":206,"character":6},"file":"rust/vectordb/src/index/vector.rs"},{"cursor":{"line":47,"character":10},"file":"rust/vectordb/src/utils.rs"},{"cursor":{"line":416,"character":8},"file":"rust/vectordb/src/table.rs"},{"cursor":{"line":0,"character":12},"file":"rust/vectordb/src/io.rs"},{"cursor":{"line":108,"character":1},"file":"rust/vectordb/src/query.rs"},{"cursor":{"line":61,"character":10},"file":"rust/vectordb/src/utils.rs"},{"cursor":{"line":524,"character":12},"file":"rust/vectordb/src/table.rs"},{"cursor":{"line":23,"character":9},"file":"rust/vectordb/src/error.rs"},{"cursor":{"line":152,"character":7},"file":"rust/vectordb/src/database.rs"},{"cursor":{"line":192,"character":4},"file":"rust/vectordb/src/query.rs"},{"cursor":{"line":229,"character":11},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":42,"character":0},"file":"rust/vectordb/src/utils.rs"},{"cursor":{"line":161,"character":10},"file":"rust/vectordb/src/index/vector.rs"},{"cursor":{"line":60,"character":10},"file":"rust/vectordb/src/database.rs"},{"cursor":{"line":14,"character":0},"file":"rust/vectordb/src/arrow.rs"},{"cursor":{"line":183,"character":1},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":94,"character":3},"file":"rust/vectordb/src/data/inspect.rs"},{"cursor":{"line":238,"character":14},"file":"rust/vectordb/src/io/object_store.rs"},{"cursor":{"line":66,"character":4},"file":"rust/vectordb/src/error.rs"},{"cursor":{"line":94,"character":13},"file":"rust/vectordb/src/index/vector.rs"},{"cursor":{"line":130,"character":4},"file":"rust/vectordb/src/data/inspect.rs"},{"cursor":{"line":72,"character":6},"file":"rust/vectordb/src/data/inspect.rs"},{"cursor":{"line":146,"character":10},"file":"rust/vectordb/src/index/vector.rs"},{"cursor":{"line":30,"character":0},"file":"rust/vectordb/src/error.rs"},{"cursor":{"line":169,"character":1},"file":"rust/vectordb/src/data/inspect.rs"},{"cursor":{"line":20,"character":10},"file":"rust/vectordb/src/lib.rs"},{"cursor":{"line":0,"character":0},"file":"rust/vectordb/src/io.rs"},{"cursor":{"line":70,"character":1},"file":"rust/vectordb/src/error.rs"},{"cursor":{"line":222,"character":12},"file":"rust/vectordb/src/query.rs"},{"cursor":{"line":149,"character":3},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":20,"character":10},"file":"rust/vectordb/src/lib.rs"},{"cursor":{"line":179,"character":0},"file":"rust/vectordb/src/io/object_store.rs"},{"cursor":{"line":305,"character":12},"file":"rust/vectordb/src/database.rs"},{"cursor":{"line":30,"character":11},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":59,"character":6},"file":"rust/vectordb/src/utils.rs"},{"cursor":{"line":17,"character":2},"file":"rust/vectordb/src/data.rs"},{"cursor":{"line":279,"character":5},"file":"rust/vectordb/src/io/object_store.rs"},{"cursor":{"line":62,"character":0},"file":"rust/vectordb/src/error.rs"},{"cursor":{"line":37,"character":9},"file":"rust/vectordb/src/utils.rs"},{"cursor":{"line":19,"character":8},"file":"rust/vectordb/src/lib.rs"},{"cursor":{"line":17,"character":12},"file":"rust/vectordb/src/lib.rs"},{"cursor":{"line":67,"character":12},"file":"rust/vectordb/src/index/vector.rs"},{"cursor":{"line":169,"character":2},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":90,"character":8},"file":"rust/vectordb/src/query.rs"},{"cursor":{"line":32,"character":14},"file":"rust/vectordb/src/query.rs"},{"cursor":{"line":18,"character":13},"file":"rust/vectordb/src/index/vector.rs"},{"cursor":{"line":33,"character":7},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":163,"character":4},"file":"rust/vectordb/src/data/inspect.rs"},{"cursor":{"line":124,"character":7},"file":"rust/vectordb/src/database.rs"},{"cursor":{"line":65,"character":4},"file":"rust/vectordb/src/utils.rs"},{"cursor":{"line":65,"character":0},"file":"rust/vectordb/src/utils.rs"},{"cursor":{"line":59,"character":7},"file":"rust/vectordb/src/error.rs"},{"cursor":{"line":276,"character":1},"file":"rust/vectordb/src/database.rs"},{"cursor":{"line":199,"character":11},"file":"rust/vectordb/src/index/vector.rs"},{"cursor":{"line":39,"character":8},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":89,"character":10},"file":"rust/vectordb/src/data/inspect.rs"},{"cursor":{"line":42,"character":6},"file":"rust/vectordb/src/utils.rs"},{"cursor":{"line":301,"character":11},"file":"rust/vectordb/src/database.rs"},{"cursor":{"line":85,"character":1},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":177,"character":14},"file":"rust/vectordb/src/data/inspect.rs"},{"cursor":{"line":309,"character":12},"file":"rust/vectordb/src/database.rs"},{"cursor":{"line":160,"character":2},"file":"rust/vectordb/src/index/vector.rs"},{"cursor":{"line":116,"character":12},"file":"rust/vectordb/src/index/vector.rs"},{"cursor":{"line":81,"character":2},"file":"rust/vectordb/src/io/object_store.rs"},{"cursor":{"line":16,"character":12},"file":"rust/vectordb/src/data.rs"},{"cursor":{"line":118,"character":5},"file":"rust/vectordb/src/data/inspect.rs"},{"cursor":{"line":61,"character":8},"file":"rust/vectordb/src/error.rs"},{"cursor":{"line":47,"character":10},"file":"rust/vectordb/src/utils.rs"},{"cursor":{"line":56,"character":3},"file":"rust/vectordb/src/database.rs"},{"cursor":{"line":202,"character":14},"file":"rust/vectordb/src/table.rs"},{"cursor":{"line":121,"character":9},"file":"rust/vectordb/src/io/object_store.rs"},{"cursor":{"line":28,"character":6},"file":"rust/vectordb/src/error.rs"},{"cursor":{"line":233,"character":5},"file":"rust/vectordb/src/data/sanitize.rs"},{"cursor":{"line":0,"character":14},"file":"rust/vectordb/src/io.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/picklescan-smol.json b/crates/testbed/holes/picklescan-smol.json new file mode 100644 index 0000000..47d4057 --- /dev/null +++ b/crates/testbed/holes/picklescan-smol.json @@ -0,0 +1 @@ +[{"cursor":{"line":374,"character":3},"file":"src/picklescan/scanner.py"},{"cursor":{"line":7,"character":4},"file":"src/picklescan/torch.py"},{"cursor":{"line":0,"character":5},"file":"src/picklescan/__main__.py"},{"cursor":{"line":0,"character":3},"file":"src/picklescan/torch.py"},{"cursor":{"line":351,"character":10},"file":"src/picklescan/scanner.py"},{"cursor":{"line":2,"character":6},"file":"src/picklescan/__main__.py"},{"cursor":{"line":192,"character":10},"file":"src/picklescan/scanner.py"},{"cursor":{"line":0,"character":9},"file":"src/picklescan/__init__.py"},{"cursor":{"line":2,"character":2},"file":"src/picklescan/__main__.py"},{"cursor":{"line":33,"character":3},"file":"src/picklescan/cli.py"}] \ No newline at end of file diff --git a/crates/testbed/holes/picklescan.json b/crates/testbed/holes/picklescan.json new file mode 100644 index 0000000..5faad2a --- /dev/null +++ b/crates/testbed/holes/picklescan.json @@ -0,0 +1 @@ +[{"cursor":{"line":26,"character":8},"file":"src/picklescan/cli.py"},{"cursor":{"line":239,"character":6},"file":"src/picklescan/scanner.py"},{"cursor":{"line":0,"character":2},"file":"src/picklescan/__main__.py"},{"cursor":{"line":25,"character":8},"file":"src/picklescan/torch.py"},{"cursor":{"line":238,"character":4},"file":"src/picklescan/scanner.py"},{"cursor":{"line":2,"character":12},"file":"src/picklescan/__init__.py"},{"cursor":{"line":10,"character":1},"file":"src/picklescan/torch.py"},{"cursor":{"line":35,"character":8},"file":"src/picklescan/torch.py"},{"cursor":{"line":76,"character":2},"file":"src/picklescan/cli.py"},{"cursor":{"line":205,"character":4},"file":"src/picklescan/scanner.py"},{"cursor":{"line":171,"character":8},"file":"src/picklescan/scanner.py"},{"cursor":{"line":219,"character":11},"file":"src/picklescan/scanner.py"},{"cursor":{"line":2,"character":7},"file":"src/picklescan/__init__.py"},{"cursor":{"line":46,"character":3},"file":"src/picklescan/scanner.py"},{"cursor":{"line":88,"character":1},"file":"src/picklescan/cli.py"},{"cursor":{"line":2,"character":4},"file":"src/picklescan/__main__.py"},{"cursor":{"line":20,"character":13},"file":"src/picklescan/cli.py"},{"cursor":{"line":150,"character":4},"file":"src/picklescan/scanner.py"},{"cursor":{"line":0,"character":13},"file":"src/picklescan/__main__.py"},{"cursor":{"line":72,"character":11},"file":"src/picklescan/torch.py"},{"cursor":{"line":0,"character":14},"file":"src/picklescan/__main__.py"},{"cursor":{"line":70,"character":0},"file":"src/picklescan/cli.py"},{"cursor":{"line":0,"character":5},"file":"src/picklescan/__main__.py"},{"cursor":{"line":45,"character":0},"file":"src/picklescan/cli.py"},{"cursor":{"line":0,"character":14},"file":"src/picklescan/__init__.py"},{"cursor":{"line":39,"character":6},"file":"src/picklescan/torch.py"},{"cursor":{"line":70,"character":8},"file":"src/picklescan/cli.py"},{"cursor":{"line":8,"character":0},"file":"src/picklescan/cli.py"},{"cursor":{"line":0,"character":8},"file":"src/picklescan/__init__.py"},{"cursor":{"line":34,"character":6},"file":"src/picklescan/torch.py"},{"cursor":{"line":328,"character":7},"file":"src/picklescan/scanner.py"},{"cursor":{"line":0,"character":1},"file":"src/picklescan/__init__.py"},{"cursor":{"line":40,"character":2},"file":"src/picklescan/cli.py"},{"cursor":{"line":0,"character":13},"file":"src/picklescan/__init__.py"},{"cursor":{"line":76,"character":12},"file":"src/picklescan/scanner.py"},{"cursor":{"line":2,"character":3},"file":"src/picklescan/__init__.py"},{"cursor":{"line":14,"character":3},"file":"src/picklescan/scanner.py"},{"cursor":{"line":264,"character":4},"file":"src/picklescan/scanner.py"},{"cursor":{"line":2,"character":1},"file":"src/picklescan/__init__.py"},{"cursor":{"line":106,"character":10},"file":"src/picklescan/scanner.py"},{"cursor":{"line":274,"character":8},"file":"src/picklescan/scanner.py"},{"cursor":{"line":57,"character":13},"file":"src/picklescan/scanner.py"},{"cursor":{"line":2,"character":0},"file":"src/picklescan/__main__.py"},{"cursor":{"line":80,"character":2},"file":"src/picklescan/torch.py"},{"cursor":{"line":308,"character":1},"file":"src/picklescan/scanner.py"},{"cursor":{"line":0,"character":6},"file":"src/picklescan/__init__.py"},{"cursor":{"line":0,"character":0},"file":"src/picklescan/__init__.py"},{"cursor":{"line":0,"character":6},"file":"src/picklescan/__main__.py"},{"cursor":{"line":63,"character":0},"file":"src/picklescan/cli.py"},{"cursor":{"line":2,"character":4},"file":"src/picklescan/__main__.py"},{"cursor":{"line":34,"character":0},"file":"src/picklescan/torch.py"},{"cursor":{"line":17,"character":4},"file":"src/picklescan/cli.py"},{"cursor":{"line":281,"character":5},"file":"src/picklescan/scanner.py"},{"cursor":{"line":16,"character":5},"file":"src/picklescan/cli.py"},{"cursor":{"line":2,"character":1},"file":"src/picklescan/__main__.py"},{"cursor":{"line":0,"character":1},"file":"src/picklescan/__init__.py"},{"cursor":{"line":211,"character":7},"file":"src/picklescan/scanner.py"},{"cursor":{"line":403,"character":10},"file":"src/picklescan/scanner.py"},{"cursor":{"line":421,"character":14},"file":"src/picklescan/scanner.py"},{"cursor":{"line":163,"character":3},"file":"src/picklescan/scanner.py"},{"cursor":{"line":2,"character":6},"file":"src/picklescan/__main__.py"},{"cursor":{"line":302,"character":1},"file":"src/picklescan/scanner.py"},{"cursor":{"line":73,"character":2},"file":"src/picklescan/cli.py"},{"cursor":{"line":1,"character":2},"file":"src/picklescan/torch.py"},{"cursor":{"line":71,"character":8},"file":"src/picklescan/torch.py"},{"cursor":{"line":0,"character":9},"file":"src/picklescan/__main__.py"},{"cursor":{"line":0,"character":3},"file":"src/picklescan/__main__.py"},{"cursor":{"line":91,"character":12},"file":"src/picklescan/scanner.py"},{"cursor":{"line":83,"character":4},"file":"src/picklescan/cli.py"},{"cursor":{"line":35,"character":12},"file":"src/picklescan/torch.py"},{"cursor":{"line":0,"character":7},"file":"src/picklescan/__main__.py"},{"cursor":{"line":2,"character":5},"file":"src/picklescan/__main__.py"},{"cursor":{"line":211,"character":3},"file":"src/picklescan/scanner.py"},{"cursor":{"line":3,"character":9},"file":"src/picklescan/cli.py"},{"cursor":{"line":70,"character":10},"file":"src/picklescan/cli.py"},{"cursor":{"line":23,"character":13},"file":"src/picklescan/cli.py"},{"cursor":{"line":3,"character":4},"file":"src/picklescan/cli.py"},{"cursor":{"line":2,"character":6},"file":"src/picklescan/__init__.py"},{"cursor":{"line":76,"character":6},"file":"src/picklescan/cli.py"},{"cursor":{"line":39,"character":5},"file":"src/picklescan/cli.py"},{"cursor":{"line":8,"character":9},"file":"src/picklescan/cli.py"},{"cursor":{"line":1,"character":9},"file":"src/picklescan/cli.py"},{"cursor":{"line":2,"character":3},"file":"src/picklescan/__main__.py"},{"cursor":{"line":2,"character":2},"file":"src/picklescan/__main__.py"},{"cursor":{"line":0,"character":0},"file":"src/picklescan/__init__.py"},{"cursor":{"line":61,"character":12},"file":"src/picklescan/cli.py"},{"cursor":{"line":79,"character":10},"file":"src/picklescan/torch.py"},{"cursor":{"line":36,"character":0},"file":"src/picklescan/cli.py"},{"cursor":{"line":347,"character":2},"file":"src/picklescan/scanner.py"},{"cursor":{"line":155,"character":13},"file":"src/picklescan/scanner.py"},{"cursor":{"line":12,"character":12},"file":"src/picklescan/torch.py"},{"cursor":{"line":2,"character":1},"file":"src/picklescan/__main__.py"},{"cursor":{"line":77,"character":4},"file":"src/picklescan/torch.py"},{"cursor":{"line":2,"character":3},"file":"src/picklescan/__main__.py"},{"cursor":{"line":2,"character":3},"file":"src/picklescan/__main__.py"},{"cursor":{"line":2,"character":2},"file":"src/picklescan/__main__.py"},{"cursor":{"line":2,"character":13},"file":"src/picklescan/__init__.py"},{"cursor":{"line":0,"character":10},"file":"src/picklescan/__init__.py"},{"cursor":{"line":387,"character":5},"file":"src/picklescan/scanner.py"},{"cursor":{"line":16,"character":2},"file":"src/picklescan/cli.py"}] \ No newline at end of file diff --git a/crates/testbed/holes/simple.json b/crates/testbed/holes/simple.json new file mode 100644 index 0000000..459a176 --- /dev/null +++ b/crates/testbed/holes/simple.json @@ -0,0 +1 @@ +[{"cursor":{"line":6,"character":1},"file":"src/main.rs"},{"cursor":{"line":30,"character":3},"file":"src/main.rs"},{"cursor":{"line":38,"character":4},"file":"src/main.rs"},{"cursor":{"line":37,"character":14},"file":"src/main.rs"},{"cursor":{"line":37,"character":6},"file":"src/main.rs"},{"cursor":{"line":31,"character":5},"file":"src/main.rs"},{"cursor":{"line":17,"character":13},"file":"src/main.rs"},{"cursor":{"line":43,"character":14},"file":"src/main.rs"},{"cursor":{"line":19,"character":7},"file":"src/main.rs"},{"cursor":{"line":12,"character":0},"file":"src/main.rs"},{"cursor":{"line":44,"character":1},"file":"src/main.rs"},{"cursor":{"line":30,"character":0},"file":"src/main.rs"},{"cursor":{"line":2,"character":1},"file":"src/main.rs"},{"cursor":{"line":1,"character":12},"file":"src/main.rs"},{"cursor":{"line":23,"character":8},"file":"src/main.rs"},{"cursor":{"line":28,"character":3},"file":"src/main.rs"},{"cursor":{"line":13,"character":9},"file":"src/main.rs"},{"cursor":{"line":16,"character":0},"file":"src/main.rs"},{"cursor":{"line":42,"character":10},"file":"src/main.rs"},{"cursor":{"line":18,"character":13},"file":"src/main.rs"},{"cursor":{"line":42,"character":0},"file":"src/main.rs"},{"cursor":{"line":9,"character":11},"file":"src/main.rs"},{"cursor":{"line":10,"character":1},"file":"src/main.rs"},{"cursor":{"line":12,"character":4},"file":"src/main.rs"},{"cursor":{"line":8,"character":11},"file":"src/main.rs"},{"cursor":{"line":39,"character":3},"file":"src/main.rs"},{"cursor":{"line":33,"character":4},"file":"src/main.rs"},{"cursor":{"line":23,"character":6},"file":"src/main.rs"},{"cursor":{"line":4,"character":1},"file":"src/main.rs"},{"cursor":{"line":39,"character":2},"file":"src/main.rs"},{"cursor":{"line":25,"character":5},"file":"src/main.rs"},{"cursor":{"line":16,"character":7},"file":"src/main.rs"},{"cursor":{"line":37,"character":10},"file":"src/main.rs"},{"cursor":{"line":5,"character":4},"file":"src/main.rs"},{"cursor":{"line":17,"character":9},"file":"src/main.rs"},{"cursor":{"line":25,"character":3},"file":"src/main.rs"},{"cursor":{"line":12,"character":4},"file":"src/main.rs"},{"cursor":{"line":0,"character":8},"file":"src/main.rs"},{"cursor":{"line":25,"character":7},"file":"src/main.rs"},{"cursor":{"line":31,"character":3},"file":"src/main.rs"},{"cursor":{"line":33,"character":1},"file":"src/main.rs"},{"cursor":{"line":12,"character":10},"file":"src/main.rs"},{"cursor":{"line":6,"character":1},"file":"src/main.rs"},{"cursor":{"line":26,"character":0},"file":"src/main.rs"},{"cursor":{"line":33,"character":10},"file":"src/main.rs"},{"cursor":{"line":1,"character":11},"file":"src/main.rs"},{"cursor":{"line":42,"character":13},"file":"src/main.rs"},{"cursor":{"line":9,"character":6},"file":"src/main.rs"},{"cursor":{"line":9,"character":5},"file":"src/main.rs"},{"cursor":{"line":6,"character":1},"file":"src/main.rs"},{"cursor":{"line":34,"character":4},"file":"src/main.rs"},{"cursor":{"line":13,"character":6},"file":"src/main.rs"},{"cursor":{"line":1,"character":8},"file":"src/main.rs"},{"cursor":{"line":39,"character":2},"file":"src/main.rs"},{"cursor":{"line":26,"character":4},"file":"src/main.rs"},{"cursor":{"line":41,"character":7},"file":"src/main.rs"},{"cursor":{"line":38,"character":0},"file":"src/main.rs"},{"cursor":{"line":13,"character":6},"file":"src/main.rs"},{"cursor":{"line":2,"character":0},"file":"src/main.rs"},{"cursor":{"line":18,"character":11},"file":"src/main.rs"},{"cursor":{"line":1,"character":1},"file":"src/main.rs"},{"cursor":{"line":32,"character":4},"file":"src/main.rs"},{"cursor":{"line":12,"character":7},"file":"src/main.rs"},{"cursor":{"line":41,"character":11},"file":"src/main.rs"},{"cursor":{"line":43,"character":4},"file":"src/main.rs"},{"cursor":{"line":10,"character":1},"file":"src/main.rs"},{"cursor":{"line":5,"character":6},"file":"src/main.rs"},{"cursor":{"line":21,"character":0},"file":"src/main.rs"},{"cursor":{"line":0,"character":7},"file":"src/main.rs"},{"cursor":{"line":16,"character":1},"file":"src/main.rs"},{"cursor":{"line":5,"character":10},"file":"src/main.rs"},{"cursor":{"line":20,"character":9},"file":"src/main.rs"},{"cursor":{"line":0,"character":0},"file":"src/main.rs"},{"cursor":{"line":41,"character":5},"file":"src/main.rs"},{"cursor":{"line":28,"character":3},"file":"src/main.rs"},{"cursor":{"line":26,"character":14},"file":"src/main.rs"},{"cursor":{"line":31,"character":5},"file":"src/main.rs"},{"cursor":{"line":19,"character":7},"file":"src/main.rs"},{"cursor":{"line":1,"character":12},"file":"src/main.rs"},{"cursor":{"line":26,"character":4},"file":"src/main.rs"},{"cursor":{"line":26,"character":6},"file":"src/main.rs"},{"cursor":{"line":38,"character":8},"file":"src/main.rs"},{"cursor":{"line":31,"character":14},"file":"src/main.rs"},{"cursor":{"line":23,"character":7},"file":"src/main.rs"},{"cursor":{"line":38,"character":2},"file":"src/main.rs"},{"cursor":{"line":17,"character":8},"file":"src/main.rs"},{"cursor":{"line":30,"character":11},"file":"src/main.rs"},{"cursor":{"line":12,"character":1},"file":"src/main.rs"},{"cursor":{"line":20,"character":0},"file":"src/main.rs"},{"cursor":{"line":1,"character":2},"file":"src/main.rs"},{"cursor":{"line":45,"character":1},"file":"src/main.rs"},{"cursor":{"line":2,"character":1},"file":"src/main.rs"},{"cursor":{"line":6,"character":1},"file":"src/main.rs"},{"cursor":{"line":18,"character":6},"file":"src/main.rs"},{"cursor":{"line":18,"character":0},"file":"src/main.rs"},{"cursor":{"line":10,"character":0},"file":"src/main.rs"},{"cursor":{"line":20,"character":10},"file":"src/main.rs"},{"cursor":{"line":33,"character":2},"file":"src/main.rs"},{"cursor":{"line":18,"character":10},"file":"src/main.rs"},{"cursor":{"line":8,"character":5},"file":"src/main.rs"}] \ No newline at end of file diff --git a/crates/testbed/holes/starlette-smol.json b/crates/testbed/holes/starlette-smol.json new file mode 100644 index 0000000..b2de18d --- /dev/null +++ b/crates/testbed/holes/starlette-smol.json @@ -0,0 +1 @@ +[{"cursor":{"line":3,"character":9},"file":"starlette/_utils.py"},{"cursor":{"line":0,"character":10},"file":"starlette/__init__.py"},{"cursor":{"line":38,"character":2},"file":"starlette/config.py"},{"cursor":{"line":23,"character":14},"file":"starlette/_utils.py"},{"cursor":{"line":393,"character":5},"file":"starlette/datastructures.py"},{"cursor":{"line":114,"character":2},"file":"starlette/testclient.py"},{"cursor":{"line":187,"character":13},"file":"starlette/templating.py"},{"cursor":{"line":79,"character":3},"file":"starlette/status.py"},{"cursor":{"line":129,"character":3},"file":"starlette/middleware/cors.py"},{"cursor":{"line":22,"character":6},"file":"starlette/middleware/sessions.py"}] \ No newline at end of file diff --git a/crates/testbed/holes/starlette.json b/crates/testbed/holes/starlette.json new file mode 100644 index 0000000..41f47b7 --- /dev/null +++ b/crates/testbed/holes/starlette.json @@ -0,0 +1 @@ +[{"cursor":{"line":66,"character":12},"file":"starlette/schemas.py"},{"cursor":{"line":1,"character":9},"file":"starlette/status.py"},{"cursor":{"line":52,"character":8},"file":"starlette/middleware/sessions.py"},{"cursor":{"line":106,"character":13},"file":"starlette/formparsers.py"},{"cursor":{"line":19,"character":4},"file":"starlette/config.py"},{"cursor":{"line":38,"character":4},"file":"starlette/_utils.py"},{"cursor":{"line":16,"character":12},"file":"starlette/formparsers.py"},{"cursor":{"line":6,"character":11},"file":"starlette/middleware/__init__.py"},{"cursor":{"line":7,"character":0},"file":"starlette/convertors.py"},{"cursor":{"line":73,"character":10},"file":"starlette/middleware/sessions.py"},{"cursor":{"line":221,"character":1},"file":"starlette/datastructures.py"},{"cursor":{"line":37,"character":6},"file":"starlette/middleware/authentication.py"},{"cursor":{"line":44,"character":3},"file":"starlette/websockets.py"},{"cursor":{"line":12,"character":8},"file":"starlette/middleware/gzip.py"},{"cursor":{"line":4,"character":8},"file":"starlette/convertors.py"},{"cursor":{"line":222,"character":1},"file":"starlette/middleware/errors.py"},{"cursor":{"line":272,"character":6},"file":"starlette/responses.py"},{"cursor":{"line":0,"character":0},"file":"starlette/__init__.py"},{"cursor":{"line":24,"character":10},"file":"starlette/middleware/exceptions.py"},{"cursor":{"line":21,"character":8},"file":"starlette/middleware/authentication.py"},{"cursor":{"line":35,"character":14},"file":"starlette/middleware/gzip.py"},{"cursor":{"line":19,"character":1},"file":"starlette/formparsers.py"},{"cursor":{"line":49,"character":10},"file":"starlette/exceptions.py"},{"cursor":{"line":70,"character":9},"file":"starlette/applications.py"},{"cursor":{"line":154,"character":0},"file":"starlette/authentication.py"},{"cursor":{"line":168,"character":8},"file":"starlette/applications.py"},{"cursor":{"line":196,"character":9},"file":"starlette/requests.py"},{"cursor":{"line":5,"character":7},"file":"starlette/_exception_handler.py"},{"cursor":{"line":94,"character":9},"file":"starlette/middleware/wsgi.py"},{"cursor":{"line":25,"character":8},"file":"starlette/exceptions.py"},{"cursor":{"line":206,"character":3},"file":"starlette/middleware/base.py"},{"cursor":{"line":43,"character":6},"file":"starlette/middleware/trustedhost.py"},{"cursor":{"line":329,"character":0},"file":"starlette/responses.py"},{"cursor":{"line":73,"character":5},"file":"starlette/staticfiles.py"},{"cursor":{"line":65,"character":5},"file":"starlette/middleware/errors.py"},{"cursor":{"line":44,"character":14},"file":"starlette/datastructures.py"},{"cursor":{"line":26,"character":5},"file":"starlette/background.py"},{"cursor":{"line":274,"character":2},"file":"starlette/requests.py"},{"cursor":{"line":5,"character":4},"file":"starlette/middleware/exceptions.py"},{"cursor":{"line":140,"character":5},"file":"starlette/staticfiles.py"},{"cursor":{"line":0,"character":7},"file":"starlette/__init__.py"},{"cursor":{"line":15,"character":1},"file":"starlette/background.py"},{"cursor":{"line":384,"character":8},"file":"starlette/datastructures.py"},{"cursor":{"line":21,"character":13},"file":"starlette/middleware/trustedhost.py"},{"cursor":{"line":0,"character":6},"file":"starlette/config.py"},{"cursor":{"line":51,"character":1},"file":"starlette/middleware/authentication.py"},{"cursor":{"line":30,"character":10},"file":"starlette/middleware/exceptions.py"},{"cursor":{"line":258,"character":11},"file":"starlette/requests.py"},{"cursor":{"line":186,"character":2},"file":"starlette/applications.py"},{"cursor":{"line":164,"character":7},"file":"starlette/datastructures.py"},{"cursor":{"line":10,"character":14},"file":"starlette/middleware/__init__.py"},{"cursor":{"line":185,"character":8},"file":"starlette/websockets.py"},{"cursor":{"line":100,"character":11},"file":"starlette/templating.py"},{"cursor":{"line":24,"character":9},"file":"starlette/_compat.py"},{"cursor":{"line":290,"character":1},"file":"starlette/datastructures.py"},{"cursor":{"line":137,"character":13},"file":"starlette/websockets.py"},{"cursor":{"line":130,"character":13},"file":"starlette/middleware/wsgi.py"},{"cursor":{"line":812,"character":14},"file":"starlette/routing.py"},{"cursor":{"line":0,"character":1},"file":"starlette/middleware/httpsredirect.py"},{"cursor":{"line":32,"character":13},"file":"starlette/endpoints.py"},{"cursor":{"line":34,"character":13},"file":"starlette/_utils.py"},{"cursor":{"line":114,"character":8},"file":"starlette/endpoints.py"},{"cursor":{"line":60,"character":3},"file":"starlette/formparsers.py"},{"cursor":{"line":135,"character":6},"file":"starlette/middleware/base.py"},{"cursor":{"line":121,"character":6},"file":"starlette/schemas.py"},{"cursor":{"line":100,"character":2},"file":"starlette/templating.py"},{"cursor":{"line":32,"character":1},"file":"starlette/middleware/exceptions.py"},{"cursor":{"line":217,"character":10},"file":"starlette/requests.py"},{"cursor":{"line":136,"character":7},"file":"starlette/websockets.py"},{"cursor":{"line":28,"character":12},"file":"starlette/middleware/authentication.py"},{"cursor":{"line":1,"character":0},"file":"starlette/exceptions.py"},{"cursor":{"line":53,"character":10},"file":"starlette/routing.py"},{"cursor":{"line":356,"character":0},"file":"starlette/testclient.py"},{"cursor":{"line":69,"character":4},"file":"starlette/templating.py"},{"cursor":{"line":25,"character":2},"file":"starlette/status.py"},{"cursor":{"line":204,"character":4},"file":"starlette/middleware/errors.py"},{"cursor":{"line":13,"character":11},"file":"starlette/middleware/httpsredirect.py"},{"cursor":{"line":84,"character":9},"file":"starlette/middleware/wsgi.py"},{"cursor":{"line":0,"character":3},"file":"starlette/datastructures.py"},{"cursor":{"line":53,"character":4},"file":"starlette/middleware/trustedhost.py"},{"cursor":{"line":76,"character":10},"file":"starlette/middleware/wsgi.py"},{"cursor":{"line":15,"character":6},"file":"starlette/middleware/httpsredirect.py"},{"cursor":{"line":27,"character":3},"file":"starlette/_exception_handler.py"},{"cursor":{"line":6,"character":8},"file":"starlette/middleware/httpsredirect.py"},{"cursor":{"line":26,"character":13},"file":"starlette/types.py"},{"cursor":{"line":37,"character":2},"file":"starlette/middleware/gzip.py"},{"cursor":{"line":336,"character":6},"file":"starlette/responses.py"},{"cursor":{"line":34,"character":3},"file":"starlette/background.py"},{"cursor":{"line":32,"character":13},"file":"starlette/middleware/trustedhost.py"},{"cursor":{"line":63,"character":2},"file":"starlette/middleware/errors.py"},{"cursor":{"line":203,"character":6},"file":"starlette/responses.py"},{"cursor":{"line":120,"character":3},"file":"starlette/testclient.py"},{"cursor":{"line":22,"character":1},"file":"starlette/middleware/wsgi.py"},{"cursor":{"line":52,"character":1},"file":"starlette/middleware/trustedhost.py"},{"cursor":{"line":31,"character":0},"file":"starlette/middleware/errors.py"},{"cursor":{"line":56,"character":6},"file":"starlette/concurrency.py"},{"cursor":{"line":55,"character":2},"file":"starlette/middleware/cors.py"},{"cursor":{"line":80,"character":12},"file":"starlette/staticfiles.py"},{"cursor":{"line":24,"character":6},"file":"starlette/middleware/exceptions.py"},{"cursor":{"line":46,"character":13},"file":"starlette/exceptions.py"}] \ No newline at end of file diff --git a/crates/testbed/holes/zod-smol.json b/crates/testbed/holes/zod-smol.json new file mode 100644 index 0000000..13b8472 --- /dev/null +++ b/crates/testbed/holes/zod-smol.json @@ -0,0 +1 @@ +[{"cursor":{"line":165,"character":10},"file":"src/helpers/util.ts"},{"cursor":{"line":147,"character":7},"file":"src/ZodError.ts"},{"cursor":{"line":0,"character":14},"file":"src/ZodError.ts"},{"cursor":{"line":166,"character":9},"file":"src/helpers/util.ts"},{"cursor":{"line":5,"character":5},"file":"src/helpers/enumUtil.ts"},{"cursor":{"line":10,"character":2},"file":"src/errors.ts"},{"cursor":{"line":134,"character":12},"file":"src/benchmarks/primitives.ts"},{"cursor":{"line":2,"character":10},"file":"src/benchmarks/index.ts"},{"cursor":{"line":33,"character":5},"file":"src/benchmarks/realworld.ts"},{"cursor":{"line":12,"character":13},"file":"src/benchmarks/index.ts"}] \ No newline at end of file diff --git a/crates/testbed/holes/zod.json b/crates/testbed/holes/zod.json new file mode 100644 index 0000000..8efa3c1 --- /dev/null +++ b/crates/testbed/holes/zod.json @@ -0,0 +1 @@ +[{"cursor":{"line":46,"character":14},"file":"src/helpers/partialUtil.ts"},{"cursor":{"line":10,"character":3},"file":"src/benchmarks/object.ts"},{"cursor":{"line":5,"character":3},"file":"src/helpers/typeAliases.ts"},{"cursor":{"line":1332,"character":10},"file":"src/types.ts"},{"cursor":{"line":3,"character":10},"file":"src/index.ts"},{"cursor":{"line":26,"character":1},"file":"src/benchmarks/string.ts"},{"cursor":{"line":8,"character":1},"file":"src/errors.ts"},{"cursor":{"line":60,"character":2},"file":"src/benchmarks/realworld.ts"},{"cursor":{"line":124,"character":10},"file":"src/helpers/util.ts"},{"cursor":{"line":30,"character":3},"file":"src/benchmarks/index.ts"},{"cursor":{"line":4,"character":14},"file":"src/benchmarks/string.ts"},{"cursor":{"line":1,"character":11},"file":"src/errors.ts"},{"cursor":{"line":27,"character":8},"file":"src/benchmarks/object.ts"},{"cursor":{"line":107,"character":0},"file":"src/benchmarks/primitives.ts"},{"cursor":{"line":30,"character":2},"file":"src/benchmarks/index.ts"},{"cursor":{"line":226,"character":0},"file":"src/ZodError.ts"},{"cursor":{"line":4,"character":9},"file":"src/external.ts"},{"cursor":{"line":2,"character":1},"file":"src/external.ts"},{"cursor":{"line":25,"character":3},"file":"src/benchmarks/discriminatedUnion.ts"},{"cursor":{"line":104,"character":8},"file":"src/benchmarks/primitives.ts"},{"cursor":{"line":4,"character":1},"file":"src/helpers/errorUtil.ts"},{"cursor":{"line":53,"character":14},"file":"src/helpers/partialUtil.ts"},{"cursor":{"line":4,"character":3},"file":"src/helpers/errorUtil.ts"},{"cursor":{"line":2,"character":11},"file":"src/index.ts"},{"cursor":{"line":2,"character":5},"file":"src/helpers/util.ts"},{"cursor":{"line":0,"character":8},"file":"src/errors.ts"},{"cursor":{"line":41,"character":2},"file":"src/benchmarks/discriminatedUnion.ts"},{"cursor":{"line":17,"character":7},"file":"src/helpers/enumUtil.ts"},{"cursor":{"line":1,"character":10},"file":"src/helpers/enumUtil.ts"},{"cursor":{"line":89,"character":3},"file":"src/helpers/parseUtil.ts"},{"cursor":{"line":9,"character":7},"file":"src/helpers/enumUtil.ts"},{"cursor":{"line":50,"character":1},"file":"src/benchmarks/realworld.ts"},{"cursor":{"line":2,"character":5},"file":"src/index.ts"},{"cursor":{"line":40,"character":13},"file":"src/benchmarks/realworld.ts"},{"cursor":{"line":196,"character":3},"file":"src/ZodError.ts"},{"cursor":{"line":3,"character":2},"file":"src/index.ts"},{"cursor":{"line":4,"character":14},"file":"src/benchmarks/index.ts"},{"cursor":{"line":5,"character":7},"file":"src/helpers/typeAliases.ts"},{"cursor":{"line":3,"character":12},"file":"src/helpers/errorUtil.ts"},{"cursor":{"line":2,"character":5},"file":"src/index.ts"},{"cursor":{"line":68,"character":2},"file":"src/benchmarks/object.ts"},{"cursor":{"line":1,"character":5},"file":"src/helpers/typeAliases.ts"},{"cursor":{"line":41,"character":4},"file":"src/benchmarks/object.ts"},{"cursor":{"line":15,"character":12},"file":"src/helpers/enumUtil.ts"},{"cursor":{"line":5,"character":6},"file":"src/helpers/partialUtil.ts"},{"cursor":{"line":27,"character":7},"file":"src/ZodError.ts"},{"cursor":{"line":8,"character":9},"file":"src/helpers/typeAliases.ts"},{"cursor":{"line":66,"character":5},"file":"src/locales/en.ts"},{"cursor":{"line":15,"character":12},"file":"src/benchmarks/object.ts"},{"cursor":{"line":29,"character":12},"file":"src/helpers/parseUtil.ts"},{"cursor":{"line":159,"character":2},"file":"src/ZodError.ts"},{"cursor":{"line":49,"character":2},"file":"src/benchmarks/primitives.ts"},{"cursor":{"line":7,"character":4},"file":"src/helpers/typeAliases.ts"},{"cursor":{"line":1727,"character":3},"file":"src/types.ts"},{"cursor":{"line":3,"character":1},"file":"src/external.ts"},{"cursor":{"line":33,"character":1},"file":"src/benchmarks/realworld.ts"},{"cursor":{"line":3,"character":9},"file":"src/index.ts"},{"cursor":{"line":9,"character":7},"file":"src/helpers/enumUtil.ts"},{"cursor":{"line":287,"character":12},"file":"src/ZodError.ts"},{"cursor":{"line":3,"character":9},"file":"src/helpers/typeAliases.ts"},{"cursor":{"line":4,"character":2},"file":"src/benchmarks/discriminatedUnion.ts"},{"cursor":{"line":141,"character":7},"file":"src/helpers/parseUtil.ts"},{"cursor":{"line":25,"character":2},"file":"src/benchmarks/index.ts"},{"cursor":{"line":23,"character":8},"file":"src/benchmarks/string.ts"},{"cursor":{"line":44,"character":1},"file":"src/benchmarks/realworld.ts"},{"cursor":{"line":41,"character":2},"file":"src/benchmarks/union.ts"},{"cursor":{"line":152,"character":2},"file":"src/helpers/util.ts"},{"cursor":{"line":4,"character":13},"file":"src/errors.ts"},{"cursor":{"line":300,"character":0},"file":"src/ZodError.ts"},{"cursor":{"line":4,"character":6},"file":"src/helpers/typeAliases.ts"},{"cursor":{"line":76,"character":0},"file":"src/helpers/parseUtil.ts"},{"cursor":{"line":123,"character":4},"file":"src/benchmarks/primitives.ts"},{"cursor":{"line":52,"character":7},"file":"src/benchmarks/union.ts"},{"cursor":{"line":4,"character":9},"file":"src/external.ts"},{"cursor":{"line":140,"character":9},"file":"src/helpers/parseUtil.ts"},{"cursor":{"line":5,"character":4},"file":"src/helpers/errorUtil.ts"},{"cursor":{"line":3845,"character":3},"file":"src/types.ts"},{"cursor":{"line":6,"character":3},"file":"src/errors.ts"},{"cursor":{"line":2,"character":6},"file":"src/helpers/typeAliases.ts"},{"cursor":{"line":1,"character":11},"file":"src/external.ts"},{"cursor":{"line":10,"character":1},"file":"src/errors.ts"},{"cursor":{"line":0,"character":3},"file":"src/index.ts"},{"cursor":{"line":0,"character":14},"file":"src/index.ts"},{"cursor":{"line":9,"character":14},"file":"src/benchmarks/object.ts"},{"cursor":{"line":3,"character":11},"file":"src/index.ts"},{"cursor":{"line":2,"character":2},"file":"src/benchmarks/object.ts"},{"cursor":{"line":14,"character":7},"file":"src/benchmarks/primitives.ts"},{"cursor":{"line":3,"character":8},"file":"src/index.ts"},{"cursor":{"line":3,"character":13},"file":"src/index.ts"},{"cursor":{"line":38,"character":7},"file":"src/locales/en.ts"},{"cursor":{"line":4,"character":8},"file":"src/benchmarks/string.ts"},{"cursor":{"line":3,"character":6},"file":"src/external.ts"},{"cursor":{"line":135,"character":4},"file":"src/ZodError.ts"},{"cursor":{"line":2,"character":6},"file":"src/benchmarks/union.ts"},{"cursor":{"line":48,"character":9},"file":"src/locales/en.ts"},{"cursor":{"line":0,"character":11},"file":"src/helpers/errorUtil.ts"},{"cursor":{"line":17,"character":8},"file":"src/benchmarks/primitives.ts"},{"cursor":{"line":15,"character":3},"file":"src/helpers/parseUtil.ts"},{"cursor":{"line":1,"character":10},"file":"src/index.ts"},{"cursor":{"line":124,"character":1},"file":"src/locales/en.ts"}] \ No newline at end of file diff --git a/crates/testbed/repositories-ci.yaml b/crates/testbed/repositories-ci.yaml new file mode 100644 index 0000000..7540ddb --- /dev/null +++ b/crates/testbed/repositories-ci.yaml @@ -0,0 +1,247 @@ +--- +context_window: 2000 +fim: + enabled: true + prefix: + middle: + suffix: +model: bigcode/starcoder +request_params: + max_new_tokens: 150 + temperature: 0.2 + do_sample: true + top_p: 0.95 +tls_skip_verify_insecure: false +tokenizer_config: + repository: bigcode/starcoder +tokens_to_clear: ["<|endoftext|>"] +repositories: + - source: + type: local + path: simple + src_path: src + build_command: cargo + build_args: ["build"] + language: rust + runner: cargo + holes_file: simple.json + - source: + type: github + owner: mmaitre314 + name: picklescan + revision: 40001cd1caa9e041b1bce1b80f3707056cd8be52 + src_path: src/picklescan + build_command: picklescan-venv/bin/python3 + build_args: ["-m", "compileall", "-q", "."] + language: python + runner: pytest + runner_command: picklescan-venv/bin/python3 + setup_commands: + - ["python3", ["-m", "venv", "picklescan-venv"]] + - ["picklescan-venv/bin/python3", ["-m", "pip", "install", "."]] + - ["picklescan-venv/bin/python3", ["-m", "pip", "install", "-r", "requirements.txt"]] + holes_file: picklescan-smol.json + - source: + type: github + owner: huggingface + name: huggingface_hub + revision: a48eb89d4186bc84bca67b117cf29a0ee0b69774 + src_path: src/huggingface_hub + build_command: huggingface_hub-venv/bin/python3 + build_args: ["-m", "compileall", "-q", "."] + language: python + runner: pytest + runner_command: huggingface_hub-venv/bin/python3 + runner_extra_args: + - "-k" + - "_utils_ and not _utils_cache and not _utils_http and not paginate and not git" + setup_commands: + - ["python3", ["-m", "venv", "huggingface_hub-venv"]] + - ["huggingface_hub-venv/bin/python3", ["-m", "pip", "install", ".[dev]"]] + holes_file: huggingface_hub-smol.json + - source: + type: github + owner: tiangolo + name: fastapi + revision: e4b21c6eab7cd58caf3c6c492ea1ce7945425dd1 + src_path: fastapi + build_command: fastapi-venv/bin/python3 + build_args: ["-m", "compileall", "-q", "."] + language: python + runner: pytest + runner_command: fastapi-venv/bin/python3 + setup_commands: + - ["python3", ["-m", "venv", "fastapi-venv"]] + - ["fastapi-venv/bin/python3", ["-m", "pip", "install", "--upgrade", "pip"]] + - ["fastapi-venv/bin/python3", ["-m", "pip", "install", "-r", "requirements-tests.txt"]] + - ["fastapi-venv/bin/python3", ["-m", "pip", "install", "pydantic"]] + holes_file: fastapi-smol.json + - source: + type: github + owner: encode + name: starlette + revision: 657e7e7b728e13dc66cc3f77dffd00a42545e171 + src_path: starlette + build_command: starlette-venv/bin/python3 + build_args: ["-m", "compileall", "-q", "."] + language: python + runner: pytest + runner_command: starlette-venv/bin/python3 + setup_commands: + - ["python3", ["-m", "venv", "starlette-venv"]] + - ["starlette-venv/bin/python3", ["-m", "pip", "install", "--upgrade", "pip"]] + - ["starlette-venv/bin/python3", ["-m", "pip", "install", "-r", "requirements.txt"]] + holes_file: starlette-smol.json + - source: + type: github + owner: lancedb + name: lancedb + revision: 682e95fa8388d5839c8a782063beb307c4fca4bc + src_path: rust/vectordb/src + build_command: cargo + build_args: ["build"] + language: rust + runner: cargo + # this is to avoid skewing the average hole completion time + setup_commands: + - ["cargo", ["build"]] + holes_file: lancedb-smol.json + - source: + type: github + owner: lancedb + name: lance + revision: c8ee16ec31eeca884c78bd4a400404aaa994ed46 + src_path: rust + exclude_paths: + - .cargo + - .vscode + - .gitignore + - README.md + - img.png + build_command: cargo + build_args: ["build", "--all-features", "--manifest-path", "rust/Cargo.toml"] + language: rust + runner: cargo + runner_extra_args: ["--all-features", "--manifest-path", "rust/Cargo.toml"] + setup_commands: + - ["rm", ["rust/lance-core/protos", "rust/lance-index/protos"]] + - ["ln", ["-s", "../../protos", "rust/lance-core/protos"]] + - ["ln", ["-s", "../../protos", "rust/lance-index/protos"]] + - ["cargo", ["build", "--all-features", "--manifest-path", "rust/Cargo.toml"]] + holes_file: lance-smol.json + - source: + type: github + owner: tkaitchuck + name: constrandom + revision: e9f560ba14e09ff9db9caca3f2dfa3ff52cc96de + src_path: src + build_command: cargo + build_args: ["build"] + language: rust + runner: cargo + setup_commands: + - ["cargo", ["build"]] + holes_file: constrandom-smol.json + - source: + type: github + owner: jaemk + name: cached + revision: b1015561fb121c3e5698183c39df202e5a83994a + src_path: src + build_command: cargo + build_args: ["build"] + language: rust + runner: cargo + setup_commands: + - ["cargo", ["build"]] + holes_file: cached-smol.json + - source: + type: github + owner: smol-rs + name: async-executor + revision: b91875e73bd9aec582e099d8c792514381fc8d0f + src_path: src + build_command: cargo + build_args: ["build"] + language: rust + runner: cargo + setup_commands: + - ["cargo", ["build"]] + holes_file: async-executor-smol.json + - source: + type: github + owner: gcanti + name: io-ts + revision: 616583de0198632cad7820ed8701b15f654c7fd2 + src_path: src + build_command: npm + build_args: ["run", "build"] + language: typescript + runner: vitest + setup_commands: + - ["npm", ["install"]] + holes_file: io-ts-smol.json + - source: + type: github + owner: colinhacks + name: zod + revision: 481c9ba1932203777f6fe9497bb2a8a1d33c620e + src_path: src + exclude_paths: ["src/__tests__"] + build_command: yarn + build_args: ["build"] + language: typescript + runner: jest + runner_command: yarn + runner_args: ["test", "--", "--no-colors"] + setup_commands: + - ["yarn", ["install"]] + holes_file: zod-smol.json + - source: + type: github + owner: helix-editor + name: helix + revision: ae6a0a9cfd377fbfa494760282498cf2ca322782 + exclude_paths: + - .cargo + - .github + - book + - contrib + - docs + - helix-core/tests + - helix-term/tests + - helix-tui/tests + - helix-view/tests + - runtime + - xtask + - .envrc + - .gitattributes + - .gitignore + - .ignore + - CHANGELOG.md + - Cargo.lock + - LICENSE + - README.md + - VERSION + - base16_theme.toml + - default.nix + - flake.lock + - flake.nix + - grammars.nix + - languages.toml + - logo.svg + - logo_dark.svg + - logo_light.svg + - rust-toolchain.toml + - rustfmt.toml + - screenshot.png + - shell.nix + - theme.toml + build_command: cargo + build_args: ["build"] + language: rust + runner: cargo + runner_extra_args: ["--workspace"] + setup_commands: + - ["cargo", ["build"]] + holes_file: helix-smol.json diff --git a/crates/testbed/repositories.yaml b/crates/testbed/repositories.yaml new file mode 100644 index 0000000..4ea242d --- /dev/null +++ b/crates/testbed/repositories.yaml @@ -0,0 +1,247 @@ +--- +context_window: 2000 +fim: + enabled: true + prefix: + middle: + suffix: +model: bigcode/starcoder +request_params: + max_new_tokens: 150 + temperature: 0.2 + do_sample: true + top_p: 0.95 +tls_skip_verify_insecure: false +tokenizer_config: + repository: bigcode/starcoder +tokens_to_clear: ["<|endoftext|>"] +repositories: + - source: + type: local + path: simple + src_path: src + build_command: cargo + build_args: ["build"] + language: rust + runner: cargo + holes_file: simple.json + - source: + type: github + owner: mmaitre314 + name: picklescan + revision: 40001cd1caa9e041b1bce1b80f3707056cd8be52 + src_path: src/picklescan + build_command: picklescan-venv/bin/python3 + build_args: ["-m", "compileall", "-q", "."] + language: python + runner: pytest + runner_command: picklescan-venv/bin/python3 + setup_commands: + - ["python3", ["-m", "venv", "picklescan-venv"]] + - ["picklescan-venv/bin/python3", ["-m", "pip", "install", "."]] + - ["picklescan-venv/bin/python3", ["-m", "pip", "install", "-r", "requirements.txt"]] + holes_file: picklescan.json + - source: + type: github + owner: huggingface + name: huggingface_hub + revision: a48eb89d4186bc84bca67b117cf29a0ee0b69774 + src_path: src/huggingface_hub + build_command: huggingface_hub-venv/bin/python3 + build_args: ["-m", "compileall", "-q", "."] + language: python + runner: pytest + runner_command: huggingface_hub-venv/bin/python3 + runner_extra_args: + - "-k" + - "_utils_ and not _utils_cache and not _utils_http and not paginate and not git" + setup_commands: + - ["python3", ["-m", "venv", "huggingface_hub-venv"]] + - ["huggingface_hub-venv/bin/python3", ["-m", "pip", "install", ".[dev]"]] + holes_file: huggingface_hub.json + - source: + type: github + owner: tiangolo + name: fastapi + revision: e4b21c6eab7cd58caf3c6c492ea1ce7945425dd1 + src_path: fastapi + build_command: fastapi-venv/bin/python3 + build_args: ["-m", "compileall", "-q", "."] + language: python + runner: pytest + runner_command: fastapi-venv/bin/python3 + setup_commands: + - ["python3", ["-m", "venv", "fastapi-venv"]] + - ["fastapi-venv/bin/python3", ["-m", "pip", "install", "--upgrade", "pip"]] + - ["fastapi-venv/bin/python3", ["-m", "pip", "install", "-r", "requirements-tests.txt"]] + - ["fastapi-venv/bin/python3", ["-m", "pip", "install", "pydantic"]] + holes_file: fastapi.json + - source: + type: github + owner: encode + name: starlette + revision: 657e7e7b728e13dc66cc3f77dffd00a42545e171 + src_path: starlette + build_command: starlette-venv/bin/python3 + build_args: ["-m", "compileall", "-q", "."] + language: python + runner: pytest + runner_command: starlette-venv/bin/python3 + setup_commands: + - ["python3", ["-m", "venv", "starlette-venv"]] + - ["starlette-venv/bin/python3", ["-m", "pip", "install", "--upgrade", "pip"]] + - ["starlette-venv/bin/python3", ["-m", "pip", "install", "-r", "requirements.txt"]] + holes_file: starlette.json + - source: + type: github + owner: lancedb + name: lancedb + revision: 682e95fa8388d5839c8a782063beb307c4fca4bc + src_path: rust/vectordb/src + build_command: cargo + build_args: ["build"] + language: rust + runner: cargo + # this is to avoid skewing the average hole completion time + setup_commands: + - ["cargo", ["build"]] + holes_file: lancedb.json + - source: + type: github + owner: lancedb + name: lance + revision: 4f7fb490c6b36a659b2c40b3945b4d533356acf2 + src_path: rust + exclude_paths: + - .cargo + - .vscode + - .gitignore + - README.md + - img.png + build_command: cargo + build_args: ["build", "--all-features", "--manifest-path", "rust/Cargo.toml"] + language: rust + runner: cargo + runner_extra_args: ["--all-features", "--manifest-path", "rust/Cargo.toml"] + setup_commands: + - ["rm", ["rust/lance-core/protos", "rust/lance-index/protos"]] + - ["ln", ["-s", "../../protos", "rust/lance-core/protos"]] + - ["ln", ["-s", "../../protos", "rust/lance-index/protos"]] + - ["cargo", ["build", "--all-features", "--manifest-path", "rust/Cargo.toml"]] + holes_file: lance.json + - source: + type: github + owner: tkaitchuck + name: constrandom + revision: e9f560ba14e09ff9db9caca3f2dfa3ff52cc96de + src_path: src + build_command: cargo + build_args: ["build"] + language: rust + runner: cargo + setup_commands: + - ["cargo", ["build"]] + holes_file: constrandom.json + - source: + type: github + owner: jaemk + name: cached + revision: b1015561fb121c3e5698183c39df202e5a83994a + src_path: src + build_command: cargo + build_args: ["build"] + language: rust + runner: cargo + setup_commands: + - ["cargo", ["build"]] + holes_file: cached.json + - source: + type: github + owner: smol-rs + name: async-executor + revision: b91875e73bd9aec582e099d8c792514381fc8d0f + src_path: src + build_command: cargo + build_args: ["build"] + language: rust + runner: cargo + setup_commands: + - ["cargo", ["build"]] + holes_file: async-executor.json + - source: + type: github + owner: gcanti + name: io-ts + revision: 616583de0198632cad7820ed8701b15f654c7fd2 + src_path: src + build_command: npm + build_args: ["run", "build"] + language: typescript + runner: vitest + setup_commands: + - ["npm", ["install"]] + holes_file: io-ts.json + - source: + type: github + owner: colinhacks + name: zod + revision: 481c9ba1932203777f6fe9497bb2a8a1d33c620e + src_path: src + exclude_paths: ["src/__tests__"] + build_command: yarn + build_args: ["build"] + language: typescript + runner: jest + runner_command: yarn + runner_args: ["test", "--", "--no-colors"] + setup_commands: + - ["yarn", ["install"]] + holes_file: zod.json + - source: + type: github + owner: helix-editor + name: helix + revision: ae6a0a9cfd377fbfa494760282498cf2ca322782 + exclude_paths: + - .cargo + - .github + - book + - contrib + - docs + - helix-core/tests + - helix-term/tests + - helix-tui/tests + - helix-view/tests + - runtime + - xtask + - .envrc + - .gitattributes + - .gitignore + - .ignore + - CHANGELOG.md + - Cargo.lock + - LICENSE + - README.md + - VERSION + - base16_theme.toml + - default.nix + - flake.lock + - flake.nix + - grammars.nix + - languages.toml + - logo.svg + - logo_dark.svg + - logo_light.svg + - rust-toolchain.toml + - rustfmt.toml + - screenshot.png + - shell.nix + - theme.toml + build_command: cargo + build_args: ["build"] + language: rust + runner: cargo + runner_extra_args: ["--workspace"] + setup_commands: + - ["cargo", ["build"]] + holes_file: helix.json diff --git a/crates/testbed/repositories/simple/Cargo.lock b/crates/testbed/repositories/simple/Cargo.lock new file mode 100644 index 0000000..05a9e70 --- /dev/null +++ b/crates/testbed/repositories/simple/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "simple" +version = "0.1.0" diff --git a/crates/testbed/repositories/simple/Cargo.toml b/crates/testbed/repositories/simple/Cargo.toml new file mode 100644 index 0000000..0c1b9cb --- /dev/null +++ b/crates/testbed/repositories/simple/Cargo.toml @@ -0,0 +1,10 @@ +[workspace] + +[package] +name = "simple" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/crates/testbed/repositories/simple/src/main.rs b/crates/testbed/repositories/simple/src/main.rs new file mode 100644 index 0000000..104ded2 --- /dev/null +++ b/crates/testbed/repositories/simple/src/main.rs @@ -0,0 +1,46 @@ +fn sum(lhs: i32, rhs: i32) -> i32 { + lhs + rhs +} + +fn sub(lhs: i32, rhs: i32) -> i32 { + lhs - rhs +} + +fn mul(lhs: i32, rhs: i32) -> i32 { + lhs * rhs +} + +fn div(lhs: i32, rhs: i32) -> i32 { + lhs / rhs +} + +fn main() { + println!("42 + 42 = {}", sum(42, 42)); + println!("41 - 42 = {}", sub(41, 42)); + println!("42 * 42 = {}", mul(42, 42)); + println!("42 / 42 = {}", div(42, 42)); +} + +#[cfg(test)] +mod tests { + #[test] + fn test_sum() { + assert_eq!(42 + 42, super::sum(42, 42)); + } + + #[test] + fn test_sub() { + assert_eq!(42 - 42, super::sub(42, 42)); + assert_eq!(41 - 42, super::sub(41, 42)); + } + + #[test] + fn test_mul() { + assert_eq!(42 * 42, super::mul(42, 42)); + } + + #[test] + fn test_div() { + assert_eq!(42 / 42, super::div(42, 42)); + } +} diff --git a/crates/testbed/src/holes_generator.rs b/crates/testbed/src/holes_generator.rs new file mode 100644 index 0000000..5fd8c23 --- /dev/null +++ b/crates/testbed/src/holes_generator.rs @@ -0,0 +1,113 @@ +use std::{ + collections::VecDeque, + path::{Path, PathBuf}, +}; + +use anyhow::anyhow; +use rand::{seq::SliceRandom, Rng}; +use ropey::Rope; +use tokio::{ + fs::{self, OpenOptions}, + io::{AsyncReadExt, AsyncWriteExt}, +}; +use tracing::info; + +use crate::{setup_repo_dir, Hole, RepositoriesConfig}; + +async fn file_is_empty(file_path: impl AsRef) -> anyhow::Result { + let mut content = String::new(); + fs::File::open(&file_path) + .await? + .read_to_string(&mut content) + .await?; + Ok(content.trim().is_empty()) +} + +pub(crate) async fn generate_holes( + repositories_config: RepositoriesConfig, + repos_dir_path: &Path, + holes_dir_path: &Path, + holes_per_repo: usize, + filter_repos: bool, + filter_list: Vec, +) -> anyhow::Result<()> { + let mut rng = rand::thread_rng(); + for repo in repositories_config.repositories { + if filter_repos && !filter_list.contains(&repo.name()) { + continue; + } + let repo_name = repo.name(); + info!("creating {} holes for {}", holes_per_repo, repo_name); + let (_tmp_dir, path) = setup_repo_dir(repos_dir_path, &repo.source).await?; + let mut files = vec![]; + + let mut stack = VecDeque::new(); + let exclude_paths = repo + .source + .exclude_paths() + .iter() + .map(|p| path.join(p)) + .collect::>(); + stack.push_back(path.join(repo.source.src_path())); + while let Some(src) = stack.pop_back() { + let mut entries = fs::read_dir(&src).await?; + while let Some(entry) = entries.next_entry().await? { + let entry_type = entry.file_type().await?; + + let src_path = entry.path(); + if exclude_paths.iter().any(|p| src_path.starts_with(p)) { + continue; + } + + if entry_type.is_dir() { + stack.push_back(src_path); + } else if entry_type.is_file() + && repo + .language + .is_code_file(src_path.file_name().unwrap().to_str().unwrap()) + && !file_is_empty(&src_path).await? + { + files.push(src_path); + } + } + } + + let mut holes = vec![]; + let mut i = 0; + while i < holes_per_repo { + let file_path = files + .choose(&mut rng) + .ok_or(anyhow!("files vec is empty"))?; + let mut content = String::new(); + fs::File::open(&file_path) + .await? + .read_to_string(&mut content) + .await?; + let rope = Rope::from_str(&content); + let line_nb = rng.gen_range(0..rope.len_lines()); + let line = rope.line(line_nb); + let line_string = line.to_string(); + let trimmed = line_string.trim(); + if trimmed.starts_with(repo.language.comment_token()) || trimmed.is_empty() { + continue; + } + let column_nb = rng.gen_range(0..15.min(line.len_chars())); + holes.push(Hole::new( + line_nb as u32, + column_nb as u32, + file_path.strip_prefix(&path)?.to_str().unwrap().to_owned(), + )); + i += 1; + } + let mut file = OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open(&holes_dir_path.join(repo.holes_file)) + .await?; + file.write_all(serde_json::to_string(&holes)?.as_bytes()) + .await?; + } + + Ok(()) +} diff --git a/crates/testbed/src/lang.rs b/crates/testbed/src/lang.rs new file mode 100644 index 0000000..8acb91a --- /dev/null +++ b/crates/testbed/src/lang.rs @@ -0,0 +1,44 @@ +use std::fmt; + +use serde::{Deserialize, Serialize}; + +// const JS_EXT: [&str; 2] = [".js", ".jsx"]; +const PY_EXT: [&str; 1] = [".py"]; +const RS_EXT: [&str; 1] = [".rs"]; +const TS_EXT: [&str; 3] = [".ts", ".tsx", ".d.ts"]; + +#[derive(Clone, Deserialize, Serialize)] +#[serde(rename_all = "lowercase")] +pub(crate) enum Language { + Python, + Rust, + Typescript, +} + +impl fmt::Display for Language { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Python => write!(f, "python"), + Self::Rust => write!(f, "rust"), + Self::Typescript => write!(f, "typescript"), + } + } +} + +impl Language { + pub(crate) fn is_code_file(&self, file_name: &str) -> bool { + match self { + Self::Python => PY_EXT.iter().any(|ext| file_name.ends_with(ext)), + Self::Rust => RS_EXT.iter().any(|ext| file_name.ends_with(ext)), + Self::Typescript => TS_EXT.iter().any(|ext| file_name.ends_with(ext)), + } + } + + pub(crate) fn comment_token(&self) -> &str { + match self { + Self::Python => "#", + Self::Rust => "//", + Self::Typescript => "//", + } + } +} diff --git a/crates/testbed/src/main.rs b/crates/testbed/src/main.rs new file mode 100644 index 0000000..5266cea --- /dev/null +++ b/crates/testbed/src/main.rs @@ -0,0 +1,717 @@ +use std::{ + collections::{HashMap, VecDeque}, + fmt::Display, + io::BufReader, + path::{Path, PathBuf}, + process::Stdio, + sync::Arc, + time::Instant, +}; + +use anyhow::anyhow; +use clap::Parser; +use futures_util::{stream::FuturesUnordered, StreamExt, TryStreamExt}; +use lang::Language; +use lsp_client::{client::LspClient, msg::RequestId, server::Server}; +use lsp_types::{ + DidOpenTextDocumentParams, InitializeParams, TextDocumentIdentifier, TextDocumentItem, + TextDocumentPositionParams, +}; +use ropey::Rope; +use runner::Runner; +use serde::{Deserialize, Serialize}; +use tempfile::TempDir; +use tokio::{ + fs::{self, read_to_string, File, OpenOptions}, + io::{self, AsyncReadExt, AsyncWriteExt}, + process::Command, + sync::{RwLock, Semaphore}, +}; +use tokio_util::compat::FuturesAsyncReadCompatExt; +use tracing::{debug, error, info, info_span, warn, Instrument}; +use tracing_subscriber::EnvFilter; +use url::Url; + +use crate::{ + holes_generator::generate_holes, + runner::run_test, + types::{ + FimParams, GetCompletions, GetCompletionsParams, GetCompletionsResult, Ide, RequestParams, + TokenizerConfig, + }, +}; + +mod holes_generator; +mod lang; +mod runner; +mod types; + +/// Testbed runs llm-ls' code completion to measure its performance +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// Hugging Face Inference API Token + #[arg(short, long)] + api_token: Option, + + /// Comma separated list of repos in the repositories file to run completions or holes generation for; + /// matches on path for local repos and `owner/name` for github repos + #[arg(short, long)] + filter: Option, + + /// When this is specified, holes files will be generated based on the repositories.yaml file + #[arg(short, long, action)] + generate_holes: bool, + + /// Path to the directory containing the holes files + #[arg(short = 'H', long)] + holes_dir_path: Option, + + /// Number of holes to create per repository + #[arg(short = 'n', long, default_value_t = 100)] + holes_per_repo: usize, + + /// Path to llm-ls' binary + #[arg(short, long)] + llm_ls_bin_path: Option, + + /// Path to the local repositories/ directory + #[arg(short = 'R', long)] + repos_dir_path: Option, + + /// Path to the repositories.yaml file + #[arg(short, long)] + repos_file_path: Option, +} + +#[derive(Clone, Deserialize, Serialize)] +struct LocalRepo { + path: PathBuf, + src_path: String, + #[serde(default)] + exclude_paths: Vec, +} + +#[derive(Clone, Deserialize, Serialize)] +struct GithubRepo { + owner: String, + name: String, + revision: String, + #[serde(default)] + src_path: String, + #[serde(default)] + exclude_paths: Vec, +} + +#[derive(Clone, Deserialize, Serialize)] +#[serde(tag = "type")] +#[serde(rename_all = "lowercase")] +enum RepoSource { + Local(LocalRepo), + Github(GithubRepo), +} + +impl RepoSource { + fn source_type(&self) -> String { + match self { + Self::Local { .. } => "local".to_owned(), + Self::Github { .. } => "github".to_owned(), + } + } + + fn src_path(&self) -> String { + match self { + Self::Local(local) => local.src_path.clone(), + Self::Github(github) => github.src_path.clone(), + } + } + + fn exclude_paths(&self) -> Vec { + match self { + Self::Local(local) => local.exclude_paths.clone(), + Self::Github(github) => github.exclude_paths.clone(), + } + } +} + +#[derive(Clone, Deserialize, Serialize)] +struct Repository { + build_command: String, + build_args: Vec, + env: Option>, + holes_file: String, + language: Language, + runner: Runner, + runner_command: Option, + runner_args: Option>, + #[serde(default)] + runner_extra_args: Vec, + setup_commands: Option)>>, + source: RepoSource, +} + +impl Repository { + /// can panic if local path is not utf8 + fn name(&self) -> String { + match &self.source { + RepoSource::Local(local) => local.path.to_str().unwrap().to_owned(), + RepoSource::Github(github) => format!("{}/{}", github.owner, github.name), + } + } +} + +#[derive(Clone, Deserialize, Serialize)] +struct Hole { + cursor: lsp_types::Position, + /// relative path of a file in the repository + file: String, +} + +impl Hole { + fn new(line: u32, character: u32, file: String) -> Self { + Self { + cursor: lsp_types::Position::new(line, character), + file, + } + } +} + +impl Display for Hole { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{} [{}, {}]", + self.file, self.cursor.line, self.cursor.character + ) + } +} + +// unused for now, consider all holes as lines +// enum HoleType { +// Line, +// Multiline +// } + +#[derive(Clone, Deserialize, Serialize)] +struct RepositoriesConfig { + context_window: usize, + fim: FimParams, + model: String, + request_params: RequestParams, + repositories: Vec, + tls_skip_verify_insecure: bool, + tokenizer_config: Option, + tokens_to_clear: Vec, +} + +struct HoleCompletionResult { + repo_name: String, + repo_source_type: String, + pass_percentage: f32, + completion_time_ms: u128, +} + +impl HoleCompletionResult { + fn new( + repo_name: String, + repo_source_type: String, + pass_percentage: f32, + completion_time_ms: u128, + ) -> Self { + Self { + repo_name, + repo_source_type, + pass_percentage, + completion_time_ms, + } + } +} + +async fn get_api_token(args_token: Option) -> anyhow::Result> { + if args_token.is_some() { + Ok(args_token) + } else { + let home_dir = home::home_dir().ok_or(anyhow!("failed to find home dir"))?; + let cached_token = home_dir.join(".cache/huggingface/token"); + if cached_token.try_exists()? { + let mut token = String::new(); + File::open(cached_token) + .await? + .read_to_string(&mut token) + .await?; + Ok(Some(token.trim().to_owned())) + } else { + Ok(None) + } + } +} + +async fn download_repo_from_github( + temp_dir: &TempDir, + repo: &GithubRepo, +) -> anyhow::Result { + let repo_dir_name = format!("{}-{}", repo.name, repo.revision); + let archive_path = temp_dir.path().join(format!("{}.zip", repo_dir_name)); + let mut archive = File::create(&archive_path).await?; + let stream = reqwest::get(&format!( + "https://github.com/{}/{}/archive/{}.zip", + repo.owner, repo.name, repo.revision, + )) + .await? + .error_for_status()? + .bytes_stream(); + let stream = stream + .map_err(|e| futures::io::Error::new(futures::io::ErrorKind::Other, e)) + .into_async_read(); + let mut stream = stream.compat(); + io::copy(&mut stream, &mut archive).await?; + let archive = BufReader::new(std::fs::File::open(archive_path)?); + zip::ZipArchive::new(archive)?.extract(temp_dir.path())?; + Ok(temp_dir.path().join(repo_dir_name)) +} + +async fn copy_dir_contents(source: &Path, dest: &Path) -> anyhow::Result<()> { + let mut stack = VecDeque::new(); + stack.push_back((source.to_path_buf(), dest.to_path_buf())); + while let Some((src, dst)) = stack.pop_back() { + let mut entries = fs::read_dir(&src).await?; + while let Some(entry) = entries.next_entry().await? { + let entry_type = entry.file_type().await?; + + let src_path = entry.path(); + let dst_path = fs::canonicalize(&dst).await?.join(entry.file_name()); + + if entry_type.is_dir() { + fs::create_dir(&dst_path).await?; + stack.push_back((src_path, dst_path)); + } else if entry_type.is_file() { + fs::copy(&src_path, &dst_path).await?; + } + } + } + + Ok(()) +} + +async fn setup_repo_dir( + repos_dir_path: &Path, + source: &RepoSource, +) -> anyhow::Result<(TempDir, PathBuf)> { + match source { + RepoSource::Local(local) => { + debug!("setting up local repo: {}", local.path.to_str().unwrap()); + let temp_dir = TempDir::new()?; + copy_dir_contents(&repos_dir_path.join(&local.path), temp_dir.path()).await?; + let repo_path = temp_dir.path().to_path_buf(); + Ok((temp_dir, repo_path)) + } + RepoSource::Github(github) => { + debug!("setting repo from github: {}/{}", github.owner, github.name); + let temp_dir = TempDir::new()?; + let repo_path = download_repo_from_github(&temp_dir, github).await?; + Ok((temp_dir, repo_path)) + } + } +} + +fn parse_env(env: &Option>) -> anyhow::Result> { + let mut env_vars = vec![]; + if let Some(env) = env { + for var in env { + env_vars.push( + var.split_once('=') + .map(|(n, v)| (n.to_owned(), v.to_owned())) + .ok_or(anyhow!("failed to split env var {var}"))?, + ); + } + } + Ok(env_vars) +} + +async fn run_setup( + commands: &Vec<(String, Vec)>, + env: &Option>, + repo_path: impl AsRef, +) -> anyhow::Result<()> { + let parsed_env = parse_env(env)?; + for command in commands { + let mut status_cmd = Command::new(&command.0); + for (name, value) in &parsed_env { + status_cmd.env(name, value); + } + debug!("running setup command: {} {:?}", command.0, command.1); + let status = status_cmd + .args(&command.1) + .current_dir(&repo_path) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn()? + .wait() + .await?; + + if !status.success() { + return Err(anyhow!( + "error running: \"{} {}\"", + command.0, + command.1.join(" ") + )); + } + } + Ok(()) +} + +async fn build( + command: &str, + args: &Vec, + env: &Option>, + repo_path: impl AsRef, +) -> anyhow::Result { + let parsed_env = parse_env(env)?; + let mut status_cmd = Command::new(command); + for (name, value) in parsed_env { + status_cmd.env(name, value); + } + debug!("building repo: {command} {args:?}"); + let status = status_cmd + .args(args) + .current_dir(repo_path) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn()? + .wait() + .await?; + Ok(status.success()) +} + +#[allow(clippy::too_many_arguments)] +async fn complete_holes( + repo: Repository, + client: Arc, + file_cache: Arc>>, + holes_dir_path: PathBuf, + repos_dir_path: PathBuf, + repos_config: RepositoriesConfig, + api_token: Option, + semaphore: Arc, +) -> anyhow::Result> { + let permit = semaphore.acquire_owned().await?; + let span = info_span!("complete_hole", repo_name = repo.name()); + async move { + let holes_file_path = holes_dir_path.join(&repo.holes_file); + let mut holes = String::new(); + File::open(holes_file_path) + .await? + .read_to_string(&mut holes) + .await?; + let holes: Vec = serde_json::from_str(&holes)?; + let ten_percent = if holes.len() >= 10 { + holes.len() / 10 + } else { + 1 + }; + info!("running {} hole completions", holes.len()); + let RepositoriesConfig { + context_window, + fim, + model, + request_params, + tls_skip_verify_insecure, + tokenizer_config, + tokens_to_clear, + .. + } = repos_config; + let (_temp_dir, repo_path) = setup_repo_dir(&repos_dir_path, &repo.source).await?; + if let Some(commands) = &repo.setup_commands { + run_setup(commands, &repo.env, &repo_path).await?; + } + let mut hole_completions_result = Vec::with_capacity(holes.len()); + for (idx, hole) in holes.iter().enumerate() { + let hole_instant = Instant::now(); + let file_path = repo_path.join(&hole.file); + let file_path_str = file_path + .to_str() + .ok_or(anyhow!("failed to convert file to str"))?; + let mut file_content = if file_cache.read().await.contains_key(&file_path) { + file_cache + .read() + .await + .get(&file_path) + .ok_or(anyhow!("failed to find {} in file cache", file_path_str))? + .to_owned() + } else { + let file_content = Rope::from_str(&read_to_string(&file_path).await?); + file_cache + .write() + .await + .insert(file_path.clone(), file_content.clone()); + file_content + }; + let original_content = file_content.clone(); + let hole_start = file_content.line_to_char(hole.cursor.line as usize) + + hole.cursor.character as usize; + let hole_end = hole_start + + file_content + .line(hole.cursor.line as usize) + .slice(hole.cursor.character as usize..) + .len_chars() + - 1; + file_content.remove(hole_start..hole_end); + + let uri = Url::parse(&format!("file:/{file_path_str}"))?; + client.send_notification::( + DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: uri.clone(), + language_id: repo.language.to_string(), + version: 0, + text: file_content.to_string(), + }, + }, + ); + let response = client + .send_request::(GetCompletionsParams { + api_token: api_token.clone(), + context_window, + fim: fim.clone(), + ide: Ide::default(), + model: model.clone(), + request_params: request_params.clone(), + text_document_position: TextDocumentPositionParams { + position: hole.cursor, + text_document: TextDocumentIdentifier { uri }, + }, + tls_skip_verify_insecure, + tokens_to_clear: tokens_to_clear.clone(), + tokenizer_config: tokenizer_config.clone(), + }) + .await?; + let (_, result): (RequestId, GetCompletionsResult) = match response.extract() { + Ok(res) => res, + Err(err) => { + error!("llm-ls response error: {err}"); + continue; + } + }; + + file_content.insert(hole_start, &result.completions[0].generated_text); + let mut file = OpenOptions::new() + .write(true) + .truncate(true) + .open(&file_path) + .await?; + file.write_all(file_content.to_string().as_bytes()).await?; + let test_percentage = + if build(&repo.build_command, &repo.build_args, &repo.env, &repo_path).await? { + run_test( + repo.runner, + &repo.runner_command, + &repo.runner_args, + &mut repo.runner_extra_args.clone(), + &repo.env, + &repo_path, + ) + .await? + } else { + 0f32 + }; + debug!("{} passed {}%", hole.to_string(), test_percentage * 100f32); + hole_completions_result.push(HoleCompletionResult::new( + repo.name(), + repo.source.source_type(), + test_percentage, + hole_instant.elapsed().as_millis(), + )); + let mut file = OpenOptions::new() + .write(true) + .truncate(true) + .open(&file_path) + .await?; + file.write_all(original_content.to_string().as_bytes()) + .await?; + if (idx + 1) % ten_percent == 0 { + info!("completed {}%", (idx + 1) / ten_percent * 10); + } + } + drop(permit); + info!("finished running hole completions"); + Ok(hole_completions_result) + } + .instrument(span) + .await +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt() + .with_target(true) + .with_line_number(true) + .with_env_filter( + EnvFilter::try_from_env("LOG_LEVEL").unwrap_or_else(|_| EnvFilter::new("info")), + ) + .init(); + + let args = Args::parse(); + + let api_token = get_api_token(args.api_token).await?; + let current_dir = std::env::current_dir()?; + let llm_ls_path = if let Some(bin_path) = args.llm_ls_bin_path { + bin_path.into() + } else { + current_dir.join("target/release/llm-ls") + }; + + let repos_dir_path = if let Some(path) = args.repos_dir_path { + path.into() + } else { + current_dir.join("crates/testbed/repositories") + }; + + let repos_file_path = if let Some(path) = args.repos_file_path { + path.into() + } else { + current_dir.join("crates/testbed/repositories.yaml") + }; + + let holes_dir_path = if let Some(path) = args.holes_dir_path { + path.into() + } else { + current_dir.join("crates/testbed/holes") + }; + + let (filter_repos, filter_list) = if let Some(filter) = args.filter { + (true, filter.split(',').map(|s| s.to_owned()).collect()) + } else { + (false, vec![]) + }; + + let mut repos_file = String::new(); + File::open(&repos_file_path) + .await? + .read_to_string(&mut repos_file) + .await?; + let repos_config: RepositoriesConfig = serde_yaml::from_str(&repos_file)?; + if args.generate_holes { + return generate_holes( + repos_config, + &repos_dir_path, + &holes_dir_path, + args.holes_per_repo, + filter_repos, + filter_list, + ) + .await; + } + + debug!( + "initializing language server at path: {}", + llm_ls_path.to_str().unwrap() + ); + let (conn, server) = Server::build().binary_path(llm_ls_path).start().await?; + let client = Arc::new(LspClient::new(conn, server).await); + client + .send_request::(InitializeParams::default()) + .await?; + + let file_cache = Arc::new(RwLock::new(HashMap::new())); + let mut passing_tests_percentage = vec![]; + + let repositories = repos_config.repositories.clone(); + let mut handles = FuturesUnordered::new(); + // Query the model by batches of 64 + let semaphore = Arc::new(Semaphore::new(8)); + for repo in repositories { + if filter_repos && !filter_list.contains(&repo.name()) { + continue; + } + let client = client.clone(); + let file_cache = file_cache.clone(); + let holes_dir_path = holes_dir_path.clone(); + let repos_dir_path = repos_dir_path.clone(); + let repos_config = repos_config.clone(); + let api_token = api_token.clone(); + let semaphore = semaphore.clone(); + handles.push(tokio::spawn(async move { + complete_holes( + repo, + client, + file_cache, + holes_dir_path, + repos_dir_path, + repos_config, + api_token, + semaphore, + ) + .await + })); + } + + while let Some(res) = handles.next().await { + match res { + Ok(Ok(res)) => passing_tests_percentage.extend(res), + Ok(Err(err)) => return Err(err), + Err(err) => return Err(err.into()), + } + } + let mut results_map: HashMap<(String, String), (u128, f32, f32)> = HashMap::new(); + for res in passing_tests_percentage { + results_map + .entry((res.repo_name, res.repo_source_type)) + .and_modify(|p| { + p.0 += res.completion_time_ms; + p.1 += res.pass_percentage; + p.2 += 1f32; + }) + .or_insert((res.completion_time_ms, res.pass_percentage, 1f32)); + } + let mut results_table = + "| Repository name | Source type | Average hole completion time (s) | Pass percentage |\n| :-------------- | :---------- | -------------------------------: | --------------: |\n".to_owned(); + let mut total_time = 0; + let mut total_percentage = 0f32; + let mut total_count = 0f32; + for (k, v) in results_map.iter() { + let avg = v.1 / v.2; + let avg_time = v.0 as f32 / v.2; + results_table.push_str(&format!( + "| {} | {} | {} | {}% |\n", + k.0, + k.1, + avg_time / 1_000f32, + avg * 100f32 + )); + total_percentage += v.1; + total_count += v.2; + total_time += v.0; + } + let total_avg = total_percentage / total_count; + let total_time_avg = total_time as f32 / total_count; + results_table.push_str(&format!( + "| **Total** | -- | {} | {}% |\n\n", + total_time_avg / 1_000f32, + total_avg * 100f32 + )); + results_table.push_str( + &[ + "**Note:** The \"hole completion time\" represents the full process of:", + " - replacing the code from the file with a completion from the model", + " - building the project", + " - running the tests", + ] + .join("\n"), + ); + info!("llm-ls results:\n{}", results_table); + OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open("results.md") + .await? + .write_all(results_table.as_bytes()) + .await?; + + client.shutdown().await?; + match Arc::into_inner(client) { + Some(client) => client.exit().await, + None => warn!("could not send exit notification because client is referenced elsewhere"), + } + Ok(()) +} diff --git a/crates/testbed/src/runner.rs b/crates/testbed/src/runner.rs new file mode 100644 index 0000000..46f48ab --- /dev/null +++ b/crates/testbed/src/runner.rs @@ -0,0 +1,278 @@ +use std::{path::Path, process::Stdio}; + +use anyhow::anyhow; +use serde::{Deserialize, Serialize}; +use tokio::{io::AsyncReadExt, process::Command}; +use tracing::debug; + +use crate::parse_env; + +#[derive(Deserialize, Serialize)] +struct TestSuiteResult { + r#type: String, + event: String, + passed: u32, + failed: u32, + ignored: u32, + measured: u32, + filtered_out: u32, + exec_time: f64, +} + +async fn pytest_runner( + override_cmd: &Option, + extra_args: &mut Vec, + repo_path: &Path, +) -> anyhow::Result { + let cmd = if let Some(cmd) = override_cmd { + cmd + } else { + "python3" + }; + let mut args = vec![ + "-m".to_owned(), + "pytest".to_owned(), + "tests".to_owned(), + "-q".to_owned(), + "--disable-warnings".to_owned(), + "--no-header".to_owned(), + ]; + args.append(extra_args); + debug!("running pytest tests: {cmd} {args:?}"); + let mut child = Command::new(cmd) + .args(args) + .current_dir(repo_path) + .stdout(Stdio::piped()) + .stderr(Stdio::null()) + .spawn()?; + let mut stdout = String::new(); + child + .stdout + .take() + .ok_or(anyhow!("failed to take stdout"))? + .read_to_string(&mut stdout) + .await?; + + // XXX: the pytest command can still fail even after the compilation check + // the above check should prevent an error, but better safe than sorry + let lines = stdout.split_terminator('\n'); + let result = match lines.last() { + Some(line) => line.replace('=', "").trim().to_owned(), + None => return Ok(0f32), + }; + let mut passed = 0f32; + let mut failed = 0f32; + let without_time = &result[0..result.find("in").unwrap_or(result.len())].trim(); + for res in without_time.split(", ") { + if res.contains("passed") { + let passed_str = res.replace(" passed", ""); + passed = passed_str.parse::()? as f32; + } else if res.contains("failed") && !res.contains("xfailed") { + let failed_str = res.replace(" failed", ""); + failed = failed_str.parse::()? as f32; + } else if res.contains("error") { + return Ok(0f32); + } + } + if passed == 0f32 && failed == 0f32 { + return Ok(0f32); + } + + Ok(passed / (passed + failed)) +} + +async fn cargo_runner( + override_cmd: &Option, + extra_args: &mut Vec, + env: &Option>, + repo_path: &Path, +) -> anyhow::Result { + let cmd = if let Some(cmd) = override_cmd { + cmd + } else { + "cargo" + }; + let mut args = vec![]; + args.append(extra_args); + if !args.contains(&"--".to_owned()) { + args.push("--".to_owned()); + } + args.extend([ + "-Z".to_owned(), + "unstable-options".to_owned(), + "--format".to_owned(), + "json".to_owned(), + ]); + debug!("running cargo tests: {cmd} test {args:?}"); + let parsed_env = parse_env(env)?; + let mut cmd = Command::new(cmd); + for (name, value) in parsed_env { + cmd.env(name, value); + } + let mut child = cmd + .arg("test") + .args(args) + .current_dir(repo_path) + .stdout(Stdio::piped()) + .stderr(Stdio::null()) + .spawn()?; + + let mut stdout = String::new(); + child + .stdout + .take() + .ok_or(anyhow!("failed to take stdout"))? + .read_to_string(&mut stdout) + .await?; + let lines = stdout.split_terminator('\n'); + let mut passed = 0; + let mut failed = 0; + for line in lines { + let test_suite_result = match serde_json::from_str::(line) { + Ok(res) => res, + Err(_) => continue, + }; + passed += test_suite_result.passed; + failed += test_suite_result.failed; + } + if passed == 0 && failed == 0 { + return Ok(0f32); + } + + Ok(passed as f32 / (passed as f32 + failed as f32)) +} + +async fn jest_runner( + override_cmd: &Option, + override_args: &Option>, + repo_path: &Path, +) -> anyhow::Result { + let cmd = if let Some(cmd) = override_cmd { + cmd + } else { + "npm" + }; + let default_args = vec!["run".to_owned(), "test".to_owned()]; + let args = if let Some(args) = override_args { + args + } else { + &default_args + }; + debug!("running jest tests: {cmd} {args:?}"); + let mut child = Command::new(cmd) + .args(args) + .current_dir(repo_path) + .stdout(Stdio::null()) + .stderr(Stdio::piped()) + .spawn()?; + + let mut stderr = String::new(); + child + .stderr + .take() + .ok_or(anyhow!("failed to take stderr"))? + .read_to_string(&mut stderr) + .await?; + let lines = stderr.split_terminator('\n'); + let mut passed = 0f32; + let mut failed = 0f32; + for line in lines { + if line.contains("Tests:") { + let words = line.trim().split(' ').collect::>(); + let mut prev = words[0]; + for word in words { + if word.contains("passed") { + passed = prev.parse::()? as f32; + } else if line.contains("failed") { + failed = prev.parse::()? as f32; + } + prev = word; + } + } + } + if passed == 0f32 && failed == 0f32 { + return Ok(0f32); + } + + Ok(passed / (passed + failed)) +} + +async fn vitest_runner( + override_cmd: &Option, + override_args: &Option>, + repo_path: &Path, +) -> anyhow::Result { + let cmd = if let Some(cmd) = override_cmd { + cmd + } else { + "npm" + }; + let default_args = vec!["run".to_owned(), "test".to_owned()]; + let args = if let Some(args) = override_args { + args + } else { + &default_args + }; + debug!("running vitest tests: {cmd} {args:?}"); + let mut child = Command::new(cmd) + .args(args) + .current_dir(repo_path) + .stdout(Stdio::piped()) + .stderr(Stdio::null()) + .spawn()?; + + let mut stdout = String::new(); + child + .stdout + .take() + .ok_or(anyhow!("failed to take stdout"))? + .read_to_string(&mut stdout) + .await?; + let lines = stdout.split_terminator('\n'); + let mut passed = 0f32; + let mut failed = 0f32; + for line in lines { + if line.contains(" Tests ") { + let words = line.trim().split(' ').collect::>(); + let mut prev = words[0]; + for word in words { + if word.contains("passed") { + passed = prev.parse::()? as f32; + } else if line.contains("failed") { + failed = prev.parse::()? as f32; + } + prev = word; + } + } + } + if passed == 0f32 && failed == 0f32 { + return Ok(0f32); + } + + Ok(passed / (passed + failed)) +} + +#[derive(Clone, Copy, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum Runner { + Cargo, + Jest, + Pytest, + Vitest, +} + +pub async fn run_test( + runner: Runner, + override_cmd: &Option, + override_args: &Option>, + extra_args: &mut Vec, + env: &Option>, + repo_path: &Path, +) -> anyhow::Result { + match runner { + Runner::Cargo => cargo_runner(override_cmd, extra_args, env, repo_path).await, + Runner::Jest => jest_runner(override_cmd, override_args, repo_path).await, + Runner::Pytest => pytest_runner(override_cmd, extra_args, repo_path).await, + Runner::Vitest => vitest_runner(override_cmd, override_args, repo_path).await, + } +} diff --git a/crates/testbed/src/types.rs b/crates/testbed/src/types.rs new file mode 100644 index 0000000..e5ccb42 --- /dev/null +++ b/crates/testbed/src/types.rs @@ -0,0 +1,88 @@ +use std::path::PathBuf; + +use lsp_types::{request::Request, TextDocumentPositionParams}; +use serde::{Deserialize, Deserializer, Serialize}; +use uuid::Uuid; + +#[derive(Debug)] +pub(crate) enum GetCompletions {} + +impl Request for GetCompletions { + type Params = GetCompletionsParams; + type Result = GetCompletionsResult; + const METHOD: &'static str = "llm-ls/getCompletions"; +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub(crate) struct RequestParams { + pub(crate) max_new_tokens: u32, + pub(crate) temperature: f32, + pub(crate) do_sample: bool, + pub(crate) top_p: f32, + pub(crate) stop_tokens: Option>, +} + +#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "lowercase")] +pub(crate) enum Ide { + Neovim, + VSCode, + JetBrains, + Emacs, + Jupyter, + Sublime, + VisualStudio, + #[default] + Unknown, +} + +fn parse_ide<'de, D>(d: D) -> std::result::Result +where + D: Deserializer<'de>, +{ + Deserialize::deserialize(d).map(|b: Option<_>| b.unwrap_or(Ide::Unknown)) +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub(crate) struct FimParams { + pub(crate) enabled: bool, + pub(crate) prefix: String, + pub(crate) middle: String, + pub(crate) suffix: String, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(untagged)] +pub(crate) enum TokenizerConfig { + Local { path: PathBuf }, + HuggingFace { repository: String }, + Download { url: String, to: PathBuf }, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub(crate) struct GetCompletionsParams { + #[serde(flatten)] + pub(crate) text_document_position: TextDocumentPositionParams, + pub(crate) request_params: RequestParams, + #[serde(default)] + #[serde(deserialize_with = "parse_ide")] + pub(crate) ide: Ide, + pub(crate) fim: FimParams, + pub(crate) api_token: Option, + pub(crate) model: String, + pub(crate) tokens_to_clear: Vec, + pub(crate) tokenizer_config: Option, + pub(crate) context_window: usize, + pub(crate) tls_skip_verify_insecure: bool, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub(crate) struct Completion { + pub(crate) generated_text: String, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub(crate) struct GetCompletionsResult { + request_id: Uuid, + pub(crate) completions: Vec, +}